我正在创建一些.wmf文件,但其中一些似乎已损坏,无法显示在任何图元文件查看器中.经过一番试错,我发现问题是由他们的尺寸造成的.如果我通过一个因素缩放相同的图形来减小尺寸,那么它将被显示出来.

现在,我想知道绘图的大小是否有限制,或者问题是其他的.我知道这些文件有一个16位的数据结构,所以我猜测每个维度的限制将是2 ^ 16个单位(如果签名则为2 ^ 15).但是在我的测试中,它是25,000左右.所以我不能依赖这个值,因为限制可以在任何东西(宽度*高度可能,或者也许绘图的分辨率可能会影响它).我找不到有关描述这个的.wmf文件的可靠资源.

以下是显示问题的示例代码:

procedure DrawWMF(const Rect: TRect; const Scale: Double; FileName: string);
var
  Metafile: TMetafile;
  Canvas: TMetafileCanvas;
  W,H: Integer;
begin
  W := Round(Rect.Width * Scale);
  H := Round(Rect.Height * Scale);

  Metafile := TMetafile.Create;
  Metafile.SetSize(W,H);

  Canvas := TMetafileCanvas.Create(Metafile,0);
  Canvas.Lineto(W,H);
  Canvas.Free;

  Metafile.SavetoFile(FileName);
  Metafile.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  Dim = 40000;
begin
  DrawWMF(Rect(0,Dim,Dim),1.0,'Original.wmf');
  DrawWMF(Rect(0,0.5,'Scaled.wmf');

  try
    Image1.Picture.LoadFromFile('Original.wmf');
  except
    Image1.Picture.Assign(nil);
  end;

  try
    Image2.Picture.LoadFromFile('Scaled.wmf');
  except
    Image2.Picture.Assign(nil);
  end;
end;

PS:我知道设置Metafile.Enhanced为True并将其保存为.emf文件将解决问题,但生成文件的目标应用程序不支持增强型图元文件.

编辑:
如下面的答案所述,这里有两个不同的问题:

主要问题是关于文件本身,它对每个维度都有一个2 ^ 15的限制.如果绘图的宽度或高度超过此值,则delphi会写入损坏的文件.您可以在Sertac’s answer找到更多的细节.

第二个问题是将文件加载到timage中.当您想在delphi VCL应用程序中显示图像时,还有另一个限制.这一个是系统依赖的,并且与图形将被绘制的DC的dpi相关. Tom’s answer详细描述.传递0.7作为缩放DrawWMF(上面的代码示例)在我的电脑上再现这种情况.生成的文件可以使用其他图元文件查看器(我使用MS Office Picture Manager)查看,但VCL无法显示,但在加载文件时不会出现异常.

解决方法

你的上限是32767.

跟踪VCL代码,输出文件在TMetafile.WriteWMFStream中被破坏. VCL写入一个WmfPlaceableFileHeader(TMetafileHeader在VCL)记录,然后调用GetWinMetaFileBits将’emf’记录转换为’wmf’记录.如果边界矩形(调用CreateEnhMetaFile时使用)的任何维度大于32767,则此函数将失败.不检查返回值,VCL不会引发任何异常,只关闭22个字节的文件 – 只有“可放置的头”.

即使尺寸小于32767,“可放置的标题”可能有错误的值(从Tom’s answer读取详细的原因和含义,并给出了答案),但更多的是在以后…

我使用下面的代码找到限制.请注意,GetWinMetaFileBits不会使用增强型图元文件在VCL代码中调用.

function IsDimOverLimit(W,H: Integer): Boolean;
var
  Metafile: TMetafile;
  RefDC: HDC;
begin
  Metafile := TMetafile.Create;
  Metafile.SetSize(W,H);
  RefDC := GetDC(0);
  TMetafileCanvas.Create(Metafile,RefDC).Free;
  Result := GetWinMetaFileBits(MetaFile.Handle,nil,MM_ANISOTROPIC,RefDC) > 0;
  ReleaseDC(0,RefDC);
  Metafile.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  for i := 20000 to 40000 do
    if not IsDimOverLimit(100,i) then begin
      ShowMessage(SysErrorMessage(GetLastError)); // ReleaseDc and freeing Meta file does not set any last error
      Break;
    end;
end;

错误是534(“算术结果超过32位”).显然有一些有符号的整数溢出.一些“mf3216.dll”(“32位到16位元文件转换DLL”)将GetWinMetaFileBits调用期间的错误设置为其导出的ConvertEmfToWmf函数,但不会导致任何有关溢出的文档.关于wmf限制的唯一官方文档是this(其主要内容是“仅在16位可执行文件中使用wmf”)).

