diff --git a/CHANGES.rst b/CHANGES.rst index fcddd8da0..b33c476d7 100644 --- a/CHANGES.rst +++ b/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] diff --git a/Tests/fonts/LICENSE.txt b/Tests/fonts/LICENSE.txt index 0e0baaabb..726d5d797 100644 --- a/Tests/fonts/LICENSE.txt +++ b/Tests/fonts/LICENSE.txt @@ -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 diff --git a/Tests/fonts/NotoSansSymbols-Regular.ttf b/Tests/fonts/NotoSansSymbols-Regular.ttf new file mode 100644 index 000000000..92accef72 Binary files /dev/null and b/Tests/fonts/NotoSansSymbols-Regular.ttf differ diff --git a/Tests/images/imagedraw_rectangle_I.png b/Tests/images/imagedraw_rectangle_I.png new file mode 100644 index 000000000..4e94f6943 Binary files /dev/null and b/Tests/images/imagedraw_rectangle_I.png differ diff --git a/Tests/images/unicode_extended.png b/Tests/images/unicode_extended.png new file mode 100644 index 000000000..c0ffad3c6 Binary files /dev/null and b/Tests/images/unicode_extended.png differ diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 69a1ee5be..45409cbc6 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -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 diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 070fe44c1..232796332 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -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() diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 945372f86..3b0afba67 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -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): diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 7abc34aab..753b98681 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -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") diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 0ee3b979e..5532750fe 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -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) diff --git a/Tests/test_imagesequence.py b/Tests/test_imagesequence.py index 38645f133..5d90dc4c5 100644 --- a/Tests/test_imagesequence.py +++ b/Tests/test_imagesequence.py @@ -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) diff --git a/docs/releasenotes/6.1.0.rst b/docs/releasenotes/6.1.0.rst index 98568fb52..851dcb2d0 100644 --- a/docs/releasenotes/6.1.0.rst +++ b/docs/releasenotes/6.1.0.rst @@ -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 ^^^^^^^^^^^^^^^ diff --git a/setup.py b/setup.py index 5ccf7133d..2c25543a9 100755 --- a/setup.py +++ b/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)) diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index b35420328..bbf1c603f 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -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) diff --git a/src/PIL/ImageSequence.py b/src/PIL/ImageSequence.py index 84199fe27..f9be92d48 100644 --- a/src/PIL/ImageSequence.py +++ b/src/PIL/ImageSequence.py @@ -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 diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 7a1ff49e0..db287967d 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -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, diff --git a/src/_imagingft.c b/src/_imagingft.c index 2567e30d1..4a3b3ccff 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -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"); diff --git a/src/decode.c b/src/decode.c index 10e740aaf..79133f48f 100644 --- a/src/decode.c +++ b/src/decode.c @@ -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)); diff --git a/src/libImaging/Draw.c b/src/libImaging/Draw.c index 6bcd1d2b3..58af4f7f5 100644 --- a/src/libImaging/Draw.c +++ b/src/libImaging/Draw.c @@ -68,7 +68,12 @@ static inline void point8(Imaging im, int x, int y, int ink) { if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) - im->image8[y][x] = (UINT8) ink; + 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 @@ -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); + } } } diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 30c63f7de..e72dae0c8 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -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")); diff --git a/src/libImaging/TiffDecode.h b/src/libImaging/TiffDecode.h index 6cb7e53a2..08ef35cfd 100644 --- a/src/libImaging/TiffDecode.h +++ b/src/libImaging/TiffDecode.h @@ -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, ...);