Transformation de metafile Windows (rotation, miroir, inversion)
Date de publication : 26/02/2005
Par
Pierre Castelain (Contributions)
Routine Delphi de transformation d'un metafile Windows (image au format vectoriel)
Voici une unité contenant une procédure de transformation d'un metafichier Windows.
Les metafichiers (wmf ou emf) sont des fichiers images contenant la description
vectorielle d'un dessin. Ils ont l'avantage de pouvoir être redimensionnés sans
perte de qualité. Par contre, leur modification en mémoire est assez fastidieuse.
Le source suivant vous permet d'appliquer plusieurs transformations à un de ces
fichiers en mémoire : rotation (dans le sens inverse des aiguilles d'une montre,
inversion (haut-bas) et miroir (droite-gauche).
Pour l'utiliser, passez le handle d'un TMetafile à la procédure en indiquant les
transformations désirées.
Ce code source n'est pas parfait car la transformation de certains ordres GDI n'est pas
supportée. Par exemple, si le metafile contient du texte, celui-ci ne subira pas les
transformations.
GDI+ vous permet d'appliquer des transformations beaucoup plus évoluées lors du tracé. Vous êtes
encouragés à l'utiliser, mais si pour une raison quelconque cela n'est pas possible, vous pouvez
utiliser cette unité.
unit EMFTransform;
interface
uses
Classes, Windows;
procedure TransformEMF(emf: HENHMETAFILE; DoRotate, DoFlip, DoMirror: boolean);
implementation
uses
SysUtils, Dialogs;
var
centerl: TPoint;
Rotate, Flip, Mirror: boolean;
function SmallPoint(x, y: SHORT): TSmallPoint;
begin
Result.x:= x;
Result.y:= y;
end;
function RectCenter(rec: TRect): TPoint;
begin
result:= Point((rec.Left + rec.Right) div 2, (rec.Top + rec.Bottom) div 2);
end;
procedure InvertHVRect(var rec: TRect);
var
tmp: LongInt;
begin
tmp:= rec.Left;
rec.Left:= rec.Top;
rec.Top:= tmp;
tmp:= rec.Right;
rec.Right:= rec.Bottom;
rec.Bottom:= tmp;
end;
procedure InvertHVPoint(var pt: TPoint);
var
tmp: LongInt;
begin
tmp:= pt.X;
pt.X:= pt.Y;
pt.Y:= tmp;
end;
procedure RotatePoint(var pt: TPoint; center: TPoint);
begin
pt:= Point(pt.Y, 2*center.X - pt.X);
end;
procedure FlipPoint(var pt: TPoint; center: TPoint);
begin
pt:= Point(pt.X, 2*center.Y - pt.Y);
end;
procedure MirrorPoint(var pt: TPoint; center: TPoint);
begin
pt:= Point(2*center.X - pt.X, pt.Y);
end;
procedure RotateSmallPoint(var pt: TSmallPoint; center: TPoint);
begin
pt:= SmallPoint(pt.Y, 2*center.X - pt.X);
end;
procedure FlipSmallPoint(var pt: TSmallPoint; center: TPoint);
begin
pt:= SmallPoint(pt.X, 2*center.Y - pt.Y);
end;
procedure MirrorSmallPoint(var pt: TSmallPoint; center: TPoint);
begin
pt:= SmallPoint(2*center.X - pt.X, pt.Y);
end;
procedure RotateRect(var r: TRect; center: TPoint);
var
p2, p4: TPoint;
begin
p2:= Point(r.Right, r.Top);
p4:= Point(r.Left, r.Bottom);
RotatePoint(p2, Center);
RotatePoint(p4, Center);
r:= Rect(p2.X, p2.Y, p4.X, p4.Y);
end;
procedure FlipRect(var r: TRect; center: TPoint);
var
p1, p2: TPoint;
begin
p1:= r.TopLeft;
p2:= r.BottomRight;
FlipPoint(p1, center);
FlipPoint(p2, center);
r.Top:= p2.Y;
r.Bottom:= p1.Y;
end;
procedure MirrorRect(var r: TRect; center: TPoint);
var
p1, p2: TPoint;
begin
p1:= r.TopLeft;
p2:= r.BottomRight;
MirrorPoint(p1, center);
MirrorPoint(p2, center);
r.Left:= p2.X;
r.Right:= p1.X;
end;
procedure RotateSize(var sz: TSize);
var
tmpl: LongInt;
begin
tmpl:= sz.cx;
sz.cx:= sz.cy;
sz.cy:= tmpl;
end;
function EnhMetaFileProc_Manipulate(DC: HDC; lpHTable: PHandleTable; lpEMFR: PENHMetaRecord; nObj: integer; lpData: LPARAM): integer; stdcall;
var
i: integer;
begin
Result:= 1;
case lpEMFR^.iType of
EMR_HEADER:
with PEnhMetaHeader(lpEMFR)^ do
begin
if Rotate then
begin
InvertHVRect(PEnhMetaHeader(lpEMFR)^.rclBounds);
InvertHVRect(PEnhMetaHeader(lpEMFR)^.rclFrame);
RotateSize(PEnhMetaHeader(lpEMFR)^.szlDevice);
RotateSize(PEnhMetaHeader(lpEMFR)^.szlMillimeters);
end;
end;
EMR_LINETO, EMR_MOVETOEX:
begin
if Rotate then
RotatePoint(PEMRLineTo(lpEMFR)^.ptl, centerl);
if Flip then
FlipPoint(PEMRLineTo(lpEMFR)^.ptl, centerl);
if Mirror then
MirrorPoint(PEMRLineTo(lpEMFR)^.ptl, centerl);
end;
EMR_OFFSETCLIPRGN:
begin
if Rotate then
RotatePoint(PEMROffsetClipRgn(lpEMFR)^.ptlOffset, centerl);
if Flip then
FlipPoint(PEMROffsetClipRgn(lpEMFR)^.ptlOffset, centerl);
if Mirror then
MirrorPoint(PEMROffsetClipRgn(lpEMFR)^.ptlOffset, centerl);
end;
EMR_FILLPATH, EMR_STROKEANDFILLPATH, EMR_STROKEPATH:
begin
if Rotate then
RotateRect(PEMRFillPath(lpEMFR)^.rclBounds, centerl);
if Flip then
FlipRect(PEMRFillPath(lpEMFR)^.rclBounds, centerl);
if Mirror then
MirrorRect(PEMRFillPath(lpEMFR)^.rclBounds, centerl);
end;
EMR_EXCLUDECLIPRECT, EMR_INTERSECTCLIPRECT:
begin
if Rotate then
RotateRect(PEMRExcludeClipRect(lpEMFR)^.rclClip, centerl);
if Flip then
FlipRect(PEMRExcludeClipRect(lpEMFR)^.rclClip, centerl);
if Mirror then
MirrorRect(PEMRExcludeClipRect(lpEMFR)^.rclClip, centerl);
end;
EMR_SETWINDOWORGEX:
with PEMRSetViewportOrgEx(lpEMFR)^ do
begin
end;
EMR_SETVIEWPORTORGEX, EMR_SETBRUSHORGEX:
with PEMRSetViewportOrgEx(lpEMFR)^ do
begin
end;
EMR_SETVIEWPORTEXTEX, EMR_SETWINDOWEXTEX:
begin
end;
EMR_SETPIXELV:
begin
if Rotate then
RotatePoint(PEMRSetPixelV(lpEMFR)^.ptlPixel, centerl);
if Flip then
FlipPoint(PEMRSetPixelV(lpEMFR)^.ptlPixel, centerl);
if Mirror then
MirrorPoint(PEMRSetPixelV(lpEMFR)^.ptlPixel, centerl);
end;
EMR_EXTFLOODFILL:
begin
if Rotate then
RotatePoint(PEMRExtFloodFill(lpEMFR)^.ptlStart, centerl);
if Flip then
FlipPoint(PEMRExtFloodFill(lpEMFR)^.ptlStart, centerl);
if Mirror then
MirrorPoint(PEMRExtFloodFill(lpEMFR)^.ptlStart, centerl);
end;
EMR_ELLIPSE, EMR_RECTANGLE:
begin
if Rotate then
RotateRect(PEMREllipse(lpEMFR)^.rclBox, centerl);
if Flip then
FlipRect(PEMREllipse(lpEMFR)^.rclBox, centerl);
if Mirror then
MirrorRect(PEMREllipse(lpEMFR)^.rclBox, centerl);
end;
EMR_ROUNDRECT:
begin
if Rotate then
begin
RotateRect(PEMRRoundRect(lpEMFR)^.rclBox, centerl);
RotateSize(PEMRRoundRect(lpEMFR)^.szlCorner);
end;
if Flip then
FlipRect(PEMRRoundRect(lpEMFR)^.rclBox, centerl);
if Mirror then
MirrorRect(PEMRRoundRect(lpEMFR)^.rclBox, centerl);
end;
EMR_ARC, EMR_ARCTO, EMR_CHORD, EMR_PIE:
begin
if Rotate then
begin
RotateRect(PEMRArc(lpEMFR)^.rclBox, centerl);
RotatePoint(PEMRArc(lpEMFR)^.ptlStart, centerl);
RotatePoint(PEMRArc(lpEMFR)^.ptlEnd, centerl);
end;
if Flip then
begin
FlipRect(PEMRArc(lpEMFR)^.rclBox, centerl);
FlipPoint(PEMRArc(lpEMFR)^.ptlStart, centerl);
FlipPoint(PEMRArc(lpEMFR)^.ptlEnd, centerl);
end;
if Mirror then
begin
MirrorRect(PEMRArc(lpEMFR)^.rclBox, centerl);
MirrorPoint(PEMRArc(lpEMFR)^.ptlStart, centerl);
MirrorPoint(PEMRArc(lpEMFR)^.ptlEnd, centerl);
end;
end;
EMR_ANGLEARC:
begin
if Rotate then
RotatePoint(PEMRAngleArc(lpEMFR)^.ptlcenter, centerl);
if Flip then
FlipPoint(PEMRAngleArc(lpEMFR)^.ptlcenter, centerl);
if Mirror then
MirrorPoint(PEMRAngleArc(lpEMFR)^.ptlcenter, centerl);
end;
EMR_POLYLINE, EMR_POLYBEZIER, EMR_POLYGON, EMR_POLYBEZIERTO, EMR_POLYLINETO:
begin
if Rotate then
RotateRect(PEMRPolyline(lpEMFR)^.rclBounds, centerl);
if Flip then
FlipRect(PEMRPolyline(lpEMFR)^.rclBounds, centerl);
if Mirror then
MirrorRect(PEMRPolyline(lpEMFR)^.rclBounds, centerl);
for i:=0 to PEMRPolyline(lpEMFR)^.cptl-1 do
begin
if Rotate then
RotatePoint(PEMRPolyline(lpEMFR)^.aptl[i], Centerl);
if Flip then
FlipPoint(PEMRPolyline(lpEMFR)^.aptl[i], Centerl);
if Mirror then
MirrorPoint(PEMRPolyline(lpEMFR)^.aptl[i], Centerl);
end;
end;
EMR_POLYLINE16, EMR_POLYBEZIER16, EMR_POLYGON16, EMR_POLYBEZIERTO16, EMR_POLYLINETO16:
begin
if Rotate then
RotateRect(PEMRPolyline16(lpEMFR)^.rclBounds, centerl);
if Flip then
FlipRect(PEMRPolyline16(lpEMFR)^.rclBounds, centerl);
if Mirror then
MirrorRect(PEMRPolyline16(lpEMFR)^.rclBounds, centerl);
for i:=0 to PEMRPolyline16(lpEMFR)^.cpts-1 do
begin
if Rotate then
RotateSmallPoint(PEMRPolyline16(lpEMFR)^.apts[i], Centerl);
if Flip then
FlipSmallPoint(PEMRPolyline16(lpEMFR)^.apts[i], Centerl);
if Mirror then
MirrorSmallPoint(PEMRPolyline16(lpEMFR)^.apts[i], Centerl);
end;
end;
EMR_POLYDRAW:
begin
if Rotate then
RotateRect(PEMRPolyDraw(lpEMFR)^.rclBounds, centerl);
if Flip then
FlipRect(PEMRPolyDraw(lpEMFR)^.rclBounds, centerl);
if Mirror then
MirrorRect(PEMRPolyDraw(lpEMFR)^.rclBounds, centerl);
for i:=0 to PEMRPolyDraw(lpEMFR)^.cptl-1 do
begin
if Rotate then
RotatePoint(PEMRPolyDraw(lpEMFR)^.aptl[i], Centerl);
if Flip then
FlipPoint(PEMRPolyDraw(lpEMFR)^.aptl[i], Centerl);
if Mirror then
MirrorPoint(PEMRPolyDraw(lpEMFR)^.aptl[i], Centerl);
end;
end;
EMR_POLYDRAW16:
begin
if Rotate then
RotateRect(PEMRPolyDraw16(lpEMFR)^.rclBounds, centerl);
if Flip then
FlipRect(PEMRPolyDraw16(lpEMFR)^.rclBounds, centerl);
if Mirror then
MirrorRect(PEMRPolyDraw16(lpEMFR)^.rclBounds, centerl);
for i:=0 to PEMRPolyDraw16(lpEMFR)^.cpts-1 do
begin
if Rotate then
RotateSmallPoint(PEMRPolyDraw16(lpEMFR)^.apts[i], Centerl);
if Flip then
FlipSmallPoint(PEMRPolyDraw16(lpEMFR)^.apts[i], Centerl);
if Mirror then
MirrorSmallPoint(PEMRPolyDraw16(lpEMFR)^.apts[i], Centerl);
end;
end;
EMR_POLYPOLYLINE, EMR_POLYPOLYGON:
begin
if Rotate then
RotateRect(PEMRPolyPolyLine(lpEMFR)^.rclBounds, centerl);
if Flip then
FlipRect(PEMRPolyPolyLine(lpEMFR)^.rclBounds, centerl);
if Mirror then
MirrorRect(PEMRPolyPolyLine(lpEMFR)^.rclBounds, centerl);
for i:=0 to PEMRPolyPolyLine(lpEMFR)^.cptl-1 do
begin
if Rotate then
RotatePoint(PEMRPolyPolyLine(lpEMFR)^.aptl[i], Centerl);
if Flip then
FlipPoint(PEMRPolyPolyLine(lpEMFR)^.aptl[i], Centerl);
if Mirror then
MirrorPoint(PEMRPolyPolyLine(lpEMFR)^.aptl[i], Centerl);
end;
end;
EMR_POLYPOLYLINE16, EMR_POLYPOLYGON16:
begin
if Rotate then
RotateRect(PEMRPolyPolyLine16(lpEMFR)^.rclBounds, centerl);
if Flip then
FlipRect(PEMRPolyPolyLine16(lpEMFR)^.rclBounds, centerl);
if Mirror then
MirrorRect(PEMRPolyPolyLine16(lpEMFR)^.rclBounds, centerl);
for i:=0 to PEMRPolyPolyLine16(lpEMFR)^.cpts-1 do
begin
if Rotate then
RotateSmallPoint(PEMRPolyPolyLine16(lpEMFR)^.apts[i], Centerl);
if Flip then
FlipSmallPoint(PEMRPolyPolyLine16(lpEMFR)^.apts[i], Centerl);
if Mirror then
MirrorSmallPoint(PEMRPolyPolyLine16(lpEMFR)^.apts[i], Centerl);
end;
end;
EMR_EXTSELECTCLIPRGN:
begin
end;
EMR_SCALEVIEWPORTEXTEX, EMR_SCALEWINDOWEXTEX, EMR_SETWORLDTRANSFORM,
EMR_MODIFYWORLDTRANSFORM, EMR_INVERTRGN, EMR_PAINTRGN, EMR_FILLRGN,
EMR_FRAMERGN, EMR_EXTTEXTOUTA, EMR_EXTTEXTOUTW,
EMR_POLYTEXTOUTA, EMR_POLYTEXTOUTW :
begin
end;
end;
end;
procedure TransformEMF(emf: HENHMETAFILE; DoRotate, DoFlip, DoMirror: boolean);
var
metaHeader: TEnhMetaHeader;
begin
Rotate:= DoRotate;
Flip:= DoFlip;
Mirror:= DoMirror;
GetEnhMetaFileHeader(emf, SizeOf(TEnhMetaHeader), @metaHeader);
with metaHeader do
centerl:= Point((rclBounds.Left + rclBounds.Right) div 2,
(rclBounds.Top + rclBounds.Bottom) div 2);
EnumEnhMetaFile(0, emf, @EnhMetaFileProc_Manipulate, nil, Rect(0, 0, 0, 0));
end;
end.
|