2016-06-18 8 views
1

Windowsのクリップボードからイメージを貼り付けるために、私のアプリケーション(RGBA8888イメージで動作)が必要です。だから、クリップボードから、Gimp、Photoshop、MSPaintなどの一般的なラスターイメージアプリから来た画像を読み取ることができるはずです。を呼び出すことができるようです。 WindowsはそれをCF_BITMAPとCF_DIBの間で自動的に変換するので、クリップボードにあるほとんどすべてのビットマップタイプにアクセスできます。しかし、DIBフォーマットを読み上げることで、ビット深度、RGBオーダー、オプションの圧縮などの組み合わせが膨大な数であることがわかります。私がやっていることはよくあることですが、 Windows APIの変換関数を見ることはできません(検索に貧弱な場合を除きます)、これは可能なすべての形式をサポートするために1週間かかると思われます。だから明らかに何かを見落としてしまったのかなと思います。あるいは、私がこれを単純化するために行うことができる何らかの仮定がある場合...一般的な画像アプリケーションのすべてが非圧縮/非インデックス形式で画像をクリップボードにコピーするような場合Windowsのクリップボードから32ビットのRGBAイメージを取得する

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を使用する必要はありません。

私は必要なデータの種類に.bmps、.jpgs、および.pngをロードできる、stdb_image.hという第三者のライブラリを知っています。だから、アルファを失うことなくクリップボードのデータをビットマップやPNGファイルに変換する方法があれば、私はうまくいくでしょう。

+1

'GetDIBits'と' SetDIBits'は、DIBとDDB間のビットマップデータを変換し、 'BITMAPINFO'のパラメータに従って変換します。 – GSerg

+0

アルファ透明度レベルを必要としない限り、 'GetClipboardData(CF_BITMAP)'で十分です。これまで行ってきたことと、特定のプログラムで何が問題になっているのかを示してください。(Microsoft paint.exeは問題にならないはずです) –

+0

getDIBits関数を理解しています。私はアルファが必要です。インデックスされていないビットマップのように見えますが、アルファは4バイト目です(各ピクセルはRGBだけでも長いピクセルを使用する必要があります)が、アルファがあるかどうかを判断するためにヘッダーには何もありません。 – Tenfour04

答えて

1

可能な場合は。それが一番簡単です。 GIMPなどの一部のアプリでは、画像をPNG形式でクリップボードにコピーします。

次に、CF_DIBV5を確認します。

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_BITFIELDSであるかどうかに依存します。

ヘッダーに圧縮がBI_RGBで、ビット数が24または32と表示されている場合は、そのバイトをアンパックできます。 24バイトというのは、行サイズがDWORD境界上に上がらない可能性があることを意味します。

最後に、24より小さいビット数は、まだ機能していないインデックスカラーを意味する可能性があります。

0

CF_DIBV5CF_DIBの使用例を次に示します。バックアップオプションとしてCF_DIBを使用することをお勧めします。このコードは、あなたがドンをHDCに直接描画、またはSetDIBits

GDI関数を使用するSetDIBitsToDeviceを使用することができます

(それが保証されていない場合、32ビットはその後、さらに下の方法を参照)パレットベースのイメージのために動作しません、注意してくださいアルファ透明度(TransparentBltのような2つの関数を除く)をサポートしていないため、一般的に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を追加して(ソースがビットマップであると仮定して)、他のライブラリに渡すこともできます。

これはピクセルが32ビットであることを確認するCreateDIBitmapGetDIBitsを使用した例である:私が見つけた、基本的な戦略は、クリップボードと最初の使用上の生PNGをありますかどうかを確認することです

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圧縮が含まれています。私はそれが次のビットが文字通りそれらのイメージタイプの1つのファイルデータであること、あるいは単純にその圧縮スタイルが使用されていることを意味するかどうかはわかりません。 – Tenfour04

+0

'header-> bV5BitCount'が32の場合、' bits'はあなたが望む "32bit image data"を指します。それが24の場合は、32ビットに変換する必要があります。 –

関連する問題