Datenbank Blob to TImage

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Benutzeravatar
Levario
Beiträge: 132
Registriert: Mo 1. Sep 2014, 14:32
OS, Lazarus, FPC: Windows 11 Pro , MacOS und Linux Mint (Version 3.4 for Windows 64 bit )
CPU-Target: 64 Bit
Wohnort: Deutschland / NRW

Datenbank Blob to TImage

Beitrag von Levario »

Hallo zusammen,

Ich habe mal wieder eine frage zum Blob (mediumblob) aus einer Datenbank. Diesmal möchte ich ihn nicht herunterladen, sondern in einem Stream und von da in ein TImage.

Ich benötige eine Lösung für Jpg und png. Meine Lösung funktioniert leider nicht

Code: Alles auswählen

procedure TStammdaten.LoadDBImg;
var
ms : TMemoryStream;
begin
// Datenbank Abfrage mit Zeos
DBHiddenForm.ZQueryIndividual.SQL.Clear;
DBHiddenForm.ZQueryIndividual.SQL.Text := 'Select logoimg FROM coredata';
DBHiddenForm.ZQueryIndividual.open;

ms:=TMemoryStream.Create; // TMemorystrem erstellen
ms.Position:=0; // Memory Stream beginnt beim Zeichen 0

TBlobField(DBHiddenForm.ZQueryIndividual.FieldByName('logoimg')).SaveToStream(ms); // Datenbank Abfrage in den Stream ms speichern
try
  ImgLogo.picture.Graphic.LoadFromStream(ms);  // Stream in das TImage laden.
finally
   ms.free;
end;
end;  
.

ich bekomme hier einen Access Violation Error. Kann mir jemand auf die Sprünge helfen?

Ich habe herausgefunden das der Fehler in der Zeile:

Code: Alles auswählen

ImgLogo.picture.Graphic.LoadFromStream(ms);
liegt. Aber noch keine Lösung.

Ich rufe die oben stehende Prozedure in einem Frame über einen selbst erstellten Konstruktor auf.

Code: Alles auswählen

constructor TStammdaten.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  LoadDBImg;
end;
Der Weg ist das Ziel... Aber bitte nicht vergessen los zu laufen :).

paweld
Beiträge: 91
Registriert: So 11. Jun 2023, 16:01
OS, Lazarus, FPC: Lazarus trunk, FPC fixes

Re: Datenbank Blob to TImage

Beitrag von paweld »

Code: Alles auswählen

procedure TStammdaten.LoadDBImg;
begin
  // Datenbank Abfrage mit Zeos
  DBHiddenForm.ZQueryIndividual.SQL.Text := 'select logoimg FROM coredata';
  DBHiddenForm.ZQueryIndividual.Open;
  if not DBHiddenForm.ZQueryIndividual.IsNull then
    ImgLogo.Picture.LoadFromStream(DBHiddenForm.ZQueryIndividual.CreateBlobStream(DBHiddenForm.ZQueryIndividual.FieldByName('logoimg'), bmRead));  
  DBHiddenForm.ZQueryIndividual.Close;
end;  
Zuletzt geändert von paweld am Fr 16. Aug 2024, 07:35, insgesamt 1-mal geändert.
Grüße / Pozdrawiam
paweld

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6854
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Datenbank Blob to TImage

Beitrag von af0815 »

und vor dem Laden immer den Stream auf Position 0 setzen. Generell bewegst du durch dieledeoperation den Streampointer, damit steht der IMMER am Ende des Streams. Die Leseoperation würde ohne zurücksetzen auch dort passieren und dort ist halt nichts mehr zu lesen.

Paweld umgeht das geschickt, da der Stream quasi in Line verwendet wird. Deine Lõsung kann man besser verstehen und auch debuggen. Und ist DB unabhängiger.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: Datenbank Blob to TImage

Beitrag von wp_xyz »

paweld hat geschrieben: Fr 16. Aug 2024, 06:07

Code: Alles auswählen

procedure TStammdaten.LoadDBImg;
begin
  // Datenbank Abfrage mit Zeos
  DBHiddenForm.ZQueryIndividual.SQL.Text := 'select logoimg FROM coredata';
  DBHiddenForm.ZQueryIndividual.Open;
  if not DBHiddenForm.ZQueryIndividual.IsNull then
    ImgLogo.Picture.LoadFromStream(DBHiddenForm.ZQueryIndividual.CreateBlobStream(DBHiddenForm.ZQueryIndividual.FieldByName('logoimg'), bmRead));  
  DBHiddenForm.ZQueryIndividual.Close;
end;  
Das Inline-Erzeugen des Streams sieht zwar sehr kompakt aus, allerdings verführt das dazu, das Free zu vergessen. Besser:

Code: Alles auswählen

procedure TStammdaten.LoadDBImg;
var
  stream: TStream = nil;
  field: TField;
