/* * Copyright 2000 Corel Corporation * Copyright 2006 Marcus Meissner * Copyright 2006 CodeWeavers, Aric Stewart * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include "gphoto2_i.h" #include "wingdi.h" #include "winuser.h" #include "unixlib.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(twain); /* for the jpeg decompressor source manager. */ static void _jpeg_init_source(j_decompress_ptr cinfo) { } static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) { ERR("(), should not get here.\n"); return FALSE; } static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) { TRACE("Skipping %ld bytes...\n", num_bytes); cinfo->src->next_input_byte += num_bytes; cinfo->src->bytes_in_buffer -= num_bytes; } static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) { ERR("(desired=%d), should not get here.\n",desired); return FALSE; } static void _jpeg_term_source(j_decompress_ptr cinfo) { } static void close_file( void *handle ) { struct close_file_params params = { handle }; GPHOTO2_CALL( close_file, ¶ms ); } static void close_current_file(void) { close_file( activeDS.file_handle ); activeDS.file_handle = NULL; free( activeDS.file_data ); } /* DG_IMAGE/DAT_CIECOLOR/MSG_GET */ TW_UINT16 GPHOTO2_CIEColorGet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } /* DG_IMAGE/DAT_EXTIMAGEINFO/MSG_GET */ TW_UINT16 GPHOTO2_ExtImageInfoGet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_RESET */ TW_UINT16 GPHOTO2_GrayResponseReset (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_SET */ TW_UINT16 GPHOTO2_GrayResponseSet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } /* DG_IMAGE/DAT_IMAGEFILEXFER/MSG_GET */ TW_UINT16 GPHOTO2_ImageFileXferGet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } static TW_UINT16 _get_image_and_startup_jpeg(void) { unsigned int i; int ret; struct open_file_params open_params; struct get_file_data_params get_data_params; if (activeDS.file_handle) /* Already loaded. */ return TWRC_SUCCESS; for (i = 0; i < activeDS.file_count; i++) { if (activeDS.download_flags[i]) { activeDS.download_flags[i] = FALSE; /* mark as done */ break; } } if (i == activeDS.file_count) { activeDS.twCC = TWCC_SEQERROR; return TWRC_FAILURE; } open_params.idx = i; open_params.preview = FALSE; open_params.handle = &activeDS.file_handle; open_params.size = &activeDS.file_size; if (GPHOTO2_CALL( open_file, &open_params )) { activeDS.twCC = TWCC_SEQERROR; return TWRC_FAILURE; } activeDS.file_data = malloc( activeDS.file_size ); get_data_params.handle = activeDS.file_handle; get_data_params.data = activeDS.file_data; get_data_params.size = activeDS.file_size; if (GPHOTO2_CALL( get_file_data, &get_data_params )) { activeDS.twCC = TWCC_SEQERROR; return TWRC_FAILURE; } /* This is basically so we can use in-memory data for jpeg decompression. * We need to have all the functions. */ activeDS.xjsm.next_input_byte = activeDS.file_data; activeDS.xjsm.bytes_in_buffer = activeDS.file_size; activeDS.xjsm.init_source = _jpeg_init_source; activeDS.xjsm.fill_input_buffer = _jpeg_fill_input_buffer; activeDS.xjsm.skip_input_data = _jpeg_skip_input_data; activeDS.xjsm.resync_to_restart = _jpeg_resync_to_restart; activeDS.xjsm.term_source = _jpeg_term_source; activeDS.jd.err = jpeg_std_error(&activeDS.jerr); /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h * jpeg_create_decompress(&jd); */ jpeg_CreateDecompress(&activeDS.jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct)); activeDS.jd.src = &activeDS.xjsm; ret=jpeg_read_header(&activeDS.jd,TRUE); activeDS.jd.out_color_space = JCS_RGB; jpeg_start_decompress(&activeDS.jd); if (ret != JPEG_HEADER_OK) { ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret); close_current_file(); return TWRC_FAILURE; } return TWRC_SUCCESS; } /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */ TW_UINT16 GPHOTO2_ImageInfoGet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData; TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n"); if (activeDS.currentState != 6 && activeDS.currentState != 7) { activeDS.twCC = TWCC_SEQERROR; return TWRC_FAILURE; } if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) { FIXME("Failed to get an image\n"); activeDS.twCC = TWCC_SEQERROR; return TWRC_FAILURE; } if (activeDS.currentState == 6) { /* return general image description information about the image about to be transferred */ TRACE("Getting parameters\n"); } TRACE("activeDS.jd.output_width = %d\n", activeDS.jd.output_width); TRACE("activeDS.jd.output_height = %d\n", activeDS.jd.output_height); pImageInfo->Compression = TWCP_NONE; pImageInfo->SamplesPerPixel = 3; pImageInfo->BitsPerSample[0]= 8; pImageInfo->BitsPerSample[1]= 8; pImageInfo->BitsPerSample[2]= 8; pImageInfo->PixelType = TWPT_RGB; pImageInfo->Planar = FALSE; /* R-G-B is chunky! */ pImageInfo->XResolution.Whole = -1; pImageInfo->XResolution.Frac = 0; pImageInfo->YResolution.Whole = -1; pImageInfo->YResolution.Frac = 0; pImageInfo->ImageWidth = activeDS.jd.output_width; pImageInfo->ImageLength = activeDS.jd.output_height; pImageInfo->BitsPerPixel = 24; return TWRC_SUCCESS; } /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */ TW_UINT16 GPHOTO2_ImageLayoutGet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */ TW_UINT16 GPHOTO2_ImageLayoutGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */ TW_UINT16 GPHOTO2_ImageLayoutReset (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */ TW_UINT16 GPHOTO2_ImageLayoutSet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { FIXME ("stub!\n"); return TWRC_FAILURE; } /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */ TW_UINT16 GPHOTO2_ImageMemXferGet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { TW_UINT16 twRC = TWRC_SUCCESS; pTW_IMAGEMEMXFER pImageMemXfer = (pTW_IMAGEMEMXFER) pData; LPBYTE buffer; int readrows; unsigned int curoff; TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n"); if (activeDS.currentState < 6 || activeDS.currentState > 7) { activeDS.twCC = TWCC_SEQERROR; return TWRC_FAILURE; } TRACE("pImageMemXfer.Compression is %d\n", pImageMemXfer->Compression); if (activeDS.currentState == 6) { if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) { FIXME("Failed to get an image\n"); activeDS.twCC = TWCC_SEQERROR; return TWRC_FAILURE; } if (!activeDS.progressWnd) activeDS.progressWnd = TransferringDialogBox(NULL,0); TransferringDialogBox(activeDS.progressWnd,0); activeDS.currentState = 7; } else { if (!activeDS.file_handle) { activeDS.twCC = TWRC_SUCCESS; return TWRC_XFERDONE; } } if (pImageMemXfer->Memory.Flags & TWMF_HANDLE) { FIXME("Memory Handle, may not be locked correctly\n"); buffer = LocalLock(pImageMemXfer->Memory.TheMem); } else buffer = pImageMemXfer->Memory.TheMem; memset(buffer,0,pImageMemXfer->Memory.Length); curoff = 0; readrows = 0; pImageMemXfer->YOffset = activeDS.jd.output_scanline; pImageMemXfer->XOffset = 0; /* we do whole strips */ while ((activeDS.jd.output_scanlineMemory.Length - curoff) > activeDS.jd.output_width*activeDS.jd.output_components) ) { JSAMPROW row = buffer+curoff; int x = jpeg_read_scanlines(&activeDS.jd,&row,1); if (x != 1) { FIXME("failed to read current scanline?\n"); break; } readrows++; curoff += activeDS.jd.output_width*activeDS.jd.output_components; } pImageMemXfer->Compression = TWCP_NONE; pImageMemXfer->BytesPerRow = activeDS.jd.output_components * activeDS.jd.output_width; pImageMemXfer->Rows = readrows; pImageMemXfer->Columns = activeDS.jd.output_width; /* we do whole strips */ pImageMemXfer->BytesWritten = curoff; TransferringDialogBox(activeDS.progressWnd,0); if (activeDS.jd.output_scanline == activeDS.jd.output_height) { jpeg_finish_decompress(&activeDS.jd); jpeg_destroy_decompress(&activeDS.jd); close_current_file(); TRACE("xfer is done!\n"); /*TransferringDialogBox(activeDS.progressWnd, -1);*/ twRC = TWRC_XFERDONE; } activeDS.twCC = TWRC_SUCCESS; if (pImageMemXfer->Memory.Flags & TWMF_HANDLE) LocalUnlock(pImageMemXfer->Memory.TheMem); return twRC; } /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */ TW_UINT16 GPHOTO2_ImageNativeXferGet (pTW_IDENTITY pOrigin, TW_MEMREF pData) { pTW_UINT32 pHandle = (pTW_UINT32) pData; HBITMAP hDIB; BITMAPINFO bmpInfo; LPBYTE bits; JSAMPROW samprow, oldsamprow; FIXME("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET: implemented, but expect program crash due to DIB.\n"); /* NOTE NOTE NOTE NOTE NOTE NOTE NOTE * * While this is a mandatory transfer mode and this function * is correctly implemented and fully works, the calling program * will likely crash after calling. * * Reason is that there is a lot of example code that does: * bmpinfo = GlobalLock(hBITMAP); ... pointer access to bmpinfo * * Our current HBITMAP handles do not support getting GlobalLocked -> App Crash * * This needs a GDI Handle rewrite, at least for DIB sections. * - Marcus */ if (activeDS.currentState != 6) { activeDS.twCC = TWCC_SEQERROR; return TWRC_FAILURE; } if (TWRC_SUCCESS != _get_image_and_startup_jpeg()) { FIXME("Failed to get an image\n"); activeDS.twCC = TWCC_OPERATIONERROR; return TWRC_FAILURE; } TRACE("Acquiring image %dx%dx%d bits from gphoto.\n", activeDS.jd.output_width, activeDS.jd.output_height, activeDS.jd.output_components*8); ZeroMemory (&bmpInfo, sizeof (BITMAPINFO)); bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); bmpInfo.bmiHeader.biWidth = activeDS.jd.output_width; bmpInfo.bmiHeader.biHeight = -activeDS.jd.output_height; bmpInfo.bmiHeader.biPlanes = 1; bmpInfo.bmiHeader.biBitCount = activeDS.jd.output_components*8; bmpInfo.bmiHeader.biCompression = BI_RGB; bmpInfo.bmiHeader.biSizeImage = 0; bmpInfo.bmiHeader.biXPelsPerMeter = 0; bmpInfo.bmiHeader.biYPelsPerMeter = 0; bmpInfo.bmiHeader.biClrUsed = 0; bmpInfo.bmiHeader.biClrImportant = 0; hDIB = CreateDIBSection (0, &bmpInfo, DIB_RGB_COLORS, (LPVOID)&bits, 0, 0); if (!hDIB) { FIXME("Failed creating DIB.\n"); close_current_file(); activeDS.twCC = TWCC_LOWMEMORY; return TWRC_FAILURE; } samprow = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,activeDS.jd.output_width*activeDS.jd.output_components); oldsamprow = samprow; while ( activeDS.jd.output_scanline