cmd: Turn off echo, add visual separator between testcases.
[wine/multimedia.git] / dlls / sane.ds / ds_image.c
blob4945e55bcbdec8da72f830c41c7cce179126025d
1 /*
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
20 #include "config.h"
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "twain.h"
29 #include "sane_i.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
34 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
35 TW_UINT16 SANE_ImageInfoGet (pTW_IDENTITY pOrigin,
36 TW_MEMREF pData)
38 #ifndef SONAME_LIBSANE
39 return TWRC_FAILURE;
40 #else
41 TW_UINT16 twRC = TWRC_SUCCESS;
42 pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
43 SANE_Status status;
44 SANE_Int resolution;
46 TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
48 if (activeDS.currentState != 6 && activeDS.currentState != 7)
50 twRC = TWRC_FAILURE;
51 activeDS.twCC = TWCC_SEQERROR;
53 else
55 if (activeDS.currentState == 6)
57 /* return general image description information about the image about to be transferred */
58 status = psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
59 TRACE("Getting parameters\n");
60 if (status != SANE_STATUS_GOOD)
62 WARN("psane_get_parameters: %s\n", psane_strstatus (status));
63 psane_cancel (activeDS.deviceHandle);
64 activeDS.sane_started = FALSE;
65 activeDS.twCC = TWCC_OPERATIONERROR;
66 return TWRC_FAILURE;
68 activeDS.sane_param_valid = TRUE;
71 if (sane_option_get_int(activeDS.deviceHandle, "resolution", &resolution) == SANE_STATUS_GOOD)
72 pImageInfo->XResolution.Whole = pImageInfo->YResolution.Whole = resolution;
73 else
74 pImageInfo->XResolution.Whole = pImageInfo->YResolution.Whole = -1;
75 pImageInfo->XResolution.Frac = 0;
76 pImageInfo->YResolution.Frac = 0;
77 pImageInfo->ImageWidth = activeDS.sane_param.pixels_per_line;
78 pImageInfo->ImageLength = activeDS.sane_param.lines;
80 TRACE("Bits per Sample %i\n",activeDS.sane_param.depth);
81 TRACE("Frame Format %i\n",activeDS.sane_param.format);
83 if (activeDS.sane_param.format == SANE_FRAME_RGB )
85 pImageInfo->BitsPerPixel = activeDS.sane_param.depth * 3;
86 pImageInfo->Compression = TWCP_NONE;
87 pImageInfo->Planar = TRUE;
88 pImageInfo->SamplesPerPixel = 3;
89 pImageInfo->BitsPerSample[0] = activeDS.sane_param.depth;
90 pImageInfo->BitsPerSample[1] = activeDS.sane_param.depth;
91 pImageInfo->BitsPerSample[2] = activeDS.sane_param.depth;
92 pImageInfo->PixelType = TWPT_RGB;
94 else if (activeDS.sane_param.format == SANE_FRAME_GRAY)
96 pImageInfo->BitsPerPixel = activeDS.sane_param.depth;
97 pImageInfo->Compression = TWCP_NONE;
98 pImageInfo->Planar = TRUE;
99 pImageInfo->SamplesPerPixel = 1;
100 pImageInfo->BitsPerSample[0] = activeDS.sane_param.depth;
101 if (activeDS.sane_param.depth == 1)
102 pImageInfo->PixelType = TWPT_BW;
103 else
104 pImageInfo->PixelType = TWPT_GRAY;
106 else
108 ERR("Unhandled source frame type %i\n",activeDS.sane_param.format);
109 twRC = TWRC_FAILURE;
110 activeDS.twCC = TWCC_SEQERROR;
114 return twRC;
115 #endif
118 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
119 TW_UINT16 SANE_ImageLayoutGet (pTW_IDENTITY pOrigin,
120 TW_MEMREF pData)
122 #ifndef SONAME_LIBSANE
123 return TWRC_FAILURE;
124 #else
125 TW_IMAGELAYOUT *img = (TW_IMAGELAYOUT *) pData;
126 SANE_Fixed tlx_current;
127 SANE_Fixed tly_current;
128 SANE_Fixed brx_current;
129 SANE_Fixed bry_current;
130 SANE_Status status;
132 TRACE("DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET\n");
134 status = sane_option_probe_scan_area(activeDS.deviceHandle, "tl-x", &tlx_current, NULL, NULL, NULL, NULL);
135 if (status == SANE_STATUS_GOOD)
136 status = sane_option_probe_scan_area(activeDS.deviceHandle, "tl-y", &tly_current, NULL, NULL, NULL, NULL);
138 if (status == SANE_STATUS_GOOD)
139 status = sane_option_probe_scan_area(activeDS.deviceHandle, "br-x", &brx_current, NULL, NULL, NULL, NULL);
141 if (status == SANE_STATUS_GOOD)
142 status = sane_option_probe_scan_area(activeDS.deviceHandle, "br-y", &bry_current, NULL, NULL, NULL, NULL);
144 if (status != SANE_STATUS_GOOD)
146 activeDS.twCC = sane_status_to_twcc(status);
147 return TWRC_FAILURE;
150 convert_sane_res_to_twain(SANE_UNFIX(tlx_current), SANE_UNIT_MM, &img->Frame.Left, TWUN_INCHES);
151 convert_sane_res_to_twain(SANE_UNFIX(tly_current), SANE_UNIT_MM, &img->Frame.Top, TWUN_INCHES);
152 convert_sane_res_to_twain(SANE_UNFIX(brx_current), SANE_UNIT_MM, &img->Frame.Right, TWUN_INCHES);
153 convert_sane_res_to_twain(SANE_UNFIX(bry_current), SANE_UNIT_MM, &img->Frame.Bottom, TWUN_INCHES);
155 img->DocumentNumber = 1;
156 img->PageNumber = 1;
157 img->FrameNumber = 1;
159 activeDS.twCC = TWCC_SUCCESS;
160 return TWRC_SUCCESS;
161 #endif
164 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
165 TW_UINT16 SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin,
166 TW_MEMREF pData)
168 FIXME ("stub!\n");
170 return TWRC_FAILURE;
173 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
174 TW_UINT16 SANE_ImageLayoutReset (pTW_IDENTITY pOrigin,
175 TW_MEMREF pData)
177 FIXME ("stub!\n");
179 return TWRC_FAILURE;
182 #ifdef SONAME_LIBSANE
183 static TW_UINT16 set_one_imagecoord(const char *option_name, TW_FIX32 val, BOOL *changed)
185 double d = val.Whole + ((double) val.Frac / 65536.0);
186 int set_status = 0;
187 SANE_Status status;
188 status = sane_option_set_fixed(activeDS.deviceHandle, option_name,
189 SANE_FIX((d * 254) / 10), &set_status);
190 if (status != SANE_STATUS_GOOD)
192 activeDS.twCC = sane_status_to_twcc(status);
193 return TWRC_FAILURE;
195 if (set_status & SANE_INFO_INEXACT)
196 *changed = TRUE;
197 return TWRC_SUCCESS;
199 #endif
201 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
202 TW_UINT16 SANE_ImageLayoutSet (pTW_IDENTITY pOrigin,
203 TW_MEMREF pData)
205 #ifndef SONAME_LIBSANE
206 return TWRC_FAILURE;
207 #else
208 TW_IMAGELAYOUT *img = (TW_IMAGELAYOUT *) pData;
209 BOOL changed = FALSE;
210 TW_UINT16 twrc;
212 TRACE("DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET\n");
213 TRACE("Frame: [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x]\n",
214 img->Frame.Left.Whole, img->Frame.Left.Frac,
215 img->Frame.Top.Whole, img->Frame.Top.Frac,
216 img->Frame.Right.Whole, img->Frame.Right.Frac,
217 img->Frame.Bottom.Whole, img->Frame.Bottom.Frac);
219 twrc = set_one_imagecoord("tl-x", img->Frame.Left, &changed);
220 if (twrc != TWRC_SUCCESS)
221 return (twrc);
223 twrc = set_one_imagecoord("tl-y", img->Frame.Top, &changed);
224 if (twrc != TWRC_SUCCESS)
225 return (twrc);
227 twrc = set_one_imagecoord("br-x", img->Frame.Right, &changed);
228 if (twrc != TWRC_SUCCESS)
229 return (twrc);
231 twrc = set_one_imagecoord("br-y", img->Frame.Bottom, &changed);
232 if (twrc != TWRC_SUCCESS)
233 return (twrc);
235 activeDS.twCC = TWCC_SUCCESS;
236 return changed ? TWRC_CHECKSTATUS : TWRC_SUCCESS;
237 #endif
240 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
241 TW_UINT16 SANE_ImageMemXferGet (pTW_IDENTITY pOrigin,
242 TW_MEMREF pData)
244 #ifndef SONAME_LIBSANE
245 return TWRC_FAILURE;
246 #else
247 TW_UINT16 twRC = TWRC_SUCCESS;
248 pTW_IMAGEMEMXFER pImageMemXfer = (pTW_IMAGEMEMXFER) pData;
249 SANE_Status status = SANE_STATUS_GOOD;
251 TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
253 if (activeDS.currentState < 6 || activeDS.currentState > 7)
255 twRC = TWRC_FAILURE;
256 activeDS.twCC = TWCC_SEQERROR;
258 else
260 LPBYTE buffer;
261 int buff_len = 0;
262 int consumed_len = 0;
263 LPBYTE ptr;
264 int rows;
266 /* Transfer an image from the source to the application */
267 if (activeDS.currentState == 6)
270 /* trigger scanning dialog */
271 activeDS.progressWnd = ScanningDialogBox(NULL,0);
273 ScanningDialogBox(activeDS.progressWnd,0);
275 if (! activeDS.sane_started)
277 status = psane_start (activeDS.deviceHandle);
278 if (status != SANE_STATUS_GOOD)
280 WARN("psane_start: %s\n", psane_strstatus (status));
281 psane_cancel (activeDS.deviceHandle);
282 activeDS.twCC = TWCC_OPERATIONERROR;
283 return TWRC_FAILURE;
285 activeDS.sane_started = TRUE;
288 status = psane_get_parameters (activeDS.deviceHandle,
289 &activeDS.sane_param);
290 activeDS.sane_param_valid = TRUE;
292 if (status != SANE_STATUS_GOOD)
294 WARN("psane_get_parameters: %s\n", psane_strstatus (status));
295 psane_cancel (activeDS.deviceHandle);
296 activeDS.sane_started = FALSE;
297 activeDS.twCC = TWCC_OPERATIONERROR;
298 return TWRC_FAILURE;
301 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
302 , activeDS.sane_param.pixels_per_line, activeDS.sane_param.lines,
303 activeDS.sane_param.depth, activeDS.sane_param.format,
304 activeDS.sane_param.last_frame);
306 activeDS.currentState = 7;
309 /* access memory buffer */
310 if (pImageMemXfer->Memory.Length < activeDS.sane_param.bytes_per_line)
312 psane_cancel (activeDS.deviceHandle);
313 activeDS.sane_started = FALSE;
314 activeDS.twCC = TWCC_BADVALUE;
315 return TWRC_FAILURE;
318 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
320 FIXME("Memory Handle, may not be locked correctly\n");
321 buffer = LocalLock(pImageMemXfer->Memory.TheMem);
323 else
324 buffer = pImageMemXfer->Memory.TheMem;
326 memset(buffer,0,pImageMemXfer->Memory.Length);
328 ptr = buffer;
329 consumed_len = 0;
330 rows = pImageMemXfer->Memory.Length / activeDS.sane_param.bytes_per_line;
332 /* must fill full lines */
333 while (consumed_len < (activeDS.sane_param.bytes_per_line*rows) &&
334 status == SANE_STATUS_GOOD)
336 status = psane_read (activeDS.deviceHandle, ptr,
337 (activeDS.sane_param.bytes_per_line*rows) - consumed_len ,
338 &buff_len);
339 consumed_len += buff_len;
340 ptr += buff_len;
343 if (status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF)
345 pImageMemXfer->Compression = TWCP_NONE;
346 pImageMemXfer->BytesPerRow = activeDS.sane_param.bytes_per_line;
347 pImageMemXfer->Columns = activeDS.sane_param.pixels_per_line;
348 pImageMemXfer->Rows = rows;
349 pImageMemXfer->XOffset = 0;
350 pImageMemXfer->YOffset = 0;
351 pImageMemXfer->BytesWritten = consumed_len;
353 ScanningDialogBox(activeDS.progressWnd, consumed_len);
355 if (status == SANE_STATUS_EOF)
357 ScanningDialogBox(activeDS.progressWnd, -1);
358 TRACE("psane_read: %s\n", psane_strstatus (status));
359 psane_cancel (activeDS.deviceHandle);
360 activeDS.sane_started = FALSE;
361 twRC = TWRC_XFERDONE;
363 activeDS.twCC = TWRC_SUCCESS;
365 else if (status != SANE_STATUS_EOF)
367 ScanningDialogBox(activeDS.progressWnd, -1);
368 WARN("psane_read: %s\n", psane_strstatus (status));
369 psane_cancel (activeDS.deviceHandle);
370 activeDS.sane_started = FALSE;
371 activeDS.twCC = TWCC_OPERATIONERROR;
372 twRC = TWRC_FAILURE;
376 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
377 LocalUnlock(pImageMemXfer->Memory.TheMem);
379 return twRC;
380 #endif
383 #ifdef SONAME_LIBSANE
384 static SANE_Status read_one_line(SANE_Handle h, BYTE *line, int len)
386 int read_len;
387 SANE_Status status;
389 for (;;)
391 read_len = 0;
392 status = psane_read (activeDS.deviceHandle, line, len, &read_len);
393 if (status != SANE_STATUS_GOOD)
394 break;
396 if (read_len == len)
397 break;
399 line += read_len;
400 len -= read_len;
403 return status;
405 #endif
407 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
408 TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin,
409 TW_MEMREF pData)
411 #ifndef SONAME_LIBSANE
412 return TWRC_FAILURE;
413 #else
414 TW_UINT16 twRC = TWRC_SUCCESS;
415 pTW_UINT32 pHandle = (pTW_UINT32) pData;
416 SANE_Status status;
417 HANDLE hDIB;
418 BITMAPINFOHEADER *header = NULL;
419 int dib_bytes;
420 int dib_bytes_per_line;
421 BYTE *line;
422 RGBQUAD *colors;
423 int color_size = 0;
424 int i;
425 BYTE *p;
427 TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
429 if (activeDS.currentState != 6)
431 twRC = TWRC_FAILURE;
432 activeDS.twCC = TWCC_SEQERROR;
434 else
436 /* Transfer an image from the source to the application */
437 if (! activeDS.sane_started)
439 status = psane_start (activeDS.deviceHandle);
440 if (status != SANE_STATUS_GOOD)
442 WARN("psane_start: %s\n", psane_strstatus (status));
443 psane_cancel (activeDS.deviceHandle);
444 activeDS.twCC = TWCC_OPERATIONERROR;
445 return TWRC_FAILURE;
447 activeDS.sane_started = TRUE;
450 status = psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
451 activeDS.sane_param_valid = TRUE;
452 if (status != SANE_STATUS_GOOD)
454 WARN("psane_get_parameters: %s\n", psane_strstatus (status));
455 psane_cancel (activeDS.deviceHandle);
456 activeDS.sane_started = FALSE;
457 activeDS.twCC = TWCC_OPERATIONERROR;
458 return TWRC_FAILURE;
461 if (activeDS.sane_param.format == SANE_FRAME_GRAY)
463 if (activeDS.sane_param.depth == 8)
464 color_size = (1 << 8) * sizeof(*colors);
465 else if (activeDS.sane_param.depth == 1)
467 else
469 FIXME("For NATIVE, we support only 1 bit monochrome and 8 bit Grayscale, not %d\n", activeDS.sane_param.depth);
470 psane_cancel (activeDS.deviceHandle);
471 activeDS.sane_started = FALSE;
472 activeDS.twCC = TWCC_OPERATIONERROR;
473 return TWRC_FAILURE;
476 else if (activeDS.sane_param.format != SANE_FRAME_RGB)
478 FIXME("For NATIVE, we support only GRAY and RGB, not %d\n", activeDS.sane_param.format);
479 psane_cancel (activeDS.deviceHandle);
480 activeDS.sane_started = FALSE;
481 activeDS.twCC = TWCC_OPERATIONERROR;
482 return TWRC_FAILURE;
485 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d bpl=%d) from sane...\n"
486 , activeDS.sane_param.pixels_per_line, activeDS.sane_param.lines,
487 activeDS.sane_param.depth, activeDS.sane_param.format,
488 activeDS.sane_param.last_frame, activeDS.sane_param.bytes_per_line);
490 dib_bytes_per_line = ((activeDS.sane_param.bytes_per_line + 3) / 4) * 4;
491 dib_bytes = activeDS.sane_param.lines * dib_bytes_per_line;
493 hDIB = GlobalAlloc(GMEM_ZEROINIT, dib_bytes + sizeof(*header) + color_size);
494 if (hDIB)
495 header = GlobalLock(hDIB);
497 if (!header)
499 psane_cancel (activeDS.deviceHandle);
500 activeDS.sane_started = FALSE;
501 activeDS.twCC = TWCC_LOWMEMORY;
502 if (hDIB)
503 GlobalFree(hDIB);
504 return TWRC_FAILURE;
507 header->biSize = sizeof (*header);
508 header->biWidth = activeDS.sane_param.pixels_per_line;
509 header->biHeight = activeDS.sane_param.lines;
510 header->biPlanes = 1;
511 header->biCompression = BI_RGB;
512 if (activeDS.sane_param.format == SANE_FRAME_RGB)
513 header->biBitCount = activeDS.sane_param.depth * 3;
514 if (activeDS.sane_param.format == SANE_FRAME_GRAY)
515 header->biBitCount = activeDS.sane_param.depth;
516 header->biSizeImage = dib_bytes;
517 header->biXPelsPerMeter = 0;
518 header->biYPelsPerMeter = 0;
519 header->biClrUsed = 0;
520 header->biClrImportant = 0;
522 p = (BYTE *)(header + 1);
524 if (color_size > 0)
526 colors = (RGBQUAD *) p;
527 p += color_size;
528 for (i = 0; i < (color_size / sizeof(*colors)); i++)
529 colors[i].rgbBlue = colors[i].rgbRed = colors[i].rgbGreen = i;
533 /* Sane returns data in top down order. Acrobat does best with
534 a bottom up DIB being returned. */
535 line = p + (activeDS.sane_param.lines - 1) * dib_bytes_per_line;
536 for (i = activeDS.sane_param.lines - 1; i >= 0; i--)
538 activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd,
539 ((activeDS.sane_param.lines - 1 - i) * 100)
541 (activeDS.sane_param.lines - 1));
543 status = read_one_line(activeDS.deviceHandle, line,
544 activeDS.sane_param.bytes_per_line);
545 if (status != SANE_STATUS_GOOD)
546 break;
548 line -= dib_bytes_per_line;
550 activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd, -1);
552 GlobalUnlock(hDIB);
554 if (status != SANE_STATUS_GOOD && status != SANE_STATUS_EOF)
556 WARN("psane_read: %s, reading line %d\n", psane_strstatus(status), i);
557 psane_cancel (activeDS.deviceHandle);
558 activeDS.sane_started = FALSE;
559 activeDS.twCC = TWCC_OPERATIONERROR;
560 GlobalFree(hDIB);
561 return TWRC_FAILURE;
564 psane_cancel (activeDS.deviceHandle);
565 activeDS.sane_started = FALSE;
566 *pHandle = (UINT_PTR)hDIB;
567 twRC = TWRC_XFERDONE;
568 activeDS.twCC = TWCC_SUCCESS;
569 activeDS.currentState = 7;
571 return twRC;
572 #endif