2016-06-18 15 views
1

Я хочу, чтобы мое приложение (которое работает с изображениями RGBA8888) позволяет вставлять изображения из буфера обмена Windows. Таким образом, он должен иметь возможность считывать изображения из буфера обмена, которые поступают из любых распространенных приложений растрового изображения, таких как Gimp, Photoshop, MSPaint и т. Д.Получить 32-битное изображение RGBA из буфера обмена Windows

От чтения функций буфера обмена, кажется, я могу позвонить GetClipboardData(CF_DIBV5) в получить доступ практически к любому растровому типу, который находится в буфере обмена, поскольку Windows автоматически преобразует его в CF_BITMAP и CF_DIB. Но после чтения в формате DIB я вижу, что существует огромное количество возможных комбинаций битовой глубины, порядка RGB, дополнительного сжатия и т. Д. Похоже, что то, что я делаю, будет обычной задачей, но я не знаю, я вижу какие-либо функции преобразования в Windows API (если я не беден в поиске), и это похоже на то, что потребуется неделя, чтобы писать для поддержки всех возможных форматов. Поэтому мне интересно, не упустил ли я что-то очевидное. Или если есть какое-то предположение, которое я могу сделать, чтобы упростить это ... например, если все популярные приложения для изображений будут копировать изображения в буфер обмена в несжатых/неиндексированных форматах.

UPDATE: Вот что я до сих пор:

HGLOBAL clipboard = GetClipboardData(CF_DIBV5); 
exists = clipboard != NULL; 
int dataLength = GlobalSize(clipboard); 
exists = dataLength != 0; 
if (exists) { 
    LPTSTR lockedClipboard = GlobalLock(clipboard); 
    exists = lockedClipboard != NULL; 
    if (exists) { 
     BITMAPV5HEADER *header = (BITMAPV5HEADER*)lockedClipboard; 
     LONG width = header->bV5Width; 
     LONG height = header->bV5Height; 
     BYTE *bits = header + sizeof(header) + header->bV5ClrUsed * sizeof(RGBQUAD); 

     //Now what? Need function to convert the bits to something uncompressed. 

     GlobalUnlock(clipboard); 
    } 
} 

UPDATE 2:

Чтобы уточнить, мне нужно буквально несжатого 32 бит данных изображения (RRGGBBAA), которые я могу манипулировать однако Мне нравится в кросс-платформенном приложении. Мне не нужно использовать Windows API для рисования этого изображения.

Я знаю о сторонней библиотеке под названием stdb_image.h, которая может загружать .bmps, .jpg и .png в тип данных, который мне нужен. Поэтому, если есть способ, я могу превратить данные буфера обмена в растровые или png-файлы, не теряя альфа, тогда я буду в хорошей форме.

+1

'GetDIBits' и' SetDIBits' преобразуют растровые данные между DIB и DDB, преобразуя их в соответствии с параметрами из 'BITMAPINFO'. – GSerg

+0

'GetClipboardData (CF_BITMAP)' должно быть достаточно, если вам не нужны уровни альфа-прозрачности. Покажите, что вы сделали до сих пор и какие проблемы у вас есть с определенными программами (Microsoft paint.exe не должно быть проблемой) –

+0

Я работаю над пониманием функции getDIBits и обновляюсь, если не могу заставить ее работать. Мне нужна альфа. Похоже, что для неиндексированных растровых изображений альфа находится в четвертом байте (каждый пиксель должен использовать длинный, хотя и только RGB), но в заголовке нет ничего, чтобы определить, есть ли альфа. – Tenfour04

ответ

1

Основная стратегия, которую я нашел, чтобы проверить, есть ли сырой PNG в буфер обмена и использования, что первый если доступно. Это самое легкое. Некоторые приложения, такие как GIMP, копируют изображения в формате PNG в буфер обмена.

Затем проверьте наличие CF_DIBV5.Расположение фактических бит зависит от того, «сжатие» является BI_BITFIELDS:

int offset = bitmapV5Header->bV5Size + bitmapV5Header->bV5ClrUsed * (bitmapV5Header->bV5BitCount > 24 ? sizeof(RGBQUAD) : sizeof(RGBTRIPLE)); 
if (compression == BI_BITFIELDS) 
    offset += 12; //bit masks follow the header 
BYTE *bits = (BYTE*)bitmapV5Header + offset; 

Если заголовок говорит сжатие BI_BITFIELDS, то данные уже как мне нужно это.

Если заголовок говорит, что сжатие равно BI_RGB, а количество бит равно 24 или 32, тогда я могу распаковать байты. 24 байта означает, что размер строки может не приземляться на границе DWORD, поэтому вы должны следить за этим.

И, наконец, нижний бит имеет значение, равное 24, вероятно, означает индексный цвет, который у меня пока не работает.

0

Ниже приведен пример использования для CF_DIBV5 и CF_DIB. Лучше использовать CF_DIB в качестве опции резервного копирования. Обратите внимание, что этот код не будет работать на палитру на основе изображений (если это не гарантировано 32bit тогда смотрите метод далее вниз)

