Link to home
Start Free TrialLog in
Avatar of jose rodriguez
jose rodriguez

asked on

How to show .jpg image on BLOG using DBCtrlGrid and DBImage component

I am using Delphi con connect to mysql, using myDac componentes (paid version).

I have a table called items(upc,description,retail,picture).
picture is a Blob Field storing .bmp or .jpg images.

How can I show a .jpg image from a BLOB field using the DBCtrlGrid and DBImage component on Delphi XE7.

There is no way for me to have .jpg in the Blob and be able to show it on the DBImage over the DBCtrlGrid, as if .bmp is the only image supported, only .bmp works ok.

I used the DBCTRLGRID to arrange the way visual components should display information, but it seems only to support display for .gmp images, I already put in use the .jpeg library but no luck.
DBCtrol_grid_noJPG_SUPPORT.png
Avatar of Ferruccio Accalai
Ferruccio Accalai
Flag of Italy image

You should load the image to a TJpg and then assign the TPicture to the DBImage Pricture
Anyway JVCL TJVDBImage supports JPEG format, and also you can register other formats like png or tiff
Avatar of jose rodriguez
jose rodriguez

ASKER

Hie Mr Accalai, yes I could load the image, problem is as shown in the picture that I am using the DBCtrlGrid and then need DBImage component to list images from the Table, If I put a TImage component then all images will be the same.

And as far as I am concern, there is no way to load a .jpb into the DBImage component when is ON A DBCTRLGRID, if I am mistaken this is why I am requesting help.
I was speaking about TDBImage, not Timage. You can assign graphics to a dbimage pitcure also.
When you try to load even at design time the component image from Blob Field, if the field on the table contains .BMP its ok if not, you get this error, anybody could answer with code?

Thanks
DBImage-Error-on-DBCtrlGrid.png
Again, there're lot of examples around the web about this.
This is just one of the many results you can get, also on ExEx https://groups.google.com/forum/#!topic/borland.public.delphi.ide/BFDA6s8c2cY
Again, those codes are not working, could you do it yourself to see is not working?

Here is my code:

unit uTest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.DBCtrls, Vcl.DBCGrids, Data.DB,
  DBAccess, MyAccess, MemDS, Vcl.StdCtrls, jpeg, Vcl.ExtCtrls, cxGraphics,
  cxControls, cxLookAndFeels, cxLookAndFeelPainters, cxContainer, cxEdit,
  cxTextEdit, cxDBEdit;

type
  TForm3 = class(TForm)
    db: TMyConnection;
    qTemp: TMyQuery;
    dsTemp: TMyDataSource;
    DBCtrlGrid1: TDBCtrlGrid;
    TImage1: TDBImage;
    DBText1: TDBText;
    DBText2: TDBText;
    Image1: TImage;
    DBImage1: TDBImage;
    Button1: TButton;
    qTempid: TIntegerField;
    qTempupc: TStringField;
    qTempaltupc: TStringField;
    qTempbrand: TStringField;
    qTempdescription: TStringField;
    qTempsplit: TIntegerField;
    qTempretail: TStringField;
    qTempsalesSplit: TIntegerField;
    qTempsalesRetail: TStringField;
    qTempitemnumber: TStringField;
    qTemppsize: TStringField;
    qTempuom: TStringField;
    qTempunitmea: TStringField;
    qTempcaseqty: TIntegerField;
    qTemppack: TIntegerField;
    qTemppacksize: TStringField;
    qTemppackweight: TStringField;
    qTempunitprice: TStringField;
    qTempunitcost: TFloatField;
    qTempgroup_name: TStringField;
    qTemppdate: TDateField;
    qTempptime: TTimeField;
    qTempfoodstamp: TStringField;
    qTempwic: TStringField;
    qTempwicvv: TStringField;
    qTemptaxable: TStringField;
    qTempscale: TStringField;
    qTempdeposit: TStringField;
    qTempdepositvalue: TStringField;
    qTempcomments: TStringField;
    qTemppicture: TStringField;
    qTempactive: TStringField;
    Label1: TLabel;
    cxDBTextEdit1: TcxDBTextEdit;
    DBImage2: TDBImage;
    procedure qTempAfterScroll(DataSet: TDataSet);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure DBCtrlGrid1PaintPanel(DBCtrlGrid: TDBCtrlGrid; Index: Integer);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
     procedure ShowJPG(FieldImagen:TBlobField; Picture:TPicture);
  end;

var
  Form3: TForm3;
  JPegImage : TJpegImage;  //A temporary JPeg
implementation

{$R *.dfm}

procedure TForm3.Button1Click(Sender: TObject);
begin

end;

procedure TForm3.DBCtrlGrid1PaintPanel(DBCtrlGrid: TDBCtrlGrid; Index: Integer);
Var
  MyBlobStream : TBlobStream;
