BLOB-Field aus SQLite auslesen und als JPG abbilden

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.

BLOB-Field aus SQLite auslesen und als JPG abbilden

Beitragvon joo » 25. Jun 2017, 17:36 BLOB-Field aus SQLite auslesen und als JPG abbilden

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;
 
joo
 
Beiträge: 6
Registriert: 28. Feb 2010, 19:23
OS, Lazarus, FPC: Winux (L 1.1 FPC 2.6) | 
CPU-Target: 64Bit
Nach oben

Beitragvon kralle » 25. Jun 2017, 18:46 Re: BLOB-Field aus SQLite auslesen und als JPG abbilden

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
Linux Mint 18.2 und Lazarus 1.9 (FPC-Version: 3.0.2)
Windows 8.1 Pro Lazarus 1.6 + Delphi XE7SP1
kralle
 
Beiträge: 470
Registriert: 17. Mär 2010, 14:50
Wohnort: Bremerhaven
OS, Lazarus, FPC: Linux Mint 18.2 - Lazarus 1.9 - FPC 3.0.2 -Win8.1 & XE7Pro | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 25. Jun 2017, 23:37 Re: BLOB-Field aus SQLite auslesen und als JPG abbilden

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.
wp_xyz
 
Beiträge: 2249
Registriert: 8. Apr 2011, 08:01

Beitragvon joo » 26. Jun 2017, 08:44 Re: BLOB-Field aus SQLite auslesen und als JPG abbilden

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]
joo
 
Beiträge: 6
Registriert: 28. Feb 2010, 19:23
OS, Lazarus, FPC: Winux (L 1.1 FPC 2.6) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 26. Jun 2017, 09:32 Re: BLOB-Field aus SQLite auslesen und als JPG abbilden

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...
wp_xyz
 
Beiträge: 2249
Registriert: 8. Apr 2011, 08:01

• Themenende •

Zurück zu Sonstiges



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast

porpoises-institution
accuracy-worried