2 * Copyright 2000 Corel Corporation
3 * Copyright 2006 CodeWeavers, Aric Stewart
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
34 /* DG_IMAGE/DAT_CIECOLOR/MSG_GET */
35 TW_UINT16 SANE_CIEColorGet (pTW_IDENTITY pOrigin,
43 /* DG_IMAGE/DAT_EXTIMAGEINFO/MSG_GET */
44 TW_UINT16 SANE_ExtImageInfoGet (pTW_IDENTITY pOrigin,
52 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_RESET */
53 TW_UINT16 SANE_GrayResponseReset (pTW_IDENTITY pOrigin,
61 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_SET */
62 TW_UINT16 SANE_GrayResponseSet (pTW_IDENTITY pOrigin,
70 /* DG_IMAGE/DAT_IMAGEFILEXFER/MSG_GET */
71 TW_UINT16 SANE_ImageFileXferGet (pTW_IDENTITY pOrigin,
79 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
80 TW_UINT16 SANE_ImageInfoGet (pTW_IDENTITY pOrigin,
83 #ifndef SONAME_LIBSANE
86 TW_UINT16 twRC = TWRC_SUCCESS;
87 pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
91 TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
93 if (activeDS.currentState != 6 && activeDS.currentState != 7)
96 activeDS.twCC = TWCC_SEQERROR;
100 if (activeDS.currentState == 6)
102 /* return general image description information about the image about to be transferred */
103 status = psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
104 TRACE("Getting parameters\n");
105 if (status != SANE_STATUS_GOOD)
107 WARN("psane_get_parameters: %s\n", psane_strstatus (status));
108 psane_cancel (activeDS.deviceHandle);
109 activeDS.twCC = TWCC_OPERATIONERROR;
112 activeDS.sane_param_valid = TRUE;
115 if (sane_option_get_int(activeDS.deviceHandle, "resolution", &resolution) == SANE_STATUS_GOOD)
116 pImageInfo->XResolution.Whole = pImageInfo->YResolution.Whole = resolution;
118 pImageInfo->XResolution.Whole = pImageInfo->YResolution.Whole = -1;
119 pImageInfo->XResolution.Frac = 0;
120 pImageInfo->YResolution.Frac = 0;
121 pImageInfo->ImageWidth = activeDS.sane_param.pixels_per_line;
122 pImageInfo->ImageLength = activeDS.sane_param.lines;
124 TRACE("Bits per Sample %i\n",activeDS.sane_param.depth);
125 TRACE("Frame Format %i\n",activeDS.sane_param.format);
127 if (activeDS.sane_param.format == SANE_FRAME_RGB )
129 pImageInfo->BitsPerPixel = activeDS.sane_param.depth * 3;
130 pImageInfo->Compression = TWCP_NONE;
131 pImageInfo->Planar = TRUE;
132 pImageInfo->SamplesPerPixel = 3;
133 pImageInfo->BitsPerSample[0] = activeDS.sane_param.depth;
134 pImageInfo->BitsPerSample[1] = activeDS.sane_param.depth;
135 pImageInfo->BitsPerSample[2] = activeDS.sane_param.depth;
136 pImageInfo->PixelType = TWPT_RGB;
138 else if (activeDS.sane_param.format == SANE_FRAME_GRAY)
140 pImageInfo->BitsPerPixel = activeDS.sane_param.depth;
141 pImageInfo->Compression = TWCP_NONE;
142 pImageInfo->Planar = TRUE;
143 pImageInfo->SamplesPerPixel = 1;
144 pImageInfo->BitsPerSample[0] = activeDS.sane_param.depth;
145 if (activeDS.sane_param.depth == 1)
146 pImageInfo->PixelType = TWPT_BW;
148 pImageInfo->PixelType = TWPT_GRAY;
152 ERR("Unhandled source frame type %i\n",activeDS.sane_param.format);
154 activeDS.twCC = TWCC_SEQERROR;
162 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
163 TW_UINT16 SANE_ImageLayoutGet (pTW_IDENTITY pOrigin,
171 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
172 TW_UINT16 SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin,
180 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
181 TW_UINT16 SANE_ImageLayoutReset (pTW_IDENTITY pOrigin,
189 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
190 TW_UINT16 SANE_ImageLayoutSet (pTW_IDENTITY pOrigin,
198 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
199 TW_UINT16 SANE_ImageMemXferGet (pTW_IDENTITY pOrigin,
202 #ifndef SONAME_LIBSANE
205 TW_UINT16 twRC = TWRC_SUCCESS;
206 pTW_IMAGEMEMXFER pImageMemXfer = (pTW_IMAGEMEMXFER) pData;
207 SANE_Status status = SANE_STATUS_GOOD;
209 TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
211 if (activeDS.currentState < 6 || activeDS.currentState > 7)
214 activeDS.twCC = TWCC_SEQERROR;
220 int consumed_len = 0;
224 /* Transfer an image from the source to the application */
225 if (activeDS.currentState == 6)
228 /* trigger scanning dialog */
229 activeDS.progressWnd = ScanningDialogBox(NULL,0);
231 ScanningDialogBox(activeDS.progressWnd,0);
233 status = psane_start (activeDS.deviceHandle);
234 if (status != SANE_STATUS_GOOD)
236 WARN("psane_start: %s\n", psane_strstatus (status));
237 psane_cancel (activeDS.deviceHandle);
238 activeDS.twCC = TWCC_OPERATIONERROR;
242 status = psane_get_parameters (activeDS.deviceHandle,
243 &activeDS.sane_param);
244 activeDS.sane_param_valid = TRUE;
246 if (status != SANE_STATUS_GOOD)
248 WARN("psane_get_parameters: %s\n", psane_strstatus (status));
249 psane_cancel (activeDS.deviceHandle);
250 activeDS.twCC = TWCC_OPERATIONERROR;
254 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
255 , activeDS.sane_param.pixels_per_line, activeDS.sane_param.lines,
256 activeDS.sane_param.depth, activeDS.sane_param.format,
257 activeDS.sane_param.last_frame);
259 activeDS.currentState = 7;
262 /* access memory buffer */
263 if (pImageMemXfer->Memory.Length < activeDS.sane_param.bytes_per_line)
265 psane_cancel (activeDS.deviceHandle);
266 activeDS.twCC = TWCC_BADVALUE;
270 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
272 FIXME("Memory Handle, may not be locked correctly\n");
273 buffer = LocalLock(pImageMemXfer->Memory.TheMem);
276 buffer = pImageMemXfer->Memory.TheMem;
278 memset(buffer,0,pImageMemXfer->Memory.Length);
282 rows = pImageMemXfer->Memory.Length / activeDS.sane_param.bytes_per_line;
284 /* must fill full lines */
285 while (consumed_len < (activeDS.sane_param.bytes_per_line*rows) &&
286 status == SANE_STATUS_GOOD)
288 status = psane_read (activeDS.deviceHandle, ptr,
289 (activeDS.sane_param.bytes_per_line*rows) - consumed_len ,
291 consumed_len += buff_len;
295 if (status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF)
297 pImageMemXfer->Compression = TWCP_NONE;
298 pImageMemXfer->BytesPerRow = activeDS.sane_param.bytes_per_line;
299 pImageMemXfer->Columns = activeDS.sane_param.pixels_per_line;
300 pImageMemXfer->Rows = rows;
301 pImageMemXfer->XOffset = 0;
302 pImageMemXfer->YOffset = 0;
303 pImageMemXfer->BytesWritten = consumed_len;
305 ScanningDialogBox(activeDS.progressWnd, consumed_len);
307 if (status == SANE_STATUS_EOF)
309 ScanningDialogBox(activeDS.progressWnd, -1);
310 TRACE("psane_read: %s\n", psane_strstatus (status));
311 psane_cancel (activeDS.deviceHandle);
312 twRC = TWRC_XFERDONE;
314 activeDS.twCC = TWRC_SUCCESS;
316 else if (status != SANE_STATUS_EOF)
318 ScanningDialogBox(activeDS.progressWnd, -1);
319 WARN("psane_read: %s\n", psane_strstatus (status));
320 psane_cancel (activeDS.deviceHandle);
321 activeDS.twCC = TWCC_OPERATIONERROR;
326 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
327 LocalUnlock(pImageMemXfer->Memory.TheMem);
333 #ifdef SONAME_LIBSANE
334 static SANE_Status read_one_line(SANE_Handle h, BYTE *line, int len)
342 status = psane_read (activeDS.deviceHandle, line, len, &read_len);
343 if (status != SANE_STATUS_GOOD)
357 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
358 TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin,
361 #ifndef SONAME_LIBSANE
364 TW_UINT16 twRC = TWRC_SUCCESS;
365 pTW_UINT32 pHandle = (pTW_UINT32) pData;
368 BITMAPINFOHEADER *header = NULL;
370 int dib_bytes_per_line;
377 TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
379 if (activeDS.currentState != 6)
382 activeDS.twCC = TWCC_SEQERROR;
386 /* Transfer an image from the source to the application */
387 status = psane_start (activeDS.deviceHandle);
388 if (status != SANE_STATUS_GOOD)
390 WARN("psane_start: %s\n", psane_strstatus (status));
391 psane_cancel (activeDS.deviceHandle);
392 activeDS.twCC = TWCC_OPERATIONERROR;
396 status = psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
397 activeDS.sane_param_valid = TRUE;
398 if (status != SANE_STATUS_GOOD)
400 WARN("psane_get_parameters: %s\n", psane_strstatus (status));
401 psane_cancel (activeDS.deviceHandle);
402 activeDS.twCC = TWCC_OPERATIONERROR;
406 if (activeDS.sane_param.format == SANE_FRAME_GRAY)
408 if (activeDS.sane_param.depth == 8)
409 color_size = (1 << 8) * sizeof(*colors);
410 else if (activeDS.sane_param.depth == 1)
414 FIXME("For NATIVE, we support only 1 bit monochrome and 8 bit Grayscale, not %d\n", activeDS.sane_param.depth);
415 psane_cancel (activeDS.deviceHandle);
416 activeDS.twCC = TWCC_OPERATIONERROR;
420 else if (activeDS.sane_param.format != SANE_FRAME_RGB)
422 FIXME("For NATIVE, we support only GRAY and RGB, not %d\n", activeDS.sane_param.format);
423 psane_cancel (activeDS.deviceHandle);
424 activeDS.twCC = TWCC_OPERATIONERROR;
428 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d bpl=%d) from sane...\n"
429 , activeDS.sane_param.pixels_per_line, activeDS.sane_param.lines,
430 activeDS.sane_param.depth, activeDS.sane_param.format,
431 activeDS.sane_param.last_frame, activeDS.sane_param.bytes_per_line);
433 dib_bytes_per_line = ((activeDS.sane_param.bytes_per_line + 3) / 4) * 4;
434 dib_bytes = activeDS.sane_param.lines * dib_bytes_per_line;
436 hDIB = GlobalAlloc(GMEM_ZEROINIT, dib_bytes + sizeof(*header) + color_size);
438 header = GlobalLock(hDIB);
442 psane_cancel (activeDS.deviceHandle);
443 activeDS.twCC = TWCC_LOWMEMORY;
449 header->biSize = sizeof (*header);
450 header->biWidth = activeDS.sane_param.pixels_per_line;
451 header->biHeight = activeDS.sane_param.lines;
452 header->biPlanes = 1;
453 header->biCompression = BI_RGB;
454 if (activeDS.sane_param.format == SANE_FRAME_RGB)
455 header->biBitCount = activeDS.sane_param.depth * 3;
456 if (activeDS.sane_param.format == SANE_FRAME_GRAY)
457 header->biBitCount = activeDS.sane_param.depth;
458 header->biSizeImage = dib_bytes;
459 header->biXPelsPerMeter = 0;
460 header->biYPelsPerMeter = 0;
461 header->biClrUsed = 0;
462 header->biClrImportant = 0;
464 p = (BYTE *)(header + 1);
468 colors = (RGBQUAD *) p;
470 for (i = 0; i < (color_size / sizeof(*colors)); i++)
471 colors[i].rgbBlue = colors[i].rgbRed = colors[i].rgbGreen = i;
475 /* Sane returns data in top down order. Acrobat does best with
476 a bottom up DIB being returned. */
477 line = p + (activeDS.sane_param.lines - 1) * dib_bytes_per_line;
478 for (i = activeDS.sane_param.lines - 1; i >= 0; i--)
480 activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd,
481 ((activeDS.sane_param.lines - 1 - i) * 100)
483 (activeDS.sane_param.lines - 1));
485 status = read_one_line(activeDS.deviceHandle, line,
486 activeDS.sane_param.bytes_per_line);
487 if (status != SANE_STATUS_GOOD)
490 line -= dib_bytes_per_line;
492 activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd, -1);
496 if (status != SANE_STATUS_GOOD && status != SANE_STATUS_EOF)
498 WARN("psane_read: %s, reading line %d\n", psane_strstatus(status), i);
499 psane_cancel (activeDS.deviceHandle);
500 activeDS.twCC = TWCC_OPERATIONERROR;
505 psane_cancel (activeDS.deviceHandle);
506 *pHandle = (TW_UINT32)hDIB;
507 twRC = TWRC_XFERDONE;
508 activeDS.twCC = TWCC_SUCCESS;
509 activeDS.currentState = 7;
515 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GET */
516 TW_UINT16 SANE_JPEGCompressionGet (pTW_IDENTITY pOrigin,
524 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GETDEFAULT */
525 TW_UINT16 SANE_JPEGCompressionGetDefault (pTW_IDENTITY pOrigin,
534 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_RESET */
535 TW_UINT16 SANE_JPEGCompressionReset (pTW_IDENTITY pOrigin,
543 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_SET */
544 TW_UINT16 SANE_JPEGCompressionSet (pTW_IDENTITY pOrigin,
552 /* DG_IMAGE/DAT_PALETTE8/MSG_GET */
553 TW_UINT16 SANE_Palette8Get (pTW_IDENTITY pOrigin,
561 /* DG_IMAGE/DAT_PALETTE8/MSG_GETDEFAULT */
562 TW_UINT16 SANE_Palette8GetDefault (pTW_IDENTITY pOrigin,
570 /* DG_IMAGE/DAT_PALETTE8/MSG_RESET */
571 TW_UINT16 SANE_Palette8Reset (pTW_IDENTITY pOrigin,
579 /* DG_IMAGE/DAT_PALETTE8/MSG_SET */
580 TW_UINT16 SANE_Palette8Set (pTW_IDENTITY pOrigin,
588 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_RESET */
589 TW_UINT16 SANE_RGBResponseReset (pTW_IDENTITY pOrigin,
597 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_SET */
598 TW_UINT16 SANE_RGBResponseSet (pTW_IDENTITY pOrigin,