Раздел 4. Поиск начала JPEG в BLOB
Формат типа объекта OLE — возьми три!
Теперь все, что нам нужно сделать, это сохранить образ на диск (как обычный двоичный файл) и понять, что у него внутри.
Все файлы изображений (форматы) имеют заголовки файлов, которые однозначно идентифицируют изображение. Файлы изображений JPG начинаются с так называемого тега SOI, шестнадцатеричное значение которого равно $FFD8.
Следующая строка кода сохраняет значение поля изображения в соответствующем файле (BlobImage.dat) в рабочем каталоге. Поместите этот код в событие OnCreate формы и удалите его после запуска проекта.
ADOTable1Picture.SaveToFile('BlobImage.dat');
Как только у нас будет этот файл. Мы можем использовать Hex-редактор для просмотра его содержимого.
Вы верите в это? Доступ MS сохраняет путь к подключенному объекту OLE в поле объекта OLE как часть определения объекта. Поскольку определение хранилища объектов OLE не документировано (!? Оно исходит непосредственно от MS), невозможно узнать, какие фактические данные изображения получат до их записи.
Рассмотрим этот вопрос в двух частях. Первое: нам нужно найти «FFD8» и начать читать изображение оттуда. Во-вторых: «FFD8» не может всегда находиться в одной и той же позиции в файле. Вывод: нам нужна функция, которая возвращает расположение тега SOI файла JPG, хранящегося как объект OLE в базе данных Access.
Правильный путь – берите четыре!
При наличии поля типа Blob наша функция должна возвращать позицию строки FFD8 в ADOBlobStream. ReadBuffer считывает данные из потока побайтно. Каждый вызов ReadBuffer перемещает позицию потока байт за байтом. Функция возвращает позицию потока, когда два байта вместе ведут к маркеру SOI. Это функция:
функция JpegStartsInBlob(PicField:TBlobField): целое число;
вар
бС: TADOBlobStream;
буфер: Слово;
hx: строка;
начинать
Результат := -1;
bS := TADOBlobStream.Create(PicField, bmRead);
пытаться
в то время как (Результат = -1) и (bS.Position + 1 < bS.Size) делают
начинать
bS.ReadBuffer(буфер, 1);
hx:=IntToHex(буфер, 2);
если hx = 'FF', то начнем
bS.ReadBuffer(буфер, 1);
hx:=IntToHex(буфер, 2);
если hx = 'D8', то Результат: = bS.Position - 2
иначе, если hx = 'FF', тогда
bS.Position := bS.Position-1;
конец; // если
конец; // пока
окончательно
bS.Бесплатно
конец; //попробуем
конец;
Получив местоположение маркера SOI, мы можем использовать его для определения местоположения изображения в потоке ADOBlob.
использует JPEG;
...
PROcedure TForm1.btnShowImageClick(Отправитель: TObject);
вар
бС: TADOBlobStream;
Изображение: TJpegImage;
начинать
bS := TADOBlobStream.Create(AdoTable1Picture, bmRead);
пытаться
bS.Seek(JpegStartsInBlob(AdoTable1Picture),soFromBeginning);
Рис:=TJpegImage.Create;
пытаться
Pic.LoadFromStream(bS);
ADOImage.Picture.Graphic:=Рис;
окончательно
Рис.Бесплатно;
конец;
окончательно
bS.Бесплатно
конец;
конец;
Запустите проект, ОК!
Кто может сказать, что программирование — это не весело?
Примечание. В реальной программе мы добавим код для чтения и отображения изображения из текущей строки в событии AfterScroll TDataSet (он находится в процедуре события ADOTable1AfterScroll). Событие AfterScroll возникает, когда приложение прокручивает от одной записи к другой.
Идея пятая!
Вот о чем эта глава. Теперь вы можете хранить и отображать все интересующие вас изображения JPG. На последней странице этой статьи я приведу полный код (модуль form1); вся организация данных размещена в событии OnCreate формы. Это гарантирует правильное соединение всех трех компонентов — вам не нужно использовать Инспектор объектов при проектировании.
Признаюсь, эта глава не для новичков, но мир — жестокое место! Другое дело: вы замечаете, что в итоге даже не знаете, как изменить (или добавить какие-то новые) картинки в таблицу! Да это совсем другая история!