netapi32: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / gphoto2.ds / ds_image.c
blob55bd6a2908a9e1050266f25948340f427f446666
1 /*
2 * Copyright 2000 Corel Corporation
3 * Copyright 2006 Marcus Meissner
4 * Copyright 2006 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
25 #include "gphoto2_i.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "unixlib.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(twain);
33 /* for the jpeg decompressor source manager. */
34 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
36 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
37 ERR("(), should not get here.\n");
38 return FALSE;
41 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
42 TRACE("Skipping %ld bytes...\n", num_bytes);
43 cinfo->src->next_input_byte += num_bytes;
44 cinfo->src->bytes_in_buffer -= num_bytes;
47 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
48 ERR("(desired=%d), should not get here.\n",desired);
49 return FALSE;
51 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
53 static void close_file( UINT64 handle )
55 struct close_file_params params = { handle };
56 GPHOTO2_CALL( close_file, &params );
59 static void close_current_file(void)
61 close_file( activeDS.file_handle );
62 activeDS.file_handle = 0;
63 free( activeDS.file_data );
66 /* DG_IMAGE/DAT_CIECOLOR/MSG_GET */
67 TW_UINT16 GPHOTO2_CIEColorGet (pTW_IDENTITY pOrigin,
68 TW_MEMREF pData)
70 FIXME ("stub!\n");
72 return TWRC_FAILURE;
75 /* DG_IMAGE/DAT_EXTIMAGEINFO/MSG_GET */
76 TW_UINT16 GPHOTO2_ExtImageInfoGet (pTW_IDENTITY pOrigin,
77 TW_MEMREF pData)
79 FIXME ("stub!\n");
81 return TWRC_FAILURE;
84 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_RESET */
85 TW_UINT16 GPHOTO2_GrayResponseReset (pTW_IDENTITY pOrigin,
86 TW_MEMREF pData)
88 FIXME ("stub!\n");
90 return TWRC_FAILURE;
93 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_SET */
94 TW_UINT16 GPHOTO2_GrayResponseSet (pTW_IDENTITY pOrigin,
95 TW_MEMREF pData)
97 FIXME ("stub!\n");
99 return TWRC_FAILURE;
102 /* DG_IMAGE/DAT_IMAGEFILEXFER/MSG_GET */
103 TW_UINT16 GPHOTO2_ImageFileXferGet (pTW_IDENTITY pOrigin,
104 TW_MEMREF pData)
106 FIXME ("stub!\n");
108 return TWRC_FAILURE;
111 static TW_UINT16 _get_image_and_startup_jpeg(void) {
112 unsigned int i;
113 int ret;
114 struct open_file_params open_params;
115 struct get_file_data_params get_data_params;
117 if (activeDS.file_handle) /* Already loaded. */
118 return TWRC_SUCCESS;
120 for (i = 0; i < activeDS.file_count; i++)
122 if (activeDS.download_flags[i])
124 activeDS.download_flags[i] = FALSE; /* mark as done */
125 break;
128 if (i == activeDS.file_count)
130 activeDS.twCC = TWCC_SEQERROR;
131 return TWRC_FAILURE;
134 open_params.idx = i;
135 open_params.preview = FALSE;
136 open_params.handle = &activeDS.file_handle;
137 open_params.size = &activeDS.file_size;
138 if (GPHOTO2_CALL( open_file, &open_params ))
140 activeDS.twCC = TWCC_SEQERROR;
141 return TWRC_FAILURE;
144 activeDS.file_data = malloc( activeDS.file_size );
145 get_data_params.handle = activeDS.file_handle;
146 get_data_params.data = activeDS.file_data;
147 get_data_params.size = activeDS.file_size;
148 if (GPHOTO2_CALL( get_file_data, &get_data_params ))
150 activeDS.twCC = TWCC_SEQERROR;
151 return TWRC_FAILURE;
154 /* This is basically so we can use in-memory data for jpeg decompression.
155 * We need to have all the functions.
157 activeDS.xjsm.next_input_byte = activeDS.file_data;
158 activeDS.xjsm.bytes_in_buffer = activeDS.file_size;
159 activeDS.xjsm.init_source = _jpeg_init_source;
160 activeDS.xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
161 activeDS.xjsm.skip_input_data = _jpeg_skip_input_data;
162 activeDS.xjsm.resync_to_restart = _jpeg_resync_to_restart;
163 activeDS.xjsm.term_source = _jpeg_term_source;
165 activeDS.jd.err = jpeg_std_error(&activeDS.jerr);
166 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
167 * jpeg_create_decompress(&jd); */
168 jpeg_CreateDecompress(&activeDS.jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
169 activeDS.jd.src = &activeDS.xjsm;
170 ret=jpeg_read_header(&activeDS.jd,TRUE);
171 activeDS.jd.out_color_space = JCS_RGB;
172 jpeg_start_decompress(&activeDS.jd);
173 if (ret != JPEG_HEADER_OK) {
174 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
175 close_current_file();
176 return TWRC_FAILURE;
178 return TWRC_SUCCESS;
181 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
182 TW_UINT16 GPHOTO2_ImageInfoGet (pTW_IDENTITY pOrigin,
183 TW_MEMREF pData)
185 pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
187 TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
189 if (activeDS.currentState != 6 && activeDS.currentState != 7) {
190 activeDS.twCC = TWCC_SEQERROR;
191 return TWRC_FAILURE;
193 if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) {
194 FIXME("Failed to get an image\n");
195 activeDS.twCC = TWCC_SEQERROR;
196 return TWRC_FAILURE;
198 if (activeDS.currentState == 6)
200 /* return general image description information about the image about to be transferred */
201 TRACE("Getting parameters\n");
203 TRACE("activeDS.jd.output_width = %d\n", activeDS.jd.output_width);
204 TRACE("activeDS.jd.output_height = %d\n", activeDS.jd.output_height);
205 pImageInfo->Compression = TWCP_NONE;
206 pImageInfo->SamplesPerPixel = 3;
207 pImageInfo->BitsPerSample[0]= 8;
208 pImageInfo->BitsPerSample[1]= 8;
209 pImageInfo->BitsPerSample[2]= 8;
210 pImageInfo->PixelType = TWPT_RGB;
211 pImageInfo->Planar = FALSE; /* R-G-B is chunky! */
212 pImageInfo->XResolution.Whole = -1;
213 pImageInfo->XResolution.Frac = 0;
214 pImageInfo->YResolution.Whole = -1;
215 pImageInfo->YResolution.Frac = 0;
216 pImageInfo->ImageWidth = activeDS.jd.output_width;
217 pImageInfo->ImageLength = activeDS.jd.output_height;
218 pImageInfo->BitsPerPixel = 24;
219 return TWRC_SUCCESS;
222 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
223 TW_UINT16 GPHOTO2_ImageLayoutGet (pTW_IDENTITY pOrigin,
224 TW_MEMREF pData)
226 FIXME ("stub!\n");
228 return TWRC_FAILURE;
231 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
232 TW_UINT16 GPHOTO2_ImageLayoutGetDefault (pTW_IDENTITY pOrigin,
233 TW_MEMREF pData)
235 FIXME ("stub!\n");
237 return TWRC_FAILURE;
240 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
241 TW_UINT16 GPHOTO2_ImageLayoutReset (pTW_IDENTITY pOrigin,
242 TW_MEMREF pData)
244 FIXME ("stub!\n");
246 return TWRC_FAILURE;
249 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
250 TW_UINT16 GPHOTO2_ImageLayoutSet (pTW_IDENTITY pOrigin,
251 TW_MEMREF pData)
253 FIXME ("stub!\n");
255 return TWRC_FAILURE;
258 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
259 TW_UINT16 GPHOTO2_ImageMemXferGet (pTW_IDENTITY pOrigin,
260 TW_MEMREF pData)
262 TW_UINT16 twRC = TWRC_SUCCESS;
263 pTW_IMAGEMEMXFER pImageMemXfer = (pTW_IMAGEMEMXFER) pData;
264 LPBYTE buffer;
265 int readrows;
266 unsigned int curoff;
268 TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
269 if (activeDS.currentState < 6 || activeDS.currentState > 7) {
270 activeDS.twCC = TWCC_SEQERROR;
271 return TWRC_FAILURE;
273 TRACE("pImageMemXfer.Compression is %d\n", pImageMemXfer->Compression);
274 if (activeDS.currentState == 6) {
275 if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) {
276 FIXME("Failed to get an image\n");
277 activeDS.twCC = TWCC_SEQERROR;
278 return TWRC_FAILURE;
281 if (!activeDS.progressWnd)
282 activeDS.progressWnd = TransferringDialogBox(NULL,0);
283 TransferringDialogBox(activeDS.progressWnd,0);
285 activeDS.currentState = 7;
286 } else {
287 if (!activeDS.file_handle) {
288 activeDS.twCC = TWRC_SUCCESS;
289 return TWRC_XFERDONE;
293 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE) {
294 FIXME("Memory Handle, may not be locked correctly\n");
295 buffer = LocalLock(pImageMemXfer->Memory.TheMem);
296 } else
297 buffer = pImageMemXfer->Memory.TheMem;
299 memset(buffer,0,pImageMemXfer->Memory.Length);
300 curoff = 0; readrows = 0;
301 pImageMemXfer->YOffset = activeDS.jd.output_scanline;
302 pImageMemXfer->XOffset = 0; /* we do whole strips */
303 while ((activeDS.jd.output_scanline<activeDS.jd.output_height) &&
304 ((pImageMemXfer->Memory.Length - curoff) > activeDS.jd.output_width*activeDS.jd.output_components)
306 JSAMPROW row = buffer+curoff;
307 int x = jpeg_read_scanlines(&activeDS.jd,&row,1);
308 if (x != 1) {
309 FIXME("failed to read current scanline?\n");
310 break;
312 readrows++;
313 curoff += activeDS.jd.output_width*activeDS.jd.output_components;
315 pImageMemXfer->Compression = TWCP_NONE;
316 pImageMemXfer->BytesPerRow = activeDS.jd.output_components * activeDS.jd.output_width;
317 pImageMemXfer->Rows = readrows;
318 pImageMemXfer->Columns = activeDS.jd.output_width; /* we do whole strips */
319 pImageMemXfer->BytesWritten = curoff;
321 TransferringDialogBox(activeDS.progressWnd,0);
323 if (activeDS.jd.output_scanline == activeDS.jd.output_height) {
324 jpeg_finish_decompress(&activeDS.jd);
325 jpeg_destroy_decompress(&activeDS.jd);
326 close_current_file();
327 TRACE("xfer is done!\n");
329 /*TransferringDialogBox(activeDS.progressWnd, -1);*/
330 twRC = TWRC_XFERDONE;
332 activeDS.twCC = TWRC_SUCCESS;
333 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
334 LocalUnlock(pImageMemXfer->Memory.TheMem);
335 return twRC;
338 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
339 TW_UINT16 GPHOTO2_ImageNativeXferGet (pTW_IDENTITY pOrigin,
340 TW_MEMREF pData)
342 pTW_UINT32 pHandle = (pTW_UINT32) pData;
343 HBITMAP hDIB;
344 BITMAPINFO bmpInfo;
345 LPBYTE bits;
346 JSAMPROW samprow, oldsamprow;
348 FIXME("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET: implemented, but expect program crash due to DIB.\n");
350 /* NOTE NOTE NOTE NOTE NOTE NOTE NOTE
352 * While this is a mandatory transfer mode and this function
353 * is correctly implemented and fully works, the calling program
354 * will likely crash after calling.
356 * Reason is that there is a lot of example code that does:
357 * bmpinfo = GlobalLock(hBITMAP); ... pointer access to bmpinfo
359 * Our current HBITMAP handles do not support getting GlobalLocked -> App Crash
361 * This needs a GDI Handle rewrite, at least for DIB sections.
362 * - Marcus
364 if (activeDS.currentState != 6) {
365 activeDS.twCC = TWCC_SEQERROR;
366 return TWRC_FAILURE;
368 if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) {
369 FIXME("Failed to get an image\n");
370 activeDS.twCC = TWCC_OPERATIONERROR;
371 return TWRC_FAILURE;
373 TRACE("Acquiring image %dx%dx%d bits from gphoto.\n",
374 activeDS.jd.output_width, activeDS.jd.output_height,
375 activeDS.jd.output_components*8);
376 ZeroMemory (&bmpInfo, sizeof (BITMAPINFO));
377 bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
378 bmpInfo.bmiHeader.biWidth = activeDS.jd.output_width;
379 bmpInfo.bmiHeader.biHeight = -activeDS.jd.output_height;
380 bmpInfo.bmiHeader.biPlanes = 1;
381 bmpInfo.bmiHeader.biBitCount = activeDS.jd.output_components*8;
382 bmpInfo.bmiHeader.biCompression = BI_RGB;
383 bmpInfo.bmiHeader.biSizeImage = 0;
384 bmpInfo.bmiHeader.biXPelsPerMeter = 0;
385 bmpInfo.bmiHeader.biYPelsPerMeter = 0;
386 bmpInfo.bmiHeader.biClrUsed = 0;
387 bmpInfo.bmiHeader.biClrImportant = 0;
388 hDIB = CreateDIBSection (0, &bmpInfo, DIB_RGB_COLORS, (LPVOID)&bits, 0, 0);
389 if (!hDIB) {
390 FIXME("Failed creating DIB.\n");
391 close_current_file();
392 activeDS.twCC = TWCC_LOWMEMORY;
393 return TWRC_FAILURE;
395 samprow = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,activeDS.jd.output_width*activeDS.jd.output_components);
396 oldsamprow = samprow;
397 while ( activeDS.jd.output_scanline<activeDS.jd.output_height ) {
398 unsigned int i;
399 int x = jpeg_read_scanlines(&activeDS.jd,&samprow,1);
400 if (x != 1) {
401 FIXME("failed to read current scanline?\n");
402 break;
404 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
405 for(i=0;i<activeDS.jd.output_width;i++,samprow+=activeDS.jd.output_components) {
406 *(bits++) = *(samprow+2);
407 *(bits++) = *(samprow+1);
408 *(bits++) = *(samprow);
410 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
411 samprow = oldsamprow;
413 HeapFree (GetProcessHeap(), 0, samprow);
414 close_current_file();
415 *pHandle = (UINT_PTR)hDIB;
416 activeDS.twCC = TWCC_SUCCESS;
417 activeDS.currentState = 7;
418 return TWRC_XFERDONE;
421 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GET */
422 TW_UINT16 GPHOTO2_JPEGCompressionGet (pTW_IDENTITY pOrigin,
423 TW_MEMREF pData)
425 FIXME ("stub!\n");
427 return TWRC_FAILURE;
430 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GETDEFAULT */
431 TW_UINT16 GPHOTO2_JPEGCompressionGetDefault (pTW_IDENTITY pOrigin,
433 TW_MEMREF pData)
435 FIXME ("stub!\n");
437 return TWRC_FAILURE;
440 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_RESET */
441 TW_UINT16 GPHOTO2_JPEGCompressionReset (pTW_IDENTITY pOrigin,
442 TW_MEMREF pData)
444 FIXME ("stub!\n");
446 return TWRC_FAILURE;
449 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_SET */
450 TW_UINT16 GPHOTO2_JPEGCompressionSet (pTW_IDENTITY pOrigin,
451 TW_MEMREF pData)
453 FIXME ("stub!\n");
455 return TWRC_FAILURE;
458 /* DG_IMAGE/DAT_PALETTE8/MSG_GET */
459 TW_UINT16 GPHOTO2_Palette8Get (pTW_IDENTITY pOrigin,
460 TW_MEMREF pData)
462 FIXME ("stub!\n");
464 return TWRC_FAILURE;
467 /* DG_IMAGE/DAT_PALETTE8/MSG_GETDEFAULT */
468 TW_UINT16 GPHOTO2_Palette8GetDefault (pTW_IDENTITY pOrigin,
469 TW_MEMREF pData)
471 FIXME ("stub!\n");
473 return TWRC_FAILURE;
476 /* DG_IMAGE/DAT_PALETTE8/MSG_RESET */
477 TW_UINT16 GPHOTO2_Palette8Reset (pTW_IDENTITY pOrigin,
478 TW_MEMREF pData)
480 FIXME ("stub!\n");
482 return TWRC_FAILURE;
485 /* DG_IMAGE/DAT_PALETTE8/MSG_SET */
486 TW_UINT16 GPHOTO2_Palette8Set (pTW_IDENTITY pOrigin,
487 TW_MEMREF pData)
489 FIXME ("stub!\n");
491 return TWRC_FAILURE;
494 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_RESET */
495 TW_UINT16 GPHOTO2_RGBResponseReset (pTW_IDENTITY pOrigin,
496 TW_MEMREF pData)
498 FIXME ("stub!\n");
500 return TWRC_FAILURE;
503 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_SET */
504 TW_UINT16 GPHOTO2_RGBResponseSet (pTW_IDENTITY pOrigin,
505 TW_MEMREF pData)
507 FIXME ("stub!\n");
509 return TWRC_FAILURE;
512 TW_UINT16
513 _get_gphoto2_file_as_DIB( unsigned int idx, BOOL preview, HWND hwnd, HBITMAP *hDIB )
515 unsigned char *filedata;
516 int ret;
517 struct jpeg_source_mgr xjsm;
518 struct jpeg_decompress_struct jd;
519 struct jpeg_error_mgr jerr;
520 BITMAPINFO bmpInfo;
521 LPBYTE bits;
522 JSAMPROW samprow, oldsamprow;
523 struct open_file_params open_params;
524 struct get_file_data_params get_data_params;
525 UINT64 file_handle;
526 unsigned int filesize;
528 open_params.idx = idx;
529 open_params.preview = preview;
530 open_params.handle = &file_handle;
531 open_params.size = &filesize;
532 if (GPHOTO2_CALL( open_file, &open_params ))
534 FIXME( "Failed to get file %u\n", idx);
535 return TWRC_FAILURE;
537 filedata = malloc( filesize );
538 get_data_params.handle = file_handle;
539 get_data_params.data = filedata;
540 get_data_params.size = filesize;
541 if (GPHOTO2_CALL( get_file_data, &get_data_params ))
543 close_file( file_handle );
544 free( filedata );
545 return TWRC_FAILURE;
548 /* FIXME: Actually we might get other types than JPEG ... But only handle JPEG for now */
549 if (filedata[0] != 0xff) {
550 ERR("File %u might not be JPEG, cannot decode!\n", idx);
553 /* This is basically so we can use in-memory data for jpeg decompression.
554 * We need to have all the functions.
556 xjsm.next_input_byte = filedata;
557 xjsm.bytes_in_buffer = filesize;
558 xjsm.init_source = _jpeg_init_source;
559 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
560 xjsm.skip_input_data = _jpeg_skip_input_data;
561 xjsm.resync_to_restart = _jpeg_resync_to_restart;
562 xjsm.term_source = _jpeg_term_source;
564 jd.err = jpeg_std_error(&jerr);
565 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
566 * jpeg_create_decompress(&jd); */
567 jpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
568 jd.src = &xjsm;
569 ret=jpeg_read_header(&jd,TRUE);
570 jd.out_color_space = JCS_RGB;
571 jpeg_start_decompress(&jd);
572 if (ret != JPEG_HEADER_OK) {
573 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
574 close_file( file_handle );
575 free( filedata );
576 return TWRC_FAILURE;
579 ZeroMemory (&bmpInfo, sizeof (BITMAPINFO));
580 bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
581 bmpInfo.bmiHeader.biWidth = jd.output_width;
582 bmpInfo.bmiHeader.biHeight = -jd.output_height;
583 bmpInfo.bmiHeader.biPlanes = 1;
584 bmpInfo.bmiHeader.biBitCount = jd.output_components*8;
585 bmpInfo.bmiHeader.biCompression = BI_RGB;
586 bmpInfo.bmiHeader.biSizeImage = 0;
587 bmpInfo.bmiHeader.biXPelsPerMeter = 0;
588 bmpInfo.bmiHeader.biYPelsPerMeter = 0;
589 bmpInfo.bmiHeader.biClrUsed = 0;
590 bmpInfo.bmiHeader.biClrImportant = 0;
591 *hDIB = CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, (LPVOID)&bits, 0, 0);
592 if (!*hDIB) {
593 FIXME("Failed creating DIB.\n");
594 close_file( file_handle );
595 free( filedata );
596 return TWRC_FAILURE;
598 samprow = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
599 oldsamprow = samprow;
600 while ( jd.output_scanline<jd.output_height ) {
601 unsigned int i;
602 int x = jpeg_read_scanlines(&jd,&samprow,1);
603 if (x != 1) {
604 FIXME("failed to read current scanline?\n");
605 break;
607 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
608 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
609 *(bits++) = *(samprow+2);
610 *(bits++) = *(samprow+1);
611 *(bits++) = *(samprow);
613 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
614 samprow = oldsamprow;
616 HeapFree (GetProcessHeap(), 0, samprow);
617 close_file( file_handle );
618 free( filedata );
619 return TWRC_SUCCESS;