Технология без интересного имени или как работать со сканером
Автор: Павел
В настоящее время в конференциях то и дело встречаются вопросы типа: как мне получить изображение со сканера, с 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) для каждого устройства.
К настоящему времени (май 2000 г.) TWAIN доступен для Windows 3.1 и выше (Intel и совместимые процессоры), Macintosh и OS/2. Для Linux самый близкий стандарт - SANE.
Менеджер 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 данных в библиотеке имеется несколько сервисных функций:
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 устройства:
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.
Заключение
Приведенный здесь пример тестировался на сканере Umax 2000P с драйвером VistaScan32 V3.52. При получении изображений следует помнить, что максимальный размер блока памяти, который может распределить Windows, составляет 2 Гб и при попытке сканировании страниц формата А4 с высоким разрешением можно превысить этот предел. Кроме того, достаточно простой в обращении объект TBitMap имеет куда более серьезные ограничения на размер загружаемых изображений, что требует непосредственной работы с DIB данными. Но это уже тема для отдельной статьи. Если у Вас появились вопросы или предложения пишите мне: speclab@4unet.ru
|