Форум: "Базы";
Текущий архив: 2004.06.06;
Скачать: [xml.tar.bz2];
ВнизКак распознать какой тип рисунка при загрузке из BLOB поля Найти похожие ветки
← →
TATIANA (2004-05-12 08:50) [0]Здравствуйте господа !
Из BLOB - поля требуется загрузить рисунок в Image , но рисунок может быть Bmp , а может быть и Jpg , как распознать при создании изображения :
var Bm2:TMemoryStream;
// Jp2:TBitmapImage; - Bmp
Jp2:TJPEGImage; - Jpg
begin
Bm2:= TMemoryStream.Create;
IBQuery1PLAN_KV.SaveToStream(Bm2);
Bm2.Position := 0;
// Jp2 := TBitmapImage.Create; - Bmp
Jp2 := TJPEGImage.Create; - Jpg
Jp2.LoadFromStream(Bm2);
Clipboard.Assign(Jp2);
// Image1.Picture.Bitmap.Assign(Jp2);
Image1.Picture.Assign(Clipboard);
Bm2.Free;
jp2.Free;
Если рисунок Bmp - Jp2 := TBitmapImage.Create; ;
Если рисунок JPG - Jp2 := TJPEGImage.Create; ,
Как же узнать , в каком случае - какой Jp2 создавать ?
Всем спасибо .
← →
sniknik © (2004-05-12 09:05) [1]у ни префикс (первые 2 байта) должны быть разные, посмотри.
← →
Desdechado © (2004-05-12 10:53) [2]лучше завести в таблице отдельное поле для указания типа
IBExpert - это оболочка, а не СУБД :)
← →
Вованчик © (2004-05-12 11:02) [3]вот посмотри рабочий пример:
//процедуры загрузки изображения из Blob-поля
type
TGraphicType = (gtBitmap, gtIcon, gtJpeg);
...
procedure ImgLoadFromStream(Stream: TMemoryStream; Image: TImage);
var
GT: TGraphicType;
NewGraphic: TGraphic;
begin
Image.Picture.Graphic := nil;
if Stream.Size > 0 then
begin
Stream.Position := 0;
//считываем данные о типе картинке
Stream.Read(GT, SizeOf(GT));
case GT of //создаем соответствующее полотно
gtBitmap : NewGraphic := TBitmap.Create;
gtIcon : NewGraphic := TIcon.Create;
gtJpeg : NewGraphic := TJPEGImage.Create;
end;
end;
//загружаем картинку из потока
try
NewGraphic.LoadFromStream(Stream);
Image.Picture.Assign(NewGraphic);
finally
NewGraphic.Free;
end;
end;
procedure LoadBlob(Image: TImage);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
TBlobField(Data.Query.FieldByName("Picture")).SaveToStream(Stream);
ImgLoadFromStream(Stream, Image);
finally
Stream.Free;
end
end;
//процедура сохранения изображения в Blob-поле
procedure TF_Main.SaveBlob(Image: TImage; GT: TGraphicType);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Stream.Position := 0;
//записываем данные о типе картинки
Stream.Write(GT, SizeOf(GT));
//загружаем картинку в поток
Image.Picture.Graphic.SaveToStream(Stream);
//и сохраняем в базе
if Data.Query.State in [dsBrowse] then
Data.Query.Edit;
TBlobField(Data.Query.FieldByName("Picture")).LoadFromStream(Stream);
Data.Query.Post;
//подтверждая изменения
Data.Query.ApplyUpdates;
finally
Stream.Free;
end
end;
← →
Danilka © (2004-05-12 11:04) [4][2] Desdechado © (12.05.04 10:53)
Чем лучше?
← →
y-soft © (2004-05-12 11:07) [5]Если формат изображения в BLOB может быть любым, то только анализом содержимого
Для наиболее распространенных примерно так:
function StreamGraphicClass(S : TStream) : TGraphicClass;
var
Pos : integer;
function IsBitmap : boolean;
var
BMPHeader : TBitmapFileHeader;
begin
Result := False;
if S.Size >= SizeOf(TBitmapFileHeader) then
begin
Pos := S.Position;
S.Seek(0,soFromBeginning);
S.ReadBuffer(BMPHeader, SizeOf(TBitmapFileHeader));
S.Position := Pos;
Result := BmpHeader.bfType = $4D42;
end;
end;
function IsMetafile : boolean;
type
PMetafileHeader = ^TMetafileHeader;
TMetafileHeader = packed record
Key : Longint;
Handle : SmallInt;
Box : TSmallRect;
Inch : Word;
Reserved : Longint;
CheckSum : Word;
end;
var
MFHeader : TMetafileHeader;
EMFHeader : TEnhMetaHeader;
begin
Result := False;
if S.Size >= SizeOf(TEnhMetaHeader) then
begin
Pos := S.Position;
S.Seek(0,soFromBeginning);
S.ReadBuffer(EMFHeader, SizeOf(TEnhMetaHeader));
S.Position := Pos;
Result := EMFHeader.dSignature = ENHMETA_SIGNATURE;
end;
if not Result and (S.Size >= SizeOf(TMetaFileHeader)) then
begin
Pos := S.Position;
S.Seek(0,soFromBeginning);
S.ReadBuffer(MFHeader, SizeOf(TMetaFileHeader));
S.Position := Pos;
Result := MFHeader.Key = integer($9AC6CDD7);
end;
end;
function IsJpegImage : boolean;
type
TJPGSignature = array[0..9] of Byte;
const
JPGSignature : TJPGSignature =
($FF, $D8, $FF, $E0, $00, $10, $4A, $46, $49, $46);
var
I : integer;
JPGS : TJPGSignature;
begin
Result := False;
if S.Size >= SizeOf(JPGSignature) then
begin
Pos := S.Position;
S.Seek(0,soFromBeginning);
S.ReadBuffer(JPGS, SizeOf(TJPGSignature));
S.Position := Pos;
for I := Low(JPGSignature) to High(JPGSignature) do
if JPGSignature[I] <> JPGS[I] then
exit;
Result := True;
end;
end;
function IsGifImage : boolean;
type
TGIFVersionRec = array[0..2] of char;
TGIFHeaderRec = packed record
Signature : array[0..2] of char; { contains "GIF" }
Version : TGIFVersionRec; { "87a" or "89a" }
end;
var
GIFHeader : TGIFHeaderRec;
begin
Result := False;
if S.Size >= SizeOf(TGIFHeader) then
begin
Pos := S.Position;
S.Seek(0,soFromBeginning);
S.ReadBuffer(GIFHeader, SizeOf(TGIFHeader));
S.Position := Pos;
Result := UpperCase(GIFHeader.Signature) = "GIF";
end;
end;
begin
if IsMetafile then
Result := TMetafile
else if IsGIFImage then
Result := TGifImage
else if IsBitmap then
Result := TBitmap
else if IsJPEGImage then
Result := TJPEGImage
else
Result := nil;
end;
← →
Desdechado © (2004-05-12 11:19) [6]2 danilka
хотя бы тем, что не надо заморачиваться анализом при чтении.
при записи сразу тип туда загнал и дальше используй.
если других средств записи в поле нет, кроме твоей программы, то все должно быть корректно.
кстати, лучше еще тем, что блоб не надо читать ДО его обработки, вдруг тебе только гифы нужны, а ты всю БД метафайлами напихал - будешь тянуть все на клиента?
не надо вскрывать банку, чтоб узнать, какое варенье в ней - прочти этикетку :)
← →
y-soft © (2004-05-12 11:19) [7]Но вообще, если форматы заранее известны, то IMHO хранить в отдельном поле уникальную сигнатуру (например, расширение аналогичного файла) лучше - не тратится время на дополнительные проверки
← →
y-soft © (2004-05-12 11:22) [8]>Desdechado © (12.05.04 11:19) [6]
Зачем тянуть все на клиента? Можно функции анализа вынести в UDF
← →
Desdechado © (2004-05-12 11:25) [9]ну, в UDF тоже не гуд блобы анализировать ...
если без UDF можно обойтись, лучше обойтись
← →
y-soft © (2004-05-12 11:25) [10]Хранение типа в отдельном поле имеет только один недостаток - худшую надежность по сравнению с непосредственным анализом данных
← →
y-soft © (2004-05-12 11:32) [11]>Desdechado © (12.05.04 11:25) [9]
А какая разница в UDF? Блобы передаются по ссылке, анализ минимальный, быстрый...
Можно предложить еще вариант: писать в блоб сначала сигнатуру типа в поле фиксированной длины, а потом саму картинку. Будет надежнее, чем хранить в отдельных полях.
← →
Danilka © (2004-05-12 11:33) [12][6] Desdechado © (12.05.04 11:19)
> вдруг тебе только гифы нужны
Хм, а зачем? Не могу представить такую задачу, когда есть необходимость выборки только, скажем, гифов, причем в этой таблице не будет поля с именем файла. А для других задач, формат по-барабану. Например, в таблице сотрудников есть необходимость хранить фотографии, в этом случае, выборка только джипегов будет бессмысленна, иметь смысл будет выборка, например, по подразделениям.
В так, дополнительное поле - больше кода и больше вероятность ошибки, чем при загрузке из поля анализ того, что там лежит.
← →
TATIANA (2004-05-12 12:51) [13]Господа , спасибо за советы .
Результат не могу сказать , еще не пробовала , но столкнулась , что DBImage работает без дополнительных действий с форматом .bmp , а с форматом .jpg - дает ошибку "Bitmap image is not valid" , неужели надо и при загрузке в DBImage анализировать формат .
← →
sniknik © (2004-05-12 12:58) [14]> неужели надо и при загрузке в DBImage анализировать формат
надо таня надо. ;о)
только не в DBImage, он с одним форматом работает а в просто Image.
если хочеш могу послать пример, работает в аксесс базой. пример убогий конечно, потому как а) писал давно б) ничего в него и вкладывал особого. но достаточно понятный.
(раньше он был в кладовке но... то было ранше :)
← →
Danilka © (2004-05-12 13:07) [15]Я года полтора дописывал квик-репорт, чтобы он джипеги понимал, выглядело примерно так:
procedure TQRDBImage.Print(OfsX, OfsY : integer);
var
jp: TJPEGImage;
DrawPict: TPicture;
Stream : TStream;
notJpg: boolean;
begin
...
jp:=TJPEGImage.Create;
Stream := TBlobStream.Create(FField as TBlobField, bmRead);
notJpg:=false;
try
jp.LoadFromStream(Stream);
except
on exception do notJpg:=true;
end;
if (not jp.Empty) and ((jp.Height=0) or (jp.width=0)) then notJpg:=true;
if notJpg then DrawPict.Assign(FField) else DrawPict.assign(jp);
Stream.free;
jp.free;
...
Код - не пример для подражания, но кое-где работает до сих пор, идею как сделать понять можно. :))
← →
Danilka © (2004-05-12 13:15) [16]Впрочем, тут еще и до меня выложили рабочие примеры, не только для джипег-бмп, короче, выбирай на вкус. :))
← →
TATIANA (2004-05-12 14:21) [17]Всем спасибо . Идея ясна .
Смотрела и думала , и надумала согласиться с danilk-ой и y_soft ,
хранить тип изображения в отдельном поле , может быть и некорректно , но делать заморочки в программе , тащить Blob на клиента , очень горомоздко .
Жаль , что DBImage работает только с одним типом .
← →
TATIANA (2004-05-13 10:51) [18]Господа , зравствуйте !
Спасибо всем за советы . Все получилось . Может быть кому-нибудь начинающему пригодится код , вожможно это не щедевр , но работает без ошибок , отлажено :
var Bm2:TMemoryStream;
Jp1:TBitmap;
Jp2:TJPEGImage;
notJpg:Boolean;
begin
notJpg := False;
Bm2:= TMemoryStream.Create;
IBQuery1PLAN_KV.SaveToStream(Bm2);
Bm2.Position := 0;
Jp1 := TBitmap.Create;
Jp1.LoadFromStream(Bm2);
try
Image1.Picture.Bitmap.Assign(Jp1);
Except
on EInvalidGraphic do notJpg := true;
end;
Jp1.Free;
Bm2.Free;
if notJpg then begin
Bm2:= TMemoryStream.Create;
IBQuery1PLAN_KV.SaveToStream(Bm2);
Bm2.Position := 0;
Jp2 := TJPEGImage.Create;
Jp2.LoadFromStream(Bm2);
try
Image1.Picture.Bitmap.Assign(Jp2);
finally
Bm2.Free;
Jp2.Free;
end;
end;
Рисунки выводятся на экран в компонент Jmage .
При записи в поле базы лучше использовать поток Bm2:TMemoryStream; , а не Bm2:TStringStream; . Tstring записывает формат Jpg некорректно , при этом не выдаются сообщения , а при загрузке в Jmage даются сообщения .
← →
sniknik © (2004-05-13 11:09) [19]лутше наверное всетаки анализировать первые 2 байта чем с вероятностью 50% нарываться на ексепт, и перезагружать картинку не говоря уже о двойном создании обьектов.
> При записи в поле базы лучше использовать поток Bm2:TMemoryStream; , а не Bm2:TStringStream; .
это вызывало сомнения? TStringStream для текста.
← →
Romkin © (2004-05-13 11:19) [20]Мой вариант:
function GetStreamImgType(Stream: TStream): TClass;
var
StreamPos: int64;
ImgSign: string;
begin
StreamPos := Stream.Position;
try
//BMP если не определено
Result := Graphics.TBitmap;
//JPEG
SetLength(ImgSign, 4);
Stream.Seek(6, soFromCurrent);
Stream.Read(ImgSign[1],4);
if (UpperCase(ImgSign) = "JFIF") or (UpperCase(ImgSign) = "EXIF") then
Result := Jpeg.TJPEGImage;
//WMF
Stream.Position := StreamPos;
SetLength(ImgSign, 4);
Stream.Read(ImgSign[1],4);
if ImgSign = #$D7#$CD#$C6#$9A then
Result := Graphics.TMetafile;
finally
Stream.Position := StreamPos;
end;
end;
procedure LoadProperImage(Stream: TStream; Picture: TPicture);
var
Img: TGraphic;
StreamPos: int64;
begin
StreamPos := Stream.Position;
Img := TGraphicClass(GetStreamImgType(Stream)).Create;
try
Stream.Position := StreamPos;
Img.LoadFromStream(Stream);
Picture.Graphic := Img;
finally
Img.Free;
end;
end;
function LoadPictureFromBLOB(Picture: TPicture; Field: TBlobField): boolean;
var
Stream: TStream;
begin
Result := False;
if not Field.isNULL then
begin
Stream := TMemoryStream.Create;
try
Field.SaveToStream(Stream);
Stream.Position := 0;
LoadProperImage(Stream, Picture);
Result := True;
finally
Stream.Free;
end;
end;
end;
procedure SavePictureToBlob(Picture: TPicture; Field: TBlobField);
var
Stream: TStream;
begin
if not (Field.DataSet.State in [dsEdit, dsInsert]) then
Field.DataSet.Edit;
Field.Clear;
if Assigned(Picture.Graphic) then
if not Picture.Graphic.Empty then
begin
Stream := TMemoryStream.Create;
try
Picture.Graphic.SaveToStream(Stream);
Stream.Position := 0;
Field.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
end;
Не идеально, конечно. Сигнатуры, кстати, в модулях есть, но я их поздно увидел :(
Зато для добавления нового формата надо просто прописать его в GetStreamImgType.
← →
y-soft © (2004-05-13 11:43) [21]>Romkin © (13.05.04 11:19) [20]
У нас очень похожие подходы :)
Вот еще, может кому-нибудь пригодится: PNG всегда начинается со строчки "‰PNG" ($89,$50,$4E,$47)
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2004.06.06;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.066 c