Содержание материала

 

Приведенный здесь пример тестировался на сканере Umax 2000P с драйвером VistaScan32 V3.52. При получении изображений следует помнить, что максимальный размер блока памяти, который может распределить Windows, составляет 2 Гб для 32-ух битной винды (8 Тб для 64-х битной) и при попытке сканировании страниц формата А4 с высоким разрешением можно превысить этот предел. Кроме того, достаточно простой в обращении объект TBitMap имеет куда более серьезные ограничения на размер загружаемых изображений, что требует непосредственной работы с DIB данными. Но это уже тема для отдельной статьи.

Code:

////////////////////////////////////////////////////////////////////////

//                                                                    //

//               Delphi Scanner Support Framework                     //

////////////////////////////////////////////////////////////////////////

//                                                                    //

//         Modified and rewritten as a Delphi component by:           //

//                                                                    //

//                           M. de Haan                               //

//                                                                    //

////////////////////////////////////////////////////////////////////////

 

unit

TWAIN;

 

interface

 

uses

SysUtils, // Exceptions

Forms, // TMessageEvent

Windows, // HMODULE

Graphics, // TBitmap

IniFiles, // Inifile

Controls, // TCursor

Classes; // Class

 

const

// Messages

MSG_GET = $0001; // Get one or more values

MSG_GETCURRENT = $0002; // Get current value

MSG_GETDEFAULT = $0003; // Get default (e.g. power up) value

MSG_GETFIRST = $0004; // Get first of a series of items,

// e.g. Data Sources

MSG_GETNEXT = $0005; // Iterate through a series of items

MSG_SET = $0006; // Set one or more values

MSG_RESET = $0007; // Set current value to default value

MSG_QUERYSUPPORT = $0008; // Get supported operations on the

// capacities

 

// Messages used with DAT_NULL

// ---------------------------

MSG_XFERREADY = $0101; // The data source has data ready

MSG_CLOSEDSREQ = $0102; // Request for the application to close

// the Data Source

MSG_CLOSEDSOK = $0103; // Tell the application to save the

// state

MSG_DEVICEEVENT = $0104; // Some event has taken place

 

// Messages used with a pointer to a DAT_STATUS structure

// ------------------------------------------------------

MSG_CHECKSTATUS = $0201; // Get status information

 

// Messages used with a pointer to DAT_PARENT data

// -----------------------------------------------

MSG_OPENDSM = $0301; // Open the Data Source Manager

MSG_CLOSEDSM = $0302; // Close the Data Source Manager

 

// Messages used with a pointer to a DAT_IDENTITY structure

// --------------------------------------------------------

MSG_OPENDS = $0401; // Open a Data Source

MSG_CLOSEDS = $0402; // Close a Data Source

MSG_USERSELECT = $0403; // Put up a dialog of all Data Sources

// The user can select a Data Source

 

// Messages used with a pointer to a DAT_USERINTERFACE structure

// -------------------------------------------------------------

MSG_DISABLEDS = $0501; // Disable data transfer in the Data

// Source

MSG_ENABLEDS = $0502; // Enable data transfer in the Data

// Source

MSG_ENABLEDSUIONLY = $0503; // Enable for saving Data Source state

// only

 

// Messages used with a pointer to a DAT_EVENT structure

// -----------------------------------------------------

MSG_PROCESSEVENT = $0601;

 

// Messages used with a pointer to a DAT_PENDINGXFERS structure

// ------------------------------------------------------------

MSG_ENDXFER = $0701;

MSG_STOPFEEDER = $0702;

 

// Messages used with a pointer to a DAT_FILESYSTEM structure

// ----------------------------------------------------------

MSG_CHANGEDIRECTORY = $0801;

MSG_CREATEDIRECTORY = $0802;

MSG_DELETE = $0803;

MSG_FORMATMEDIA = $0804;

MSG_GETCLOSE = $0805;

MSG_GETFIRSTFILE = $0806;

MSG_GETINFO = $0807;

MSG_GETNEXTFILE = $0808;

MSG_RENAME = $0809;

MSG_COPY = $080A;

MSG_AUTOMATICCAPTUREDIRECTORY = $080B;

 

// Messages used with a pointer to a DAT_PASSTHRU structure

// --------------------------------------------------------

MSG_PASSTHRU = $0901;

 

const

DG_CONTROL = $0001; // data pertaining to control

DG_IMAGE = $0002; // data pertaining to raster images

 

const

// Data Argument Types for the DG_CONTROL Data Group.

DAT_CAPABILITY = $0001; // TW_CAPABILITY

DAT_EVENT = $0002; // TW_EVENT

DAT_IDENTITY = $0003; // TW_IDENTITY

DAT_PARENT = $0004; // TW_HANDLE,

// application win handle in Windows

DAT_PENDINGXFERS = $0005; // TW_PENDINGXFERS

DAT_SETUPMEMXFER = $0006; // TW_SETUPMEMXFER

DAT_SETUPFILEXFER = $0007; // TW_SETUPFILEXFER

DAT_STATUS = $0008; // TW_STATUS

DAT_USERINTERFACE = $0009; // TW_USERINTERFACE

DAT_XFERGROUP = $000A; // TW_UINT32

DAT_IMAGEMEMXFER = $0103; // TW_IMAGEMEMXFER

DAT_IMAGENATIVEXFER = $0104; // TW_UINT32, loword is hDIB, PICHandle

DAT_IMAGEFILEXFER = $0105; // Null data

 

const

// Condition Codes: Application gets these by doing DG_CONTROL

// DAT_STATUS MSG_GET.

TWCC_CUSTOMBASE = $8000;

TWCC_SUCCESS = 00; // It worked!

TWCC_BUMMER = 01; // Failure due to unknown causes

TWCC_LOWMEMORY = 02; // Not enough memory to perform operation

TWCC_NODS = 03; // No Data Source

TWCC_MAXCONNECTIONS = 04; // Data Source is connected to maximum

// number of possible applications

TWCC_OPERATIONERROR = 05; // Data Source or Data Source Manager

// reported error, application

// shouldn't report an error

TWCC_BADCAP = 06; // Unknown capability

TWCC_BADPROTOCOL = 09; // Unrecognized MSG DG DAT combination

TWCC_BADVALUE = 10; // Data parameter out of range

TWCC_SEQERROR = 11; // DG DAT MSG out of expected sequence

TWCC_BADDEST = 12; // Unknown destination Application /

// Source in DSM_Entry

TWCC_CAPUNSUPPORTED = 13; // Capability not supported by source

TWCC_CAPBADOPERATION = 14; // Operation not supported by

// capability

TWCC_CAPSEQERROR = 15; // Capability has dependancy on other

// capability

TWCC_DENIED = 16; // File System operation is denied

// (file is protected)

TWCC_FILEEXISTS = 17; // Operation failed because file

// already exists

TWCC_FILENOTFOUND = 18; // File not found

TWCC_NOTEMPTY = 19; // Operation failed because directory

// is not empty

TWCC_PAPERJAM = 20; // The feeder is jammed

TWCC_PAPERDOUBLEFEED = 21; // The feeder detected multiple pages

TWCC_FILEWRITEERROR = 22; // Error writing the file (meant for

// things like disk full conditions)

TWCC_CHECKDEVICEONLINE = 23; // The device went offline prior to or

// during this operation

 

const

// Flags used in TW_MEMORY structure

TWMF_APPOWNS = $01;

TWMF_DSMOWNS = $02;

TWMF_DSOWNS = $04;

TWMF_POINTER = $08;

TWMF_HANDLE = $10;

 

const

// Flags for country, which seems to be equal to their telephone

// number

TWCY_AFGHANISTAN = 1001;

TWCY_ALGERIA = 0213;

TWCY_AMERICANSAMOA = 0684;

TWCY_ANDORRA = 0033;

TWCY_ANGOLA = 1002;

TWCY_ANGUILLA = 8090;

TWCY_ANTIGUA = 8091;

TWCY_ARGENTINA = 0054;

TWCY_ARUBA = 0297;

TWCY_ASCENSIONI = 0247;

TWCY_AUSTRALIA = 0061;

TWCY_AUSTRIA = 0043;

TWCY_BAHAMAS = 8092;

TWCY_BAHRAIN = 0973;

TWCY_BANGLADESH = 0880;

TWCY_BARBADOS = 8093;

TWCY_BELGIUM = 0032;

TWCY_BELIZE = 0501;

TWCY_BENIN = 0229;

TWCY_BERMUDA = 8094;

TWCY_BHUTAN = 1003;

TWCY_BOLIVIA = 0591;

TWCY_BOTSWANA = 0267;

TWCY_BRITAIN = 0006;

TWCY_BRITVIRGINIS = 8095;

TWCY_BRAZIL = 0055;

TWCY_BRUNEI = 0673;

TWCY_BULGARIA = 0359;

TWCY_BURKINAFASO = 1004;

TWCY_BURMA = 1005;

TWCY_BURUNDI = 1006;

TWCY_CAMAROON = 0237;

TWCY_CANADA = 0002;

TWCY_CAPEVERDEIS = 0238;

TWCY_CAYMANIS = 8096;

TWCY_CENTRALAFREP = 1007;

TWCY_CHAD = 1008;

TWCY_CHILE = 0056;

TWCY_CHINA = 0086;

TWCY_CHRISTMASIS = 1009;

TWCY_COCOSIS = 1009;

TWCY_COLOMBIA = 0057;

TWCY_COMOROS = 1010;

TWCY_CONGO = 1011;

TWCY_COOKIS = 1012;

TWCY_COSTARICA = 0506;

TWCY_CUBA = 0005;

TWCY_CYPRUS = 0357;

TWCY_CZECHOSLOVAKIA = 0042;

TWCY_DENMARK = 0045;

TWCY_DJIBOUTI = 1013;

TWCY_DOMINICA = 8097;

TWCY_DOMINCANREP = 8098;

TWCY_EASTERIS = 1014;

TWCY_ECUADOR = 0593;

TWCY_EGYPT = 0020;

TWCY_ELSALVADOR = 0503;

TWCY_EQGUINEA = 1015;

TWCY_ETHIOPIA = 0251;

TWCY_FALKLANDIS = 1016;

TWCY_FAEROEIS = 0298;

TWCY_FIJIISLANDS = 0679;

TWCY_FINLAND = 0358;

TWCY_FRANCE = 0033;

TWCY_FRANTILLES = 0596;

TWCY_FRGUIANA = 0594;

TWCY_FRPOLYNEISA = 0689;

TWCY_FUTANAIS = 1043;

TWCY_GABON = 0241;

TWCY_GAMBIA = 0220;

TWCY_GERMANY = 0049;

TWCY_GHANA = 0233;

TWCY_GIBRALTER = 0350;

TWCY_GREECE = 0030;

TWCY_GREENLAND = 0299;