begin
  // Do Only if a JPeg available
  if (qTemp.FieldByName('Picture').IsBlob) and (not(qTemp.FieldByName('Picture').IsNull)) then
  begin
    // Prepare Streams
    MyBlobStream := TBlobStream.Create(TBlobField(qTemp.FieldByName('Picture')),bmRead);
    JPegImage.LoadFromStream(MyBlobStream);
    TImage1.Picture.Assign(JPegImage);
    MyBlobStream.Free;  // Free Stream
  end
  else Timage1.Picture := Nil;  // No JPeg saved disable display

end;

procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  JPegImage.Free;  // Free JPeg-Object
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
 JpegImage := TJPegImage.Create; // Create JPeg-Object
 qTemp.Open ;
end;

procedure TForm3.qTempAfterScroll(DataSet: TDataSet);
Var
  MyBlobStream : TBlobStream;
begin

  // Do Only if a JPeg available
  if (qTemp.FieldByName('picture').IsBlob) and (not(qTemp.FieldByName('picture').IsNull)) then
  begin
    // Prepare Streams
    MyBlobStream := TBlobStream.Create(TBlobField(qTemp.FieldByName('Picture')),bmRead);
    JPegImage.LoadFromStream(MyBlobStream);
    TImage1.Picture.Assign(JPegImage);
    MyBlobStream.Free;  // Free Stream
  end
  else Timage1.Picture := Nil;  // No JPeg saved disable display

end;

procedure TForm3.ShowJPG(FieldImagen: TBlobField; Picture: TPicture);
var
    Stream: TMemoryStream;
    Jpg   : TJpegImage;
  begin
    Jpg    := nil;
    Stream := nil;
    try
      Stream := TMemoryStream.Create;
      FieldImagen.SaveToStream(Stream);
      if Stream.Size > 0
       then
       begin
              Jpg             := TJpegImage.Create;
              Stream.Position := 0;
              Jpg.LoadFromStream(Stream);
              Picture.Assign(Jpg);
           end
       else Picture.Assign(nil);
    except
      Picture.Assign(nil);
    end;
    jpg.Free;
    Stream.Free;
end;

end.

That code, generates NO ERRORS but images are not loaded.

ENPHASIS:  "*.BMP images are are shown on Direct DBImage component over a DBCtrlGrid.  Whoever responding to this, first test my code (just copy paste) and then express your opinions, I searched all possible solutions on the web and still cannot find it.

Thanks again.
NOTWORKING.jpg
Jose,
I used a TImage component

and just this piece of code: (my image is in the column IMG)
implementation

uses Jpeg;

{$R *.dfm}

procedure TForm1.DBCtrlGrid1PaintPanel(DBCtrlGrid: TDBCtrlGrid; Index: Integer);
var JI: TJPEGImage;
  fld: TField;
  bs: TBlobStream;
begin
  fld := DBCtrlGrid.DataSource.DataSet.FieldByName('IMG');
  if not fld.IsNull and fld.IsBlob then
  begin
    Ji := TJPegImage.Create;
    try
      bs := TBlobStream.Create(TBlobField(fld), bmRead);
      try
        ji.LoadFromStream(bs);
        ji.DIBNeeded;
        Image1.Picture.Assign(ji);
      finally
        bs.Free;
      end;
    finally
      Ji.Free;
    end;
  end;
end;

Open in new window

hmmm, seems you copied from Kretschmar's code:
https://www.experts-exchange.com/questions/10175461/JPG-Images-into-TDBCtrlGrid.html

odd that he uses a component with a global scope for that

for your code, some remarks:
your getting warnings ? object not initialized

that's because you use the try finally block in a wrong way
and you probably have memory leaks

  Jpg    := nil;  
    Stream := nil;
    try
      Stream := TMemoryStream.Create;
      FieldImagen.SaveToStream(Stream);

Open in new window


There is no point in setting Jpg and Stream := nil
It just removes the warning, but doesn't solve the problem > potential memory leak

Try should come after the create
and the free should be wrapped in a finally end

Jpg := TJpegImage.Create;
try
  // do something
finally
    jpg.Free;
end; 

Open in new window


you get an access violation when stream.size = 0
when executing jpg.Free
I need specifically to use TDBImage to load it, remember this guys.  No body is pointing straight to the problem, focus on the issue not on my coding, again "WHY DBIMAGE only shows .bmp image when is on a DBCTRLGrid.
no you don't :)
as it doesn't work with a TDBImage, we all provide a workaround.

certain components are built by borland and why they were so narrow minded about this, i don't know

in principal, you could do the following:
* convert the image to a .bmp upon uploading it to the database (same technique as shown)
* store the .bmp it in a secondary blob and show that secondary blob column via the TDBImage
if you don't believe me, which i follow ...

attempted this:
https://delphihaven.wordpress.com/2011/01/22/tip-detecting-graphic-formats/

