How to access metafile records ?

Please discuss general Delphi programming topics here.

How to access metafile records ?

Postby P_G » October 14th, 2004, 1:22 pm

Hello,

Has anyone a code example for accessing the data of a metafiles records? I need to get the drawing operation (polyline, circle etc.) and the coordinates of each record of a given metafile. I think I have to enumerate through the records with enumenhmetafile but I don't know how to get the code working and how to get the data. :(
Any ideas or examples would be appreciated.

Thanks, P_G
P_G
Senior Member
Senior Member
 
Posts: 51
Joined: June 14th, 2004, 11:13 am
Location: Germany

How to access the records of a metafile

Postby P_G » October 15th, 2004, 9:36 am

No ideas? Anyone? :shock:
P_G
Senior Member
Senior Member
 
Posts: 51
Joined: June 14th, 2004, 11:13 am
Location: Germany

Postby Stefan » October 15th, 2004, 1:12 pm

Something like this should work:

function EnumEnhFunc(DC: HDC; lpHTable: PHandleTable; lpEMFR:
PEnhMetaRecord; nObj: Integer; lpData: LPARAM): BOOL; stdcall;
begin
case lpEMFR^.iType of
EMR_HEADER: Form1.Memo1.Lines.Add('EMR_HEADER:');
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
hEmf: HENHMETAFILE;
rect: TRect;
MetaFile: TMetaFile;
begin
MetaFile := TMetaFile.Create;
MetaFile.LoadFromFile('C:\sample.emf');
rect.Left := 0;
rect.Top := 0;
rect.Right := MetaFile.MMWidth;
rect.Bottom := MetaFile.MMHeight;
EnumEnhMetaFile(nil, MetaFile.Handle, @EnumEnhFunc, nil, rect)
end;
User avatar
Stefan
Moderator
Moderator
 
Posts: 128
Joined: September 27th, 2004, 9:40 am
Location: Tilburg, The Netherlands

Metafile records

Postby P_G » October 18th, 2004, 11:43 am

Thank you, Stefan

I think I understand the basic concept of EnumEnhMetafile now.
But I'm still struggling with the EnumEnhFunc function of yours.
I changed the line to
EMR_HEADER: Form1.Memo1.Lines.Add(IntToStr(EMR_HEADER));
because EMR_HEADER: Form1.Memo1.Lines.Add('EMR_HEADER:');
delivers a string of course (EMR_HEADER:).
By the way - The result is always 1.
So I still don't know how to extract the drawing instruction and the coordinates of each record. :?:

P_G
P_G
Senior Member
Senior Member
 
Posts: 51
Joined: June 14th, 2004, 11:13 am
Location: Germany

Postby Stefan » October 18th, 2004, 3:16 pm

P_G,

Have a look at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/metafile_5hkj.asp

for an overview of all possible metafile records and how to parse them...

Cheers,
Stefan
User avatar
Stefan
Moderator
Moderator
 
Posts: 128
Joined: September 27th, 2004, 9:40 am
Location: Tilburg, The Netherlands

Metafile records

Postby P_G » October 19th, 2004, 10:35 am

Thanks, Stefan

That's exactly what I was looking for.

P_G
P_G
Senior Member
Senior Member
 
Posts: 51
Joined: June 14th, 2004, 11:13 am
Location: Germany

Postby P_G » October 25th, 2004, 10:16 am

Well, sorry, it's me again...