TWCY_GRENADA = 8099;

TWCY_GRENEDINES = 8015;

TWCY_GUADELOUPE = 0590;

TWCY_GUAM = 0671;

TWCY_GUANTANAMOBAY = 5399;

TWCY_GUATEMALA = 0502;

TWCY_GUINEA = 0224;

TWCY_GUINEABISSAU = 1017;

TWCY_GUYANA = 0592;

TWCY_HAITI = 0509;

TWCY_HONDURAS = 0504;

TWCY_HONGKONG = 0852;

TWCY_HUNGARY = 0036;

TWCY_ICELAND = 0354;

TWCY_INDIA = 0091;

TWCY_INDONESIA = 0062;

TWCY_IRAN = 0098;

TWCY_IRAQ = 0964;

TWCY_IRELAND = 0353;

TWCY_ISRAEL = 0972;

TWCY_ITALY = 0039;

TWCY_IVORYCOAST = 0225;

TWCY_JAMAICA = 8010;

TWCY_JAPAN = 0081;

TWCY_JORDAN = 0962;

TWCY_KENYA = 0254;

TWCY_KIRIBATI = 1018;

TWCY_KOREA = 0082;

TWCY_KUWAIT = 0965;

TWCY_LAOS = 1019;

TWCY_LEBANON = 1020;

TWCY_LIBERIA = 0231;

TWCY_LIBYA = 0218;

TWCY_LIECHTENSTEIN = 0041;

TWCY_LUXENBOURG = 0352;

TWCY_MACAO = 0853;

TWCY_MADAGASCAR = 1021;

TWCY_MALAWI = 0265;

TWCY_MALAYSIA = 0060;

TWCY_MALDIVES = 0960;

TWCY_MALI = 1022;

TWCY_MALTA = 0356;

TWCY_MARSHALLIS = 0692;

TWCY_MAURITANIA = 1023;

TWCY_MAURITIUS = 0230;

TWCY_MEXICO = 0003;

TWCY_MICRONESIA = 0691;

TWCY_MIQUELON = 0508;

TWCY_MONACO = 0033;

TWCY_MONGOLIA = 1024;

TWCY_MONTSERRAT = 8011;

TWCY_MOROCCO = 0212;

TWCY_MOZAMBIQUE = 1025;

TWCY_NAMIBIA = 0264;

TWCY_NAURU = 1026;

TWCY_NEPAL = 0977;

TWCY_NETHERLANDS = 0031;

TWCY_NETHANTILLES = 0599;

TWCY_NEVIS = 8012;

TWCY_NEWCALEDONIA = 0687;

TWCY_NEWZEALAND = 0064;

TWCY_NICARAGUA = 0505;

TWCY_NIGER = 0227;

TWCY_NIGERIA = 0234;

TWCY_NIUE = 1027;

TWCY_NORFOLKI = 1028;

TWCY_NORWAY = 0047;

TWCY_OMAN = 0968;

TWCY_PAKISTAN = 0092;

TWCY_PALAU = 1029;

TWCY_PANAMA = 0507;

TWCY_PARAGUAY = 0595;

TWCY_PERU = 0051;

TWCY_PHILLIPPINES = 0063;

TWCY_PITCAIRNIS = 1030;

TWCY_PNEWGUINEA = 0675;

TWCY_POLAND = 0048;

TWCY_PORTUGAL = 0351;

TWCY_QATAR = 0974;

TWCY_REUNIONI = 1031;

TWCY_ROMANIA = 0040;

TWCY_RWANDA = 0250;

TWCY_SAIPAN = 0670;

TWCY_SANMARINO = 0039;

TWCY_SAOTOME = 1033;

TWCY_SAUDIARABIA = 0966;

TWCY_SENEGAL = 0221;

TWCY_SEYCHELLESIS = 1034;

TWCY_SIERRALEONE = 1035;

TWCY_SINGAPORE = 0065;

TWCY_SOLOMONIS = 1036;

TWCY_SOMALI = 1037;

TWCY_SOUTHAFRICA = 0027;

TWCY_SPAIN = 0034;

TWCY_SRILANKA = 0094;

TWCY_STHELENA = 1032;

TWCY_STKITTS = 8013;

TWCY_STLUCIA = 8014;

TWCY_STPIERRE = 0508;

TWCY_STVINCENT = 8015;

TWCY_SUDAN = 1038;

TWCY_SURINAME = 0597;

TWCY_SWAZILAND = 0268;

TWCY_SWEDEN = 0046;

TWCY_SWITZERLAND = 0041;

TWCY_SYRIA = 1039;

TWCY_TAIWAN = 0886;

TWCY_TANZANIA = 0255;

TWCY_THAILAND = 0066;

TWCY_TOBAGO = 8016;

TWCY_TOGO = 0228;

TWCY_TONGAIS = 0676;

TWCY_TRINIDAD = 8016;

TWCY_TUNISIA = 0216;

TWCY_TURKEY = 0090;

TWCY_TURKSCAICOS = 8017;

TWCY_TUVALU = 1040;

TWCY_UGANDA = 0256;

TWCY_USSR = 0007;

TWCY_UAEMIRATES = 0971;

TWCY_UNITEDKINGDOM = 0044;

TWCY_USA = 0001;

TWCY_URUGUAY = 0598;

TWCY_VANUATU = 1041;

TWCY_VATICANCITY = 0039;

TWCY_VENEZUELA = 0058;

TWCY_WAKE = 1042;

TWCY_WALLISIS = 1043;

TWCY_WESTERNSAHARA = 1044;

TWCY_WESTERNSAMOA = 1045;

TWCY_YEMEN = 1046;

TWCY_YUGOSLAVIA = 0038;

TWCY_ZAIRE = 0243;

TWCY_ZAMBIA = 0260;

TWCY_ZIMBABWE = 0263;

TWCY_ALBANIA = 0355;

TWCY_ARMENIA = 0374;

TWCY_AZERBAIJAN = 0994;

TWCY_BELARUS = 0375;

TWCY_BOSNIAHERZGO = 0387;

TWCY_CAMBODIA = 0855;

TWCY_CROATIA = 0385;

TWCY_CZECHREPUBLIC = 0420;

TWCY_DIEGOGARCIA = 0246;

TWCY_ERITREA = 0291;

TWCY_ESTONIA = 0372;

TWCY_GEORGIA = 0995;

TWCY_LATVIA = 0371;

TWCY_LESOTHO = 0266;

TWCY_LITHUANIA = 0370;

TWCY_MACEDONIA = 0389;

TWCY_MAYOTTEIS = 0269;

TWCY_MOLDOVA = 0373;

TWCY_MYANMAR = 0095;

TWCY_NORTHKOREA = 0850;

TWCY_PUERTORICO = 0787;

TWCY_RUSSIA = 0007;

TWCY_SERBIA = 0381;

TWCY_SLOVAKIA = 0421;

TWCY_SLOVENIA = 0386;

TWCY_SOUTHKOREA = 0082;

TWCY_UKRAINE = 0380;

TWCY_USVIRGINIS = 0340;

TWCY_VIETNAM = 0084;

 

const

// Flags for languages

TWLG_DAN = 000; // Danish

TWLG_DUT = 001; // Dutch

TWLG_ENG = 002; // English

TWLG_FCF = 003; // French Canadian

TWLG_FIN = 004; // Finnish

TWLG_FRN = 005; // French

TWLG_GER = 006; // German

TWLG_ICE = 007; // Icelandic

TWLG_ITN = 008; // Italian

TWLG_NOR = 009; // Norwegian

TWLG_POR = 010; // Portuguese

TWLG_SPA = 011; // Spannish

TWLG_SWE = 012; // Swedish

TWLG_USA = 013;

TWLG_AFRIKAANS = 014;

TWLG_ALBANIA = 015;

TWLG_ARABIC = 016;

TWLG_ARABIC_ALGERIA = 017;

TWLG_ARABIC_BAHRAIN = 018;

TWLG_ARABIC_EGYPT = 019;

TWLG_ARABIC_IRAQ = 020;

TWLG_ARABIC_JORDAN = 021;

TWLG_ARABIC_KUWAIT = 022;

TWLG_ARABIC_LEBANON = 023;

TWLG_ARABIC_LIBYA = 024;

TWLG_ARABIC_MOROCCO = 025;

TWLG_ARABIC_OMAN = 026;

TWLG_ARABIC_QATAR = 027;

TWLG_ARABIC_SAUDIARABIA = 028;

TWLG_ARABIC_SYRIA = 029;

TWLG_ARABIC_TUNISIA = 030;

TWLG_ARABIC_UAE = 031; // United Arabic Emirates

TWLG_ARABIC_YEMEN = 032;

TWLG_BASQUE = 033;

TWLG_BYELORUSSIAN = 034;

TWLG_BULGARIAN = 035;

TWLG_CATALAN = 036;

TWLG_CHINESE = 037;

TWLG_CHINESE_HONGKONG = 038;

TWLG_CHINESE_PRC = 039; // People's Republic of China

TWLG_CHINESE_SINGAPORE = 040;

TWLG_CHINESE_SIMPLIFIED = 041;

TWLG_CHINESE_TAIWAN = 042;

TWLG_CHINESE_TRADITIONAL = 043;

TWLG_CROATIA = 044;

TWLG_CZECH = 045;

TWLG_DANISH = TWLG_DAN;

TWLG_DUTCH = TWLG_DUT;

TWLG_DUTCH_BELGIAN = 046;

TWLG_ENGLISH = TWLG_ENG;

TWLG_ENGLISH_AUSTRALIAN = 047;

TWLG_ENGLISH_CANADIAN = 048;

TWLG_ENGLISH_IRELAND = 049;

TWLG_ENGLISH_NEWZEALAND = 050;

TWLG_ENGLISH_SOUTHAFRICA = 051;

TWLG_ENGLISH_UK = 052;

TWLG_ENGLISH_USA = TWLG_USA;

TWLG_ESTONIAN = 053;

TWLG_FAEROESE = 054;

TWLG_FARSI = 055;

TWLG_FINNISH = TWLG_FIN;

TWLG_FRENCH = TWLG_FRN;

TWLG_FRENCH_BELGIAN = 056;

TWLG_FRENCH_CANADIAN = TWLG_FCF;

TWLG_FRENCH_LUXEMBOURG = 057;

TWLG_FRENCH_SWISS = 058;

TWLG_GERMAN = TWLG_GER;

TWLG_GERMAN_AUSTRIAN = 059;

TWLG_GERMAN_LUXEMBOURG = 060;

TWLG_GERMAN_LIECHTENSTEIN = 061;

TWLG_GERMAN_SWISS = 062;

TWLG_GREEK = 063;

TWLG_HEBREW = 064;

TWLG_HUNGARIAN = 065;

TWLG_ICELANDIC = TWLG_ICE;

