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_CIECOLOR/MSG_GET */
35 TW_UINT16
SANE_CIEColorGet (pTW_IDENTITY pOrigin
,
43 /* DG_IMAGE/DAT_EXTIMAGEINFO/MSG_GET */
44 TW_UINT16
SANE_ExtImageInfoGet (pTW_IDENTITY pOrigin
,
52 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_RESET */
53 TW_UINT16
SANE_GrayResponseReset (pTW_IDENTITY pOrigin
,
61 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_SET */
62 TW_UINT16
SANE_GrayResponseSet (pTW_IDENTITY pOrigin
,
70 /* DG_IMAGE/DAT_IMAGEFILEXFER/MSG_GET */
71 TW_UINT16
SANE_ImageFileXferGet (pTW_IDENTITY pOrigin
,
79 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
80 TW_UINT16
SANE_ImageInfoGet (pTW_IDENTITY pOrigin
,
83 #ifndef SONAME_LIBSANE
86 TW_UINT16 twRC
= TWRC_SUCCESS
;
87 pTW_IMAGEINFO pImageInfo
= (pTW_IMAGEINFO
) pData
;
91 TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
93 if (activeDS
.currentState
!= 6 && activeDS
.currentState
!= 7)
96 activeDS
.twCC
= TWCC_SEQERROR
;
100 if (activeDS
.currentState
== 6)
102 /* return general image description information about the image about to be transferred */
103 status
= psane_get_parameters (activeDS
.deviceHandle
, &activeDS
.sane_param
);
104 TRACE("Getting parameters\n");
105 if (status
!= SANE_STATUS_GOOD
)
107 WARN("psane_get_parameters: %s\n", psane_strstatus (status
));
108 psane_cancel (activeDS
.deviceHandle
);
109 activeDS
.twCC
= TWCC_OPERATIONERROR
;
112 activeDS
.sane_param_valid
= TRUE
;
115 if (sane_option_get_int(activeDS
.deviceHandle
, "resolution", &resolution
) == SANE_STATUS_GOOD
)
116 pImageInfo
->XResolution
.Whole
= pImageInfo
->YResolution
.Whole
= resolution
;
118 pImageInfo
->XResolution
.Whole
= pImageInfo
->YResolution
.Whole
= -1;
119 pImageInfo
->XResolution
.Frac
= 0;
120 pImageInfo
->YResolution
.Frac
= 0;
121 pImageInfo
->ImageWidth
= activeDS
.sane_param
.pixels_per_line
;
122 pImageInfo
->ImageLength
= activeDS
.sane_param
.lines
;
124 TRACE("Bits per Sample %i\n",activeDS
.sane_param
.depth
);
125 TRACE("Frame Format %i\n",activeDS
.sane_param
.format
);
127 if (activeDS
.sane_param
.format
== SANE_FRAME_RGB
)
129 pImageInfo
->BitsPerPixel
= activeDS
.sane_param
.depth
* 3;
130 pImageInfo
->Compression
= TWCP_NONE
;
131 pImageInfo
->Planar
= TRUE
;
132 pImageInfo
->SamplesPerPixel
= 3;
133 pImageInfo
->BitsPerSample
[0] = activeDS
.sane_param
.depth
;
134 pImageInfo
->BitsPerSample
[1] = activeDS
.sane_param
.depth
;
135 pImageInfo
->BitsPerSample
[2] = activeDS
.sane_param
.depth
;
136 pImageInfo
->PixelType
= TWPT_RGB
;
138 else if (activeDS
.sane_param
.format
== SANE_FRAME_GRAY
)
140 pImageInfo
->BitsPerPixel
= activeDS
.sane_param
.depth
;
141 pImageInfo
->Compression
= TWCP_NONE
;
142 pImageInfo
->Planar
= TRUE
;
143 pImageInfo
->SamplesPerPixel
= 1;
144 pImageInfo
->BitsPerSample
[0] = activeDS
.sane_param
.depth
;
145 pImageInfo
->PixelType
= TWPT_GRAY
;
149 ERR("Unhandled source frame type %i\n",activeDS
.sane_param
.format
);
151 activeDS
.twCC
= TWCC_SEQERROR
;
159 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
160 TW_UINT16
SANE_ImageLayoutGet (pTW_IDENTITY pOrigin
,
168 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
169 TW_UINT16
SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin
,
177 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
178 TW_UINT16
SANE_ImageLayoutReset (pTW_IDENTITY pOrigin
,
186 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
187 TW_UINT16
SANE_ImageLayoutSet (pTW_IDENTITY pOrigin
,
195 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
196 TW_UINT16
SANE_ImageMemXferGet (pTW_IDENTITY pOrigin
,
199 #ifndef SONAME_LIBSANE
202 TW_UINT16 twRC
= TWRC_SUCCESS
;
203 pTW_IMAGEMEMXFER pImageMemXfer
= (pTW_IMAGEMEMXFER
) pData
;
204 SANE_Status status
= SANE_STATUS_GOOD
;
206 TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
208 if (activeDS
.currentState
< 6 || activeDS
.currentState
> 7)
211 activeDS
.twCC
= TWCC_SEQERROR
;
217 int consumed_len
= 0;
221 /* Transfer an image from the source to the application */
222 if (activeDS
.currentState
== 6)
225 /* trigger scanning dialog */
226 activeDS
.progressWnd
= ScanningDialogBox(NULL
,0);
228 ScanningDialogBox(activeDS
.progressWnd
,0);
230 status
= psane_start (activeDS
.deviceHandle
);
231 if (status
!= SANE_STATUS_GOOD
)
233 WARN("psane_start: %s\n", psane_strstatus (status
));
234 psane_cancel (activeDS
.deviceHandle
);
235 activeDS
.twCC
= TWCC_OPERATIONERROR
;
239 status
= psane_get_parameters (activeDS
.deviceHandle
,
240 &activeDS
.sane_param
);
241 activeDS
.sane_param_valid
= TRUE
;
243 if (status
!= SANE_STATUS_GOOD
)
245 WARN("psane_get_parameters: %s\n", psane_strstatus (status
));
246 psane_cancel (activeDS
.deviceHandle
);
247 activeDS
.twCC
= TWCC_OPERATIONERROR
;
251 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
252 , activeDS
.sane_param
.pixels_per_line
, activeDS
.sane_param
.lines
,
253 activeDS
.sane_param
.depth
, activeDS
.sane_param
.format
,
254 activeDS
.sane_param
.last_frame
);
256 activeDS
.currentState
= 7;
259 /* access memory buffer */
260 if (pImageMemXfer
->Memory
.Length
< activeDS
.sane_param
.bytes_per_line
)
262 psane_cancel (activeDS
.deviceHandle
);
263 activeDS
.twCC
= TWCC_BADVALUE
;
267 if (pImageMemXfer
->Memory
.Flags
& TWMF_HANDLE
)
269 FIXME("Memory Handle, may not be locked correctly\n");
270 buffer
= LocalLock(pImageMemXfer
->Memory
.TheMem
);
273 buffer
= pImageMemXfer
->Memory
.TheMem
;
275 memset(buffer
,0,pImageMemXfer
->Memory
.Length
);
279 rows
= pImageMemXfer
->Memory
.Length
/ activeDS
.sane_param
.bytes_per_line
;
281 /* must fill full lines */
282 while (consumed_len
< (activeDS
.sane_param
.bytes_per_line
*rows
) &&
283 status
== SANE_STATUS_GOOD
)
285 status
= psane_read (activeDS
.deviceHandle
, ptr
,
286 (activeDS
.sane_param
.bytes_per_line
*rows
) - consumed_len
,
288 consumed_len
+= buff_len
;
292 if (status
== SANE_STATUS_GOOD
|| status
== SANE_STATUS_EOF
)
294 pImageMemXfer
->Compression
= TWCP_NONE
;
295 pImageMemXfer
->BytesPerRow
= activeDS
.sane_param
.bytes_per_line
;
296 pImageMemXfer
->Columns
= activeDS
.sane_param
.pixels_per_line
;
297 pImageMemXfer
->Rows
= rows
;
298 pImageMemXfer
->XOffset
= 0;
299 pImageMemXfer
->YOffset
= 0;
300 pImageMemXfer
->BytesWritten
= consumed_len
;
302 ScanningDialogBox(activeDS
.progressWnd
, consumed_len
);
304 if (status
== SANE_STATUS_EOF
)
306 ScanningDialogBox(activeDS
.progressWnd
, -1);
307 TRACE("psane_read: %s\n", psane_strstatus (status
));
308 psane_cancel (activeDS
.deviceHandle
);
309 twRC
= TWRC_XFERDONE
;
311 activeDS
.twCC
= TWRC_SUCCESS
;
313 else if (status
!= SANE_STATUS_EOF
)
315 ScanningDialogBox(activeDS
.progressWnd
, -1);
316 WARN("psane_read: %s\n", psane_strstatus (status
));
317 psane_cancel (activeDS
.deviceHandle
);
318 activeDS
.twCC
= TWCC_OPERATIONERROR
;
323 if (pImageMemXfer
->Memory
.Flags
& TWMF_HANDLE
)
324 LocalUnlock(pImageMemXfer
->Memory
.TheMem
);
330 #ifdef SONAME_LIBSANE
331 static SANE_Status
read_one_line(SANE_Handle h
, BYTE
*line
, int len
)
339 status
= psane_read (activeDS
.deviceHandle
, line
, len
, &read_len
);
340 if (status
!= SANE_STATUS_GOOD
)
354 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
355 TW_UINT16
SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin
,
358 #ifndef SONAME_LIBSANE
361 TW_UINT16 twRC
= TWRC_SUCCESS
;
362 pTW_UINT32 pHandle
= (pTW_UINT32
) pData
;
365 BITMAPINFOHEADER
*header
= NULL
;
367 int dib_bytes_per_line
;
371 TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
373 if (activeDS
.currentState
!= 6)
376 activeDS
.twCC
= TWCC_SEQERROR
;
380 /* Transfer an image from the source to the application */
381 status
= psane_start (activeDS
.deviceHandle
);
382 if (status
!= SANE_STATUS_GOOD
)
384 WARN("psane_start: %s\n", psane_strstatus (status
));
385 psane_cancel (activeDS
.deviceHandle
);
386 activeDS
.twCC
= TWCC_OPERATIONERROR
;
390 status
= psane_get_parameters (activeDS
.deviceHandle
, &activeDS
.sane_param
);
391 activeDS
.sane_param_valid
= TRUE
;
392 if (status
!= SANE_STATUS_GOOD
)
394 WARN("psane_get_parameters: %s\n", psane_strstatus (status
));
395 psane_cancel (activeDS
.deviceHandle
);
396 activeDS
.twCC
= TWCC_OPERATIONERROR
;
400 if (activeDS
.sane_param
.format
!= SANE_FRAME_RGB
)
402 FIXME("For NATIVE, we support only RGB, not %d\n", activeDS
.sane_param
.format
);
403 psane_cancel (activeDS
.deviceHandle
);
404 activeDS
.twCC
= TWCC_OPERATIONERROR
;
408 TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d bpl=%d) from sane...\n"
409 , activeDS
.sane_param
.pixels_per_line
, activeDS
.sane_param
.lines
,
410 activeDS
.sane_param
.depth
, activeDS
.sane_param
.format
,
411 activeDS
.sane_param
.last_frame
, activeDS
.sane_param
.bytes_per_line
);
413 dib_bytes_per_line
= ((activeDS
.sane_param
.bytes_per_line
+ 3) / 4) * 4;
414 dib_bytes
= activeDS
.sane_param
.lines
* dib_bytes_per_line
;
416 hDIB
= GlobalAlloc(GMEM_ZEROINIT
, dib_bytes
+ sizeof(*header
));
418 header
= GlobalLock(hDIB
);
422 psane_cancel (activeDS
.deviceHandle
);
423 activeDS
.twCC
= TWCC_LOWMEMORY
;
429 header
->biSize
= sizeof (*header
);
430 header
->biWidth
= activeDS
.sane_param
.pixels_per_line
;
431 header
->biHeight
= activeDS
.sane_param
.lines
;
432 header
->biPlanes
= 1;
433 header
->biBitCount
= activeDS
.sane_param
.depth
* 3;
434 header
->biCompression
= BI_RGB
;
435 header
->biSizeImage
= dib_bytes
;
436 header
->biXPelsPerMeter
= 0;
437 header
->biYPelsPerMeter
= 0;
438 header
->biClrUsed
= 0;
439 header
->biClrImportant
= 0;
441 /* Sane returns data in top down order. Acrobat does best with
442 a bottom up DIB being returned. */
443 line
= (BYTE
*)(header
+ 1) +
444 (activeDS
.sane_param
.lines
- 1) * dib_bytes_per_line
;
445 for (i
= activeDS
.sane_param
.lines
- 1; i
>= 0; i
--)
447 activeDS
.progressWnd
= ScanningDialogBox(activeDS
.progressWnd
,
448 ((activeDS
.sane_param
.lines
- 1 - i
) * 100)
450 (activeDS
.sane_param
.lines
- 1));
452 status
= read_one_line(activeDS
.deviceHandle
, line
,
453 activeDS
.sane_param
.bytes_per_line
);
454 if (status
!= SANE_STATUS_GOOD
)
457 line
-= dib_bytes_per_line
;
459 activeDS
.progressWnd
= ScanningDialogBox(activeDS
.progressWnd
, -1);
463 if (status
!= SANE_STATUS_GOOD
&& status
!= SANE_STATUS_EOF
)
465 WARN("psane_read: %s, reading line %d\n", psane_strstatus(status
), i
);
466 psane_cancel (activeDS
.deviceHandle
);
467 activeDS
.twCC
= TWCC_OPERATIONERROR
;
472 psane_cancel (activeDS
.deviceHandle
);
473 *pHandle
= (TW_UINT32
)hDIB
;
474 twRC
= TWRC_XFERDONE
;
475 activeDS
.twCC
= TWCC_SUCCESS
;
476 activeDS
.currentState
= 7;
482 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GET */
483 TW_UINT16
SANE_JPEGCompressionGet (pTW_IDENTITY pOrigin
,
491 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GETDEFAULT */
492 TW_UINT16
SANE_JPEGCompressionGetDefault (pTW_IDENTITY pOrigin
,
501 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_RESET */
502 TW_UINT16
SANE_JPEGCompressionReset (pTW_IDENTITY pOrigin
,
510 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_SET */
511 TW_UINT16
SANE_JPEGCompressionSet (pTW_IDENTITY pOrigin
,
519 /* DG_IMAGE/DAT_PALETTE8/MSG_GET */
520 TW_UINT16
SANE_Palette8Get (pTW_IDENTITY pOrigin
,
528 /* DG_IMAGE/DAT_PALETTE8/MSG_GETDEFAULT */
529 TW_UINT16
SANE_Palette8GetDefault (pTW_IDENTITY pOrigin
,
537 /* DG_IMAGE/DAT_PALETTE8/MSG_RESET */
538 TW_UINT16
SANE_Palette8Reset (pTW_IDENTITY pOrigin
,
546 /* DG_IMAGE/DAT_PALETTE8/MSG_SET */
547 TW_UINT16
SANE_Palette8Set (pTW_IDENTITY pOrigin
,
555 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_RESET */
556 TW_UINT16
SANE_RGBResponseReset (pTW_IDENTITY pOrigin
,
564 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_SET */
565 TW_UINT16
SANE_RGBResponseSet (pTW_IDENTITY pOrigin
,