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_IMAGEINFO/MSG_GET */
35 TW_UINT16
SANE_ImageInfoGet (pTW_IDENTITY pOrigin
,
38 #ifndef SONAME_LIBSANE
41 TW_UINT16 twRC
= TWRC_SUCCESS
;
42 pTW_IMAGEINFO pImageInfo
= (pTW_IMAGEINFO
) pData
;
46 TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
48 if (activeDS
.currentState
!= 6 && activeDS
.currentState
!= 7)
51 activeDS
.twCC
= TWCC_SEQERROR
;
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
;
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
;
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
;
104 pImageInfo
->PixelType
= TWPT_GRAY
;
108 ERR("Unhandled source frame type %i\n",activeDS
.sane_param
.format
);
110 activeDS
.twCC
= TWCC_SEQERROR
;
118 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
119 TW_UINT16
SANE_ImageLayoutGet (pTW_IDENTITY pOrigin
,
122 #ifndef SONAME_LIBSANE
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
;
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
);
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;
157 img
->FrameNumber
= 1;
159 activeDS
.twCC
= TWCC_SUCCESS
;
164 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
165 TW_UINT16
SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin
,
173 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
174 TW_UINT16
SANE_ImageLayoutReset (pTW_IDENTITY pOrigin
,
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);
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
);
195 if (set_status
& SANE_INFO_INEXACT
)
201 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
202 TW_UINT16
SANE_ImageLayoutSet (pTW_IDENTITY pOrigin
,
205 #ifndef SONAME_LIBSANE
208 TW_IMAGELAYOUT
*img
= (TW_IMAGELAYOUT
*) pData
;
209 BOOL changed
= FALSE
;
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
)
223 twrc
= set_one_imagecoord("tl-y", img
->Frame
.Top
, &changed
);
224 if (twrc
!= TWRC_SUCCESS
)
227 twrc
= set_one_imagecoord("br-x", img
->Frame
.Right
, &changed
);
228 if (twrc
!= TWRC_SUCCESS
)
231 twrc
= set_one_imagecoord("br-y", img
->Frame
.Bottom
, &changed
);
232 if (twrc
!= TWRC_SUCCESS
)
235 activeDS
.twCC
= TWCC_SUCCESS
;
236 return changed
? TWRC_CHECKSTATUS
: TWRC_SUCCESS
;
240 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
241 TW_UINT16
SANE_ImageMemXferGet (pTW_IDENTITY pOrigin
,
244 #ifndef SONAME_LIBSANE
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)
256 activeDS
.twCC
= TWCC_SEQERROR
;
262 int consumed_len
= 0;
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
;
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
;
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
;
318 if (pImageMemXfer
->Memory
.Flags
& TWMF_HANDLE
)
320 FIXME("Memory Handle, may not be locked correctly\n");
321 buffer
= LocalLock(pImageMemXfer
->Memory
.TheMem
);
324 buffer
= pImageMemXfer
->Memory
.TheMem
;
326 memset(buffer
,0,pImageMemXfer
->Memory
.Length
);
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
,
339 consumed_len
+= 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
;
376 if (pImageMemXfer
->Memory
.Flags
& TWMF_HANDLE
)
377 LocalUnlock(pImageMemXfer
->Memory
.TheMem
);
383 #ifdef SONAME_LIBSANE
384 static SANE_Status
read_one_line(SANE_Handle h
, BYTE
*line
, int len
)
392 status
= psane_read (activeDS
.deviceHandle
, line
, len
, &read_len
);
393 if (status
!= SANE_STATUS_GOOD
)
407 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
408 TW_UINT16
SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin
,
411 #ifndef SONAME_LIBSANE
414 TW_UINT16 twRC
= TWRC_SUCCESS
;
415 pTW_UINT32 pHandle
= (pTW_UINT32
) pData
;
418 BITMAPINFOHEADER
*header
= NULL
;
420 int dib_bytes_per_line
;
427 TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
429 if (activeDS
.currentState
!= 6)
432 activeDS
.twCC
= TWCC_SEQERROR
;
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
;
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
;
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)
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
;
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
;
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
);
495 header
= GlobalLock(hDIB
);
499 psane_cancel (activeDS
.deviceHandle
);
500 activeDS
.sane_started
= FALSE
;
501 activeDS
.twCC
= TWCC_LOWMEMORY
;
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);
526 colors
= (RGBQUAD
*) p
;
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
)
548 line
-= dib_bytes_per_line
;
550 activeDS
.progressWnd
= ScanningDialogBox(activeDS
.progressWnd
, -1);
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
;
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;