TWLG_INDONESIAN = 066;

TWLG_ITALIAN = TWLG_ITN;

TWLG_ITALIAN_SWISS = 067;

TWLG_JAPANESE = 068;

TWLG_KOREAN = 069;

TWLG_KOREAN_JOHAB = 070;

TWLG_LATVIAN = 071;

TWLG_LITHUANIAN = 072;

TWLG_NORWEGIAN = TWLG_NOR;

TWLG_NORWEGIAN_BOKMAL = 073;

TWLG_NORWEGIAN_NYNORSK = 074;

TWLG_POLISH = 075;

TWLG_PORTUGUESE = TWLG_POR;

TWLG_PORTUGUESE_BRAZIL = 076;

TWLG_ROMANIAN = 077;

TWLG_RUSSIAN = 078;

TWLG_SERBIAN_LATIN = 079;

TWLG_SLOVAK = 080;

TWLG_SLOVENIAN = 081;

TWLG_SPANISH = TWLG_SPA;

TWLG_SPANISH_MEXICAN = 082;

TWLG_SPANISH_MODERN = 083;

TWLG_SWEDISH = TWLG_SWE;

TWLG_THAI = 084;

TWLG_TURKISH = 085;

TWLG_UKRANIAN = 086;

TWLG_ASSAMESE = 087;

TWLG_BENGALI = 088;

TWLG_BIHARI = 089;

TWLG_BODO = 090;

TWLG_DOGRI = 091;

TWLG_GUJARATI = 092;

TWLG_HARYANVI = 093;

TWLG_HINDI = 094;

TWLG_KANNADA = 095;

TWLG_KASHMIRI = 096;

TWLG_MALAYALAM = 097;

TWLG_MARATHI = 098;

TWLG_MARWARI = 099;

TWLG_MEGHALAYAN = 100;

TWLG_MIZO = 101;

TWLG_NAGA = 102;

TWLG_ORISSI = 103;

TWLG_PUNJABI = 104;

TWLG_PUSHTU = 105;

TWLG_SERBIAN_CYRILLIC = 106;

TWLG_SIKKIMI = 107;

TWLG_SWEDISH_FINLAND = 108;

TWLG_TAMIL = 109;

TWLG_TELUGU = 110;

TWLG_TRIPURI = 111;

TWLG_URDU = 112;

TWLG_VIETNAMESE = 113;

 

const

TWRC_SUCCESS = 0;

TWRC_FAILURE = 1; // Application may get TW_STATUS for

// info on failure

TWRC_CHECKSTATUS = 2; // tried hard to get the status

TWRC_CANCEL = 3;

TWRC_DSEVENT = 4;

TWRC_NOTDSEVENT = 5;

TWRC_XFERDONE = 6;

TWRC_ENDOFLIST = 7; // After MSG_GETNEXT if nothing left

TWRC_INFONOTSUPPORTED = 8;

TWRC_DATANOTAVAILABLE = 9;

 

const

TWON_ONEVALUE = $05; // indicates TW_ONEVALUE container

TWON_DONTCARE8 = $FF;

 

const

ICAP_XFERMECH = $0103;

 

const

TWTY_UINT16 = $0004; // Means: item is a TW_UINT16

 

const

// ICAP_XFERMECH values (SX_ means Setup XFer)

TWSX_NATIVE = 0;

TWSX_FILE = 1;

TWSX_MEMORY = 2;

TWSX_FILE2 = 3;

 

type

TW_UINT16 = WORD; // unsigned short TW_UINT16

pTW_UINT16 = ^TW_UINT16;

TTWUInt16 = TW_UINT16;

PTWUInt16 = pTW_UINT16;

 

type

TW_BOOL = WORDBOOL; // unsigned short TW_BOOL

pTW_BOOL = ^TW_BOOL;

TTWBool = TW_BOOL;

PTWBool = pTW_BOOL;

 

type

TW_STR32 = array[0..33] of Char; // char TW_STR32[34]

pTW_STR32 = ^TW_STR32;

TTWStr32 = TW_STR32;

PTWStr32 = pTW_STR32;

 

type

TW_STR255 = array[0..255] of Char; // char TW_STR255[256]

pTW_STR255 = ^TW_STR255;

TTWStr255 = TW_STR255;

PTWStr255 = pTW_STR255;

 

type

TW_INT16 = SmallInt; // short TW_INT16

pTW_INT16 = ^TW_INT16;

TTWInt16 = TW_INT16;

PTWInt16 = pTW_INT16;

 

type

TW_UINT32 = ULONG; // unsigned long TW_UINT32

pTW_UINT32 = ^TW_UINT32;

TTWUInt32 = TW_UINT32;

PTWUInt32 = pTW_UINT32;

 

type

TW_HANDLE = THandle;

TTWHandle = TW_HANDLE;

TW_MEMREF = Pointer;

TTWMemRef = TW_MEMREF;

 

type

// DAT_PENDINGXFERS. Used with MSG_ENDXFER to indicate additional

// data

TW_PENDINGXFERS = packed record

   Count: TW_UINT16;

   case Boolean of

     False: (EOJ: TW_UINT32);

     True: (Reserved: TW_UINT32);

end;

pTW_PENDINGXFERS = ^TW_PENDINGXFERS;

TTWPendingXFERS = TW_PENDINGXFERS;

PTWPendingXFERS = pTW_PENDINGXFERS;

 

type

// DAT_EVENT. For passing events down from the application to the DS

TW_EVENT = packed record

   pEvent: TW_MEMREF; // Windows pMSG or Mac pEvent.

   TWMessage: TW_UINT16; // TW msg from data source, e.g.

   // MSG_XFERREADY

end;

pTW_EVENT = ^TW_EVENT;

TTWEvent = TW_EVENT;

PTWEvent = pTW_EVENT;

 

type

// TWON_ONEVALUE. Container for one value

TW_ONEVALUE = packed record

   ItemType: TW_UINT16;

   Item: TW_UINT32;

end;

pTW_ONEVALUE = ^TW_ONEVALUE;

TTWOneValue = TW_ONEVALUE;

PTWOneValue = pTW_ONEVALUE;

 

type

// DAT_CAPABILITY. Used by application to get/set capability from/in

// a data source.

TW_CAPABILITY = packed record

   Cap: TW_UINT16; // id of capability to set or get, e.g.

   // CAP_BRIGHTNESS

   ConType: TW_UINT16; // TWON_ONEVALUE, _RANGE, _ENUMERATION or

   // _ARRAY

   hContainer: TW_HANDLE; // Handle to container of type Dat

end;

pTW_CAPABILITY = ^TW_CAPABILITY;

TTWCapability = TW_CAPABILITY;

PTWCapability = pTW_CAPABILITY;

 

type

// DAT_STATUS. Application gets detailed status info from a data

// source with this

TW_STATUS = packed record

   ConditionCode: TW_UINT16; // Any TWCC_xxx constant

   Reserved: TW_UINT16; // Future expansion space

end;

pTW_STATUS = ^TW_STATUS;

TTWStatus = TW_STATUS;

PTWStatus = pTW_STATUS;

 

type

// No DAT needed. Used to manage memory buffers

TW_MEMORY = packed record

   Flags: TW_UINT32; // Any combination of the TWMF_ constants

   Length: TW_UINT32; // Number of bytes stored in buffer TheMem

   TheMem: TW_MEMREF; // Pointer or handle to the allocated memory

   // buffer

end;

pTW_MEMORY = ^TW_MEMORY;

TTWMemory = TW_MEMORY;

PTWMemory = pTW_MEMORY;

 

const

// ICAP_IMAGEFILEFORMAT values (FF_means File Format

TWFF_TIFF = 0; // Tagged Image File Format

TWFF_PICT = 1; // Macintosh PICT

TWFF_BMP = 2; // Windows Bitmap

TWFF_XBM = 3; // X-Windows Bitmap

TWFF_JFIF = 4; // JPEG File Interchange Format

TWFF_FPX = 5; // Flash Pix

TWFF_TIFFMULTI = 6; // Multi-page tiff file

TWFF_PNG = 7; // Portable Network Graphic

TWFF_SPIFF = 8;

TWFF_EXIF = 9;

 

type

// DAT_SETUPFILEXFER. Sets up DS to application data transfer via a

// file

TW_SETUPFILEXFER = packed record

   FileName: TW_STR255;

   Format: TW_UINT16; // Any TWFF_xxx constant

   VRefNum: TW_INT16; // Used for Mac only

end;

pTW_SETUPFILEXFER = ^TW_SETUPFILEXFER;

TTWSetupFileXFER = TW_SETUPFILEXFER;

PTWSetupFileXFER = pTW_SETUPFILEXFER;

 

type

// DAT_SETUPFILEXFER2. Sets up DS to application data transfer via a

// file. }

TW_SETUPFILEXFER2 = packed record

   FileName: TW_MEMREF; // Pointer to file name text

   FileNameType: TW_UINT16; // TWTY_STR1024 or TWTY_UNI512

   Format: TW_UINT16; // Any TWFF_xxx constant

   VRefNum: TW_INT16; // Used for Mac only

   parID: TW_UINT32; // Used for Mac only

end;

pTW_SETUPFILEXFER2 = ^TW_SETUPFILEXFER2;

TTWSetupFileXFER2 = TW_SETUPFILEXFER2;

PTWSetupFileXFER2 = pTW_SETUPFILEXFER2;

 

type

// DAT_SETUPMEMXFER. Sets up Data Source to application data

// transfer via a memory buffer

TW_SETUPMEMXFER = packed record

   MinBufSize: TW_UINT32;

   MaxBufSize: TW_UINT32;

   Preferred: TW_UINT32;

end;

pTW_SETUPMEMXFER = ^TW_SETUPMEMXFER;

TTWSetupMemXFER = TW_SETUPMEMXFER;

PTWSetupMemXFER = pTW_SETUPMEMXFER;

 

type

TW_VERSION = packed record

   MajorNum: TW_UINT16; // Major revision number of the software.

   MinorNum: TW_UINT16; // Incremental revision number of the

   // software

   Language: TW_UINT16; // e.g. TWLG_SWISSFRENCH

   Country: TW_UINT16; // e.g. TWCY_SWITZERLAND

   Info: TW_STR32; // e.g. "1.0b3 Beta release"

end;

pTW_VERSION = ^TW_VERSION;

PTWVersion = pTW_VERSION;

TTWVersion = TW_VERSION;

 

type

TW_IDENTITY = packed record

   Id: TW_UINT32; // Unique number. In Windows,

   // application hWnd

   Version: TW_VERSION; // Identifies the piece of code

   ProtocolMajor: TW_UINT16; // Application and DS must set to

   // TWON_PROTOCOLMAJOR

   ProtocolMinor: TW_UINT16; // Application and DS must set to

   // TWON_PROTOCOLMINOR

   SupportedGroups: TW_UINT32; // Bit field OR combination of DG_

   // constants

   Manufacturer: TW_STR32; // Manufacturer name, e.g.

   // "Hewlett-Packard"

   ProductFamily: TW_STR32; // Product family name, e.g.

   // "ScanJet"

   ProductName: TW_STR32; // Product name, e.g. "ScanJet Plus"

