Gelöst: TDBGrid Bilder aus DB BLOB anzeigen lassen

Rund um die LCL und andere Komponenten
Antworten
DR. Volker Jaenisch
Beiträge: 4
Registriert: Do 6. Aug 2015, 02:32

Gelöst: TDBGrid Bilder aus DB BLOB anzeigen lassen

Beitrag von DR. Volker Jaenisch »

Servus!

Ich habe TDBGrid erweitert um Bilder aus BLob-Felder anzuzeigen. Dabei sind mir einige bedenkenswerte Dinge aufgefallen.

Es hat mich sehr erstaunt, dass ich ein JPGBild welches ich problemlos per TDBImage als BLOB in eine SQLIte DB schreiben und auch lesen konnte, nicht aus dem BLOB-Stream des Feldes in ein TPicture laden konnte. Beim Versuch aus den Stream zu lesen kam die Meldung "Unbekanntes Bildformat".

Die Ursache offenbarte sich mir nach einiger Zeit der Recherche. TDBImage schreibt in den Blob-Stream eine Kennung den sogenannten Header, welcher beim späteren Lesen dem TDBImage-Feld sagen soll, was für ein Typ von Grafik (JPG, GIF, etc.) denn dort gespeichert ist.
Warum TDBImage diese Information nicht aus dem Header des Bildes auslesen kann bleibt mir ein Mysterium, da z.B. TPicture genau das kann.

In den neueren Versionen von Lazarus kann man dieses "Feature" von TDBImage deaktivieren (WriteHeader := False), mit der Folge, dass TDBImage seine in die DB geschriebenen Bilder nicht mehr laden kann. Was für ein Fortschritt :-). Allerdings gelang danach das Lesen aus dem Stream in ein TPicture sofort.

Für mich aber keine Lösung, da ich in meiner Anwendung sowohl TDBImage als auch ein TDBGrid mit Bildern anzeigen will.

Der folgende Code kloppt die Bilder brutal in die Zellen ohne auf die Aspect-Ratio Rücksicht zu nehmen. Das kann man einfach verbessern.
Mir geht es hier nur darum zu Zeigen, wie man das oben genannte Problem löst. Läuft unter Debian/Windows 64 Bit. Nicht getestet unter 32 Bit!

Code: Alles auswählen

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  ms : TMemoryStream; // Buffer for the image data
  Image : TPicture; // Image Instance as source for drawing into the canvas of the grid cell
  Field : TField; // The Field of the current cell in the DBGrid
  BlobField : TBlobField; // The Field casted to a BlobField
begin
  with (Sender As TDBGrid) do
  begin
    Field := Column.Field;
    if Field.isBlob then  // Do we deal with a blob field?
    begin
      ms := TMemoryStream.Create; 
      BlobField := TBlobField( Field );
      if BlobField.BlobSize > 0 then // The blob maybe empty
      begin
        BlobField.SaveToStream(ms);
        if ms.Position > 0 then // The blob may be empty, check again (redundant checking?)
        begin
          ms.Position := 8 ; //Skip TDBImage induced type code header. Not tested if the length of the header is platform dependend.  
 
          Image := TPicture.Create;
          try
              Image.LoadFromStream( ms ) ;
              ms.Free ;
              Canvas.StretchDraw(Rect, Image.graphic);
              image.free;
          except
          end;
        end;
      end
      else
      begin // Draw a red cross in the cell if the Blob is empty
          Canvas.Brush.color:= clwhite;
          Canvas.Rectangle(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);
          Canvas.Pen.color:= clred;
          Canvas.Line(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom );
          Canvas.Line(Rect.Right, Rect.Top, Rect.Left, Rect.Bottom );
      end;
    end;
  end;
end;     
Normalerweise Code ich mit Python. Da das Deployment von Python QT-Anwendungen unter Windows aufwändig ist, habe ich für ein Spielprojekt mal wieder nach etwa 5 Jahren PASCAL ausprobiert. Lazarus hat sich gut weiter entwickelt und läuft unter Debian sehr stabil.
Auch lief der unter Debian entwickelte Code unter Windows out of the Box. Lazarus hält also sein Versprechen "Write Once compile everywhere". Und das ist unter Python tatsächlich nicht so einfach der Fall.

Aber mich haben andere Dinge furchtbar abgeschreckt:
* Gibt es kein Paket-System für Lazarus? Also wie CPAN, PyPI, etc. hat doch heute jede Programmiersprache einen Paket-Server und entsprechende Client-Tools um 3rd-Party-Pakete für jede Plattform standartisiert und reproduzierbar zur Verfügung zu stellen.
* Wie kann es sein, dass solche Inkompatibilitäten wie zwischen TPicture und TDBImage überhaupt auftreten? Wie kann es sein, dass der Fix an einer Komponente diese außer Gefecht setzt? In den 20 Jahren die ich mit Python programmiere ist es mir, mal abgesehen vom debuggen von Netzwerk-Protokollen, nie nötig gewesen einen Byte-Stream einer Komponente der Klassen-Bibliothek debuggen zu müssen.
* Es scheint mir keine Unterstützung für unterschiedliche VCS in Lazarus zu geben?

Ich weiß wie unfair es ist an eine Nischen-Sprache wie Lazarus die Anforderungen von Main-Stream-Sprachen wie Python zu stellen.
Aber Python war auch mal ein Nischen-Sprache. Diese Nische hat Python verlassen, in dem es sich großen Anforderungen gestellt hat und diese gemeistert hat.

Beste Grüße

Volker

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6782
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: Gelöst: TDBGrid Bilder aus DB BLOB anzeigen lassen

Beitrag von af0815 »

Ich glaube, das einige der Fragen im Englischen Forum bzw. auf der Maillingliste von Lazarus (http://lists.lazarus.freepascal.org/mai ... fo/lazarus) besser aufgehoben sind bzw. dort auch mehr Entwickler anzutreffen sind.

Es ist aber auch so, das manche Besonderheiten aufgrund der Kompatibilität mit Delphi vorhanden sind. Das ist aber schon öfters Ausdiskutiert worden und deshalb gibt es auch GUI/Projekte die diese 'Abhängigkeit' nicht wünschen und deshalb alles selbst in die Hand nehmen (msegui z.B. hat hier im Forum einen eigenen Bereich).

Natürlich werden von den Lazarusentwickler auch Patches entgegengenommen, bzw. wird in der Mailingliste dann oft der Hinweis gegeben es bitte in den Bugtracker einzutragen, damit das 'Mis-' Verhalten dann dokumentiert ist. Auch ist dann die Zuordnung einfacher, da öfters erst geklärt werden muss ob Lazarus oder der FPC (bzw. die Bibliotheken der Programme) an den Verhalten mitwirkt.

Andi
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten