DIB Engine: fix vertically mirrored images caused by GetObject() changes
[wine/hacks.git] / dlls / winedib.drv / convert.c
blob5fc7eeacaa37d332ce17a9ec7c69e92479310375
1 /*
2 * DIB Engine conversion routines
3 * Converts DDB <--> DIB
5 * Copyright 2009 Massimo Del Fedele
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include "dibdrv.h"
27 #include "winuser.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(dibdrv);
31 /***********************************************************************
32 * Creates DDB that is compatible with source hdc.
33 * hdc is the HDC on where the DIB MUST be selected in
34 * srcBmp is the source DIB
35 * startScan and scanLines specify the portion of DIB to convert
36 * in order to avoid unneeded conversion of large DIBs on blitting
38 * NOTE : the srcBmp DIB MUST NOT be selected in any DC */
39 HBITMAP _DIBDRV_ConvertDIBtoDDB( HDC hdc, HBITMAP srcBmp, int startScan, int scanLines )
41 DIBSECTION ds;
42 BITMAPINFO *bmi;
43 HBITMAP hBmp = NULL;
45 int dibWidth, dibHeight;
46 BOOL topDown;
47 void *bits;
48 int stride;
49 UINT colorUsed;
50 int bitFields;
51 HDC tmpHdc;
52 HBITMAP tmpBmp;
53 int res;
54 DIBDRVBITMAP *physBitmap;
56 /* gets DIBSECTION data from source DIB */
57 if(GetObjectW(srcBmp, sizeof(DIBSECTION), &ds) != sizeof(DIBSECTION))
59 ERR("Couldn't get DIBSECTION data\n");
60 return 0;
63 /* gets DIB info */
64 dibWidth = ds.dsBmih.biWidth;
65 dibHeight = ds.dsBmih.biHeight;
66 bits = ds.dsBm.bmBits;
67 stride = ((dibWidth * ds.dsBmih.biBitCount +31) &~31) / 8;
69 /* get physical bitmap -- needed for topdown flag */
70 if( (physBitmap = _BITMAPLIST_Get(srcBmp)) == NULL)
72 ERR("Couldn't retrieve physical bitmap\n");
73 return 0;
75 topDown = physBitmap->topdown;
77 /* adjust bits to point at needed starting stripe */
78 if(topDown)
79 /* top-down DIB */
80 bits = (BYTE *)bits + startScan * stride;
81 else
82 bits = (BYTE *)bits + (dibHeight - startScan - scanLines) * stride;
84 /* if requested part is out of source bitmap, returns 0 */
85 if(startScan >= dibHeight)
86 return 0;
87 if(startScan + scanLines >= dibHeight)
88 scanLines = dibHeight - startScan;
90 /* gets the size of DIB palette and bitfields, if any */
91 bitFields = 0;
92 colorUsed = 0;
93 if(ds.dsBmih.biCompression == BI_BITFIELDS)
94 bitFields = 3;
95 else if(ds.dsBmih.biBitCount <= 8)
97 colorUsed = ds.dsBmih.biClrUsed;
98 if(!colorUsed)
99 colorUsed = 1 << ds.dsBmih.biBitCount;
102 /* builds the needed BITMAPINFOHEADER */
103 bmi = HeapAlloc( GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER)+
104 sizeof(RGBQUAD)*colorUsed + sizeof(DWORD) * bitFields );
105 if (!bmi)
107 ERR("HeapAlloc failed\n");
108 return 0;
111 /* copy the header part */
112 memcpy( &bmi->bmiHeader, &ds.dsBmih, sizeof(BITMAPINFOHEADER) );
114 /* gets the color table part, if any */
115 if(colorUsed)
117 /* create a temporary DC, GetDIBColorTable() requests that
118 the DIB is selected in a DC.... */
119 if(!(tmpHdc = CreateCompatibleDC(hdc)))
121 ERR("Couldn't create the temporary HDC\n");
122 HeapFree(GetProcessHeap(), 0, bmi);
123 return 0;
125 /* selects the DIB into the temporary DC */
126 if( !(tmpBmp = SelectObject(tmpHdc, srcBmp)))
128 ERR("Couldn't select source DIB into temporary DC\n");
129 DeleteDC(tmpHdc);
130 HeapFree(GetProcessHeap(), 0, bmi);
131 return 0;
133 if(!GetDIBColorTable(tmpHdc, 0, colorUsed, bmi->bmiColors))
134 ERR("GetDIBColorTable failed\n");
135 SelectObject(tmpHdc, tmpBmp);
136 DeleteDC(tmpHdc);
140 /* fill the bitfields part, if any */
141 if(bitFields)
142 memcpy(bmi->bmiColors, ds.dsBitfields, 3 * sizeof(DWORD));
144 /* adjust dib size for SetDIBits, as it needs it to reverse top-down dibs
145 it must be set to the number of scanLines to transfer */
146 bmi->bmiHeader.biHeight = topDown ? -scanLines : scanLines;
148 /* creates destination compatible bitmap */
149 tmpHdc = GetDC(NULL);
150 hBmp = CreateCompatibleBitmap(tmpHdc, dibWidth, scanLines);
151 ReleaseDC(NULL, tmpHdc);
152 if(!hBmp)
154 ERR("CreateCompatibleBitmap failed\n");
155 HeapFree( GetProcessHeap(), 0, bmi );
156 return 0;
159 /* copies the requested scan lines from DIB to DDB */
160 /* FIXME : still no support for RLE packed DIBs */
161 res = SetDIBits( hdc, hBmp, 0, scanLines, bits, bmi, DIB_RGB_COLORS );
162 HeapFree( GetProcessHeap(), 0, bmi );
163 if(!res)
165 ERR("SetDIBits failed\n");
166 DeleteObject( hBmp );
167 return 0;
170 return hBmp;
173 /***********************************************************************
174 * Creates DIB that is compatible with the target hdc.
175 * startScan and scanLines specify the portion of DDB to convert
176 * in order to avoid unneeded conversion of large DDBs on blitting
178 * NOTE : the srcBmp DDB MUST NOT be selected in any DC */
179 HBITMAP _DIBDRV_ConvertDDBtoDIB( HDC hdc, HBITMAP srcBmp, int startScan, int scanLines )
181 HBITMAP hBmp = NULL;
182 BITMAP bitmap;
183 BITMAPINFO *bi;
184 void *bits = NULL;
186 if (!GetObjectW( srcBmp, sizeof(bitmap), &bitmap ))
188 ERR("Couldn't retrieve source bitmap\n");
189 return 0;
192 if(startScan + scanLines >= bitmap.bmHeight)
193 scanLines = bitmap.bmHeight - startScan;
195 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) /* + 256 * sizeof(RGBQUAD) */);
196 if (!bi)
198 ERR("HeapAlloc failed\n");
199 return 0;
202 bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
203 bi->bmiHeader.biWidth = bitmap.bmWidth;
204 bi->bmiHeader.biHeight = scanLines;
205 bi->bmiHeader.biPlanes = bitmap.bmPlanes;
206 bi->bmiHeader.biBitCount = 32;
207 bi->bmiHeader.biCompression = BI_RGB;
208 bi->bmiHeader.biSizeImage = 0;
210 /* No need to get the color table or the color masks
211 as we're requesting a 32 bit rgba DIB */
213 /* Create bitmap and fill in bits */
214 hBmp = CreateDIBSection(hdc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
215 if(!hBmp)
217 ERR("Failed to create DIB section\n");
218 HeapFree( GetProcessHeap(), 0, bi );
219 return 0;
221 if (bits)
223 if(!GetDIBits(hdc, srcBmp, startScan, scanLines, bits, bi, DIB_RGB_COLORS))
225 ERR("GetDIBits failed\n");
226 DeleteObject( hBmp );
227 HeapFree( GetProcessHeap(), 0, bi );
228 return 0;
231 else
233 ERR("CreateDibSection couldn't allocate DIB bits\n");
234 DeleteObject( hBmp );
235 HeapFree( GetProcessHeap(), 0, bi );
236 return 0;
238 HeapFree( GetProcessHeap(), 0, bi );
239 return hBmp;
242 /***********************************************************************
243 * BITBLT_ConvertDevDDBtoDIB
245 * Creates DIB that is compatible with the target hdc for a device (non memory) source DC */
246 HBITMAP _DIBDRV_ConvertDevDDBtoDIB( HDC hdcSrc, HDC hdcDst, int xSrc, int ySrc, int width, int height )
248 HBITMAP bmp, dib;
249 HDC memHDC = NULL;
251 /* at first, we create a compatible DC and a bitmap with needed sizes */
252 memHDC = CreateCompatibleDC(hdcSrc);
253 if(!memHDC)
255 ERR("CreateCompatibleDC failed\n");
256 return 0;
258 bmp = CreateCompatibleBitmap(hdcSrc, width, height);
259 if(!bmp)
261 ERR("CreateCompatibleBitmap failed\n");
262 DeleteDC(memHDC);
263 return 0;
266 /* select the newly created DDB into the temporary DC */
267 bmp = SelectObject(memHDC, bmp);
268 if(!bmp)
270 ERR("Failed selecting DDB into temporary DC\n");
271 DeleteObject(bmp);
272 DeleteDC(memHDC);
273 return 0;
276 /* next, we blit pixels from device to the compatible bitmap */
277 if(!BitBlt(memHDC, 0, 0, width, height, hdcSrc, xSrc, ySrc, SRCCOPY))
279 ERR("BitBlt failed\n");
280 DeleteObject(bmp);
281 DeleteDC(memHDC);
282 return 0;
285 /* select out the DDB from the temporary DC */
286 bmp = SelectObject(memHDC, bmp);
287 DeleteDC(memHDC);
288 if(!bmp)
290 ERR("Failed selecting DDB out temporary DC\n");
291 DeleteObject(bmp);
292 return 0;
295 /*now we can convert the bitmap to a DIB */
296 dib = _DIBDRV_ConvertDDBtoDIB( hdcDst, bmp, 0, height );
297 if(!dib)
298 FIXME("ConvertDDBtoDIB failed\n");
300 /* free resources and return the created dib */
301 DeleteObject(bmp);
302 return dib;