Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 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.04 c
6-1081890622
Анонимщик
2004-04-14 01:10
2004.06.06
TIdTCPServer, TIdTCPClient


1-1085296596
Natalia
2004-05-23 11:16
2004.06.06
Проблема при подключении С-ной DLL.


6-1082461934
Max003
2004-04-20 15:52
2004.06.06
Как задать автора сообщения?


14-1085052644
Igor_thief
2004-05-20 15:30
2004.06.06
Путин подписал антихакерский указ


4-1083309694
Stas
2004-04-30 11:21
2004.06.06
Изменение даты создания файла





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский