Omar Gonzales
Omar Gonzales

Reputation: 4008

Delphi: JPG to Bitmap: Incompatible types: 'TPersistent' and 'TFileName'

I'm writing a program that:

1.- Ask the user to select a file, Any kind of image (JPG, PNG, etc)
2.- Let's user pixellate the image and shows the new pixellated image.

Since my test image is a JPG, I'm getting error: Incompatible types: 'TPersistent' and 'TFileName'

enter image description here

Before trying to convert the JPG to Bitmap, I was getting:

Bitmap image is not valid

enter image description here

Code:

unit demo_2;

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
  OpenDialog: TOpenDialog;
  OpenFolder: TFileOpenDialog;
  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);
begin
  OpenDialog := TOpenDialog.Create(nil);
  OpenDialog.Filter := 'All Files|*.*';
  OpenDialog.Options := [ofPathMustExist, ofFileMustExist];
  try
    if OpenDialog.Execute then
    begin
      // Print the selected file's path to the console
      //WriteLn(OpenDialog.FileName);
      lbl_selected_file.Caption := OpenDialog.FileName;
      img1.Picture.LoadFromFile(OpenDialog.FileName);
    end;
  finally
    //OpenDialog.Free;
  end;
end;


procedure TForm1.btn2_select_output_pathClick(Sender: TObject);
begin
  //OpenFolder := TFileOpenDialog.Create(nil);  for folder selection
  //OpenFolder.Options := [fdoPickFolders];  for folder selection
  try
    //if OpenFolder.Execute then
    begin
      PixellatedImage := TBitmap.Create;
      //PixellatedImage.LoadFromFile(OpenDialog.FileName);
      PixellatedImage.Assign(OpenDialog.FileName);

      // Pixellate the image by setting the Width and Height to a small value
      PixellatedImage.Width := 10;
      PixellatedImage.Height := 10;

      img1.Picture.Bitmap := PixellatedImage;

      //lbl_output_path.Caption := OpenFolder.FileName;   for folder selection
    end;
  finally
    //OpenFolder.Free;
    //OpenDialog.Free;
    PixellatedImage.Free;
  end;

end;

end.

Upvotes: 0

Views: 371

Answers (1)

Andreas Rejbrand
Andreas Rejbrand

Reputation: 109068

Since my test image is a JPG, I'm getting error: Incompatible types: 'TPersistent' and 'TFileName'

Actually, that's wrong in the sense that the error has nothing to do with the image being JPG. So while both "my test image is a JPG" and "I'm getting error ..." are correct, the implication ("since") is not.

The TPersistent.Assign method used in

PixellatedImage.Assign(OpenDialog.FileName);

requires a TPersistent object. In this case, when you are dealing with graphics, you typically need a TGraphic instance. Hence, you cannot pass a string, even if that string happens to be a file name of an image file.

So if you want to use the Assign method on a graphics object, you need to pass it another graphics object -- one you may have loaded from file using its own LoadFromFile:

procedure TForm1.FormCreate(Sender: TObject);
begin

  var JpegImage := TJPEGImage.Create;
  try

    var OpenDlg := TFileOpenDialog.Create(Self);
    try
      with OpenDlg.FileTypes.Add do
      begin
        DisplayName := 'JPEG images';
        FileMask := '*.jpg';
      end;
      if OpenDlg.Execute then
        JpegImage.LoadFromFile(OpenDlg.FileName)
      else
        Exit;
    finally
      OpenDlg.Free;
    end;

    var BmpImage := TBitmap.Create;
    try
      BmpImage.Assign(JpegImage);
      // For example: BmpImage.SaveToFile('K:\bitmap.bmp');
    finally
      BmpImage.Free;
    end;

  finally
    JpegImage.Free;
  end;

end;

Also, please note that you must use the idiom

LFrog := TFrog.Create;
try
  // use LFrog
finally
  LFrog.Free;
end

and never

try
  LFrog := TFrog.Create;
  // use LFrog
finally                   // WRONG!
  LFrog.Free;
end

assuming LFrog is a local variable. If LFrog isn't a local variable, it probably should be made local! Otherwise, it is important to do FreeAndNil on it and not only Free.


Update. The Q was changed so it no longer is about JPG -> BMP, but "any" image file to BMP. Then perhaps the best way is to use the Windows Imaging Component:

procedure TForm1.FormCreate(Sender: TObject);
begin

  var WicImage := TWICImage.Create;
  try

    var OpenDlg := TFileOpenDialog.Create(Self);
    try
      with OpenDlg.FileTypes.Add do
      begin
        DisplayName := 'All image files';
        FileMask := '*.jpg;*.tiff;*.tif;*.png;*.gif;*.bmp';
      end;
      with OpenDlg.FileTypes.Add do
      begin
        DisplayName := 'JPEG images';
        FileMask := '*.jpg';
      end;
      with OpenDlg.FileTypes.Add do
      begin
        DisplayName := 'TIFF images';
        FileMask := '*.tiff;*.tif';
      end;
      with OpenDlg.FileTypes.Add do
      begin
        DisplayName := 'PNG images';
        FileMask := '*.png';
      end;
      with OpenDlg.FileTypes.Add do
      begin
        DisplayName := 'GIF images';
        FileMask := '*.gif';
      end;
      with OpenDlg.FileTypes.Add do
      begin
        DisplayName := 'Bitmap images';
        FileMask := '*.bmp';
      end;
      // etc.
      if OpenDlg.Execute then
        WicImage.LoadFromFile(OpenDlg.FileName);
    finally
      OpenDlg.Free;
    end;

    var BmpImage := TBitmap.Create;
    try
      BmpImage.Assign(WicImage);
      // For example: BmpImage.SaveToFile('K:\bitmap.bmp');
    finally
      BmpImage.Free;
    end;

  finally
    WicImage.Free;
  end;

end;

Finally, I note that you write

// Pixellate the image by setting the Width and Height to a small value
PixellatedImage.Width := 10;
PixellatedImage.Height := 10;

Although not relevant to your main question about TGraphic.Assign, I should note that setting a TBitmap's Width and Height very much doesn't pixelate the image in the usual sense of the word. (Algorithmically, pixelation should be done like in this Pixelate procedure.)

Upvotes: 1

Related Questions