mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
EMF: support negative bounding box coordinates (#2249)
* EMF: support negative bounding box coordinates Similar to placeable WMF, bounding box coordinates should be interpreted as signed integer, otherwise opening EMF file with negative (x0,y0) fails. * Basic load tests for WMF and EMF formats * WMF/WMF tests: just test open(), not load() Not sure why load() fails on Debian build. Well, at least we can test open(). * WMF/EMF: Unpack signed integers using unpack() * WMF/EMF: Compare to reference PNG rendering * EMF/WMF comparison: use assert_image_similar() * Use similarity epsilon 0.5 for WMF, as vector rendering looks different across Windows platforms * Trigger rebuild
This commit is contained in:
parent
fdeff998df
commit
0116c9240e
|
@ -14,6 +14,10 @@
|
|||
#
|
||||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
# WMF/EMF reference documentation:
|
||||
# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf
|
||||
# http://wvware.sourceforge.net/caolan/index.html
|
||||
# http://wvware.sourceforge.net/caolan/ora-wmf.html
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
|
||||
|
@ -56,16 +60,9 @@ if hasattr(Image.core, "drawwmf"):
|
|||
# --------------------------------------------------------------------
|
||||
|
||||
word = _binary.i16le
|
||||
|
||||
|
||||
def short(c, o=0):
|
||||
v = word(c, o)
|
||||
if v >= 32768:
|
||||
v -= 65536
|
||||
return v
|
||||
|
||||
short = _binary.si16le
|
||||
dword = _binary.i32le
|
||||
|
||||
_long = _binary.si32le
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -121,13 +118,13 @@ class WmfStubImageFile(ImageFile.StubImageFile):
|
|||
# enhanced metafile
|
||||
|
||||
# get bounding box
|
||||
x0 = dword(s, 8)
|
||||
y0 = dword(s, 12)
|
||||
x1 = dword(s, 16)
|
||||
y1 = dword(s, 20)
|
||||
x0 = _long(s, 8)
|
||||
y0 = _long(s, 12)
|
||||
x1 = _long(s, 16)
|
||||
y1 = _long(s, 20)
|
||||
|
||||
# get frame (in 0.01 millimeter units)
|
||||
frame = dword(s, 24), dword(s, 28), dword(s, 32), dword(s, 36)
|
||||
frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)
|
||||
|
||||
# normalize size to 72 dots per inch
|
||||
size = x1 - x0, y1 - y0
|
||||
|
|
|
@ -31,23 +31,41 @@ else:
|
|||
# TODO: replace with more readable struct.unpack equivalent
|
||||
def i16le(c, o=0):
|
||||
"""
|
||||
Converts a 2-bytes (16 bits) string to an integer.
|
||||
Converts a 2-bytes (16 bits) string to an unsigned integer.
|
||||
|
||||
c: string containing bytes to convert
|
||||
o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack("<H", c[o:o+2])[0]
|
||||
|
||||
def si16le(c, o=0):
|
||||
"""
|
||||
Converts a 2-bytes (16 bits) string to a signed integer.
|
||||
|
||||
c: string containing bytes to convert
|
||||
o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack("<h", c[o:o+2])[0]
|
||||
|
||||
|
||||
def i32le(c, o=0):
|
||||
"""
|
||||
Converts a 4-bytes (32 bits) string to an integer.
|
||||
Converts a 4-bytes (32 bits) string to an unsigned integer.
|
||||
|
||||
c: string containing bytes to convert
|
||||
o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack("<I", c[o:o+4])[0]
|
||||
|
||||
def si32le(c, o=0):
|
||||
"""
|
||||
Converts a 4-bytes (32 bits) string to a signed integer.
|
||||
|
||||
c: string containing bytes to convert
|
||||
o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack("<i", c[o:o+4])[0]
|
||||
|
||||
|
||||
def i16be(c, o=0):
|
||||
return unpack(">H", c[o:o+2])[0]
|
||||
|
|
BIN
Tests/images/drawing.emf
Normal file
BIN
Tests/images/drawing.emf
Normal file
Binary file not shown.
BIN
Tests/images/drawing.wmf
Normal file
BIN
Tests/images/drawing.wmf
Normal file
Binary file not shown.
BIN
Tests/images/drawing_emf_ref.png
Normal file
BIN
Tests/images/drawing_emf_ref.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
Tests/images/drawing_wmf_ref.png
Normal file
BIN
Tests/images/drawing_wmf_ref.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 531 B |
31
Tests/test_file_wmf.py
Normal file
31
Tests/test_file_wmf.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
|
||||
class TestFileWmf(PillowTestCase):
|
||||
|
||||
def test_load_raw(self):
|
||||
|
||||
# Test basic EMF open and rendering
|
||||
im = Image.open('Tests/images/drawing.emf')
|
||||
if hasattr(Image.core, "drawwmf"):
|
||||
# Currently, support for WMF/EMF is Windows-only
|
||||
im.load()
|
||||
# Compare to reference rendering
|
||||
imref = Image.open('Tests/images/drawing_emf_ref.png')
|
||||
imref.load()
|
||||
self.assert_image_similar(im, imref, 0)
|
||||
|
||||
# Test basic WMF open and rendering
|
||||
im = Image.open('Tests/images/drawing.wmf')
|
||||
if hasattr(Image.core, "drawwmf"):
|
||||
# Currently, support for WMF/EMF is Windows-only
|
||||
im.load()
|
||||
# Compare to reference rendering
|
||||
imref = Image.open('Tests/images/drawing_wmf_ref.png')
|
||||
imref.load()
|
||||
self.assert_image_similar(im, imref, 0.5)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user