在将图像绘制到屏幕分辨率之外的坐标时,我们遇到了 TMetaFileCanvas 输出问题。矢量操作似乎没有问题,但图像操作只是“忽略”。如果我们将相同的图像绘制到屏幕边界内的坐标上,那么就没有问题了。
例如。此 SSCCE 将生成 4 个输出文件。位图变体没有问题,并且将按预期输出,左上角为inscreen.bmp
红色方块,右下角为红色方块outsidescreen.bmp
。元文件按预期工作,inscreen.emf
左上角绘制了红色方块。outsidescreen.emf
不起作用,只画线。
program Project6;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Types,
Windows,
Vcl.Graphics;
const
SIZECONST = 3000; // should be larger than your screen resolution
OFFSET = 1500;
function GetMyMetafile(const aHDC: HDC): TMetafile;
var
metcnv: TMetafileCanvas;
begin
Result := TMetafile.Create;
Result.SetSize(500, 500);
metcnv := TMetafileCanvas.Create(Result, aHDC);
metcnv.Brush.Color := clRed;
metcnv.FillRect(Rect(0, 0, 500, 500));
metcnv.Free;
end;
procedure OutputToMetaFile(const aFilename: string; const aStartOffset,
aEndOffset, aMaxSize: Integer; aGraphic: TGraphic; aHDC: HDC);
var
metafile: TMetafile;
metcnv: TMetafileCanvas;
begin
metafile := TMetafile.Create;
try
metafile.SetSize(aMaxSize, aMaxSize);
metcnv := TMetafileCanvas.Create(metafile, aHDC);
try
// draw it somewhere offscreen
metcnv.StretchDraw(Rect(aStartOffset, aStartOffset, aEndOffset, aEndOffset), aGraphic);
metcnv.MoveTo(aStartOffset, aStartOffset);
metcnv.LineTo(aEndOffset, aEndOffset);
finally
metcnv.Free;
end;
metafile.SaveToFile(aFilename);
finally
metafile.Free;
end;
end;
procedure OutputToBitmap(const aFilename: string; const aStartOffset,
aEndOffset, aMaxSize: Integer; aGraphic: TGraphic);
var
bmp: TBitmap;
begin
bmp := TBitmap.Create;
try
bmp.SetSize(aMaxSize, aMaxSize);
bmp.Canvas.StretchDraw(Rect(aStartOffset, aStartOffset, aEndOffset, aEndOffset), aGraphic);
bmp.Canvas.MoveTo(aStartOffset, aStartOffset);
bmp.Canvas.LineTo(aEndOffset, aEndOffset);
bmp.SaveToFile(aFilename);
finally
bmp.Free;
end;
end;
var
mygraph: TMetafile;
bigBitmap: TBitmap;
begin
bigBitmap := TBitmap.Create;
try
bigBitmap.PixelFormat := pf24bit;
Assert(bigBitmap.HandleType = bmDIB, 'Handle Type should be a DIB');
bigBitmap.Width := SIZECONST;
bigBitmap.Height := SIZECONST;
mygraph := GetMyMetafile(bigBitmap.Canvas.Handle);
OutputToMetaFile('inscreen.emf', 0, 1000, SIZECONST, mygraph, bigBitmap.Canvas.Handle);
OutputToMetaFile('outsidescreen.emf', OFFSET, SIZECONST-1, SIZECONST, mygraph, bigBitmap.Canvas.Handle);
// do the same using bitmap
OutputToBitmap('inscreen.bmp', 0, 1000, SIZECONST, mygraph);
OutputToBitmap('outsidescreen.bmp', OFFSET, SIZECONST-1, SIZECONST, mygraph);
finally
bigBitmap.Free;
mygraph.Free;
end;
end.
任何人都可以看到问题是什么,或者你知道解决这个问题的方法吗?
更新
当我最初问这个问题时,我应该包括这个。我们确实使用 HDC 对大位图进行了测试,并且出现了同样的问题。我已经更新了示例代码来演示这一点。
更新 2
不幸的是,即使在赏金之后,解决方案仍然难以捉摸。不会绘制屏幕大小之外的任何 BitBlt 操作。
这是当图像在屏幕坐标范围内时提取的 Metafile 操作:
R0001: [001] EMR_HEADER (s=108) {{ Bounds(500,500,18138,18129), Frame(0,0,105000,105000), ver(0x10000), size(688), recs(33), handles(2), pals(0), dev_pix(1080,1920), dev_mil(381,677), pixf_size(0), pixf_ofs(0), openGL(0) }}
R0002: [033] EMR_SAVEDC (s=8)
R0003: [115] EMR_SETLAYOUT (s=12) {iMode(0=<default>)}
R0004: [028] EMR_SETMETARGN (s=8)
R0005: [037] EMR_SELECTOBJECT (s=12) {Stock object: 0=OBJ_BRUSH.(BS_SOLID)}
R0006: [037] EMR_SELECTOBJECT (s=12) {Stock object: 7=OBJ_PEN.(PS_SOLID | COSMETIC)}
R0007: [037] EMR_SELECTOBJECT (s=12) {Stock object: 14=OBJ_FONT}
R0008: [025] EMR_SETBKCOLOR (s=12) {0x00FFFFFF}
R0009: [024] EMR_SETTEXTCOLOR (s=12) {0x00000000}
R0010: [018] EMR_SETBKMODE (s=12) {iMode(2=OPAQUE)}
R0011: [019] EMR_SETPOLYFILLMODE (s=12) {iMode(1=ALTERNATE)}
R0012: [020] EMR_SETROP2 (s=12) {iMode(13=R2_COPYPEN)}
R0013: [021] EMR_SETSTRETCHBLTMODE (s=12) {iMode(1=BLACKONWHITE)}
R0014: [022] EMR_SETTEXTALIGN (s=12) {iMode(0= TA_LEFT TA_TOP)}
R0015: [013] EMR_SETBRUSHORGEX (s=16) {ptlOrigin(0,0)}
R0016: [058] EMR_SETMITERLIMIT (s=12) {Limit:0.000}
R0017: [027] EMR_MOVETOEX (s=16) { ptl(0,0)}
R0018: [035] EMR_SETWORLDTRANSFORM (s=32) {xform(eDx:500.000000, eDy:500.000000, eM11:5.039683, eM12:0.000000, eM21:0.000000, eM22:5.037203)}
R0019: [036] EMR_MODIFYWORLDTRANSFORM (s=36) {iMode(4=MWT_??), xform(eDx:500.000000, eDy:500.000000, eM11:5.039683, eM12:0.000000, eM21:0.000000, eM22:5.037203)}
R0020: [115] EMR_SETLAYOUT (s=12) {iMode(0=<default>)}
R0021: [070] EMR_GDICOMMENT (s=40) {GDI.Begin Group}
R0022: [039] EMR_CREATEBRUSHINDIRECT (s=24) {ihBrush(1), style(0=BS_SOLID, color:0x000000FF)}
R0023: [037] EMR_SELECTOBJECT (s=12) {Table object: 1=OBJ_BRUSH.(BS_SOLID)}
R0024: [037] EMR_SELECTOBJECT (s=12) {Table object: 1=OBJ_BRUSH.(BS_SOLID)}
R0025: [076] EMR_BITBLT (s=100) {rclBounds(500,500,18138,18129), Dest[x:0, y:0, cx:3500, cy:3500)], dwRop(0x00F00021), Src[x:0, y:0, xform(eDx:0.000000, eDy:0.000000, eM11:1.000000, eM12:0.000000, eM21:0.000000, eM22:1.000000), BkColor:0x00000000, iUsage:0, offBmi:0, Bmi:0, offBits:0, Bits:0]}
R0026: [037] EMR_SELECTOBJECT (s=12) {Table object: 1=OBJ_BRUSH.(BS_SOLID)}
R0027: [037] EMR_SELECTOBJECT (s=12) {Stock object: 0=OBJ_BRUSH.(BS_SOLID)}
R0028: [040] EMR_DELETEOBJECT (s=12) {ihObject(1)}
R0029: [070] EMR_GDICOMMENT (s=20) {GDI.End Group}
R0030: [034] EMR_RESTOREDC (s=12) {iRelative(-1)}
R0031: [027] EMR_MOVETOEX (s=16) { ptl(500,500)}
R0032: [054] EMR_LINETO (s=16) { ptl(1000,1000)}
R0033: [014] EMR_EOF (s=20) {nPalEntries:0, offPalEntries:16, nSizeLast:20}
以下是当图像超出屏幕坐标范围时的 Metafile 操作的提取:
R0001: [001] EMR_HEADER (s=108) {{ Bounds(1500,1500,2999,2999), Frame(0,0,105000,105000), ver(0x10000), size(588), recs(32), handles(2), pals(0), dev_pix(1080,1920), dev_mil(381,677), pixf_size(0), pixf_ofs(0), openGL(0) }}
R0002: [033] EMR_SAVEDC (s=8)
R0003: [115] EMR_SETLAYOUT (s=12) {iMode(0=<default>)}
R0004: [028] EMR_SETMETARGN (s=8)
R0005: [037] EMR_SELECTOBJECT (s=12) {Stock object: 0=OBJ_BRUSH.(BS_SOLID)}
R0006: [037] EMR_SELECTOBJECT (s=12) {Stock object: 7=OBJ_PEN.(PS_SOLID | COSMETIC)}
R0007: [037] EMR_SELECTOBJECT (s=12) {Stock object: 14=OBJ_FONT}
R0008: [025] EMR_SETBKCOLOR (s=12) {0x00FFFFFF}
R0009: [024] EMR_SETTEXTCOLOR (s=12) {0x00000000}
R0010: [018] EMR_SETBKMODE (s=12) {iMode(2=OPAQUE)}
R0011: [019] EMR_SETPOLYFILLMODE (s=12) {iMode(1=ALTERNATE)}
R0012: [020] EMR_SETROP2 (s=12) {iMode(13=R2_COPYPEN)}
R0013: [021] EMR_SETSTRETCHBLTMODE (s=12) {iMode(1=BLACKONWHITE)}
R0014: [022] EMR_SETTEXTALIGN (s=12) {iMode(0= TA_LEFT TA_TOP)}
R0015: [013] EMR_SETBRUSHORGEX (s=16) {ptlOrigin(0,0)}
R0016: [058] EMR_SETMITERLIMIT (s=12) {Limit:0.000}
R0017: [027] EMR_MOVETOEX (s=16) { ptl(0,0)}
R0018: [035] EMR_SETWORLDTRANSFORM (s=32) {xform(eDx:1500.000000, eDy:1500.000000, eM11:15.108969, eM12:0.000000, eM21:0.000000, eM22:15.101533)}
R0019: [036] EMR_MODIFYWORLDTRANSFORM (s=36) {iMode(4=MWT_??), xform(eDx:1500.000000, eDy:1500.000000, eM11:15.108969, eM12:0.000000, eM21:0.000000, eM22:15.101533)}
R0020: [115] EMR_SETLAYOUT (s=12) {iMode(0=<default>)}
R0021: [070] EMR_GDICOMMENT (s=40) {GDI.Begin Group}
R0022: [039] EMR_CREATEBRUSHINDIRECT (s=24) {ihBrush(1), style(0=BS_SOLID, color:0x000000FF)}
R0023: [037] EMR_SELECTOBJECT (s=12) {Table object: 1=OBJ_BRUSH.(BS_SOLID)}
R0024: [037] EMR_SELECTOBJECT (s=12) {Table object: 1=OBJ_BRUSH.(BS_SOLID)}
R0025: [037] EMR_SELECTOBJECT (s=12) {Table object: 1=OBJ_BRUSH.(BS_SOLID)}
R0026: [037] EMR_SELECTOBJECT (s=12) {Stock object: 0=OBJ_BRUSH.(BS_SOLID)}
R0027: [040] EMR_DELETEOBJECT (s=12) {ihObject(1)}
R0028: [070] EMR_GDICOMMENT (s=20) {GDI.End Group}
R0029: [034] EMR_RESTOREDC (s=12) {iRelative(-1)}
R0030: [027] EMR_MOVETOEX (s=16) { ptl(1500,1500)}
R0031: [054] EMR_LINETO (s=16) { ptl(2999,2999)}
R0032: [014] EMR_EOF (s=20) {nPalEntries:0, offPalEntries:16, nSizeLast:20}
您可以非常清楚地看到 BilBlt 操作(第一个中的 R0025)丢失了。