This code of mine is a little tricky. Now I'm able to access the metafile records and load their values into an array of record. I can get the drawing operation of each record (in the example below I only implemented the Polyline16 but it works fine). But the cpts (size of TPoint array) and the apts (array of TPoint) of each metafile record deliver absolutely wrong values.
Any ideas? This really drives me crazy ... :(

Code: Select all
type TSignChunk = record
 SignOp : string[5];
 Data   : Array of TPoint;
end;

var
  Form1: TForm1;
  SignChunk: TSignChunk;
  SignArray: Array of TSignChunk;

implementation

{$R *.dfm}

function MyEnhMetafileProc(DC: HDC; lpHTable: PHandleTable; lpEMFR: pEnhMetaRecord; nObj: Integer; TheForm:TForm1):Integer; stdcall;
var p: PEMRPolyline16;
 rec: TENHMetaRecord;
 i: Integer;
 nb: Integer;
begin
 PlayEnhMetafileRecord(dc, lpHTable^, lpEMFR^,nObj);
case lpEMFR^.iType of
 EMR_Polyline16 : begin
                   p := PEMRPolyLine16(@rec);
                   nb := p.cpts;
                   SetLength(SignArray, Length(SignArray) + 1);
                   SignArray[High(SignArray)].SignOp := 'Pl';
                   SetLength(SignArray[High(SignArray)].Data, nb);
                   For I := 0 to nb -1 do
                    begin
                     SignArray[High(SignArray)].Data[I] := Point(p.apts[I].X, p.apts[I].y);
                    end;
                  end;
 end;
 result := 1;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
MyMetafile: TMetafile;
begin
 MyMetafile := TMetafile.Create;
 MyMetafile.LoadFromFile('sample.emf');
 SignArray := nil;
 EnumEnhMetafile(Canvas.Handle, MyMetafile.Handle, @MyEnhMetafileProc, self, rect(0, 0, MyMetafile.Width,MyMetafile.Height));
 MyMetafile.Free;
end;
P_G
Senior Member
Senior Member
 
Posts: 51
Joined: June 14th, 2004, 11:13 am
Location: Germany

Postby Stefan » October 27th, 2004, 10:49 am

Hi,

The cpts does not seem to return the right ammount of points (and if it does it will surely overflow the maximum of your dynamic array)

try the following code:

Code: Select all
procedure DrawPolyline16 (var rec: TEnhMetaRecord; dc: HDC);
var
    p: PEMRPolyline16;
    i: integer;
    ar: array of TPoint;
begin
    p := PEMRPolyline16(@rec);
    SetLength(ar, Length(p.apts));
    for i := 0 to Length(p.apts)-1 do
      ar[i] := Point(p.apts[i].y, p.apts[i].x);
    polyline(dc, ar, Length(ar)-1);
end;


function MyEnhMetafileProc(DC: HDC; lpHTable: PHandleTable; lpEMFR: pEnhMetaRecord; nObj: Integer; TheForm:TForm1):Integer; stdcall;
var
  p: PEMRPolyline16;
  rec: TENHMetaRecord;
  i: Integer;
  nb: Integer;
begin
  PlayEnhMetafileRecord(dc, lpHTable^, lpEMFR^,nObj);
  case lpEMFR^.iType of
    EMR_Polyline16 : DrawPolyline16(rec, dc);
  end;
  result := 1;
end;
User avatar
Stefan
Moderator
Moderator
 
Posts: 128
Joined: September 27th, 2004, 9:40 am
Location: Tilburg, The Netherlands

This drives me nuts ...

Postby P_G » October 28th, 2004, 9:16 am

Stefan wrote:The cpts does not seem to return the right ammount of points (and if it does it will surely overflow the maximum of your dynamic array)


You're absolutely right, Stefan (I noticed this problem a couple of days ago too). But not only cpts doesn't return the correct number of points,
Code: Select all
Length(p.apts)
returns always 1 (!). Even if I use something like 20 or so for the iteration of apts, the returned coordinates are absolutely wrong.
It seems as if Microsoft did not document the metafile in a proper way, I'm afraid.
I send you a metafile, but I checked this code with several metafiles as well, and the problem occurs with any of them.
Thank you so far for your interest in this problem and your time of course.

P_G
P_G
Senior Member
Senior Member
 
Posts: 51
Joined: June 14th, 2004, 11:13 am
Location: Germany

Attachment

Postby P_G » October 28th, 2004, 9:25 am

I hope the attachment works this time...
P_G
Senior Member
Senior Member
 
Posts: 51
Joined: June 14th, 2004, 11:13 am
Location: Germany

nuts? I love nuts!

Postby Stefan » October 28th, 2004, 9:41 am

P_G,

I've tried to draw your emf to canvas and it works perfectly (see attachment)....?
User avatar
Stefan
Moderator
Moderator
 
Posts: 128
Joined: September 27th, 2004, 9:40 am
Location: Tilburg, The Netherlands

Postby Kambiz » October 28th, 2004, 2:01 pm

Stefan,

Please change your code as follow to see whether it is working.

Code: Select all
function MyEnhMetafileProc(DC: HDC; lpHTable: PHandleTable; lpEMFR: pEnhMetaRecord; nObj: Integer; TheForm:TForm1):Integer; stdcall;
var
  p: PEMRPolyline16;
  rec: TENHMetaRecord;
  i: Integer;
  nb: Integer;
begin
  case lpEMFR^.iType of
    EMR_Polyline16 : DrawPolyline16(rec, dc);
  else
    PlayEnhMetafileRecord(dc, lpHTable^, lpEMFR^,nObj);
  end;
  result := 1;
end;


It's PlayEnhMetafileRecord that draws the polyline not your function. :wink:
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm

Postby Kambiz » October 28th, 2004, 2:24 pm

Do you know what? None of you has initialized the rec variable at your codes. :lol:

Code: Select all
procedure DrawPolyline16 (const rec: TEnhMetaRecord; dc: HDC);
var
  Count: Integer;
  Pt: PSmallPoint;
begin
  with PEMRPolyline16(@Rec)^ do
  begin
    Count := cpts - 1;
    Pt := @apts[0];
  end;
  MoveToEx(dc, Pt.x, Pt.y, nil);
  while Count > 0 do
  begin
    Inc(Pt);
    Dec(Count);
    LineTo(dc, Pt.x, Pt.y);
  end;
end;


function MyEnhMetafileProc(DC: HDC; lpHTable: PHandleTable; lpEMFR: pEnhMetaRecord; nObj: Integer; TheForm:TForm1):Integer; stdcall;
begin
  case lpEMFR^.iType of
    EMR_Polyline16 : DrawPolyline16(lpEMFR^, dc);
  else
    PlayEnhMetafileRecord(dc, lpHTable^, lpEMFR^,nObj);
  end;
  result := 1;
end;
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm

Postby Stefan » October 28th, 2004, 3:39 pm

good to still have you around Kambiz :)
User avatar
Stefan
Moderator
Moderator
 
Posts: 128
Joined: September 27th, 2004, 9:40 am
Location: Tilburg, The Netherlands

Postby P_G » October 29th, 2004, 7:16 pm

Uhmm ... Yes ... That's it.
How could I ever doubt in a microsoft documentation ? :wink:
This code works perfectly.
Thanks a lot Kambiz and Stefan. You guys are lifesavers. I already had my own tombstone in mind: Died in the attempt to access metafile records...

P_G
P_G
Senior Member
Senior Member
 
Posts: 51
Joined: June 14th, 2004, 11:13 am
Location: Germany

Next

Return to Delphi Programming

Who is online

Users browsing this forum: No registered users and 3 guests

cron