0

I'm writing a simple app to load images and save it to a Blob field in a database , and retrieve the image again when needed.

Here is my code :

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs , Vcl.StdCtrls, Vcl.ExtCtrls,
  FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf,
  FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async,
  FireDAC.Phys, FireDAC.Phys.MSAcc, FireDAC.Phys.MSAccDef, FireDAC.VCLUI.Wait,
  FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, Data.DB,
  Vcl.Grids, Vcl.DBGrids, FireDAC.Comp.DataSet, FireDAC.Comp.Client, Vcl.ExtDlgs ,Vcl.Imaging.jpeg , pngimage;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Load: TButton;
    FDConnection1: TFDConnection;
    FDTable1: TFDTable;
    DataSource1: TDataSource;
    FDTable1ID: TFDAutoIncField;
    FDTable1IMG: TBlobField;
    DBGrid1: TDBGrid;
    Write: TButton;
    Read: TButton;
    Image2: TImage;
    OpenPictureDialog1: TOpenPictureDialog;
    procedure LoadClick(Sender: TObject);
    procedure WriteClick(Sender: TObject);
    procedure ReadClick(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;
  Pic , Graph : TPicture;
  Stream1 : TStream;
implementation

{$R *.dfm}

procedure TForm1.LoadClick(Sender: TObject);
begin
//Create Tpicture
Pic := TPicture.Create;
try
// Load from file
if OpenPictureDialog1.Execute then
  begin
    Pic.LoadFromFile(OpenPictureDialog1.FileName);
    // Assign Image1 to Pic
    Image1.Picture.Assign(Pic);
    // Stretch
    Image1.Stretch := True;
  end;
Except on E : Exception do
  ShowMessage(E.Message);
end;

end;

procedure TForm1.WriteClick(Sender: TObject);
begin
Stream1 := TStream.Create;
try
  // With .JPG , .BMP files it works fine , But not workin with .PNG , .ICO files
   Pic.Graphic.SaveToStream(Stream1);
   FDTable1.Append;
   Stream1 := FDTable1.CreateBlobStream(FDTable1IMG , bmWrite);
   FDTable1.Post;

finally
  Stream1.Free;
  Pic.Free;
end;
end;

procedure TForm1.ReadClick(Sender: TObject);
begin
Graph := TPicture.Create;
try
Graph.Assign(FDTable1IMG);
Image2.Picture.Assign(Graph);   //<-- here is the problem  , Nothing shown in the TImage control
finally
  Graph.Free;
end;


end;
end.

I have two problems here :

  • First :
    In WriteClick procedure when I try to save .JPG or .bmp files , the code run without errors , and the image saved to the database , but when I try to sae .ICO or .PNG files, I the following error :

    Write error in stream

  • Second :

In ReadClick procedure , when I assign Graph to the Image2 control , Nothing shown in the TImage control, and there is no error Msg.

How can fix this problems? What I'm doing wrong?

Ilyes
  • 14,640
  • 4
  • 29
  • 55
  • Look at the code. You assigned to Stream 1 twice. Why did you do that? Read the docs and examples again. – David Heffernan May 21 '17 at 19:08
  • Every time I ask a question with delphi tag , I got a downvote , for what ? I think my question is clear and with good formatting. That only happen to my questions with delphi tag not other tags – Ilyes May 21 '17 at 19:10
  • @DavidHeffernan I try also `FDTable1IMG.LoadFromStream(Stream1);` – Ilyes May 21 '17 at 19:22
  • It's an abstract class. Read the docs. Understand the examples. Don't make stuff up at random. That never works. – David Heffernan May 21 '17 at 19:29
  • I have to say that I cannot understand how this question was ever asked. If you read any example code for `CreateBlobStream` you will surely see that it creates the stream and returns it. You will never see `TStream.Create`. Indeed `TStream.Create` is always a mistake. There are so many mistakes in the code in the question that I cannot bring myself to attempt an answer. – David Heffernan May 22 '17 at 09:02

1 Answers1

0

This is not directly the answer to what is wrong with your code, but about the inability of the TImage component to work with various image types loaded from stream (because its image type detection is based only for files by the file extension). There is no image type detection for stream loading implemented (right now) internally in this component.


The TPicture class is internally based on file extensions for content loading (from files), so you're out of luck here with streams (unless there will be an image type in stream detection implemented by the vendor).

For you it means an extra work. You can e.g. save the image type into your DB storage into an extra field, do a case switch by the stored value (e.g. a small integer kind of column where for example 0 will mean BMP, 1 PNG, 2 JPEG, etc.). Or for example save the image type e.g. as the first byte of the BLOB stream (and do the switch by that). Then create an instance by this image type (TBitmap, TPngImage, TJpegImage, etc.), load it from the BLOB stream and assign it to the TPicture of your image component.

Or implement the image type in stream detection by yourself (by inspecting the raw data for known image type headers) and do the switch by the detection result and the rest as described without explicit storing the image type in DB.


In any case, the moral story here is that if you store nothing but an image file stream into your DB storage, how you'll then determine what type of image it is when you decide to save it as a file to your disk? Which extension will you choose when having only the raw data, .bmp, .png, .jpg, or...? That's just what TImage struggles with internally.

Victoria
  • 7,822
  • 2
  • 21
  • 44