BLOB-Field aus SQLite auslesen und als JPG abbilden

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
joo
Beiträge: 6
Registriert: So 28. Feb 2010, 19:23
OS, Lazarus, FPC: Winux (L 1.1 FPC 2.6)
CPU-Target: 64Bit

BLOB-Field aus SQLite auslesen und als JPG abbilden

Beitrag von joo »

Ich das Web und die Foren nach Beispielen durchsucht und habe folgende Prozeduren geschrieben, die aber nur z.T. erfolgreich sind.
Aufgabenstellung: Aus dem Dateisystem soll ein JPG in ein TImage geladen werden (funktioniert).
Das JPG soll in ein SQLite-Blob gespeichert werden (funktioniert). (Prozedur loadGBildClick)
Beim Retrieve des Blob aus SQLite in ein Stream wird zwar die Größe korrekt ausgegeben,
das Abbilden in ein TImage bleibt ergebnislos. (Prozedur retrieveGBild)

Hat jemand einen Rat für mich?

Code: Alles auswählen

procedure TbilderForm.loadGBildClick(Sender: TObject);
var
  Jpg: TJpegImage;
  Stream: TMemoryStream;
  FileExt: string;
  GraphType: TGraphType;
begin
  OpenPictureDialog1.Options:=OpenPictureDialog1.Options+[ofFileMustExist];
  if not OpenPictureDialog1.Execute then
    exit
  else begin
    Jpg := nil;
    Stream := nil;
    try
      Stream := TMemoryStream.Create;
      FileExt := LowerCase(ExtractFileExt(OpenPictureDialog1.FileName));
    if (FileExt = '.jpg') or (FileExt = '.jpeg') or (FileExt = '.jpe') then
      begin
      Jpg := TJpegImage.Create;
      Jpg.LoadFromFile(OpenPictureDialog1.FileName);
      Image1.Picture.Assign(Jpg);
      GraphType := gtJpeg;
      Stream.Write(GraphType, 1);
      Jpg.SaveToStream(Stream);
    end;
    Stream.Position := 0;
    S:= ' insert into GBild (GName, GBild_Data, AufnameDat, Aktuell) '
        + 'values (:iGName,:iPic,0,0)';
    with ZQGBild do begin
      Active := False;
      SQL.Clear;
      SQL.Add(S);
      ParamByName('iGName').AsString:= DBEdit8.Text;
      ParamByName('iPic').SetBlobData(Stream.Memory,Stream.Size);
      ExecSQL;
    end;
    except
      jpg.Free;
      Stream.Free;
    raise;
    end;
      jpg.Free;
      Stream.Free;
    end;
end;
 
procedure TbilderForm.retrieveGBildClick(Sender: TObject);
var
  Stream: TMemoryStream;
  Jpg: TJpegImage;
  Size: Integer;
  myGName: String;
begin
  Jpg := nil;
  Stream := nil;
  with ZQGBild do begin
    SQL.clear;
    SQL.Add('select * from GBild ');
    SQL.Add('where GName = :iGName');
    ParamByName('iGName').AsString := DBEdit8.Text;
    ExecSQL;
    Open;
    myGname:= FieldByName('GName').AsString;
    if not FieldByName('GBild_Data').IsNull then
    try
      Stream:= TMemoryStream.Create;
      TBlobField(FieldByName('GBild_Data')).SaveToStream(Stream);
      if Stream.Size > 0 then begin
      showMessage('StreamSize='+intToStr(Stream.Size)+' Jpeg von '+myGName);
        Jpg:= TJpegImage.Create;
        Stream.Position := 0;
        Jpg.LoadFromStream(Stream, Stream.Size);
        Image1.Picture.Jpeg.Assign(Jpg);
      end
      else
        Image1.Picture.Assign(nil);
        showMessage('StreamSize = 0');
    except
      Image1.Picture.Assign(nil);
      showMessage('McMurphy');
    end;
    Jpg.Free;
    Stream.Free;
  end;
end;
 

Benutzeravatar
kralle
Lazarusforum e. V.
Beiträge: 988
Registriert: Mi 17. Mär 2010, 14:50
OS, Lazarus, FPC: Linux Mint 20 , FPC 3.3.1 , Lazarus 2.1.0 -Win10 & XE7Pro
CPU-Target: 64Bit
Wohnort: Bremerhaven
Kontaktdaten:

Re: BLOB-Field aus SQLite auslesen und als JPG abbilden

Beitrag von kralle »

Moin,

joo hat geschrieben:

Code: Alles auswählen

 
        Image1.Picture.Jpeg.Assign(Jpg);
 

muß man vor einem "Assign" nicht ein "Create" nutzen?
Die Autovervollständigung von " Image1.Picture.Jpeg." bietet das jedenfalls an?

