1 /*
2 * Copyright 2000 Corel Corporation
3 * Copyright 2006 CodeWeavers, Aric Stewart
4 *
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.
9 *
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.
14 *
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
18 */
19
20 #include "config.h"
21
22 #include <stdarg.h>
23
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"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
33
34 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
35 TW_UINT16 SANE_ImageInfoGet (pTW_IDENTITY pOrigin,
36 TW_MEMREF pData)
37 {
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;
45
46 TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
47
48 if (activeDS.currentState != 6 && activeDS.currentState != 7)
49 {
50 twRC = TWRC_FAILURE;
51 activeDS.twCC = TWCC_SEQERROR;
52 }
53 else
54 {
55 if (activeDS.currentState == 6)
56 {
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)
61 {
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;
67 }
68 activeDS.sane_param_valid = TRUE;
69 }
70
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;
79
80 TRACE("Bits per Sample %i\n",activeDS.sane_param.depth);
81 TRACE("Frame Format %i\n",activeDS.sane_param.format);
82
83 if (activeDS.sane_param.format == SANE_FRAME_RGB )
84 {
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;
93 }
94 else if (activeDS.sane_param.format == SANE_FRAME_GRAY)
95 {
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;
105 }
106 else
107 {
108 ERR("Unhandled source frame type %i\n",activeDS.sane_param.format);
109 twRC = TWRC_FAILURE;
110 activeDS.twCC = TWCC_SEQERROR;
111 }
112 }
113
114 return twRC;
115 #endif
116 }
117
118 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
119 TW_UINT16 SANE_ImageLayoutGet (pTW_IDENTITY pOrigin,
120 TW_MEMREF pData)
121 {
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;
131
132 TRACE("DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET\n");
133
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);
137
138 if (status == SANE_STATUS_GOOD)
139 status = sane_option_probe_scan_area(activeDS.deviceHandle, "br-x", &brx_current, NULL, NULL, NULL, NULL);
140
141 if (status == SANE_STATUS_GOOD)
142 status = sane_option_probe_scan_area(activeDS.deviceHandle, "br-y", &bry_current, NULL, NULL, NULL, NULL);
143
144 if (status != SANE_STATUS_GOOD)
145 {
146 activeDS.twCC = sane_status_to_twcc(status);
147 return TWRC_FAILURE;
148 }
149
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);
154
155 img->DocumentNumber = 1;
156 img->PageNumber = 1;
157 img->FrameNumber = 1;
158
159 activeDS.twCC = TWCC_SUCCESS;
160 return TWRC_SUCCESS;
161 #endif
162 }
163
164 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
165 TW_UINT16 SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin,
166 TW_MEMREF pData)
167 {
168 FIXME ("stub!\n");
169
170 return TWRC_FAILURE;
171 }
172
173 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
174 TW_UINT16 SANE_ImageLayoutReset (pTW_IDENTITY pOrigin,
175 TW_MEMREF pData)
176 {
177 FIXME ("stub!\n");
178
179 return TWRC_FAILURE;
180 }
181
182 #ifdef SONAME_LIBSANE
183 static TW_UINT16 set_one_imagecoord(const char *option_name, TW_FIX32 val, BOOL *changed)
184 {
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)
191 {
192 activeDS.twCC = sane_status_to_twcc(status);
193 return TWRC_FAILURE;
194 }
195 if (set_status & SANE_INFO_INEXACT)
196 *changed = TRUE;
197 return TWRC_SUCCESS;
198 }
199 #endif
200
201 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
202 TW_UINT16 SANE_ImageLayoutSet (pTW_IDENTITY pOrigin,
203 TW_MEMREF pData)
204 {
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;
211
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);
218
219 twrc = set_one_imagecoord("tl-x", img->Frame.Left, &changed);
220 if (twrc != TWRC_SUCCESS)
221 return (twrc);
222
223 twrc = set_one_imagecoord("tl-y", img->Frame.Top, &changed);
224 if (twrc != TWRC_SUCCESS)
225 return (twrc);
226
227 twrc = set_one_imagecoord("br-x", img->Frame.Right, &changed);
228 if (twrc != TWRC_SUCCESS)
229 return (twrc);
230
231 twrc = set_one_imagecoord("br-y", img->Frame.Bottom, &changed);
232 if (twrc != TWRC_SUCCESS)
233 return (twrc);
234
235 activeDS.twCC = TWCC_SUCCESS;
236 return changed ? TWRC_CHECKSTATUS : TWRC_SUCCESS;
237 #endif
238 }
239
240 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
241 TW_UINT16 SANE_ImageMemXferGet (pTW_IDENTITY pOrigin,
242 TW_MEMREF pData)
243 {
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;
250
251 TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
252
253 if (activeDS.currentState < 6 || activeDS.currentState > 7)
254 {
255 twRC = TWRC_FAILURE;
256 activeDS.twCC = TWCC_SEQERROR;
257 }
258 else
259 {
260 LPBYTE buffer;
261 int buff_len = 0;
262 int consumed_len = 0;
263 LPBYTE ptr;
264 int rows;
265
266 /* Transfer an image from the source to the application */
267 if (activeDS.currentState == 6)
268 {
269
270 /* trigger scanning dialog */
271 activeDS.progressWnd = ScanningDialogBox(NULL,0);
272
273 ScanningDialogBox(activeDS.progressWnd,0);
274
275 if (! activeDS.sane_started)
276 {
277 status = psane_start (activeDS.deviceHandle);
278 if (status != SANE_STATUS_GOOD)
279 {
280 WARN("psane_start: %s\n", psane_strstatus (status));
281 psane_cancel (activeDS.deviceHandle);
282 activeDS.twCC = TWCC_OPERATIONERROR;
283 return TWRC_FAILURE;
284 }
285 activeDS.sane_started = TRUE;
286 }
287
288 status = psane_get_parameters (activeDS.deviceHandle,
289 &activeDS.sane_param);
290 activeDS.sane_param_valid = TRUE;
291
292 if (status != SANE_STATUS_GOOD)
293 {
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;
299 }
300
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);
305
306 activeDS.currentState = 7;
307 }
308
309 /* access memory buffer */
310 if (pImageMemXfer->Memory.Length < activeDS.sane_param.bytes_per_line)
311 {
312 psane_cancel (activeDS.deviceHandle);
313 activeDS.sane_started = FALSE;
314 activeDS.twCC = TWCC_BADVALUE;
315 return TWRC_FAILURE;
316 }
317
318 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
319 {
320 FIXME("Memory Handle, may not be locked correctly\n");
321 buffer = LocalLock(pImageMemXfer->Memory.TheMem);
322 }
323 else
324 buffer = pImageMemXfer->Memory.TheMem;
325
326 memset(buffer,0,pImageMemXfer->Memory.Length);
327
328 ptr = buffer;
329 consumed_len = 0;
330 rows = pImageMemXfer->Memory.Length / activeDS.sane_param.bytes_per_line;
331
332 /* must fill full lines */
333 while (consumed_len < (activeDS.sane_param.bytes_per_line*rows) &&
334 status == SANE_STATUS_GOOD)
335 {
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;
341 }
342
343 if (status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF)
344 {
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;
352
353 ScanningDialogBox(activeDS.progressWnd, consumed_len);
354
355 if (status == SANE_STATUS_EOF)
356 {
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;
362 }
363 activeDS.twCC = TWRC_SUCCESS;
364 }
365 else if (status != SANE_STATUS_EOF)
366 {
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;
373 }
374 }
375
376 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
377 LocalUnlock(pImageMemXfer->Memory.TheMem);
378
379 return twRC;
380 #endif
381 }
382
383 #ifdef SONAME_LIBSANE
384 static SANE_Status read_one_line(SANE_Handle h, BYTE *line, int len)
385 {
386 int read_len;
387 SANE_Status status;
388
389 for (;;)
390 {
391 read_len = 0;
392 status = psane_read (activeDS.deviceHandle, line, len, &read_len);
393 if (status != SANE_STATUS_GOOD)
394 break;
395
396 if (read_len == len)
397 break;
398
399 line += read_len;
400 len -= read_len;
401 }
402
403 return status;
404 }
405 #endif
406
407 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
408 TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin,
409 TW_MEMREF pData)
410 {
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;
426
427 TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
428
429 if (activeDS.currentState != 6)
430 {
431 twRC = TWRC_FAILURE;
432 activeDS.twCC = TWCC_SEQERROR;
433 }
434 else
435 {
436 /* Transfer an image from the source to the application */
437 if (! activeDS.sane_started)
438 {
439 status = psane_start (activeDS.deviceHandle);
440 if (status != SANE_STATUS_GOOD)
441 {
442 WARN("psane_start: %s\n", psane_strstatus (status));
443 psane_cancel (activeDS.deviceHandle);
444 activeDS.twCC = TWCC_OPERATIONERROR;
445 return TWRC_FAILURE;
446 }
447 activeDS.sane_started = TRUE;
448 }
449
450 status = psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
451 activeDS.sane_param_valid = TRUE;
452 if (status != SANE_STATUS_GOOD)
453 {
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;
459 }
460
461 if (activeDS.sane_param.format == SANE_FRAME_GRAY)
462 {
463 if (activeDS.sane_param.depth == 8)
464 color_size = (1 << 8) * sizeof(*colors);
465 else if (activeDS.sane_param.depth == 1)
466 ;
467 else
468 {
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;
474 }
475 }
476 else if (activeDS.sane_param.format != SANE_FRAME_RGB)
477 {
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;
483 }
484
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);
489
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;
492
493 hDIB = GlobalAlloc(GMEM_ZEROINIT, dib_bytes + sizeof(*header) + color_size);
494 if (hDIB)
495 header = GlobalLock(hDIB);
496
497 if (!header)
498 {
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;
505 }
506
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;
521
522 p = (BYTE *)(header + 1);
523
524 if (color_size > 0)
525 {
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;
530 }
531
532
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--)
537 {
538 activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd,
539 ((activeDS.sane_param.lines - 1 - i) * 100)
540 /
541 (activeDS.sane_param.lines - 1));
542
543 status = read_one_line(activeDS.deviceHandle, line,
544 activeDS.sane_param.bytes_per_line);
545 if (status != SANE_STATUS_GOOD)
546 break;
547
548 line -= dib_bytes_per_line;
549 }
550 activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd, -1);
551
552 GlobalUnlock(hDIB);
553
554 if (status != SANE_STATUS_GOOD && status != SANE_STATUS_EOF)
555 {
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;
562 }
563
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;
570 }
571 return twRC;
572 #endif
573 }
574
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.