end;

pTW_IDENTITY = ^TW_IDENTITY;

 

type

// DAT_USERINTERFACE. Coordinates UI between application and data

// source

TW_USERINTERFACE = packed record

   ShowUI: TW_BOOL; // TRUE if DS should bring up its UI

   ModalUI: TW_BOOL; // For Mac only - true if the DS's UI is modal

   hParent: TW_HANDLE; // For Windows only - Application handle

end;

pTW_USERINTERFACE = ^TW_USERINTERFACE;

TTWUserInterface = TW_USERINTERFACE;

PTWUserInterface = pTW_USERINTERFACE;

 

////////////////////////////////////////////////////////////////////////

//                                                                    //

//                END OF TWAIN TYPES AND CONSTANTS                    //

//                                                                    //

////////////////////////////////////////////////////////////////////////

 

const

TWAIN_DLL_Name = 'TWAIN_32.DLL';

DSM_Entry_Name = 'DSM_Entry';

Ini_File_Name = 'WIN.INI';

CrLf = #13 + #10;

 

resourcestring // Errorstrings:

ERR_DSM_ENTRY_NOT_FOUND = 'Unable to find the entry of the Data ' +

   'Source Manager in: TWAIN_32.DLL';

ERR_TWAIN_NOT_LOADED = 'Unable to load or find: TWAIN_32.DLL';

ERR_DSM_CALL_FAILED = 'A call to the Data Source Manager failed ' +

   'in module %s';

ERR_UNKNOWN = 'A call to the Data Source Manager failed ' +

   'in module %s: Code %.04x';

ERR_DSM_OPEN = 'Unable to close the Data Source Manager. ' +

   'Maybe a source is still in use';

ERR_STATUS = 'Unable to get the status';

ERR_DSM = 'Data Source Manager error in module %s:' +

   CrLf + '%s';

ERR_DS = 'Data Source error in module %s:' +

   CrLf + '%s';

 

type

ETwainError = class(Exception);

TImageType = (ffTIFF, ffPICT, ffBMP, ffXBM, ffJFIF, ffFPX,

   ffTIFFMULTI, ffPNG, ffSPIFF, ffEXIF, ffUNKNOWN);

TTransferType = (xfNative, xfMemory, xfFile);

TLanguageType = (lgDutch, lgEnglish,

   lgFrench, lgGerman,

   lgAmerican, lgItalian,

   lgSpanish, lgNorwegian,

   lgFinnish, lgDanish,

   lgRussian, lgPortuguese,

   lgSwedish, lgPolish,

   lgGreek, lgTurkish);

TCountryType = (ctNetherlands, ctEngland,

   ctFrance, ctGermany,

   ctUSA, ctSpain,

   ctItaly, ctDenmark,

   ctFinland, ctNorway,

   ctRussia, ctPortugal,

   ctSweden, ctPoland,

   ctGreece, ctTurkey);

TTWAIN = class(TComponent)

private

   // Private declarations

   fBitmap: TBitmap; // the actual bmp used for

   // scanning, must be

   // removed

   HDSMDLL: HMODULE; // = 0, the library handle:

   // will stay global

   appId: TW_IDENTITY; // our (Application) ID.

   // (may stay global)

   dsId: TW_IDENTITY; // Data Source ID (will

   // become member of DS

   // class)

   fhWnd: HWND; // = 0, maybe will be

   // removed, use

   // application.handle

   // instead

   fXfer: TTransferType; // = xfNative;

   bDataSourceManagerOpen: Boolean; // = False, flag, may stay

   // global

   bDataSourceOpen: Boolean; // = False, will become

   // member of DS class

   bDataSourceEnabled: Boolean; // = False, will become

   // member of DS class

   fScanReady: TNotifyEvent; // notifies that the scan

   // is ready

   sDefaultSource: string; // remember old data source

   fOldOnMessageHandler: TMessageEvent; // Save old OnMessage event

   fShowUI: Boolean; // Show User Interface

   fSetupFileXfer: TW_SETUPFILEXFER; // Not used yet

   fSetupMemoryXfer: TW_SETUPMEMXFER; // Not used yet

   fMemory: TW_MEMORY; // Not used yet

 

   function fLoadTwain: Boolean;

   procedure fUnloadTwain;

   function fNativeXfer: Boolean;

   function fMemoryXfer: Boolean; // Not used yet

   function fFileXfer: Boolean; // Not used yet

   function fGetDestination: TTransferType;

   procedure fSetDestination(dest: TTransferType);

   function Condition2String(ConditionCode: TW_UINT16): string;

   procedure RaiseLastDataSourceManagerCondition(module: string);

   procedure RaiseLastDataSourceCondition(module: string);

   procedure TwainCheckDataSourceManager(res: TW_UINT16;

     module: string);

   procedure TwainCheckDataSource(res: TW_UINT16;

     module: string);

 

   function CallDataSourceManager(pOrigin: pTW_IDENTITY;

     DG: TW_UINT32;

     DAT: TW_UINT16;

     MSG: TW_UINT16;

     pData: TW_MEMREF): TW_UINT16;

 

   function CallDataSource(DG: TW_UINT32;

     DAT: TW_UINT16;

     MSG: TW_UINT16;

     pData: TW_MEMREF): TW_UINT16;

 

   procedure XferMech;

   procedure fSetProductname(pn: string);

   function fGetProductname: string;

   procedure fSetManufacturer(mf: string);

   function fGetManufacturer: string;

   procedure fSetProductFamily(pf: string);

   function fGetProductFamily: string;

   procedure fSetLanguage(lg: TLanguageType);

   function fGetLanguage: TLanguageType;

   procedure fSetCountry(ct: TCountryType);

   function fGetCountry: TCountryType;

   procedure SaveDefaultSourceEntry;

   procedure RestoreDefaultSourceEntry;

   procedure fSetCursor(cr: TCursor);

   function fGetCursor: TCursor;

   procedure fSetImageType(it: TImageType);

   function fGetImageType: TImageType;

   procedure fSetFilename(fn: string);

   function fGetFilename: string;

   procedure fSetVersionInfo(vi: string);

   function fGetVersionInfo: string;

   procedure fSetVersionMajor(vmaj: WORD);

   procedure fSetVersionMinor(vmin: WORD);

   function fGetVersionMajor: WORD;

   function fGetVersionMinor: WORD;

 

protected

   procedure ScanReady; dynamic; // Notifies when image transfer is

   // ready

   procedure fNewOnMessageHandler(var Msg: TMsg;

     var Handled: Boolean); virtual;

 

public

   // Public declarations

   constructor Create(AOwner: TComponent); override;

   destructor Destroy; override;

   procedure Acquire(aBmp: TBitmap);

   procedure OpenDataSource;

   procedure CloseDataSource;

   procedure InitTWAIN;

   procedure OpenDataSourceManager;

   procedure CloseDataSourceManager;

   function IsDataSourceManagerOpen: Boolean;

   procedure EnableDataSource;

   // Procedure TWEnableDSUIOnly(ShowUI : Boolean);

   procedure DisableDataSource;

   function IsDataSourceOpen: Boolean;

   function IsDataSourceEnabled: Boolean;

   procedure SelectDataSource;

   function IsTwainDriverAvailable: Boolean;

   function ProcessSourceMessage(var Msg: TMsg): Boolean;

 

published

   // Published declarations

   // Properties, methods

   property Destination: TTransferType

     read fGetDestination write fSetDestination;

   property TwainDriverFound: Boolean

     read IsTwainDriverAvailable;

   property Productname: string

     read fGetProductname write fSetProductname;

   property Manufacturer: string

     read fGetManufacturer write fSetManufacturer;

   property ProductFamily: string

     read fGetProductFamily write fSetProductFamily;

   property Language: TLanguageType

     read fGetLanguage write fSetLanguage;

   property Country: TCountryType

     read fGetCountry write fSetCountry;

   property ShowUI: Boolean

     read fShowUI write fShowUI;

   property Cursor: TCursor

     read fGetCursor write fSetCursor;

   property FileFormat: TImageType

     read fGetImageType write fSetImageType;

   property Filename: string

     read fGetFilename write fSetFilename;

   property VersionInfo: string

     read fGetVersionInfo write fSetVersionInfo;

   property VersionMajor: WORD

     read fGetVersionMajor write fSetVersionMajor;

   property VersionMinor: WORD

     read fGetVersionMinor write fSetVersionMinor;

   // Events

   property OnScanReady: TNotifyEvent

     read fScanReady write fScanReady;

end;

 

procedure Register;

 

type

DSMENTRYPROC = function(pOrigin: pTW_IDENTITY;

   pDest: pTW_IDENTITY;

   DG: TW_UINT32;

   DAT: TW_UINT16;

   MSG: TW_UINT16;

   pData: TW_MEMREF): TW_UINT16; stdcall;

TDSMEntryProc = DSMENTRYPROC;

 

type

DSENTRYPROC = function(pOrigin: pTW_IDENTITY;

   DG: TW_UINT32;

   DAT: TW_UINT16;

   MSG: TW_UINT16;

   pData: TW_MEMREF): TW_UINT16; stdcall;

TDSEntryProc = DSENTRYPROC;

 

var

DS_Entry: TDSEntryProc = nil; // Initialize

DSM_Entry: TDSMEntryProc = nil; // Initialize

 

implementation

 

//---------------------------------------------------------------------

 

constructor TTWAIN.Create(AOwner: TComponent);

 

begin

inherited Create(AOwner);

// Initialize variables

appID.Version.Info := 'Twain component';

appID.Version.Country := TWCY_USA;

appID.Version.Language := TWLG_USA;

appID.Productname := 'SimpelSoft TWAIN module'; // This is the one that you are

// going to see in the UI

appID.ManuFacturer := 'SimpelSoft';

appID.ProductFamily := 'SimpelSoft components';

appID.Version.MajorNum := 1;

appID.Version.MinorNum := 0;

// appID.ID := Application.Handle;

 

fSetFilename('C:\TWAIN.BMP');

// fSetupFileXfer.FileName := 'C:\TWAIN.TMP':

fSetImageType(ffBMP);

// fSetupFileXfer.Format := TWFF_BMP;

// fSetupFileXfer.VRefNum := xx; // For Mac

// fSetupMemoryXfer.MinBufSize := xx;

// fSetupMemoryXfer.MaxBufSize := yy;

// fSetupMemoryXfer.Preferred := zz;

fMemory.Flags := TWFF_BMP;

// fMemory.Length := SizeOf(Mem);

