Open petsuter opened 1 year ago
(It seems Pillow calls the GDI routine PlayEnhMetaFile
which fails.
The same EMF file works with this C# code:
var emf_filename = @"test_libuemf_ref.emf";
var png_filename = @"out.png";
var metafile = new Metafile(emf_filename);
var metafileHeader = metafile.GetMetafileHeader();
var bitmap = new Bitmap(metafile.Width, metafile.Height);
using (var gfx = Graphics.FromImage(bitmap))
{
gfx.Clear(Color.White);
float sx = metafileHeader.DpiX / gfx.DpiX;
float sy = metafileHeader.DpiY / gfx.DpiY;
gfx.ScaleTransform(sx, sy);
gfx.DrawImage(metafile, 0, 0);
}
bitmap.Save(png_filename);
C# seems to also uses GDI (but PlayMetafileRecord
instead of PlayEnhMetaFile
? not sure) here I think: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.cs
Just in case this helps.)
I think the first record that fails record ~13 is a EMR_STROKEANDFILLPATH with "bounds" arguments 0,0,29699,20999 which is probably rejected because it is larger than the EMR_HEADER
bounds 0,0,14030,9920.
In other files there are EMR_POLYBEZIER16
records with count 0 which also fails to load in Pillow. These empty records could just be dropped e.g. like this:
import pathlib
import struct
input_path = pathlib.Path("test.emf")
output_path = pathlib.Path("filtered.emf")
input_bytes = input_path.read_bytes()
output_records = []
offset = 0
while offset < len(input_bytes):
rec_type, rec_size = struct.unpack_from('<ii', input_bytes, offset)
if rec_type == 88: # EMR_POLYBEZIER16
count = struct.unpack_from('<i', input_bytes, offset + 24)[0]
if count == 0:
offset += rec_size
continue
rec_bytes = input_bytes[offset:offset+rec_size]
output_records.append(rec_bytes)
offset += rec_size
output_bytes = b''.join(output_records)
output_path.write_bytes(
output_bytes[:0x30] +
struct.pack('<i', len(output_bytes)) +
struct.pack('<i', len(output_records)) +
output_bytes[0x38:]
)
I think the first record that fails record ~13 is a EMR_STROKEANDFILLPATH with "bounds" arguments 0,0,29699,20999 which is probably rejected because it is larger than the
EMR_HEADER
bounds 0,0,14030,9920.
So, if I understand you correctly, the image actually has bugs in it? You're requesting that Pillow be more flexible when reading?
Other programs can open and display the image without a problem, including Windows Paint and IrfanView and the C# reader above. I don't know if the image can be considered to have bugs, but maybe "unusual edge cases"?
A few days ago I didn't know anything about EMF files. I wanted to load some seemingly valid files. They were rejected for unknown reasons. If you can make Pillow more flexible to allow reading these files, I think that would be valuable.
In other files there are
EMR_POLYBEZIER16
records with count 0 which also fails to load in Pillow. These empty records could just be dropped
Do you have examples of such files? I thought you might be referring to attachment 75058 at 2013-02-18 16:41:51 UTC in https://bugs.documentfoundation.org/show_bug.cgi?id=55058, but I was able to open load that file with Pillow without a problem.
Right, those are different EMF files. I have to check if I can find a public one.
libUEMF-0.2.8.tar.gz
from https://sourceforge.net/projects/libuemf/ contains more EMF test files. Almost none of them work with Pillow.
there are EMR_POLYBEZIER16 records with count 0 which also fails to load in Pillow
Here is a test file test_20241010.zip As described above it can be opened for example in Windows Paint and IrfanView, but not in Pillow (v10.4.0)
Thanks. Is that image one that can be included in our test suite and distributed under the Pillow license?
I've created #8506 to resolve this. With it, I'm able to render test_20241010.emf and test_libuemf_ref.emf.
Here are the results, saved as PNGs.
Sounds great, thanks!
C# seems to also uses GDI (but
PlayMetafileRecord
instead ofPlayEnhMetaFile
? not sure) here I think: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.cs Just in case this helps.)
(Apparently they moved this in the meantime. In version 7 it was here I guess: https://github.com/dotnet/runtime/blob/v7.0.20/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.cs#L525
In version 9 it's now here: https://github.com/dotnet/winforms/blob/release/9.0/src/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.cs#L541 )
What did you do?
Download example EMF file
test_libuemf_ref.emf
from https://bugs.documentfoundation.org/attachment.cgi?id=135791 (via https://bugs.documentfoundation.org/show_bug.cgi?id=55058)Run:
What did you expect to happen?
out.png
should be created.What actually happened?
What are your OS, Python and Pillow versions?