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
,
127 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
128 TW_UINT16
SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin
,
136 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
137 TW_UINT16
SANE_ImageLayoutReset (pTW_IDENTITY pOrigin
,
145 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
146 TW_UINT16
SANE_ImageLayoutSet (pTW_IDENTITY pOrigin
,
154 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
155 TW_UINT16
SANE_ImageMemXferGet (pTW_IDENTITY pOrigin
,
158 #ifndef SONAME_LIBSANE
161 TW_UINT16 twRC
= TWRC_SUCCESS
;
162 pTW_IMAGEMEMXFER pImageMemXfer
= (pTW_IMAGEMEMXFER
) pData
;
163 SANE_Status status
= SANE_STATUS_GOOD
;
165 TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
167 if (activeDS
.currentState
< 6 || activeDS
.currentState
> 7)
170 activeDS
.twCC
= TWCC_SEQERROR
;
176 int consumed_len
= 0;
180 /* Transfer an image from the source to the application */
181 if (activeDS
.currentState
== 6)
184 /* trigger scanning dialog */
185 activeDS
.progressWnd
= ScanningDialogBox(NULL
,0);
187 ScanningDialogBox(activeDS
.progressWnd
,0);
189 if (! activeDS
.sane_started
)
191 status
= psane_start (activeDS
.deviceHandle
);
192 if (status
!= SANE_STATUS_GOOD
)
194 WARN("psane_start: %s\n", psane_strstatus (status
));
195 psane_cancel (activeDS
.deviceHandle
);
196 activeDS
.twCC
= TWCC_OPERATIONERROR
;
199 activeDS
.sane_started
= TRUE
;
202 status
= psane_get_parameters (activeDS
.deviceHandle
,
203 &activeDS
.sane_param
);
204 activeDS
.sane_param_valid
= TRUE
;
206 if (status
!= SANE_STATUS_GOOD
)
208 WARN("psane_get_parameters: %s\n", psane_strstatus (status
));
209 psane_cancel (activeDS
.deviceHandle
);
210 activeDS
.sane_started
= FALSE
;
211 activeDS
.twCC
= TWCC_OPERATIONERROR
;
215 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
216 , activeDS
.sane_param
.pixels_per_line
, activeDS
.sane_param
.lines
,
217 activeDS
.sane_param
.depth
, activeDS
.sane_param
.format
,
218 activeDS
.sane_param
.last_frame
);
220 activeDS
.currentState
= 7;
223 /* access memory buffer */
224 if (pImageMemXfer
->Memory
.Length
< activeDS
.sane_param
.bytes_per_line
)
226 psane_cancel (activeDS
.deviceHandle
);
227 activeDS
.sane_started
= FALSE
;
228 activeDS
.twCC
= TWCC_BADVALUE
;
232 if (pImageMemXfer
->Memory
.Flags
& TWMF_HANDLE
)
234 FIXME("Memory Handle, may not be locked correctly\n");
235 buffer
= LocalLock(pImageMemXfer
->Memory
.TheMem
);
238 buffer
= pImageMemXfer
->Memory
.TheMem
;
240 memset(buffer
,0,pImageMemXfer
->Memory
.Length
);
244 rows
= pImageMemXfer
->Memory
.Length
/ activeDS
.sane_param
.bytes_per_line
;
246 /* must fill full lines */
247 while (consumed_len
< (activeDS
.sane_param
.bytes_per_line
*rows
) &&
248 status
== SANE_STATUS_GOOD
)
250 status
= psane_read (activeDS
.deviceHandle
, ptr
,
251 (activeDS
.sane_param
.bytes_per_line
*rows
) - consumed_len
,
253 consumed_len
+= buff_len
;
257 if (status
== SANE_STATUS_GOOD
|| status
== SANE_STATUS_EOF
)
259 pImageMemXfer
->Compression
= TWCP_NONE
;
260 pImageMemXfer
->BytesPerRow
= activeDS
.sane_param
.bytes_per_line
;
261 pImageMemXfer
->Columns
= activeDS
.sane_param
.pixels_per_line
;
262 pImageMemXfer
->Rows
= rows
;
263 pImageMemXfer
->XOffset
= 0;
264 pImageMemXfer
->YOffset
= 0;
265 pImageMemXfer
->BytesWritten
= consumed_len
;
267 ScanningDialogBox(activeDS
.progressWnd
, consumed_len
);
269 if (status
== SANE_STATUS_EOF
)
271 ScanningDialogBox(activeDS
.progressWnd
, -1);
272 TRACE("psane_read: %s\n", psane_strstatus (status
));
273 psane_cancel (activeDS
.deviceHandle
);
274 activeDS
.sane_started
= FALSE
;
275 twRC
= TWRC_XFERDONE
;
277 activeDS
.twCC
= TWRC_SUCCESS
;
279 else if (status
!= SANE_STATUS_EOF
)
281 ScanningDialogBox(activeDS
.progressWnd
, -1);
282 WARN("psane_read: %s\n", psane_strstatus (status
));
283 psane_cancel (activeDS
.deviceHandle
);
284 activeDS
.sane_started
= FALSE
;
285 activeDS
.twCC
= TWCC_OPERATIONERROR
;
290 if (pImageMemXfer
->Memory
.Flags
& TWMF_HANDLE
)
291 LocalUnlock(pImageMemXfer
->Memory
.TheMem
);
297 #ifdef SONAME_LIBSANE
298 static SANE_Status
read_one_line(SANE_Handle h
, BYTE
*line
, int len
)
306 status
= psane_read (activeDS
.deviceHandle
, line
, len
, &read_len
);
307 if (status
!= SANE_STATUS_GOOD
)
321 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
322 TW_UINT16
SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin
,
325 #ifndef SONAME_LIBSANE
328 TW_UINT16 twRC
= TWRC_SUCCESS
;
329 pTW_UINT32 pHandle
= (pTW_UINT32
) pData
;
332 BITMAPINFOHEADER
*header
= NULL
;
334 int dib_bytes_per_line
;
341 TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
343 if (activeDS
.currentState
!= 6)
346 activeDS
.twCC
= TWCC_SEQERROR
;
350 /* Transfer an image from the source to the application */
351 if (! activeDS
.sane_started
)
353 status
= psane_start (activeDS
.deviceHandle
);
354 if (status
!= SANE_STATUS_GOOD
)
356 WARN("psane_start: %s\n", psane_strstatus (status
));
357 psane_cancel (activeDS
.deviceHandle
);
358 activeDS
.twCC
= TWCC_OPERATIONERROR
;
361 activeDS
.sane_started
= TRUE
;
364 status
= psane_get_parameters (activeDS
.deviceHandle
, &activeDS
.sane_param
);
365 activeDS
.sane_param_valid
= TRUE
;
366 if (status
!= SANE_STATUS_GOOD
)
368 WARN("psane_get_parameters: %s\n", psane_strstatus (status
));
369 psane_cancel (activeDS
.deviceHandle
);
370 activeDS
.sane_started
= FALSE
;
371 activeDS
.twCC
= TWCC_OPERATIONERROR
;
375 if (activeDS
.sane_param
.format
== SANE_FRAME_GRAY
)
377 if (activeDS
.sane_param
.depth
== 8)
378 color_size
= (1 << 8) * sizeof(*colors
);
379 else if (activeDS
.sane_param
.depth
== 1)
383 FIXME("For NATIVE, we support only 1 bit monochrome and 8 bit Grayscale, not %d\n", activeDS
.sane_param
.depth
);
384 psane_cancel (activeDS
.deviceHandle
);
385 activeDS
.sane_started
= FALSE
;
386 activeDS
.twCC
= TWCC_OPERATIONERROR
;
390 else if (activeDS
.sane_param
.format
!= SANE_FRAME_RGB
)
392 FIXME("For NATIVE, we support only GRAY and RGB, not %d\n", activeDS
.sane_param
.format
);
393 psane_cancel (activeDS
.deviceHandle
);
394 activeDS
.sane_started
= FALSE
;
395 activeDS
.twCC
= TWCC_OPERATIONERROR
;
399 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d bpl=%d) from sane...\n"
400 , activeDS
.sane_param
.pixels_per_line
, activeDS
.sane_param
.lines
,
401 activeDS
.sane_param
.depth
, activeDS
.sane_param
.format
,
402 activeDS
.sane_param
.last_frame
, activeDS
.sane_param
.bytes_per_line
);
404 dib_bytes_per_line
= ((activeDS
.sane_param
.bytes_per_line
+ 3) / 4) * 4;
405 dib_bytes
= activeDS
.sane_param
.lines
* dib_bytes_per_line
;
407 hDIB
= GlobalAlloc(GMEM_ZEROINIT
, dib_bytes
+ sizeof(*header
) + color_size
);
409 header
= GlobalLock(hDIB
);
413 psane_cancel (activeDS
.deviceHandle
);
414 activeDS
.sane_started
= FALSE
;
415 activeDS
.twCC
= TWCC_LOWMEMORY
;
421 header
->biSize
= sizeof (*header
);
422 header
->biWidth
= activeDS
.sane_param
.pixels_per_line
;
423 header
->biHeight
= activeDS
.sane_param
.lines
;
424 header
->biPlanes
= 1;
425 header
->biCompression
= BI_RGB
;
426 if (activeDS
.sane_param
.format
== SANE_FRAME_RGB
)
427 header
->biBitCount
= activeDS
.sane_param
.depth
* 3;
428 if (activeDS
.sane_param
.format
== SANE_FRAME_GRAY
)
429 header
->biBitCount
= activeDS
.sane_param
.depth
;
430 header
->biSizeImage
= dib_bytes
;
431 header
->biXPelsPerMeter
= 0;
432 header
->biYPelsPerMeter
= 0;
433 header
->biClrUsed
= 0;
434 header
->biClrImportant
= 0;
436 p
= (BYTE
*)(header
+ 1);
440 colors
= (RGBQUAD
*) p
;
442 for (i
= 0; i
< (color_size
/ sizeof(*colors
)); i
++)
443 colors
[i
].rgbBlue
= colors
[i
].rgbRed
= colors
[i
].rgbGreen
= i
;
447 /* Sane returns data in top down order. Acrobat does best with
448 a bottom up DIB being returned. */
449 line
= p
+ (activeDS
.sane_param
.lines
- 1) * dib_bytes_per_line
;
450 for (i
= activeDS
.sane_param
.lines
- 1; i
>= 0; i
--)
452 activeDS
.progressWnd
= ScanningDialogBox(activeDS
.progressWnd
,
453 ((activeDS
.sane_param
.lines
- 1 - i
) * 100)
455 (activeDS
.sane_param
.lines
- 1));
457 status
= read_one_line(activeDS
.deviceHandle
, line
,
458 activeDS
.sane_param
.bytes_per_line
);
459 if (status
!= SANE_STATUS_GOOD
)
462 line
-= dib_bytes_per_line
;
464 activeDS
.progressWnd
= ScanningDialogBox(activeDS
.progressWnd
, -1);
468 if (status
!= SANE_STATUS_GOOD
&& status
!= SANE_STATUS_EOF
)
470 WARN("psane_read: %s, reading line %d\n", psane_strstatus(status
), i
);
471 psane_cancel (activeDS
.deviceHandle
);
472 activeDS
.sane_started
= FALSE
;
473 activeDS
.twCC
= TWCC_OPERATIONERROR
;
478 psane_cancel (activeDS
.deviceHandle
);
479 activeDS
.sane_started
= FALSE
;
480 *pHandle
= (TW_UINT32
)hDIB
;
481 twRC
= TWRC_XFERDONE
;
482 activeDS
.twCC
= TWCC_SUCCESS
;
483 activeDS
.currentState
= 7;