Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
 Создание скриншота с глубиной цвета 8 bit  [new]
Mandarin
Member

Откуда: Саратов
Сообщений: 1191
Всем привет! Помогите пожалуйста разобраться как сделать восьми битный скриншот.
Я могу сделать 24 и 16 битный а вот 8 битный не получается, наверное не правильно битовую маску указываю. Вот пример кода.
package javaapplication28;

import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;

import com.sun.jna.Memory;
import com.sun.jna.platform.win32.GDI32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HBITMAP;
import com.sun.jna.platform.win32.WinDef.HDC;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinGDI;
import com.sun.jna.platform.win32.WinGDI.BITMAPINFO;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferUShort;

public class TestGDI {

    // 24bit
    public static final DirectColorModel SCREENSHOT_COLOR_MODEL_24 = new DirectColorModel(24, 0x00FF0000, 0xFF00, 0xFF);
    // 16bit
    public static final DirectColorModel SCREENSHOT_COLOR_MODEL_16 = new DirectColorModel(16, 0x7C00, 0x3E0, 0x1F);
    // 8bit
    public static final DirectColorModel SCREENSHOT_COLOR_MODEL_8 = new DirectColorModel(8, 3, 3, 2);

    public static final int[] SCREENSHOT_BAND_MASKS_24 = {
        SCREENSHOT_COLOR_MODEL_24.getRedMask(),
        SCREENSHOT_COLOR_MODEL_24.getGreenMask(),
        SCREENSHOT_COLOR_MODEL_24.getBlueMask()
    };
    public static final int[] SCREENSHOT_BAND_MASKS_16 = {
        SCREENSHOT_COLOR_MODEL_16.getRedMask(),
        SCREENSHOT_COLOR_MODEL_16.getGreenMask(),
        SCREENSHOT_COLOR_MODEL_16.getBlueMask()
    };
    public static final int[] SCREENSHOT_BAND_MASKS_8 = {
        SCREENSHOT_COLOR_MODEL_8.getRedMask(),
        SCREENSHOT_COLOR_MODEL_8.getGreenMask(),
        SCREENSHOT_COLOR_MODEL_8.getBlueMask()
    };

    public static BufferedImage getScreenshot(HWND target, int width, int height) throws Exception {
        int bit = 8;
        HDC hdcTarget = User32.INSTANCE.GetDC(target);
        HDC hdcTargetMem = GDI32.INSTANCE.CreateCompatibleDC(hdcTarget);
        HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcTarget, width, height);
        GDI32.INSTANCE.SelectObject(hdcTargetMem, hBitmap);
        GDI32.INSTANCE.BitBlt(hdcTargetMem, 0, 0, width, height, hdcTarget, 0, 0, GDI32.SRCCOPY);
        //
        int bufferSize = width * height;
        int pixelByte;
        DirectColorModel colorModel;
        int[] bandMask;
        short bitCount;
        //
        switch (bit) {
            case 24:
                pixelByte = 4;
                colorModel = SCREENSHOT_COLOR_MODEL_24;
                bandMask = SCREENSHOT_BAND_MASKS_24;
                bitCount = 32;
                break;
            case 16:
                pixelByte = 2;
                colorModel = SCREENSHOT_COLOR_MODEL_16;
                bandMask = SCREENSHOT_BAND_MASKS_16;
                bitCount = 16;
                break;
            case 8:
                pixelByte = 1;
                colorModel = SCREENSHOT_COLOR_MODEL_8;
                bandMask = SCREENSHOT_BAND_MASKS_8;
                bitCount = 8;
                break;
            default:
                throw new Exception("unknown bit");
        }
        //
        BITMAPINFO bmi = new BITMAPINFO();
        bmi.bmiHeader.biWidth = width;
        bmi.bmiHeader.biHeight = -height;
        bmi.bmiHeader.biPlanes = 1;
        bmi.bmiHeader.biBitCount = bitCount;
        bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
        //

        Memory buffer = new Memory(bufferSize * pixelByte);
        GDI32.INSTANCE.GetDIBits(hdcTarget, hBitmap, 0, height, buffer, bmi, WinGDI.DIB_RGB_COLORS);
        DataBuffer dataBuffer;
        switch (bit) {
            case 24:
                dataBuffer = new DataBufferInt(buffer.getIntArray(0, bufferSize), bufferSize);
                break;
            case 16:
                dataBuffer = new DataBufferUShort(buffer.getShortArray(0, bufferSize), bufferSize);
                break;
            case 8:
                dataBuffer = new DataBufferByte(buffer.getByteArray(0, bufferSize), bufferSize);
                break;
            default:
                throw new Exception("unknown bit");
        }