the bottomline is: TPicture doesn't have a LoadFromStream
> it uses registered file extensions and LoadFromFile to determine the picture graphic class

I attempted an old trick:
Copy a Borland/Embarcadero source file: Vcl.DBCtrls.pas to the project directory and modify it
> I added virtual to the TDBImage.LoadPicture method so i could override it in a descendant
procedure LoadPicture; virtual;

alas, all my attempts fail
this is my source 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, Data.DB,
  DBAccess, Ora, OraCall, MemDS, Vcl.DBCGrids;

type
  TBDImage = class(Vcl.DBCtrls.TDBImage)
  public
    procedure LoadPicture; override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    DBCtrlGrid1: TDBCtrlGrid;
    DBText1: TDBText;
    DBImage1: TDBImage;
    OraQuery1: TOraQuery;
    OraSession1: TOraSession;
    OraDataSource1: TOraDataSource;
    Image1: TImage;
    procedure FormShow(Sender: TObject);
  private
    procedure AddMsg(Msg: string);
    { Private declarations }
  public
    { Public declarations }
  end;



var
  Form1: TForm1;

implementation

uses GIFImg, JPEG, PngImage;

{$R *.dfm}

const
  MinGraphicSize = 44; //we may test up to & including the 11th longword
  SInvalidImage = 'Invalid image';

function FindGraphicClass(const Buffer; const BufferSize: Int64;
  out GraphicClass: TGraphicClass): Boolean; overload;
var
  LongWords: array[Byte] of LongWord absolute Buffer;
  Words: array[Byte] of Word absolute Buffer;
begin
  GraphicClass := nil;
  Result := False;
  if BufferSize < MinGraphicSize then Exit;
  case Words[0] of
    $4D42: GraphicClass := TBitmap;
    $D8FF: GraphicClass := TJPEGImage;
    $4949: if Words[1] = $002A then GraphicClass := TWicImage; //i.e., TIFF
    $4D4D: if Words[1] = $2A00 then GraphicClass := TWicImage; //i.e., TIFF
  else
    if Int64(Buffer) = $A1A0A0D474E5089 then
      GraphicClass := TPNGImage
    else if LongWords[0] = $9AC6CDD7 then
      GraphicClass := TMetafile
    else if (LongWords[0] = 1) and (LongWords[10] = $464D4520) then
      GraphicClass := TMetafile
    else if StrLComp(PAnsiChar(@Buffer), 'GIF', 3) = 0 then
      GraphicClass := TGIFImage
    else if Words[1] = 1 then
      GraphicClass := TIcon;
  end;
  Result := (GraphicClass <> nil);
end;

function FindGraphicClass(Stream: TStream;
  out GraphicClass: TGraphicClass): Boolean; overload;
var
  Buffer: PByte;
  CurPos: Int64;
  BytesRead: Integer;
begin
  if Stream is TCustomMemoryStream then
  begin
    Buffer := TCustomMemoryStream(Stream).Memory;
    CurPos := Stream.Position;
    Inc(Buffer, CurPos);
    Result := FindGraphicClass(Buffer^, Stream.Size - CurPos, GraphicClass);
    Exit;
  end;
  GetMem(Buffer, MinGraphicSize);
  try
    BytesRead := Stream.Read(Buffer^, MinGraphicSize);
    Stream.Seek(-BytesRead, soCurrent);
    Result := FindGraphicClass(Buffer^, BytesRead, GraphicClass);
  finally
    FreeMem(Buffer);
  end;
end;

procedure LoadPictureFromBlobField(Field: TBlobField; Dest: TPicture);
var
  Graphic: TGraphic;
  GraphicClass: TGraphicClass;
  Stream: TMemoryStream;
begin
  Graphic := nil;
  Stream := TMemoryStream.Create;
  try
    Field.SaveToStream(Stream);
    if Stream.Size = 0 then
    begin
      Dest.Assign(nil);
      Exit;
    end;
    if not FindGraphicClass(Stream.Memory^, Stream.Size, GraphicClass) then
      raise EInvalidGraphic.Create(SInvalidImage);
    Graphic := GraphicClass.Create;
    Stream.Position := 0;
    Graphic.LoadFromStream(Stream);
    Dest.Assign(Graphic);
  finally
    Stream.Free;
    Graphic.Free;
  end;
end;

procedure Tform1.AddMsg(Msg: string);
begin
  Memo1.Lines.Insert(0, Msg);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
end;

{ TBDImage }

procedure TBDImage.LoadPicture;
begin
  if Assigned(Field) and not Field.IsNull and Field.IsBlob then
  begin
    LoadPictureFromBlobField(TBlobField(Field), Picture);
  end;
end;

end.

Open in new window


als, that trick doesn't work anymore
This question needs an answer!
Become an EE member today
7 DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.