// fMemory.TheMem := @Mem;

 

// fhWnd := Application.Handle;

fShowUI := True;

 

HDSMDLL := 0;

sDefaultSource := '';

fXfer := xfNative;

bDataSourceManagerOpen := False;

bDataSourceOpen := False;

bDataSourceEnabled := False;

end;

//---------------------------------------------------------------------

 

destructor TTWAIN.Destroy;

 

begin

if bDataSourceEnabled then

   DisableDataSource;

if bDataSourceOpen then

   CloseDataSource;

if bDataSourceManagerOpen then

   CloseDataSourceManager;

fUnLoadTwain; // Loose the TWAIN_32.DLL

if sDefaultSource <> '' then

   RestoreDefaultSourceEntry; // Write old entry back in WIN.INI

Application.OnMessage := fOldOnMessageHandler; // Restore old OnMessage

// handler

inherited Destroy;

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetVersionMajor: WORD;

 

begin

Result := appID.Version.MajorNum;

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetVersionMinor: WORD;

 

begin

Result := appID.Version.MinorNum;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetVersionMajor(vmaj: WORD);

 

begin

appID.Version.MajorNum := vmaj;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetVersionMinor(vmin: WORD);

 

begin

appID.Version.MinorNum := vmin;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetVersionInfo(vi: string);

 

var

I, L: Integer;

 

begin

