Home > Blockchain >  User-selected image file not showing in TImage component
User-selected image file not showing in TImage component

Time:01-02

I have this procedure that lets a user select an image file. Once selected, it should be displayed in a TImage component.

Why is it not showing (even when the file path is shown in a label)?

procedure TForm1.btn1_select_imgClick(Sender: TObject);
var
  OpenDialog: TOpenDialog;
begin
  OpenDialog := TOpenDialog.Create(nil);
  OpenDialog.Filter := 'All Files|*.*';
  OpenDialog.Options := [ofPathMustExist, ofFileMustExist];
  try
    if OpenDialog.Execute then
    begin
      lbl_selected_file.Caption := OpenDialog.FileName;
      img1.Picture.LoadFromFile(OpenDialog.FileName);
      OriginalImage := TBitmap.Create;
      OriginalImage.Assign(img1.Picture.Bitmap);
    end;
  finally
    OpenDialog.Free;
  end;
end;

image

Expected result:

image

Full code:

unit image_blurrr_unit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Imaging.Jpeg;

var
  OriginalImage: TBitmap;
  PixellatedImage: TBitmap;

type
  TForm1 = class(TForm)
    btn1_select_img: TButton;
    btn2_select_output_path: TButton;
    lbl_selected_file: TLabel;
    lbl_output_path: TLabel;
    img1: TImage;
    pnl_img: TPanel;
    pnl_btns: TPanel;
    procedure btn1_select_imgClick(Sender: TObject);
    procedure btn2_select_output_pathClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn1_select_imgClick(Sender: TObject);
var
  OpenDialog: TOpenDialog;
begin
  OpenDialog := TOpenDialog.Create(nil);
  OpenDialog.Filter := 'All Files|*.*';
  OpenDialog.Options := [ofPathMustExist, ofFileMustExist];
  try
    if OpenDialog.Execute then
    begin
      lbl_selected_file.Caption := OpenDialog.FileName;
      img1.Picture.LoadFromFile(OpenDialog.FileName);
      OriginalImage := TBitmap.Create;
      OriginalImage.Assign(img1.Picture.Bitmap);
    end;
  finally
    OpenDialog.Free;
  end;
end;

procedure TForm1.btn2_select_output_pathClick(Sender: TObject);
var
  FileOpenDialog: TFileOpenDialog;
  OutputImage: TBitmap;
begin
  FileOpenDialog := TFileOpenDialog.Create(nil);
  try
    FileOpenDialog.Options := [fdoPickFolders];
    FileOpenDialog.Title := 'Select Output Path';
    if FileOpenDialog.Execute then
    begin
      OutputImage := TBitmap.Create;
      try
        // Create a copy of the original image
        OutputImage.Assign(OriginalImage);

        // Apply the blur effect to the output image here...

        // Save the output image to the selected folder
        OutputImage.SaveToFile(FileOpenDialog.FileName   '\output.jpg');
      finally
        OutputImage.Free;
      end;
    end;
  finally
    FileOpenDialog.Free;
  end;
end;

end.

CodePudding user response:

The answer is in the TPicture.Bitmap documentation:

If Bitmap is referenced when the picture contains a Metafile or Icon graphic 1, the graphic won't be converted (Types of Graphic Objects). Instead, the original contents of the picture are discarded and Bitmap returns a new, blank bitmap.

1: just replace "a Metafile or Icon graphic" with "any non-BMP graphic".

So, if the user selects a non-.bmp file (which is likely the case, since .bmp files are rarely used nowadays, in favor of other file formats, like PNG), then accessing img1.Picture.Bitmap will wipe out the current image that has been loaded into img1.Picture, replaced with a blank TBitmap object (which you then assign to your OriginalImage object). That is why you don't see anything being displayed in the TImage.

The solution is to access the original loaded image via the TPicture.Graphic property, instead of the TPicture.Bitmap property, eg:

OriginalImage.Assign(img1.Picture.Graphic);

That being said, there is another problem with your code:

OutputImage.SaveToFile(FileOpenDialog.FileName   '\output.jpg');

OutputImage is a TBitmap, so its SaveToFile() method can only create a BMP-encoded file. So, you are creating a BMP file with a .jpg file extension, which does not make it a valid JPG image. To do that, you would need to use TJPEGImage instead of TBitmap, eg:

uses
  ..., Vcl.Imaging.jpeg;

procedure TForm1.btn2_select_output_pathClick(Sender: TObject);
var
  FileOpenDialog: TFileOpenDialog;
  BlurredImage: TBitmap;
  OutputImage: TJPEGImage;