Nur mal so ein Schuß in Blaue.

Gruß Heiko
OS: Manjaro Linux, Debian und Windows 10
FPC-Version: 3.2.2 , Lazarus 3.0
+ Delphi XE7SP1

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: BLOB-Field aus SQLite auslesen und als JPG abbilden

Beitrag von wp_xyz »

Du hast beim Schreiben des BLOB zuerst 1 Byte für GraphType geschrieben, dann das JPEG. Beim lesen hast du aber den kompletten Stream an JPEG übergeben, ohne das GraphType-Byte am Anfang zu berücksichtigen. Das heißt, dass der Stream um 1 Byte versetzt ist. Also: Setze Stream.Position vor Jpeg.LoadFromStream auf 1 (statt auf 0). Und werte das GraphType-Byte richtig aus - es könnte ja sein, dass gar keine JPEG geschrieben ist.

joo
Beiträge: 6
Registriert: So 28. Feb 2010, 19:23
OS, Lazarus, FPC: Winux (L 1.1 FPC 2.6)
CPU-Target: 64Bit

Re: BLOB-Field aus SQLite auslesen und als JPG abbilden

Beitrag von joo »

Problem gelöst.
Beide Antworten waren sehr hilfreich, danke!

Korrektur lautet:
if Stream.Size > 0 then begin
showMessage('StreamSize='+intToStr(Stream.Size)+' Jpeg von '+myGName);
Jpg:= TJpegImage.Create;
Stream.Position:= 1; // Byte 0 is GraphType
Jpg.LoadFromStream(Stream);
Image1.Picture.Jpeg.Create.Assign(Jpg);
end;[code=laz][/code]

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: BLOB-Field aus SQLite auslesen und als JPG abbilden

Beitrag von wp_xyz »

joo hat geschrieben:

Code: Alles auswählen

 Image1.Picture.Jpeg.Create.Assign(Jpg)

Das ist nicht nötig, man kann ein Jpg dem Picture direkt zuweisen:

Code: Alles auswählen

 Image1.Picture.Assign(jpg);

Und das GraphType-Byte solltest du schon auswerten, sonst brauchst du es ja auch gar nicht zu schreiben. Also: Prüfen, ob GraphType dem Wert für JPEG entspricht. Wenn ja: JPEG erzeugen und Rest des Streams einlesen. Andernfalls Fehlermeldung

Code: Alles auswählen

var
  GraphType: Byte;
begin
  if Stream.Size > 0 then begin
    ShowMessage('StreamSize='+intToStr(Stream.Size)+' Jpeg von '+myGName);
  GraphType := Stream.ReadByte;
  if GraphType = ord(gtJpeg) then  begin
    jpeg := TJpegImage.Create;
    try
      //Stream.Position:= 1; // Byte 0 is GraphType  // NICHT MEHR NÖTIG, DA STREAM SCHON AN POS 1 ist
      Jpg.LoadFromStream(Stream);
      Image1.Picture.Assign(Jpg);
    finally
      jpeg.Free;
    end;
    // oder auch gleich direkt: Image1.Picture.LoadfromStream(Stream);
  end else
    ShowMessage('JPEG-Bild erwartet, aber nicht gefunden.');
end;

Und die Art, mit Exceptions umzugehen, ist etwas seltsam, evtl sogar falsch (darüber habe ich im Detail nicht nachgedacht). Statt

Code: Alles auswählen

  stream := nil;
  jpeg := nil
  try
    stream := TMemorystream.Create;
    jpeg := TJpegImage.Create;
    //mach' was damit...
  except
    jpeg.Free;
    stream.Free;
    raise;
  end;
  jpeg.Free;
  stream.Free;

schreibe einfach

Code: Alles auswählen

  stream := TMemorystream.Create;
  jpeg := TJpegImage.Create;
  try
    // mach' was damit...
  finally  // Der Code zwischen "finally" und "end" wird ausgeführt, wenn im Bereich "try"-"finally" eine Exception auftritt, oder exit aufgerufen wird.
    jpeg.Free;
    stream.Free;
  end;

Die "super-exakte" Version wäre

Code: Alles auswählen

  stream := TMemoryStream.Create;
  try
    jpeg := TJpegImage.Create;
    try
      // mach' etwas damit...
    finally
      jpeg.Free;
    end;
  finally
    stream.Free;
  end;

weil hier auch der Fall abgefangen wird, dass beim Erzeugen des jpeg-Objekts etwas schief geht. das könnte aber nur ein Speicherüberlauf sein. Aber wenn es zu einem speicherüberlauf kommt, hat man eh schon verloren...

Antworten