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;
Expected result:
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 andBitmap
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;