mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-27 09:44:31 +03:00
commit
cd17b66541
|
@ -34,7 +34,8 @@
|
||||||
|
|
||||||
__version__ = "0.6"
|
__version__ = "0.6"
|
||||||
|
|
||||||
import array, struct
|
import array
|
||||||
|
import struct
|
||||||
from PIL import Image, ImageFile, _binary
|
from PIL import Image, ImageFile, _binary
|
||||||
from PIL.JpegPresets import presets
|
from PIL.JpegPresets import presets
|
||||||
from PIL._util import isStringType
|
from PIL._util import isStringType
|
||||||
|
@ -44,6 +45,7 @@ o8 = _binary.o8
|
||||||
i16 = _binary.i16be
|
i16 = _binary.i16be
|
||||||
i32 = _binary.i32be
|
i32 = _binary.i32be
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Parser
|
# Parser
|
||||||
|
|
||||||
|
@ -51,6 +53,7 @@ def Skip(self, marker):
|
||||||
n = i16(self.fp.read(2))-2
|
n = i16(self.fp.read(2))-2
|
||||||
ImageFile._safe_read(self.fp, n)
|
ImageFile._safe_read(self.fp, n)
|
||||||
|
|
||||||
|
|
||||||
def APP(self, marker):
|
def APP(self, marker):
|
||||||
#
|
#
|
||||||
# Application marker. Store these in the APP dictionary.
|
# Application marker. Store these in the APP dictionary.
|
||||||
|
@ -59,14 +62,14 @@ def APP(self, marker):
|
||||||
n = i16(self.fp.read(2))-2
|
n = i16(self.fp.read(2))-2
|
||||||
s = ImageFile._safe_read(self.fp, n)
|
s = ImageFile._safe_read(self.fp, n)
|
||||||
|
|
||||||
app = "APP%d" % (marker&15)
|
app = "APP%d" % (marker & 15)
|
||||||
|
|
||||||
self.app[app] = s # compatibility
|
self.app[app] = s # compatibility
|
||||||
self.applist.append((app, s))
|
self.applist.append((app, s))
|
||||||
|
|
||||||
if marker == 0xFFE0 and s[:4] == b"JFIF":
|
if marker == 0xFFE0 and s[:4] == b"JFIF":
|
||||||
# extract JFIF information
|
# extract JFIF information
|
||||||
self.info["jfif"] = version = i16(s, 5) # version
|
self.info["jfif"] = version = i16(s, 5) # version
|
||||||
self.info["jfif_version"] = divmod(version, 256)
|
self.info["jfif_version"] = divmod(version, 256)
|
||||||
# extract JFIF properties
|
# extract JFIF properties
|
||||||
try:
|
try:
|
||||||
|
@ -81,10 +84,10 @@ def APP(self, marker):
|
||||||
self.info["jfif_density"] = jfif_density
|
self.info["jfif_density"] = jfif_density
|
||||||
elif marker == 0xFFE1 and s[:5] == b"Exif\0":
|
elif marker == 0xFFE1 and s[:5] == b"Exif\0":
|
||||||
# extract Exif information (incomplete)
|
# extract Exif information (incomplete)
|
||||||
self.info["exif"] = s # FIXME: value will change
|
self.info["exif"] = s # FIXME: value will change
|
||||||
elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
|
elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
|
||||||
# extract FlashPix information (incomplete)
|
# extract FlashPix information (incomplete)
|
||||||
self.info["flashpix"] = s # FIXME: value will change
|
self.info["flashpix"] = s # FIXME: value will change
|
||||||
elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0":
|
elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0":
|
||||||
# Since an ICC profile can be larger than the maximum size of
|
# Since an ICC profile can be larger than the maximum size of
|
||||||
# a JPEG marker (64K), we need provisions to split it into
|
# a JPEG marker (64K), we need provisions to split it into
|
||||||
|
@ -108,16 +111,17 @@ def APP(self, marker):
|
||||||
else:
|
else:
|
||||||
self.info["adobe_transform"] = adobe_transform
|
self.info["adobe_transform"] = adobe_transform
|
||||||
|
|
||||||
|
|
||||||
def COM(self, marker):
|
def COM(self, marker):
|
||||||
#
|
#
|
||||||
# Comment marker. Store these in the APP dictionary.
|
# Comment marker. Store these in the APP dictionary.
|
||||||
|
|
||||||
n = i16(self.fp.read(2))-2
|
n = i16(self.fp.read(2))-2
|
||||||
s = ImageFile._safe_read(self.fp, n)
|
s = ImageFile._safe_read(self.fp, n)
|
||||||
|
|
||||||
self.app["COM"] = s # compatibility
|
self.app["COM"] = s # compatibility
|
||||||
self.applist.append(("COM", s))
|
self.applist.append(("COM", s))
|
||||||
|
|
||||||
|
|
||||||
def SOF(self, marker):
|
def SOF(self, marker):
|
||||||
#
|
#
|
||||||
# Start of frame marker. Defines the size and mode of the
|
# Start of frame marker. Defines the size and mode of the
|
||||||
|
@ -149,21 +153,22 @@ def SOF(self, marker):
|
||||||
|
|
||||||
if self.icclist:
|
if self.icclist:
|
||||||
# fixup icc profile
|
# fixup icc profile
|
||||||
self.icclist.sort() # sort by sequence number
|
self.icclist.sort() # sort by sequence number
|
||||||
if i8(self.icclist[0][13]) == len(self.icclist):
|
if i8(self.icclist[0][13]) == len(self.icclist):
|
||||||
profile = []
|
profile = []
|
||||||
for p in self.icclist:
|
for p in self.icclist:
|
||||||
profile.append(p[14:])
|
profile.append(p[14:])
|
||||||
icc_profile = b"".join(profile)
|
icc_profile = b"".join(profile)
|
||||||
else:
|
else:
|
||||||
icc_profile = None # wrong number of fragments
|
icc_profile = None # wrong number of fragments
|
||||||
self.info["icc_profile"] = icc_profile
|
self.info["icc_profile"] = icc_profile
|
||||||
self.icclist = None
|
self.icclist = None
|
||||||
|
|
||||||
for i in range(6, len(s), 3):
|
for i in range(6, len(s), 3):
|
||||||
t = s[i:i+3]
|
t = s[i:i+3]
|
||||||
# 4-tuples: id, vsamp, hsamp, qtable
|
# 4-tuples: id, vsamp, hsamp, qtable
|
||||||
self.layer.append((t[0], i8(t[1])//16, i8(t[1])&15, i8(t[2])))
|
self.layer.append((t[0], i8(t[1])//16, i8(t[1]) & 15, i8(t[2])))
|
||||||
|
|
||||||
|
|
||||||
def DQT(self, marker):
|
def DQT(self, marker):
|
||||||
#
|
#
|
||||||
|
@ -181,10 +186,10 @@ def DQT(self, marker):
|
||||||
raise SyntaxError("bad quantization table marker")
|
raise SyntaxError("bad quantization table marker")
|
||||||
v = i8(s[0])
|
v = i8(s[0])
|
||||||
if v//16 == 0:
|
if v//16 == 0:
|
||||||
self.quantization[v&15] = array.array("b", s[1:65])
|
self.quantization[v & 15] = array.array("b", s[1:65])
|
||||||
s = s[65:]
|
s = s[65:]
|
||||||
else:
|
else:
|
||||||
return # FIXME: add code to read 16-bit tables!
|
return # FIXME: add code to read 16-bit tables!
|
||||||
# raise SyntaxError, "bad quantization table element size"
|
# raise SyntaxError, "bad quantization table element size"
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,6 +266,7 @@ MARKER = {
|
||||||
def _accept(prefix):
|
def _accept(prefix):
|
||||||
return prefix[0:1] == b"\377"
|
return prefix[0:1] == b"\377"
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Image plugin for JPEG and JFIF images.
|
# Image plugin for JPEG and JFIF images.
|
||||||
|
|
||||||
|
@ -284,32 +290,37 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
self.huffman_dc = {}
|
self.huffman_dc = {}
|
||||||
self.huffman_ac = {}
|
self.huffman_ac = {}
|
||||||
self.quantization = {}
|
self.quantization = {}
|
||||||
self.app = {} # compatibility
|
self.app = {} # compatibility
|
||||||
self.applist = []
|
self.applist = []
|
||||||
self.icclist = []
|
self.icclist = []
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
s = s + self.fp.read(1)
|
i = i8(s)
|
||||||
|
if i == 0xFF:
|
||||||
i = i16(s)
|
s = s + self.fp.read(1)
|
||||||
|
i = i16(s)
|
||||||
|
else:
|
||||||
|
# Skip non-0xFF junk
|
||||||
|
s = b"\xff"
|
||||||
|
continue
|
||||||
|
|
||||||
if i in MARKER:
|
if i in MARKER:
|
||||||
name, description, handler = MARKER[i]
|
name, description, handler = MARKER[i]
|
||||||
# print hex(i), name, description
|
# print hex(i), name, description
|
||||||
if handler is not None:
|
if handler is not None:
|
||||||
handler(self, i)
|
handler(self, i)
|
||||||
if i == 0xFFDA: # start of scan
|
if i == 0xFFDA: # start of scan
|
||||||
rawmode = self.mode
|
rawmode = self.mode
|
||||||
if self.mode == "CMYK":
|
if self.mode == "CMYK":
|
||||||
rawmode = "CMYK;I" # assume adobe conventions
|
rawmode = "CMYK;I" # assume adobe conventions
|
||||||
self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
|
self.tile = [("jpeg", (0, 0) + self.size, 0, (rawmode, ""))]
|
||||||
# self.__offset = self.fp.tell()
|
# self.__offset = self.fp.tell()
|
||||||
break
|
break
|
||||||
s = self.fp.read(1)
|
s = self.fp.read(1)
|
||||||
elif i == 0 or i == 65535:
|
elif i == 0 or i == 0xFFFF:
|
||||||
# padded marker or junk; move on
|
# padded marker or junk; move on
|
||||||
s = "\xff"
|
s = b"\xff"
|
||||||
else:
|
else:
|
||||||
raise SyntaxError("no marker found")
|
raise SyntaxError("no marker found")
|
||||||
|
|
||||||
|
@ -343,7 +354,8 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
|
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
|
||||||
|
|
||||||
import tempfile, os
|
import tempfile
|
||||||
|
import os
|
||||||
f, path = tempfile.mkstemp()
|
f, path = tempfile.mkstemp()
|
||||||
os.close(f)
|
os.close(f)
|
||||||
if os.path.exists(self.filename):
|
if os.path.exists(self.filename):
|
||||||
|
@ -354,8 +366,10 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
try:
|
try:
|
||||||
self.im = Image.core.open_ppm(path)
|
self.im = Image.core.open_ppm(path)
|
||||||
finally:
|
finally:
|
||||||
try: os.unlink(path)
|
try:
|
||||||
except: pass
|
os.unlink(path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
self.mode = self.im.mode
|
self.mode = self.im.mode
|
||||||
self.size = self.im.size
|
self.size = self.im.size
|
||||||
|
@ -372,6 +386,7 @@ def _getexif(self):
|
||||||
# version.
|
# version.
|
||||||
from PIL import TiffImagePlugin
|
from PIL import TiffImagePlugin
|
||||||
import io
|
import io
|
||||||
|
|
||||||
def fixup(value):
|
def fixup(value):
|
||||||
if len(value) == 1:
|
if len(value) == 1:
|
||||||
return value[0]
|
return value[0]
|
||||||
|
@ -422,7 +437,7 @@ RAWMODE = {
|
||||||
"RGB": "RGB",
|
"RGB": "RGB",
|
||||||
"RGBA": "RGB",
|
"RGBA": "RGB",
|
||||||
"RGBX": "RGB",
|
"RGBX": "RGB",
|
||||||
"CMYK": "CMYK;I", # assume adobe conventions
|
"CMYK": "CMYK;I", # assume adobe conventions
|
||||||
"YCbCr": "YCbCr",
|
"YCbCr": "YCbCr",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,16 +456,19 @@ samplings = {
|
||||||
(2, 2, 1, 1, 1, 1): 2,
|
(2, 2, 1, 1, 1, 1): 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def convert_dict_qtables(qtables):
|
def convert_dict_qtables(qtables):
|
||||||
qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
|
qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
|
||||||
for idx, table in enumerate(qtables):
|
for idx, table in enumerate(qtables):
|
||||||
qtables[idx] = [table[i] for i in zigzag_index]
|
qtables[idx] = [table[i] for i in zigzag_index]
|
||||||
return qtables
|
return qtables
|
||||||
|
|
||||||
|
|
||||||
def get_sampling(im):
|
def get_sampling(im):
|
||||||
sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3]
|
sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3]
|
||||||
return samplings.get(sampling, -1)
|
return samplings.get(sampling, -1)
|
||||||
|
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _save(im, fp, filename):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -563,12 +581,11 @@ def _save(im, fp, filename):
|
||||||
info.get("exif", b"")
|
info.get("exif", b"")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# if we optimize, libjpeg needs a buffer big enough to hold the whole image
|
||||||
# if we optimize, libjpeg needs a buffer big enough to hold the whole image in a shot.
|
# in a shot. Guessing on the size, at im.size bytes. (raw pizel size is
|
||||||
# Guessing on the size, at im.size bytes. (raw pizel size is channels*size, this
|
# channels*size, this is a value that's been used in a django patch.
|
||||||
# is a value that's been used in a django patch.
|
|
||||||
# https://github.com/jdriscoll/django-imagekit/issues/50
|
# https://github.com/jdriscoll/django-imagekit/issues/50
|
||||||
bufsize=0
|
bufsize = 0
|
||||||
if "optimize" in info or "progressive" in info or "progression" in info:
|
if "optimize" in info or "progressive" in info or "progression" in info:
|
||||||
if quality >= 95:
|
if quality >= 95:
|
||||||
bufsize = 2 * im.size[0] * im.size[1]
|
bufsize = 2 * im.size[0] * im.size[1]
|
||||||
|
@ -577,17 +594,20 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
# The exif info needs to be written as one block, + APP1, + one spare byte.
|
# The exif info needs to be written as one block, + APP1, + one spare byte.
|
||||||
# Ensure that our buffer is big enough
|
# Ensure that our buffer is big enough
|
||||||
bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif",b"")) + 5 )
|
bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5)
|
||||||
|
|
||||||
|
ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize)
|
||||||
|
|
||||||
ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)], bufsize)
|
|
||||||
|
|
||||||
def _save_cjpeg(im, fp, filename):
|
def _save_cjpeg(im, fp, filename):
|
||||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
|
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
|
||||||
import os
|
import os
|
||||||
file = im._dump()
|
file = im._dump()
|
||||||
os.system("cjpeg %s >%s" % (file, filename))
|
os.system("cjpeg %s >%s" % (file, filename))
|
||||||
try: os.unlink(file)
|
try:
|
||||||
except: pass
|
os.unlink(file)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# -------------------------------------------------------------------q-
|
# -------------------------------------------------------------------q-
|
||||||
# Registry stuff
|
# Registry stuff
|
||||||
|
|
BIN
Tests/images/junk_jpeg_header.jpg
Normal file
BIN
Tests/images/junk_jpeg_header.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
|
@ -12,17 +12,19 @@ if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:
|
||||||
|
|
||||||
test_file = "Images/lena.jpg"
|
test_file = "Images/lena.jpg"
|
||||||
|
|
||||||
|
|
||||||
def roundtrip(im, **options):
|
def roundtrip(im, **options):
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
im.save(out, "JPEG", **options)
|
im.save(out, "JPEG", **options)
|
||||||
bytes = out.tell()
|
bytes = out.tell()
|
||||||
out.seek(0)
|
out.seek(0)
|
||||||
im = Image.open(out)
|
im = Image.open(out)
|
||||||
im.bytes = bytes # for testing only
|
im.bytes = bytes # for testing only
|
||||||
return im
|
return im
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def test_sanity():
|
def test_sanity():
|
||||||
|
|
||||||
# internal version number
|
# internal version number
|
||||||
|
@ -34,6 +36,7 @@ def test_sanity():
|
||||||
assert_equal(im.size, (128, 128))
|
assert_equal(im.size, (128, 128))
|
||||||
assert_equal(im.format, "JPEG")
|
assert_equal(im.format, "JPEG")
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
def test_app():
|
def test_app():
|
||||||
|
@ -44,6 +47,7 @@ def test_app():
|
||||||
assert_equal(im.applist[1], ("COM", b"Python Imaging Library"))
|
assert_equal(im.applist[1], ("COM", b"Python Imaging Library"))
|
||||||
assert_equal(len(im.applist), 2)
|
assert_equal(len(im.applist), 2)
|
||||||
|
|
||||||
|
|
||||||
def test_cmyk():
|
def test_cmyk():
|
||||||
# Test CMYK handling. Thanks to Tim and Charlie for test data,
|
# Test CMYK handling. Thanks to Tim and Charlie for test data,
|
||||||
# Michael for getting me to look one more time.
|
# Michael for getting me to look one more time.
|
||||||
|
@ -62,6 +66,7 @@ def test_cmyk():
|
||||||
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))]
|
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0]-1, im.size[1]-1))]
|
||||||
assert_true(k > 0.9)
|
assert_true(k > 0.9)
|
||||||
|
|
||||||
|
|
||||||
def test_dpi():
|
def test_dpi():
|
||||||
def test(xdpi, ydpi=None):
|
def test(xdpi, ydpi=None):
|
||||||
im = Image.open(test_file)
|
im = Image.open(test_file)
|
||||||
|
@ -70,7 +75,8 @@ def test_dpi():
|
||||||
assert_equal(test(72), (72, 72))
|
assert_equal(test(72), (72, 72))
|
||||||
assert_equal(test(300), (300, 300))
|
assert_equal(test(300), (300, 300))
|
||||||
assert_equal(test(100, 200), (100, 200))
|
assert_equal(test(100, 200), (100, 200))
|
||||||
assert_equal(test(0), None) # square pixels
|
assert_equal(test(0), None) # square pixels
|
||||||
|
|
||||||
|
|
||||||
def test_icc():
|
def test_icc():
|
||||||
# Test ICC support
|
# Test ICC support
|
||||||
|
@ -89,6 +95,7 @@ def test_icc():
|
||||||
assert_false(im1.info.get("icc_profile"))
|
assert_false(im1.info.get("icc_profile"))
|
||||||
assert_true(im2.info.get("icc_profile"))
|
assert_true(im2.info.get("icc_profile"))
|
||||||
|
|
||||||
|
|
||||||
def test_icc_big():
|
def test_icc_big():
|
||||||
# Make sure that the "extra" support handles large blocks
|
# Make sure that the "extra" support handles large blocks
|
||||||
def test(n):
|
def test(n):
|
||||||
|
@ -96,16 +103,20 @@ def test_icc_big():
|
||||||
# using a 4-byte test code should allow us to detect out of
|
# using a 4-byte test code should allow us to detect out of
|
||||||
# order issues.
|
# order issues.
|
||||||
icc_profile = (b"Test"*int(n/4+1))[:n]
|
icc_profile = (b"Test"*int(n/4+1))[:n]
|
||||||
assert len(icc_profile) == n # sanity
|
assert len(icc_profile) == n # sanity
|
||||||
im1 = roundtrip(lena(), icc_profile=icc_profile)
|
im1 = roundtrip(lena(), icc_profile=icc_profile)
|
||||||
assert_equal(im1.info.get("icc_profile"), icc_profile or None)
|
assert_equal(im1.info.get("icc_profile"), icc_profile or None)
|
||||||
test(0); test(1)
|
test(0)
|
||||||
test(3); test(4); test(5)
|
test(1)
|
||||||
test(65533-14) # full JPEG marker block
|
test(3)
|
||||||
test(65533-14+1) # full block plus one byte
|
test(4)
|
||||||
test(ImageFile.MAXBLOCK) # full buffer block
|
test(5)
|
||||||
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
|
test(65533-14) # full JPEG marker block
|
||||||
test(ImageFile.MAXBLOCK*4+3) # large block
|
test(65533-14+1) # full block plus one byte
|
||||||
|
test(ImageFile.MAXBLOCK) # full buffer block
|
||||||
|
test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte
|
||||||
|
test(ImageFile.MAXBLOCK*4+3) # large block
|
||||||
|
|
||||||
|
|
||||||
def test_optimize():
|
def test_optimize():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
|
@ -113,25 +124,29 @@ def test_optimize():
|
||||||
assert_image_equal(im1, im2)
|
assert_image_equal(im1, im2)
|
||||||
assert_true(im1.bytes >= im2.bytes)
|
assert_true(im1.bytes >= im2.bytes)
|
||||||
|
|
||||||
|
|
||||||
def test_optimize_large_buffer():
|
def test_optimize_large_buffer():
|
||||||
#https://github.com/python-imaging/Pillow/issues/148
|
# https://github.com/python-imaging/Pillow/issues/148
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
# this requires ~ 1.5x Image.MAXBLOCK
|
# this requires ~ 1.5x Image.MAXBLOCK
|
||||||
im = Image.new("RGB", (4096,4096), 0xff3333)
|
im = Image.new("RGB", (4096, 4096), 0xff3333)
|
||||||
im.save(f, format="JPEG", optimize=True)
|
im.save(f, format="JPEG", optimize=True)
|
||||||
|
|
||||||
|
|
||||||
def test_progressive():
|
def test_progressive():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), progressive=True)
|
im2 = roundtrip(lena(), progressive=True)
|
||||||
assert_image_equal(im1, im2)
|
assert_image_equal(im1, im2)
|
||||||
assert_true(im1.bytes >= im2.bytes)
|
assert_true(im1.bytes >= im2.bytes)
|
||||||
|
|
||||||
|
|
||||||
def test_progressive_large_buffer():
|
def test_progressive_large_buffer():
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
# this requires ~ 1.5x Image.MAXBLOCK
|
# this requires ~ 1.5x Image.MAXBLOCK
|
||||||
im = Image.new("RGB", (4096,4096), 0xff3333)
|
im = Image.new("RGB", (4096, 4096), 0xff3333)
|
||||||
im.save(f, format="JPEG", progressive=True)
|
im.save(f, format="JPEG", progressive=True)
|
||||||
|
|
||||||
|
|
||||||
def test_progressive_large_buffer_highest_quality():
|
def test_progressive_large_buffer_highest_quality():
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
if py3:
|
if py3:
|
||||||
|
@ -142,16 +157,18 @@ def test_progressive_large_buffer_highest_quality():
|
||||||
# this requires more bytes than pixels in the image
|
# this requires more bytes than pixels in the image
|
||||||
im.save(f, format="JPEG", progressive=True, quality=100)
|
im.save(f, format="JPEG", progressive=True, quality=100)
|
||||||
|
|
||||||
|
|
||||||
def test_large_exif():
|
def test_large_exif():
|
||||||
#https://github.com/python-imaging/Pillow/issues/148
|
# https://github.com/python-imaging/Pillow/issues/148
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
im = lena()
|
im = lena()
|
||||||
im.save(f,'JPEG', quality=90, exif=b"1"*65532)
|
im.save(f, 'JPEG', quality=90, exif=b"1"*65532)
|
||||||
|
|
||||||
|
|
||||||
def test_progressive_compat():
|
def test_progressive_compat():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), progressive=1)
|
im2 = roundtrip(lena(), progressive=1)
|
||||||
im3 = roundtrip(lena(), progression=1) # compatibility
|
im3 = roundtrip(lena(), progression=1) # compatibility
|
||||||
assert_image_equal(im1, im2)
|
assert_image_equal(im1, im2)
|
||||||
assert_image_equal(im1, im3)
|
assert_image_equal(im1, im3)
|
||||||
assert_false(im1.info.get("progressive"))
|
assert_false(im1.info.get("progressive"))
|
||||||
|
@ -161,31 +178,34 @@ def test_progressive_compat():
|
||||||
assert_true(im3.info.get("progressive"))
|
assert_true(im3.info.get("progressive"))
|
||||||
assert_true(im3.info.get("progression"))
|
assert_true(im3.info.get("progression"))
|
||||||
|
|
||||||
|
|
||||||
def test_quality():
|
def test_quality():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), quality=50)
|
im2 = roundtrip(lena(), quality=50)
|
||||||
assert_image(im1, im2.mode, im2.size)
|
assert_image(im1, im2.mode, im2.size)
|
||||||
assert_true(im1.bytes >= im2.bytes)
|
assert_true(im1.bytes >= im2.bytes)
|
||||||
|
|
||||||
|
|
||||||
def test_smooth():
|
def test_smooth():
|
||||||
im1 = roundtrip(lena())
|
im1 = roundtrip(lena())
|
||||||
im2 = roundtrip(lena(), smooth=100)
|
im2 = roundtrip(lena(), smooth=100)
|
||||||
assert_image(im1, im2.mode, im2.size)
|
assert_image(im1, im2.mode, im2.size)
|
||||||
|
|
||||||
|
|
||||||
def test_subsampling():
|
def test_subsampling():
|
||||||
def getsampling(im):
|
def getsampling(im):
|
||||||
layer = im.layer
|
layer = im.layer
|
||||||
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
|
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
|
||||||
# experimental API
|
# experimental API
|
||||||
im = roundtrip(lena(), subsampling=-1) # default
|
im = roundtrip(lena(), subsampling=-1) # default
|
||||||
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
|
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
|
||||||
im = roundtrip(lena(), subsampling=0) # 4:4:4
|
im = roundtrip(lena(), subsampling=0) # 4:4:4
|
||||||
assert_equal(getsampling(im), (1, 1, 1, 1, 1, 1))
|
assert_equal(getsampling(im), (1, 1, 1, 1, 1, 1))
|
||||||
im = roundtrip(lena(), subsampling=1) # 4:2:2
|
im = roundtrip(lena(), subsampling=1) # 4:2:2
|
||||||
assert_equal(getsampling(im), (2, 1, 1, 1, 1, 1))
|
assert_equal(getsampling(im), (2, 1, 1, 1, 1, 1))
|
||||||
im = roundtrip(lena(), subsampling=2) # 4:1:1
|
im = roundtrip(lena(), subsampling=2) # 4:1:1
|
||||||
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
|
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
|
||||||
im = roundtrip(lena(), subsampling=3) # default (undefined)
|
im = roundtrip(lena(), subsampling=3) # default (undefined)
|
||||||
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
|
assert_equal(getsampling(im), (2, 2, 1, 1, 1, 1))
|
||||||
|
|
||||||
im = roundtrip(lena(), subsampling="4:4:4")
|
im = roundtrip(lena(), subsampling="4:4:4")
|
||||||
|
@ -197,6 +217,7 @@ def test_subsampling():
|
||||||
|
|
||||||
assert_exception(TypeError, lambda: roundtrip(lena(), subsampling="1:1:1"))
|
assert_exception(TypeError, lambda: roundtrip(lena(), subsampling="1:1:1"))
|
||||||
|
|
||||||
|
|
||||||
def test_exif():
|
def test_exif():
|
||||||
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
||||||
info = im._getexif()
|
info = im._getexif()
|
||||||
|
@ -207,3 +228,11 @@ def test_quality_keep():
|
||||||
im = Image.open("Images/lena.jpg")
|
im = Image.open("Images/lena.jpg")
|
||||||
f = tempfile('temp.jpg')
|
f = tempfile('temp.jpg')
|
||||||
assert_no_exception(lambda: im.save(f, quality='keep'))
|
assert_no_exception(lambda: im.save(f, quality='keep'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_junk_jpeg_header():
|
||||||
|
# https://github.com/python-imaging/Pillow/issues/630
|
||||||
|
filename = "Tests/images/junk_jpeg_header.jpg"
|
||||||
|
assert_no_exception(lambda: Image.open(filename))
|
||||||
|
|
||||||
|
# End of file
|
||||||
|
|
Loading…
Reference in New Issue
Block a user