-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwia.pas
3258 lines (2711 loc) · 105 KB
/
wia.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(****************************************************************************
* FreePascal \ Delphi WIA Implementation
*
* FILE: WIA.pas
*
* VERSION: 0.0.2
*
* DESCRIPTION:
* WIA Base classes.
*
*****************************************************************************
*
* (c) 2024 Massimo Magnano
*
* See changelog.txt for Change Log
*
*****************************************************************************)
unit WIA;
{$H+}
{$R-}
{$POINTERMATH ON}
interface
uses
Windows, DelphiCompatibility, Classes, SysUtils, ComObj, ActiveX,
WiaDef, WIA_LH, Wia_PaperSizes;
type
//Dinamic Array types
TArraySingle = array of Single;
TArrayDouble = array of Double;
TArrayInteger = array of Integer;
TArraySmallint = array of Smallint;
TArrayByte = array of Byte;
TArrayWord = array of Word;
TArrayLongWord = array of LongWord;
TStringArray = array of String;
TArrayGUID = array of TGUID;
TWIAManager = class;
TWIAItemType = (
witFree,
witImage,
witFile,
witFolder,
witRoot,
witAnalyze,
witAudio,
witDevice,
witDeleted,
witDisconnected,
witHPanorama,
witVPanorama,
witBurst,
witStorage,
witTransfer,
witGenerated,
witHasAttachments,
witVideo,
witTwainCompatibility,
witRemoved,
witDocument,
witProgrammableDataSource
);
TWIAItemTypes = set of TWIAItemType;
TWIAItemCategory = (
wicNULL,
wicFINISHED_FILE,
wicFLATBED,
wicFEEDER,
wicFILM,
wicROOT,
wicFOLDER,
wicFEEDER_FRONT,
wicFEEDER_BACK,
wicAUTO,
wicIMPRINTER,
wicENDORSER,
wicBARCODE_READER,
wicPATCH_CODE_READER,
wicMICR_READER
);
TWIAItem = record
Name: String;
ItemType: TWIAItemTypes;
ItemCategory: TWIAItemCategory;
end;
PWIAItem = ^TWIAItem;
TArrayWIAItem = array of TWIAItem;
TWIADeviceType = (
WIADeviceTypeDefault = StiDeviceTypeDefault,
WIADeviceTypeScanner = StiDeviceTypeScanner,
WIADeviceTypeDigitalCamera = StiDeviceTypeDigitalCamera,
WIADeviceTypeStreamingVideo = StiDeviceTypeStreamingVideo
);
TWIAPropertyFlag = (
WIAProp_READ, WIAProp_WRITE, WIAProp_SYNC_REQUIRED, WIAProp_NONE,
WIAProp_RANGE, WIAProp_LIST, WIAProp_FLAG, WIAProp_CACHEABLE
);
TWIAPropertyFlags = set of TWIAPropertyFlag;
TWIARotation = (
wrPortrait = WiaDef.PORTRAIT,
wrLandscape = WiaDef.LANSCAPE,
wrRot180 = WiaDef.ROT180,
wrRot270 = WiaDef.ROT270
);
TWIARotationSet = set of TWIARotation;
TWIADocumentHandling = (
wdhFeeder,
wdhFlatbed,
wdhDuplex,
wdhFront_First,
wdhBack_First,
wdhFront_Only,
wdhBack_Only,
wdhNext_Page,
wdhPreFeed,
wdhAuto_Advance,
wdhAdvanced_Duplex
);
TWIADocumentHandlingSet = set of TWIADocumentHandling;
TWIAAlignVertical = (waVTop, waVCenter, waVBottom);
TWIAAlignHorizontal = (waHLeft, waHCenter, waHRight);
TWIAImageFormat = (
wifUNDEFINED,
wifRAWRGB,
wifMEMORYBMP,
wifBMP,
wifEMF,
wifWMF,
wifJPEG,
wifPNG,
wifGIF,
wifTIFF,
wifEXIF,
wifPHOTOCD,
wifFLASHPIX,
wifICO,
wifCIFF,
wifPICT,
wifJPEG2K,
wifJPEG2KX,
wifRAW,
wifJBIG,
wifJBIG2
);
TWIAImageFormatSet = set of TWIAImageFormat;
TWIADataType = (
wdtBN = WIA_DATA_THRESHOLD,
wdtDITHER = WIA_DATA_DITHER,
wdtGRAYSCALE = WIA_DATA_GRAYSCALE,
wdtCOLOR = WIA_DATA_COLOR,
wdtCOLOR_THRESHOLD = WIA_DATA_COLOR_THRESHOLD,
wdtCOLOR_DITHER = WIA_DATA_COLOR_DITHER,
wdtRAW_RGB = WIA_DATA_RAW_RGB,
wdtRAW_BGR = WIA_DATA_RAW_BGR,
wdtRAW_YUV = WIA_DATA_RAW_YUV,
wdtRAW_YUVK = WIA_DATA_RAW_YUVK,
wdtRAW_CMY = WIA_DATA_RAW_CMY,
wdtRAW_CMYK = WIA_DATA_RAW_CMYK,
wdtAUTO = WIA_DATA_AUTO
);
TWIADataTypeSet = set of TWIADataType;
TWIAParams = packed record
NativeUI: Boolean;
PaperType: TWIAPaperType;
//Used only if PaperType=wptCUSTOM
PaperW,
PaperH: Integer;
Rotation: TWIARotation;
HAlign: TWIAAlignHorizontal;
VAlign: TWIAAlignVertical;
Resolution,
Contrast,
//BitDepth,
Brightness: Integer;
DataType: TWIADataType;
DocHandling: TWIADocumentHandlingSet; { #todo 5 -oMaxM : Must be tested in a Duplex Scanner first }
end;
TArrayWIAParams = array of TWIAParams;
TWIAParamsCapabilities = packed record
PaperSizeMaxWidth,
PaperSizeMaxHeight: Integer;
PaperTypeSet: TWIAPaperTypeSet;
PaperTypeCurrent,
PaperTypeDefault: TWIAPaperType;
RotationCurrent,
RotationDefault: TWIARotation;
RotationSet: TWIARotationSet;
ResolutionArray: TArrayInteger;
ResolutionRange: Boolean;
ResolutionCurrent,
ResolutionDefault,
BrightnessCurrent,
BrightnessDefault,
BrightnessMin,
BrightnessMax,
BrightnessStep,
ContrastCurrent,
ContrastDefault,
ContrastMin,
ContrastMax,
ContrastStep (*,
BitDepthCurrent,
BitDepthDefault*): Integer;
//BitDepthArray: TArrayInteger;
DataTypeCurrent,
DataTypeDefault: TWIADataType;
DataTypeSet: TWIADataTypeSet;
DocHandlingCurrent,
DocHandlingDefault,
DocHandlingSet: TWIADocumentHandlingSet; { #todo 5 -oMaxM : Must be tested in a Duplex Scanner }
end;
TArrayWIAParamsCapabilities = array of TWIAParamsCapabilities;
{ TWIADevice }
TWIADevice = class(TNoRefCountObject, IWiaTransferCallback)
protected
rOwner: TWIAManager;
rIndex: Integer;
rID,
rManufacturer,
rName: String;
rType: TWIADeviceType;
rSubType: Word;
rVersion,
rVersionSub: Integer;
lres: HResult;
pRootItem,
pSelectedItem: IWiaItem2;
pRootProperties,
pSelectedProperties: IWiaPropertyStorage;
StreamDestination: TFileStream;
StreamAdapter: TStreamAdapter;
rSelectedItemIndex: Integer;
HasEnumerated: Boolean;
rItemList : TArrayWIAItem;
rXRes, rYRes: Integer; //Used with PaperSizes_Calculated, if -1 then i need to Get Values from Device
rPaperLandscape: Boolean;
rHAlign: TWIAAlignHorizontal;
rVAlign: TWIAAlignVertical;
rDownloaded: Boolean;
rDownload_Count: Integer;
rDownload_Path,
rDownload_Ext,
rDownload_FileName: String;
function GetItem(Index: Integer): PWIAItem;
function GetItemCount: Integer;
procedure SetSelectedItemIndex(AValue: Integer);
function GetSelectedItem: PWIAItem;
function GetRootItemIntf: IWiaItem2;
function GetSelectedItemIntf: IWiaItem2;
function GetRootPropertiesIntf: IWiaPropertyStorage;
function GetSelectedPropertiesIntf: IWiaPropertyStorage;
//Enumerate the avaliable items
function EnumerateItems: Boolean;
function CreateDestinationStream(FileName: String; var ppDestination: IStream): HRESULT;
public
//Behaviour Variables
PaperSizes_Calculated: Boolean;
//IWiaTransferCallback implementation
function TransferCallback(lFlags: LONG;
pWiaTransferParams: PWiaTransferParams): HRESULT; stdcall;
function GetNextStream(lFlags: LONG;
bstrItemName,
bstrFullItemName: BSTR;
out ppDestination: IStream): HRESULT; stdcall;
constructor Create(AOwner: TWIAManager; AIndex: Integer; ADeviceID: String);
destructor Destroy; override;
function SelectItem(AName: String): Boolean;
//Download the Selected Item and return the number of files transfered.
// if multiple pages is downloaded then the file names are
// APath\AFileName-n.AExt where n is then Index (when 0 n is not present)
function Download(APath, AFileName, AExt: String): Integer; overload;
function Download(APath, AFileName, AExt: String; AFormat: TWIAImageFormat): Integer; overload;
function Download(APath, AFileName, AExt: String; AFormat: TWIAImageFormat;
var DownloadedFiles: TStringArray; UseRelativePath: Boolean=False): Integer; overload;
(* // In Wia 2 the user must specify what to download from the feeder using the ADocHandling parameter,
// the SettingsForm store DocHandling in Params so the user can use here.
function Download(APath, AFileName, AExt: String; ADocHandling: TWIADocumentHandlingSet=[]): Integer; overload;
function Download(APath, AFileName, AExt: String;
AFormat: TWIAImageFormat;
ADocHandling: TWIADocumentHandlingSet=[]): Integer; overload;
*)
//Download using Native UI and return the number of files transfered in DownloadedFiles array.
// The system dialog works at Device level, so the selected item is ignored
function DownloadNativeUI(hwndParent: HWND; useSystemUI: Boolean;
APath, AFileName: String;
var DownloadedFiles: TStringArray; UseRelativePath: Boolean=False): Integer;
//Get Current Property Value and it's type given the ID
function GetProperty(APropId: PROPID; var propType: TVarType;
var APropValue; useRoot: Boolean=False): Boolean; overload;
//Get Current, Default and Possible Values of a Property given the ID,
// Depending on the type returned in propType
// APropListValues can be a Dynamic Array of Integers, Real, etc... user must free it
// if Result contain the Flag WIAProp_RANGE then use WIA_RANGE_XXX Indexes to get MIN/MAX/STEP Values
function GetProperty(APropId: PROPID; var propType: TVarType;
var APropValue, APropDefaultValue;
var APropListValues;
useRoot: Boolean=False): TWIAPropertyFlags; overload;
//Get a Range Property with Current, Default, Min, Max, Step Values { #note 5 -oMaxM : do I keep it? }
function GetProperty(APropId: PROPID; var propType: TVarType;
var APropValue, APropDefault, APropMin, APropMax, APropStep;
useRoot: Boolean=False): Boolean; overload;
//Set the Property Value given the ID, the user must know the correct type to use
function SetProperty(APropId: PROPID; propType: TVarType; const APropValue; useRoot: Boolean=False): Boolean;
{ #note -oMaxM : Build overloaded functions for Set/Get Property? }
(*
function SetProperty(APropId: PROPID; APropValue: Smallint; useRoot: Boolean=False): Boolean; overload; //VT_I2
function SetProperty(APropId: PROPID; APropValue: Integer; useRoot: Boolean=False): Boolean; overload; //VT_I4, VT_INT
function SetProperty(APropId: PROPID; APropValue: Single; useRoot: Boolean=False): Boolean; overload; //VT_R4
function SetProperty(APropId: PROPID; APropValue: Double; useRoot: Boolean=False): Boolean; overload; //VT_R8
function SetProperty(APropId: PROPID; APropValue: Currency; useRoot: Boolean=False): Boolean; overload; //VT_R8
function SetProperty(APropId: PROPID; APropValue: TDateTime; useRoot: Boolean=False): Boolean; overload; //VT_DATE
function SetProperty(APropId: PROPID; APropValue: BSTR; useRoot: Boolean=False): Boolean; overload; //VT_BSTR
function SetProperty(APropId: PROPID; APropValue: Boolean; useRoot: Boolean=False): Boolean; overload; //VT_BOOL
function SetProperty(APropId: PROPID; APropValue: Word; useRoot: Boolean=False): Boolean; overload; //VT_UI2
function SetProperty(APropId: PROPID; APropValue: DWord; useRoot: Boolean=False): Boolean; overload; //VT_UI4, VT_UINT
function SetProperty(APropId: PROPID; APropValue: Int64; useRoot: Boolean=False): Boolean; overload; //VT_I8
function SetProperty(APropId: PROPID; APropValue: UInt64; useRoot: Boolean=False): Boolean; overload; //VT_UI8
function SetProperty(APropId: PROPID; APropValue: LPSTR; useRoot: Boolean=False): Boolean; overload; //VT_LPSTR
// procedure SetProperty(APropId: PROPID; APropValue: LPWSTR; useRoot: Boolean=False): Boolean; overload; //VT_LPWSTR
*)
//Get Available Values for XResolution,
// if Result contain the Flag WIAProp_RANGE then use WIA_RANGE_XXX Indexes to get MIN/MAX/STEP Values
function GetResolutionsX(var Current, Default: Integer; var Values: TArrayInteger; useRoot: Boolean=False): TWIAPropertyFlags;
//Get Available Values for YResolutions
function GetResolutionsY(var Current, Default: Integer; var Values: TArrayInteger; useRoot: Boolean=False): TWIAPropertyFlags;
//Get the Minimun and Maximum Resolutions Values
function GetResolutionsLimit(var AMin, AMax: Integer; useRoot: Boolean=False): Boolean; overload;
function GetResolutionsLimit(var AMinX, AMaxX, AMinY, AMaxY: Integer; useRoot: Boolean=False): Boolean; overload;
//Get Current Resolutions
function GetResolution(var AXRes, AYRes: Integer; useRoot: Boolean=False): Boolean;
//Set Current Resolutions, The user is responsible for checking the validity of the values
function SetResolution(const AXRes, AYRes: Integer; useRoot: Boolean=False): Boolean;
//Get Current Paper Align
function GetPaperAlign(var ALandscape:Boolean; var HAlign: TWIAAlignHorizontal; var VAlign: TWIAAlignVertical;
useRoot: Boolean=False): Boolean;
//Set Current Paper Align
function SetPaperAlign(const ALandscape:Boolean; const HAlign: TWIAAlignHorizontal; const VAlign: TWIAAlignVertical;
useRoot: Boolean=False): Boolean;
//Get Max Paper Width, Height
function GetPaperSizeMax(var AMaxWidth, AMaxHeight: Integer; useRoot: Boolean=False): Boolean;
//Get Current Paper Type
// if PaperSizes_Calculated then the PaperSize is calculated using real Paper Size
// else this functions uses WIA_IPS_PAGE_SIZE
function GetPaperType(var Current: TWIAPaperType; useRoot: Boolean=False): Boolean; overload;
//Get Available Paper Sizes
function GetPaperType(var Current, Default: TWIAPaperType; var Values: TWIAPaperTypeSet; useRoot: Boolean=False): Boolean; overload;
//Set Current Paper Type,
// if PaperSizes_Calculated then the Area is calculated using real Paper Size,Orientation and Align Values
// else this function use WIA_IPS_PAGE_SIZE and the user is responsible for checking the validity of the value
function SetPaperType(const Value: TWIAPaperType; useRoot: Boolean=False): Boolean;
//Set Current Paper Size, the Area is calculated using Width, Height (in TH Inchs),Orientation and Align Values
function SetPaperSize(Width, Height: Integer; useRoot: Boolean=False): Boolean;
//Get Current Paper Landscape,
// if PaperSizes_Calculated=False then this function use WIA_IPS_ROTATION else return internal value
function GetPaperLandscape(var Value: Boolean; useRoot: Boolean=False): Boolean;
//Set Current Paper Landscape,
// if PaperSizes_Calculated=False then this function use WIA_IPS_ROTATION
// else set internal value and rotation is done when papersize is setted
function SetPaperLandscape(const Value: Boolean; useRoot: Boolean=False): Boolean;
//Get Current Rotation,
// Not to be confused with PaperLandscape, this function only uses WIA_IPS_ROTATION
function GetRotation(var Value: TWIARotation; useRoot: Boolean=False): Boolean; overload;
//Get Available Rotations
function GetRotation(var Current, Default: TWIARotation; var Values: TWIARotationSet; useRoot: Boolean=False): Boolean; overload;
//Set Current Rotation,
// Not to be confused with PaperLandscape, this function only uses WIA_IPS_ROTATION
// which rotates the image after capturing it
function SetRotation(const Value: TWIARotation; useRoot: Boolean=False): Boolean;
//Get Current DocumentHandling,
function GetDocumentHandling(var Value: TWIADocumentHandlingSet; useRoot: Boolean=False): Boolean; overload;
//Get Available DocumentHandling
function GetDocumentHandling(var Current, Default, Values: TWIADocumentHandlingSet; useRoot: Boolean=False): Boolean; overload;
//Set Current Rotation,
// Not to be confused with PaperLandscape, this function only uses WIA_IPS_ROTATION
// which rotates the image after capturing it
function SetDocumentHandling(const Value: TWIADocumentHandlingSet; useRoot: Boolean=False): Boolean;
//Get Current Pages (0 = All)
function GetPages(var Current: Integer; useRoot: Boolean=False): Boolean; overload;
//Get Current, Default and Range Values for Pages
function GetPages(var Current, Default, AMin, AMax, AStep: Integer; useRoot: Boolean=False): Boolean; overload;
//Set Current Pages (0 = All)
// If a Feeder Scanner is unable to scan only one side of a page while in Duplex you must use an even value
function SetPages(const Value: Integer; useRoot: Boolean=False): Boolean;
//Get Current Brightness
function GetBrightness(var Current: Integer; useRoot: Boolean=False): Boolean; overload;
//Get Current, Default and Range Values for Brightness
function GetBrightness(var Current, Default, AMin, AMax, AStep: Integer; useRoot: Boolean=False): Boolean; overload;
//Set Current Brightness, The user is responsible for checking the validity of the value
function SetBrightness(const Value: Integer; useRoot: Boolean=False): Boolean;
//Get Current Contrast
function GetContrast(var Current: Integer; useRoot: Boolean=False): Boolean; overload;
//Get Current, Default and Range Values for Contrast
function GetContrast(var Current, Default, AMin, AMax, AStep: Integer; useRoot: Boolean=False): Boolean; overload;
//Set Current Contrast, The user is responsible for checking the validity of the value
function SetContrast(const Value: Integer; useRoot: Boolean=False): Boolean;
//Get Current Image Format
function GetImageFormat(var Current: TWIAImageFormat; useRoot: Boolean=False): Boolean; overload;
//Get Available Image Formats
function GetImageFormat(var Current, Default: TWIAImageFormat; var Values: TWIAImageFormatSet; useRoot: Boolean=False): Boolean; overload;
//Set Current Image Format
function SetImageFormat(const Value: TWIAImageFormat; useRoot: Boolean=False): Boolean;
//Get Current Image DataType
function GetDataType(var Current: TWIADataType; useRoot: Boolean=False): Boolean; overload;
//Get Available Image DataTypes
function GetDataType(var Current, Default: TWIADataType; var Values: TWIADataTypeSet; useRoot: Boolean=False): Boolean; overload;
//Set Current Image DataType
function SetDataType(const Value: TWIADataType; useRoot: Boolean=False): Boolean;
//Get Available Values for BitDepth
function GetBitDepth(var Current, Default: Integer; var Values: TArrayInteger; useRoot: Boolean=False): TWIAPropertyFlags; overload;
//Get Current BitDepth
function GetBitDepth(var Current: Integer; useRoot: Boolean=False): Boolean; overload;
//Set Current BitDepth, The user is responsible for checking the validity of the value
function SetBitDepth(const Value: Integer; useRoot: Boolean=False): Boolean;
//Get Capabilities for Current Selected Item
function GetParamsCapabilities(var Value: TWIAParamsCapabilities): Boolean;
//Set Params to Current Selected Item
function SetParams(const AParams: TWIAParams): Boolean;
//Get Sub Items of Selected Item if any
function GetSelectedItemSubItems(var AItemArray: TArrayWIAItem): Boolean;
property ID: String read rID;
property Manufacturer: String read rManufacturer;
property Name: String read rName;
property Type_: TWIADeviceType read rType;
property SubType: Word read rSubType;
property ItemCount: Integer read GetItemCount;
//Returns an Item by it's Index
// Note:
// In WIA 1.0, the root device only has a single child, "Scan"
// https://docs.microsoft.com/en-us/windows-hardware/drivers/image/wia-scanner-tree
// In WIA 2.0, the root device may have multiple children, i.e. "Flatbed" and "Feeder"
// https://docs.microsoft.com/en-us/windows-hardware/drivers/image/non-duplex-capable-document-feeder
// The "Feeder" child may also have a pair of children (for front/back sides with duplex)
// https://docs.microsoft.com/en-us/windows-hardware/drivers/image/simple-duplex-capable-document-feeder
{ #todo 10 -oMaxM : It would be better to keep an array of Item Classes where you can move the various Get/Set Properties methods}
property Items[Index: Integer]: PWIAItem read GetItem;
property RootItemIntf: IWiaItem2 read GetRootItemIntf;
property RootPropertiesIntf: IWiaPropertyStorage read GetRootPropertiesIntf;
property SelectedItemIntf: IWiaItem2 read GetSelectedItemIntf;
property SelectedPropertiesIntf: IWiaPropertyStorage read GetSelectedPropertiesIntf;
property SelectedItem: PWIAItem read GetSelectedItem;
property SelectedItemIndex: Integer read rSelectedItemIndex write SetSelectedItemIndex;
property Downloaded: Boolean read rDownloaded;
property Download_Count: Integer read rDownload_Count;
property Download_Path: String read rDownload_Path;
property Download_Ext: String read rDownload_Ext;
property Download_FileName: String read rDownload_FileName;
end;
{ TWIAManager }
TOnDeviceTransfer = function (AWiaManager: TWIAManager; AWiaDevice: TWIADevice;
lFlags: LONG; pWiaTransferParams: PWiaTransferParams): Boolean of object;
TWIAManager = class(TObject)
protected
rEnumAll: Boolean;
pDevMgr: WIA_LH.IWiaDevMgr2;
lres: HResult;
HasEnumerated: Boolean;
rSelectedDeviceIndex: Integer;
rDeviceList : array of TWIADevice;
rOnAfterDeviceTransfer,
rOnBeforeDeviceTransfer: TOnDeviceTransfer;
function GetDevMgrIntf: WIA_LH.IWiaDevMgr2;
procedure SetEnumAll(AValue: Boolean);
function GetSelectedDevice: TWIADevice;
procedure SetSelectedDeviceIndex(AValue: Integer);
function GetDevice(Index: Integer): TWIADevice;
function GetDevicesCount: Integer;
function CreateDevManager: IUnknown; virtual;
procedure EmptyDeviceList(setZeroLength:Boolean);
//Enumerate the avaliable devices
function EnumerateDevices: Boolean;
public
constructor Create(AEnumAll: Boolean = True);
destructor Destroy; override;
//Clears the list of sources
procedure ClearDeviceList;
//Refresh the list of sources
procedure RefreshDeviceList;
//Display a dialog to let the user choose a Device and returns it's index
function SelectDeviceDialog: Integer; virtual;
//Finds a matching Device index
function FindDevice(AID: String): Integer; overload;
function FindDevice(Value: TWIADevice): Integer; overload;
function FindDevice(AName: String; AManufacturer: String=''): Integer; overload;
//Find a Device by it's ID and Select the given Item
procedure SelectDeviceItem(ADeviceID, ADeviceItem: String; var ADevice: TWIADevice; var AIndex: Integer);
property DevMgrIntf: WIA_LH.IWiaDevMgr2 read GetDevMgrIntf;
//Kind of Enum, if True Enum even disconnected Devices
property EnumAll: Boolean read rEnumAll write SetEnumAll;
//Returns a Device
property Devices[Index: Integer]: TWIADevice read GetDevice;
//Returns the number of Devices
property DevicesCount: Integer read GetDevicesCount;
//Selected Device index
property SelectedDeviceIndex: Integer read rSelectedDeviceIndex write SetSelectedDeviceIndex;
//Selected Device in a dialog
property SelectedDevice: TWIADevice read GetSelectedDevice;
//Events
property OnBeforeDeviceTransfer:TOnDeviceTransfer read rOnBeforeDeviceTransfer write rOnBeforeDeviceTransfer;
property OnAfterDeviceTransfer:TOnDeviceTransfer read rOnAfterDeviceTransfer write rOnAfterDeviceTransfer;
end;
const
WIADeviceTypeDescr : array [TWIADeviceType] of String = (
'Default', 'Scanner', 'Digital Camera', 'Streaming Video'
);
WiaImageFormatGUID : array [TWIAImageFormat] of TGUID = (
'{b96b3ca9-0728-11d3-9d7b-0000f81ef32e}',
'{bca48b55-f272-4371-b0f1-4a150d057bb4}',
'{b96b3caa-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cab-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cac-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cad-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cae-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3caf-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cb0-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cb1-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cb2-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cb3-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cb4-0728-11d3-9d7b-0000f81ef32e}',
'{b96b3cb5-0728-11d3-9d7b-0000f81ef32e}',
'{9821a8ab-3a7e-4215-94e0-d27a460c03b2}',
'{a6bc85d8-6b3e-40ee-a95c-25d482e41adc}',
'{344ee2b2-39db-4dde-8173-c4b75f8f1e49}',
'{43e14614-c80a-4850-baf3-4b152dc8da27}',
'{6f120719-f1a8-4e07-9ade-9b64c63a3dcc}',
'{41e8dd92-2f0a-43d4-8636-f1614ba11e46}',
'{bb8e7e67-283c-4235-9e59-0b9bf94ca687}'
);
WiaImageFormatDescr : array [TWIAImageFormat] of String = (
'Undefined',
'Raw RGB format',
'Windows bitmap without a header',
'Windows Device Independent Bitmap',
'Extended Windows metafile',
'Windows metafile',
'JPEG compressed format',
'W3C PNG format',
'GIF image format',
'Tagged Image File format',
'Exchangeable File Format',
'Eastman Kodak file format',
'FlashPix format',
'Windows icon file format',
'Camera Image File format',
'Apple file format',
'JPEG 2000 compressed format',
'JPEG 2000X compressed format',
'WIA Raw image file format',
'Joint Bi-level Image experts Group format',
'Joint Bi-level Image experts Group format (ver 2)'
);
WiaItemCategoryGUID : array[TWIAItemCategory] of TGUID = (
'',
'{ff2b77ca-cf84-432b-a735-3a130dde2a88}',
'{fb607b1f-43f3-488b-855b-fb703ec342a6}',
'{fe131934-f84c-42ad-8da4-6129cddd7288}',
'{fcf65be7-3ce3-4473-af85-f5d37d21b68a}',
'{f193526f-59b8-4a26-9888-e16e4f97ce10}',
'{c692a446-6f5a-481d-85bb-92e2e86fd30a}',
'{4823175c-3b28-487b-a7e6-eebc17614fd1}',
'{61ca74d4-39db-42aa-89b1-8c19c9cd4c23}',
'{defe5fd8-6c97-4dde-b11e-cb509b270e11}',
'{fc65016d-9202-43dd-91a7-64c2954cfb8b}',
'{47102cc3-127f-4771-adfc-991ab8ee1e97}',
'{36e178a0-473f-494b-af8f-6c3f6d7486fc}',
'{8faa1a6d-9c8a-42cd-98b3-ee9700cbc74f}',
'{3b86c1ec-71bc-4645-b4d5-1b19da2be978}'
);
WIADataTypeDescr: array [wdtBN..wdtRAW_CMYK] of String = (
'Black & White',
'Gray scale (Dither)',
'Gray scale',
'Color (RGB)',
'Color (BN)',
'Color (Dither)',
'Color (RAW RGB)',
'Color (RAW BGR)',
'Color (RAW YUV)',
'Color (RAW YUVK)',
'Color (RAW CMY)',
'Color (RAW CMYK)'
);
function WIAItemTypes(pItemType: LONG): TWIAItemTypes;
function WIAItemCategory(const AGUID: TGUID): TWIAItemCategory;
function WIAPropertyFlags(pFlags: ULONG): TWIAPropertyFlags;
function WIACopyCurrentValues(const WIACap: TWIAParamsCapabilities;
aHAlign: TWIAAlignHorizontal=waHLeft;
aVAlign: TWIAAlignVertical=waVTop): TWIAParams;
function WIACopyDefaultValues(const WIACap: TWIAParamsCapabilities;
aHAlign: TWIAAlignHorizontal=waHLeft;
aVAlign: TWIAAlignVertical=waVTop): TWIAParams;
function WIAImageFormat(const AGUID: TGUID; var Value: TWIAImageFormat): Boolean;
implementation
uses WIA_SelectForm;
procedure VersionStrToInt(const s: String; var Ver, VerSub: Integer);
var
pPos, ppPos: Integer;
begin
Ver:= 0;
VerSub:= 0;
try
pPos:= Pos('.', s);
if (pPos > 0) then
begin
Ver:= StrToInt(Copy(s, 0, pPos-1));
ppPos:= Pos('.', s, pPos+1);
if (ppPos > 0)
then VerSub:= StrToInt(Copy(s, pPos+1, ppPos-1))
else VerSub:= StrToInt(Copy(s, pPos+1, 255));
end;
except
end;
end;
function FullPathToRelativePath(const ABasePath: String; var APath: String): Boolean;
begin
Result:= (Pos(ABasePath, APath) = 1);
if Result
then APath:= '.'+DirectorySeparator+Copy(APath, Length(ABasePath)+1, MaxInt);
end;
function WIAItemTypes(pItemType: LONG): TWIAItemTypes;
begin
Result :=[];
if (pItemType and WiaItemTypeFree <> 0) then Result:= Result+[witFree];
if (pItemType and WiaItemTypeImage <> 0) then Result:= Result+[witImage];
if (pItemType and WiaItemTypeFile <> 0) then Result:= Result+[witFile];
if (pItemType and WiaItemTypeFolder <> 0) then Result:= Result+[witFolder];
if (pItemType and WiaItemTypeRoot <> 0) then Result:= Result+[witRoot];
if (pItemType and WiaItemTypeAnalyze <> 0) then Result:= Result+[witAnalyze];
if (pItemType and WiaItemTypeAudio <> 0) then Result:= Result+[witAudio];
if (pItemType and WiaItemTypeDevice <> 0) then Result:= Result+[witDevice];
if (pItemType and WiaItemTypeDeleted <> 0) then Result:= Result+[witDeleted];
if (pItemType and WiaItemTypeDisconnected <> 0) then Result:= Result+[witDisconnected];
if (pItemType and WiaItemTypeHPanorama <> 0) then Result:= Result+[witHPanorama];
if (pItemType and WiaItemTypeVPanorama <> 0) then Result:= Result+[witVPanorama];
if (pItemType and WiaItemTypeBurst <> 0) then Result:= Result+[witBurst];
if (pItemType and WiaItemTypeStorage <> 0) then Result:= Result+[witStorage];
if (pItemType and WiaItemTypeTransfer <> 0) then Result:= Result+[witTransfer];
if (pItemType and WiaItemTypeGenerated <> 0) then Result:= Result+[witGenerated];
if (pItemType and WiaItemTypeHasAttachments <> 0) then Result:= Result+[witHasAttachments];
if (pItemType and WiaItemTypeVideo <> 0) then Result:= Result+[witVideo];
if (pItemType and WiaItemTypeTwainCompatibility <> 0) then Result:= Result+[witTwainCompatibility];
if (pItemType and WiaItemTypeRemoved <> 0) then Result:= Result+[witRemoved];
if (pItemType and WiaItemTypeDocument <> 0) then Result:= Result+[witDocument];
if (pItemType and WiaItemTypeProgrammableDataSource <> 0) then Result:= Result+[witProgrammableDataSource];
end;
function WIAItemCategory(const AGUID: TGUID): TWIAItemCategory;
var
i: TWIAItemCategory;
begin
Result:= wicNULL;
for i:=Low(TWIAItemCategory) to High(TWIAItemCategory) do
if (WiaItemCategoryGUID[i] = AGUID) then
begin
Result:= i;
break;
end;
end;
function WIAPropertyFlags(pFlags: ULONG): TWIAPropertyFlags;
begin
Result :=[];
if (pFlags and WIA_PROP_READ <> 0) then Result:= Result+[WIAProp_READ];
if (pFlags and WIA_PROP_WRITE <> 0) then Result:= Result+[WIAProp_WRITE];
if (pFlags and WIA_PROP_SYNC_REQUIRED <> 0) then Result:= Result+[WIAProp_SYNC_REQUIRED];
if (pFlags and WIA_PROP_NONE <> 0) then Result:= Result+[WIAProp_NONE];
if (pFlags and WIA_PROP_RANGE <> 0) then Result:= Result+[WIAProp_RANGE];
if (pFlags and WIA_PROP_LIST <> 0) then Result:= Result+[WIAProp_LIST];
if (pFlags and WIA_PROP_FLAG <> 0) then Result:= Result+[WIAProp_FLAG];
if (pFlags and WIA_PROP_CACHEABLE <> 0) then Result:= Result+[WIAProp_CACHEABLE];
end;
function WIACopyCurrentValues(const WIACap: TWIAParamsCapabilities;
aHAlign: TWIAAlignHorizontal=waHLeft;
aVAlign: TWIAAlignVertical=waVTop): TWIAParams;
begin
with Result do
begin
PaperType:= WIACap.PaperTypeCurrent;
Resolution:= WIACap.ResolutionCurrent;
Contrast:= WiaCap.ContrastCurrent;
Brightness:= WIACap.BrightnessCurrent;
DocHandling:= WIACap.DocHandlingCurrent;
//BitDepth:= WIACap.BitDepthCurrent;
DataType:= WIACap.DataTypeCurrent;
HAlign:= aHAlign;
VAlign:= aVAlign;
end;
end;
function WIACopyDefaultValues(const WIACap: TWIAParamsCapabilities;
aHAlign: TWIAAlignHorizontal=waHLeft;
aVAlign: TWIAAlignVertical=waVTop): TWIAParams;
begin
FillChar(Result, Sizeof(Result), 0);
with Result do
begin
PaperType:= WIACap.PaperTypeDefault;
Resolution:= WIACap.ResolutionDefault;
Contrast:= WiaCap.ContrastDefault;
Brightness:= WIACap.BrightnessDefault;
DocHandling:= WIACap.DocHandlingDefault;
//BitDepth:= WIACap.BitDepthDefault;
DataType:= WIACap.DataTypeDefault;
HAlign:= aHAlign;
VAlign:= aVAlign;
end;
end;
function WIAImageFormat(const AGUID: TGUID; var Value: TWIAImageFormat): Boolean;
var
i: TWIAImageFormat;
begin
Result:= False;
for i:=Low(TWIAImageFormat) to High(TWIAImageFormat) do
if (WiaImageFormatGUID[i] = AGUID) then
begin
Value:= i;
Result:= True;
break;
end;
end;
function WIADocumentHandling(iDocumentHandling: Integer): TWIADocumentHandlingSet;
begin
Result :=[];
if (iDocumentHandling and FEEDER <> 0) then Result:= Result+[wdhFeeder];
if (iDocumentHandling and FLATBED <> 0) then Result:= Result+[wdhFlatbed];
if (iDocumentHandling and DUPLEX <> 0) then Result:= Result+[wdhDuplex];
if (iDocumentHandling and FRONT_FIRST <> 0) then Result:= Result+[wdhFront_First];
if (iDocumentHandling and BACK_FIRST <> 0) then Result:= Result+[wdhBack_First];
if (iDocumentHandling and FRONT_ONLY <> 0) then Result:= Result+[wdhFront_Only];
if (iDocumentHandling and BACK_ONLY <> 0) then Result:= Result+[wdhBack_Only];
if (iDocumentHandling and NEXT_PAGE <> 0) then Result:= Result+[wdhNext_Page];
if (iDocumentHandling and PREFEED <> 0) then Result:= Result+[wdhPreFeed];
if (iDocumentHandling and AUTO_ADVANCE <> 0) then Result:= Result+[wdhAuto_Advance];
if (iDocumentHandling and ADVANCED_DUPLEX <> 0) then Result:= Result+[wdhAdvanced_Duplex];
end;
function WIADocumentHandlingInt(sDocumentHandling: TWIADocumentHandlingSet): Integer;
begin
Result :=0;
if (wdhFeeder in sDocumentHandling) then Result:= Result or FEEDER;
if (wdhFlatbed in sDocumentHandling) then Result:= Result or FLATBED;
if (wdhDuplex in sDocumentHandling) then Result:= Result or DUPLEX;
if (wdhFront_First in sDocumentHandling) then Result:= Result or FRONT_FIRST;
if (wdhBack_First in sDocumentHandling) then Result:= Result or BACK_FIRST;
if (wdhFront_Only in sDocumentHandling) then Result:= Result or FRONT_ONLY;
if (wdhBack_Only in sDocumentHandling) then Result:= Result or BACK_ONLY;
if (wdhNext_Page in sDocumentHandling) then Result:= Result or NEXT_PAGE;
if (wdhPreFeed in sDocumentHandling) then Result:= Result or PREFEED;
if (wdhAuto_Advance in sDocumentHandling) then Result:= Result or AUTO_ADVANCE;
if (wdhAdvanced_Duplex in sDocumentHandling) then Result:= Result or ADVANCED_DUPLEX;
end;
{ TWIADevice }
function TWIADevice.GetRootItemIntf: IWiaItem2;
begin
Result :=nil;
if (rOwner <> nil) then
begin
if (pRootItem = nil)
then try
lres :=rOwner.pDevMgr.CreateDevice(0, StringToOleStr(Self.rID), pRootItem);
if (lres = S_OK) then Result :=pRootItem;
finally
end
else Result :=pRootItem;
end;
end;
function TWIADevice.GetSelectedItemIntf: IWiaItem2;
begin
//Enumerate Items if needed
if not(HasEnumerated)
then HasEnumerated:= EnumerateItems;
if HasEnumerated and
(rSelectedItemIndex >= 0) and (rSelectedItemIndex < GetItemCount)
then Result:= pSelectedItem
else Result:= nil;
end;
function TWIADevice.GetRootPropertiesIntf: IWiaPropertyStorage;
begin
Result:= nil;
if (pRootItem = nil) then GetRootItemIntf;
if (pRootItem <> nil) then
begin
if (pRootProperties = nil)
then lres:= pRootItem.QueryInterface(IID_IWiaPropertyStorage, pRootProperties);
Result:= pRootProperties;
end;
end;
function TWIADevice.GetSelectedPropertiesIntf: IWiaPropertyStorage;
begin
Result:= nil;
if (pSelectedItem = nil) then GetSelectedItemIntf;
if (pSelectedItem <> nil)
then Result:= pSelectedProperties;
end;
function TWIADevice.GetItem(Index: Integer): PWIAItem;
begin
if (Index >= 0) and (Index < Length(rItemList))
then Result:= @rItemList[Index]
else Result:= nil;
end;
function TWIADevice.GetItemCount: Integer;
begin
//Enumerate Items if needed
if not(HasEnumerated)
then HasEnumerated:= EnumerateItems;
if HasEnumerated
then Result:= Length(rItemList)
else Result:= 0;
end;
procedure TWIADevice.SetSelectedItemIndex(AValue: Integer);
begin
if (rSelectedItemIndex <> AValue) and
(AValue >= 0) and (AValue < GetItemCount)
then begin
rSelectedItemIndex:= AValue;
//Re Enumerate Items so the correct IWiaItem2 interface is assigned in pSelectedItem
EnumerateItems;
end;
end;
function TWIADevice.GetSelectedItem: PWIAItem;
begin
Result:= GetItem(rSelectedItemIndex);
end;
function TWIADevice.EnumerateItems: Boolean;
var
pIEnumItem: IEnumWiaItem2;
pItem: IWiaItem2;
iCount,
itemFetched: ULONG;
itemType: LONG;
itemCategory: TGUID;
i: Integer;
pPropSpec: PROPSPEC;
pPropVar: PROPVARIANT;
pWiaPropertyStorage: IWiaPropertyStorage;
begin
Result :=False;
try
rItemList:= nil;
if (GetRootItemIntf = nil) then exit;
lres:= pRootItem.EnumChildItems(nil, pIEnumItem);
if (lres = S_OK) then
begin
lres:= pIEnumItem.GetCount(iCount);
if (lres = S_OK) then
begin
SetLength(rItemList, iCount);
//Select the First item by default
if (rSelectedItemIndex < 0) or (rSelectedItemIndex > iCount-1)
then rSelectedItemIndex:= 0;
//If there is an Item Selected free Interfaces pointers
if (pSelectedItem <> nil) then
begin