begin
  ...
  if not DBHiddenForm.ZQueryIndividual.IsNull then
  begin
    field := DBHiddenForm.ZQueryIndividual.FieldByName('logoimg');
    stream := DBHiddenForm.ZQueryIndividual.CreateBlobStream(field, bmRead);
    try
      ImgLogo.Picture.LoadFromStream(stream);
    finally
      stream.Free;
    end
  end;
  ...
  
(Ich habe, der besseren Lesbarkeit halber, auch noch das BlobField in eine separate Variable genommen).

paweld
Beiträge: 91
Registriert: So 11. Jun 2023, 16:01
OS, Lazarus, FPC: Lazarus trunk, FPC fixes

Re: Datenbank Blob to TImage

Beitrag von paweld »

wp_xyz hat geschrieben: Das Inline-Erzeugen des Streams sieht zwar sehr kompakt aus, allerdings verführt das dazu, das Free zu vergessen.
@wp: Vielen Dank für den Hinweis. In der Tat führt die von mir angegebene Methode zu Speicherlecks - dies sollte mit einer Variablen erfolgen, wie Sie gezeigt haben
Grüße / Pozdrawiam
paweld

Benutzeravatar
Levario
Beiträge: 132
Registriert: Mo 1. Sep 2014, 14:32
OS, Lazarus, FPC: Windows 11 Pro , MacOS und Linux Mint (Version 3.4 for Windows 64 bit )
CPU-Target: 64 Bit
Wohnort: Deutschland / NRW

Re: Datenbank Blob to TImage

Beitrag von Levario »

Gibt es eine Möglichkeit meinen Ansatz zum laufen zu bringen, denn in etwas abgewandeloter Form
mit Dateien und Datenbanken scheint er zu funktionieren.

Mit:

Code: Alles auswählen

ms:=TMemoryStream.Create; // TMemorystrem erstellen
ms.Position:=0; // Memory Stream beginnt beim Zeichen 0
hatte ich vor den Stream auf Null zu setzen.

Gruß
Levi

P.S. Ich bekomme leider keinen der beiden Ansätze zum laufen.
Der Weg ist das Ziel... Aber bitte nicht vergessen los zu laufen :).

Benutzeravatar
theo
Beiträge: 10925
Registriert: Mo 11. Sep 2006, 19:01

Re: Datenbank Blob to TImage

Beitrag von theo »

Levario hat geschrieben: Sa 17. Aug 2024, 09:58 Gibt es eine Möglichkeit meinen Ansatz zum laufen zu bringen, denn in etwas abgewandeloter Form
mit Dateien und Datenbanken scheint er zu funktionieren.

Mit:

Code: Alles auswählen

ms:=TMemoryStream.Create; // TMemorystrem erstellen
ms.Position:=0; // Memory Stream beginnt beim Zeichen 0
hatte ich vor den Stream auf Null zu setzen.

Gruß
Levi

P.S. Ich bekomme leider keinen der beiden Ansätze zum laufen.
Nach dem createn ist die Position sowieso bei 0, das kannst du dir sparen.

Ansonsten ist dir wohl nicht aufgefallen, dass oben die Lösung wahrscheinlich schon genannt ist.

