mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-24 14:14:47 +03:00
Merge branch 'master' into tiff-tags
This commit is contained in:
commit
f39bf365af
30
CHANGES.rst
30
CHANGES.rst
|
@ -5,6 +5,36 @@ Changelog (Pillow)
|
|||
6.1.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Update Py_UNICODE to Py_UCS4 #3780
|
||||
[nulano]
|
||||
|
||||
- Consider I;16 pixel size when drawing #3899
|
||||
[radarhere]
|
||||
|
||||
- Add TIFFTAG_SAMPLEFORMAT to blocklist #3926
|
||||
[cgohlke, radarhere]
|
||||
|
||||
- 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]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
NotoNastaliqUrdu-Regular.ttf, from https://github.com/googlei18n/noto-fonts
|
||||
NotoNastaliqUrdu-Regular.ttf and NotoSansSymbols-Regular.ttf, from https://github.com/googlei18n/noto-fonts
|
||||
NotoSansJP-Thin.otf, from https://www.google.com/get/noto/help/cjk/
|
||||
AdobeVFPrototype.ttf, from https://github.com/adobe-fonts/adobe-variable-font-prototype
|
||||
TINY5x3GX.ttf, from http://velvetyne.fr/fonts/tiny
|
||||
|
|
BIN
Tests/fonts/NotoSansSymbols-Regular.ttf
Normal file
BIN
Tests/fonts/NotoSansSymbols-Regular.ttf
Normal file
Binary file not shown.
BIN
Tests/images/imagedraw_rectangle_I.png
Normal file
BIN
Tests/images/imagedraw_rectangle_I.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 181 B |
BIN
Tests/images/unicode_extended.png
Normal file
BIN
Tests/images/unicode_extended.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 999 B |
|
@ -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")
|
||||
|
@ -684,10 +684,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),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
@ -701,7 +701,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()
|
||||
|
||||
|
@ -720,7 +721,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()
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import sys
|
|||
|
||||
from .helper import unittest, PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, TiffImagePlugin
|
||||
from PIL import Image, TiffImagePlugin, features
|
||||
from PIL._util import py3
|
||||
from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION, RESOLUTION_UNIT
|
||||
|
||||
|
@ -587,6 +587,30 @@ class TestFileTiff(PillowTestCase):
|
|||
im.load()
|
||||
self.assertFalse(fp.closed)
|
||||
|
||||
@unittest.skipUnless(features.check("libtiff"), "libtiff not installed")
|
||||
def test_sampleformat_not_corrupted(self):
|
||||
# Assert that a TIFF image with SampleFormat=UINT tag is not corrupted
|
||||
# when saving to a new file.
|
||||
# Pillow 6.0 fails with "OSError: cannot identify image file".
|
||||
import base64
|
||||
|
||||
tiff = BytesIO(
|
||||
base64.b64decode(
|
||||
b"SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAAQAAAAEBBAABAAAAAQAA"
|
||||
b"AAIBAwADAAAAwgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAA"
|
||||
b"4AAAABUBAwABAAAAAwAAABYBBAABAAAAAQAAABcBBAABAAAACwAAABoBBQAB"
|
||||
b"AAAAyAAAABsBBQABAAAA0AAAABwBAwABAAAAAQAAACgBAwABAAAAAQAAAFMB"
|
||||
b"AwADAAAA2AAAAAAAAAAIAAgACAABAAAAAQAAAAEAAAABAAAAAQABAAEAAAB4"
|
||||
b"nGNgYAAAAAMAAQ=="
|
||||
)
|
||||
)
|
||||
out = BytesIO()
|
||||
with Image.open(tiff) as im:
|
||||
im.save(out, format="tiff")
|
||||
out.seek(0)
|
||||
with Image.open(out) as im:
|
||||
im.load()
|
||||
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("win32"), "Windows only")
|
||||
class TestFileTiffW32(PillowTestCase):
|
||||
|
|
|
@ -479,6 +479,19 @@ class TestImageDraw(PillowTestCase):
|
|||
# Assert
|
||||
self.assert_image_equal(im, Image.open(expected))
|
||||
|
||||
def test_rectangle_I16(self):
|
||||
# Arrange
|
||||
im = Image.new("I;16", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
||||
# Act
|
||||
draw.rectangle(BBOX1, fill="black", outline="green")
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
im.convert("I"), Image.open("Tests/images/imagedraw_rectangle_I.png")
|
||||
)
|
||||
|
||||
def test_floodfill(self):
|
||||
red = ImageColor.getrgb("red")
|
||||
|
||||
|
|
|
@ -463,6 +463,26 @@ class TestImageFont(PillowTestCase):
|
|||
with self.assertRaises(UnicodeEncodeError):
|
||||
font.getsize(u"’")
|
||||
|
||||
@unittest.skipIf(
|
||||
sys.platform.startswith("win32") and sys.version.startswith("2"),
|
||||
"requires Python 3.x on Windows",
|
||||
)
|
||||
def test_unicode_extended(self):
|
||||
# issue #3777
|
||||
text = u"A\u278A\U0001F12B"
|
||||
target = "Tests/images/unicode_extended.png"
|
||||
|
||||
ttf = ImageFont.truetype(
|
||||
"Tests/fonts/NotoSansSymbols-Regular.ttf",
|
||||
FONT_SIZE,
|
||||
layout_engine=self.LAYOUT_ENGINE,
|
||||
)
|
||||
img = Image.new("RGB", (100, 60))
|
||||
d = ImageDraw.Draw(img)
|
||||
d.text((10, 10), text, font=ttf)
|
||||
|
||||
self.assert_image_similar_tofile(img, target, self.metrics["multiline"])
|
||||
|
||||
def _test_fake_loading_font(self, path_to_fake, fontname):
|
||||
# Make a copy of FreeTypeFont so we can patch the original
|
||||
free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1123,7 +1123,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
|
||||
|
@ -1330,8 +1330,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
|
||||
|
@ -1542,6 +1542,8 @@ def _save(im, fp, filename):
|
|||
|
||||
# optional types for non core tags
|
||||
types = {}
|
||||
# SAMPLEFORMAT is determined by the image format and should not be copied
|
||||
# from legacy_ifd.
|
||||
# STRIPOFFSETS and STRIPBYTECOUNTS are added by the library
|
||||
# based on the data in the strip.
|
||||
# The other tags expect arrays with a certain length (fixed or depending on
|
||||
|
@ -1550,6 +1552,7 @@ def _save(im, fp, filename):
|
|||
blocklist = [
|
||||
COLORMAP,
|
||||
REFERENCEBLACKWHITE,
|
||||
SAMPLEFORMAT,
|
||||
STRIPBYTECOUNTS,
|
||||
STRIPOFFSETS,
|
||||
TRANSFERFUNCTION,
|
||||
|
|
|
@ -327,6 +327,7 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
|||
static int
|
||||
font_getchar(PyObject* string, int index, FT_ULong* char_out)
|
||||
{
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
if (PyUnicode_Check(string)) {
|
||||
Py_UNICODE* p = PyUnicode_AS_UNICODE(string);
|
||||
int size = PyUnicode_GET_SIZE(string);
|
||||
|
@ -336,7 +337,6 @@ font_getchar(PyObject* string, int index, FT_ULong* char_out)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
if (PyString_Check(string)) {
|
||||
unsigned char* p = (unsigned char*) PyString_AS_STRING(string);
|
||||
int size = PyString_GET_SIZE(string);
|
||||
|
@ -345,6 +345,13 @@ font_getchar(PyObject* string, int index, FT_ULong* char_out)
|
|||
*char_out = (unsigned char) p[index];
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
if (PyUnicode_Check(string)) {
|
||||
if (index >= PyUnicode_GET_LENGTH(string))
|
||||
return 0;
|
||||
*char_out = PyUnicode_READ_CHAR(string, index);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -366,6 +373,7 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *
|
|||
goto failed;
|
||||
}
|
||||
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
if (PyUnicode_Check(string)) {
|
||||
Py_UNICODE *text = PyUnicode_AS_UNICODE(string);
|
||||
Py_ssize_t size = PyUnicode_GET_SIZE(string);
|
||||
|
@ -385,9 +393,7 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
else if (PyString_Check(string)) {
|
||||
} else if (PyString_Check(string)) {
|
||||
char *text = PyString_AS_STRING(string);
|
||||
int size = PyString_GET_SIZE(string);
|
||||
if (! size) {
|
||||
|
@ -404,6 +410,28 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *
|
|||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (PyUnicode_Check(string)) {
|
||||
Py_UCS4 *text = PyUnicode_AsUCS4Copy(string);
|
||||
Py_ssize_t size = PyUnicode_GET_LENGTH(string);
|
||||
if (!text || !size) {
|
||||
/* return 0 and clean up, no glyphs==no size,
|
||||
and raqm fails with empty strings */
|
||||
goto failed;
|
||||
}
|
||||
int set_text = (*p_raqm.set_text)(rq, (const uint32_t *)(text), size);
|
||||
PyMem_Free(text);
|
||||
if (!set_text) {
|
||||
PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed");
|
||||
goto failed;
|
||||
}
|
||||
if (lang) {
|
||||
if (!(*p_raqm.set_language)(rq, lang, start, size)) {
|
||||
PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "expected string");
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -68,8 +68,13 @@ static inline void
|
|||
point8(Imaging im, int x, int y, int ink)
|
||||
{
|
||||
if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize)
|
||||
if (strncmp(im->mode, "I;16", 4) == 0) {
|
||||
im->image8[y][x*2] = (UINT8) ink;
|
||||
im->image8[y][x*2+1] = (UINT8) ink;
|
||||
} else {
|
||||
im->image8[y][x] = (UINT8) ink;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
point32(Imaging im, int x, int y, int ink)
|
||||
|
@ -95,7 +100,7 @@ point32rgba(Imaging im, int x, int y, int ink)
|
|||
static inline void
|
||||
hline8(Imaging im, int x0, int y0, int x1, int ink)
|
||||
{
|
||||
int tmp;
|
||||
int tmp, pixelwidth;
|
||||
|
||||
if (y0 >= 0 && y0 < im->ysize) {
|
||||
if (x0 > x1)
|
||||
|
@ -108,8 +113,11 @@ hline8(Imaging im, int x0, int y0, int x1, int ink)
|
|||
return;
|
||||
else if (x1 >= im->xsize)
|
||||
x1 = im->xsize-1;
|
||||
if (x0 <= x1)
|
||||
memset(im->image8[y0] + x0, (UINT8) ink, x1 - x0 + 1);
|
||||
if (x0 <= x1) {
|
||||
pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1;
|
||||
memset(im->image8[y0] + x0 * pixelwidth, (UINT8) ink,
|
||||
(x1 - x0 + 1) * pixelwidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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, ...);
|
||||
|
|
Loading…
Reference in New Issue
Block a user