Страница 1 из 1
UDF, записывающая картинку из файла в BLOB
Добавлено: 16 янв 2007, 11:53
Leonid K.
Здравствуйте. Помогите, пожалуйта, разобраться с моей проблемой.
Использую Firebird 2.0+Delphi 6. Есть таблица, в которой хранятся пути к графическим файлам. В клиентском приложении требуется по имени файла получить картинку и вывести её пользователю. Требуется написать UDF, которой передаётся имя файла, она переписывает содержимое файла в переменную типа BLOB и возвращает её. Проблема в том, что мне никак не удаётся реализовать такую функцию.
Добавлено: 16 янв 2007, 12:39
kdv
а что, на сайте разве нет?
Добавлено: 16 янв 2007, 13:18
Leonid K.
Нашёл только функцию LoadBlobFromFile из UDFDEMO. После её выполнения что-то записывается, но точно не картинка.
Сама функция (немного изменёная):
Код: Выделить всё
function LoadBlobFromFile(FileName: PChar; Blob: PBlob): PBlob; cdecl; export;
const
MaxBufSize = $8192;
var
BufSize, ReadLength, StreamSize: Integer;
Buffer: PChar;
Stream: TStream;
begin
Result:=Blob;
try
Stream := TFileStream.Create(FileName, fmOpenRead or
fmShareDenyNone);
try
StreamSize := Stream.Size;
if StreamSize > MaxBufSize then BufSize := MaxBufSize
else BufSize := StreamSize;
GetMem(Buffer, BufSize);
try
while StreamSize <> 0 do begin
if StreamSize > BufSize then ReadLength := BufSize
else ReadLength := StreamSize;
Stream.ReadBuffer(Buffer^, ReadLength);
Blob^.PutSegment(Blob^.BlobHandle, Buffer, ReadLength);
Dec(StreamSize, ReadLength);
end;
finally
FreeMem(Buffer, BufSize);
end;
finally
Stream.Free;
end;
except
{$Ifdef Debug}
on E: Exception do begin
Writeln(X, 'Exception in LoadBLObFromFile!!!');
Writeln(X, 'FileName ', FileName);
Writeln(X, E.Message);
Flush(X);
end;
{$Endif}
end;
end;
Объявление её в базе:
Код: Выделить всё
DECLARE EXTERNAL FUNCTION GET_IMAGE
CSTRING(100),
BLOB,
BLOB
RETURNS PARAMETER 3
ENTRY_POINT 'LoadBlobFromFile' MODULE_NAME 'FreeUDFLib'
Вызов:
Код: Выделить всё
CREATE PROCEDURE "GetImage" (
id integer)
returns (
res integer)
as
declare variable imgid integer;
declare variable fname varchar(100);
declare variable path varchar(70);
declare variable img blob sub_type 0 segment size 16384;
BEGIN
res=0;
--получение пути к картинке
SELECT "ImageId" FROM "Object" WHERE "Id1"=:id INTO :ImgId;
select "ImageFile" FROM "Images" WHERE "Id1"=:ImgId INTO :fname;
SELECT "Value" FROM "Options" WHERE "Param"='ImagePath' INTO :path;
fname=:path||:fname;
--получение самой картинки
img=GET_IMAGE(:fname,:img);
INSERT INTO "TempObject" ("Image") VALUES (:img);
END
Добавлено: 16 янв 2007, 14:13
kdv
а если сохранить из блоба в файл - будет картинка?
кстати:
Код: Выделить всё
declare variable img blob sub_type 0 segment size 16384;
вот это безобразие в виде segment size - зачем?
Добавлено: 16 янв 2007, 15:00
Leonid K.
При сохранении BLOB в файл получается пустой рисунок.
Добавлено: 16 янв 2007, 16:19
WildSery
Leonid Kul писал(а):Нашёл только функцию LoadBlobFromFile из UDFDEMO....
Сама функция (немного изменёная):
Фиг поверю, что
немного. Найди отличия
Код: Выделить всё
function LoadBlobFromFile(FileName: PChar; Blob: PBlob): PBlob;
procedure LoadBLObFromFile(FileName: PChar; Blob: PBlob);
И зачем ещё один BLOb в объявлении функции?
Не пробовал и пробовать не стану, будет ли вот так работать правильно:
Вот скопировал бы как в демо, и объявил без выкрутасов - и всё б заработало.
Добавлено: 16 янв 2007, 17:25
Leonid K.
При объявлении функции, как
Код: Выделить всё
procedure LoadBLObFromFile(FileName: PChar; Blob: PBlob);
и следующем её вызове:
img равняется NULL (имя файла передаётся верно).
Добавлено: 16 янв 2007, 17:32
WildSery
Да понятно, понятно.
Только это совсем нетрадиционный подход.
Говорю ж - нафиг доп.параметр, который и не нужен? Функция проверено работает в том виде, как в демке. Если тебе нужна именно такая, чего эксперементируешь-то?
У меня самого такая же функция работает замечательно (и именно с картинками), и без всякой дополнительной тусовки.
(ну там ещё дополнительно прикручены функции для конвертации на лету в jpeg, но это уже так, к делу не относится).
Добавлено: 16 янв 2007, 17:46
Leonid K.
Я же написал выше, что в том виде как в демке тоже не работает. В этом случае в таблицу записывается null.
Добавлено: 16 янв 2007, 18:05
WildSery
Leonid K. писал(а):Я же написал выше, что в том виде как в демке тоже не работает. В этом случае в таблицу записывается null.
Вернись к родному варианту процедуры, и выполни в IBExpert'е следующее:
Код: Выделить всё
select GET_IMAGE ('тут путь с именем файла') from rdb$database
Эксперт умеет показывать картинки в том числе, да и в бинарном виде будет сразу видно.
А то может у тебя для сервера доступа к каталогу с картинками нет, а ты тут нам про неработу UDF рассказываешь.
Добавлено: 16 янв 2007, 18:57
kdv
а у меня - работает. я не скажу чего делаю, но функция LoadBlobFromFile, выдранная 1 в 1 из udfdemo, прекрасно загружает файл в блоб (на fb 1.5. на 2.0 тоже проверю).
Добавлено: 16 янв 2007, 19:25
Leonid K.
Всё, разобрался. Всем спасибо.
Всё, как обычно, из-за моей невнимательности. Перечитав ещё раз "Как научиться писать UDF за 21 минуту", понял свою ошибку. LoadBlobFromFile из UDFDEMO работает нормально, просто меня смутило то, что это процедура, а не функция, и я неправильно её задекларировал в Firebird.
Добавлено: 16 янв 2007, 19:49
kdv
и я неправильно её задекларировал в Firebird.
вот-вот. в этом плане на сайте все проверено, ошибок нет.
также стоило посмотреть
www.ibase.ru/download/safeudf.zip
p.s. собственно, я решил сделать отдельную либу с save и load блобов.
и все вроде бы нормально, только при сохранении буфера в файл почему-то у меня лезет ошибка записи в поток. вот дела...
Добавлено: 16 янв 2007, 20:37
WildSery
kdv писал(а):только при сохранении буфера в файл почему-то у меня лезет ошибка записи в поток. вот дела...
Интересно.
У меня тоже была такая срань - я правда не в файл, а просто в TMemoryStream буфер пытался запихать - скрючивало.
Так и не отладил - необходимость в процедуре отпала, и руки не дошли с тех пор.
Добавлено: 16 янв 2007, 21:56
kdv
вот-вот. и главное, в firebird.conf установлен полный доступ к external files. странные дела творятся...
Добавлено: 17 янв 2007, 15:08
kdv
www.ibase.ru/download/blobsaveload.zip
декларация, исходник (Delphi) и dll (D2006).
Функции LoadBLOBFromFile и SaveBLOBToFile.
SaveBLOBToFile в качестве результата выдает
размер сохраненного блоба.
в blobsaveload.sql - декларация функций и пример использования.
Добавлено: 17 янв 2007, 15:58
WildSery
О как. Кому верить?
BLObSaveLoad.dpr писал(а):EndOfBLOb := GetSegment(Handle, Buffer, MaxBufSize, GotLength);
DEMO/udflib.pas писал(а):EndOfBLOb := not GetSegment(Handle, Buf + ReadLen, FreeBufLenX, GotLength);
Добавлено: 17 янв 2007, 16:20
kdv
когда Кукарцев писал на дельфях, дельфя еще позволяла над числовыми типами выполнять булевские операции.
а я не стал морочить голову, применяя wordbool.
и потом, я ж перед выкладыванием все проверил в т.ч и в отладчике. на корректность работы, отсутствие утечек памяти и т.п. ну может на ошибки всесторонне не проверял, но задача была за 5 минут слабать пару функций.
Добавлено: 17 янв 2007, 17:29
WildSery
Тьфу, не обратил внимание на
until EndOfBLOb = 0;
Привык как-то наоборот, на TRUE сравнивать
