从 EMF 图像文件中提取宽度/高度尺寸

发布于 2024-09-12 16:59:31 字数 177 浏览 9 评论 0原文

我维护一个小型 Perl 库,用于从图像中提取宽度/高度,供那些想要该功能而不使用更大、更通用的库的人使用。有人询问我是否可以支持 Windows EMF 格式。然而,我在 Google-fu 上并没有找到很好的格式规范,或者更好的示例代码(任何语言)。我正在寻找一个合适的格式规范,或者读取/解析文件的示例。像往常一样,非常感谢所有帮助。

I maintain a small Perl library that extracts width/height from images, for people who want that functionality without using a larger, more generalized library. I've been asked if I can support the Windows EMF format. However, I haven't had much luck with my Google-fu in trying to find a good specification of the format, or better yet example code (in any language). I'm looking for either a decent spec on the format, or examples of reading/parsing the files. As usually, and and all help is greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

自在安然 2024-09-19 16:59:31

官方规范可以直接从 MSDN 下载 http:// msdn.microsoft.com/en-us/library/cc230514(PROT.10).aspx

阅读和理解需要一些时间,但如果您以前使用过二进制文件格式,那么它绝对是可行的。

但请注意,EMF 是一种(伪)矢量图像格式,因此图像可以缩放到任何大小。但可能有默认宽度和高度。特别是,确实应该有一个明确定义的纵横比。

更新

我认为元文件的宽度(以像素为单位)是文件的第五个基数,高度(以像素为单位)是第六个基数。在典型案例中。至少这对您来说可能是一个不错的起点。

我刚刚创建了一个示例 EMF 文件,该

01 00 00 00 88 00 00 00 00 00 00 00 00 00 00 00
ae 01 00 00 75 01 00 00 00 00 00 00 00 00 00 00

文件以第五个基数为 AE010000 开头,由于字节小尾数,十六进制为 000001AE,即十进制为 430。第六个基数是 75010000,即十六进制的 00000175 或十进制的 373。因此我得到的尺寸为 430×373 平方像素。 Paint 报告 432×374 平方像素。

如果还有更多时间,我会更广泛地研究文件格式。但至少我希望这可以成为您的起点。

更新 2

第三和第四个 32 位整数显然分别是图像的左坐标和上坐标(以逻辑单位表示),而第五个和第六个 32 位整数是右坐标和下坐标。在大多数情况下 (top, left) = (0, 0),然后我上面的文本是正确的(即 width = right, height = top< /代码> 坐标)。

如果 (顶部,左​​侧) <> (0, 0),那么,自然地,宽度 = 右 - 左高度 = 下 - 上

这可能还不是故事的全部。如果将获得的数字与 Paint 报告的数字进行比较,您会发现很小的偏差。所以待续...

The official specification can be downloaded directly from MSDN at http://msdn.microsoft.com/en-us/library/cc230514(PROT.10).aspx.

It will take some time to read and understand, but it should definitely be doable if you have worked with binary file formats before.

But please notice that EMF is a (pseudo-) vector image format, and so images can be scaled to any size. But there might be a default width and height. In particular, there really should be a well-defined aspect ratio.

Update

I think that the width (in pixels) of the metafile is the 5th cardinal of the file, and the height (in pixels) the 6th cardinal. In a typical case. At least this might be a decent starting point for you.

I just created a sample EMF file, which starts

01 00 00 00 88 00 00 00 00 00 00 00 00 00 00 00
ae 01 00 00 75 01 00 00 00 00 00 00 00 00 00 00

The fifth cardinal is AE010000 which, due to the byte little-endianness, is 000001AE in hex, i.e. 430 in decimal. The sixth cardinal is 75010000, i.e. 00000175 in hex or 373 in decimal. Hence I get the dimension to be 430×373 sq. pixels. Paint reports 432×374 sq. pixels.

If I get more time left, I will study the file format more extensively. But at least I hope this might be a starting point for you.

Update 2

The third and forth 32-bit integers are apparently the left and top coordinates of the image, in logical units, respectively, while the fifth and sixth 32-bit integers are the right and bottom coordinates. In most cases (top, left) = (0, 0), and then my text above is correct (i.e. then width = right, height = top coordinate).

If (top, left) <> (0, 0), then, naturally, width = right - left and height = bottom - top.

Now this is probably not the whole story; if you compare the obtained numbers with the ones reported by Paint you will get small deviations. So To be continued....

一身仙ぐ女味 2024-09-19 16:59:31

根据 Andreas Rejbrand 的研究,我用 Python 编写了获取 EMF 文件大小的代码:

with open("img.emf", "rb") as f:
    f.read(16)
    w1, w2 = f.read(1).hex(), f.read(1).hex()
    f.read(2)
    h1, h2 = f.read(1).hex(), f.read(1).hex()

width  = int(str(w2) + str(w1), 16) * 762 # I've no idea why is '762' but it works this way
height = int(str(h2) + str(h1), 16) * 762

我相信如果它能够读取字节,它也可以用 Perl 实现。

以下是它在实际任务中的工作原理: 无法将 EMF 插入 Word使用Python

Based on Andreas Rejbrand's researches I've made the code in Python that gets the sizes of EMF file:

with open("img.emf", "rb") as f:
    f.read(16)
    w1, w2 = f.read(1).hex(), f.read(1).hex()
    f.read(2)
    h1, h2 = f.read(1).hex(), f.read(1).hex()