FillChar(appID.Version.Info, SizeOf(appID.Version.Info), #0);

L := Length(vi);

if L = 0 then

   Exit;

if L > 32 then

   L := 32;

for I := 1 to L do

   appID.Version.Info[I - 1] := vi[I];

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetVersionInfo: string;

 

var

I: Integer;

 

begin

Result := '';

I := 0;

if appID.Version.Info[I] <> #0 then

   repeat

     Result := Result + appID.Version.Info[I];

     Inc(I);

   until appID.Version.Info[I] = #0;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetImageType(it: TImageType);

 

begin

fSetupFileXfer.Format := TWFF_BMP; // Initialize

fMemory.Flags := TWFF_BMP; // Initialize

 

case it of

   ffTIFF:

     begin

       fSetupFileXfer.Format := TWFF_TIFF;

       fMemory.Flags := TWFF_TIFF;

     end;

   ffPICT:

     begin

       fSetupFileXfer.Format := TWFF_PICT;

       fMemory.Flags := TWFF_PICT;

     end;

   ffBMP:

     begin

       fSetupFileXfer.Format := TWFF_BMP;

       fMemory.Flags := TWFF_BMP;

     end;

   ffXBM:

     begin

       fSetupFileXfer.Format := TWFF_XBM;

       fMemory.Flags := TWFF_XBM;

     end;

   ffJFIF:

     begin

       fSetupFileXfer.Format := TWFF_JFIF;

       fMemory.Flags := TWFF_JFIF;

     end;

   ffFPX:

     begin

       fSetupFileXfer.Format := TWFF_FPX;

       fMemory.Flags := TWFF_FPX;

     end;

   ffTIFFMULTI:

     begin

       fSetupFileXfer.Format := TWFF_TIFFMULTI;

       fMemory.Flags := TWFF_TIFFMULTI;

     end;

   ffPNG:

     begin

       fSetupFileXfer.Format := TWFF_PNG;

       fMemory.Flags := TWFF_PNG;

     end;

   ffSPIFF:

     begin

       fSetupFileXfer.Format := TWFF_SPIFF;

       fMemory.Flags := TWFF_SPIFF;

     end;

   ffEXIF:

     begin

       fSetupFileXfer.Format := TWFF_EXIF;

       fMemory.Flags := TWFF_EXIF;

     end;

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetFilename(fn: string);

 

var

L, I: Integer;

 

begin

FillChar(fSetupFileXfer.FileName, SizeOf(fSetupFileXfer.Filename), #0);

L := Length(fn);

if L > 0 then

   for I := 1 to L do

     fSetupFileXfer.Filename[I - 1] := fn[I];

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetFilename: string;

 

var

I: Integer;

 

begin

Result := '';

I := 0;

if fSetupFileXfer.Filename[I] <> #0 then

   repeat

     Result := Result + fSetupFileXfer.Filename[I];

     Inc(I);

   until fSetupFileXfer.Filename[I] = #0;

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetImageType: TImageType;

 

begin

Result := ffUNKNOWN; // Initialize

case fSetupFileXfer.Format of

   TWFF_TIFF: Result := ffTIFF;

   TWFF_PICT: Result := ffPICT;

   TWFF_BMP: Result := ffBMP;

   TWFF_XBM: Result := ffXBM;

   TWFF_JFIF: Result := ffJFIF;

   TWFF_FPX: Result := ffFPX;

   TWFF_TIFFMULTI: Result := ffTIFFMULTI;

   TWFF_PNG: Result := ffPNG;

   TWFF_SPIFF: Result := ffSPIFF;

   TWFF_EXIF: Result := ffEXIF;

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetCursor(cr: TCursor);

 

begin

Screen.Cursor := cr;

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetCursor: TCursor;

 

begin

Result := Screen.Cursor;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetCountry(ct: TCountryType);

 

begin

case ct of

   ctDenmark: appID.Version.Country := TWCY_DENMARK;

   ctNetherlands: appID.Version.Country := TWCY_NETHERLANDS;

   ctEngland: appID.Version.Country := TWCY_BRITAIN;

   ctFinland: appID.Version.Country := TWCY_FINLAND;

   ctFrance: appID.Version.Country := TWCY_FRANCE;

   ctGermany: appID.Version.Country := TWCY_GERMANY;

   ctItaly: appID.Version.Country := TWCY_ITALY;

   ctNorWay: appID.Version.Country := TWCY_NORWAY;

   ctSpain: appID.Version.Country := TWCY_SPAIN;

   ctUSA: appID.Version.Country := TWCY_USA;

   ctRussia: appID.Version.Country := TWCY_RUSSIA;

   ctPortugal: appID.Version.Country := TWCY_PORTUGAL;

   ctSweden: appID.Version.Country := TWCY_SWEDEN;

   ctPoland: appID.Version.Country := TWCY_POLAND;

   ctGreece: appID.Version.Country := TWCY_GREECE;

   ctTurkey: appID.Version.Country := TWCY_TURKEY;

end;

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetCountry: TCountryType;

 

begin

Result := ctNetherlands; // Initialize

case appID.Version.Country of

   TWCY_NETHERLANDS: Result := ctNetherlands;

   TWCY_DENMARK: Result := ctDenmark;

   TWCY_BRITAIN: Result := ctEngland;

   TWCY_FINLAND: Result := ctFinland;

   TWCY_FRANCE: Result := ctFrance;

   TWCY_GERMANY: Result := ctGermany;

   TWCY_NORWAY: Result := ctNorway;

   TWCY_ITALY: Result := ctItaly;

   TWCY_SPAIN: Result := ctSpain;

   TWCY_USA: Result := ctUSA;

   TWCY_RUSSIA: Result := ctRussia;

   TWCY_PORTUGAL: Result := ctPortugal;

   TWCY_SWEDEN: Result := ctSweden;

   TWCY_TURKEY: Result := ctTurkey;

   TWCY_GREECE: Result := ctGreece;

   TWCY_POLAND: Result := ctPoland;

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetLanguage(lg: TLanguageType);

 

begin

case lg of

   lgDanish: appID.Version.Language := TWLG_DAN;

   lgDutch: appID.Version.Language := TWLG_DUT;

   lgEnglish: appID.Version.Language := TWLG_ENG;

   lgFinnish: appID.Version.Language := TWLG_FIN;

   lgFrench: appID.Version.Language := TWLG_FRN;

   lgGerman: appID.Version.Language := TWLG_GER;

   lgNorwegian: appID.Version.Language := TWLG_NOR;

   lgItalian: appID.Version.Language := TWLG_ITN;

   lgSpanish: appID.Version.Language := TWLG_SPA;

   lgAmerican: appID.Version.Language := TWLG_USA;

   lgRussian: appID.Version.Language := TWLG_RUSSIAN;

   lgPortuguese: appID.Version.Language := TWLG_POR;

   lgSwedish: appID.Version.Language := TWLG_SWE;

   lgPolish: appID.Version.Language := TWLG_POLISH;

   lgGreek: appID.Version.Language := TWLG_GREEK;

   lgTurkish: appID.Version.Language := TWLG_TURKISH;

end;

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetLanguage: TLanguageType;

 

begin

Result := lgDutch; // Initialize

case appID.Version.Language of

   TWLG_DAN: Result := lgDanish;

   TWLG_DUT: Result := lgDutch;

   TWLG_ENG: Result := lgEnglish;

   TWLG_FIN: Result := lgFinnish;

   TWLG_FRN: Result := lgFrench;

   TWLG_GER: Result := lgGerman;

   TWLG_ITN: Result := lgItalian;

   TWLG_NOR: Result := lgNorwegian;

   TWLG_SPA: Result := lgSpanish;

   TWLG_USA: Result := lgAmerican;

   TWLG_RUSSIAN: Result := lgRussian;

   TWLG_POR: Result := lgPortuguese;

   TWLG_SWE: Result := lgSwedish;

   TWLG_POLISH: Result := lgPolish;

   TWLG_GREEK: Result := lgGreek;

   TWLG_TURKISH: Result := lgTurkish;

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetManufacturer(mf: string);

 

var

I, L: Integer;

 

begin

FillChar(appID.Manufacturer, SizeOf(appID.Manufacturer), #0);

L := Length(mf);

if L = 0 then

   Exit;

if L > 32 then

   L := 32;

for I := 1 to L do

   appID.Manufacturer[I - 1] := mf[I];

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetManufacturer: string;

 

var

I: Integer;

 

begin

Result := '';

I := 0;

if appID.Manufacturer[I] <> #0 then

   repeat

     Result := Result + appID.Manufacturer[I];

     Inc(I);

   until appID.Manufacturer[I] = #0;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetProductname(pn: string);

 

var

I, L: Integer;

 

begin

FillChar(appID.Productname, SizeOf(appID.Productname), #0);

L := Length(pn);

if L = 0 then

   Exit;

if L > 32 then

   L := 32;

for I := 1 to L do

   appID.Productname[I - 1] := pn[I];

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetProductName: string;

 

var

I: Integer;

 

begin

Result := '';

I := 0;

if appID.ProductName[I] <> #0 then

   repeat

     Result := Result + appID.ProductName[I];

     Inc(I);

   until appID.ProductName[I] = #0;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetProductFamily(pf: string);

 

var

I, L: Integer;

 

begin

FillChar(appID.ProductFamily, SizeOf(appID.ProductFamily), #0);

L := Length(pf);

if L = 0 then

   Exit;

if L > 32 then

   L := 32;

for I := 1 to L do

   appID.ProductFamily[I - 1] := pf[I];

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetProductFamily: string;

 

var

I: Integer;

 

begin

Result := '';

I := 0;

if appID.ProductFamily[I] <> #0 then

   repeat

     Result := Result + appID.ProductFamily[I];

     Inc(I);

   until appID.ProductFamily[I] = #0;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.ScanReady;

 

begin

if Assigned(fScanReady) then

   fScanReady(Self);

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fSetDestination(dest: TTransferType);

 

begin

fXfer := dest;

end;

//---------------------------------------------------------------------

 

function TTWAIN.fGetDestination: TTransferType;

 

begin

Result := fXfer;

end;

//----------------------------------------------------------------------

 

function UpCaseStr(const s: string): string;

 

var

I, L: Integer;

 

begin

Result := s;

L := Length(Result);

if L > 0 then

begin

   for I := 1 to L do

     Result[I] := UpCase(Result[I]);

end;

// Result := s; // Minor bug, changed 23/05/03

end;

//----------------------------------------------------------------------

// Internal routine

//----------------------------------------------------------------------

 

function GetWinDir: string;

 

var

WD: array[0..MAX_PATH] of Char;

L: WORD;

 

begin

WD := #0;

GetWindowsDirectory(WD, MAX_PATH);

Result := StrPas(WD);

L := Length(Result);

// Remove the "\" if any

if L > 0 then

   if Result[L] = '\' then

     Result := Copy(Result, 1, L - 1);

end;

//----------------------------------------------------------------------

// Internal routine

//----------------------------------------------------------------------

 

procedure FileFindSubDir(const ffsPath: string;

var ffsBo: Boolean);

 

var

sr: TSearchRec;

 

begin

if FindFirst(ffsPath + '\*.*', faAnyFile, sr) = 0 then

   repeat

     if sr.Name <> '.' then

       if sr.Name <> '..' then

         if sr.Attr and faDirectory = faDirectory then

         begin

           FileFindSubDir(ffsPath + '\' + sr.name, ffsBo);

         end

         else

         begin

           if UpCaseStr(ExtractFileExt(sr.Name)) = '.DS' then

             if UpCaseStr(sr.Name) <> 'WIATWAIN.DS' then

               ffsBo := True;

         end;

   until FindNext(sr) <> 0;

// Error if SysUtils is not added in front of FindClose!

SysUtils.FindClose(sr);

end;

//----------------------------------------------------------------------

 

function TTWAIN.IsTwainDriverAvailable: Boolean;

 

var

sr: TSearchRec;

s: string;

Bo: Boolean;

 

begin

// This routine might not be failsafe!

// Under circumstances the twain drivers found in the directory

// %WINDOWS%\TWAIN_32\*.ds and below could be not properly installed!

Bo := False;

s := GetWinDir + '\TWAIN_32';

FileFindSubDir(s, Bo);

Result := Bo;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.SaveDefaultSourceEntry;

 

var

WinIni: TIniFile;

 

begin

if sDefaultSource <> '' then

   Exit;

WinIni := TIniFile.Create(Ini_File_Name);

sDefaultSource := WinIni.ReadString('TWAIN', 'DEFAULT SOURCE', '');

WinIni.Free;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.RestoreDefaultSourceEntry;

 

var

WinIni: TIniFile;

 

begin

if sDefaultSource = '' then

   Exit; // It is not changed by this component or it is not there...

WinIni := TIniFile.Create(Ini_File_Name);

WinIni.WriteString('TWAIN', 'DEFAULT SOURCE', sDefaultSource);

WinIni.Free;

sDefaultSource := '';

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.InitTWAIN;

 

begin

appID.ID := Application.Handle;

fHwnd := Application.Handle;

fLoadTwain; // Load TWAIN_32.DLL

fOldOnMessageHandler := Application.OnMessage; // Save old pointer

Application.OnMessage := fNewOnMessageHandler; // Set to our handler

OpenDataSourceManager; // Open DS

end;

//---------------------------------------------------------------------

 

function TTWAIN.fLoadTwain: Boolean;

 

begin

if HDSMDLL = 0 then

begin

   HDSMDLL := LoadLibrary(TWAIN_DLL_Name);

   DSM_Entry := GetProcAddress(HDSMDLL, DSM_Entry_Name);

   // if @DSM_Entry = nil then

   //   raise ETwainError.Create(SErrDSMEntryNotFound);

end;

 

Result := (HDSMDLL <> 0);

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fUnloadTwain;

 

begin

if HDSMDLL <> 0 then

begin

   DSM_Entry := nil;

   FreeLibrary(HDSMDLL);

   HDSMDLL := 0;

end;

end;

//---------------------------------------------------------------------

 

function TTWAIN.Condition2String(ConditionCode: TW_UINT16): string;

 

begin

// Texts copied from PDF Documentation: Rework needed

case ConditionCode of

   TWCC_BADCAP: Result :=

     'Capability not supported by source or operation (get,' + CrLf +

       'set) is not supported on capability, or capability had' + CrLf +

       'dependencies on other capabilities and cannot be' + CrLf +

       'operated upon at this time';

   TWCC_BADDEST: Result := 'Unknown destination in DSM_Entry.';

   TWCC_BADPROTOCOL: Result := 'Unrecognized operation triplet.';

   TWCC_BADVALUE: Result :=

     'Data parameter out of supported range.';

   TWCC_BUMMER: Result :=

     'General failure. Unload Source immediately.';

   TWCC_CAPUNSUPPORTED: Result := 'Capability not supported by ' +

     'Data Source.';

   TWCC_CAPBADOPERATION: Result := 'Operation not supported on ' +

     'capability.';

   TWCC_CAPSEQERROR: Result :=

     'Capability has dependencies on other capabilities and ' + CrLf +

       'cannot be operated upon at this time.';

   TWCC_DENIED: Result :=

     'File System operation is denied (file is protected).';

   TWCC_PAPERDOUBLEFEED,

     TWCC_PAPERJAM: Result :=

     'Transfer failed because of a feeder error';

   TWCC_FILEEXISTS: Result :=

     'Operation failed because file already exists.';

   TWCC_FILENOTFOUND: Result := 'File not found.';

   TWCC_LOWMEMORY: Result :=

     'Not enough memory to complete the operation.';

   TWCC_MAXCONNECTIONS: Result :=

     'Data Source is connected to maximum supported number of ' +

       CrLf + 'applications.';

   TWCC_NODS: Result :=

     'Data Source Manager was unable to find the specified Data ' +

       'Source.';

   TWCC_NOTEMPTY: Result :=

     'Operation failed because directory is not empty.';

   TWCC_OPERATIONERROR: Result :=

     'Data Source or Data Source Manager reported an error to the' +

       CrLf + 'user and handled the error. No application action ' +

       'required.';

   TWCC_SEQERROR: Result :=

     'Illegal operation for current Data Source Manager' + CrLf +

       'and Data Source state.';

   TWCC_SUCCESS: Result := 'Operation was succesful.';

else

   Result := Format('Unknown condition %.04x', [ConditionCode]);

end;

end;

///////////////////////////////////////////////////////////////////////

// RaiseLastDSMCondition (idea: like RaiseLastWin32Error)            //

// Tries to get the status from the DSM and raises an exception      //

// with it.                                                          //

///////////////////////////////////////////////////////////////////////

 

procedure TTWAIN.RaiseLastDataSourceManagerCondition(module: string);

 

var

status: TW_STATUS;

 

begin

Assert(@DSM_Entry <> nil);

if DSM_Entry(@appId, nil, DG_CONTROL, DAT_STATUS, MSG_GET, @status) <>

   TWRC_SUCCESS then

   raise ETwainError.Create(ERR_STATUS)

else

   raise ETwainError.CreateFmt(ERR_DSM, [module,

     Condition2String(status.ConditionCode)]);

end;

///////////////////////////////////////////////////////////////////////

// RaiseLastDSCondition                                              //

// same again, but for the actual DS                                 //

// (should be a method of DS)                                        //

///////////////////////////////////////////////////////////////////////

 

procedure TTWAIN.RaiseLastDataSourceCondition(module: string);

 

var

status: TW_STATUS;

 

begin

Assert(@DSM_Entry <> nil);

if DSM_Entry(@appId, @dsID, DG_CONTROL, DAT_STATUS, MSG_GET, @status) <>

   TWRC_SUCCESS then

   raise ETwainError.Create(ERR_STATUS)

else

   raise ETwainError.CreateFmt(ERR_DSM, [module,

     Condition2String(status.ConditionCode)]);

end;

///////////////////////////////////////////////////////////////////////

// TwainCheckDSM (idea: like Win32Check or GDICheck in Graphics.pas) //

///////////////////////////////////////////////////////////////////////

 

procedure TTWAIN.TwainCheckDataSourceManager(res: TW_UINT16;

module: string);

 

begin

if res <> TWRC_SUCCESS then

begin

   if res = TWRC_FAILURE then

     RaiseLastDataSourceManagerCondition(module)

   else

     raise ETwainError.CreateFmt(ERR_UNKNOWN, [module, res]);

end;

end;

///////////////////////////////////////////////////////////////////////

// TwainCheckDS                                                      //

// same again, but for the actual DS                                 //

// (should be a method of DS)                                        //

///////////////////////////////////////////////////////////////////////

 

procedure TTWAIN.TwainCheckDataSource(res: TW_UINT16;

module: string);

 

begin

if res <> TWRC_SUCCESS then

begin

   if res = TWRC_FAILURE then

     RaiseLastDataSourceCondition(module)

   else

     raise ETwainError.CreateFmt(ERR_UNKNOWN, [module, res]);

end;

end;

///////////////////////////////////////////////////////////////////////

// CallDSMEntry:                                                     //

// Short form for DSM Calls: appId is not needed as parameter        //

///////////////////////////////////////////////////////////////////////

 

function TTWAIN.CallDataSourceManager(pOrigin: pTW_IDENTITY;

DG: TW_UINT32;

DAT: TW_UINT16;

MSG: TW_UINT16;

pData: TW_MEMREF): TW_UINT16;

 

begin

Assert(@DSM_Entry <> nil);

 

Result := DSM_Entry(@appID,

   pOrigin,

   DG,

   DAT,

   MSG,

   pData);

if (Result <> TWRC_SUCCESS) and (DAT <> DAT_EVENT) then

begin

end;

end;

///////////////////////////////////////////////////////////////////////

// Short form for (actual) DS Calls. appId and dsID are not needed   //

// (this should be a DS class method)                                //

///////////////////////////////////////////////////////////////////////

 

function TTWAIN.CallDataSource(DG: TW_UINT32;

DAT: TW_UINT16;

MSG: TW_UINT16;

pData: TW_MEMREF): TW_UINT16;

 

begin

Assert(@DSM_Entry <> nil);

Result := DSM_Entry(@appID,

   @dsID,

   DG,

   DAT,

   MSG,

   pData);

end;

///////////////////////////////////////////////////////////////////////

//  A lot of the following code is a conversion from the             //

//  twain example program (and some comments are copied, too)        //

//  (The error handling is done differently)                         //

//  Most functions should be moved to a DSM or DS class              //

///////////////////////////////////////////////////////////////////////

 

procedure TTWAIN.OpenDataSourceManager;

 

begin

if not bDataSourceManagerOpen then

begin

   Assert(appID.ID <> 0);

   if not fLoadTwain then

     raise ETwainError.Create(ERR_TWAIN_NOT_LOADED);

 

   // appID.Id := fhWnd;

   // appID.Version.MajorNum := 1;

   // appID.Version.MinorNum := 0;

   // appID.Version.Language := TWLG_USA;

   // appID.Version.Country  := TWCY_USA;

   // appID.Version.Info     := 'Twain Component';

   appID.ProtocolMajor := 1; // TWON_PROTOCOLMAJOR;

   appID.ProtocolMinor := 7; // TWON_PROTOCOLMINOR;

   appID.SupportedGroups := DG_IMAGE or DG_CONTROL;

   // appID.Productname      := 'HP ScanJet 5p';

   // appId.ProductFamily    := 'ScanJet';

   // appId.Manufacturer     := 'Hewlett-Packard';

 

   TwainCheckDataSourceManager(CallDataSourceManager(nil,

     DG_CONTROL,

     DAT_PARENT,

     MSG_OPENDSM,

     @fhWnd),

     'OpenDataSourceManager');

 

   bDataSourceManagerOpen := True;

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.CloseDataSourceManager;

 

begin

if bDataSourceOpen then

   raise ETwainError.Create(ERR_DSM_OPEN);

 

if bDataSourceManagerOpen then

begin

   // This call performs one important function:

   // - tells the SM which application, appID.id, is requesting SM to

   //   close

   // - be sure to test return code, failure indicates SM did not

   //   close !!

 

   TwainCheckDataSourceManager(CallDataSourceManager(nil,

     DG_CONTROL,

     DAT_PARENT,

     MSG_CLOSEDSM,

     @fhWnd),

     'CloseDataSourceManager');

 

   bDataSourceManagerOpen := False;

 

end;

fUnLoadTwain; // Loose the DLL

 

if sDefaultSource <> '' then

   RestoreDefaultSourceEntry;

 

end;

//---------------------------------------------------------------------

 

function TTWAIN.IsDataSourceManagerOpen: Boolean;

 

begin

Result := bDataSourceManagerOpen;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.OpenDataSource;

 

begin

Assert(bDataSourceManagerOpen, 'Data Source Manager must be open');

 

if not bDataSourceOpen then

begin

   TwainCheckDataSourceManager(CallDataSourceManager(nil,

     DG_CONTROL,

     DAT_IDENTITY,

     MSG_OPENDS,

     @dsID),

     'OpenDataSource');

   bDataSourceOpen := True;

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.CloseDataSource;

 

begin

Assert(bDataSourceManagerOpen, 'Data Source Manager must be open');

if bDataSourceOpen then

begin

   TwainCheckDataSourceManager(CallDataSourceManager(nil,

     DG_CONTROL,

     DAT_IDENTITY,

     MSG_CLOSEDS,

     @dsID),

     'CloseDataSource');

   bDataSourceOpen := False;

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.EnableDataSource;

 

var

twUI: TW_USERINTERFACE;

 

begin

Assert(bDataSourceOpen, 'Data Source must be open');

 

if not bDataSourceEnabled then

begin

   FillChar(twUI, SizeOf(twUI), #0);

 

   twUI.hParent := fhWnd;

   twUI.ShowUI := fShowUI;

   twUI.ModalUI := True;

 

   TwainCheckDataSourceManager(CallDataSourceManager(@dsID,

     DG_CONTROL,

     DAT_USERINTERFACE,

     MSG_ENABLEDS,

     @twUI),

     'EnableDataSource');

 

   bDataSourceEnabled := True;

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.DisableDataSource;

 

var

twUI: TW_USERINTERFACE;

 

begin

Assert(bDataSourceOpen, 'Data Source must be open');

 

if bDataSourceEnabled then

begin

   twUI.hParent := fhWnd;

   twUI.ShowUI := TW_BOOL(TWON_DONTCARE8); (*!!!!*)

 

   TwainCheckDataSourceManager(CallDataSourceManager(@dsID,

     DG_CONTROL,

     DAT_USERINTERFACE,

     MSG_DISABLEDS,

     @twUI),

     'DisableDataSource');

 

   bDataSourceEnabled := False;

end;

end;

//---------------------------------------------------------------------

 

function TTWAIN.IsDataSourceOpen: Boolean;

 

begin

Result := bDataSourceOpen;

end;

//---------------------------------------------------------------------

 

function TTWAIN.IsDataSourceEnabled: Boolean;

 

begin

Result := bDataSourceEnabled;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.SelectDataSource;

 

var

NewDSIdentity: TW_IDENTITY;

twRC: TW_UINT16;

 

begin

SaveDefaultSourceEntry;

Assert(not bDataSourceOpen, 'Data Source must be closed');

 

TwainCheckDataSourceManager(CallDataSourceManager(nil,

   DG_CONTROL,

   DAT_IDENTITY,

   MSG_GETDEFAULT,

   @NewDSIdentity),

   'SelectDataSource1');

 

twRC := CallDataSourceManager(nil,

   DG_CONTROL,

   DAT_IDENTITY,

   MSG_USERSELECT,

   @NewDSIdentity);

 

case twRC of

   TWRC_SUCCESS: dsID := NewDSIdentity; // log in new Source

   TWRC_CANCEL: ; // keep the current Source

else

   TwainCheckDataSourceManager(twRC, 'SelectDataSource2');

end;

end;

(*******************************************************************

Functions from CAPTEST.C

*******************************************************************)

 

procedure TTWAIN.XferMech;

 

var

cap: TW_CAPABILITY;

pVal: pTW_ONEVALUE;

 

begin

fXfer := xfNative; // Override

cap.Cap := ICAP_XFERMECH;

cap.ConType := TWON_ONEVALUE;

cap.hContainer := GlobalAlloc(GHND, SizeOf(TW_ONEVALUE));

Assert(cap.hContainer <> 0);

try

   pval := pTW_ONEVALUE(GlobalLock(cap.hContainer));

   Assert(pval <> nil);

   try

     pval.ItemType := TWTY_UINT16;

     case fXfer of

       xfMemory: pval.Item := TWSX_MEMORY;

       xfFile: pval.Item := TWSX_FILE;

       xfNative: pval.Item := TWSX_NATIVE;

     end;

   finally

     GlobalUnlock(cap.hContainer);

   end;

 

   TwainCheckDataSource(CallDataSource(DG_CONTROL,

     DAT_CAPABILITY,

     MSG_SET,

     @cap),

     'XferMech');

 

finally

   GlobalFree(cap.hContainer);

end;

 

end;

///////////////////////////////////////////////////////////////////////

 

function TTWAIN.ProcessSourceMessage(var Msg: TMsg): Boolean;

 

var

twRC: TW_UINT16;

event: TW_EVENT;

pending: TW_PENDINGXFERS;

 

begin

Result := False;

 

if bDataSourceManagerOpen and bDataSourceOpen then

begin

   event.pEvent := @Msg;

   event.TWMessage := 0;

 

   twRC := CallDataSource(DG_CONTROL,

     DAT_EVENT,

     MSG_PROCESSEVENT,

     @event);

 

   case event.TWMessage of

     MSG_XFERREADY:

       begin

         case fXfer of

           xfNative: fNativeXfer;

           xfMemory: fMemoryXfer;

           xfFile: fFileXfer;

         end;

         TwainCheckDataSource(CallDataSource(DG_CONTROL,

           DAT_PENDINGXFERS,

           MSG_ENDXFER,

           @pending),

           'Check for Pending Transfers');

 

         if pending.Count > 0 then

           TwainCheckDataSource(CallDataSource(

             DG_CONTROL,

             DAT_PENDINGXFERS,

             MSG_RESET,

             @pending),

             'Abort Pending Transfers');

 

         DisableDataSource;

         CloseDataSource;

         ScanReady; // Event

       end;

     MSG_CLOSEDSOK,

       MSG_CLOSEDSREQ:

       begin

         DisableDataSource;

         CloseDataSource;

         ScanReady // Event

       end;

   end;

 

   Result := not (twRC = TWRC_NOTDSEVENT);

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.Acquire(aBmp: TBitmap);

 

begin

// fOldOnMessageHandler := Application.OnMessage; // Save old pointer

// Application.OnMessage := fNewOnMessageHandler; // Set to our handler

// OpenDataSourceManager;                         // Open DS

fBitmap := aBmp;

OpenDataSourceManager;

OpenDataSource;

XferMech; // Must be written for xfMemory and xfFile

EnableDataSource;

end;

//---------------------------------------------------------------------

// Must be written!

 

function TTWAIN.fMemoryXfer: Boolean;

 

var

twRC: TW_UINT16;

 

begin

Result := False;

twRC := CallDataSource(DG_IMAGE,

   DAT_IMAGEMEMXFER,

   MSG_GET,

   nil);

case twRC of

   TWRC_XFERDONE: Result := True;

   TWRC_CANCEL: ;

   TWRC_FAILURE: ;

end;

end;

//---------------------------------------------------------------------

// Must be written!

 

function TTWAIN.fFileXfer: Boolean;

 

var

twRC: TW_UINT16;

 

begin

// Not yet implemented!

Result := False;

twRC := CallDataSource(DG_IMAGE,

   DAT_IMAGEFILEXFER,

   MSG_GET,

   nil);

case twRC of

   TWRC_XFERDONE: Result := True;

   TWRC_CANCEL: ;

   TWRC_FAILURE: ;

end;

end;

//---------------------------------------------------------------------

 

function TTWAIN.fNativeXfer: Boolean;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function DibNumColors(dib: Pointer): Integer;

 

var

   lpbi: PBITMAPINFOHEADER;

   lpbc: PBITMAPCOREHEADER;

   bits: Integer;

 

begin

   lpbi := dib;

   lpbc := dib;

 

   if lpbi.biSize <> SizeOf(BITMAPCOREHEADER) then

   begin

     if lpbi.biClrUsed <> 0 then

     begin

       Result := lpbi.biClrUsed;

       Exit;

     end;

     bits := lpbi.biBitCount;

   end

   else

     bits := lpbc.bcBitCount;

 

   case bits of

     1: Result := 2;

     4: Result := 16; // 4?

     8: Result := 256; // 8?

   else

     Result := 0;

   end;

end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

var

twRC: TW_UINT16;

hDIB: TW_UINT32;

hBmp: HBITMAP;

lpDib: ^TBITMAPINFO;

lpBits: PChar;

ColorTableSize: Integer;

dc: HDC;

 

begin

Result := False;

 

twRC := CallDataSource(DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, @hDIB);

 

case twRC of

   TWRC_XFERDONE:

     begin

       lpDib := GlobalLock(hDIB);

       try

         ColorTableSize := (DibNumColors(lpDib) *

           SizeOf(RGBQUAD));

 

         lpBits := PChar(lpDib);

         Inc(lpBits, lpDib.bmiHeader.biSize);

         Inc(lpBits, ColorTableSize);

 

         dc := GetDC(0);

         try

           hBMP := CreateDIBitmap(dc, lpdib.bmiHeader,

             CBM_INIT, lpBits, lpDib^, DIB_RGB_COLORS);

 

           fBitmap.Handle := hBMP;

 

           Result := True;

         finally

           ReleaseDC(0, dc);

         end;

       finally

         GlobalUnlock(hDIB);

         GlobalFree(hDIB);

       end;

     end;

   TWRC_CANCEL: ;

   TWRC_FAILURE: RaiseLastDataSourceManagerCondition('Native Transfer');

end;

end;

//---------------------------------------------------------------------

 

procedure TTWAIN.fNewOnMessageHandler(var Msg: TMsg;

var Handled: Boolean);

 

begin

Handled := ProcessSourceMessage(Msg);

if Assigned(fOldOnMessageHandler) then

   fOldOnMessageHandler(Msg, Handled)

end;

 

  


 

The setup program for Imaging (tool that ships with Windows > 98) installs the Image

Scan control (OCX) and the 32-bit TWAIN DLLs.

All you have to do is to import this ActiveX control in Delphi and generate a component wrapper:

 

Import the ActiveX Control "Kodak Image Scan Control"

(Select Component|Import ActiveX Control...)

 

Now add a TImgScan Component from the Register "ActiveX" to your form.

 

Change the following Properties in the Object Inspector:

 

FileType = 3 - BMP_Bitmap

PageOption = 4 - OverwritePages

ScanTo = 2 - FileOnly

 

Code:

FileType = 3 - BMP_Bitmap

PageOption = 4 - OverwritePages

ScanTo = 2 - FileOnly

 

{***}

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  if imgScan1.ScannerAvailable then

    try

      imgScan1.Image := 'c:\Scanner.bmp';

      imgScan1.OpenScanner;

      imgScan1.Zoom := 100;

      imgScan1.StartScan;

      Application.ProcessMessages;

    finally

      imgScan1.CloseScanner;

      { Show the scanned image in Image1 }

      imgScan1.Picture.LoadFromFile(Image1.Image);

    end;

end;

 


Автор: Павел

 

В настоящее время в конференциях то и дело встречаются вопросы типа: как мне получить изображение со сканера, с web камеры и т.д.. При том, что и интернете практически полностью отсутствуют материалы по этим вопросам на русском языке и при достаточном разнообразии их на английском. Эта статья должна помочь начинающему программисту на Delphi разобраться в них. В статье подробно, с примерами описана работа со сканером с использованием популярной библиотеки Easy TWAIN.

 

Введение

 

В отличие от принтеров сканеры изначально не поддерживались ОС Windows и не имеют API для работы с ними. В начале своего появления сканеры взаимодействовали с программами посредством уникального для каждой модели сканера интерфейса, что серьезно затрудняло включение поддержки работы со сканером в прикладные программы.

 

Для решения этой проблемы был разработан TWAIN - индустриальный стандарт интерфейса программного обеспечения для передачи изображений из различных устройств в Windows и Macintosh. Стандарт издан и поддерживается TWAIN рабочей группой - официальный сайт www.twain.org. Стандарт издан в 1992 г. В настоящее время действует версия 1.9 от января 2000 г. Абревеатура TWAIN изначально не имела какого-то определенного смысла хотя позже была придумана расшифровка: (Technology Without An Interesting Name - Технология без интересного имени). TWAIN - не протокол аппаратного уровня, он требует драйвера (названного Data Source или DS) для каждого устройства.

 Менеджер TWAIN (DSM) - действует как координатор между приложениями и Источником Данных (Data Source). DSM имеет минимальный пользовательский интерфейс - только выбор DS. Все взаимодействие с пользователем вне прикладной программы осуществляется по средствам DS.

 

Каждый источник данных разрабатывается непосредственно производителем соответствующих устройств. И их поддержка стандарта TWAIN осуществляется на добровольной основе.

 

Использование TWAIN

 

DSM и DS это DLLs загружаемые в адресное пространство приложения и работают как подпрограммы приложения. DSM использует межпроцесcную связь, что бы координировать действия со своими копиями, когда больше чем одна программа использует TWAIN.

 

Упрощенная схема действия приложения использующего TWAIN:

 

Открыть диалог настройки соответствующего устройства (диалог отображает DS) и задать соответствующие настройки.

Приложение ожидает сообщение от DS, что изображение готово. Во время ожидания все зарегистрированные сообщения будут направляться через TWAIN. Если это не будет выполняться, то приложение не получит сообщения о готовности изображения.

Приложение принимает изображение от DS.

TWAIN определяет три типа передачи изображения:

Native - в Windows это DIB в памяти

Memory - как блоки пикселей в буферах памяти

File - DS записывает изображение непосредственно в файл (не обязательно поддерживается)

Приложение закрывает DS.

Использование EZTWAIN

 

Данная библиотека была разработана, что бы упростить разработку программ использующих TWAIN предоставляя разработчику упрощенную версию TWAIN API.

 

EZTWAN обеспечивает передачу всех windows сообщений через TWAIN и ожидает сообщения о готовности изображения.

 

Библиотека EZTWAIN является свободно распространяемой библиотекой с открытыми исходными кодами. В настоящее время выпущена версия 1.12. Библиотеку можно свободно скачать с сайта: www.dosadi.com, библиотека написана на C и предназначена для использования как DLL, необходимый для ее использования с Delphi модуль так же можно скачать с сайта. Кроме нее у меня с сайта можно скачать модификацию данной библиотеки, предназначенную для статической компоновки с программой на Delphi. Указанная версия (MultiTWAIN for Delphi) не требует наличия библиотеки EZTW32.DLL.

 

Структура программы

 

Используемые функции.

 

Перед вызовом функций сканирования необходимо вызвать функцию:

TWAIN_SelectImageSource(hwnd: HWND): Integer;

 

Данная функция позволяет выбрать источник получения данных из списка TWAIN совместимых устройств, в качестве параметра она получает хендл основного окна прикладной программы. Следует заменить, что если в системе имеется одно TWAIN совместимое устройство, то вызывать функцию не обязательно.

 

Для получения изображения служит функция:

TWAIN_AcquireNative(hwnd: HWND; pixmask: Integer): HBitmap;

 

где:

hwnd - хендел основного окна прикладной программы (допускается указывать 0);

pixmask - режим сканирования ( необходимо задавать 0 - указание другого режима может приводить к ошибке);

hBitmap - указатель на область памяти, содержащей полученные данные в DIB формате.

 

По окончании работы с DIB данными их необходимо удалить вызвав процедуру:

TWAIN_FreeNative(hDIB: HBitmap);

 

где:

hDIB - указатель, полученный при вызове функции TWAIN_AcquireNative.

 

Для облегчения обработки полученных DIB данных в библиотеке имеется несколько сервисных функций:

Code:

TWAIN_DibWidth(hDib: HBitmap): Integer;

// Получает ширину изображения в пикселях

 

TWAIN_DibHeight(hDib: HBitmap): Integer;

// Получает высоту изображения в пикселях

 

TWAIN_CreateDibPalette(hdib: HBitmap): Integer;

// Получает цветовую палитру изображения

 

TWAIN_DrawDibToDC(hDC: HDC;

dx, dy, w, h: Integer;

hDib: HBitmap;

sx, sy: Integer);

// Передает DIB данные в формате совместимым

// с указанным контекстом устройства.

 


Пример программы

 

Полный текст примера можно взять отсюда. Мы рассмотрим только функцию получения данных с TWAIN устройства:

Code:

procedure TForm1.Accquire1Click(Sender: TObject);

var

dat: hBitMap;

PInfo: PBitMapInfoHeader;

Height, Width: integer;

 

{Функция возведения 2 в степень s}

function stp2(s: byte): longint;

var

   m: longint;

   i: byte;

begin

   m := 2;

   for i := 2 to s do

     m := m * 2;

   stp2 := m;

end;

 

begin

{Получаем указатель на графические данные}

dat := TWAIN_AcquireNative(Handle, 0);

if dat <> 0 then

begin

   {Получаем указатель на область памяти содержащей DIB

    данные и блокируем область памяти}

   PInfo := GlobalLock(dat);

   {Анализируем полученные данные}

   Height := PInfo.biHeight;

   Width := PInfo.biWidth;

   {Узнаем размер полученного изображения в сантиметрах}

   Wcm.Caption := floatToStrF(100 / PInfo.biXPelsPerMeter * Width, ffNumber, 8,

     3)

     + ' cm';

   Hcm.Caption := floatToStrF(100 / PInfo.biYPelsPerMeter * Height, ffNumber,

     8, 3)

     + ' cm';

   {Определяем число цветов в изображении}

   Colors.Caption := floatToStrF(stp2(PInfo.biBitCount), ffNumber, 8, 0) +

     ' цветов';

   {Разблокируем память}

   GlobalUnlock(dat);

   {Передаем в битовую матрицу графические данные}

   {И устанавливаем перехват ошибок}

   try

     MyBitMap.Palette := TWAIN_CreateDibPalette(dat);

     MyBitMap.Width := Width;

     MyBitMap.Height := Height;

     TWAIN_DrawDibToDC(MyBitMap.Canvas.Handle, 0, 0, Width, Height, dat, 0, 0);

   except

     // Обрабатываем наиболее вероятную ошибку связанную

     // с не хваткой ресурсов для загрузки изображения

     on EOutOFResources do

       MessageDlg('TBitMap: Нет ресурсов для загрузки изображения!',

         mtError, [mbOk], 0);

   end;

   {Отображаем графические данные}

   Image1.Picture.Graphic := MyBitMap;

   {Освобождаем память занятую графическими данными}

   TWAIN_FreeNative(dat);

end;

end;

 

Обработка ошибок необходима, так как объект TBitMap имеет серьезные ограничения на размер создаваемого изображения. При этом производится обработка наиболее вероятной ошибки, в случае возникновения другой ошибки, ее обработка будет передана обработчику по умолчанию. Обработка ошибки в данном случае заключается в выдаче диагностического сообщения, в прикладной программе можно реализовать выполнение любых необходимых действий, например, произвести уменьшение разрешения и повторно подать на загрузку в TBitMap.

 

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить