sane.ds: Implement grayscale and B&W scanning for native image transfers.
[wine] / dlls / sane.ds / ds_image.c
1 /*
2  * Copyright 2000 Corel Corporation
3  * Copyright 2006 CodeWeavers, Aric Stewart
4  *
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.
9  *
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.
14  *
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
18  */
19
20 #include "config.h"
21
22 #include <stdarg.h>
23
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"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
33
34 /* DG_IMAGE/DAT_CIECOLOR/MSG_GET */
35 TW_UINT16 SANE_CIEColorGet (pTW_IDENTITY pOrigin, 
36                              TW_MEMREF pData)
37 {
38     FIXME ("stub!\n");
39
40     return TWRC_FAILURE;
41 }
42
43 /* DG_IMAGE/DAT_EXTIMAGEINFO/MSG_GET */
44 TW_UINT16 SANE_ExtImageInfoGet (pTW_IDENTITY pOrigin, 
45                                  TW_MEMREF pData)
46 {
47     FIXME ("stub!\n");
48
49     return TWRC_FAILURE;
50 }
51
52 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_RESET */
53 TW_UINT16 SANE_GrayResponseReset (pTW_IDENTITY pOrigin, 
54                                    TW_MEMREF pData)
55 {
56     FIXME ("stub!\n");
57
58     return TWRC_FAILURE;
59 }
60
61 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_SET */
62 TW_UINT16 SANE_GrayResponseSet (pTW_IDENTITY pOrigin, 
63                                  TW_MEMREF pData)
64 {
65     FIXME ("stub!\n");
66
67     return TWRC_FAILURE;
68 }
69
70 /* DG_IMAGE/DAT_IMAGEFILEXFER/MSG_GET */
71 TW_UINT16 SANE_ImageFileXferGet (pTW_IDENTITY pOrigin, 
72                                   TW_MEMREF pData)
73 {
74     FIXME ("stub!\n");
75
76     return TWRC_FAILURE;
77 }
78
79 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
80 TW_UINT16 SANE_ImageInfoGet (pTW_IDENTITY pOrigin, 
81                               TW_MEMREF pData)
82 {
83 #ifndef SONAME_LIBSANE
84     return TWRC_FAILURE;
85 #else
86     TW_UINT16 twRC = TWRC_SUCCESS;
87     pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
88     SANE_Status status;
89     SANE_Int resolution;
90
91     TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
92
93     if (activeDS.currentState != 6 && activeDS.currentState != 7)
94     {
95         twRC = TWRC_FAILURE;
96         activeDS.twCC = TWCC_SEQERROR;
97     }
98     else
99     {
100         if (activeDS.currentState == 6)
101         {
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)
106             {
107                 WARN("psane_get_parameters: %s\n", psane_strstatus (status));
108                 psane_cancel (activeDS.deviceHandle);
109                 activeDS.twCC = TWCC_OPERATIONERROR;
110                 return TWRC_FAILURE;
111             }
112             activeDS.sane_param_valid = TRUE;
113         }
114
115         if (sane_option_get_int(activeDS.deviceHandle, "resolution", &resolution) == SANE_STATUS_GOOD)
116             pImageInfo->XResolution.Whole = pImageInfo->YResolution.Whole = resolution;
117         else
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;
123
124         TRACE("Bits per Sample %i\n",activeDS.sane_param.depth);
125         TRACE("Frame Format %i\n",activeDS.sane_param.format);
126
127         if (activeDS.sane_param.format == SANE_FRAME_RGB )
128         {
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;
137         }
138         else if (activeDS.sane_param.format == SANE_FRAME_GRAY)
139         {
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             if (activeDS.sane_param.depth == 1)
146                 pImageInfo->PixelType = TWPT_BW;
147             else
148                 pImageInfo->PixelType = TWPT_GRAY;
149         }
150         else
151         {
152             ERR("Unhandled source frame type %i\n",activeDS.sane_param.format);
153             twRC = TWRC_FAILURE;
154             activeDS.twCC = TWCC_SEQERROR;
155         }
156     }
157
158     return twRC;
159 #endif
160 }
161
162 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
163 TW_UINT16 SANE_ImageLayoutGet (pTW_IDENTITY pOrigin, 
164                                 TW_MEMREF pData)
165 {
166     FIXME ("stub!\n");
167
168     return TWRC_FAILURE;
169 }
170
171 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
172 TW_UINT16 SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin, 
173                                        TW_MEMREF pData)
174 {
175     FIXME ("stub!\n");
176
177     return TWRC_FAILURE;
178 }
179
180 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
181 TW_UINT16 SANE_ImageLayoutReset (pTW_IDENTITY pOrigin, 
182                                   TW_MEMREF pData)
183 {
184     FIXME ("stub!\n");
185
186     return TWRC_FAILURE;
187 }
188
189 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
190 TW_UINT16 SANE_ImageLayoutSet (pTW_IDENTITY pOrigin, 
191                                 TW_MEMREF pData)
192 {
193     FIXME ("stub!\n");
194
195     return TWRC_FAILURE;
196 }
197
198 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
199 TW_UINT16 SANE_ImageMemXferGet (pTW_IDENTITY pOrigin, 
200                                  TW_MEMREF pData)
201 {
202 #ifndef SONAME_LIBSANE
203     return TWRC_FAILURE;
204 #else
205     TW_UINT16 twRC = TWRC_SUCCESS;
206     pTW_IMAGEMEMXFER pImageMemXfer = (pTW_IMAGEMEMXFER) pData;
207     SANE_Status status = SANE_STATUS_GOOD;
208
209     TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
210
211     if (activeDS.currentState < 6 || activeDS.currentState > 7)
212     {
213         twRC = TWRC_FAILURE;
214         activeDS.twCC = TWCC_SEQERROR;
215     }
216     else
217     {
218         LPBYTE buffer;
219         int buff_len = 0;
220         int consumed_len = 0;
221         LPBYTE ptr;
222         int rows;
223
224         /* Transfer an image from the source to the application */
225         if (activeDS.currentState == 6)
226         {
227
228             /* trigger scanning dialog */
229             activeDS.progressWnd = ScanningDialogBox(NULL,0);
230
231             ScanningDialogBox(activeDS.progressWnd,0);
232
233             status = psane_start (activeDS.deviceHandle);
234             if (status != SANE_STATUS_GOOD)
235             {
236                 WARN("psane_start: %s\n", psane_strstatus (status));
237                 psane_cancel (activeDS.deviceHandle);
238                 activeDS.twCC = TWCC_OPERATIONERROR;
239                 return TWRC_FAILURE;
240             }
241
242             status = psane_get_parameters (activeDS.deviceHandle,
243                     &activeDS.sane_param);
244             activeDS.sane_param_valid = TRUE;
245
246             if (status != SANE_STATUS_GOOD)
247             {
248                 WARN("psane_get_parameters: %s\n", psane_strstatus (status));
249                 psane_cancel (activeDS.deviceHandle);
250                 activeDS.twCC = TWCC_OPERATIONERROR;
251                 return TWRC_FAILURE;
252             }
253
254             TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
255               , activeDS.sane_param.pixels_per_line, activeDS.sane_param.lines,
256               activeDS.sane_param.depth, activeDS.sane_param.format,
257               activeDS.sane_param.last_frame);
258
259             activeDS.currentState = 7;
260         }
261
262         /* access memory buffer */
263         if (pImageMemXfer->Memory.Length < activeDS.sane_param.bytes_per_line)
264         {
265             psane_cancel (activeDS.deviceHandle);
266             activeDS.twCC = TWCC_BADVALUE;
267             return TWRC_FAILURE;
268         }
269
270         if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
271         {
272             FIXME("Memory Handle, may not be locked correctly\n");
273             buffer = LocalLock(pImageMemXfer->Memory.TheMem);
274         }
275         else
276             buffer = pImageMemXfer->Memory.TheMem;
277        
278         memset(buffer,0,pImageMemXfer->Memory.Length);
279
280         ptr = buffer;
281         consumed_len = 0;
282         rows = pImageMemXfer->Memory.Length / activeDS.sane_param.bytes_per_line;
283
284         /* must fill full lines */
285         while (consumed_len < (activeDS.sane_param.bytes_per_line*rows) && 
286                 status == SANE_STATUS_GOOD)
287         {
288             status = psane_read (activeDS.deviceHandle, ptr,
289                     (activeDS.sane_param.bytes_per_line*rows) - consumed_len ,
290                     &buff_len);
291             consumed_len += buff_len;
292             ptr += buff_len;
293         }
294
295         if (status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF)
296         {
297             pImageMemXfer->Compression = TWCP_NONE;
298             pImageMemXfer->BytesPerRow = activeDS.sane_param.bytes_per_line;
299             pImageMemXfer->Columns = activeDS.sane_param.pixels_per_line;
300             pImageMemXfer->Rows = rows;
301             pImageMemXfer->XOffset = 0;
302             pImageMemXfer->YOffset = 0;
303             pImageMemXfer->BytesWritten = consumed_len;
304
305             ScanningDialogBox(activeDS.progressWnd, consumed_len);
306
307             if (status == SANE_STATUS_EOF)
308             {
309                 ScanningDialogBox(activeDS.progressWnd, -1);
310                 TRACE("psane_read: %s\n", psane_strstatus (status));
311                 psane_cancel (activeDS.deviceHandle);
312                 twRC = TWRC_XFERDONE;
313             }
314             activeDS.twCC = TWRC_SUCCESS;
315         }
316         else if (status != SANE_STATUS_EOF)
317         {
318             ScanningDialogBox(activeDS.progressWnd, -1);
319             WARN("psane_read: %s\n", psane_strstatus (status));
320             psane_cancel (activeDS.deviceHandle);
321             activeDS.twCC = TWCC_OPERATIONERROR;
322             twRC = TWRC_FAILURE;
323         }
324     }
325
326     if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
327         LocalUnlock(pImageMemXfer->Memory.TheMem);
328     
329     return twRC;
330 #endif
331 }
332
333 #ifdef SONAME_LIBSANE
334 static SANE_Status read_one_line(SANE_Handle h, BYTE *line, int len)
335 {
336     int read_len;
337     SANE_Status status;
338
339     for (;;)
340     {
341         read_len = 0;
342         status = psane_read (activeDS.deviceHandle, line, len, &read_len);
343         if (status != SANE_STATUS_GOOD)
344             break;
345
346         if (read_len == len)
347             break;
348
349         line += read_len;
350         len -= read_len;
351     }
352
353     return status;
354 }
355 #endif
356
357 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
358 TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin, 
359                                     TW_MEMREF pData)
360 {
361 #ifndef SONAME_LIBSANE
362     return TWRC_FAILURE;
363 #else
364     TW_UINT16 twRC = TWRC_SUCCESS;
365     pTW_UINT32 pHandle = (pTW_UINT32) pData;
366     SANE_Status status;
367     HANDLE hDIB;
368     BITMAPINFOHEADER *header = NULL;
369     int dib_bytes;
370     int dib_bytes_per_line;
371     BYTE *line;
372     RGBQUAD *colors;
373     int color_size = 0;
374     int i;
375     BYTE *p;
376
377     TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
378
379     if (activeDS.currentState != 6)
380     {
381         twRC = TWRC_FAILURE;
382         activeDS.twCC = TWCC_SEQERROR;
383     }
384     else
385     {
386         /* Transfer an image from the source to the application */
387         status = psane_start (activeDS.deviceHandle);
388         if (status != SANE_STATUS_GOOD)
389         {
390             WARN("psane_start: %s\n", psane_strstatus (status));
391             psane_cancel (activeDS.deviceHandle);
392             activeDS.twCC = TWCC_OPERATIONERROR;
393             return TWRC_FAILURE;
394         }
395
396         status = psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
397         activeDS.sane_param_valid = TRUE;
398         if (status != SANE_STATUS_GOOD)
399         {
400             WARN("psane_get_parameters: %s\n", psane_strstatus (status));
401             psane_cancel (activeDS.deviceHandle);
402             activeDS.twCC = TWCC_OPERATIONERROR;
403             return TWRC_FAILURE;
404         }
405
406         if (activeDS.sane_param.format == SANE_FRAME_GRAY)
407         {
408             if (activeDS.sane_param.depth == 8)
409                 color_size = (1 << 8) * sizeof(*colors);
410             else if (activeDS.sane_param.depth == 1)
411                 ;
412             else
413             {
414                 FIXME("For NATIVE, we support only 1 bit monochrome and 8 bit Grayscale, not %d\n", activeDS.sane_param.depth);
415                 psane_cancel (activeDS.deviceHandle);
416                 activeDS.twCC = TWCC_OPERATIONERROR;
417                 return TWRC_FAILURE;
418             }
419         }
420         else if (activeDS.sane_param.format != SANE_FRAME_RGB)
421         {
422             FIXME("For NATIVE, we support only GRAY and RGB, not %d\n", activeDS.sane_param.format);
423             psane_cancel (activeDS.deviceHandle);
424             activeDS.twCC = TWCC_OPERATIONERROR;
425             return TWRC_FAILURE;
426         }
427
428         TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d bpl=%d) from sane...\n"
429               , activeDS.sane_param.pixels_per_line, activeDS.sane_param.lines,
430               activeDS.sane_param.depth, activeDS.sane_param.format,
431               activeDS.sane_param.last_frame, activeDS.sane_param.bytes_per_line);
432
433         dib_bytes_per_line = ((activeDS.sane_param.bytes_per_line + 3) / 4) * 4;
434         dib_bytes = activeDS.sane_param.lines * dib_bytes_per_line;
435
436         hDIB = GlobalAlloc(GMEM_ZEROINIT, dib_bytes + sizeof(*header) + color_size);
437         if (hDIB)
438            header = GlobalLock(hDIB);
439
440         if (!header)
441         {
442             psane_cancel (activeDS.deviceHandle);
443             activeDS.twCC = TWCC_LOWMEMORY;
444             if (hDIB)
445                 GlobalFree(hDIB);
446             return TWRC_FAILURE;
447         }
448
449         header->biSize = sizeof (*header);
450         header->biWidth = activeDS.sane_param.pixels_per_line;
451         header->biHeight = activeDS.sane_param.lines;
452         header->biPlanes = 1;
453         header->biCompression = BI_RGB;
454         if (activeDS.sane_param.format == SANE_FRAME_RGB)
455             header->biBitCount = activeDS.sane_param.depth * 3;
456         if (activeDS.sane_param.format == SANE_FRAME_GRAY)
457             header->biBitCount = activeDS.sane_param.depth;
458         header->biSizeImage = dib_bytes;
459         header->biXPelsPerMeter = 0;
460         header->biYPelsPerMeter = 0;
461         header->biClrUsed = 0;
462         header->biClrImportant = 0;
463
464         p = (BYTE *)(header + 1);
465
466         if (color_size > 0)
467         {
468             colors = (RGBQUAD *) p;
469             p += color_size;
470             for (i = 0; i < (color_size / sizeof(*colors)); i++)
471                 colors[i].rgbBlue = colors[i].rgbRed = colors[i].rgbGreen = i;
472         }
473
474
475         /* Sane returns data in top down order.  Acrobat does best with
476            a bottom up DIB being returned.  */
477         line = p + (activeDS.sane_param.lines - 1) * dib_bytes_per_line;
478         for (i = activeDS.sane_param.lines - 1; i >= 0; i--)
479         {
480             activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd,
481                     ((activeDS.sane_param.lines - 1 - i) * 100)
482                             /
483                     (activeDS.sane_param.lines - 1));
484
485             status = read_one_line(activeDS.deviceHandle, line,
486                             activeDS.sane_param.bytes_per_line);
487             if (status != SANE_STATUS_GOOD)
488                 break;
489
490             line -= dib_bytes_per_line;
491         }
492         activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd, -1);
493
494         GlobalUnlock(hDIB);
495
496         if (status != SANE_STATUS_GOOD && status != SANE_STATUS_EOF)
497         {
498             WARN("psane_read: %s, reading line %d\n", psane_strstatus(status), i);
499             psane_cancel (activeDS.deviceHandle);
500             activeDS.twCC = TWCC_OPERATIONERROR;
501             GlobalFree(hDIB);
502             return TWRC_FAILURE;
503         }
504
505         psane_cancel (activeDS.deviceHandle);
506         *pHandle = (TW_UINT32)hDIB;
507         twRC = TWRC_XFERDONE;
508         activeDS.twCC = TWCC_SUCCESS;
509         activeDS.currentState = 7;
510     }
511     return twRC;
512 #endif
513 }
514
515 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GET */
516 TW_UINT16 SANE_JPEGCompressionGet (pTW_IDENTITY pOrigin, 
517                                     TW_MEMREF pData)
518 {
519     FIXME ("stub!\n");
520
521     return TWRC_FAILURE;
522 }
523
524 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GETDEFAULT */
525 TW_UINT16 SANE_JPEGCompressionGetDefault (pTW_IDENTITY pOrigin,
526                                            
527                                            TW_MEMREF pData)
528 {
529     FIXME ("stub!\n");
530
531     return TWRC_FAILURE;
532 }
533
534 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_RESET */
535 TW_UINT16 SANE_JPEGCompressionReset (pTW_IDENTITY pOrigin, 
536                                       TW_MEMREF pData)
537 {
538     FIXME ("stub!\n");
539
540     return TWRC_FAILURE;
541 }
542
543 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_SET */
544 TW_UINT16 SANE_JPEGCompressionSet (pTW_IDENTITY pOrigin, 
545                                     TW_MEMREF pData)
546 {
547     FIXME ("stub!\n");
548
549     return TWRC_FAILURE;
550 }
551
552 /* DG_IMAGE/DAT_PALETTE8/MSG_GET */
553 TW_UINT16 SANE_Palette8Get (pTW_IDENTITY pOrigin, 
554                              TW_MEMREF pData)
555 {
556     FIXME ("stub!\n");
557
558     return TWRC_FAILURE;
559 }
560
561 /* DG_IMAGE/DAT_PALETTE8/MSG_GETDEFAULT */
562 TW_UINT16 SANE_Palette8GetDefault (pTW_IDENTITY pOrigin, 
563                                     TW_MEMREF pData)
564 {
565     FIXME ("stub!\n");
566
567     return TWRC_FAILURE;
568 }
569
570 /* DG_IMAGE/DAT_PALETTE8/MSG_RESET */
571 TW_UINT16 SANE_Palette8Reset (pTW_IDENTITY pOrigin, 
572                                TW_MEMREF pData)
573 {
574     FIXME ("stub!\n");
575
576     return TWRC_FAILURE;
577 }
578
579 /* DG_IMAGE/DAT_PALETTE8/MSG_SET */
580 TW_UINT16 SANE_Palette8Set (pTW_IDENTITY pOrigin, 
581                              TW_MEMREF pData)
582 {
583     FIXME ("stub!\n");
584
585     return TWRC_FAILURE;
586 }
587
588 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_RESET */
589 TW_UINT16 SANE_RGBResponseReset (pTW_IDENTITY pOrigin, 
590                                   TW_MEMREF pData)
591 {
592     FIXME ("stub!\n");
593
594     return TWRC_FAILURE;
595 }
596
597 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_SET */
598 TW_UINT16 SANE_RGBResponseSet (pTW_IDENTITY pOrigin, 
599                                 TW_MEMREF pData)
600 {
601     FIXME ("stub!\n");
602
603     return TWRC_FAILURE;
604 }