diff --git a/CHANGES.rst b/CHANGES.rst index cd00ce285..02e8d318d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,9 @@ Changelog (Pillow) 2.6.0 (unreleased) ------------------ +- Image.tobytes() and Image.tostring() documentation update #916 #917 + [mgedmin] + - On Windows, do not execute convert.exe without specifying path #912 [cgohlke] diff --git a/PIL/Image.py b/PIL/Image.py index 34b49c802..99ab6327b 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -665,6 +665,10 @@ class Image: # Declare tostring as alias to tobytes def tostring(self, *args, **kw): + """Deprecated alias to tobytes. + + .. deprecated:: 2.0 + """ warnings.warn( 'tostring() is deprecated. Please call tobytes() instead.', DeprecationWarning, diff --git a/PIL/ImageWin.py b/PIL/ImageWin.py index 3e0bbaf99..300d118c9 100644 --- a/PIL/ImageWin.py +++ b/PIL/ImageWin.py @@ -23,7 +23,7 @@ from PIL import Image class HDC: """ - Wraps a HDC integer. The resulting object can be passed to the + Wraps an HDC integer. The resulting object can be passed to the :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose` methods. """ @@ -36,7 +36,7 @@ class HDC: class HWND: """ - Wraps a HWND integer. The resulting object can be passed to the + Wraps an HWND integer. The resulting object can be passed to the :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose` methods, instead of a DC. """ @@ -86,8 +86,8 @@ class Dib: """ Copy the bitmap contents to a device context. - :param handle: Device context (HDC), cast to a Python integer, or a HDC - or HWND instance. In PythonWin, you can use the + :param handle: Device context (HDC), cast to a Python integer, or an + HDC or HWND instance. In PythonWin, you can use the :py:meth:`CDC.GetHandleAttrib` to get a suitable handle. """ if isinstance(handle, HWND): diff --git a/PIL/PSDraw.py b/PIL/PSDraw.py index 208f7b6a6..5a24441a8 100644 --- a/PIL/PSDraw.py +++ b/PIL/PSDraw.py @@ -74,8 +74,7 @@ class PSDraw: def setink(self, ink): """ - .. warning:: This has been in the PIL API for ages but was never - implemented. + .. warning:: This has been in the PIL API for ages but was never implemented. """ print("*** NOT YET IMPLEMENTED ***") diff --git a/Tests/images/hopper_gray.jpg b/Tests/images/hopper_gray.jpg new file mode 100644 index 000000000..db3831ded Binary files /dev/null and b/Tests/images/hopper_gray.jpg differ diff --git a/Tests/images/lena.jpg b/Tests/images/lena.jpg deleted file mode 100644 index ed01c4e67..000000000 Binary files a/Tests/images/lena.jpg and /dev/null differ diff --git a/Tests/images/lena.tif b/Tests/images/lena.tif deleted file mode 100644 index fead980d4..000000000 Binary files a/Tests/images/lena.tif and /dev/null differ diff --git a/Tests/images/lena_bw.png b/Tests/images/lena_bw.png deleted file mode 100644 index f9b64c185..000000000 Binary files a/Tests/images/lena_bw.png and /dev/null differ diff --git a/Tests/images/lena_gray.jpg b/Tests/images/lena_gray.jpg deleted file mode 100644 index 72e9a4a77..000000000 Binary files a/Tests/images/lena_gray.jpg and /dev/null differ diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 308489d65..e46b656bb 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -1,4 +1,4 @@ -from helper import unittest, PillowTestCase, lena, py3 +from helper import unittest, PillowTestCase, hopper, py3 from helper import djpeg_available, cjpeg_available import random @@ -10,7 +10,7 @@ from PIL import JpegImagePlugin codecs = dir(Image.core) -test_file = "Tests/images/lena.jpg" +TEST_FILE = "Tests/images/hopper.jpg" class TestFileJpeg(PillowTestCase): @@ -33,7 +33,7 @@ class TestFileJpeg(PillowTestCase): # internal version number self.assertRegexpMatches(Image.core.jpeglib_version, "\d+\.\d+$") - im = Image.open(test_file) + im = Image.open(TEST_FILE) im.load() self.assertEqual(im.mode, "RGB") self.assertEqual(im.size, (128, 128)) @@ -41,11 +41,12 @@ class TestFileJpeg(PillowTestCase): def test_app(self): # Test APP/COM reader (@PIL135) - im = Image.open(test_file) + im = Image.open(TEST_FILE) self.assertEqual( im.applist[0], - ("APP0", b"JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00")) - self.assertEqual(im.applist[1], ("COM", b"Python Imaging Library")) + ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00")) + self.assertEqual(im.applist[1], ( + "COM", b"File written by Adobe Photoshop\xa8 4.0\x00")) self.assertEqual(len(im.applist), 2) def test_cmyk(self): @@ -76,7 +77,7 @@ class TestFileJpeg(PillowTestCase): def test_dpi(self): def test(xdpi, ydpi=None): - im = Image.open(test_file) + im = Image.open(TEST_FILE) im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi)) return im.info.get("dpi") self.assertEqual(test(72), (72, 72)) @@ -95,8 +96,8 @@ class TestFileJpeg(PillowTestCase): im2 = Image.open(f) self.assertEqual(im2.info.get("icc_profile"), icc_profile) # Roundtrip via memory buffer. - im1 = self.roundtrip(lena()) - im2 = self.roundtrip(lena(), icc_profile=icc_profile) + im1 = self.roundtrip(hopper()) + im2 = self.roundtrip(hopper(), icc_profile=icc_profile) self.assert_image_equal(im1, im2) self.assertFalse(im1.info.get("icc_profile")) self.assertTrue(im2.info.get("icc_profile")) @@ -109,7 +110,7 @@ class TestFileJpeg(PillowTestCase): # order issues. icc_profile = (b"Test"*int(n/4+1))[:n] assert len(icc_profile) == n # sanity - im1 = self.roundtrip(lena(), icc_profile=icc_profile) + im1 = self.roundtrip(hopper(), icc_profile=icc_profile) self.assertEqual(im1.info.get("icc_profile"), icc_profile or None) test(0) test(1) @@ -123,8 +124,8 @@ class TestFileJpeg(PillowTestCase): test(ImageFile.MAXBLOCK*4+3) # large block def test_optimize(self): - im1 = self.roundtrip(lena()) - im2 = self.roundtrip(lena(), optimize=1) + im1 = self.roundtrip(hopper()) + im2 = self.roundtrip(hopper(), optimize=1) self.assert_image_equal(im1, im2) self.assertGreaterEqual(im1.bytes, im2.bytes) @@ -136,8 +137,8 @@ class TestFileJpeg(PillowTestCase): im.save(f, format="JPEG", optimize=True) def test_progressive(self): - im1 = self.roundtrip(lena()) - im2 = self.roundtrip(lena(), progressive=True) + im1 = self.roundtrip(hopper()) + im2 = self.roundtrip(hopper(), progressive=True) self.assert_image_equal(im1, im2) self.assertGreaterEqual(im1.bytes, im2.bytes) @@ -161,13 +162,13 @@ class TestFileJpeg(PillowTestCase): def test_large_exif(self): # https://github.com/python-pillow/Pillow/issues/148 f = self.tempfile('temp.jpg') - im = lena() + im = hopper() im.save(f, 'JPEG', quality=90, exif=b"1"*65532) def test_progressive_compat(self): - im1 = self.roundtrip(lena()) - im2 = self.roundtrip(lena(), progressive=1) - im3 = self.roundtrip(lena(), progression=1) # compatibility + im1 = self.roundtrip(hopper()) + im2 = self.roundtrip(hopper(), progressive=1) + im3 = self.roundtrip(hopper(), progression=1) # compatibility self.assert_image_equal(im1, im2) self.assert_image_equal(im1, im3) self.assertFalse(im1.info.get("progressive")) @@ -178,14 +179,14 @@ class TestFileJpeg(PillowTestCase): self.assertTrue(im3.info.get("progression")) def test_quality(self): - im1 = self.roundtrip(lena()) - im2 = self.roundtrip(lena(), quality=50) + im1 = self.roundtrip(hopper()) + im2 = self.roundtrip(hopper(), quality=50) self.assert_image(im1, im2.mode, im2.size) self.assertGreaterEqual(im1.bytes, im2.bytes) def test_smooth(self): - im1 = self.roundtrip(lena()) - im2 = self.roundtrip(lena(), smooth=100) + im1 = self.roundtrip(hopper()) + im2 = self.roundtrip(hopper(), smooth=100) self.assert_image(im1, im2.mode, im2.size) def test_subsampling(self): @@ -193,26 +194,26 @@ class TestFileJpeg(PillowTestCase): layer = im.layer return layer[0][1:3] + layer[1][1:3] + layer[2][1:3] # experimental API - im = self.roundtrip(lena(), subsampling=-1) # default + im = self.roundtrip(hopper(), subsampling=-1) # default self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) - im = self.roundtrip(lena(), subsampling=0) # 4:4:4 + im = self.roundtrip(hopper(), subsampling=0) # 4:4:4 self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1)) - im = self.roundtrip(lena(), subsampling=1) # 4:2:2 + im = self.roundtrip(hopper(), subsampling=1) # 4:2:2 self.assertEqual(getsampling(im), (2, 1, 1, 1, 1, 1)) - im = self.roundtrip(lena(), subsampling=2) # 4:1:1 + im = self.roundtrip(hopper(), subsampling=2) # 4:1:1 self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) - im = self.roundtrip(lena(), subsampling=3) # default (undefined) + im = self.roundtrip(hopper(), subsampling=3) # default (undefined) self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) - im = self.roundtrip(lena(), subsampling="4:4:4") + im = self.roundtrip(hopper(), subsampling="4:4:4") self.assertEqual(getsampling(im), (1, 1, 1, 1, 1, 1)) - im = self.roundtrip(lena(), subsampling="4:2:2") + im = self.roundtrip(hopper(), subsampling="4:2:2") self.assertEqual(getsampling(im), (2, 1, 1, 1, 1, 1)) - im = self.roundtrip(lena(), subsampling="4:1:1") + im = self.roundtrip(hopper(), subsampling="4:1:1") self.assertEqual(getsampling(im), (2, 2, 1, 1, 1, 1)) self.assertRaises( - TypeError, lambda: self.roundtrip(lena(), subsampling="1:1:1")) + TypeError, lambda: self.roundtrip(hopper(), subsampling="1:1:1")) def test_exif(self): im = Image.open("Tests/images/pil_sample_rgb.jpg") @@ -225,11 +226,11 @@ class TestFileJpeg(PillowTestCase): def test_quality_keep(self): # RGB - im = Image.open("Tests/images/lena.jpg") + im = Image.open("Tests/images/hopper.jpg") f = self.tempfile('temp.jpg') im.save(f, quality='keep') # Grayscale - im = Image.open("Tests/images/lena_gray.jpg") + im = Image.open("Tests/images/hopper_gray.jpg") f = self.tempfile('temp.jpg') im.save(f, quality='keep') # CMYK @@ -243,7 +244,7 @@ class TestFileJpeg(PillowTestCase): Image.open(filename) def test_qtables(self): - im = Image.open("Tests/images/lena.jpg") + im = Image.open("Tests/images/hopper.jpg") qtables = im.quantization reloaded = self.roundtrip(im, qtables=qtables, subsampling=0) self.assertEqual(im.quantization, reloaded.quantization) @@ -296,18 +297,18 @@ class TestFileJpeg(PillowTestCase): @unittest.skipUnless(djpeg_available(), "djpeg not available") def test_load_djpeg(self): - img = Image.open(test_file) + img = Image.open(TEST_FILE) img.load_djpeg() - self.assert_image_similar(img, Image.open(test_file), 0) + self.assert_image_similar(img, Image.open(TEST_FILE), 0) @unittest.skipUnless(cjpeg_available(), "cjpeg not available") def test_save_cjpeg(self): - img = Image.open(test_file) + img = Image.open(TEST_FILE) tempfile = self.tempfile("temp.jpg") JpegImagePlugin._save_cjpeg(img, 0, tempfile) # Default save quality is 75%, so a tiny bit of difference is alright - self.assert_image_similar(img, Image.open(tempfile), 1) + self.assert_image_similar(img, Image.open(tempfile), 15) def test_no_duplicate_0x1001_tag(self): # Arrange diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index a4b6fbb31..e05bdcb20 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -1,4 +1,4 @@ -from helper import unittest, PillowTestCase, lena +from helper import unittest, PillowTestCase, hopper, lena from PIL import Image @@ -38,36 +38,36 @@ class TestImageCms(PillowTestCase): # internal version number self.assertRegexpMatches(ImageCms.core.littlecms_version, "\d+\.\d+$") - i = ImageCms.profileToProfile(lena(), SRGB, SRGB) + i = ImageCms.profileToProfile(hopper(), SRGB, SRGB) self.assert_image(i, "RGB", (128, 128)) - i = lena() + i = hopper() ImageCms.profileToProfile(i, SRGB, SRGB, inPlace=True) self.assert_image(i, "RGB", (128, 128)) t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB") - i = ImageCms.applyTransform(lena(), t) + i = ImageCms.applyTransform(hopper(), t) self.assert_image(i, "RGB", (128, 128)) - i = lena() + i = hopper() t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB") - ImageCms.applyTransform(lena(), t, inPlace=True) + ImageCms.applyTransform(hopper(), t, inPlace=True) self.assert_image(i, "RGB", (128, 128)) p = ImageCms.createProfile("sRGB") o = ImageCms.getOpenProfile(SRGB) t = ImageCms.buildTransformFromOpenProfiles(p, o, "RGB", "RGB") - i = ImageCms.applyTransform(lena(), t) + i = ImageCms.applyTransform(hopper(), t) self.assert_image(i, "RGB", (128, 128)) t = ImageCms.buildProofTransform(SRGB, SRGB, SRGB, "RGB", "RGB") self.assertEqual(t.inputMode, "RGB") self.assertEqual(t.outputMode, "RGB") - i = ImageCms.applyTransform(lena(), t) + i = ImageCms.applyTransform(hopper(), t) self.assert_image(i, "RGB", (128, 128)) # test PointTransform convenience API - lena().point(t) + hopper().point(t) def test_name(self): # get profile information for file @@ -132,7 +132,7 @@ class TestImageCms(PillowTestCase): # the procedural pyCMS API uses PyCMSError for all sorts of errors self.assertRaises( ImageCms.PyCMSError, - lambda: ImageCms.profileToProfile(lena(), "foo", "bar")) + lambda: ImageCms.profileToProfile(hopper(), "foo", "bar")) self.assertRaises( ImageCms.PyCMSError, lambda: ImageCms.buildTransform("foo", "bar", "RGB", "RGB")) @@ -211,14 +211,14 @@ class TestImageCms(PillowTestCase): t2 = ImageCms.buildTransform(pLab, SRGB, "LAB", "RGB") - i = ImageCms.applyTransform(lena(), t) + i = ImageCms.applyTransform(hopper(), t) self.assertEqual(i.info['icc_profile'], ImageCmsProfile(pLab).tobytes()) out = ImageCms.applyTransform(i, t2) - self.assert_image_similar(lena(), out, 2) + self.assert_image_similar(hopper(), out, 2) def test_profile_tobytes(self): from io import BytesIO @@ -235,7 +235,6 @@ class TestImageCms(PillowTestCase): self.assertEqual(ImageCms.getProfileDescription(p), ImageCms.getProfileDescription(p2)) - if __name__ == '__main__': unittest.main() diff --git a/Tests/test_imagewin.py b/Tests/test_imagewin.py index 2609beaf6..6fb58a0dc 100644 --- a/Tests/test_imagewin.py +++ b/Tests/test_imagewin.py @@ -1,16 +1,123 @@ -from helper import unittest, PillowTestCase +from helper import unittest, PillowTestCase, hopper -from PIL import Image from PIL import ImageWin +import sys class TestImageWin(PillowTestCase): def test_sanity(self): - dir(Image) dir(ImageWin) pass + def test_hdc(self): + # Arrange + dc = 50 + + # Act + hdc = ImageWin.HDC(dc) + dc2 = int(hdc) + + # Assert + self.assertEqual(dc2, 50) + + def test_hwnd(self): + # Arrange + wnd = 50 + + # Act + hwnd = ImageWin.HWND(wnd) + wnd2 = int(hwnd) + + # Assert + self.assertEqual(wnd2, 50) + + +@unittest.skipUnless(sys.platform.startswith('win32'), "Windows only") +class TestImageWinDib(PillowTestCase): + + def test_dib_image(self): + # Arrange + im = hopper() + + # Act + dib = ImageWin.Dib(im) + + # Assert + self.assertEqual(dib.size, im.size) + + def test_dib_mode_string(self): + # Arrange + mode = "RGBA" + size = (128, 128) + + # Act + dib = ImageWin.Dib(mode, size) + + # Assert + self.assertEqual(dib.size, (128, 128)) + + def test_dib_paste(self): + # Arrange + im = hopper() + + mode = "RGBA" + size = (128, 128) + dib = ImageWin.Dib(mode, size) + + # Act + dib.paste(im) + + # Assert + self.assertEqual(dib.size, (128, 128)) + + def test_dib_paste_bbox(self): + # Arrange + im = hopper() + bbox = (0, 0, 10, 10) + + mode = "RGBA" + size = (128, 128) + dib = ImageWin.Dib(mode, size) + + # Act + dib.paste(im, bbox) + + # Assert + self.assertEqual(dib.size, (128, 128)) + + def test_dib_frombytes_tobytes_roundtrip(self): + # Arrange + # Make two different DIB images + im = hopper() + dib1 = ImageWin.Dib(im) + + mode = "RGB" + size = (128, 128) + dib2 = ImageWin.Dib(mode, size) + + # Confirm they're different + self.assertNotEqual(dib1.tobytes(), dib2.tobytes()) + + # Act + # Make one the same as the using tobytes()/frombytes() + buffer = dib1.tobytes() + dib2.frombytes(buffer) + + # Assert + # Confirm they're the same + self.assertEqual(dib1.tobytes(), dib2.tobytes()) + + def test_dib_fromstring_tostring_deprecated(self): + # Arrange + im = hopper() + dib = ImageWin.Dib(im) + buffer = dib.tobytes() + + # Act/Assert + self.assert_warning(DeprecationWarning, lambda: dib.tostring()) + self.assert_warning(DeprecationWarning, lambda: dib.fromstring(buffer)) + if __name__ == '__main__': unittest.main() diff --git a/Tests/test_mode_i16.py b/Tests/test_mode_i16.py index 9a0f6956c..20e39b235 100644 --- a/Tests/test_mode_i16.py +++ b/Tests/test_mode_i16.py @@ -5,7 +5,7 @@ from PIL import Image class TestModeI16(PillowTestCase): - original = lena().resize((32, 32)).convert('I') + original = hopper().resize((32, 32)).convert('I') def verify(self, im1): im2 = self.original.copy() diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 11666dd0b..249543004 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -135,6 +135,7 @@ ITU-R 709, using the D65 luminant) to the CIE XYZ color space: .. automethod:: PIL.Image.Image.tell .. automethod:: PIL.Image.Image.thumbnail .. automethod:: PIL.Image.Image.tobitmap +.. automethod:: PIL.Image.Image.tobytes .. automethod:: PIL.Image.Image.tostring .. automethod:: PIL.Image.Image.transform .. automethod:: PIL.Image.Image.transpose diff --git a/libImaging/JpegEncode.c b/libImaging/JpegEncode.c index 711b201e0..dcb2e1151 100644 --- a/libImaging/JpegEncode.c +++ b/libImaging/JpegEncode.c @@ -151,7 +151,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) if (context->quality > 0) { quality = context->quality; } - for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int); i++) { + for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int *); i++) { // TODO: Should add support for none baseline jpeg_add_quant_table(&context->cinfo, i, context->qtables[i], quality, TRUE);