Save picture to a variety of file formats

Uli Gerhardt picture Uli Gerhardt · Sep 7, 2011 · Viewed 8.1k times · Source

I have a routine procedure DrawStuff(ACanvas: TCanvas; const ARect: TRect) that draws something to a specified rectangle on a TCanvas. At the moment I call DrawStuff with a PaintBox's canvas. Now I'm adding a Save as option, in which the user shall be able to select from a variety of file formats (bmp, wmf, jpg, ... - preferrably as many TGraphic descendants as possible) to save the results of DrawStuff to.

Drawing to a TMetafile and saving that as "bla.bmp" or Assigning it to a TPicture doesn't work correctly - e.g. it produces files with extension ".bmp" that aren't bitmaps. Right now I can't figure a solution that doesn't involve special-casing every single file format:

  • bmp - Use TBitmap.Canvas.
  • wmf/emf: Use TMetafileCanvas.
  • etc. etc.

Do you know have any ideas for me?

Answer

Ken Bourassa picture Ken Bourassa · Sep 7, 2011

I guess a "dumb" conversion would probably as simple as this :

type
  TGraphicTypeEnum = (gteBMP, gteJPG, gteTIF, gtePNG);

procedure SaveGraphicAs(AGraphic : TGraphic; AGraphicType : TGraphicTypeEnum; AFileName : String);
var vGraphicClass : TGraphicClass;
    vTargetGraphic : TGraphic;
    vBmp : TBitmap;
begin

  case AGraphicType of
    gteBMP : vGraphicClass := TBitmap;
    gtejpg : vGraphicClass := TJPEGImage;
    gtetif : vGraphicClass := TWICImage;
    gtepng : vGraphicClass := TPngImage;
  else
    // EXIT; or raise...
  end;
  if aGraphic is vGraphicClass then //As suggested by Rob Kennedy
    AGraphic.SaveToFile(AFileName)
  else
  begin
    vBmp := nil;
    vTargetGraphic := vGraphicClass.Create;
    try
      vBmp := TBitmap.Create;
      vBmp.Assign(AGraphic);
      vTargetGraphic.Assign(vBmp);
      vTargetGraphic.SaveToFile(aFileName);
    finally
      vTargetGraphic.Free;
      vBmp.Free;
    end;
  end;
end;

Assigning to a TPicture didn't work, as when you assign to a TPicture, TPicture will convert the graphic to the class you are assigning from.

Note that in my example, there is 2 layers of conversion as the original image is converted to bitmap before being converted to the final format. There can be quite a bit of loss of information in the process. Most (all?) graphic type know how to convert to and from TBitmap, but TJPEGImage has no idea how to convert to TPngImage and vice versa.

More efficient conversion method can be developed that keeps transparency and other effects specific to a file format, but that is beyong my knowledge. But depending on your needs, that might be sufficient.