begin
  FileOpenDialog := TFileOpenDialog.Create(nil);
  try
    FileOpenDialog.Options := [fdoPickFolders];
    FileOpenDialog.Title := 'Select Output Path';
    if FileOpenDialog.Execute then
    begin
      BlurredImage := TBitmap.Create;
      try
        // Create a copy of the original image
        BlurredImage.Assign(OriginalImage);

        // Apply the blur effect to the output image here...

        // Save the output image to the selected folder
        OutputImage := TJPEGImage.Create;
        try
          OutputImage.Assign(BlurredImage);
          OutputImage.SaveToFile(FileOpenDialog.FileName   '\output.jpg');
        finally
          OutputImage.Free;
        end;
      finally
        BlurredImage.Free;
      end;
    end;
  finally
    FileOpenDialog.Free;
  end;
end;

UPDATE:

That said, if you want the output file to be in the same format as the input file, then you can do this instead:

var
  OriginalImage: TGraphic;
  OriginalExt: String;

...

procedure TForm1.btn1_select_imgClick(Sender: TObject);
var
  OpenDialog: TOpenDialog;
begin
  OpenDialog := TOpenDialog.Create(nil);
  OpenDialog.Filter := 'All Files|*.*';
  OpenDialog.Options := [ofPathMustExist, ofFileMustExist];
  try
    if OpenDialog.Execute then
    begin
      lbl_selected_file.Caption := OpenDialog.FileName;
      img1.Picture.LoadFromFile(OpenDialog.FileName);
      OriginalImage := TGraphicClass(img1.Picture.Graphic.ClassType).Create;
      OriginalImage.Assign(img1.Picture.Graphic);
      OriginalExt := ExtractFileExt(OpenDialog.FileName);
    end;
  finally
    OpenDialog.Free;
  end;
end;

procedure TForm1.btn2_select_output_pathClick(Sender: TObject);
var
  FileOpenDialog: TFileOpenDialog;
  BlurredImage: TBitmap;
  OutputImage: TGraphic;
begin
  FileOpenDialog := TFileOpenDialog.Create(nil);
  try
    FileOpenDialog.Options := [fdoPickFolders];
    FileOpenDialog.Title := 'Select Output Path';
    if FileOpenDialog.Execute then
    begin
      BlurredImage := TBitmap.Create;
      try
        // Create a copy of the original image
        BlurredImage.Assign(OriginalImage);

        // Apply the blur effect to the output image here...

        // Save the output image to the selected folder
        OutputImage := TGraphicClass(OriginalImage.ClassType).Create;
        try
          OutputImage.Assign(BlurredImage);
          OutputImage.SaveToFile(FileOpenDialog.FileName   '\output'   OriginalExt);
          // alternatively:
          // OutputImage.SaveToFile(FileOpenDialog.FileName   '\output.'   GraphicExtension(TGraphicClass(OutputImage.ClassType)));
        finally
          OutputImage.Free;
        end;
      finally
        BlurredImage.Free;
      end;
    end;
  finally
    FileOpenDialog.Free;
  end;
end;

CodePudding user response:

Do you know that you can use FMX.TBitmap class in VCL application?

Why would anyone even consider using FMX.TBitmap in VCL application?

For one FMX.TBitmap.LoadFromFile class supports loading and saving of many image types with ease.

Another thing is that you can easily apply any number FMX.Filter.Effects to the said FMX Bitmap.

The only problem is that there is no easy way of of loading FMX Bitmap to or from VCL components.


Here is a simple code example for adding Pixelate effect for chosen file that is then saved into another file

uses FMX.Graphics, FMX.Filter.Effects;

procedure TForm1.BtnOpenImageClick(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    Image1.Picture.LoadFromFile(OPenDialog1.FileName);
    OriginalFileName := OpenDialog1.FileName;
  end;
end;

procedure TForm1.BtnSaveProcessedImageClick(Sender: TObject);
var FMXOriginalBitmap: FMX.Graphics.TBitmap;
    FMXProcessedBitmap: FMX.Graphics.TBitmap;
    FMXPixelateFilter: FMX.Filter.Effects.TFilterPixelate;
begin
  FMXOriginalBitmap := FMX.Graphics.TBitmap.Create;
  FMXOriginalBitmap.LoadFromFile(OriginalFileName);

  FMXPixelateFilter := FMX.Filter.Effects.TFilterPixelate.Create(nil);
  FMXPixelateFilter.Input := FMXOriginalBitmap;
  FMXPixelateFilter.BlockCount := 100;
  FMXProcessedBitmap := FMXPixelateFilter.Output;
  FMXProcessedBitmap.SaveToFile('D:\Proba.jpg');

  Image2.Picture.LoadFromFile('D:\Proba.jpg');
end;
  • Related