如前所述,伪造的“可置换标题”结构可能具有“伪造”值,这可能会阻止VCL正确播放图元文件.具体来说,像VCL知道它们的元文件的维度可能会溢出.您可以在加载图像以便正确显示之后执行简单的理智检查:

var
  Header: TEnhMetaHeader;
begin
  DrawWMF(Rect(0,'Scaled.wmf');

  try
    Image1.Picture.LoadFromFile('Original.wmf');
    if (TMetafile(Image1.Picture.Graphic).Width < 0) or
        (TMetafile(Image1.Picture.Graphic).Height < 0) then begin
      GetEnhMetaFileHeader(TMetafile(Image1.Picture.Graphic).Handle,SizeOf(Header),@Header);
      TMetafile(Image1.Picture.Graphic).Width := MulDiv(Header.rclFrame.Right,Header.szlDevice.cx,Header.szlMillimeters.cx * 100);
      TMetafile(Image1.Picture.Graphic).Height := MulDiv(Header.rclFrame.Bottom,Header.szlDevice.cy,Header.szlMillimeters.cy * 100);
  end;

  ...

delphi – Windows图元文件的维度是否有限制?的更多相关文章

  1. ios – Swift – 如何获得视频维度?

    解决方法试试这个:希望能帮助到你

  2. ios – 我在哪里可以找到用于创建IPad应用程序的Delphi资源?

    我之前一直在使用Delphi并且一直都是Windows家伙.我的妻子为我的生日买了一台新的iPad,我昨晚第一次使用它.哇!…

  3. 如何从命令行部署OSX或IOS Delphi项目?

    我正在使用像这样的脚本构建我的Delphi应用程序现在我想添加一个选项将应用程序部署到OSX系统修改这样的脚本,那么可以从命令行部署OSX或IOSDelphi项目吗?

  4. android – 为什么带有“用户”范围级别的自定义维度未显示在我的报告中?

    解决方法您真的需要用户级范围吗?如果用户可以在会话期间切换他的角色类型,则用户级别维度将不会反映世界的任何状态.在使用维度扩展时,可能存在许多问题,这是一个清单:>配置>您正在使用通用分析吗?

  5. 如何检查Android和iOS上的网络是否可用(Delphi XE5)

    解决方法试试这个:

  6. Pytorch中expand()的使用(扩展某个维度)

    这篇文章主要介绍了Pytorch中expand()的使用(扩展某个维度),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. 使用嵌套线程错误终止应用程序

    如果我使用一个启动了嵌套线程的线程,那么终止应用程序时会遇到问题。如果最深的嵌套线程卡住,则应用程序终止时会发生错误。在其他情况下,问题不会出现。据我所知,tSync.Free不会等待TCP.Connect完成并自行关闭。TCP.Connection在超时结束后无处返回。

  8. 通过gsdll32.dll与Delphi 11组合PDF

    我已经使用这个代码10多年了,它突然停止工作。该程序读取一个pdf文件列表,并输出一个包含列表中所有文件的pdf文件。它使用gsapi.pas包装单元。多年来,我只需要从Ghostscript.t下载一个更新版本的gsdll32.dll文件,就可以兼容更新版本的pdf文件格式。我发现他们有了一个新的翻译,也许这与此有关?请注意,在Ghostscript中使用等效的命令行本身效果良好。在我看来,他们改变了调用API的方式。如果有任何帮助,我将不胜感激。我确实尝试了添加开关“-dNEWPDF=false”,但

  9. Windows 10中的内存泄漏Delphi Seattle中的TNotification?

    我正在我的应用程序中实现Windows10通知.但是,下面的代码显然会给出1个TNotification对象和2个字符串的备忘录泄漏,但我在块的末尾释放了对象:我做了一些愚蠢的事情,或者在通知的实施中是否存在内存泄漏?

  10. 如何处理Windows 7的125%或150%放大率(Delphi)

    Windows7已添加其控制面板,外观和个性化,显示设置,放大文本和其他项目125%或150%的功能.完成后,我的Delphi2009程序的表单和对话框的一些内容被切断.我需要做些哪些更改才能确保在Windows7的任何放大设置下,我的所有表单和对话框都能正常显示.这听起来像是指文本大小设置,它在Windows中以各种形式存在多年,Delphi形成了与此设置的交互以及它们的自动缩放.我没有在这里检

随机推荐

  1. delphi – 主窗口按进程名称处理

    DelphiXe,Win7x64如何从进程名称(exe文件的完整路径)获取主窗口句柄,或至少一个类或窗口名称(如果该进程只有一个窗口).例:解决方法我同意Petesh的说法,你需要枚举顶级窗口并检查创建它的进程的模块文件名.为了帮助您开始枚举顶级窗口,这是一个delphi实现.首先,当你回调给你时,你需要一些与EnumWindows方法通信的方式.为此声明一条记录,该记录将保存您要查找的模块的文件

  2. 如何在Delphi中纯粹通过RTTI信息(即不使用任何实际对象实例)获取TObjectList的子项类型?

    我正在使用RTTI实现用于流式传输任意Delphi对象的通用代码,并且为了使其工作(更具体地说,为了使加载部分工作),我需要以某种方式获得TObjectList的子项类型<T>不使用任何实际对象实例的字段.要求不使用任何实际对象实例的明显原因是,在从流加载对象的情况下(仅基于要加载的对象的类类型的知识),我将不会有任何实例在加载完成之前完全可用–我宁愿只能访问相关类的纯RTTI数据.我希望能

  3. inno-setup – Inno Setup – 安装程序背景图片

    图像作为安装程序背景如何用inno5.5.9做到这一点?

  4. inno-setup – Inno Setup – 如何添加多个arc文件进行解压缩?

    使用InnoSetup解压缩弧文件.我希望有可能解压缩多个arc文件以从组件选择中安装文件(例如).但仍然显示所有提取的整体进度条.这可能吗?的回答的修改预备是相同的,参考其他答案.在ExtractArc中,为要提取的每个存档调用AddArchive.

  5. delphi – 如何在DataSet的帮助下在TAdvStringGrid中显示数据库中的BLOB图像

    解决方法CreateBlobStream正在创建一个TStream对象,而不是TMemoryStream.由于您不想将JPG写入数据库,因此应使用bmRead而不是bmReadWrite.我不习惯sqlite,但你必须确保使用合适的二进制日期类型.为了确保存储的图像真的是JPG,您应该编写JPG以进行测试,例如:

  6. inno-setup – 在Inno Setup的Code部分下载程序后运行程序

    如何运行我通过Internet下载的应用程序,在代码部分中使用,并等待该应用程序完成运行.我有,使用InnoTools下载程序,下载这两个文件,我想,在第二个完成下载后运行该下载,或jdk-8u111-windows-x64.exe,然后继续安装.解决方法使用其他下载插件,而不是ITD(请参阅下面的原因).例如,InnoDownloadPlugin.当您包含idp.iss时,它定义了一个全局IDP

  7. progress-bar – Inno Setup Run部分的简单进度页面

    我的安装程序非常简单,它基本上是:>欢迎页面>进展页面>最终页面欢迎页面和最终页面是标准页面.在Progress页面,我正在静默安装一堆其他程序.实际的脚本是在[Run]部分中安装每个程序.问题是酒吧达到100%然后停留在那里.我只能更改消息文本.我想要实现的是使用Pascal脚本显示进度,例如:这样我就可以显示更准确的进度条.这就是我所拥有的:问题是,当我构建安装程序时,它不显示欢迎页面.我做错了什么?

  8. delphi – 如何使“显示/隐藏桌面图标”设置生效?

    下面的代码调用SHGetSetSettings函数来隐藏桌面图标但它只是从视图菜单中取消选中“显示桌面图标”.我打电话给SHChangeNotify;更新桌面,但这不起作用?解决方法isa,要刷新桌面,您可以将F5键发送到progman窗口隐藏桌面图标的另一种方法是再次显示

  9. inno-setup – Inno Setup – 避免显示子安装程序的文件名

    我试图使用InnoSetup–Howtohidecertainfilenameswhileinstalling?(FilenameLabel)的想法Theonlysuresolutionistoavoidinstallingthefiles,youdonotwanttoshow,usingthe[Files]section.Installthemusingacodeinstead.UsetheEx

  10. inno-setup – Inno Setup磁力链接下载实施

    我目前正在使用InnoDownloadPlugin为我的安装程序下载文件,这个问题最大的问题是faila正确下载文件.因为连接不良等诸多原因.我想添加一种替代方法来下载文件,因此用户可以选择是否需要常规方式或torrent方式.我知道我可以使用aria2c.exe应用程序(https://aria2.github.io/),有人可以帮我实现它的inno设置代码吗?我需要的是使用torrent(ar

返回
顶部