Вы можете использовать SetDIBitsToDevice рисовать прямо на HDC, или использовать SetDIBits

функции GDI Дон 't поддерживает альфа-прозрачность (за исключением нескольких функций, таких как TransparentBlt), в общем, для этого вам нужно использовать такие библиотеки, как GDI +.

void foo(HDC hdc) 
{ 
    if (!OpenClipboard(NULL)) 
     return; 

    HANDLE handle = GetClipboardData(CF_DIBV5); 
    if (handle) 
    { 
     BITMAPV5HEADER* header = (BITMAPV5HEADER*)GlobalLock(handle); 
     if (header) 
     { 
      BITMAPINFO bmpinfo; 
      memcpy(&bmpinfo.bmiHeader, header, sizeof(BITMAPINFOHEADER)); 
      bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFO); 

      //(use `header` to access other BITMAPV5HEADER information) 

      int w = bmpinfo.bmiHeader.biWidth; 
      int h = bmpinfo.bmiHeader.biHeight; 
      const char* bits = (char*)(header) + header->bV5Size; 

      //draw using SetDIBitsToDevice 
      SetDIBitsToDevice(hdc,0,0,w,h,0,0,0,h,bits,&bmpinfo,DIB_RGB_COLORS); 
     } 
    } 
    else 
    { 
     handle = GetClipboardData(CF_DIB); 
     if (handle) 
     { 
      BITMAPINFO* bmpinfo = (BITMAPINFO*)GlobalLock(handle); 
      if (bmpinfo) 
      { 
       int w = bmpinfo->bmiHeader.biWidth; 
       int h = bmpinfo->bmiHeader.biHeight; 
       const char* bits = (char*)(bmpinfo)+bmpinfo->bmiHeader.biSize; 
       SetDIBitsToDevice(hdc, 0, 0, w, h, 0, 0, 0, h, bits, bmpinfo, 0); 
      } 
     } 
    } 

    CloseClipboard(); 
} 

Если исходное изображение основано на палитре, вам придется преобразовать его в 32-разрядный. В качестве альтернативы вы можете добавить BITMAPFILEHEADER к данным (при условии, что источник является растровым изображением), затем перейдите в другую библиотеку.

Это пример использования CreateDIBitmap и GetDIBits, чтобы убедиться, что пиксели в 32-х:

HANDLE handle = GetClipboardData(CF_DIB); 
if (handle) 
{ 
    BITMAPINFO* bmpinfo = (BITMAPINFO*)GlobalLock(handle); 
    if (bmpinfo) 
    { 
     int offset = (bmpinfo->bmiHeader.biBitCount > 8) ? 
      0 : sizeof(RGBQUAD) * (1 << bmpinfo->bmiHeader.biBitCount); 
     const char* bits = (const char*)(bmpinfo)+bmpinfo->bmiHeader.biSize + offset; 
     HBITMAP hbitmap = CreateDIBitmap(hdc, &bmpinfo->bmiHeader, CBM_INIT, bits, bmpinfo, DIB_RGB_COLORS); 

     //convert to 32 bits format (if it's not already 32bit) 
     BITMAP bm; 
     GetObject(hbitmap, sizeof(bm), &bm); 
     int w = bm.bmWidth; 
     int h = bm.bmHeight; 
     char *bits32 = new char[w*h*4]; 

     BITMAPINFOHEADER bmpInfoHeader = { sizeof(BITMAPINFOHEADER), w, h, 1, 32 }; 
     HDC hdc = GetDC(0); 
     GetDIBits(hdc, hbitmap, 0, h, bits32, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS); 
     ReleaseDC(0, hdc); 

     //use bits32 for whatever purpose... 

     //cleanup 
     delete[]bits32; 
    } 
} 
+0

В вашей последней функции я не буду следить за тем, что происходит. Является ли 'CreateDIBSection' единственным способом получить битмап из буфера обмена? И что делает SetDIBits на самом деле? Мне нужен просто массив байтов несжатых 32-битных данных изображения. Я использую его для загрузки изображения в OpenGL. На самом деле, если бы я мог просто преобразовать содержимое буфера обмена непосредственно в массив байтов .bmp, .png или .jpg (такие же байты, которые можно было сохранить в виде файла), я мог бы легко передать его в стороннюю сторону 'stdb_image.h' чтобы получить данные изображения в любом формате, который я хочу. – Tenfour04

+0

«BITMAPV5HEADER» упоминает сжатие JPG или PNG. Я не знаю, означает ли это, что следующие биты являются буквально файловыми данными для одного из этих типов изображений или просто используются этот стиль сжатия. – Tenfour04

+0

Если 'header-> bV5BitCount' равно 32, тогда' bits' указывает на «32-битные данные изображения», которые вы хотите. Если он равен 24, он должен быть преобразован в 32 бит. –