        WritableRaster raster = Raster.createPackedRaster(dataBuffer, width, height, width, bandMask, null);
        GDI32.INSTANCE.DeleteObject(hBitmap);
        GDI32.INSTANCE.DeleteDC(hdcTargetMem);
        User32.INSTANCE.ReleaseDC(target, hdcTarget);
        return new BufferedImage(colorModel, raster, false, null);
    }
}
23 апр 20, 14:10    [22121436]     Ответить | Цитировать Сообщить модератору
 Re: Создание скриншота с глубиной цвета 8 bit  [new]
mayton
Member

Откуда: loopback
Сообщений: 46531
Обычно RGB пространство цветов заканчивается на 16 битах.

Всё что ниже - индексный цвет. Тоесть цвет №1==красный .... цвет №256 == черный.
Цвета рандомные или по выбору пользователя.
И тут какоаз на сцене появляется выбор палитры. Начиная от стандартных
VGA-256 и заканивая адаптивными палитрами которые беруться из
центров кластеров исходного цветового пространства картики.
Можно также 8 бит представить как RGB=3:3:2 бита
но качество такой адаптации будет ужасным. Я сам пробовал.

Потом еще Microsoft различает 4-х битный цвет. И 1-битный для би-тональных картинок.
23 апр 20, 14:49    [22121468]     Ответить | Цитировать Сообщить модератору
 Re: Создание скриншота с глубиной цвета 8 bit  [new]
Mandarin
Member

Откуда: Саратов
Сообщений: 1191
mayton,

Вы все правильно и интересно говорите, как это превратить в рабочий код? :)
23 апр 20, 15:04    [22121481]     Ответить | Цитировать Сообщить модератору
 Re: Создание скриншота с глубиной цвета 8 bit  [new]
mayton
Member

Откуда: loopback
Сообщений: 46531
Я опираюсь на свои базовые знания Windows и графики. Но в Java
я никогда не использовал пакет com.sun.jna.platform.win32

Тоесть то что я написал - теория. И как правильно обращатся с этим пакетом хз.
23 апр 20, 15:11    [22121485]     Ответить | Цитировать Сообщить модератору
 Re: Создание скриншота с глубиной цвета 8 bit  [new]
Mandarin
Member

Откуда: Саратов
Сообщений: 1191
mayton,

Как превратить в знания в Java я знаю. Сможете подсказать на примере с++ например?
Я так понимаю что всё дело в правильно заполнении массива RGBQUAD?
23 апр 20, 15:42    [22121512]     Ответить | Цитировать Сообщить модератору
 Re: Создание скриншота с глубиной цвета 8 bit  [new]
mayton
Member

Откуда: loopback
Сообщений: 46531
Да.
1) Создаешь 256 штук RGBQUAD. (палитра)
2) Заполняешь их любыми цветами (но желательно брать самые популярные из изсходной картинки)
3) Генеришь destination и на каждый пиксел находишь из палитры самый близкий цвет
(по декартову расстоянию) или там есть более точная формула. Декартово расстояние
но перед каждым цветом есть весовой коэффициент. Для зеленого он самый большой.
23 апр 20, 16:01    [22121538]     Ответить | Цитировать Сообщить модератору
 Re: Создание скриншота с глубиной цвета 8 bit  [new]
mayton
Member

Откуда: loopback
Сообщений: 46531
А зачем такой странных хардкод?
    public static BufferedImage getScreenshot(HWND target, int width, int height) throws Exception {
        int bit = 8;
        HDC hdcTarget = User32.INSTANCE.GetDC(target);
        HDC hdcTargetMem = GDI32.INSTANCE.CreateCompatibleDC(hdcTarget);
        HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcTarget, width, height);
        GDI32.INSTANCE.SelectObject(hdcTargetMem, hBitmap);
        GDI32.INSTANCE.BitBlt(hdcTargetMem, 0, 0, width, height, hdcTarget, 0, 0, GDI32.SRCCOPY);
        //
        int bufferSize = width * height;
        int pixelByte;
        DirectColorModel colorModel;
        int[] bandMask;
        short bitCount;
        //
        switch (bit) {
            case 24:
24 апр 20, 14:12    [22122100]     Ответить | Цитировать Сообщить модератору
Все форумы / Java Ответить