mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
Merge branch 'master' into tiff-jpeg-quality
This commit is contained in:
commit
c994b783ec
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -67,6 +67,9 @@ docs/_build/
|
|||
\#*#
|
||||
.#*
|
||||
|
||||
#VS Code
|
||||
.vscode
|
||||
|
||||
#Komodo
|
||||
*.komodoproject
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ make clean
|
|||
make install-coverage
|
||||
|
||||
python selftest.py
|
||||
python -m pytest -vx --cov PIL --cov-report term Tests
|
||||
python -m pytest -v -x --cov PIL --cov-report term Tests
|
||||
|
||||
pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd
|
||||
|
||||
|
|
30
CHANGES.rst
30
CHANGES.rst
|
@ -5,6 +5,36 @@ Changelog (Pillow)
|
|||
6.1.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Create GIF deltas from background colour of GIF frames if disposal mode is 2 #3708
|
||||
[sircinnamon, radarhere]
|
||||
|
||||
- Added ImageSequence all_frames #3778
|
||||
[radarhere]
|
||||
|
||||
- Use unsigned int to store TIFF IFD offsets #3923
|
||||
[cgohlke]
|
||||
|
||||
- Include CPPFLAGS when searching for libraries #3819
|
||||
[jefferyto]
|
||||
|
||||
- Updated TIFF tile descriptors to match current decoding functionality #3795
|
||||
[dmnisson]
|
||||
|
||||
- Added an `image.entropy()` method (second revision) #3608
|
||||
[fish2000]
|
||||
|
||||
- Pass the correct types to PyArg_ParseTuple #3880
|
||||
[QuLogic]
|
||||
|
||||
- Fixed crash when loading non-font bytes #3912
|
||||
[radarhere]
|
||||
|
||||
- Fix SPARC memory alignment issues in Pack/Unpack functions #3858
|
||||
[kulikjak]
|
||||
|
||||
- Added CMYK;16B and CMYK;16N unpackers #3913
|
||||
[radarhere]
|
||||
|
||||
- Fixed bugs in calculating text size #3864
|
||||
[radarhere]
|
||||
|
||||
|
|
|
@ -105,6 +105,8 @@ class TestCoreMemory(PillowTestCase):
|
|||
Image.new("RGB", (10, 10))
|
||||
|
||||
self.assertRaises(ValueError, Image.core.set_blocks_max, -1)
|
||||
if sys.maxsize < 2 ** 32:
|
||||
self.assertRaises(ValueError, Image.core.set_blocks_max, 2 ** 29)
|
||||
|
||||
@unittest.skipIf(is_pypy, "images are not collected")
|
||||
def test_set_blocks_max_stats(self):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from .helper import unittest, PillowTestCase, hopper, netpbm_available
|
||||
|
||||
from PIL import Image, ImagePalette, GifImagePlugin
|
||||
from PIL import Image, ImagePalette, GifImagePlugin, ImageDraw
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
|
@ -59,7 +59,7 @@ class TestFileGif(PillowTestCase):
|
|||
return len(test_file.getvalue())
|
||||
|
||||
self.assertEqual(test_grayscale(0), 800)
|
||||
self.assertEqual(test_grayscale(1), 38)
|
||||
self.assertEqual(test_grayscale(1), 44)
|
||||
self.assertEqual(test_bilevel(0), 800)
|
||||
self.assertEqual(test_bilevel(1), 800)
|
||||
|
||||
|
@ -318,6 +318,103 @@ class TestFileGif(PillowTestCase):
|
|||
img.seek(img.tell() + 1)
|
||||
self.assertEqual(img.disposal_method, i + 1)
|
||||
|
||||
def test_dispose2_palette(self):
|
||||
out = self.tempfile("temp.gif")
|
||||
|
||||
# 4 backgrounds: White, Grey, Black, Red
|
||||
circles = [(255, 255, 255), (153, 153, 153), (0, 0, 0), (255, 0, 0)]
|
||||
|
||||
im_list = []
|
||||
for circle in circles:
|
||||
img = Image.new("RGB", (100, 100), (255, 0, 0))
|
||||
|
||||
# Red circle in center of each frame
|
||||
d = ImageDraw.Draw(img)
|
||||
d.ellipse([(40, 40), (60, 60)], fill=circle)
|
||||
|
||||
im_list.append(img)
|
||||
|
||||
im_list[0].save(out, save_all=True, append_images=im_list[1:], disposal=2)
|
||||
|
||||
img = Image.open(out)
|
||||
|
||||
for i, circle in enumerate(circles):
|
||||
img.seek(i)
|
||||
rgb_img = img.convert("RGB")
|
||||
|
||||
# Check top left pixel matches background
|
||||
self.assertEqual(rgb_img.getpixel((0, 0)), (255, 0, 0))
|
||||
|
||||
# Center remains red every frame
|
||||
self.assertEqual(rgb_img.getpixel((50, 50)), circle)
|
||||
|
||||
def test_dispose2_diff(self):
|
||||
out = self.tempfile("temp.gif")
|
||||
|
||||
# 4 frames: red/blue, red/red, blue/blue, red/blue
|
||||
circles = [
|
||||
((255, 0, 0, 255), (0, 0, 255, 255)),
|
||||
((255, 0, 0, 255), (255, 0, 0, 255)),
|
||||
((0, 0, 255, 255), (0, 0, 255, 255)),
|
||||
((255, 0, 0, 255), (0, 0, 255, 255)),
|
||||
]
|
||||
|
||||
im_list = []
|
||||
for i in range(len(circles)):
|
||||
# Transparent BG
|
||||
img = Image.new("RGBA", (100, 100), (255, 255, 255, 0))
|
||||
|
||||
# Two circles per frame
|
||||
d = ImageDraw.Draw(img)
|
||||
d.ellipse([(0, 30), (40, 70)], fill=circles[i][0])
|
||||
d.ellipse([(60, 30), (100, 70)], fill=circles[i][1])
|
||||
|
||||
im_list.append(img)
|
||||
|
||||
im_list[0].save(
|
||||
out, save_all=True, append_images=im_list[1:], disposal=2, transparency=0
|
||||
)
|
||||
|
||||
img = Image.open(out)
|
||||
|
||||
for i, colours in enumerate(circles):
|
||||
img.seek(i)
|
||||
rgb_img = img.convert("RGBA")
|
||||
|
||||
# Check left circle is correct colour
|
||||
self.assertEqual(rgb_img.getpixel((20, 50)), colours[0])
|
||||
|
||||
# Check right circle is correct colour
|
||||
self.assertEqual(rgb_img.getpixel((80, 50)), colours[1])
|
||||
|
||||
# Check BG is correct colour
|
||||
self.assertEqual(rgb_img.getpixel((1, 1)), (255, 255, 255, 0))
|
||||
|
||||
def test_dispose2_background(self):
|
||||
out = self.tempfile("temp.gif")
|
||||
|
||||
im_list = []
|
||||
|
||||
im = Image.new("P", (100, 100))
|
||||
d = ImageDraw.Draw(im)
|
||||
d.rectangle([(50, 0), (100, 100)], fill="#f00")
|
||||
d.rectangle([(0, 0), (50, 100)], fill="#0f0")
|
||||
im_list.append(im)
|
||||
|
||||
im = Image.new("P", (100, 100))
|
||||
d = ImageDraw.Draw(im)
|
||||
d.rectangle([(0, 0), (100, 50)], fill="#f00")
|
||||
d.rectangle([(0, 50), (100, 100)], fill="#0f0")
|
||||
im_list.append(im)
|
||||
|
||||
im_list[0].save(
|
||||
out, save_all=True, append_images=im_list[1:], disposal=[0, 2], background=1
|
||||
)
|
||||
|
||||
im = Image.open(out)
|
||||
im.seek(1)
|
||||
self.assertEqual(im.getpixel((0, 0)), 0)
|
||||
|
||||
def test_iss634(self):
|
||||
img = Image.open("Tests/images/iss634.gif")
|
||||
# seek to the second frame
|
||||
|
|
|
@ -122,7 +122,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
|
||||
self.assertEqual(im.mode, "RGB")
|
||||
self.assertEqual(im.size, (278, 374))
|
||||
self.assertEqual(im.tile[0][:3], ("tiff_adobe_deflate", (0, 0, 278, 374), 0))
|
||||
self.assertEqual(im.tile[0][:3], ("libtiff", (0, 0, 278, 374), 0))
|
||||
im.load()
|
||||
|
||||
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
||||
|
@ -710,10 +710,10 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
im.tile,
|
||||
[
|
||||
(
|
||||
"tiff_adobe_deflate",
|
||||
"libtiff",
|
||||
(0, 0, 100, 40),
|
||||
0,
|
||||
("RGB;16N", "tiff_adobe_deflate", False),
|
||||
("RGB;16N", "tiff_adobe_deflate", False, 8),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
@ -727,7 +727,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
self.assertEqual(im.mode, "RGBA")
|
||||
self.assertEqual(im.size, (100, 40))
|
||||
self.assertEqual(
|
||||
im.tile, [("tiff_lzw", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False))]
|
||||
im.tile,
|
||||
[("libtiff", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False, 38236))],
|
||||
)
|
||||
im.load()
|
||||
|
||||
|
@ -746,7 +747,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
self.assertEqual(im.mode, "RGB")
|
||||
self.assertEqual(im.size, (256, 256))
|
||||
self.assertEqual(
|
||||
im.tile, [("jpeg", (0, 0, 256, 256), 0, ("RGB", "jpeg", False))]
|
||||
im.tile, [("libtiff", (0, 0, 256, 256), 0, ("RGB", "jpeg", False, 5122))]
|
||||
)
|
||||
im.load()
|
||||
|
||||
|
|
17
Tests/test_image_entropy.py
Normal file
17
Tests/test_image_entropy.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
from .helper import PillowTestCase, hopper
|
||||
|
||||
|
||||
class TestImageEntropy(PillowTestCase):
|
||||
def test_entropy(self):
|
||||
def entropy(mode):
|
||||
return hopper(mode).entropy()
|
||||
|
||||
self.assertAlmostEqual(entropy("1"), 0.9138803254693582)
|
||||
self.assertAlmostEqual(entropy("L"), 7.06650513081286)
|
||||
self.assertAlmostEqual(entropy("I"), 7.06650513081286)
|
||||
self.assertAlmostEqual(entropy("F"), 7.06650513081286)
|
||||
self.assertAlmostEqual(entropy("P"), 5.0530452472519745)
|
||||
self.assertAlmostEqual(entropy("RGB"), 8.821286587714319)
|
||||
self.assertAlmostEqual(entropy("RGBA"), 7.42724306524488)
|
||||
self.assertAlmostEqual(entropy("CMYK"), 7.4272430652448795)
|
||||
self.assertAlmostEqual(entropy("YCbCr"), 7.698360534903628)
|
|
@ -420,6 +420,10 @@ class TestImageFont(PillowTestCase):
|
|||
self.assertRaises(IOError, ImageFont.load_path, filename)
|
||||
self.assertRaises(IOError, ImageFont.truetype, filename)
|
||||
|
||||
def test_load_non_font_bytes(self):
|
||||
with open("Tests/images/hopper.jpg", "rb") as f:
|
||||
self.assertRaises(IOError, ImageFont.truetype, f)
|
||||
|
||||
def test_default_font(self):
|
||||
# Arrange
|
||||
txt = 'This is a "better than nothing" default font.'
|
||||
|
|
|
@ -74,3 +74,25 @@ class TestImageSequence(PillowTestCase):
|
|||
im.seek(0)
|
||||
color2 = im.getpalette()[0:3]
|
||||
self.assertEqual(color1, color2)
|
||||
|
||||
def test_all_frames(self):
|
||||
# Test a single image
|
||||
im = Image.open("Tests/images/iss634.gif")
|
||||
ims = ImageSequence.all_frames(im)
|
||||
|
||||
self.assertEqual(len(ims), 42)
|
||||
for i, im_frame in enumerate(ims):
|
||||
self.assertFalse(im_frame is im)
|
||||
|
||||
im.seek(i)
|
||||
self.assert_image_equal(im, im_frame)
|
||||
|
||||
# Test a series of images
|
||||
ims = ImageSequence.all_frames([im, hopper(), im])
|
||||
self.assertEqual(len(ims), 85)
|
||||
|
||||
# Test an operation
|
||||
ims = ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90))
|
||||
for i, im_frame in enumerate(ims):
|
||||
im.seek(i)
|
||||
self.assert_image_equal(im.rotate(90), im_frame)
|
||||
|
|
|
@ -16,7 +16,7 @@ Open, rotate, and display an image (using the default viewer)
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following script loads an image, rotates it 45 degrees, and displays it
|
||||
using an external viewer (usually xv on Unix, and the paint program on
|
||||
using an external viewer (usually xv on Unix, and the Paint program on
|
||||
Windows).
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -116,15 +116,66 @@ ITU-R 709, using the D65 luminant) to the CIE XYZ color space:
|
|||
rgb2xyz = (
|
||||
0.412453, 0.357580, 0.180423, 0,
|
||||
0.212671, 0.715160, 0.072169, 0,
|
||||
0.019334, 0.119193, 0.950227, 0 )
|
||||
0.019334, 0.119193, 0.950227, 0)
|
||||
out = im.convert("RGB", rgb2xyz)
|
||||
|
||||
.. automethod:: PIL.Image.Image.copy
|
||||
.. automethod:: PIL.Image.Image.crop
|
||||
|
||||
This crops the input image with the provided coordinates:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PIL import Image
|
||||
|
||||
im = Image.open("hopper.jpg")
|
||||
|
||||
# The crop method from the Image module takes four coordinates as input.
|
||||
# The right can also be represented as (left+width)
|
||||
# and lower can be represented as (upper+height).
|
||||
(left, upper, right, lower) = (20, 20, 100, 100)
|
||||
|
||||
# Here the image "im" is cropped and assigned to new variable im_crop
|
||||
im_crop = im.crop((left, upper, right, lower))
|
||||
|
||||
|
||||
.. automethod:: PIL.Image.Image.draft
|
||||
.. automethod:: PIL.Image.Image.filter
|
||||
|
||||
This blurs the input image using a filter from the ``ImageFilter`` module:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PIL import Image, ImageFilter
|
||||
|
||||
im = Image.open("hopper.jpg")
|
||||
|
||||
# Blur the input image using the filter ImageFilter.BLUR
|
||||
im_blurred = im.filter(filter=ImageFilter.BLUR)
|
||||
|
||||
.. automethod:: PIL.Image.Image.getbands
|
||||
|
||||
This helps to get the bands of the input image:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PIL import Image
|
||||
|
||||
im = Image.open("hopper.jpg")
|
||||
print(im.getbands()) # Returns ('R', 'G', 'B')
|
||||
|
||||
.. automethod:: PIL.Image.Image.getbbox
|
||||
|
||||
This helps to get the bounding box coordinates of the input image:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PIL import Image
|
||||
|
||||
im = Image.open("hopper.jpg")
|
||||
print(im.getbbox())
|
||||
# Returns four coordinates in the format (left, upper, right, lower)
|
||||
|
||||
.. automethod:: PIL.Image.Image.getcolors
|
||||
.. automethod:: PIL.Image.Image.getdata
|
||||
.. automethod:: PIL.Image.Image.getextrema
|
||||
|
@ -140,8 +191,35 @@ ITU-R 709, using the D65 luminant) to the CIE XYZ color space:
|
|||
.. automethod:: PIL.Image.Image.putpixel
|
||||
.. automethod:: PIL.Image.Image.quantize
|
||||
.. automethod:: PIL.Image.Image.resize
|
||||
|
||||
This resizes the given image from ``(width, height)`` to ``(width/2, height/2)``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PIL import Image
|
||||
|
||||
im = Image.open("hopper.jpg")
|
||||
|
||||
# Provide the target width and height of the image
|
||||
(width, height) = (im.width // 2, im.height // 2)
|
||||
im_resized = im.resize((width, height))
|
||||
|
||||
.. automethod:: PIL.Image.Image.remap_palette
|
||||
.. automethod:: PIL.Image.Image.rotate
|
||||
|
||||
This rotates the input image by ``theta`` degrees counter clockwise:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PIL import Image
|
||||
|
||||
im = Image.open("hopper.jpg")
|
||||
|
||||
# Rotate the image by 60 degrees counter clockwise
|
||||
theta = 60
|
||||
# Angle is in degrees counter clockwise
|
||||
im_rotated = im.rotate(angle=theta)
|
||||
|
||||
.. automethod:: PIL.Image.Image.save
|
||||
.. automethod:: PIL.Image.Image.seek
|
||||
.. automethod:: PIL.Image.Image.show
|
||||
|
@ -154,6 +232,21 @@ ITU-R 709, using the D65 luminant) to the CIE XYZ color space:
|
|||
.. automethod:: PIL.Image.Image.tostring
|
||||
.. automethod:: PIL.Image.Image.transform
|
||||
.. automethod:: PIL.Image.Image.transpose
|
||||
|
||||
This flips the input image by using the ``Image.FLIP_LEFT_RIGHT`` method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PIL import Image
|
||||
|
||||
im = Image.open("hopper.jpg")
|
||||
|
||||
# Flip the image from left to right
|
||||
im_flipped = im.transpose(method=Image.FLIP_LEFT_RIGHT)
|
||||
# To flip the image from top to bottom,
|
||||
# use the method "Image.FLIP_TOP_BOTTOM"
|
||||
|
||||
|
||||
.. automethod:: PIL.Image.Image.verify
|
||||
|
||||
.. automethod:: PIL.Image.Image.fromstring
|
||||
|
|
|
@ -11,6 +11,14 @@ An optional ``include_layered_windows`` parameter has been added to ``ImageGrab.
|
|||
defaulting to ``False``. If true, layered windows will be included in the resulting
|
||||
image on Windows.
|
||||
|
||||
ImageSequence.all_frames
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A new method to facilitate applying a given function to all frames in an image, or to
|
||||
all frames in a list of images. The frames are returned as a list of separate images.
|
||||
For example, ``ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90))``
|
||||
could be used to return all frames from an image, each rotated 90 degrees.
|
||||
|
||||
Variation fonts
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -90,6 +90,8 @@ def testimage():
|
|||
2
|
||||
>>> len(im.histogram())
|
||||
768
|
||||
>>> '%.7f' % im.entropy()
|
||||
'8.8212866'
|
||||
>>> _info(im.point(list(range(256))*3))
|
||||
(None, 'RGB', (128, 128))
|
||||
>>> _info(im.resize((64, 64)))
|
||||
|
|
4
setup.py
4
setup.py
|
@ -386,8 +386,8 @@ class pil_build_ext(build_ext):
|
|||
_add_directory(library_dirs, lib_root)
|
||||
_add_directory(include_dirs, include_root)
|
||||
|
||||
# respect CFLAGS/LDFLAGS
|
||||
for k in ("CFLAGS", "LDFLAGS"):
|
||||
# respect CFLAGS/CPPFLAGS/LDFLAGS
|
||||
for k in ("CFLAGS", "CPPFLAGS", "LDFLAGS"):
|
||||
if k in os.environ:
|
||||
for match in re.finditer(r"-I([^\s]+)", os.environ[k]):
|
||||
_add_directory(include_dirs, match.group(1))
|
||||
|
|
|
@ -426,6 +426,7 @@ def _write_multiple_frames(im, fp, palette):
|
|||
|
||||
im_frames = []
|
||||
frame_count = 0
|
||||
background_im = None
|
||||
for imSequence in itertools.chain([im], im.encoderinfo.get("append_images", [])):
|
||||
for im_frame in ImageSequence.Iterator(imSequence):
|
||||
# a copy is required here since seek can still mutate the image
|
||||
|
@ -445,11 +446,22 @@ def _write_multiple_frames(im, fp, palette):
|
|||
if im_frames:
|
||||
# delta frame
|
||||
previous = im_frames[-1]
|
||||
if _get_palette_bytes(im_frame) == _get_palette_bytes(previous["im"]):
|
||||
delta = ImageChops.subtract_modulo(im_frame, previous["im"])
|
||||
if encoderinfo.get("disposal") == 2:
|
||||
if background_im is None:
|
||||
background = _get_background(
|
||||
im,
|
||||
im.encoderinfo.get("background", im.info.get("background")),
|
||||
)
|
||||
background_im = Image.new("P", im_frame.size, background)
|
||||
background_im.putpalette(im_frames[0]["im"].palette)
|
||||
base_im = background_im
|
||||
else:
|
||||
base_im = previous["im"]
|
||||
if _get_palette_bytes(im_frame) == _get_palette_bytes(base_im):
|
||||
delta = ImageChops.subtract_modulo(im_frame, base_im)
|
||||
else:
|
||||
delta = ImageChops.subtract_modulo(
|
||||
im_frame.convert("RGB"), previous["im"].convert("RGB")
|
||||
im_frame.convert("RGB"), base_im.convert("RGB")
|
||||
)
|
||||
bbox = delta.getbbox()
|
||||
if not bbox:
|
||||
|
@ -683,10 +695,12 @@ def _get_color_table_size(palette_bytes):
|
|||
# calculate the palette size for the header
|
||||
import math
|
||||
|
||||
color_table_size = int(math.ceil(math.log(len(palette_bytes) // 3, 2))) - 1
|
||||
if color_table_size < 0:
|
||||
color_table_size = 0
|
||||
return color_table_size
|
||||
if not palette_bytes:
|
||||
return 0
|
||||
elif len(palette_bytes) < 9:
|
||||
return 1
|
||||
else:
|
||||
return int(math.ceil(math.log(len(palette_bytes) // 3, 2))) - 1
|
||||
|
||||
|
||||
def _get_header_palette(palette_bytes):
|
||||
|
@ -717,6 +731,18 @@ def _get_palette_bytes(im):
|
|||
return im.palette.palette
|
||||
|
||||
|
||||
def _get_background(im, infoBackground):
|
||||
background = 0
|
||||
if infoBackground:
|
||||
background = infoBackground
|
||||
if isinstance(background, tuple):
|
||||
# WebPImagePlugin stores an RGBA value in info["background"]
|
||||
# So it must be converted to the same format as GifImagePlugin's
|
||||
# info["background"] - a global color table index
|
||||
background = im.palette.getcolor(background)
|
||||
return background
|
||||
|
||||
|
||||
def _get_global_header(im, info):
|
||||
"""Return a list of strings representing a GIF header"""
|
||||
|
||||
|
@ -736,14 +762,7 @@ def _get_global_header(im, info):
|
|||
if im.info.get("version") == b"89a":
|
||||
version = b"89a"
|
||||
|
||||
background = 0
|
||||
if "background" in info:
|
||||
background = info["background"]
|
||||
if isinstance(background, tuple):
|
||||
# WebPImagePlugin stores an RGBA value in info["background"]
|
||||
# So it must be converted to the same format as GifImagePlugin's
|
||||
# info["background"] - a global color table index
|
||||
background = im.palette.getcolor(background)
|
||||
background = _get_background(im, info.get("background"))
|
||||
|
||||
palette_bytes = _get_palette_bytes(im)
|
||||
color_table_size = _get_color_table_size(palette_bytes)
|
||||
|
|
|
@ -1405,6 +1405,7 @@ class Image(object):
|
|||
bi-level image (mode "1") or a greyscale image ("L").
|
||||
|
||||
:param mask: An optional mask.
|
||||
:param extrema: An optional tuple of manually-specified extrema.
|
||||
:returns: A list containing pixel counts.
|
||||
"""
|
||||
self.load()
|
||||
|
@ -1417,6 +1418,32 @@ class Image(object):
|
|||
return self.im.histogram(extrema)
|
||||
return self.im.histogram()
|
||||
|
||||
def entropy(self, mask=None, extrema=None):
|
||||
"""
|
||||
Calculates and returns the entropy for the image.
|
||||
|
||||
A bilevel image (mode "1") is treated as a greyscale ("L")
|
||||
image by this method.
|
||||
|
||||
If a mask is provided, the method employs the histogram for
|
||||
those parts of the image where the mask image is non-zero.
|
||||
The mask image must have the same size as the image, and be
|
||||
either a bi-level image (mode "1") or a greyscale image ("L").
|
||||
|
||||
:param mask: An optional mask.
|
||||
:param extrema: An optional tuple of manually-specified extrema.
|
||||
:returns: A float value representing the image entropy
|
||||
"""
|
||||
self.load()
|
||||
if mask:
|
||||
mask.load()
|
||||
return self.im.entropy((0, 0), mask.im)
|
||||
if self.mode in ("I", "F"):
|
||||
if extrema is None:
|
||||
extrema = self.getextrema()
|
||||
return self.im.entropy(extrema)
|
||||
return self.im.entropy()
|
||||
|
||||
def offset(self, xoffset, yoffset=None):
|
||||
raise NotImplementedError(
|
||||
"offset() has been removed. Please call ImageChops.offset() instead."
|
||||
|
|
|
@ -545,6 +545,8 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
|||
try:
|
||||
return freetype(font)
|
||||
except IOError:
|
||||
if not isPath(font):
|
||||
raise
|
||||
ttf_filename = os.path.basename(font)
|
||||
|
||||
dirs = []
|
||||
|
|
|
@ -54,3 +54,25 @@ class Iterator(object):
|
|||
|
||||
def next(self):
|
||||
return self.__next__()
|
||||
|
||||
|
||||
def all_frames(im, func=None):
|
||||
"""
|
||||
Applies a given function to all frames in an image or a list of images.
|
||||
The frames are returned as a list of separate images.
|
||||
|
||||
:param im: An image, or a list of images.
|
||||
:param func: The function to apply to all of the image frames.
|
||||
:returns: A list of images.
|
||||
"""
|
||||
if not isinstance(im, list):
|
||||
im = [im]
|
||||
|
||||
ims = []
|
||||
for imSequence in im:
|
||||
current = imSequence.tell()
|
||||
|
||||
ims += [im_frame.copy() for im_frame in Iterator(imSequence)]
|
||||
|
||||
imSequence.seek(current)
|
||||
return [func(im) for im in ims] if func else ims
|
||||
|
|
|
@ -1124,7 +1124,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# (self._compression, (extents tuple),
|
||||
# 0, (rawmode, self._compression, fp))
|
||||
extents = self.tile[0][1]
|
||||
args = list(self.tile[0][3]) + [self.tag_v2.offset]
|
||||
args = list(self.tile[0][3])
|
||||
|
||||
# To be nice on memory footprint, if there's a
|
||||
# file descriptor, use that instead of reading
|
||||
|
@ -1331,8 +1331,8 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
|
||||
# Offset in the tile tuple is 0, we go from 0,0 to
|
||||
# w,h, and we only do this once -- eds
|
||||
a = (rawmode, self._compression, False)
|
||||
self.tile.append((self._compression, (0, 0, xsize, ysize), 0, a))
|
||||
a = (rawmode, self._compression, False, self.tag_v2.offset)
|
||||
self.tile.append(("libtiff", (0, 0, xsize, ysize), 0, a))
|
||||
|
||||
elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2:
|
||||
# striped image
|
||||
|
|
|
@ -37,8 +37,8 @@ def i16le(c, o=0):
|
|||
"""
|
||||
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
|
||||
:param c: string containing bytes to convert
|
||||
:param o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack_from("<H", c, o)[0]
|
||||
|
||||
|
@ -47,8 +47,8 @@ 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
|
||||
:param c: string containing bytes to convert
|
||||
:param o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack_from("<h", c, o)[0]
|
||||
|
||||
|
@ -57,8 +57,8 @@ def i32le(c, o=0):
|
|||
"""
|
||||
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
|
||||
:param c: string containing bytes to convert
|
||||
:param o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack_from("<I", c, o)[0]
|
||||
|
||||
|
@ -67,8 +67,8 @@ 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
|
||||
:param c: string containing bytes to convert
|
||||
:param o: offset of bytes to convert in string
|
||||
"""
|
||||
return unpack_from("<i", c, o)[0]
|
||||
|
||||
|
|
146
src/_imaging.c
146
src/_imaging.c
|
@ -86,6 +86,9 @@
|
|||
|
||||
#include "py3.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
/* Configuration stuff. Feel free to undef things you don't need. */
|
||||
#define WITH_IMAGECHOPS /* ImageChops support */
|
||||
#define WITH_IMAGEDRAW /* ImageDraw support */
|
||||
|
@ -1176,59 +1179,68 @@ _getpixel(ImagingObject* self, PyObject* args)
|
|||
return getpixel(self->image, self->access, x, y);
|
||||
}
|
||||
|
||||
union hist_extrema {
|
||||
UINT8 u[2];
|
||||
INT32 i[2];
|
||||
FLOAT32 f[2];
|
||||
};
|
||||
|
||||
static union hist_extrema*
|
||||
parse_histogram_extremap(ImagingObject* self, PyObject* extremap,
|
||||
union hist_extrema* ep)
|
||||
{
|
||||
int i0, i1;
|
||||
double f0, f1;
|
||||
|
||||
if (extremap) {
|
||||
switch (self->image->type) {
|
||||
case IMAGING_TYPE_UINT8:
|
||||
if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1))
|
||||
return NULL;
|
||||
ep->u[0] = CLIP8(i0);
|
||||
ep->u[1] = CLIP8(i1);
|
||||
break;
|
||||
case IMAGING_TYPE_INT32:
|
||||
if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1))
|
||||
return NULL;
|
||||
ep->i[0] = i0;
|
||||
ep->i[1] = i1;
|
||||
break;
|
||||
case IMAGING_TYPE_FLOAT32:
|
||||
if (!PyArg_ParseTuple(extremap, "dd", &f0, &f1))
|
||||
return NULL;
|
||||
ep->f[0] = (FLOAT32) f0;
|
||||
ep->f[1] = (FLOAT32) f1;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return ep;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_histogram(ImagingObject* self, PyObject* args)
|
||||
{
|
||||
ImagingHistogram h;
|
||||
PyObject* list;
|
||||
int i;
|
||||
union {
|
||||
UINT8 u[2];
|
||||
INT32 i[2];
|
||||
FLOAT32 f[2];
|
||||
} extrema;
|
||||
void* ep;
|
||||
int i0, i1;
|
||||
double f0, f1;
|
||||
union hist_extrema extrema;
|
||||
union hist_extrema* ep;
|
||||
|
||||
PyObject* extremap = NULL;
|
||||
ImagingObject* maskp = NULL;
|
||||
if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp))
|
||||
return NULL;
|
||||
|
||||
if (extremap) {
|
||||
ep = &extrema;
|
||||
switch (self->image->type) {
|
||||
case IMAGING_TYPE_UINT8:
|
||||
if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1))
|
||||
return NULL;
|
||||
/* FIXME: clip */
|
||||
extrema.u[0] = i0;
|
||||
extrema.u[1] = i1;
|
||||
break;
|
||||
case IMAGING_TYPE_INT32:
|
||||
if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1))
|
||||
return NULL;
|
||||
extrema.i[0] = i0;
|
||||
extrema.i[1] = i1;
|
||||
break;
|
||||
case IMAGING_TYPE_FLOAT32:
|
||||
if (!PyArg_ParseTuple(extremap, "dd", &f0, &f1))
|
||||
return NULL;
|
||||
extrema.f[0] = (FLOAT32) f0;
|
||||
extrema.f[1] = (FLOAT32) f1;
|
||||
break;
|
||||
default:
|
||||
ep = NULL;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
ep = NULL;
|
||||
return NULL;
|
||||
|
||||
/* Using a var to avoid allocations. */
|
||||
ep = parse_histogram_extremap(self, extremap, &extrema);
|
||||
h = ImagingGetHistogram(self->image, (maskp) ? maskp->image : NULL, ep);
|
||||
|
||||
if (!h)
|
||||
return NULL;
|
||||
return NULL;
|
||||
|
||||
/* Build an integer list containing the histogram */
|
||||
list = PyList_New(h->bands * 256);
|
||||
|
@ -1243,11 +1255,59 @@ _histogram(ImagingObject* self, PyObject* args)
|
|||
PyList_SetItem(list, i, item);
|
||||
}
|
||||
|
||||
/* Destroy the histogram structure */
|
||||
ImagingHistogramDelete(h);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_entropy(ImagingObject* self, PyObject* args)
|
||||
{
|
||||
ImagingHistogram h;
|
||||
int idx, length;
|
||||
long sum;
|
||||
double entropy, fsum, p;
|
||||
union hist_extrema extrema;
|
||||
union hist_extrema* ep;
|
||||
|
||||
PyObject* extremap = NULL;
|
||||
ImagingObject* maskp = NULL;
|
||||
if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp))
|
||||
return NULL;
|
||||
|
||||
/* Using a local var to avoid allocations. */
|
||||
ep = parse_histogram_extremap(self, extremap, &extrema);
|
||||
h = ImagingGetHistogram(self->image, (maskp) ? maskp->image : NULL, ep);
|
||||
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
/* Calculate the histogram entropy */
|
||||
/* First, sum the histogram data */
|
||||
length = h->bands * 256;
|
||||
sum = 0;
|
||||
for (idx = 0; idx < length; idx++) {
|
||||
sum += h->histogram[idx];
|
||||
}
|
||||
|
||||
/* Next, normalize the histogram data, */
|
||||
/* using the histogram sum value */
|
||||
fsum = (double)sum;
|
||||
entropy = 0.0;
|
||||
for (idx = 0; idx < length; idx++) {
|
||||
p = (double)h->histogram[idx] / fsum;
|
||||
if (p != 0.0) {
|
||||
entropy += p * log(p) * M_LOG2E;
|
||||
}
|
||||
}
|
||||
|
||||
/* Destroy the histogram structure */
|
||||
ImagingHistogramDelete(h);
|
||||
|
||||
return PyFloat_FromDouble(-entropy);
|
||||
}
|
||||
|
||||
#ifdef WITH_MODEFILTER
|
||||
static PyObject*
|
||||
_modefilter(ImagingObject* self, PyObject* args)
|
||||
|
@ -3193,6 +3253,7 @@ static struct PyMethodDef methods[] = {
|
|||
{"expand", (PyCFunction)_expand_image, 1},
|
||||
{"filter", (PyCFunction)_filter, 1},
|
||||
{"histogram", (PyCFunction)_histogram, 1},
|
||||
{"entropy", (PyCFunction)_entropy, 1},
|
||||
#ifdef WITH_MODEFILTER
|
||||
{"modefilter", (PyCFunction)_modefilter, 1},
|
||||
#endif
|
||||
|
@ -3625,6 +3686,12 @@ _set_blocks_max(PyObject* self, PyObject* args)
|
|||
"blocks_max should be greater than 0");
|
||||
return NULL;
|
||||
}
|
||||
else if ( blocks_max > SIZE_MAX/sizeof(ImagingDefaultArena.blocks_pool[0])) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"blocks_max is too large");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if ( ! ImagingMemorySetBlocksMax(&ImagingDefaultArena, blocks_max)) {
|
||||
ImagingError_MemoryError();
|
||||
|
@ -3912,4 +3979,3 @@ init_imaging(void)
|
|||
setup_module(m);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|is"PY_ARG_BYTES_LENGTH"i",
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "etn|ns"PY_ARG_BYTES_LENGTH"n",
|
||||
kwlist,
|
||||
Py_FileSystemDefaultEncoding, &filename,
|
||||
&size, &index, &encoding, &font_bytes,
|
||||
|
@ -315,6 +315,7 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
|||
if (error) {
|
||||
if (self->font_bytes) {
|
||||
PyMem_Free(self->font_bytes);
|
||||
self->font_bytes = NULL;
|
||||
}
|
||||
Py_DECREF(self);
|
||||
return geterror(error);
|
||||
|
@ -1006,6 +1007,9 @@ font_render(FontObject* self, PyObject* args)
|
|||
|
||||
num_coords = PyObject_Length(axes);
|
||||
coords = malloc(2 * sizeof(coords));
|
||||
if (coords == NULL) {
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
for (i = 0; i < num_coords; i++) {
|
||||
item = PyList_GET_ITEM(axes, i);
|
||||
if (PyFloat_Check(item))
|
||||
|
@ -1015,6 +1019,7 @@ font_render(FontObject* self, PyObject* args)
|
|||
else if (PyNumber_Check(item))
|
||||
coord = PyFloat_AsDouble(item);
|
||||
else {
|
||||
free(coords);
|
||||
PyErr_SetString(PyExc_TypeError, "list must contain numbers");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1022,6 +1027,7 @@ font_render(FontObject* self, PyObject* args)
|
|||
}
|
||||
|
||||
error = FT_Set_Var_Design_Coordinates(self->face, num_coords, coords);
|
||||
free(coords);
|
||||
if (error)
|
||||
return geterror(error);
|
||||
|
||||
|
|
|
@ -503,9 +503,9 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
|
|||
char* rawmode;
|
||||
char* compname;
|
||||
int fp;
|
||||
int ifdoffset;
|
||||
uint32 ifdoffset;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "sssii", &mode, &rawmode, &compname, &fp, &ifdoffset))
|
||||
if (! PyArg_ParseTuple(args, "sssiI", &mode, &rawmode, &compname, &fp, &ifdoffset))
|
||||
return NULL;
|
||||
|
||||
TRACE(("new tiff decoder %s\n", compname));
|
||||
|
|
23
src/encode.c
23
src/encode.c
|
@ -126,7 +126,7 @@ _encode(ImagingEncoderObject* encoder, PyObject* args)
|
|||
|
||||
Py_ssize_t bufsize = 16384;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|i", &bufsize))
|
||||
if (!PyArg_ParseTuple(args, "|n", &bufsize))
|
||||
return NULL;
|
||||
|
||||
buf = PyBytes_FromStringAndSize(NULL, bufsize);
|
||||
|
@ -180,7 +180,7 @@ _encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
|
|||
Py_ssize_t fh;
|
||||
Py_ssize_t bufsize = 16384;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|i", &fh, &bufsize))
|
||||
if (!PyArg_ParseTuple(args, "n|n", &fh, &bufsize))
|
||||
return NULL;
|
||||
|
||||
/* Allocate an encoder buffer */
|
||||
|
@ -229,7 +229,7 @@ _setimage(ImagingEncoderObject* encoder, PyObject* args)
|
|||
x0 = y0 = x1 = y1 = 0;
|
||||
|
||||
/* FIXME: should publish the ImagingType descriptor */
|
||||
if (!PyArg_ParseTuple(args, "O|(iiii)", &op, &x0, &y0, &x1, &y1))
|
||||
if (!PyArg_ParseTuple(args, "O|(nnnn)", &op, &x0, &y0, &x1, &y1))
|
||||
return NULL;
|
||||
im = PyImaging_AsImaging(op);
|
||||
if (!im)
|
||||
|
@ -409,7 +409,7 @@ PyImaging_GifEncoderNew(PyObject* self, PyObject* args)
|
|||
char *rawmode;
|
||||
Py_ssize_t bits = 8;
|
||||
Py_ssize_t interlace = 0;
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits, &interlace))
|
||||
if (!PyArg_ParseTuple(args, "ss|nn", &mode, &rawmode, &bits, &interlace))
|
||||
return NULL;
|
||||
|
||||
encoder = PyImaging_EncoderNew(sizeof(GIFENCODERSTATE));
|
||||
|
@ -441,7 +441,7 @@ PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
|
|||
char *rawmode;
|
||||
Py_ssize_t bits = 8;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits)) {
|
||||
if (!PyArg_ParseTuple(args, "ss|n", &mode, &rawmode, &bits)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -474,7 +474,7 @@ PyImaging_RawEncoderNew(PyObject* self, PyObject* args)
|
|||
Py_ssize_t stride = 0;
|
||||
Py_ssize_t ystep = 1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &stride, &ystep))
|
||||
if (!PyArg_ParseTuple(args, "ss|nn", &mode, &rawmode, &stride, &ystep))
|
||||
return NULL;
|
||||
|
||||
encoder = PyImaging_EncoderNew(0);
|
||||
|
@ -506,7 +506,7 @@ PyImaging_TgaRleEncoderNew(PyObject* self, PyObject* args)
|
|||
char *rawmode;
|
||||
Py_ssize_t ystep = 1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss|i", &mode, &rawmode, &ystep))
|
||||
if (!PyArg_ParseTuple(args, "ss|n", &mode, &rawmode, &ystep))
|
||||
return NULL;
|
||||
|
||||
encoder = PyImaging_EncoderNew(0);
|
||||
|
@ -567,7 +567,7 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
|
|||
Py_ssize_t compress_type = -1;
|
||||
char* dictionary = NULL;
|
||||
Py_ssize_t dictionary_size = 0;
|
||||
if (!PyArg_ParseTuple(args, "ss|iii"PY_ARG_BYTES_LENGTH, &mode, &rawmode,
|
||||
if (!PyArg_ParseTuple(args, "ss|nnn"PY_ARG_BYTES_LENGTH, &mode, &rawmode,
|
||||
&optimize,
|
||||
&compress_level, &compress_type,
|
||||
&dictionary, &dictionary_size))
|
||||
|
@ -650,7 +650,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
PyObject *item;
|
||||
|
||||
|
||||
if (! PyArg_ParseTuple(args, "sssisOO", &mode, &rawmode, &compname, &fp, &filename, &tags, &types)) {
|
||||
if (! PyArg_ParseTuple(args, "sssnsOO", &mode, &rawmode, &compname, &fp, &filename, &tags, &types)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1025,7 +1025,7 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
|||
char* rawExif = NULL;
|
||||
Py_ssize_t rawExifLen = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss|iiiiiiiiO"PY_ARG_BYTES_LENGTH""PY_ARG_BYTES_LENGTH,
|
||||
if (!PyArg_ParseTuple(args, "ss|nnnnnnnnO"PY_ARG_BYTES_LENGTH""PY_ARG_BYTES_LENGTH,
|
||||
&mode, &rawmode, &quality,
|
||||
&progressive, &smooth, &optimize, &streamtype,
|
||||
&xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size,
|
||||
|
@ -1095,7 +1095,6 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* JPEG 2000 */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -1141,7 +1140,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
|
|||
OPJ_CINEMA_MODE cine_mode;
|
||||
Py_ssize_t fd = -1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss|OOOsOIOOOssi", &mode, &format,
|
||||
if (!PyArg_ParseTuple(args, "ss|OOOsOnOOOssn", &mode, &format,
|
||||
&offset, &tile_offset, &tile_size,
|
||||
&quality_mode, &quality_layers, &num_resolutions,
|
||||
&cblk_size, &precinct_size,
|
||||
|
|
|
@ -251,6 +251,15 @@ ImagingPackRGB(UINT8* out, const UINT8* in, int pixels)
|
|||
{
|
||||
int i = 0;
|
||||
/* RGB triplets */
|
||||
#ifdef __sparc
|
||||
/* SPARC CPUs cannot read integers from nonaligned addresses. */
|
||||
for (; i < pixels; i++) {
|
||||
out[0] = in[R];
|
||||
out[1] = in[G];
|
||||
out[2] = in[B];
|
||||
out += 3; in += 4;
|
||||
}
|
||||
#else
|
||||
for (; i < pixels-1; i++) {
|
||||
((UINT32*)out)[0] = ((UINT32*)in)[i];
|
||||
out += 3;
|
||||
|
@ -261,6 +270,7 @@ ImagingPackRGB(UINT8* out, const UINT8* in, int pixels)
|
|||
out[2] = in[i*4+B];
|
||||
out += 3;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -147,7 +147,7 @@ void _tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) {
|
|||
(void) hdata; (void) base; (void) size;
|
||||
}
|
||||
|
||||
int ImagingLibTiffInit(ImagingCodecState state, int fp, int offset) {
|
||||
int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) {
|
||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||
|
||||
TRACE(("initing libtiff\n"));
|
||||
|
@ -194,6 +194,9 @@ int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) {
|
|||
}
|
||||
|
||||
swap_line = (UINT32*)malloc(swap_line_size);
|
||||
if (swap_line == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* For some reason the TIFFReadRGBATile() function chooses the
|
||||
* lower left corner as the origin. Vertically mirror scanlines.
|
||||
|
|
|
@ -43,7 +43,7 @@ typedef struct {
|
|||
|
||||
|
||||
|
||||
extern int ImagingLibTiffInit(ImagingCodecState state, int fp, int offset);
|
||||
extern int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset);
|
||||
extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp);
|
||||
extern int ImagingLibTiffMergeFieldInfo(ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length);
|
||||
extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...);
|
||||
|
|
|
@ -480,6 +480,16 @@ void
|
|||
ImagingUnpackRGB(UINT8* _out, const UINT8* in, int pixels)
|
||||
{
|
||||
int i = 0;
|
||||
#ifdef __sparc
|
||||
/* SPARC CPUs cannot read integers from nonaligned addresses. */
|
||||
for (; i < pixels; i++) {
|
||||
_out[R] = in[0];
|
||||
_out[G] = in[1];
|
||||
_out[B] = in[2];
|
||||
_out[A] = 255;
|
||||
_out += 4; in += 3;
|
||||
}
|
||||
#else
|
||||
UINT32* out = (UINT32*) _out;
|
||||
/* RGB triplets */
|
||||
for (; i < pixels-1; i++) {
|
||||
|
@ -490,6 +500,7 @@ ImagingUnpackRGB(UINT8* _out, const UINT8* in, int pixels)
|
|||
out[i] = MAKE_UINT32(in[0], in[1], in[2], 255);
|
||||
in += 3;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1085,22 +1096,44 @@ static void
|
|||
copy4skip1(UINT8* _out, const UINT8* in, int pixels)
|
||||
{
|
||||
int i;
|
||||
#ifdef __sparc
|
||||
/* SPARC CPUs cannot read integers from nonaligned addresses. */
|
||||
for (i = 0; i < pixels; i++) {
|
||||
_out[0] = in[0];
|
||||
_out[1] = in[1];
|
||||
_out[2] = in[2];
|
||||
_out[3] = in[3];
|
||||
_out += 4; in += 5;
|
||||
}
|
||||
#else
|
||||
UINT32* out = (UINT32*) _out;
|
||||
for (i = 0; i < pixels; i++) {
|
||||
out[i] = *(UINT32*)&in[0];
|
||||
in += 5;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
copy4skip2(UINT8* _out, const UINT8* in, int pixels)
|
||||
{
|
||||
int i;
|
||||
#ifdef __sparc
|
||||
/* SPARC CPUs cannot read integers from nonaligned addresses. */
|
||||
for (i = 0; i < pixels; i++) {
|
||||
_out[0] = in[0];
|
||||
_out[1] = in[1];
|
||||
_out[2] = in[2];
|
||||
_out[3] = in[3];
|
||||
_out += 4; in += 6;
|
||||
}
|
||||
#else
|
||||
UINT32* out = (UINT32*) _out;
|
||||
for (i = 0; i < pixels; i++) {
|
||||
out[i] = *(UINT32*)&in[0];
|
||||
in += 6;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -133,8 +133,8 @@ PyPath_Flatten(PyObject* data, double **pxy)
|
|||
/* Assume the buffer contains floats */
|
||||
Py_buffer buffer;
|
||||
if (PyImaging_GetBuffer(data, &buffer) == 0) {
|
||||
int n = buffer.len / (2 * sizeof(float));
|
||||
float *ptr = (float*) buffer.buf;
|
||||
n = buffer.len / (2 * sizeof(float));
|
||||
xy = alloc_array(n);
|
||||
if (!xy)
|
||||
return -1;
|
||||
|
|
Loading…
Reference in New Issue
Block a user