Duplicate a metafile without the fill color of the original (Views: 100)


I have a TMetafile that is created drawing to a TMetafileCanvas. There are various polygons that are drawn using a solid brush style and a grey fill color (red outline). Some of the time I would like to duplicate the metafile but have no fill color (ie just red outlines). But I want to keep it as a metafile and not have to regenerate the original with no fill. I've been looking into changing the palette color, but the metafile does not seem to have any palette entries. Anyone have any ideas?


Solve 1:

function unfilledMetafile(const in_metafile: TMetafile): TMetafile;
  metaHeaderSize: DWORD;
  metaHeader: PEnhMetaHeader;
  data: PByteArray;
  metaRec: PEMR;
  brushRec: PEMRCreateBrushIndirect;
  i: cardinal;
  {Debug, copy to clipboard
  MyFormat: Word;
  AData: Cardinal;
  APalette: HPALETTE; }
  {Get the header}
  metaHeaderSize := GetEnhMetaFileHeader(in_metafile.Handle, 0, nil);
  if (metaHeaderSize > 0) then
    GetMem(metaHeader, metaHeaderSize);
      GetEnhMetaFileHeader(in_metafile.Handle, metaHeaderSize, metaHeader);
      GetMem(data, metaHeader^.nBytes);
      ZeroMemory(data, metaHeader^.nBytes);
        GetEnhMetaFileBits(in_metafile.Handle, metaHeader^.nBytes, @(data^[0]));
        {Go through the metafile and update brushes to unfilled}
        i := metaHeaderSize;
        while (i < metaHeader^.nBytes) do
          {Get record info}
          metaRec := PEMR(@(data^[i]));
          if (metaRec^.itype = EMR_CREATEBRUSHINDIRECT) then
            brushRec := PEMRCreateBrushIndirect(metaRec);
            brushRec^.lb.lbStyle := BS_HOLLOW;
          Inc(i, metaRec^.nSize);
        {Put the data into a new metafile}
        Result := TMetafile.Create();
        Result.Handle := SetEnhMetaFileBits(metaHeader^.nBytes, PChar(data));
        FreeMem(data, metaHeader^.nBytes);
      FreeMem(metaHeader, metaHeaderSize);
    raise Exception.Create('Unable to create unfilled metafile');
  {Debug, copy to clipboard
  Result.SaveToClipboardFormat(MyFormat, AData, APalette);
  ClipBoard.SetAsHandle(MyFormat, AData); }

Solve 2:

The "callback" function:

function EnhMetaFileProc(DC: HDC; {handle to device context}
  lpHTable: PHANDLETABLE; {Pointer to metafile handle table}
  lpEMFR: PENHMETARECORD; {Pointer to metafile record}
  nObj: Integer; {Count of objects}
  aCanvas: TCanvas): Integer; stdcall;
  tmpPen, OldPen: HPen;
  tmpBrush, OldBrush: HBrush;
  aCanvas.Pen.Color := clBlack;
  tmpPen := aCanvas.Pen.Handle;
  aCanvas.Brush.Style := bsClear
    tmpBrush := aCanvas.Brush.Handle;
  OldPen := SelectObject(aCanvas.Handle, tmpPen);
  OldBrush := SelectObject(aCanvas.Handle, tmpBrush);
  {Draw the metafile record}
  PlayEnhMetaFileRecord(dc, lpHTable^, lpEMFR^, nObj);
  SelectObject(aCanvas.Handle, OldPen);
  SelectObject(aCanvas.Handle, OldBrush);
  {Set to zero to stop metafile enumeration}
  Result := 1;

And then, you draw it using EnumEnhMetafile with the callback:

EnumEnhMetaFile(Canvas.Handle, FWMFImage.Handle, @EnhMetaFileProc, Canvas, tmpRect);

<< Back to main page