views:

292

answers:

2

I have an application that can load various graphical file formats such as bmp, jpg, png, emf, etc... and render them onto the screen for previewing.

I am using Delphi 7. I have just been introduced to the EMF+ file format that was created around the time of Windows XP that is created utilizing the GDIPlus.dll. I can open the EMF+ files with Windows Picture Viewer and the image is very high quaility and can zoom in and out without any blurring at all.

The problem is I can't seem to find a way (in Delphi 7) to open this file format and render it on the screen. Does anyone know of a code sample or component that can be used in Delphi 7 to render an EMF+ file?

+1  A: 

You can use a "TMetaFileCanvas" that has EMF support. A code snippet:

procedure TForm1.Button1Click(Sender: TObject);
var  
  MyMetaFile: TMetaFile;  
  MyCanvas: TMetafileCanvas;
begin
  MyMetaFile:= TMetaFile.Create;
  try
    MyMetaFile.LoadFromFile('C:\example.emf');

    MyCanvas:= TMetafileCanvas.Create(MyMetaFile, 0);
    try
      MyCanvas.Draw(0, 0, MyMetaFile);
      MyCanvas.Pen.Color:= clRed;
      MyCanvas.MoveTo(0, 0);
      MyCanvas.LineTo(100, 100);
      MyCanvas.Free;

      Image1.Canvas.Draw(0, 0, MyMetaFile);
    finally
      MyCanvas.Free;
    end;

    MyMetaFile.SaveToFile('C:\example.emf');
  finally
    MyMetaFile.Free;
  end;
end;

This way you can load EMF, draw to EMF and save it. But presenting it as a vector graphics from Delphi is another problem altogether. Delphi only works well with bitmap graphics out of the box. But as I understand you only want to read and draw it. To convert it to BMP for instance you can do:

// destroy canvas to transfer the image into the metafile object
FreeAndNil(MyCanvas);
// draw image as normal graphic
BMP.Canvas.Draw(0, 0, MyMetaFile);

EDIT:

As Marco kindly pointed out TMetaFileCanvas probably woun't work correctly with EMF+. Haven't tested that so I can't confirm it.

But there seems to be a unit that works with that.

http://blog.synopse.info/post/2010/04/02/Antialiased-drawing-from-TMetaFile

Download is available from:

http://synopse.info/files/SynGdiPlus.zip

Havent checked it out myself, but it looks appropriate for the job.

Runner
That's plain old EMF, are you sure it also does EMF+ ?Afaik Delphi has no GDIplus components in the stock distro
Marco van de Voort
Hm, nope I am not sure :)
Runner
Updated the answer.
Runner
Im not sure but IGDI by Mitov Software might have emf+ supportIGDI is a free open source Delphi library:http://www.mitov.com/html/download_igdi_.html
Logman
A: 

TMetaFileCanvas won't work correctly with EMF+ but your task can be completed using GDI+.

Here's some sample code that demonstrates how to do it using GDI+:

type
  PGdiplusStartupInput = ^TGdiplusStartupInput;
  TGdiplusStartupInput = record
    GdiplusVersion: Integer;
    DebugEventCallback: Integer;
    SuppressBackgroundThread: Integer;
    SuppressExternalCodecs: Integer;
  end;

function GdiplusStartup(var Token: Integer; InputBuf: PGDIPlusStartupInput; OutputBuf: Integer): Integer; stdcall; external 'gdiplus.dll';
procedure GdiplusShutdown(Token: Integer); stdcall; external 'gdiplus.dll';
function GdipCreateFromHDC(DC: HDC; var Graphics: Integer): Integer; stdcall; external 'gdiplus.dll';
function GdipDeleteGraphics(Graphics: Integer): Integer; stdcall; external 'gdiplus.dll';
function GdipLoadImageFromFile(Filename: PWChar; var GpImage: Integer): Integer; stdcall; external 'gdiplus.dll';
function GdipDrawImageRect(Graphics, Image: Integer; X, Y, Width, Height: Single): Integer; stdcall; external 'gdiplus.dll';

procedure LoadEMFPlus(const FileName: WideString; DC: HDC; Width, Height: Integer);
var
  Token: Integer;
  StartupInput: TGdiplusStartupInput;
  Graphics: Integer;
  Image: Integer;
begin
  StartupInput.GdiplusVersion := 1;
  StartupInput.DebugEventCallback := 0;
  StartupInput.SuppressBackgroundThread := 0;
  StartupInput.SuppressExternalCodecs := 0;
  if GdiplusStartup(Token, @StartupInput, 0) = 0 then
  begin
    if GdipCreateFromHDC(DC, Graphics) = 0 then
    begin
      if GdipLoadImageFromFile(@FileName[1], Image) = 0 then
      begin
        GdipDrawImageRect(Graphics, Image, 0, 0, Width, Height);
      end;
      GdipDeleteGraphics(Graphics);
    end;
    GdiplusShutdown(Token);
  end;
end;

And you can call it like this:

procedure TForm1.Button1Click(Sender: TObject);
begin
  LoadEMFPlus('EMFTest.emf',
    PaintBox1.Canvas.Handle, PaintBox1.Width, PaintBox1.Height);
end;
Rowan