Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.06.06;
Скачать: CL | DM;

Вниз

Как распознать какой тип рисунка при загрузке из 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;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.041 c
14-1084968224
WebErr
2004-05-19 16:03
2004.06.06
Не запускается 3DMark 2001


4-1082983555
Hecker
2004-04-26 16:45
2004.06.06
Подскажите, можно ли как-нить записать...........................


1-1085565806
Yustas
2004-05-26 14:03
2004.06.06
Многоязычность


4-1082966355
bars
2004-04-26 11:59
2004.06.06
Проблема при создании собственного компонента


4-1082639648
Talla2k
2004-04-22 17:14
2004.06.06
Проблемы с потоком