gdi32: Don't free a driver when it's popped from the stack.
[wine] / dlls / gphoto2.ds / ds_image.c
1 /*
2  * Copyright 2000 Corel Corporation
3  * Copyright 2006 Marcus Meissner
4  * Copyright 2006 CodeWeavers, Aric Stewart
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "gphoto2_i.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "wine/library.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(twain);
34
35 #ifdef HAVE_GPHOTO2
36 static void *libjpeg_handle;
37 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
38 MAKE_FUNCPTR(jpeg_std_error);
39 MAKE_FUNCPTR(jpeg_CreateDecompress);
40 MAKE_FUNCPTR(jpeg_read_header);
41 MAKE_FUNCPTR(jpeg_start_decompress);
42 MAKE_FUNCPTR(jpeg_read_scanlines);
43 MAKE_FUNCPTR(jpeg_finish_decompress);
44 MAKE_FUNCPTR(jpeg_destroy_decompress);
45 #undef MAKE_FUNCPTR
46
47 static void *load_libjpeg(void)
48 {
49     if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
50
51 #define LOAD_FUNCPTR(f) \
52     if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
53         libjpeg_handle = NULL; \
54         return NULL; \
55     }
56
57         LOAD_FUNCPTR(jpeg_std_error);
58         LOAD_FUNCPTR(jpeg_CreateDecompress);
59         LOAD_FUNCPTR(jpeg_read_header);
60         LOAD_FUNCPTR(jpeg_start_decompress);
61         LOAD_FUNCPTR(jpeg_read_scanlines);
62         LOAD_FUNCPTR(jpeg_finish_decompress);
63         LOAD_FUNCPTR(jpeg_destroy_decompress);
64 #undef LOAD_FUNCPTR
65     }
66     return libjpeg_handle;
67 }
68
69
70 /* for the jpeg decompressor source manager. */
71 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
72
73 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
74     ERR("(), should not get here.\n");
75     return FALSE;
76 }
77
78 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
79     TRACE("Skipping %ld bytes...\n", num_bytes);
80     cinfo->src->next_input_byte += num_bytes;
81     cinfo->src->bytes_in_buffer -= num_bytes;
82 }
83
84 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
85     ERR("(desired=%d), should not get here.\n",desired);
86     return FALSE;
87 }
88 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
89 #endif
90
91 /* DG_IMAGE/DAT_CIECOLOR/MSG_GET */
92 TW_UINT16 GPHOTO2_CIEColorGet (pTW_IDENTITY pOrigin, 
93                              TW_MEMREF pData)
94 {
95     FIXME ("stub!\n");
96
97     return TWRC_FAILURE;
98 }
99
100 /* DG_IMAGE/DAT_EXTIMAGEINFO/MSG_GET */
101 TW_UINT16 GPHOTO2_ExtImageInfoGet (pTW_IDENTITY pOrigin, 
102                                  TW_MEMREF pData)
103 {
104     FIXME ("stub!\n");
105
106     return TWRC_FAILURE;
107 }
108
109 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_RESET */
110 TW_UINT16 GPHOTO2_GrayResponseReset (pTW_IDENTITY pOrigin, 
111                                    TW_MEMREF pData)
112 {
113     FIXME ("stub!\n");
114
115     return TWRC_FAILURE;
116 }
117
118 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_SET */
119 TW_UINT16 GPHOTO2_GrayResponseSet (pTW_IDENTITY pOrigin, 
120                                  TW_MEMREF pData)
121 {
122     FIXME ("stub!\n");
123
124     return TWRC_FAILURE;
125 }
126
127 /* DG_IMAGE/DAT_IMAGEFILEXFER/MSG_GET */
128 TW_UINT16 GPHOTO2_ImageFileXferGet (pTW_IDENTITY pOrigin, 
129                                   TW_MEMREF pData)
130 {
131     FIXME ("stub!\n");
132
133     return TWRC_FAILURE;
134 }
135
136 #ifdef HAVE_GPHOTO2
137 static TW_UINT16 _get_image_and_startup_jpeg(void) {
138     const char *folder = NULL, *filename = NULL;
139     struct gphoto2_file *file;
140     const unsigned char *filedata;
141     unsigned long filesize;
142     int ret;
143
144     if (activeDS.file) /* Already loaded. */
145         return TWRC_SUCCESS;
146
147     if(!libjpeg_handle) {
148         if(!load_libjpeg()) {
149             FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
150             filedata = NULL;
151             return TWRC_FAILURE;
152         }
153     }
154
155     LIST_FOR_EACH_ENTRY( file, &activeDS.files, struct gphoto2_file, entry ) {
156         if (strstr(file->filename,".JPG") || strstr(file->filename,".jpg")) {
157             filename = file->filename;
158             folder = file->folder;
159             TRACE("downloading %s/%s\n", folder, filename);
160             if (file->download) {
161                 file->download = FALSE; /* mark as done */
162                 break;
163             }
164         }
165     }
166     gp_file_new (&activeDS.file);
167     ret = gp_camera_file_get(activeDS.camera, folder, filename, GP_FILE_TYPE_NORMAL,
168                              activeDS.file, activeDS.context);
169     if (ret < GP_OK) {
170         FIXME("Failed to get file?\n");
171         activeDS.twCC = TWCC_SEQERROR;
172         return TWRC_FAILURE;
173     }
174     ret = gp_file_get_data_and_size (activeDS.file, (const char**)&filedata, &filesize);
175     if (ret < GP_OK) {
176         FIXME("Failed to get file data?\n");
177         activeDS.twCC = TWCC_SEQERROR;
178         return TWRC_FAILURE;
179     }
180
181     /* This is basically so we can use in-memory data for jpeg decompression.
182      * We need to have all the functions.
183      */
184     activeDS.xjsm.next_input_byte       = filedata;
185     activeDS.xjsm.bytes_in_buffer       = filesize;
186     activeDS.xjsm.init_source   = _jpeg_init_source;
187     activeDS.xjsm.fill_input_buffer     = _jpeg_fill_input_buffer;
188     activeDS.xjsm.skip_input_data       = _jpeg_skip_input_data;
189     activeDS.xjsm.resync_to_restart     = _jpeg_resync_to_restart;
190     activeDS.xjsm.term_source   = _jpeg_term_source;
191
192     activeDS.jd.err = pjpeg_std_error(&activeDS.jerr);
193     /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
194      * jpeg_create_decompress(&jd); */
195     pjpeg_CreateDecompress(&activeDS.jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
196     activeDS.jd.src = &activeDS.xjsm;
197     ret=pjpeg_read_header(&activeDS.jd,TRUE);
198     activeDS.jd.out_color_space = JCS_RGB;
199     pjpeg_start_decompress(&activeDS.jd);
200     if (ret != JPEG_HEADER_OK) {
201         ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
202         gp_file_unref (activeDS.file);
203         activeDS.file = NULL;
204         return TWRC_FAILURE;
205     }
206     return TWRC_SUCCESS;
207 }
208 #endif
209
210 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
211 TW_UINT16 GPHOTO2_ImageInfoGet (pTW_IDENTITY pOrigin, 
212                               TW_MEMREF pData)
213 {
214 #ifdef HAVE_GPHOTO2
215     pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
216
217     TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
218
219     if (activeDS.currentState != 6 && activeDS.currentState != 7) {
220         activeDS.twCC = TWCC_SEQERROR;
221         return TWRC_FAILURE;
222     }
223     if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) {
224         FIXME("Failed to get an image\n");
225         activeDS.twCC = TWCC_SEQERROR;
226         return TWRC_FAILURE;
227     }
228     if (activeDS.currentState == 6)
229     {
230         /* return general image description information about the image about to be transferred */
231         TRACE("Getting parameters\n");
232     }
233     TRACE("activeDS.jd.output_width = %d\n", activeDS.jd.output_width);
234     TRACE("activeDS.jd.output_height = %d\n", activeDS.jd.output_height);
235     pImageInfo->Compression     = TWCP_NONE;
236     pImageInfo->SamplesPerPixel = 3;
237     pImageInfo->BitsPerSample[0]= 8;
238     pImageInfo->BitsPerSample[1]= 8;
239     pImageInfo->BitsPerSample[2]= 8;
240     pImageInfo->PixelType       = TWPT_RGB;
241     pImageInfo->Planar          = FALSE; /* R-G-B is chunky! */
242     pImageInfo->XResolution.Whole = -1;
243     pImageInfo->XResolution.Frac = 0;
244     pImageInfo->YResolution.Whole = -1;
245     pImageInfo->YResolution.Frac = 0;
246     pImageInfo->ImageWidth      = activeDS.jd.output_width;
247     pImageInfo->ImageLength     = activeDS.jd.output_height;
248     pImageInfo->BitsPerPixel    = 24;
249     return TWRC_SUCCESS;
250 #else
251     return TWRC_FAILURE;
252 #endif
253 }
254
255 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
256 TW_UINT16 GPHOTO2_ImageLayoutGet (pTW_IDENTITY pOrigin, 
257                                 TW_MEMREF pData)
258 {
259     FIXME ("stub!\n");
260
261     return TWRC_FAILURE;
262 }
263
264 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
265 TW_UINT16 GPHOTO2_ImageLayoutGetDefault (pTW_IDENTITY pOrigin, 
266                                        TW_MEMREF pData)
267 {
268     FIXME ("stub!\n");
269
270     return TWRC_FAILURE;
271 }
272
273 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
274 TW_UINT16 GPHOTO2_ImageLayoutReset (pTW_IDENTITY pOrigin, 
275                                   TW_MEMREF pData)
276 {
277     FIXME ("stub!\n");
278
279     return TWRC_FAILURE;
280 }
281
282 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
283 TW_UINT16 GPHOTO2_ImageLayoutSet (pTW_IDENTITY pOrigin, 
284                                 TW_MEMREF pData)
285 {
286     FIXME ("stub!\n");
287
288     return TWRC_FAILURE;
289 }
290
291 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
292 TW_UINT16 GPHOTO2_ImageMemXferGet (pTW_IDENTITY pOrigin, 
293                                  TW_MEMREF pData)
294 {
295 #ifdef HAVE_GPHOTO2
296     TW_UINT16 twRC = TWRC_SUCCESS;
297     pTW_IMAGEMEMXFER pImageMemXfer = (pTW_IMAGEMEMXFER) pData;
298     LPBYTE buffer;
299     int readrows;
300     unsigned int curoff;
301
302     TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
303     if (activeDS.currentState < 6 || activeDS.currentState > 7) {
304         activeDS.twCC = TWCC_SEQERROR;
305         return TWRC_FAILURE;
306     }
307     TRACE("pImageMemXfer.Compression is %d\n", pImageMemXfer->Compression);
308     if (activeDS.currentState == 6) {
309         if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) {
310             FIXME("Failed to get an image\n");
311             activeDS.twCC = TWCC_SEQERROR;
312             return TWRC_FAILURE;
313         }
314
315     if (!activeDS.progressWnd)
316         activeDS.progressWnd = TransferringDialogBox(NULL,0);
317     TransferringDialogBox(activeDS.progressWnd,0);
318
319         activeDS.currentState = 7;
320     } else {
321         if (!activeDS.file) {
322             activeDS.twCC = TWRC_SUCCESS;
323             return TWRC_XFERDONE;
324         }
325     }
326
327     if (pImageMemXfer->Memory.Flags & TWMF_HANDLE) {
328         FIXME("Memory Handle, may not be locked correctly\n");
329         buffer = LocalLock(pImageMemXfer->Memory.TheMem);
330     } else
331         buffer = pImageMemXfer->Memory.TheMem;
332    
333     memset(buffer,0,pImageMemXfer->Memory.Length);
334     curoff = 0; readrows = 0;
335     pImageMemXfer->YOffset      = activeDS.jd.output_scanline;
336     pImageMemXfer->XOffset      = 0;    /* we do whole strips */
337     while ((activeDS.jd.output_scanline<activeDS.jd.output_height) &&
338            ((pImageMemXfer->Memory.Length - curoff) > activeDS.jd.output_width*activeDS.jd.output_components)
339     ) {
340         JSAMPROW row = buffer+curoff;
341         int x = pjpeg_read_scanlines(&activeDS.jd,&row,1);
342         if (x != 1) {
343                 FIXME("failed to read current scanline?\n");
344                 break;
345         }
346         readrows++;
347         curoff += activeDS.jd.output_width*activeDS.jd.output_components;
348     }
349     pImageMemXfer->Compression  = TWCP_NONE;
350     pImageMemXfer->BytesPerRow  = activeDS.jd.output_components * activeDS.jd.output_width;
351     pImageMemXfer->Rows         = readrows;
352     pImageMemXfer->Columns      = activeDS.jd.output_width; /* we do whole strips */
353     pImageMemXfer->BytesWritten = curoff;
354
355     TransferringDialogBox(activeDS.progressWnd,0);
356
357     if (activeDS.jd.output_scanline == activeDS.jd.output_height) {
358         pjpeg_finish_decompress(&activeDS.jd);
359         pjpeg_destroy_decompress(&activeDS.jd);
360         gp_file_unref (activeDS.file);
361         activeDS.file = NULL;
362         TRACE("xfer is done!\n");
363
364         /*TransferringDialogBox(activeDS.progressWnd, -1);*/
365         twRC = TWRC_XFERDONE;
366     }
367     activeDS.twCC = TWRC_SUCCESS;
368     if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
369         LocalUnlock(pImageMemXfer->Memory.TheMem);
370     return twRC;
371 #else
372     return TWRC_FAILURE;
373 #endif
374 }
375
376 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
377 TW_UINT16 GPHOTO2_ImageNativeXferGet (pTW_IDENTITY pOrigin, 
378                                     TW_MEMREF pData)
379 {
380 #ifdef HAVE_GPHOTO2
381     pTW_UINT32 pHandle = (pTW_UINT32) pData;
382     HBITMAP hDIB;
383     BITMAPINFO bmpInfo;
384     LPBYTE bits;
385     JSAMPROW samprow, oldsamprow;
386     HDC dc;
387
388     FIXME("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET: implemented, but expect program crash due to DIB.\n");
389
390 /*  NOTE NOTE NOTE NOTE NOTE NOTE NOTE
391  *
392  *  While this is a mandatory transfer mode and this function
393  *  is correctly implemented and fully works, the calling program
394  *  will likely crash after calling.
395  *
396  *  Reason is that there is a lot of example code that does:
397  *  bmpinfo = GlobalLock(hBITMAP); ... pointer access to bmpinfo
398  *
399  *  Our current HBITMAP handles do not support getting GlobalLocked -> App Crash
400  *
401  *  This needs a GDI Handle rewrite, at least for DIB sections.
402  *  - Marcus
403  */
404     if (activeDS.currentState != 6) {
405         activeDS.twCC = TWCC_SEQERROR;
406         return TWRC_FAILURE;
407     }
408     if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) {
409         FIXME("Failed to get an image\n");
410         activeDS.twCC = TWCC_OPERATIONERROR;
411         return TWRC_FAILURE;
412     }
413     TRACE("Acquiring image %dx%dx%d bits from gphoto.\n",
414         activeDS.jd.output_width, activeDS.jd.output_height,
415         activeDS.jd.output_components*8);
416     ZeroMemory (&bmpInfo, sizeof (BITMAPINFO));
417     bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
418     bmpInfo.bmiHeader.biWidth = activeDS.jd.output_width;
419     bmpInfo.bmiHeader.biHeight = -activeDS.jd.output_height;
420     bmpInfo.bmiHeader.biPlanes = 1;
421     bmpInfo.bmiHeader.biBitCount = activeDS.jd.output_components*8;
422     bmpInfo.bmiHeader.biCompression = BI_RGB;
423     bmpInfo.bmiHeader.biSizeImage = 0;
424     bmpInfo.bmiHeader.biXPelsPerMeter = 0;
425     bmpInfo.bmiHeader.biYPelsPerMeter = 0;
426     bmpInfo.bmiHeader.biClrUsed = 0;
427     bmpInfo.bmiHeader.biClrImportant = 0;
428     hDIB = CreateDIBSection ((dc = GetDC(activeDS.hwndOwner)), &bmpInfo,
429                              DIB_RGB_COLORS, (LPVOID)&bits, 0, 0);
430     if (!hDIB) {
431         FIXME("Failed creating DIB.\n");
432         gp_file_unref (activeDS.file);
433         activeDS.file = NULL;
434         activeDS.twCC = TWCC_LOWMEMORY;
435         return TWRC_FAILURE;
436     }
437     samprow = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,activeDS.jd.output_width*activeDS.jd.output_components);
438     oldsamprow = samprow;
439     while ( activeDS.jd.output_scanline<activeDS.jd.output_height ) {
440         int i, x = pjpeg_read_scanlines(&activeDS.jd,&samprow,1);
441         if (x != 1) {
442                 FIXME("failed to read current scanline?\n");
443                 break;
444         }
445         /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
446         for(i=0;i<activeDS.jd.output_width;i++,samprow+=activeDS.jd.output_components) {
447             *(bits++) = *(samprow+2);
448             *(bits++) = *(samprow+1);
449             *(bits++) = *(samprow);
450         }
451         bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
452         samprow = oldsamprow;
453     }
454     HeapFree (GetProcessHeap(), 0, samprow);
455     gp_file_unref (activeDS.file);
456     activeDS.file = NULL;
457     ReleaseDC (activeDS.hwndOwner, dc);
458     *pHandle = (UINT_PTR)hDIB;
459     activeDS.twCC = TWCC_SUCCESS;
460     activeDS.currentState = 7;
461     return TWRC_XFERDONE;
462 #else
463     return TWRC_FAILURE;
464 #endif
465 }
466
467 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GET */
468 TW_UINT16 GPHOTO2_JPEGCompressionGet (pTW_IDENTITY pOrigin, 
469                                     TW_MEMREF pData)
470 {
471     FIXME ("stub!\n");
472
473     return TWRC_FAILURE;
474 }
475
476 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GETDEFAULT */
477 TW_UINT16 GPHOTO2_JPEGCompressionGetDefault (pTW_IDENTITY pOrigin,
478                                            
479                                            TW_MEMREF pData)
480 {
481     FIXME ("stub!\n");
482
483     return TWRC_FAILURE;
484 }
485
486 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_RESET */
487 TW_UINT16 GPHOTO2_JPEGCompressionReset (pTW_IDENTITY pOrigin, 
488                                       TW_MEMREF pData)
489 {
490     FIXME ("stub!\n");
491
492     return TWRC_FAILURE;
493 }
494
495 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_SET */
496 TW_UINT16 GPHOTO2_JPEGCompressionSet (pTW_IDENTITY pOrigin, 
497                                     TW_MEMREF pData)
498 {
499     FIXME ("stub!\n");
500
501     return TWRC_FAILURE;
502 }
503
504 /* DG_IMAGE/DAT_PALETTE8/MSG_GET */
505 TW_UINT16 GPHOTO2_Palette8Get (pTW_IDENTITY pOrigin, 
506                              TW_MEMREF pData)
507 {
508     FIXME ("stub!\n");
509
510     return TWRC_FAILURE;
511 }
512
513 /* DG_IMAGE/DAT_PALETTE8/MSG_GETDEFAULT */
514 TW_UINT16 GPHOTO2_Palette8GetDefault (pTW_IDENTITY pOrigin, 
515                                     TW_MEMREF pData)
516 {
517     FIXME ("stub!\n");
518
519     return TWRC_FAILURE;
520 }
521
522 /* DG_IMAGE/DAT_PALETTE8/MSG_RESET */
523 TW_UINT16 GPHOTO2_Palette8Reset (pTW_IDENTITY pOrigin, 
524                                TW_MEMREF pData)
525 {
526     FIXME ("stub!\n");
527
528     return TWRC_FAILURE;
529 }
530
531 /* DG_IMAGE/DAT_PALETTE8/MSG_SET */
532 TW_UINT16 GPHOTO2_Palette8Set (pTW_IDENTITY pOrigin, 
533                              TW_MEMREF pData)
534 {
535     FIXME ("stub!\n");
536
537     return TWRC_FAILURE;
538 }
539
540 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_RESET */
541 TW_UINT16 GPHOTO2_RGBResponseReset (pTW_IDENTITY pOrigin, 
542                                   TW_MEMREF pData)
543 {
544     FIXME ("stub!\n");
545
546     return TWRC_FAILURE;
547 }
548
549 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_SET */
550 TW_UINT16 GPHOTO2_RGBResponseSet (pTW_IDENTITY pOrigin, 
551                                 TW_MEMREF pData)
552 {
553     FIXME ("stub!\n");
554
555     return TWRC_FAILURE;
556 }
557
558 #ifdef HAVE_GPHOTO2
559 TW_UINT16
560 _get_gphoto2_file_as_DIB(
561     const char *folder, const char *filename, CameraFileType type,
562     HWND hwnd, HBITMAP *hDIB
563 ) {
564     const unsigned char *filedata;
565     unsigned long       filesize;
566     int                 ret;
567     CameraFile          *file;
568     struct jpeg_source_mgr              xjsm;
569     struct jpeg_decompress_struct       jd;
570     struct jpeg_error_mgr               jerr;
571     HDC                 dc;
572     BITMAPINFO          bmpInfo;
573     LPBYTE              bits;
574     JSAMPROW            samprow, oldsamprow;
575
576     if(!libjpeg_handle) {
577         if(!load_libjpeg()) {
578             FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
579             filedata = NULL;
580             return TWRC_FAILURE;
581         }
582     }
583
584     gp_file_new (&file);
585     ret = gp_camera_file_get(activeDS.camera, folder, filename, type, file, activeDS.context);
586     if (ret < GP_OK) {
587         FIXME("Failed to get file?\n");
588         gp_file_unref (file);
589         return TWRC_FAILURE;
590     }
591     ret = gp_file_get_data_and_size (file, (const char**)&filedata, &filesize);
592     if (ret < GP_OK) {
593         FIXME("Failed to get file data?\n");
594         return TWRC_FAILURE;
595     }
596
597     /* FIXME: Actually we might get other types than JPEG ... But only handle JPEG for now */
598     if (filedata[0] != 0xff) {
599         ERR("File %s/%s might not be JPEG, cannot decode!\n", folder, filename);
600     }
601
602     /* This is basically so we can use in-memory data for jpeg decompression.
603      * We need to have all the functions.
604      */
605     xjsm.next_input_byte        = filedata;
606     xjsm.bytes_in_buffer        = filesize;
607     xjsm.init_source    = _jpeg_init_source;
608     xjsm.fill_input_buffer      = _jpeg_fill_input_buffer;
609     xjsm.skip_input_data        = _jpeg_skip_input_data;
610     xjsm.resync_to_restart      = _jpeg_resync_to_restart;
611     xjsm.term_source    = _jpeg_term_source;
612
613     jd.err = pjpeg_std_error(&jerr);
614     /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
615      * jpeg_create_decompress(&jd); */
616     pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
617     jd.src = &xjsm;
618     ret=pjpeg_read_header(&jd,TRUE);
619     jd.out_color_space = JCS_RGB;
620     pjpeg_start_decompress(&jd);
621     if (ret != JPEG_HEADER_OK) {
622         ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
623         gp_file_unref (file);
624         return TWRC_FAILURE;
625     }
626
627     ZeroMemory (&bmpInfo, sizeof (BITMAPINFO));
628     bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
629     bmpInfo.bmiHeader.biWidth = jd.output_width;
630     bmpInfo.bmiHeader.biHeight = -jd.output_height;
631     bmpInfo.bmiHeader.biPlanes = 1;
632     bmpInfo.bmiHeader.biBitCount = jd.output_components*8;
633     bmpInfo.bmiHeader.biCompression = BI_RGB;
634     bmpInfo.bmiHeader.biSizeImage = 0;
635     bmpInfo.bmiHeader.biXPelsPerMeter = 0;
636     bmpInfo.bmiHeader.biYPelsPerMeter = 0;
637     bmpInfo.bmiHeader.biClrUsed = 0;
638     bmpInfo.bmiHeader.biClrImportant = 0;
639     *hDIB = CreateDIBSection ((dc = GetDC(hwnd)), &bmpInfo, DIB_RGB_COLORS, (LPVOID)&bits, 0, 0);
640     if (!*hDIB) {
641         FIXME("Failed creating DIB.\n");
642         gp_file_unref (file);
643         return TWRC_FAILURE;
644     }
645     samprow = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
646     oldsamprow = samprow;
647     while ( jd.output_scanline<jd.output_height ) {
648         int i, x = pjpeg_read_scanlines(&jd,&samprow,1);
649         if (x != 1) {
650             FIXME("failed to read current scanline?\n");
651             break;
652         }
653         /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
654         for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
655             *(bits++) = *(samprow+2);
656             *(bits++) = *(samprow+1);
657             *(bits++) = *(samprow);
658         }
659         bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
660         samprow = oldsamprow;
661     }
662     if (hwnd) ReleaseDC (hwnd, dc);
663     HeapFree (GetProcessHeap(), 0, samprow);
664     gp_file_unref (file);
665     return TWRC_SUCCESS;
666 }
667 #endif