2 * Copyright 2000 Corel Corporation
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(twain
);
29 static TW_UINT16
get_onevalue(pTW_CAPABILITY pCapability
, TW_UINT16
*type
, TW_UINT32
*value
)
31 if (pCapability
->hContainer
)
33 pTW_ONEVALUE pVal
= GlobalLock (pCapability
->hContainer
);
38 *type
= pVal
->ItemType
;
39 GlobalUnlock (pCapability
->hContainer
);
47 static TW_UINT16
set_onevalue(pTW_CAPABILITY pCapability
, TW_UINT16 type
, TW_UINT32 value
)
49 pCapability
->hContainer
= GlobalAlloc (0, sizeof(TW_ONEVALUE
));
51 if (pCapability
->hContainer
)
53 pTW_ONEVALUE pVal
= GlobalLock (pCapability
->hContainer
);
56 pCapability
->ConType
= TWON_ONEVALUE
;
57 pVal
->ItemType
= type
;
59 GlobalUnlock (pCapability
->hContainer
);
63 return TWCC_LOWMEMORY
;
66 static TW_UINT16
msg_set(pTW_CAPABILITY pCapability
, TW_UINT32
*val
)
68 if (pCapability
->ConType
== TWON_ONEVALUE
)
69 return get_onevalue(pCapability
, NULL
, val
);
71 FIXME("Partial Stub: MSG_SET only supports TW_ONEVALUE\n");
76 static TW_UINT16
msg_get_enum(pTW_CAPABILITY pCapability
, const TW_UINT32
*values
, int value_count
,
77 TW_UINT16 type
, TW_UINT32 current
, TW_UINT32 default_value
)
79 TW_ENUMERATION
*enumv
= NULL
;
84 pCapability
->ConType
= TWON_ENUMERATION
;
85 pCapability
->hContainer
= 0;
87 if (type
== TWTY_INT16
|| type
== TWTY_UINT16
)
88 pCapability
->hContainer
= GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION
, ItemList
[value_count
* sizeof(TW_UINT16
)]));
90 if (type
== TWTY_INT32
|| type
== TWTY_UINT32
)
91 pCapability
->hContainer
= GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION
, ItemList
[value_count
* sizeof(TW_UINT32
)]));
93 if (pCapability
->hContainer
)
94 enumv
= GlobalLock(pCapability
->hContainer
);
97 return TWCC_LOWMEMORY
;
99 enumv
->ItemType
= type
;
100 enumv
->NumItems
= value_count
;
102 p16
= (TW_UINT16
*) enumv
->ItemList
;
103 p32
= (TW_UINT32
*) enumv
->ItemList
;
104 for (i
= 0; i
< value_count
; i
++)
106 if (values
[i
] == current
)
107 enumv
->CurrentIndex
= i
;
108 if (values
[i
] == default_value
)
109 enumv
->DefaultIndex
= i
;
110 if (type
== TWTY_INT16
|| type
== TWTY_UINT16
)
112 if (type
== TWTY_INT32
|| type
== TWTY_UINT32
)
116 GlobalUnlock(pCapability
->hContainer
);
120 static TW_UINT16
msg_get_range(pTW_CAPABILITY pCapability
, TW_UINT16 type
,
121 TW_UINT32 minval
, TW_UINT32 maxval
, TW_UINT32 step
, TW_UINT32 def
, TW_UINT32 current
)
123 TW_RANGE
*range
= NULL
;
125 pCapability
->ConType
= TWON_RANGE
;
126 pCapability
->hContainer
= 0;
128 pCapability
->hContainer
= GlobalAlloc (0, sizeof(*range
));
129 if (pCapability
->hContainer
)
130 range
= GlobalLock(pCapability
->hContainer
);
133 return TWCC_LOWMEMORY
;
135 range
->ItemType
= type
;
136 range
->MinValue
= minval
;
137 range
->MaxValue
= maxval
;
138 range
->StepSize
= step
;
139 range
->DefaultValue
= def
;
140 range
->CurrentValue
= current
;
142 GlobalUnlock(pCapability
->hContainer
);
146 static TW_UINT16
msg_get_array(pTW_CAPABILITY pCapability
, TW_UINT16 type
, const int *values
, int value_count
)
152 pCapability
->hContainer
= 0;
153 pCapability
->ConType
= TWON_ARRAY
;
155 if (type
== TWTY_INT16
|| type
== TWTY_UINT16
)
156 pCapability
->hContainer
= GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY
, ItemList
[value_count
* sizeof(TW_UINT16
)]));
157 else if (type
== TWTY_INT32
|| type
== TWTY_UINT32
)
158 pCapability
->hContainer
= GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY
, ItemList
[value_count
* sizeof(TW_UINT32
)]));
160 if (pCapability
->hContainer
)
163 a
= GlobalLock (pCapability
->hContainer
);
165 a
->NumItems
= value_count
;
166 p16
= (TW_UINT16
*) a
->ItemList
;
167 p32
= (TW_UINT32
*) a
->ItemList
;
168 for (i
= 0; i
< a
->NumItems
; i
++)
170 if (type
== TWTY_INT16
|| type
== TWTY_UINT16
)
172 else if (type
== TWTY_INT32
|| type
== TWTY_UINT32
)
175 GlobalUnlock (pCapability
->hContainer
);
179 return TWCC_LOWMEMORY
;
182 static TW_UINT16
TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability
)
184 static const int supported_caps
[] = { CAP_SUPPORTEDCAPS
, CAP_XFERCOUNT
, CAP_UICONTROLLABLE
,
185 CAP_AUTOFEED
, CAP_FEEDERENABLED
,
186 ICAP_XFERMECH
, ICAP_PIXELTYPE
, ICAP_UNITS
, ICAP_BITDEPTH
, ICAP_COMPRESSION
, ICAP_PIXELFLAVOR
,
187 ICAP_XRESOLUTION
, ICAP_YRESOLUTION
, ICAP_PHYSICALHEIGHT
, ICAP_PHYSICALWIDTH
, ICAP_SUPPORTEDSIZES
};
189 return msg_get_array(pCapability
, TWTY_UINT16
, supported_caps
, ARRAY_SIZE(supported_caps
));
194 static TW_UINT16
SANE_ICAPXferMech (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
196 static const TW_UINT32 possible_values
[] = { TWSX_NATIVE
, TWSX_MEMORY
};
198 TW_UINT16 twCC
= TWCC_BADCAP
;
200 TRACE("ICAP_XFERMECH\n");
204 case MSG_QUERYSUPPORT
:
205 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
206 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
210 twCC
= msg_get_enum(pCapability
, possible_values
, ARRAY_SIZE(possible_values
),
211 TWTY_UINT16
, activeDS
.capXferMech
, TWSX_NATIVE
);
215 twCC
= msg_set(pCapability
, &val
);
216 if (twCC
== TWCC_SUCCESS
)
218 activeDS
.capXferMech
= (TW_UINT16
) val
;
219 FIXME("Partial Stub: XFERMECH set to %ld, but ignored\n", val
);
224 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, TWSX_NATIVE
);
228 activeDS
.capXferMech
= TWSX_NATIVE
;
229 /* .. fall through intentional .. */
232 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, activeDS
.capXferMech
);
233 FIXME("Partial Stub: XFERMECH of %d not actually used\n", activeDS
.capXferMech
);
241 static TW_UINT16
SANE_CAPXferCount (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
244 TW_UINT16 twCC
= TWCC_BADCAP
;
246 TRACE("CAP_XFERCOUNT\n");
250 case MSG_QUERYSUPPORT
:
251 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
252 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
256 twCC
= set_onevalue(pCapability
, TWTY_INT16
, -1);
257 FIXME("Partial Stub: Reporting only support for transfer all\n");
261 twCC
= msg_set(pCapability
, &val
);
262 if (twCC
== TWCC_SUCCESS
)
263 FIXME("Partial Stub: XFERCOUNT set to %ld, but ignored\n", val
);
267 twCC
= set_onevalue(pCapability
, TWTY_INT16
, -1);
271 /* .. fall through intentional .. */
274 twCC
= set_onevalue(pCapability
, TWTY_INT16
, -1);
280 static BOOL
pixeltype_to_sane_mode(TW_UINT16 pixeltype
, char *mode
, int len
)
282 const char *m
= NULL
;
297 if (strlen(m
) >= len
)
304 static TW_UINT16
SANE_ICAPPixelType (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
307 TW_UINT32 possible_values
[3];
308 int possible_value_count
;
311 TW_UINT16 current_pixeltype
= TWPT_BW
;
314 TRACE("ICAP_PIXELTYPE\n");
316 twCC
= sane_option_probe_mode(¤t_pixeltype
, possible_values
, &possible_value_count
);
317 if (twCC
!= TWCC_SUCCESS
)
319 ERR("Unable to retrieve mode from sane, ICAP_PIXELTYPE unsupported\n");
323 /* Sane does not support a concept of a default mode, so we simply cache
324 * the first mode we find */
325 if (! activeDS
.PixelTypeSet
)
327 activeDS
.PixelTypeSet
= TRUE
;
328 activeDS
.defaultPixelType
= current_pixeltype
;
333 case MSG_QUERYSUPPORT
:
334 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
335 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
339 twCC
= msg_get_enum(pCapability
, possible_values
, possible_value_count
,
340 TWTY_UINT16
, current_pixeltype
, activeDS
.defaultPixelType
);
344 twCC
= msg_set(pCapability
, &val
);
345 if (twCC
== TWCC_SUCCESS
)
347 TRACE("Setting pixeltype to %ld\n", val
);
348 if (! pixeltype_to_sane_mode(val
, mode
, sizeof(mode
)))
349 return TWCC_BADVALUE
;
351 twCC
= sane_option_set_str("mode", mode
, &reload
);
352 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
353 if (twCC
!= TWCC_SUCCESS
&& strcmp(mode
, "Gray") == 0)
355 strcpy(mode
, "Grayscale");
356 twCC
= sane_option_set_str("mode", mode
, &reload
);
358 if (reload
) get_sane_params( &activeDS
.frame_params
);
363 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, activeDS
.defaultPixelType
);
367 current_pixeltype
= activeDS
.defaultPixelType
;
368 if (! pixeltype_to_sane_mode(current_pixeltype
, mode
, sizeof(mode
)))
369 return TWCC_BADVALUE
;
371 twCC
= sane_option_set_str("mode", mode
, &reload
);
372 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
373 if (twCC
!= TWCC_SUCCESS
&& strcmp(mode
, "Gray") == 0)
375 strcpy(mode
, "Grayscale");
376 twCC
= sane_option_set_str("mode", mode
, &reload
);
378 if (twCC
!= TWCC_SUCCESS
) break;
379 if (reload
) get_sane_params( &activeDS
.frame_params
);
381 /* .. fall through intentional .. */
384 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, current_pixeltype
);
385 TRACE("Returning current pixeltype of %d\n", current_pixeltype
);
393 static TW_UINT16
SANE_ICAPUnits (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
396 TW_UINT16 twCC
= TWCC_BADCAP
;
398 TRACE("ICAP_UNITS\n");
402 case MSG_QUERYSUPPORT
:
403 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
404 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
408 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, TWUN_INCHES
);
412 twCC
= msg_set(pCapability
, &val
);
413 if (twCC
== TWCC_SUCCESS
)
415 if (val
!= TWUN_INCHES
)
417 ERR("Sane supports only SANE_UNIT_DPI\n");
418 twCC
= TWCC_BADVALUE
;
425 /* .. fall through intentional .. */
428 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, TWUN_INCHES
);
436 static TW_UINT16
SANE_ICAPBitDepth(pTW_CAPABILITY pCapability
, TW_UINT16 action
)
438 TW_UINT16 twCC
= TWCC_BADCAP
;
439 TW_UINT32 possible_values
[1];
441 TRACE("ICAP_BITDEPTH\n");
443 possible_values
[0] = activeDS
.frame_params
.depth
;
447 case MSG_QUERYSUPPORT
:
448 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
449 TWQC_GET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
);
453 twCC
= msg_get_enum(pCapability
, possible_values
, ARRAY_SIZE(possible_values
),
454 TWTY_UINT16
, activeDS
.frame_params
.depth
, activeDS
.frame_params
.depth
);
458 /* .. Fall through intentional .. */
461 TRACE("Returning current bitdepth of %d\n", activeDS
.frame_params
.depth
);
462 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, activeDS
.frame_params
.depth
);
468 /* CAP_UICONTROLLABLE */
469 static TW_UINT16
SANE_CAPUiControllable(pTW_CAPABILITY pCapability
, TW_UINT16 action
)
471 TW_UINT16 twCC
= TWCC_BADCAP
;
473 TRACE("CAP_UICONTROLLABLE\n");
477 case MSG_QUERYSUPPORT
:
478 twCC
= set_onevalue(pCapability
, TWTY_INT32
, TWQC_GET
);
482 twCC
= set_onevalue(pCapability
, TWTY_BOOL
, TRUE
);
489 /* ICAP_COMPRESSION */
490 static TW_UINT16
SANE_ICAPCompression (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
492 static const TW_UINT32 possible_values
[] = { TWCP_NONE
};
494 TW_UINT16 twCC
= TWCC_BADCAP
;
496 TRACE("ICAP_COMPRESSION\n");
500 case MSG_QUERYSUPPORT
:
501 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
502 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
506 twCC
= msg_get_enum(pCapability
, possible_values
, ARRAY_SIZE(possible_values
),
507 TWTY_UINT16
, TWCP_NONE
, TWCP_NONE
);
508 FIXME("Partial stub: We don't attempt to support compression\n");
512 twCC
= msg_set(pCapability
, &val
);
513 if (twCC
== TWCC_SUCCESS
)
514 FIXME("Partial Stub: COMPRESSION set to %ld, but ignored\n", val
);
518 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, TWCP_NONE
);
522 /* .. fall through intentional .. */
525 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, TWCP_NONE
);
531 /* ICAP_XRESOLUTION, ICAP_YRESOLUTION */
532 static TW_UINT16
SANE_ICAPResolution (pTW_CAPABILITY pCapability
, TW_UINT16 action
, TW_UINT16 cap
)
534 TW_UINT16 twCC
= TWCC_BADCAP
;
536 int current_resolution
;
537 TW_FIX32
*default_res
;
538 const char *best_option_name
;
539 struct option_descriptor opt
;
541 TRACE("ICAP_%cRESOLUTION\n", cap
== ICAP_XRESOLUTION
? 'X' : 'Y');
543 /* Some scanners support 'x-resolution', most seem to just support 'resolution' */
544 if (cap
== ICAP_XRESOLUTION
)
546 best_option_name
= "x-resolution";
547 default_res
= &activeDS
.defaultXResolution
;
551 best_option_name
= "y-resolution";
552 default_res
= &activeDS
.defaultYResolution
;
554 if (sane_option_get_int(best_option_name
, ¤t_resolution
) != TWCC_SUCCESS
)
556 best_option_name
= "resolution";
557 if (sane_option_get_int(best_option_name
, ¤t_resolution
) != TWCC_SUCCESS
)
561 /* Sane does not support a concept of 'default' resolution, so we have to
562 * cache the resolution the very first time we load the scanner, and use that
564 if (cap
== ICAP_XRESOLUTION
&& ! activeDS
.XResolutionSet
)
566 default_res
->Whole
= current_resolution
;
567 default_res
->Frac
= 0;
568 activeDS
.XResolutionSet
= TRUE
;
571 if (cap
== ICAP_YRESOLUTION
&& ! activeDS
.YResolutionSet
)
573 default_res
->Whole
= current_resolution
;
574 default_res
->Frac
= 0;
575 activeDS
.YResolutionSet
= TRUE
;
580 case MSG_QUERYSUPPORT
:
581 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
582 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
586 twCC
= sane_option_probe_resolution(best_option_name
, &opt
);
587 if (twCC
== TWCC_SUCCESS
)
589 if (opt
.constraint_type
== CONSTRAINT_RANGE
)
590 twCC
= msg_get_range(pCapability
, TWTY_FIX32
,
591 opt
.constraint
.range
.min
, opt
.constraint
.range
.max
,
592 opt
.constraint
.range
.quant
== 0 ? 1 : opt
.constraint
.range
.quant
,
593 default_res
->Whole
, current_resolution
);
594 else if (opt
.constraint_type
== CONSTRAINT_WORD_LIST
)
595 twCC
= msg_get_array(pCapability
, TWTY_UINT32
, &(opt
.constraint
.word_list
[1]),
596 opt
.constraint
.word_list
[0]);
598 twCC
= TWCC_CAPUNSUPPORTED
;
603 twCC
= msg_set(pCapability
, &val
);
604 if (twCC
== TWCC_SUCCESS
)
608 memcpy(&f32
, &val
, sizeof(f32
));
609 twCC
= sane_option_set_int(best_option_name
, f32
.Whole
, &reload
);
610 if (reload
) twCC
= TWCC_CHECKSTATUS
;
615 twCC
= set_onevalue(pCapability
, TWTY_FIX32
, default_res
->Whole
);
619 twCC
= sane_option_set_int(best_option_name
, default_res
->Whole
, NULL
);
620 if (twCC
!= TWCC_SUCCESS
) return twCC
;
622 /* .. fall through intentional .. */
625 twCC
= set_onevalue(pCapability
, TWTY_FIX32
, current_resolution
);
631 /* ICAP_PHYSICALHEIGHT, ICAP_PHYSICALWIDTH */
632 static TW_UINT16
SANE_ICAPPhysical (pTW_CAPABILITY pCapability
, TW_UINT16 action
, TW_UINT16 cap
)
636 int tlx
, tly
, brx
, bry
;
638 TRACE("ICAP_PHYSICAL%s\n", cap
== ICAP_PHYSICALHEIGHT
? "HEIGHT" : "WIDTH");
640 twCC
= sane_option_get_max_scan_area( &tlx
, &tly
, &brx
, &bry
);
641 if (twCC
!= TWCC_SUCCESS
) return twCC
;
643 res
= convert_sane_res_to_twain( (cap
== ICAP_PHYSICALHEIGHT
) ? bry
- tly
: brx
- tlx
);
647 case MSG_QUERYSUPPORT
:
648 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
649 TWQC_GET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
);
655 /* .. fall through intentional .. */
658 twCC
= set_onevalue(pCapability
, TWTY_FIX32
, res
.Whole
| (res
.Frac
<< 16));
664 /* ICAP_PIXELFLAVOR */
665 static TW_UINT16
SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
667 TW_UINT16 twCC
= TWCC_BADCAP
;
668 static const TW_UINT32 possible_values
[] = { TWPF_CHOCOLATE
, TWPF_VANILLA
};
670 TW_UINT32 flavor
= activeDS
.frame_params
.depth
== 1 ? TWPF_VANILLA
: TWPF_CHOCOLATE
;
672 TRACE("ICAP_PIXELFLAVOR\n");
676 case MSG_QUERYSUPPORT
:
677 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
678 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
682 twCC
= msg_get_enum(pCapability
, possible_values
, ARRAY_SIZE(possible_values
),
683 TWTY_UINT16
, flavor
, flavor
);
687 twCC
= msg_set(pCapability
, &val
);
688 if (twCC
== TWCC_SUCCESS
)
690 FIXME("Stub: PIXELFLAVOR set to %ld, but ignored\n", val
);
695 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, flavor
);
699 /* .. fall through intentional .. */
702 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, flavor
);
708 static TW_UINT16
get_width_height(double *width
, double *height
, BOOL max
)
711 int tlx
, tly
, brx
, bry
;
713 if (max
) rc
= sane_option_get_max_scan_area( &tlx
, &tly
, &brx
, &bry
);
714 else rc
= sane_option_get_scan_area( &tlx
, &tly
, &brx
, &bry
);
716 if (rc
== TWCC_SUCCESS
)
718 *width
= (brx
- tlx
) / 65536.0;
719 *height
= (bry
- tly
) / 65536.0;
724 static TW_UINT16
set_width_height(double width
, double height
)
726 return sane_option_set_scan_area( 0, 0, width
* 65536, height
* 65536, NULL
);
736 static const supported_size_t supported_sizes
[] =
739 { TWSS_A4
, 210, 297 },
740 { TWSS_JISB5
, 182, 257 },
741 { TWSS_USLETTER
, 215.9, 279.4 },
742 { TWSS_USLEGAL
, 215.9, 355.6 },
743 { TWSS_A5
, 148, 210 },
744 { TWSS_B4
, 250, 353 },
745 { TWSS_B6
, 125, 176 },
746 { TWSS_USLEDGER
, 215.9, 431.8 },
747 { TWSS_USEXECUTIVE
, 184.15, 266.7 },
748 { TWSS_A3
, 297, 420 },
751 static TW_UINT16
get_default_paper_size(const supported_size_t
*s
, int n
)
756 double width
, height
;
758 rc
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_IPAPERSIZE
| LOCALE_RETURN_NUMBER
, (void *) &paper
, sizeof(paper
));
763 defsize
= TWSS_USLETTER
;
766 defsize
= TWSS_USLEGAL
;
779 if (get_width_height(&width
, &height
, TRUE
) != TWCC_SUCCESS
)
782 for (i
= 0; i
< n
; i
++)
783 if (s
[i
].size
== defsize
)
785 /* Sane's use of integers to store floats is a hair lossy; deal with it */
786 if (s
[i
].x
> (width
+ .01) || s
[i
].y
> (height
+ 0.01))
795 static TW_UINT16
get_current_paper_size(const supported_size_t
*s
, int n
)
798 double width
, height
;
799 double xdelta
, ydelta
;
801 if (get_width_height(&width
, &height
, FALSE
) != TWCC_SUCCESS
)
804 for (i
= 0; i
< n
; i
++)
806 /* Sane's use of integers to store floats results
807 * in a very small error; cope with that */
808 xdelta
= s
[i
].x
- width
;
809 ydelta
= s
[i
].y
- height
;
810 if (xdelta
< 0.01 && xdelta
> -0.01 &&
811 ydelta
< 0.01 && ydelta
> -0.01)
818 /* ICAP_SUPPORTEDSIZES */
819 static TW_UINT16
SANE_ICAPSupportedSizes (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
821 TW_UINT16 twCC
= TWCC_BADCAP
;
823 static TW_UINT32 possible_values
[ARRAY_SIZE(supported_sizes
)];
826 double max_width
, max_height
;
827 TW_UINT16 default_size
= get_default_paper_size(supported_sizes
, ARRAY_SIZE(supported_sizes
));
828 TW_UINT16 current_size
= get_current_paper_size(supported_sizes
, ARRAY_SIZE(supported_sizes
));
830 TRACE("ICAP_SUPPORTEDSIZES\n");
834 case MSG_QUERYSUPPORT
:
835 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
836 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
840 for (i
= 0; i
< ARRAY_SIZE(supported_sizes
); i
++)
841 possible_values
[i
] = supported_sizes
[i
].size
;
842 twCC
= msg_get_enum(pCapability
, possible_values
, ARRAY_SIZE(possible_values
),
843 TWTY_UINT16
, current_size
, default_size
);
844 WARN("Partial Stub: our supported size selection is a bit thin.\n");
848 twCC
= msg_set(pCapability
, &val
);
849 if (twCC
== TWCC_SUCCESS
)
850 for (i
= 1; i
< ARRAY_SIZE(supported_sizes
); i
++)
851 if (supported_sizes
[i
].size
== val
)
852 return set_width_height(supported_sizes
[i
].x
, supported_sizes
[i
].y
);
853 /* TWAIN: For devices that support physical dimensions TWSS_NONE indicates that the maximum
854 image size supported by the device is to be used. */
855 if (val
== TWSS_NONE
&& get_width_height(&max_width
, &max_height
, TRUE
) == TWCC_SUCCESS
)
856 return set_width_height(max_width
, max_height
);
857 ERR("Unsupported size %ld\n", val
);
862 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, default_size
);
867 for (i
= 1; i
< ARRAY_SIZE(supported_sizes
); i
++)
868 if (supported_sizes
[i
].size
== default_size
)
870 twCC
= set_width_height(supported_sizes
[i
].x
, supported_sizes
[i
].y
);
873 if (twCC
!= TWCC_SUCCESS
)
876 /* .. fall through intentional .. */
879 twCC
= set_onevalue(pCapability
, TWTY_UINT16
, current_size
);
887 static TW_UINT16
SANE_CAPAutofeed (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
889 TW_UINT16 twCC
= TWCC_BADCAP
;
893 TRACE("CAP_AUTOFEED\n");
895 if (sane_option_get_bool("batch-scan", &autofeed
) != TWCC_SUCCESS
)
900 case MSG_QUERYSUPPORT
:
901 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
902 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
906 twCC
= set_onevalue(pCapability
, TWTY_BOOL
, autofeed
);
910 twCC
= msg_set(pCapability
, &val
);
911 if (twCC
== TWCC_SUCCESS
)
912 twCC
= sane_option_set_bool("batch-scan", !!val
);
916 twCC
= set_onevalue(pCapability
, TWTY_BOOL
, TRUE
);
921 twCC
= sane_option_set_bool("batch-scan", autofeed
);
922 if (twCC
!= TWCC_SUCCESS
) break;
923 /* .. fall through intentional .. */
926 twCC
= set_onevalue(pCapability
, TWTY_BOOL
, autofeed
);
932 /* CAP_FEEDERENABLED */
933 static TW_UINT16
SANE_CAPFeederEnabled (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
935 TW_UINT16 twCC
= TWCC_BADCAP
;
940 TRACE("CAP_FEEDERENABLED\n");
942 if (sane_option_get_str("source", source
, sizeof(source
)) != TWCC_SUCCESS
)
945 if (strcmp(source
, "Auto") == 0 || strcmp(source
, "ADF") == 0)
952 case MSG_QUERYSUPPORT
:
953 twCC
= set_onevalue(pCapability
, TWTY_INT32
,
954 TWQC_GET
| TWQC_SET
| TWQC_GETDEFAULT
| TWQC_GETCURRENT
| TWQC_RESET
);
958 twCC
= set_onevalue(pCapability
, TWTY_BOOL
, enabled
);
962 twCC
= msg_set(pCapability
, &val
);
963 if (twCC
== TWCC_SUCCESS
)
965 strcpy(source
, "ADF");
966 twCC
= sane_option_set_str("source", source
, NULL
);
967 if (twCC
!= TWCC_SUCCESS
)
969 strcpy(source
, "Auto");
970 twCC
= sane_option_set_str("source", source
, NULL
);
976 twCC
= set_onevalue(pCapability
, TWTY_BOOL
, TRUE
);
980 strcpy(source
, "Auto");
981 if (sane_option_set_str("source", source
, NULL
) == TWCC_SUCCESS
)
983 /* .. fall through intentional .. */
986 twCC
= set_onevalue(pCapability
, TWTY_BOOL
, enabled
);
994 TW_UINT16
SANE_SaneCapability (pTW_CAPABILITY pCapability
, TW_UINT16 action
)
996 TW_UINT16 twCC
= TWCC_CAPUNSUPPORTED
;
998 TRACE("capability=%d action=%d\n", pCapability
->Cap
, action
);
1000 switch (pCapability
->Cap
)
1002 case CAP_SUPPORTEDCAPS
:
1003 if (action
== MSG_GET
)
1004 twCC
= TWAIN_GetSupportedCaps(pCapability
);
1006 twCC
= TWCC_BADVALUE
;
1010 twCC
= SANE_CAPXferCount (pCapability
, action
);
1013 case CAP_UICONTROLLABLE
:
1014 twCC
= SANE_CAPUiControllable (pCapability
, action
);
1018 twCC
= SANE_CAPAutofeed (pCapability
, action
);
1021 case CAP_FEEDERENABLED
:
1022 twCC
= SANE_CAPFeederEnabled (pCapability
, action
);
1025 case ICAP_PIXELTYPE
:
1026 twCC
= SANE_ICAPPixelType (pCapability
, action
);
1030 twCC
= SANE_ICAPUnits (pCapability
, action
);
1034 twCC
= SANE_ICAPBitDepth(pCapability
, action
);
1038 twCC
= SANE_ICAPXferMech (pCapability
, action
);
1041 case ICAP_PIXELFLAVOR
:
1042 twCC
= SANE_ICAPPixelFlavor (pCapability
, action
);
1045 case ICAP_COMPRESSION
:
1046 twCC
= SANE_ICAPCompression(pCapability
, action
);
1049 case ICAP_XRESOLUTION
:
1050 twCC
= SANE_ICAPResolution(pCapability
, action
, pCapability
->Cap
);
1053 case ICAP_YRESOLUTION
:
1054 twCC
= SANE_ICAPResolution(pCapability
, action
, pCapability
->Cap
);
1057 case ICAP_PHYSICALHEIGHT
:
1058 twCC
= SANE_ICAPPhysical(pCapability
, action
, pCapability
->Cap
);
1061 case ICAP_PHYSICALWIDTH
:
1062 twCC
= SANE_ICAPPhysical(pCapability
, action
, pCapability
->Cap
);
1065 case ICAP_SUPPORTEDSIZES
:
1066 twCC
= SANE_ICAPSupportedSizes (pCapability
, action
);
1069 case ICAP_PLANARCHUNKY
:
1070 FIXME("ICAP_PLANARCHUNKY not implemented\n");
1074 FIXME("ICAP_BITORDER not implemented\n");
1079 /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
1080 * even if you don't formally support the capability */
1081 if (twCC
== TWCC_CAPUNSUPPORTED
&& action
== MSG_QUERYSUPPORT
)
1082 twCC
= set_onevalue(pCapability
, 0, TWTY_INT32
);
1084 if (twCC
== TWCC_CAPUNSUPPORTED
)
1085 TRACE("capability 0x%x/action=%d being reported as unsupported\n", pCapability
->Cap
, action
);
1090 TW_UINT16
SANE_SaneSetDefaults (void)
1094 memset(&cap
, 0, sizeof(cap
));
1095 cap
.Cap
= CAP_AUTOFEED
;
1096 cap
.ConType
= TWON_DONTCARE16
;
1098 if (SANE_SaneCapability(&cap
, MSG_RESET
) == TWCC_SUCCESS
)
1099 GlobalFree(cap
.hContainer
);
1101 memset(&cap
, 0, sizeof(cap
));
1102 cap
.Cap
= CAP_FEEDERENABLED
;
1103 cap
.ConType
= TWON_DONTCARE16
;
1105 if (SANE_SaneCapability(&cap
, MSG_RESET
) == TWCC_SUCCESS
)
1106 GlobalFree(cap
.hContainer
);
1108 memset(&cap
, 0, sizeof(cap
));
1109 cap
.Cap
= ICAP_SUPPORTEDSIZES
;
1110 cap
.ConType
= TWON_DONTCARE16
;
1112 if (SANE_SaneCapability(&cap
, MSG_RESET
) == TWCC_SUCCESS
)
1113 GlobalFree(cap
.hContainer
);
1115 return TWCC_SUCCESS
;