python-pillow / Pillow

Python Imaging Library (Fork)
https://python-pillow.org
Other
12.32k stars 2.23k forks source link

Skip failing records when rendering WMF images on 64-bit #8506

Open radarhere opened 3 weeks ago

radarhere commented 3 weeks ago

Resolves #6980

The issue would like Pillow to be more lenient when rendering invalid EMF files. The API that raises the error is relatively simple

https://github.com/python-pillow/Pillow/blob/81a3bf5f58d760128ca8beb3f10c1a2c27ec6df6/src/display.c#L799-L800

so I asked about it at https://learn.microsoft.com/en-us/answers/questions/2100252/playenhmetafile-fails-without-any-getlasterror-res, and the answer showed that PlayEnhMetaFileRecord can be used to render the image gradually, skipping failing records.

petsuter commented 3 weeks ago

Great! As mentioned in the ticket, the C# .NET implementation also uses such record-by-record API's internally and allows the files to be handled, so I wouldn't hesitate to do the same. Also programs like Windows Paint and IrfanView allow the files to be opened without error.👍

radarhere commented 3 weeks ago

It turns out my initial commit didn't work on 32-bit Windows - https://ci.appveyor.com/project/Python-pillow/pillow/builds/50869937/job/3jd42o23cjses7ms#L3048

src/display.c(807): error C2440: 'function': cannot convert from 'BOOL (__cdecl )(HDC,HANDLETABLE ,const ENHMETARECORD *,int,LPARAM)' to 'ENHMFENUMPROC'

I've pushed a commit to only use the new behaviour on 64-bit. @petsuter is that sufficient to resolve your issue? Or would you like to see this work on 32-bit as well?

petsuter commented 3 weeks ago

I don't know of any 32-bit Python usage anymore, thanks.

(Could it be the return value should be int not BOOL? https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nc-wingdi-enhmfenumproc)

radarhere commented 3 weeks ago

Thanks.

No, changing it to int still gives https://ci.appveyor.com/project/radarhere/pillow/builds/50870384/job/ji4kbtk94gl000q3#L3047

src/display.c(807): error C2440: 'function': cannot convert from 'int (__cdecl )(HDC,HANDLETABLE ,const ENHMETARECORD *,int,LPARAM)' to 'ENHMFENUMPROC'