width  = int(str(w2) + str(w1), 16) * 762 # I've no idea why is '762' but it works this way
height = int(str(h2) + str(h1), 16) * 762

I belive it can be implemented in Perl as well if it's able to read bytes.

Here is how it works in a real task: Unable to insert EMF into Word using Python

云巢 2024-09-19 16:59:31

我之前找到的所有答案要么不完整,要么给出错误的结果。在需要自己提取 EMF 尺寸后,我研究了文件格式并提出了以下内容(用 C# 编写)来从中提取它:

// C# Example
public static RectangleF? ExtractMetafileData(Stream stream)
{
    if (stream == null)
        return null;
    if (stream.Length == 0)
        return null;

    var bytes = new byte[88];
    stream.Seek(0, SeekOrigin.Begin);
    stream.Read(bytes, 0, bytes.Length);

    var rectOffset = 24;
    var x = BitConverter.ToInt32(bytes, rectOffset);
    var y = BitConverter.ToInt32(bytes, rectOffset+4);
    var width = BitConverter.ToInt32(bytes, rectOffset+8) - x;
    var height = BitConverter.ToInt32(bytes, rectOffset+12) - y;

    rectOffset = 72;
    var x1 = BitConverter.ToInt32(bytes, rectOffset);
    var y1 = BitConverter.ToInt32(bytes, rectOffset + 4);
    var x2 = BitConverter.ToInt32(bytes, rectOffset + 8);
    var y2 = BitConverter.ToInt32(bytes, rectOffset + 12);

    float factor1 = ((float)x1 / (float)x2) / 96;   // 96dpi
    float factor2 = ((float)y1 / (float)y2) / 96;   // 96dpi

    var rect = new RectangleF((float) x*factor1, (float) y*factor2, (float) width*factor1, (float) height*factor2);

    stream.Seek(0, SeekOrigin.Begin);

    return rect;
}

或者如果 Python 是你的毒药:

# Python example
with open("mymetafile.emf" , "rb") as f:
    f.read(24)
    left, top = int.from_bytes(f.read(4), 'little'), int.from_bytes(f.read(4), 'little')
    width, height = int.from_bytes(f.read(4), 'little') - left, int.from_bytes(f.read(4), 'little') - top
    f.read(32)
    xf1, yf1 = int.from_bytes(f.read(4), 'little'), int.from_bytes(f.read(4), 'little')
    xf2, yf2 = int.from_bytes(f.read(4), 'little'), int.from_bytes(f.read(4), 'little')

    xfact = (xf1 / xf2) / 96
    yfact = (yf1 / yf2) / 96
    
    pixWidth  = (width * xfact)
    pixHeight = (height * yfact)

print("Width:  " + str(pixWidth))
print("Height: " + str(pixHeight))
print()
print("Width:  " + str(round(pixWidth ,0)))
print("Height: " + str(round(pixHeight,0)))

All answers I previously found were either incomplete or giving the incorrect result. After needing to extract EMF dimensions myself I looked into the file format and came up with the following (in C#) to extract it from:

// C# Example
public static RectangleF? ExtractMetafileData(Stream stream)
{
    if (stream == null)
        return null;
    if (stream.Length == 0)
        return null;

    var bytes = new byte[88];
    stream.Seek(0, SeekOrigin.Begin);
    stream.Read(bytes, 0, bytes.Length);

    var rectOffset = 24;
    var x = BitConverter.ToInt32(bytes, rectOffset);
    var y = BitConverter.ToInt32(bytes, rectOffset+4);
    var width = BitConverter.ToInt32(bytes, rectOffset+8) - x;
    var height = BitConverter.ToInt32(bytes, rectOffset+12) - y;

    rectOffset = 72;
    var x1 = BitConverter.ToInt32(bytes, rectOffset);
    var y1 = BitConverter.ToInt32(bytes, rectOffset + 4);
    var x2 = BitConverter.ToInt32(bytes, rectOffset + 8);
    var y2 = BitConverter.ToInt32(bytes, rectOffset + 12);

    float factor1 = ((float)x1 / (float)x2) / 96;   // 96dpi
    float factor2 = ((float)y1 / (float)y2) / 96;   // 96dpi

    var rect = new RectangleF((float) x*factor1, (float) y*factor2, (float) width*factor1, (float) height*factor2);

    stream.Seek(0, SeekOrigin.Begin);

    return rect;
}

Or if Python is your poison:

# Python example
with open("mymetafile.emf" , "rb") as f:
    f.read(24)
    left, top = int.from_bytes(f.read(4), 'little'), int.from_bytes(f.read(4), 'little')
    width, height = int.from_bytes(f.read(4), 'little') - left, int.from_bytes(f.read(4), 'little') - top
    f.read(32)
    xf1, yf1 = int.from_bytes(f.read(4), 'little'), int.from_bytes(f.read(4), 'little')
    xf2, yf2 = int.from_bytes(f.read(4), 'little'), int.from_bytes(f.read(4), 'little')

    xfact = (xf1 / xf2) / 96
    yfact = (yf1 / yf2) / 96
    
    pixWidth  = (width * xfact)
    pixHeight = (height * yfact)

print("Width:  " + str(pixWidth))
print("Height: " + str(pixHeight))
print()
print("Width:  " + str(round(pixWidth ,0)))
print("Height: " + str(round(pixHeight,0)))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文