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
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(twain
);
31 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
32 TW_UINT16
SANE_ImageInfoGet (pTW_IDENTITY pOrigin
,
35 #ifndef SONAME_LIBSANE
38 TW_UINT16 twRC
= TWRC_SUCCESS
;
39 pTW_IMAGEINFO pImageInfo
= (pTW_IMAGEINFO
) pData
;
43 TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
45 if (activeDS
.currentState
!= 6 && activeDS
.currentState
!= 7)
48 activeDS
.twCC
= TWCC_SEQERROR
;
52 if (activeDS
.currentState
== 6)
54 /* return general image description information about the image about to be transferred */
55 status
= psane_get_parameters (activeDS
.deviceHandle
, &activeDS
.sane_param
);
56 TRACE("Getting parameters\n");
57 if (status
!= SANE_STATUS_GOOD
)
59 WARN("psane_get_parameters: %s\n", psane_strstatus (status
));
60 psane_cancel (activeDS
.deviceHandle
);
61 activeDS
.sane_started
= FALSE
;
62 activeDS
.twCC
= TWCC_OPERATIONERROR
;
65 activeDS
.sane_param_valid
= TRUE
;
68 if (sane_option_get_int(activeDS
.deviceHandle
, "resolution", &resolution
) == SANE_STATUS_GOOD
)
69 pImageInfo
->XResolution
.Whole
= pImageInfo
->YResolution
.Whole
= resolution
;
71 pImageInfo
->XResolution
.Whole
= pImageInfo
->YResolution
.Whole
= -1;
72 pImageInfo
->XResolution
.Frac
= 0;
73 pImageInfo
->YResolution
.Frac
= 0;
74 pImageInfo
->ImageWidth
= activeDS
.sane_param
.pixels_per_line
;
75 pImageInfo
->ImageLength
= activeDS
.sane_param
.lines
;
77 TRACE("Bits per Sample %i\n",activeDS
.sane_param
.depth
);
78 TRACE("Frame Format %i\n",activeDS
.sane_param
.format
);
80 if (activeDS
.sane_param
.format
== SANE_FRAME_RGB
)
82 pImageInfo
->BitsPerPixel
= activeDS
.sane_param
.depth
* 3;
83 pImageInfo
->Compression
= TWCP_NONE
;
84 pImageInfo
->Planar
= TRUE
;
85 pImageInfo
->SamplesPerPixel
= 3;
86 pImageInfo
->BitsPerSample
[0] = activeDS
.sane_param
.depth
;
87 pImageInfo
->BitsPerSample
[1] = activeDS
.sane_param
.depth
;
88 pImageInfo
->BitsPerSample
[2] = activeDS
.sane_param
.depth
;
89 pImageInfo
->PixelType
= TWPT_RGB
;
91 else if (activeDS
.sane_param
.format
== SANE_FRAME_GRAY
)
93 pImageInfo
->BitsPerPixel
= activeDS
.sane_param
.depth
;
94 pImageInfo
->Compression
= TWCP_NONE
;
95 pImageInfo
->Planar
= TRUE
;
96 pImageInfo
->SamplesPerPixel
= 1;
97 pImageInfo
->BitsPerSample
[0] = activeDS
.sane_param
.depth
;
98 if (activeDS
.sane_param
.depth
== 1)
99 pImageInfo
->PixelType
= TWPT_BW
;
101 pImageInfo
->PixelType
= TWPT_GRAY
;
105 ERR("Unhandled source frame type %i\n",activeDS
.sane_param
.format
);
107 activeDS
.twCC
= TWCC_SEQERROR
;
115 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
116 TW_UINT16
SANE_ImageLayoutGet (pTW_IDENTITY pOrigin
,
119 #ifndef SONAME_LIBSANE
122 TW_IMAGELAYOUT
*img
= (TW_IMAGELAYOUT
*) pData
;
123 SANE_Fixed tlx_current
;
124 SANE_Fixed tly_current
;
125 SANE_Fixed brx_current
;
126 SANE_Fixed bry_current
;
129 TRACE("DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET\n");
131 status
= sane_option_probe_scan_area(activeDS
.deviceHandle
, "tl-x", &tlx_current
, NULL
, NULL
, NULL
, NULL
);
132 if (status
== SANE_STATUS_GOOD
)
133 status
= sane_option_probe_scan_area(activeDS
.deviceHandle
, "tl-y", &tly_current
, NULL
, NULL
, NULL
, NULL
);
135 if (status
== SANE_STATUS_GOOD
)
136 status
= sane_option_probe_scan_area(activeDS
.deviceHandle
, "br-x", &brx_current
, NULL
, NULL
, NULL
, NULL
);
138 if (status
== SANE_STATUS_GOOD
)
139 status
= sane_option_probe_scan_area(activeDS
.deviceHandle
, "br-y", &bry_current
, NULL
, NULL
, NULL
, NULL
);
141 if (status
!= SANE_STATUS_GOOD
)
143 activeDS
.twCC
= sane_status_to_twcc(status
);
147 convert_sane_res_to_twain(SANE_UNFIX(tlx_current
), SANE_UNIT_MM
, &img
->Frame
.Left
, TWUN_INCHES
);
148 convert_sane_res_to_twain(SANE_UNFIX(tly_current
), SANE_UNIT_MM
, &img
->Frame
.Top
, TWUN_INCHES
);
149 convert_sane_res_to_twain(SANE_UNFIX(brx_current
), SANE_UNIT_MM
, &img
->Frame
.Right
, TWUN_INCHES
);
150 convert_sane_res_to_twain(SANE_UNFIX(bry_current
), SANE_UNIT_MM
, &img
->Frame
.Bottom
, TWUN_INCHES
);
152 img
->DocumentNumber
= 1;
154 img
->FrameNumber
= 1;
156 activeDS
.twCC
= TWCC_SUCCESS
;
161 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
162 TW_UINT16
SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin
,
170 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
171 TW_UINT16
SANE_ImageLayoutReset (pTW_IDENTITY pOrigin
,
179 #ifdef SONAME_LIBSANE
180 static TW_UINT16
set_one_imagecoord(const char *option_name
, TW_FIX32 val
, BOOL
*changed
)
182 double d
= val
.Whole
+ ((double) val
.Frac
/ 65536.0);
185 status
= sane_option_set_fixed(activeDS
.deviceHandle
, option_name
,
186 SANE_FIX((d
* 254) / 10), &set_status
);
187 if (status
!= SANE_STATUS_GOOD
)
189 activeDS
.twCC
= sane_status_to_twcc(status
);
192 if (set_status
& SANE_INFO_INEXACT
)
198 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
199 TW_UINT16
SANE_ImageLayoutSet (pTW_IDENTITY pOrigin
,
202 #ifndef SONAME_LIBSANE
205 TW_IMAGELAYOUT
*img
= (TW_IMAGELAYOUT
*) pData
;
206 BOOL changed
= FALSE
;
209 TRACE("DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET\n");
210 TRACE("Frame: [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x]\n",
211 img
->Frame
.Left
.Whole
, img
->Frame
.Left
.Frac
,
212 img
->Frame
.Top
.Whole
, img
->Frame
.Top
.Frac
,
213 img
->Frame
.Right
.Whole
, img
->Frame
.Right
.Frac
,
214 img
->Frame
.Bottom
.Whole
, img
->Frame
.Bottom
.Frac
);
216 twrc
= set_one_imagecoord("tl-x", img
->Frame
.Left
, &changed
);
217 if (twrc
!= TWRC_SUCCESS
)
220 twrc
= set_one_imagecoord("tl-y", img
->Frame
.Top
, &changed
);
221 if (twrc
!= TWRC_SUCCESS
)
224 twrc
= set_one_imagecoord("br-x", img
->Frame
.Right
, &changed
);
225 if (twrc
!= TWRC_SUCCESS
)
228 twrc
= set_one_imagecoord("br-y", img
->Frame
.Bottom
, &changed
);
229 if (twrc
!= TWRC_SUCCESS
)
232 activeDS
.twCC
= TWCC_SUCCESS
;
233 return changed
? TWRC_CHECKSTATUS
: TWRC_SUCCESS
;
237 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
238 TW_UINT16
SANE_ImageMemXferGet (pTW_IDENTITY pOrigin
,
241 #ifndef SONAME_LIBSANE
244 TW_UINT16 twRC
= TWRC_SUCCESS
;
245 pTW_IMAGEMEMXFER pImageMemXfer
= (pTW_IMAGEMEMXFER
) pData
;
246 SANE_Status status
= SANE_STATUS_GOOD
;
248 TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
250 if (activeDS
.currentState
< 6 || activeDS
.currentState
> 7)
253 activeDS
.twCC
= TWCC_SEQERROR
;
259 int consumed_len
= 0;
263 /* Transfer an image from the source to the application */
264 if (activeDS
.currentState
== 6)
267 /* trigger scanning dialog */
268 activeDS
.progressWnd
= ScanningDialogBox(NULL
,0);
270 ScanningDialogBox(activeDS
.progressWnd
,0);
272 if (! activeDS
.sane_started
)
274 status
= psane_start (activeDS
.deviceHandle
);
275 if (status
!= SANE_STATUS_GOOD
)
277 WARN("psane_start: %s\n", psane_strstatus (status
));
278 psane_cancel (activeDS
.deviceHandle
);
279 activeDS
.twCC
= TWCC_OPERATIONERROR
;
282 activeDS
.sane_started
= TRUE
;
285 status
= psane_get_parameters (activeDS
.deviceHandle
,
286 &activeDS
.sane_param
);
287 activeDS
.sane_param_valid
= TRUE
;
289 if (status
!= SANE_STATUS_GOOD
)
291 WARN("psane_get_parameters: %s\n", psane_strstatus (status
));
292 psane_cancel (activeDS
.deviceHandle
);
293 activeDS
.sane_started
= FALSE
;
294 activeDS
.twCC
= TWCC_OPERATIONERROR
;
298 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
299 , activeDS
.sane_param
.pixels_per_line
, activeDS
.sane_param
.lines
,
300 activeDS
.sane_param
.depth
, activeDS
.sane_param
.format
,
301 activeDS
.sane_param
.last_frame
);
303 activeDS
.currentState
= 7;
306 /* access memory buffer */
307 if (pImageMemXfer
->Memory
.Length
< activeDS
.sane_param
.bytes_per_line
)
309 psane_cancel (activeDS
.deviceHandle
);
310 activeDS
.sane_started
= FALSE
;
311 activeDS
.twCC
= TWCC_BADVALUE
;
315 if (pImageMemXfer
->Memory
.Flags
& TWMF_HANDLE
)
317 FIXME("Memory Handle, may not be locked correctly\n");
318 buffer
= LocalLock(pImageMemXfer
->Memory
.TheMem
);
321 buffer
= pImageMemXfer
->Memory
.TheMem
;
323 memset(buffer
,0,pImageMemXfer
->Memory
.Length
);
327 rows
= pImageMemXfer
->Memory
.Length
/ activeDS
.sane_param
.bytes_per_line
;
329 /* must fill full lines */
330 while (consumed_len
< (activeDS
.sane_param
.bytes_per_line
*rows
) &&
331 status
== SANE_STATUS_GOOD
)
333 status
= psane_read (activeDS
.deviceHandle
, ptr
,
334 (activeDS
.sane_param
.bytes_per_line
*rows
) - consumed_len
,
336 consumed_len
+= buff_len
;
340 if (status
== SANE_STATUS_GOOD
|| status
== SANE_STATUS_EOF
)
342 pImageMemXfer
->Compression
= TWCP_NONE
;
343 pImageMemXfer
->BytesPerRow
= activeDS
.sane_param
.bytes_per_line
;
344 pImageMemXfer
->Columns
= activeDS
.sane_param
.pixels_per_line
;
345 pImageMemXfer
->Rows
= rows
;
346 pImageMemXfer
->XOffset
= 0;
347 pImageMemXfer
->YOffset
= 0;
348 pImageMemXfer
->BytesWritten
= consumed_len
;
350 ScanningDialogBox(activeDS
.progressWnd
, consumed_len
);
352 if (status
== SANE_STATUS_EOF
)
354 ScanningDialogBox(activeDS
.progressWnd
, -1);
355 TRACE("psane_read: %s\n", psane_strstatus (status
));
356 psane_cancel (activeDS
.deviceHandle
);
357 activeDS
.sane_started
= FALSE
;
358 twRC
= TWRC_XFERDONE
;
360 activeDS
.twCC
= TWRC_SUCCESS
;
362 else if (status
!= SANE_STATUS_EOF
)
364 ScanningDialogBox(activeDS
.progressWnd
, -1);
365 WARN("psane_read: %s\n", psane_strstatus (status
));
366 psane_cancel (activeDS
.deviceHandle
);
367 activeDS
.sane_started
= FALSE
;
368 activeDS
.twCC
= TWCC_OPERATIONERROR
;
373 if (pImageMemXfer
->Memory
.Flags
& TWMF_HANDLE
)
374 LocalUnlock(pImageMemXfer
->Memory
.TheMem
);
380 #ifdef SONAME_LIBSANE
381 static SANE_Status
read_one_line(SANE_Handle h
, BYTE
*line
, int len
)
389 status
= psane_read (activeDS
.deviceHandle
, line
, len
, &read_len
);
390 if (status
!= SANE_STATUS_GOOD
)
404 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
405 TW_UINT16
SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin
,
408 #ifndef SONAME_LIBSANE
411 TW_UINT16 twRC
= TWRC_SUCCESS
;
412 pTW_UINT32 pHandle
= (pTW_UINT32
) pData
;
415 BITMAPINFOHEADER
*header
= NULL
;
417 int dib_bytes_per_line
;
424 TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
426 if (activeDS
.currentState
!= 6)
429 activeDS
.twCC
= TWCC_SEQERROR
;
433 /* Transfer an image from the source to the application */
434 if (! activeDS
.sane_started
)
436 status
= psane_start (activeDS
.deviceHandle
);
437 if (status
!= SANE_STATUS_GOOD
)
439 WARN("psane_start: %s\n", psane_strstatus (status
));
440 psane_cancel (activeDS
.deviceHandle
);
441 activeDS
.twCC
= TWCC_OPERATIONERROR
;
444 activeDS
.sane_started
= TRUE
;
447 status
= psane_get_parameters (activeDS
.deviceHandle
, &activeDS
.sane_param
);
448 activeDS
.sane_param_valid
= TRUE
;
449 if (status
!= SANE_STATUS_GOOD
)
451 WARN("psane_get_parameters: %s\n", psane_strstatus (status
));
452 psane_cancel (activeDS
.deviceHandle
);
453 activeDS
.sane_started
= FALSE
;
454 activeDS
.twCC
= TWCC_OPERATIONERROR
;
458 if (activeDS
.sane_param
.format
== SANE_FRAME_GRAY
)
460 if (activeDS
.sane_param
.depth
== 8)
461 color_size
= (1 << 8) * sizeof(*colors
);
462 else if (activeDS
.sane_param
.depth
== 1)
466 FIXME("For NATIVE, we support only 1 bit monochrome and 8 bit Grayscale, not %d\n", activeDS
.sane_param
.depth
);
467 psane_cancel (activeDS
.deviceHandle
);
468 activeDS
.sane_started
= FALSE
;
469 activeDS
.twCC
= TWCC_OPERATIONERROR
;
473 else if (activeDS
.sane_param
.format
!= SANE_FRAME_RGB
)
475 FIXME("For NATIVE, we support only GRAY and RGB, not %d\n", activeDS
.sane_param
.format
);
476 psane_cancel (activeDS
.deviceHandle
);
477 activeDS
.sane_started
= FALSE
;
478 activeDS
.twCC
= TWCC_OPERATIONERROR
;
482 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d bpl=%d) from sane...\n"
483 , activeDS
.sane_param
.pixels_per_line
, activeDS
.sane_param
.lines
,
484 activeDS
.sane_param
.depth
, activeDS
.sane_param
.format
,
485 activeDS
.sane_param
.last_frame
, activeDS
.sane_param
.bytes_per_line
);
487 dib_bytes_per_line
= ((activeDS
.sane_param
.bytes_per_line
+ 3) / 4) * 4;
488 dib_bytes
= activeDS
.sane_param
.lines
* dib_bytes_per_line
;
490 hDIB
= GlobalAlloc(GMEM_ZEROINIT
, dib_bytes
+ sizeof(*header
) + color_size
);
492 header
= GlobalLock(hDIB
);
496 psane_cancel (activeDS
.deviceHandle
);
497 activeDS
.sane_started
= FALSE
;
498 activeDS
.twCC
= TWCC_LOWMEMORY
;
504 header
->biSize
= sizeof (*header
);
505 header
->biWidth
= activeDS
.sane_param
.pixels_per_line
;
506 header
->biHeight
= activeDS
.sane_param
.lines
;
507 header
->biPlanes
= 1;
508 header
->biCompression
= BI_RGB
;
509 if (activeDS
.sane_param
.format
== SANE_FRAME_RGB
)
510 header
->biBitCount
= activeDS
.sane_param
.depth
* 3;
511 if (activeDS
.sane_param
.format
== SANE_FRAME_GRAY
)
512 header
->biBitCount
= activeDS
.sane_param
.depth
;
513 header
->biSizeImage
= dib_bytes
;
514 header
->biXPelsPerMeter
= 0;
515 header
->biYPelsPerMeter
= 0;
516 header
->biClrUsed
= 0;
517 header
->biClrImportant
= 0;
519 p
= (BYTE
*)(header
+ 1);
523 colors
= (RGBQUAD
*) p
;
525 for (i
= 0; i
< (color_size
/ sizeof(*colors
)); i
++)
526 colors
[i
].rgbBlue
= colors
[i
].rgbRed
= colors
[i
].rgbGreen
= i
;
530 /* Sane returns data in top down order. Acrobat does best with
531 a bottom up DIB being returned. */
532 line
= p
+ (activeDS
.sane_param
.lines
- 1) * dib_bytes_per_line
;
533 for (i
= activeDS
.sane_param
.lines
- 1; i
>= 0; i
--)
535 activeDS
.progressWnd
= ScanningDialogBox(activeDS
.progressWnd
,
536 ((activeDS
.sane_param
.lines
- 1 - i
) * 100)
538 (activeDS
.sane_param
.lines
- 1));
540 status
= read_one_line(activeDS
.deviceHandle
, line
,
541 activeDS
.sane_param
.bytes_per_line
);
542 if (status
!= SANE_STATUS_GOOD
)
545 line
-= dib_bytes_per_line
;
547 activeDS
.progressWnd
= ScanningDialogBox(activeDS
.progressWnd
, -1);
551 if (status
!= SANE_STATUS_GOOD
&& status
!= SANE_STATUS_EOF
)
553 WARN("psane_read: %s, reading line %d\n", psane_strstatus(status
), i
);
554 psane_cancel (activeDS
.deviceHandle
);
555 activeDS
.sane_started
= FALSE
;
556 activeDS
.twCC
= TWCC_OPERATIONERROR
;
561 psane_cancel (activeDS
.deviceHandle
);
562 activeDS
.sane_started
= FALSE
;
563 *pHandle
= (UINT_PTR
)hDIB
;
564 twRC
= TWRC_XFERDONE
;
565 activeDS
.twCC
= TWCC_SUCCESS
;
566 activeDS
.currentState
= 7;