push eb25bf65c4616aa55a810ed5c29198b1a080b208
[wine/hacks.git] / dlls / sane.ds / ds_image.c
blob63e0179d35bd1c54d2ecb631fcee6abd27d5e317
1 /*
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
20 #include "config.h"
22 #include <stdarg.h>
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"
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
34 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
35 TW_UINT16 SANE_ImageInfoGet (pTW_IDENTITY pOrigin,
36 TW_MEMREF pData)
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;
46 TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
48 if (activeDS.currentState != 6 && activeDS.currentState != 7)
50 twRC = TWRC_FAILURE;
51 activeDS.twCC = TWCC_SEQERROR;
53 else
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;
66 return TWRC_FAILURE;
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;
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;
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;
103 else
104 pImageInfo->PixelType = TWPT_GRAY;
106 else
108 ERR("Unhandled source frame type %i\n",activeDS.sane_param.format);
109 twRC = TWRC_FAILURE;
110 activeDS.twCC = TWCC_SEQERROR;
114 return twRC;
115 #endif
118 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
119 TW_UINT16 SANE_ImageLayoutGet (pTW_IDENTITY pOrigin,
120 TW_MEMREF pData)
122 FIXME ("stub!\n");
124 return TWRC_FAILURE;
127 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
128 TW_UINT16 SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin,
129 TW_MEMREF pData)
131 FIXME ("stub!\n");
133 return TWRC_FAILURE;
136 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
137 TW_UINT16 SANE_ImageLayoutReset (pTW_IDENTITY pOrigin,
138 TW_MEMREF pData)
140 FIXME ("stub!\n");
142 return TWRC_FAILURE;
145 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
146 TW_UINT16 SANE_ImageLayoutSet (pTW_IDENTITY pOrigin,
147 TW_MEMREF pData)
149 FIXME ("stub!\n");
151 return TWRC_FAILURE;
154 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
155 TW_UINT16 SANE_ImageMemXferGet (pTW_IDENTITY pOrigin,
156 TW_MEMREF pData)
158 #ifndef SONAME_LIBSANE
159 return TWRC_FAILURE;
160 #else
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)
169 twRC = TWRC_FAILURE;
170 activeDS.twCC = TWCC_SEQERROR;
172 else
174 LPBYTE buffer;
175 int buff_len = 0;
176 int consumed_len = 0;
177 LPBYTE ptr;
178 int rows;
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;
197 return TWRC_FAILURE;
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;
212 return TWRC_FAILURE;
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;
229 return TWRC_FAILURE;
232 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
234 FIXME("Memory Handle, may not be locked correctly\n");
235 buffer = LocalLock(pImageMemXfer->Memory.TheMem);
237 else
238 buffer = pImageMemXfer->Memory.TheMem;
240 memset(buffer,0,pImageMemXfer->Memory.Length);
242 ptr = buffer;
243 consumed_len = 0;
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 ,
252 &buff_len);
253 consumed_len += buff_len;
254 ptr += 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;
286 twRC = TWRC_FAILURE;
290 if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
291 LocalUnlock(pImageMemXfer->Memory.TheMem);
293 return twRC;
294 #endif
297 #ifdef SONAME_LIBSANE
298 static SANE_Status read_one_line(SANE_Handle h, BYTE *line, int len)
300 int read_len;
301 SANE_Status status;
303 for (;;)
305 read_len = 0;
306 status = psane_read (activeDS.deviceHandle, line, len, &read_len);
307 if (status != SANE_STATUS_GOOD)
308 break;
310 if (read_len == len)
311 break;
313 line += read_len;
314 len -= read_len;
317 return status;
319 #endif
321 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
322 TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin,
323 TW_MEMREF pData)
325 #ifndef SONAME_LIBSANE
326 return TWRC_FAILURE;
327 #else
328 TW_UINT16 twRC = TWRC_SUCCESS;
329 pTW_UINT32 pHandle = (pTW_UINT32) pData;
330 SANE_Status status;
331 HANDLE hDIB;
332 BITMAPINFOHEADER *header = NULL;
333 int dib_bytes;
334 int dib_bytes_per_line;
335 BYTE *line;
336 RGBQUAD *colors;
337 int color_size = 0;
338 int i;
339 BYTE *p;
341 TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
343 if (activeDS.currentState != 6)
345 twRC = TWRC_FAILURE;
346 activeDS.twCC = TWCC_SEQERROR;
348 else
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;
359 return TWRC_FAILURE;
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;
372 return TWRC_FAILURE;
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)
381 else
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;
387 return TWRC_FAILURE;
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;
396 return TWRC_FAILURE;
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);
408 if (hDIB)
409 header = GlobalLock(hDIB);
411 if (!header)
413 psane_cancel (activeDS.deviceHandle);
414 activeDS.sane_started = FALSE;
415 activeDS.twCC = TWCC_LOWMEMORY;
416 if (hDIB)
417 GlobalFree(hDIB);
418 return TWRC_FAILURE;
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);
438 if (color_size > 0)
440 colors = (RGBQUAD *) p;
441 p += color_size;
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)
460 break;
462 line -= dib_bytes_per_line;
464 activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd, -1);
466 GlobalUnlock(hDIB);
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;
474 GlobalFree(hDIB);
475 return TWRC_FAILURE;
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;
485 return twRC;
486 #endif