From 25ffb85a66caabb0076901ab3e39b52ab3144e51 Mon Sep 17 00:00:00 2001 From: haru-s Date: Fri, 17 Mar 2023 14:27:42 +0900 Subject: [PATCH] Fix Clipboard about DIB (1-32 bits color) --- examples/clipboard/image/sample.bmp | Bin 58662 -> 58662 bytes examples/clipboard/image/sample_1.bmp | Bin 0 -> 2702 bytes examples/clipboard/image/sample_24.bmp | Bin 0 -> 58662 bytes examples/clipboard/image/sample_4.bmp | Bin 0 -> 10150 bytes examples/clipboard/image/sample_8.bmp | Bin 0 -> 20614 bytes source/dfl/data.d | 151 +++++++++---------------- 6 files changed, 51 insertions(+), 100 deletions(-) create mode 100644 examples/clipboard/image/sample_1.bmp create mode 100644 examples/clipboard/image/sample_24.bmp create mode 100644 examples/clipboard/image/sample_4.bmp create mode 100644 examples/clipboard/image/sample_8.bmp diff --git a/examples/clipboard/image/sample.bmp b/examples/clipboard/image/sample.bmp index 2e33685d22f4cee77d12fe3d1dcbde1bd00609e3..70e9ed9aedd184ebddeb8eb9b5497e2ed97fc037 100644 GIT binary patch delta 42 xcmZ2>ih0>7<_Tt#tJ;D$2Ba}gc1X&fT;LTxG2k1JS-Mz(ih0>7<_Tt#YuW-g24pZ!c1X&fT;LTxG2k1JS-Mz(J#O1T5QP=E2#_X6P@7XkK>7f=(H2P^6*+*9LI*j3j<5kzsFZ^gvOr3c_ukBs zyCfaB&)B52AK(1!>~if7AHTlY$ll}r4%ataUvRy`5A9Pt*PyzY*(TxE+RqKgzZ>Xm z*w!#uUb4&gCF>h!_dVLLO6V-xb;0g!*iBHnTQd7RV*|!d;9=7B9Hby-6Wgt@A1ym_ zcxl;*!`lk8U4hCWojo)x`zQsJF4*f8_PBK@T^EAG3OiRUh3;{M-L`^?m;AYzCh2_{ znVKdx&2-RH`cBL`Mj@-#EKh8><9C?4L0xZGt`bd&on6WbDY3KO?j`fk&W=&-#Lfuq z)f#t%Y9TB2bQLRg=ZbOFSY^Y|<2wXkfy~Qz_6NHN8JNo%Jg$bO?38O{w{$Vv^MP~+ zMeg8+McO;dVi^Fxh)Z8*Cx9n5DOiVWXH;{m7y{dw4-yl*FWH5+ZOhb>L(8rmbZXG# z+mjucreYaPsV8@(_0E3Bgkk})21Vo=viYdvFUCFmMmuVbxZ z+;|(ltt|t9Wn598=00PXnH!rLx;3VGQpq5p!-v~*3~v+r(&!NUIi|TYBIAWlb9xEO z6v1lWEYdR0lSUmb*5Vs##{6h?9ekuKjiGO0V`ISfp{rT<4|dzZDJ+G~av|!Q@{R@i zesjhm+*p>gQlRf&XXVKDsW`I~u8JJ&zA%0XR=R+ba%5wYG_f*cEp_;oWydZUeM@4U yF`+AeD>R|PVwoD|2a_G@c*9$ce3ukop3AVr+sFp}>(nv|!bV*I`2644!{#qzO>vR{ literal 0 HcmV?d00001 diff --git a/examples/clipboard/image/sample_24.bmp b/examples/clipboard/image/sample_24.bmp new file mode 100644 index 0000000000000000000000000000000000000000..70e9ed9aedd184ebddeb8eb9b5497e2ed97fc037 GIT binary patch literal 58662 zcmeI4L5>|a3`EDb$Rf)i$O(La>~pK!z*kI`0el0883lqMsnui^MXCSSVCGw`rdY*# z-GAxd|M>OqkI$d4^7)(meUraGk{JOIF+3*xBBb_c7t$kZ>@b|UD&N1;Wpu^1q)|i!cIiHKT|`V*L)Q| z$&efhaDFA4fRcXVk4pkT2)xg$81IPmh|QwE3G;3(tJ=>&l<&BzWm@bI#{D1 zJ!p~~OXv+-iCF8$J_GLRqi``pvNO5Gw6Iey;Q&n}5K|_AL_R_$WAX`W!3Xo0!3$F? zus1RmlSxL4ISYrw95f|^36YtY9Fkgcoa}HFQR>`&Ue#;%P045)wl!oLCWoX}GM^G| z2hs278Igu198*5}5popPBW1nG8yQ8Z%Mdi#V1$xkQ$*#Aw`bVtb%tOU!z)Ko^$i8ou2u<;wN#LAXFvU?B!yfG8}1g;~i}msrnv zrw+TEZI@JcGap&IIP7x%T}<80d}Qt7uuJ(57|E@{-G%rLyIXe3f_R9BogU3@Z{J~O zVz(8(!%o=$K95LmiEY`=^HiSpei^3AE+p8Tw0yuJ| z&g|=BY*pY9Oro$#Yq;Hko5KfN5AcpD#!3bDZxw}wD#Pt1+!;RDdVqJVF_uEGf2$}g zRJv`~WLxrh>&Lodjj`+xo41OJ5Uf=iuGVBv@_1zixU|MtO2FnZQCP0@T&~H6>L(_6}xHh-S`e&W6Di9#wF~Ms8?bxeO#I- zVO3>I*og;5HxaA`0WMu)cWDBcmm^GujBQ3YP0FZC2l9BCwqvWZ?d_V$knzmurlA;h z=|CQ@g7xiIHNU!KGGq)hx_K5c0DFKBX7zI6+pX+8STh+ih8f*z9LxrGs*)}*-5Zw8 zyK5#x#x0}U4q|m8_0}V;Xtm?sujj87|(fef5<9#yf`WYiD`Aqa~ne<$I zG6wWxMpnASqA|=w=Vg-dpqVka#w(Uv+e~g=CK(U61I8D4#WHX%iIJgsnIvrtW?XX1 zE0%$IJ~1zoypzG0@wdEU893(?b2Q1D8B7{{%Q2QK=X_kgCV4+slLqhm#?m# z_tPCSe$zLWu75r&cayxO?xew+?yo)8L{LMyuz7h(#v5UIdU;C7Ma2;nMat6 zq&8JcsHI;QmBY>@Mr9MPH!jH?cFNdY${xf{=JoxSa0zf#6JKyL#nkt%Ov&AO*?j-? zjPb+RNxU=s?@w*s;F0X+O|dhLg;1YH*bFF2Uf{mFp3}V-Z0dRJB1hPY-J|h^ zeO2ZMZ#Q-i#TO4wg4&Q>!Wa4Flb>XGvBd43>{5nH0>SVtvAQ!miBU3H5{sVTLWi5P z%P(MxD1Yj+om#o}xq1Y?P&Iqa;7?Nfi)?Zd+AQ#7fLBh=WV;+?^NOA z@8*5T(Mdm{h!RK1CC4N36l!;>VD8pr`TZ2F!SZL6nXIQfrOajpf7au)SR^YR&;7X0 zrWVVU&YUYnos7ZCvZ&X-q^xEE%KPUEt!61H&wV=3iuJ4vxss)XR%4Zd30>1OpjpEC zJfc~cEBRWnxC(N$iBMUxb1XmQ*(8fR8{;&~6~$GiQ+2dmU=25p1y*=GyAOe44JWMU z+A6EJc`Me?-`+#8%%W|mHQ+jnHnj%q49hoWNU|D@j-?2x9p*WftxU2SMu4K6wOZON zdJ_t-K%K*KL$FGNH=^`m)?AvbM_~DwG^LesxrNP&^#_rgs+?2z-dn5;$=9k=EEup- z^&@vKnOuO^+A*O^v-*}*j`dkxVb%82XX%9@*If#u1U_IPEUjN&D%!CT3t$NXv#T7l zSUhr&pYOJkDM2a6#;l}+matLEqT5ED#UtVv6N? zL1Ymev&%(uy8N4t5gc1&J)mn+!AjZusTfI>Hmn2&i(-mJpeo1$Thw(SD{A72D~gWH znyw?hmSbmFEyqr=8p76C3DOYuVXUIZ4suD?E3DEtEuUs}Q&xcb}g94lL^t|H=CXU8aXDMr4XX7LcY zYjv%Iolur^COt6-H|@;fWl z+NpbaTe;O`86yME7^xlO;JI96;dhjvC}xciTWd9SZT>gZoS0sWO##N*3T=n1@DI%T laB&=!j9IEf=k}A;F~_L-^vf`%Q}pRq#~h>TO27VY+kez8PAC8X literal 0 HcmV?d00001 diff --git a/examples/clipboard/image/sample_8.bmp b/examples/clipboard/image/sample_8.bmp new file mode 100644 index 0000000000000000000000000000000000000000..60fce04a96b893036b6cb6ef497b6f5e76ca2130 GIT binary patch literal 20614 zcmeI2JCf`)6oy3=0n1Rx3W!z2P?sfWDGDeyzy=ghtV1ztAkY$SN)Zg7pJU5M^6{(d zQg?dhYsvC?{60G4?&+ByfBx+k(?5Rr)|l^^{SLpvH|D#3{g#!;WlomSfrkJQ z66AghT(*o3JOqf4Ae+GT2VXMh6}OL`abP77E!iI`9x6LV|1( z*Po092Oa`M=)UsMTGlc;@DLzEf;_aHvy2Wr1c;Cz4=w2}qXQ2CA|%K|y9UeXz(art z3G&d&(K0&l5FkQ=JhXYTj1D{mi01RZZ{`o|0`ZJ_>%Yz0TQ>u~x+R|e;pq!|bh>sQ zpFVxswYkwirRnVrRj<>f)`YGbOVJFa)701KWwlajny%|5x-^=~PI|hv6q=+ylGdhL zULN-~l~w9fc6)d^cP+r4rh4kkQ@i9- z>n%+?&9um;w_G??r%g>&ukDFDcknJvymQzJJ-Kq5rt$sE9m*P-&V@hcwW{d-ny$a> z+^(s+;{Ijle1p|BUEYM#q8`+A`rUF>)8#Uad${Ue-NB=pPRe>(Q&*Xzjr9smM;oiA z>5g_9ZCVQ`aMTkMny1JstsJc8ymBusEuvzF& ztTRlu<5-3eJVcWz%sS=zXt3GJWWD*`MMzj~w_q|U>c-{i<$PfyF4tuV=4D+4lSRIz zsG4PMy}bG{tYCgr(|e_aU_%;l|2S2q8m&idi=i;ACVF=nOr&O-ZR99Ls?l1oT^kAp zbE0X|+w2(1r`Nge)YSiVa1vM<;uY)ucydS^7SvX;gDY)YqhGu8-6(|>+%(cYYCg9uSe6SE}Ml-aTW{D)M+DOv#^k`nV!#3=$#QJ@W=-<`RV1}`d#&qIoepY}&DVOmqidSPo~qXA zMVh1yscTY-x>zSFT}o*EQc&7%_wC5uiJRPqc%hM!(Kwi5PN&mVCilbWa*;UR`bCa#-V7f^y z`0Oobsk+JLb2QbY8hrAWlhoa0`ze}gtOp<6U3Cyq~RYX5V>2_>^jUD8gE_YoT2bB4o{R?wZjdrDMGlBQ18 zd)wjS%nnUSI!(9V67JA+_}{JPiinf8BxRk5yc0*vU0K`|Zy(UVv zcY&3HStkbpa(@8q6=}M<-HttNF z@KJ`|ZmiPr@ZNQqlzUK!QhS}!)T!zoMbh@6-uk4bA^j0mdPygGd{vF1UaIGnU-RHn ootlx)pZw6ItKCPPKI){afX?cppFZlOtANhxqo4k_b^6Er2jIc#rT_o{ literal 0 HcmV?d00001 diff --git a/source/dfl/data.d b/source/dfl/data.d index 1e41f3a..3fce2ea 100644 --- a/source/dfl/data.d +++ b/source/dfl/data.d @@ -18,6 +18,7 @@ private import dfl.internal.wincom; private import core.sys.windows.ole2; // DATA_E_FORMATETC public import core.sys.windows.wingdi : BITMAPINFO; +import core.internal.gc.impl.conservative.gc; pragma(lib, "urlmon"); // CreateFormatEnumerator() @@ -423,54 +424,40 @@ private void[] _getClipboardValueFromData(int id, Data data) } else if (CF_DIB == id) { + // https://learn.microsoft.com/ja-jp/windows/win32/gdi/storing-an-image + // https://learn.microsoft.com/ja-jp/windows/win32/api/wingdi/ns-wingdi-bitmap + // https://ja.wikipedia.org/wiki/Windows_bitmap + // https://note.affi-sapo-sv.com/bitmap-file-format.php // http://dencha.ojaru.jp/programs_07/pg_graphic_04.html // http://www5d.biglobe.ne.jp/~noocyte/Programming/Windows/BmpFileFormat.html // https://imagingsolution.net/imaging/imaging-programing/bitmap-file-format/ - // https://learn.microsoft.com/ja-jp/windows/win32/api/wingdi/ns-wingdi-bitmap // http://hp.vector.co.jp/authors/VA023539/tips/bitmap/001.htm - // https://ja.wikipedia.org/wiki/Windows_bitmap - // https://learn.microsoft.com/ja-jp/windows/win32/gdi/storing-an-image // http://www.sm.rim.or.jp/~shishido/windows.html - const BITMAPINFO* pbi = data.getDIB(); assert(pbi); const uint bitsPerPixel = pbi.bmiHeader.biPlanes * pbi.bmiHeader.biBitCount; - const uint numEntry = { - if (bitsPerPixel <= 8) // 1, 4, 8 + const uint colorMaskBytes = { + if (pbi.bmiHeader.biCompression == BI_BITFIELDS) + return 4 * 3; // 4 bytes * 3 masks(R,G,B) + else + return 0; + }(); + const uint numPallet = { + if (bitsPerPixel <= 8) // 1, 4, 8 bits color { if (pbi.bmiHeader.biClrUsed == 0) - return 2 ^^ bitsPerPixel; + return 2 ^^ bitsPerPixel; // Assume max. else return pbi.bmiHeader.biClrUsed; } - else if (bitsPerPixel == 24) - { + else if (bitsPerPixel <= 32) // 16, 24, 32 bits color return pbi.bmiHeader.biClrUsed; - } - else if (bitsPerPixel <= 32) // 16, 32 - { - if (pbi.bmiHeader.biCompression == BI_RGB) - return 3;//pbi.bmiHeader.biClrUsed; // TODO: ? - else if (pbi.bmiHeader.biCompression == BI_BITFIELDS) - return 3; - else - assert(0); - } else - assert(0); - }(); - - // if (bitsPerPixel <= 16) // TODO: 1-16 bpp is not implemented... - // throw new DflException("_getClipboardValueFromData() failure"); - - const uint widthBytes = { // TODO: It is bad for 1, 4, 8 and 16 bpp... - if ((pbi.bmiHeader.biWidth * 4) % 4 == 0) // pbi.bmiHeader.biWidth * 4 bytes (For 24 and 32 bpp) - return (pbi.bmiHeader.biWidth * 4); - else - return (pbi.bmiHeader.biWidth * 4) + (4 - (pbi.bmiHeader.biWidth * 4) % 4); + throw new DflException("Illegal color bits bitmap"); }(); + const uint widthBytes = (pbi.bmiHeader.biWidth * bitsPerPixel + 31) / 32 * 4; const uint pixelBufSize = widthBytes * pbi.bmiHeader.biHeight; - ubyte[] buf = (cast(ubyte*)pbi)[0 .. BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * numEntry + pixelBufSize]; + ubyte[] buf = (cast(ubyte*)pbi)[0 .. BITMAPINFOHEADER.sizeof + colorMaskBytes + RGBQUAD.sizeof * numPallet + pixelBufSize]; return buf; } else @@ -1777,57 +1764,42 @@ private: /// -/// - https://learn.microsoft.com/ja-jp/windows/win32/gdi/storing-an-image BITMAPINFO* createBitmapInfo(Bitmap objBitmap) { HBITMAP hBitmap = objBitmap.handle; BITMAP bitmap; - GetObject(hBitmap, BITMAP.sizeof, &bitmap); + GetObject(hBitmap, BITMAP.sizeof, &bitmap); // Gets bitmap info but color bits is not used. HDC hdc = GetDC(null); HDC hdcMem = CreateCompatibleDC(hdc); - // Allocate memory of BITMAPINFO - // - https://learn.microsoft.com/ja-jp/windows/win32/gdi/storing-an-image - - const uint bitsPerPixel = bitmap.bmPlanes * bitmap.bmBitsPixel; - const uint numEntry = { // Assume max number. - if (bitsPerPixel <= 8) // 1, 4, 8 bpp - return 2 ^^ bitsPerPixel; // Assume max number of entries in order to allocate enough memory. - else if (bitsPerPixel == 24) - // Assume max number of entries in order to allocate enough memory. - return 3; - else if (bitsPerPixel <= 32) // 16, 32 bpp - // Assume max number of entries in order to allocate enough memory. - return 3; // biCompression == BI_BITFIELDS - else - assert(0); + // Allocates memory of BITMAPINFO + const uint bitsPerPixel = bitmap.bmPlanes * 32; // 32 bits color + const uint colorMaskBytes = { + // Contains color mask when biCompression is BI_BITFIELDS. + return 4 * 3; // 4 bytes * 3 masks(R,G,B) }(); + const uint numPallet = 0; // Wants that no color palette. + const uint widthBytes = (bitmap.bmWidth * bitsPerPixel + 31) / 32 * 4; + const uint bitmapBodySize = widthBytes * bitmap.bmHeight; - const uint widthBytesSize = { // Assume 32 bits color. - if (bitmap.bmWidth % 4 == 0) - return bitmap.bmWidth * 4; - else - return (bitmap.bmWidth * 4) + (4 - (bitmap.bmWidth * 4) % 4); - }(); - const uint bitmapBodySize = widthBytesSize * bitmap.bmHeight; - - BITMAPINFO* pbi = cast(BITMAPINFO*)new ubyte[BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * numEntry + bitmapBodySize]; + BITMAPINFO* pbi = cast(BITMAPINFO*)new ubyte[ + BITMAPINFOHEADER.sizeof + colorMaskBytes + RGBQUAD.sizeof * numPallet + bitmapBodySize]; // https://learn.microsoft.com/ja-jp/windows/win32/api/wingdi/nf-wingdi-getdibits pbi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; // First 6 members pbi.bmiHeader.biWidth = bitmap.bmWidth; pbi.bmiHeader.biHeight = bitmap.bmHeight; pbi.bmiHeader.biPlanes = bitmap.bmPlanes; - pbi.bmiHeader.biBitCount = 32; - pbi.bmiHeader.biCompression = BI_BITFIELDS; // numEntry == 3 - // pbi.bmiHeader.biSizeImage = // OK - // pbi.bmiHeader.biXPelsPerMeter = // OK - // pbi.bmiHeader.biYPelsPerMeter = // OK - // pbi.bmiHeader.biClrUsed = // OK - // pbi.bmiHeader.biClrImportant = // OK + pbi.bmiHeader.biBitCount = 32; // 32 bits color + pbi.bmiHeader.biCompression = BI_BITFIELDS; // Contains color mask + // pbi.bmiHeader.biSizeImage = // No other members need to be initialized. + // pbi.bmiHeader.biXPelsPerMeter = // ditto + // pbi.bmiHeader.biYPelsPerMeter = // ditto + // pbi.bmiHeader.biClrUsed = // ditto + // pbi.bmiHeader.biClrImportant = // ditto if (0 == core.sys.windows.wingdi.GetDIBits( hdc, hBitmap, 0, bitmap.bmHeight, - cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * numEntry, pbi, DIB_RGB_COLORS)) + cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + colorMaskBytes + RGBQUAD.sizeof * numPallet, pbi, DIB_RGB_COLORS)) { throw new DflException("createBitmapInfo failure"); } @@ -1840,23 +1812,15 @@ BITMAPINFO* createBitmapInfo(Bitmap objBitmap) { for (uint x = 10; x < 30; x++) { - // 32 bits color // uint.sizeof == 32 bytes - uint* p = cast(uint*)(cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * numEntry); + uint* p = cast(uint*)(cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + colorMaskBytes + RGBQUAD.sizeof * numPallet); p[y * bitmap.bmWidth + x] = 0x000000FF; - - // 24 bits color - // ubyte* p = cast(ubyte*)(pbi + BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * numEntry); - // p[y * widthBytesSize + x * 3 + 0] = 0x00000000; // B - // p[y * widthBytesSize + x * 3 + 1] = 0x00000000; // G - // p[y * widthBytesSize + x * 3 + 2] = 0x000000FF; // R - // p[y * widthBytesSize + x * 3 + 3] = 0x00000000; // (A) } } core.sys.windows.wingdi.SetDIBitsToDevice( hdcMem, 0, 0, pbi.bmiHeader.biWidth, pbi.bmiHeader.biHeight, 0, 0, 0, pbi.bmiHeader.biHeight, - cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * numEntry, pbi, DIB_RGB_COLORS); + cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + colorMaskBytes + RGBQUAD.sizeof * numPallet, pbi, DIB_RGB_COLORS); core.sys.windows.wingdi.Rectangle(hdcMem, 0, 0, 50, 50); TextOutW(hdcMem, 0, 0, "createBitmapInfo()"w.ptr, 18); core.sys.windows.wingdi.BitBlt(hdc, 200, 200, pbi.bmiHeader.biWidth, pbi.bmiHeader.biHeight, hdcMem, 0, 0, SRCCOPY); @@ -1872,48 +1836,35 @@ BITMAPINFO* createBitmapInfo(Bitmap objBitmap) /// Bitmap createBitmap(BITMAPINFO* pbi) { - // https://learn.microsoft.com/ja-jp/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader - // http://www5d.biglobe.ne.jp/~noocyte/Programming/Windows/BmpFileFormat.html const uint bitsPerPixel = pbi.bmiHeader.biPlanes * pbi.bmiHeader.biBitCount; - const uint numEntry = { - if (bitsPerPixel <= 8) // 1, 4, 8 bpp + const uint colorMaskBytes = { + if (pbi.bmiHeader.biCompression == BI_BITFIELDS) + return 4 * 3; // 4 bytes * 3 masks(R,G,B) + else + return 0; + }(); + const uint numPallet = { + if (bitsPerPixel <= 8) // 1, 4, 8 bits color { if (pbi.bmiHeader.biClrUsed == 0) - return 2 ^^ bitsPerPixel; + return 2 ^^ bitsPerPixel; // Assume max. else return pbi.bmiHeader.biClrUsed; } - else if (bitsPerPixel == 24) + else if (bitsPerPixel <= 32) // 16, 24, 32 bits color return pbi.bmiHeader.biClrUsed; - else if (bitsPerPixel <= 32) // 16, 32 bpp - { - if (pbi.bmiHeader.biCompression == BI_RGB) - return 3;//pbi.bmiHeader.biClrUsed; // TODO: ? - else if (pbi.bmiHeader.biCompression == BI_BITFIELDS) - return 3; - else - assert(0); - } else - assert(0); + throw new DflException("Illegal color bits bitmap"); }(); - - // if (bitsPerPixel <= 16) // TODO: 1-16 bpp is not implemented... - // throw new DflException("createBitmap() failure"); - HDC hdc = GetDC(null); - - // (BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof) == (BITMAPINFO.sizeof) HBITMAP hBitmap = CreateDIBitmap( hdc, &pbi.bmiHeader, CBM_INIT, - cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * numEntry, pbi, DIB_RGB_COLORS); - + cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + colorMaskBytes + RGBQUAD.sizeof * numPallet, pbi, DIB_RGB_COLORS); // If you called "HBITMAP hOldBitmap = SelectObject(hdc, hBitmap)", // you must call "SelectObject(hdc, hOldBitmap)" before "Image.fromHBitmap()". // The otherwise you will get all black. Bitmap bitmap = Image.fromHBitmap(hBitmap, true); ReleaseDC(null, hdc); - return bitmap; }