mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-08 06:14:45 +03:00
Merge branch 'master' of https://github.com/python-pillow/Pillow
This commit is contained in:
commit
a437d75163
|
@ -20,7 +20,10 @@ install:
|
||||||
- "pip install cffi"
|
- "pip install cffi"
|
||||||
- "pip install coveralls nose coveralls-merge"
|
- "pip install coveralls nose coveralls-merge"
|
||||||
- "gem install coveralls-lcov"
|
- "gem install coveralls-lcov"
|
||||||
- travis_retry pip install pyroma
|
|
||||||
|
# Pyroma installation is slow on Py3, so just do it for Py2.
|
||||||
|
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then travis_retry pip install pyroma; fi
|
||||||
|
|
||||||
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then pip install unittest2; fi
|
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then pip install unittest2; fi
|
||||||
|
|
||||||
# webp
|
# webp
|
||||||
|
|
15
CHANGES.rst
15
CHANGES.rst
|
@ -4,6 +4,15 @@ Changelog (Pillow)
|
||||||
2.6.0 (unreleased)
|
2.6.0 (unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- Fix TGA files with image ID field #856
|
||||||
|
[megabuz]
|
||||||
|
|
||||||
|
- Fixed wrong P-mode of small, unoptimized L-mode GIF #843
|
||||||
|
[uvNikita]
|
||||||
|
|
||||||
|
- Fixed CVE-2014-3598, a DOS in the Jpeg2KImagePlugin
|
||||||
|
[Andrew Drake]
|
||||||
|
|
||||||
- Fixed CVE-2014-3589, a DOS in the IcnsImagePlugin
|
- Fixed CVE-2014-3589, a DOS in the IcnsImagePlugin
|
||||||
[Andrew Drake]
|
[Andrew Drake]
|
||||||
|
|
||||||
|
@ -61,6 +70,12 @@ Changelog (Pillow)
|
||||||
- Test PalmImagePlugin and method to skip known bad tests #776
|
- Test PalmImagePlugin and method to skip known bad tests #776
|
||||||
[hugovk, wiredfool]
|
[hugovk, wiredfool]
|
||||||
|
|
||||||
|
2.5.3 (2014-08-18)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
- Fixed CVE-2014-3598, a DOS in the Jpeg2KImagePlugin (backport)
|
||||||
|
[Andrew Drake]
|
||||||
|
|
||||||
|
|
||||||
2.5.2 (2014-08-13)
|
2.5.2 (2014-08-13)
|
||||||
------------------
|
------------------
|
||||||
|
|
|
@ -268,10 +268,9 @@ def _save(im, fp, filename):
|
||||||
except IOError:
|
except IOError:
|
||||||
pass # write uncompressed file
|
pass # write uncompressed file
|
||||||
|
|
||||||
try:
|
if im.mode in RAWMODE:
|
||||||
rawmode = RAWMODE[im.mode]
|
|
||||||
imOut = im
|
imOut = im
|
||||||
except KeyError:
|
else:
|
||||||
# convert on the fly (EXPERIMENTAL -- I'm not sure PIL
|
# convert on the fly (EXPERIMENTAL -- I'm not sure PIL
|
||||||
# should automatically convert images on save...)
|
# should automatically convert images on save...)
|
||||||
if Image.getmodebase(im.mode) == "RGB":
|
if Image.getmodebase(im.mode) == "RGB":
|
||||||
|
@ -279,10 +278,8 @@ def _save(im, fp, filename):
|
||||||
if im.palette:
|
if im.palette:
|
||||||
palette_size = len(im.palette.getdata()[1]) // 3
|
palette_size = len(im.palette.getdata()[1]) // 3
|
||||||
imOut = im.convert("P", palette=1, colors=palette_size)
|
imOut = im.convert("P", palette=1, colors=palette_size)
|
||||||
rawmode = "P"
|
|
||||||
else:
|
else:
|
||||||
imOut = im.convert("L")
|
imOut = im.convert("L")
|
||||||
rawmode = "L"
|
|
||||||
|
|
||||||
# header
|
# header
|
||||||
try:
|
try:
|
||||||
|
@ -290,12 +287,6 @@ def _save(im, fp, filename):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
palette = None
|
palette = None
|
||||||
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
|
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
|
||||||
if im.encoderinfo["optimize"]:
|
|
||||||
# When the mode is L, and we optimize, we end up with
|
|
||||||
# im.mode == P and rawmode = L, which fails.
|
|
||||||
# If we're optimizing the palette, we're going to be
|
|
||||||
# in a rawmode of P anyway.
|
|
||||||
rawmode = 'P'
|
|
||||||
|
|
||||||
header, usedPaletteColors = getheader(imOut, palette, im.encoderinfo)
|
header, usedPaletteColors = getheader(imOut, palette, im.encoderinfo)
|
||||||
for s in header:
|
for s in header:
|
||||||
|
@ -352,7 +343,7 @@ def _save(im, fp, filename):
|
||||||
o8(8)) # bits
|
o8(8)) # bits
|
||||||
|
|
||||||
imOut.encoderconfig = (8, interlace)
|
imOut.encoderconfig = (8, interlace)
|
||||||
ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, rawmode)])
|
ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, RAWMODE[imOut.mode])])
|
||||||
|
|
||||||
fp.write(b"\0") # end of image data
|
fp.write(b"\0") # end of image data
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,9 @@ def _parse_jp2_header(fp):
|
||||||
else:
|
else:
|
||||||
hlen = 8
|
hlen = 8
|
||||||
|
|
||||||
|
if lbox < hlen:
|
||||||
|
raise SyntaxError('Invalid JP2 header length')
|
||||||
|
|
||||||
if tbox == b'jp2h':
|
if tbox == b'jp2h':
|
||||||
header = fp.read(lbox - hlen)
|
header = fp.read(lbox - hlen)
|
||||||
break
|
break
|
||||||
|
|
|
@ -42,9 +42,6 @@ MODES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _accept(prefix):
|
|
||||||
return prefix[0:1] == b"\0"
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Image plugin for Targa files.
|
# Image plugin for Targa files.
|
||||||
|
|
||||||
|
@ -58,7 +55,7 @@ class TgaImageFile(ImageFile.ImageFile):
|
||||||
# process header
|
# process header
|
||||||
s = self.fp.read(18)
|
s = self.fp.read(18)
|
||||||
|
|
||||||
id = i8(s[0])
|
idlen = i8(s[0])
|
||||||
|
|
||||||
colormaptype = i8(s[1])
|
colormaptype = i8(s[1])
|
||||||
imagetype = i8(s[2])
|
imagetype = i8(s[2])
|
||||||
|
@ -70,7 +67,7 @@ class TgaImageFile(ImageFile.ImageFile):
|
||||||
self.size = i16(s[12:]), i16(s[14:])
|
self.size = i16(s[12:]), i16(s[14:])
|
||||||
|
|
||||||
# validate header fields
|
# validate header fields
|
||||||
if id != 0 or colormaptype not in (0, 1) or\
|
if colormaptype not in (0, 1) or\
|
||||||
self.size[0] <= 0 or self.size[1] <= 0 or\
|
self.size[0] <= 0 or self.size[1] <= 0 or\
|
||||||
depth not in (1, 8, 16, 24, 32):
|
depth not in (1, 8, 16, 24, 32):
|
||||||
raise SyntaxError("not a TGA file")
|
raise SyntaxError("not a TGA file")
|
||||||
|
@ -103,22 +100,25 @@ class TgaImageFile(ImageFile.ImageFile):
|
||||||
if imagetype & 8:
|
if imagetype & 8:
|
||||||
self.info["compression"] = "tga_rle"
|
self.info["compression"] = "tga_rle"
|
||||||
|
|
||||||
|
if idlen:
|
||||||
|
self.info["id_section"] = self.fp.read(idlen)
|
||||||
|
|
||||||
if colormaptype:
|
if colormaptype:
|
||||||
# read palette
|
# read palette
|
||||||
start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:])
|
start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:])
|
||||||
if mapdepth == 16:
|
if mapdepth == 16:
|
||||||
self.palette = ImagePalette.raw("BGR;16",
|
self.palette = ImagePalette.raw(
|
||||||
b"\0"*2*start + self.fp.read(2*size))
|
"BGR;16", b"\0"*2*start + self.fp.read(2*size))
|
||||||
elif mapdepth == 24:
|
elif mapdepth == 24:
|
||||||
self.palette = ImagePalette.raw("BGR",
|
self.palette = ImagePalette.raw(
|
||||||
b"\0"*3*start + self.fp.read(3*size))
|
"BGR", b"\0"*3*start + self.fp.read(3*size))
|
||||||
elif mapdepth == 32:
|
elif mapdepth == 32:
|
||||||
self.palette = ImagePalette.raw("BGRA",
|
self.palette = ImagePalette.raw(
|
||||||
b"\0"*4*start + self.fp.read(4*size))
|
"BGRA", b"\0"*4*start + self.fp.read(4*size))
|
||||||
|
|
||||||
# setup tile descriptor
|
# setup tile descriptor
|
||||||
try:
|
try:
|
||||||
rawmode = MODES[(imagetype&7, depth)]
|
rawmode = MODES[(imagetype & 7, depth)]
|
||||||
if imagetype & 8:
|
if imagetype & 8:
|
||||||
# compressed
|
# compressed
|
||||||
self.tile = [("tga_rle", (0, 0)+self.size,
|
self.tile = [("tga_rle", (0, 0)+self.size,
|
||||||
|
@ -145,6 +145,7 @@ SAVE = {
|
||||||
"RGBA": ("BGRA", 32, 0, 2),
|
"RGBA": ("BGRA", 32, 0, 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _save(im, fp, filename, check=0):
|
def _save(im, fp, filename, check=0):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -185,13 +186,14 @@ def _save(im, fp, filename, check=0):
|
||||||
if colormaptype:
|
if colormaptype:
|
||||||
fp.write(im.im.getpalette("RGB", "BGR"))
|
fp.write(im.im.getpalette("RGB", "BGR"))
|
||||||
|
|
||||||
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, orientation))])
|
ImageFile._save(
|
||||||
|
im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))])
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# Registry
|
# Registry
|
||||||
|
|
||||||
Image.register_open("TGA", TgaImageFile, _accept)
|
Image.register_open("TGA", TgaImageFile)
|
||||||
Image.register_save("TGA", _save)
|
Image.register_save("TGA", _save)
|
||||||
|
|
||||||
Image.register_extension("TGA", ".tga")
|
Image.register_extension("TGA", ".tga")
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# ;-)
|
# ;-)
|
||||||
|
|
||||||
VERSION = '1.1.7' # PIL version
|
VERSION = '1.1.7' # PIL version
|
||||||
PILLOW_VERSION = '2.5.0' # Pillow
|
PILLOW_VERSION = '2.5.3' # Pillow
|
||||||
|
|
||||||
_plugins = ['BmpImagePlugin',
|
_plugins = ['BmpImagePlugin',
|
||||||
'BufrStubImagePlugin',
|
'BufrStubImagePlugin',
|
||||||
|
|
11
Tests/check_j2k_dos.py
Normal file
11
Tests/check_j2k_dos.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Tests potential DOS of Jpeg2kImagePlugin with 0 length block.
|
||||||
|
# Run from anywhere that PIL is importable.
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
if bytes is str:
|
||||||
|
Image.open(BytesIO(bytes('\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang')))
|
||||||
|
else:
|
||||||
|
Image.open(BytesIO(bytes('\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang', 'latin-1')))
|
||||||
|
|
BIN
Tests/images/tga_id_field.tga
Normal file
BIN
Tests/images/tga_id_field.tga
Normal file
Binary file not shown.
|
@ -35,6 +35,14 @@ class TestFileGif(PillowTestCase):
|
||||||
self.assertEqual(test(0), 800)
|
self.assertEqual(test(0), 800)
|
||||||
self.assertEqual(test(1), 38)
|
self.assertEqual(test(1), 38)
|
||||||
|
|
||||||
|
def test_optimize_full_l(self):
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
im = Image.frombytes("L", (16, 16), bytes(bytearray(range(256))))
|
||||||
|
file = BytesIO()
|
||||||
|
im.save(file, "GIF", optimize=True)
|
||||||
|
self.assertEqual(im.mode, "L")
|
||||||
|
|
||||||
def test_roundtrip(self):
|
def test_roundtrip(self):
|
||||||
out = self.tempfile('temp.gif')
|
out = self.tempfile('temp.gif')
|
||||||
im = lena()
|
im = lena()
|
||||||
|
|
|
@ -52,7 +52,8 @@ class TestFileJpeg2k(PillowTestCase):
|
||||||
def test_lossless(self):
|
def test_lossless(self):
|
||||||
im = Image.open('Tests/images/test-card-lossless.jp2')
|
im = Image.open('Tests/images/test-card-lossless.jp2')
|
||||||
im.load()
|
im.load()
|
||||||
im.save('/tmp/test-card.png')
|
outfile = self.tempfile('temp_test-card.png')
|
||||||
|
im.save(outfile)
|
||||||
self.assert_image_similar(im, test_card, 1.0e-3)
|
self.assert_image_similar(im, test_card, 1.0e-3)
|
||||||
|
|
||||||
def test_lossy_tiled(self):
|
def test_lossy_tiled(self):
|
||||||
|
|
20
Tests/test_file_tga.py
Normal file
20
Tests/test_file_tga.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from helper import unittest, PillowTestCase
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileTga(PillowTestCase):
|
||||||
|
|
||||||
|
def test_id_field(self):
|
||||||
|
# tga file with id field
|
||||||
|
test_file = "Tests/images/tga_id_field.tga"
|
||||||
|
|
||||||
|
# Act
|
||||||
|
im = Image.open(test_file)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(im.size, (100, 100))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -71,7 +71,7 @@
|
||||||
* See the README file for information on usage and redistribution.
|
* See the README file for information on usage and redistribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PILLOW_VERSION "2.5.0"
|
#define PILLOW_VERSION "2.5.3"
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user