Statt:
ImgLogo.Picture.Graphic.LoadFromStream(
Probiere:
ImgLogo.Picture.LoadFromStream(

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: Datenbank Blob to TImage

Beitrag von MmVisual »

Nach der Zeile mit:

.....SaveToStream(ms);

muss unbedingt diese Zeile folgen:

ms.Position:=0;

dann sollte auch dein Code funktionieren.

Ja, und dann verwenden:
ImgLogo.Picture.LoadFromStream(.....
EleLa - Elektronik Lagerverwaltung - www.elela.de

Benutzeravatar
Levario
Beiträge: 132
Registriert: Mo 1. Sep 2014, 14:32
OS, Lazarus, FPC: Windows 11 Pro , MacOS und Linux Mint (Version 3.4 for Windows 64 bit )
CPU-Target: 64 Bit
Wohnort: Deutschland / NRW

Re: Datenbank Blob to TImage

Beitrag von Levario »

theo hat geschrieben: Sa 17. Aug 2024, 11:02 Ansonsten ist dir wohl nicht aufgefallen, dass oben die Lösung wahrscheinlich schon genannt ist.

Statt:
ImgLogo.Picture.Graphic.LoadFromStream(
Probiere:
ImgLogo.Picture.LoadFromStream(
Nein ist mir nicht aufgefallen, hab es aber gerade gestestet: Fehler Unkown Picture format.

Ich nutze in den meisten Fälle Jpg oder png. Getestet habe ich es mit .jpg, png und bmp
Der Weg ist das Ziel... Aber bitte nicht vergessen los zu laufen :).

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: Datenbank Blob to TImage

Beitrag von MmVisual »

Lade die Bild Daten doch mal in ein TDBMemo und schaue was da für Daten ankommen. Ich vermute mal die Daten stehen schon falsch in der Datenbank.

Anstatt in einem TStream kann man den Inhalt in ein TFileStream speichern und sich den tatsächlichen Inhalt als Datei anschauen.

Bei einem PNG Bild sollte der Text so in etwa anfangen: ‰PNG
bei einem JPG Bild so etwas in der Nähe vom Anfang stehen: ...JFIF...

Man kann sich so den Inhalt mit Notepad++ von diesen Dateien anschauen.
Und wenn dann die Datei man nicht mit einer Bildbearbeitung geöffnet werden kann, so kann es dann Lazarus (TImage) auch nicht.
EleLa - Elektronik Lagerverwaltung - www.elela.de

Sieben
Beiträge: 292
Registriert: Mo 24. Aug 2020, 14:16
OS, Lazarus, FPC: Ubuntu Xenial 32, Lazarus 2.2.0, FPC 3.2.2
CPU-Target: i386

Re: Datenbank Blob to TImage

Beitrag von Sieben »

TPicture hat auch die Methoden SaveToStreamWithFileExt() und LoadFromStreamWithFileExt().

Benutzeravatar
Levario
Beiträge: 132
Registriert: Mo 1. Sep 2014, 14:32
OS, Lazarus, FPC: Windows 11 Pro , MacOS und Linux Mint (Version 3.4 for Windows 64 bit )
CPU-Target: 64 Bit
Wohnort: Deutschland / NRW

Re: Datenbank Blob to TImage

Beitrag von Levario »

Erssteinmal vielen Dank für die ganzen Tipps. Ich habe hier nun das Problem das, nach einem Neustart des Rechners alles geht. Aber nur einmal. Lade ich ein neues Image kommt der Fehler wieder. Trenne ich die ZConnection urz und verbinde es wieder zusammen mit dem ZQuery, vor dem neuen laden funktioniert alles wieder? Hat jemand eine Ahnung woran das liegen kann? Ich habe einen test durchgeführt in einem kleinen extra Programm nur mit einem DBImage auch hier habe ich die selben Probleme, wenn ich die Bilder direkt aus einer Datenbank lade.
Der Weg ist das Ziel... Aber bitte nicht vergessen los zu laufen :).

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: Datenbank Blob to TImage

Beitrag von MmVisual »

Ich verwende seit vielen Jahren Bilder in der Datenbank mit Zeos. Prinzipiell geht das in jedem Fall.

So in etwa sieht mein Code aus:

Code: Alles auswählen

q.Close;
q.SQL.Text := 'SELECT * FROM foto WHERE ID=' + IntToStr(iID);
q.Open;
stImg.Clear;
TBlobField(q.FieldByName('Bild')).SaveToStream(stImg); 
stImg.Position := 0;
if stImg.Size > 0 then
  img.Picture.LoadFromStream(stImg);
Drum herum gibt es noch etwas mehr, da ich die von der Datenbank geladenen Bilder in einem Cache halte um nicht jedes mal über Netzwerk die Daten zu laden. Ich verwende das mit SQLite, MySQL, MariaDB, PostgreSQL und MSSQL.
EleLa - Elektronik Lagerverwaltung - www.elela.de

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6854
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Datenbank Blob to TImage

Beitrag von af0815 »

Ich kenne so einen ähnlichen Effekt mit den Bildern. Scheinbar werden bei manchen BS die Bilder im Speicher gesperrt. Damit auch die Streams die damit zusammenhängen. Abhilfe hat mir damals nur gebracht das Bild zu lõschen und dannach erst die Streams zu schliessen und zu free'n.

Vermutlich wird das auch die Lõsung sein, warum es bei MmVisual funktioniert.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: Datenbank Blob to TImage

Beitrag von wp_xyz »

Nicht getestet, aber eins könnte noch sein: Es kommt darauf an, ob die binären Daten des Bildes in einem "reinen" BLOB-Feld gespeichert sind, oder in einem "Graphic"-Feld. Das erste enthält nur die reinen Bytes des Bildes und sollte mit Picture.LoadFromStream gelesen werden können. Das zweite enthält jedoch vor den Bilddaten eine Kennung zur Identifikation des Graphik-Formats. Ich meine, das war entweder die Endung der Graphik-Datei oder der Name der Klasse, die das Bild lesen kann (z.B. "TPortableNetworkGraphic"). Wenn dieser
Stream direkt an Picture.LoadFromStream übergeben wird, geht das schief, da dieses sofort die reinen Graphik-Daten erwartet. Du müsstest diese Kennungsbytes überlesen, so dass der Stream.Position-Zeiger wieder am Anfang der Graphik steht; dann sollte auch Picture.LoadFromStream funktionieren.

Antworten