From 4e69b9c5531b3308725e023ce77e1574608451d4 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 4 Jan 2018 20:46:04 +1100 Subject: [PATCH 01/33] Skip outline if the draw operation fills with the same colour --- src/PIL/ImageDraw.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 89df27338..80a9f6023 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -138,7 +138,7 @@ class ImageDraw(object): ink, fill = self._getink(outline, fill) if fill is not None: self.draw.draw_chord(xy, start, end, fill, 1) - if ink is not None: + if ink is not None and ink != fill: self.draw.draw_chord(xy, start, end, ink, 0) def ellipse(self, xy, fill=None, outline=None): @@ -146,7 +146,7 @@ class ImageDraw(object): ink, fill = self._getink(outline, fill) if fill is not None: self.draw.draw_ellipse(xy, fill, 1) - if ink is not None: + if ink is not None and ink != fill: self.draw.draw_ellipse(xy, ink, 0) def line(self, xy, fill=None, width=0): @@ -161,7 +161,7 @@ class ImageDraw(object): ink, fill = self._getink(outline, fill) if fill is not None: self.draw.draw_outline(shape, fill, 1) - if ink is not None: + if ink is not None and ink != fill: self.draw.draw_outline(shape, ink, 0) def pieslice(self, xy, start, end, fill=None, outline=None): @@ -169,7 +169,7 @@ class ImageDraw(object): ink, fill = self._getink(outline, fill) if fill is not None: self.draw.draw_pieslice(xy, start, end, fill, 1) - if ink is not None: + if ink is not None and ink != fill: self.draw.draw_pieslice(xy, start, end, ink, 0) def point(self, xy, fill=None): @@ -183,7 +183,7 @@ class ImageDraw(object): ink, fill = self._getink(outline, fill) if fill is not None: self.draw.draw_polygon(xy, fill, 1) - if ink is not None: + if ink is not None and ink != fill: self.draw.draw_polygon(xy, ink, 0) def rectangle(self, xy, fill=None, outline=None): @@ -191,7 +191,7 @@ class ImageDraw(object): ink, fill = self._getink(outline, fill) if fill is not None: self.draw.draw_rectangle(xy, fill, 1) - if ink is not None: + if ink is not None and ink != fill: self.draw.draw_rectangle(xy, ink, 0) def _multiline_check(self, text): From 4d3339b70376a25158156130a27788fdde6bf114 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 5 Jan 2018 11:26:24 +1100 Subject: [PATCH 02/33] Added tests --- Tests/images/imagedraw_outline_chord_L.png | Bin 0 -> 212 bytes Tests/images/imagedraw_outline_chord_RGB.png | Bin 0 -> 259 bytes Tests/images/imagedraw_outline_ellipse_L.png | Bin 0 -> 290 bytes .../images/imagedraw_outline_ellipse_RGB.png | Bin 0 -> 378 bytes Tests/images/imagedraw_outline_pieslice_L.png | Bin 0 -> 266 bytes .../images/imagedraw_outline_pieslice_RGB.png | Bin 0 -> 340 bytes Tests/images/imagedraw_outline_polygon_L.png | Bin 0 -> 309 bytes .../images/imagedraw_outline_polygon_RGB.png | Bin 0 -> 393 bytes .../images/imagedraw_outline_rectangle_L.png | Bin 0 -> 125 bytes .../imagedraw_outline_rectangle_RGB.png | Bin 0 -> 212 bytes Tests/images/imagedraw_outline_shape_L.png | Bin 0 -> 263 bytes Tests/images/imagedraw_outline_shape_RGB.png | Bin 0 -> 316 bytes Tests/test_imagedraw.py | 41 ++++++++++++++++++ 13 files changed, 41 insertions(+) create mode 100644 Tests/images/imagedraw_outline_chord_L.png create mode 100644 Tests/images/imagedraw_outline_chord_RGB.png create mode 100644 Tests/images/imagedraw_outline_ellipse_L.png create mode 100644 Tests/images/imagedraw_outline_ellipse_RGB.png create mode 100644 Tests/images/imagedraw_outline_pieslice_L.png create mode 100644 Tests/images/imagedraw_outline_pieslice_RGB.png create mode 100644 Tests/images/imagedraw_outline_polygon_L.png create mode 100644 Tests/images/imagedraw_outline_polygon_RGB.png create mode 100644 Tests/images/imagedraw_outline_rectangle_L.png create mode 100644 Tests/images/imagedraw_outline_rectangle_RGB.png create mode 100644 Tests/images/imagedraw_outline_shape_L.png create mode 100644 Tests/images/imagedraw_outline_shape_RGB.png diff --git a/Tests/images/imagedraw_outline_chord_L.png b/Tests/images/imagedraw_outline_chord_L.png new file mode 100644 index 0000000000000000000000000000000000000000..9c20ad217141450ac3ffd9bc6e6a6ae6e9ea6aeb GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^DIm-NBp5yWGui7$e$$~yckOl^Z2bE%#>1V}nANd-;FQjjRdFu*)*UA1hi7_Ad zl>B|;_m1=Av(OO#_bORSSFN@F7<}qfT1=i-ta-hE+ikDlt7VUtl$ieN`Je6g`=99? z+m+#lQKeRrp~mMd&I(L@R4bl$BC_xAYBt5=bN-aDF)$psTJ~?Z(DfyH1+pN!Jzf1= J);T3K0RW^dR@wjn literal 0 HcmV?d00001 diff --git a/Tests/images/imagedraw_outline_chord_RGB.png b/Tests/images/imagedraw_outline_chord_RGB.png new file mode 100644 index 0000000000000000000000000000000000000000..9e9cb5af006f84b806867b586948cd1b21e668c3 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^DImsV8LPK9oMvXgoV7CaQ=eTc7-)eiJ}~<9U@pyZkS}A z?YBW|Zm7bVrhB_G+MWc>3G3t24hJGrTi3{Qkas zk*s?Y&zgt7?t44ebY}SXxZ?E8zs~l>Jv+<8?pGd@`_ZPYeLE>!>hpP}%GfvGe!T0y qVis0&X!^-0`z2*w3n5NBuy-$G&o4H|_cdiRKq8*5elF{r5}E)|>1!?k literal 0 HcmV?d00001 diff --git a/Tests/images/imagedraw_outline_ellipse_L.png b/Tests/images/imagedraw_outline_ellipse_L.png new file mode 100644 index 0000000000000000000000000000000000000000..53b76b62b4210515d1dc2901d7b6fc59116ac085 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^DIm-NBp5A0m|KGp8*o2aut|H!8*U{VQ;_tq~xSue{b)7#QE5%iKTOT$UNRNqW%)$m2rRnyit4Zk@Z>VkeA7@=s zH?o?QU%M;G+vmI*{|DQM)%GhdlXg)SKC&ew24b8@vT8jr(DqFt!C>3zCMszcS<|_y6tKO>1#*lz3%tFmJ;_esyMy# zAFFk7&(7+wcQ(o5H3$8}-gm@ip8fx9?FQpL`4z|9_nZWUDi9Q~KRzKBoyz#e9K`c< L^>bP0l+XkKcy*%w literal 0 HcmV?d00001 diff --git a/Tests/images/imagedraw_outline_pieslice_L.png b/Tests/images/imagedraw_outline_pieslice_L.png new file mode 100644 index 0000000000000000000000000000000000000000..92972d54cc927111bbf41eb7b793e277493f04f4 GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^DIm-NBp5b!~gswEzg%q zKMH)+k$h50pn8Vbk)SGp#cD3{OS6SSZ)WcN68K9kaLV3k*@8y#>+h;XHv3%9-tFli z=dAQ!_OeHer*3%2$=JyYChhrPs9IhAH)vVWFR{KelkTfCF5Mux{#4A`Hx=J?mL?xv zedXLb!=HD$)>Nkd(UJ!w#Kfx%vWm%ZX&Ot)Nb2YJ%d L)z4*}Q$iB}XDe~C literal 0 HcmV?d00001 diff --git a/Tests/images/imagedraw_outline_pieslice_RGB.png b/Tests/images/imagedraw_outline_pieslice_RGB.png new file mode 100644 index 0000000000000000000000000000000000000000..4be4fc4afbbf34a16d3278dd597362399de0ed76 GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^DIm&5H; z{@dSfz0e!R<9qB$;rUCw4<|7moCs781Kan`lY4Ndtm0DQ1wP|B7RP>76+EikxbIs3 zzqo(LOm6R8*2#AK*4j6wcGJYZ6?H5Pb-$!?ZQZWvp*o`9i@HNk8HC*}k~|g^seeAg zH77Y#XL_!V=$E3tseKWQ&o&nMFREMyKPBPFi`quD5e3+g`P!L3_gU?k8^i@}ll+ z_tNK8y**2-_gc9V a4ov0$CN31iGq1x9B8V+ZHr4o!2_x3LISRL{{F=aV--xaT)lN`S2 z@dRmX^;diu>+8-ZXzr%8@zO;drP75H9WrC(BHz8)&B?LfkaedPgQjARIPcE@0e_cs zyBGRtIpzAe-Q#k5dE$@#M+@QmdNRigLFl=ACF7Ud`XLHo5-y0C-!{qq_sP3SSDtguyUKhLrxanERCzpkvl6tx^<$`v0V_$^Pi>Zq=r#-7u zJ@>YI>EG{HrM%znEjnI$JSchn7f0reTfSA#>0J6NPV~Hd_tMtyrjp*Nd%NVUWxQ9v z%eI@gsru^G?Hx<^nCt8fo*r@QgRRujOQq{y-HF@yq&B{6qsZH<0XGe&ox8v1xtwqE z$xqc^dYATBZ%y6Wr@HxfQUB8YRi)Qr1iasOo7}(K7xC$b-1Q@uyx0G$nVod<@xEz4 im;En?hYbTmgYy1woJ>=gBP$PrL_J;oT-G@yGywpHPr0xF literal 0 HcmV?d00001 diff --git a/Tests/images/imagedraw_outline_rectangle_L.png b/Tests/images/imagedraw_outline_rectangle_L.png new file mode 100644 index 0000000000000000000000000000000000000000..b9c47018fb435b7916a92051c6e3b78046c1828f GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^DIm-NBp5?LEc!(!8PgVbG9L%=Jzf1= J);T3K0RX!!He~<+ literal 0 HcmV?d00001 diff --git a/Tests/images/imagedraw_outline_shape_L.png b/Tests/images/imagedraw_outline_shape_L.png new file mode 100644 index 0000000000000000000000000000000000000000..20ebef1578cf9c919e8d4e6094bf231a5abe6fcb GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^DIm-NBp5zi$2M z)W*M`SRXD_+qQh}&ybT(n2IJm(4VQ|x!%HYlF9L@_Z>d1og@-wpF1g`&QEBoMy7se z>ck^1p6;F+t5uXv1$};~`$j%>?T;_#U&yAeHlOWZD=TlY+h*~bY~P#K%d1asyj!!Y z=1@xLCzT?OV3RDJKX(nDRw#GowQh{svi-wXgJ&MroqBC6O~R+fTnPDWuCmpeZO%lsV=7B^-+ki&`2`Bz?O_zrmzLe!>j?5DgQu&X%Q~lo FCIBt_Yasvt literal 0 HcmV?d00001 diff --git a/Tests/images/imagedraw_outline_shape_RGB.png b/Tests/images/imagedraw_outline_shape_RGB.png new file mode 100644 index 0000000000000000000000000000000000000000..6fb6f623e4b01621b35cb6e939343f1386734036 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^DImziq!6ST9>6{ZG7haGT> z+}x`@zq~r~^OvnNucS(BSiMH_*jDxAHSLQ3f8UIEd}Ab&pR~}0{V~76M&^_J_a0Qw zzp?T2eBZlwkDOz%`+arc`p&sFxf?h1`mgagcj$D+hD}YJ+Hr2?V&R&hU#rg@of>*J z`0w_IQ~eumy)XTGdCiXtZodqejBL$HynsGO1<$@QZZzczjaa`hA0*-F>gTe~DWM4f DE;olO literal 0 HcmV?d00001 diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index a79a75ca0..62b11e98c 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -572,6 +572,47 @@ class TestImageDraw(PillowTestCase): draw.textsize("\n") draw.textsize("test\n") + def test_same_color_outline(self): + # Prepare shape + x0, y0 = 5, 5 + x1, y1 = 5, 50 + x2, y2 = 95, 50 + x3, y3 = 95, 5 + + s = ImageDraw.Outline() + s.move(x0, y0) + s.curve(x1, y1, x2, y2, x3, y3) + s.line(x0, y0) + + # Begin + for mode in ["RGB", "L"]: + for fill, outline in [ + ["red", None], + ["red", "red"], + ["red", "#f00"] + ]: + for operation, args in { + 'chord':[BBOX1, 0, 180], + 'ellipse':[BBOX1], + 'shape':[s], + 'pieslice':[BBOX1, -90, 45], + 'polygon':[[(18, 30), (85, 30), (60, 72)]], + 'rectangle':[BBOX1] + }.items(): + # Arrange + im = Image.new(mode, (W, H)) + draw = ImageDraw.Draw(im) + + # Act + draw_method = getattr(draw, operation) + args += [fill, outline] + draw_method(*args) + + # Assert + expected = ("Tests/images/imagedraw_outline" + "_{}_{}.png".format(operation, mode)) + self.assert_image_similar(im, Image.open(expected), 1) + if __name__ == '__main__': unittest.main() From 1ba14783d25bfb3dd3df7c5f0e62e1f900a79b78 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Tue, 1 Nov 2016 06:16:44 -0700 Subject: [PATCH 03/33] Avoid deprecated 'U' mode when opening files Instead, use PSFile() wrapper to handle all newline in the EPS spec. Update line ending tests to handle all combinations of '\n' and '\r'. Fixes warning "DeprecationWarning: 'U' mode is deprecated" in tests. --- Tests/test_file_eps.py | 56 +++++---------------------------------- src/PIL/EpsImagePlugin.py | 12 +-------- 2 files changed, 7 insertions(+), 61 deletions(-) diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index 9d6bed060..66fedee90 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -1,7 +1,6 @@ from helper import unittest, PillowTestCase, hopper from PIL import Image, EpsImagePlugin -from PIL._util import py3 import io # Our two EPS test files (they are identical except for their bounding boxes) @@ -196,41 +195,15 @@ class TestFileEps(PillowTestCase): self.assertEqual(t.readline().strip('\r\n'), 'baz', ending) self.assertEqual(t.readline().strip('\r\n'), 'bif', ending) - def _test_readline_stringio(self, test_string, ending): - # check all the freaking line endings possible - try: - import StringIO - except ImportError: - # don't skip, it skips everything in the parent test - return - t = StringIO.StringIO(test_string) + def _test_readline_io_psfile(self, test_string, ending): + f = io.BytesIO(test_string.encode('latin-1')) + t = EpsImagePlugin.PSFile(f) self._test_readline(t, ending) - def _test_readline_io(self, test_string, ending): - if py3: - t = io.StringIO(test_string) - else: - t = io.StringIO(unicode(test_string)) - self._test_readline(t, ending) - - def _test_readline_file_universal(self, test_string, ending): - f = self.tempfile('temp.txt') - with open(f, 'wb') as w: - if py3: - w.write(test_string.encode('UTF-8')) - else: - w.write(test_string) - - with open(f, 'rU') as t: - self._test_readline(t, ending) - def _test_readline_file_psfile(self, test_string, ending): f = self.tempfile('temp.txt') with open(f, 'wb') as w: - if py3: - w.write(test_string.encode('UTF-8')) - else: - w.write(test_string) + w.write(test_string.encode('latin-1')) with open(f, 'rb') as r: t = EpsImagePlugin.PSFile(r) @@ -239,29 +212,12 @@ class TestFileEps(PillowTestCase): def test_readline(self): # check all the freaking line endings possible from the spec # test_string = u'something\r\nelse\n\rbaz\rbif\n' - line_endings = ['\r\n', '\n'] - not_working_endings = ['\n\r', '\r'] + line_endings = ['\r\n', '\n', '\n\r', '\r'] strings = ['something', 'else', 'baz', 'bif'] for ending in line_endings: s = ending.join(strings) - # Native Python versions will pass these endings. - # self._test_readline_stringio(s, ending) - # self._test_readline_io(s, ending) - # self._test_readline_file_universal(s, ending) - - self._test_readline_file_psfile(s, ending) - - for ending in not_working_endings: - # these only work with the PSFile, while they're in spec, - # they're not likely to be used - s = ending.join(strings) - - # Native Python versions may fail on these endings. - # self._test_readline_stringio(s, ending) - # self._test_readline_io(s, ending) - # self._test_readline_file_universal(s, ending) - + self._test_readline_io_psfile(s, ending) self._test_readline_file_psfile(s, ending) def test_open_eps(self): diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index 1ae7865b1..cb2c00d20 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -26,7 +26,6 @@ import os import sys from . import Image, ImageFile from ._binary import i32le as i32 -from ._util import py3 __version__ = "0.5" @@ -206,16 +205,7 @@ class EpsImageFile(ImageFile.ImageFile): # Rewrap the open file pointer in something that will # convert line endings and decode to latin-1. - try: - if py3: - # Python3, can use bare open command. - fp = open(self.fp.name, "Ur", encoding='latin-1') - else: - # Python2, no encoding conversion necessary - fp = open(self.fp.name, "Ur") - except: - # Expect this for bytesio/stringio - fp = PSFile(self.fp) + fp = PSFile(self.fp) # go to offset - start of "%!PS" fp.seek(offset) From adfcbc94787a9f17c96f6da4fe61353f240d2d60 Mon Sep 17 00:00:00 2001 From: Daniel Plakhotich Date: Mon, 2 Jul 2018 00:50:02 +0300 Subject: [PATCH 04/33] Add LA to TGA test modes --- Tests/test_file_tga.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py index c7e8ab71b..226b899dc 100644 --- a/Tests/test_file_tga.py +++ b/Tests/test_file_tga.py @@ -13,7 +13,7 @@ _TGA_DIR_COMMON = os.path.join(_TGA_DIR, "common") class TestFileTga(PillowTestCase): - _MODES = ("L", "P", "RGB", "RGBA") + _MODES = ("L", "LA", "P", "RGB", "RGBA") _ORIGINS = ("tl", "bl") _ORIGIN_TO_ORIENTATION = { From bf299602837a050b77ddae3754418619178fad6b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 11 Jun 2018 13:57:19 +1000 Subject: [PATCH 05/33] Fixed multiple spaces after operator --- src/PIL/ImageDraw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 5bc890252..920b977f4 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -384,4 +384,4 @@ def _color_diff(rgb1, rgb2): """ Uses 1-norm distance to calculate difference between two rgb values. """ - return abs(rgb1[0]-rgb2[0]) + abs(rgb1[1]-rgb2[1]) + abs(rgb1[2]-rgb2[2]) + return abs(rgb1[0]-rgb2[0]) + abs(rgb1[1]-rgb2[1]) + abs(rgb1[2]-rgb2[2]) From 5a33e02072f21fe8cdb33bb5b0688368d182befc Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 11 Jun 2018 13:58:28 +1000 Subject: [PATCH 06/33] Commented unused variable --- src/PIL/SunImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/SunImagePlugin.py b/src/PIL/SunImagePlugin.py index fd5e82724..03b266bc4 100644 --- a/src/PIL/SunImagePlugin.py +++ b/src/PIL/SunImagePlugin.py @@ -62,7 +62,7 @@ class SunImageFile(ImageFile.ImageFile): self.size = i32(s[4:8]), i32(s[8:12]) depth = i32(s[12:16]) - data_length = i32(s[16:20]) # unreliable, ignore. + # data_length = i32(s[16:20]) # unreliable, ignore. file_type = i32(s[20:24]) palette_type = i32(s[24:28]) # 0: None, 1: RGB, 2: Raw/arbitrary palette_length = i32(s[28:32]) From fe42591f5f5705e09a9ceccd05c1fedbd4592099 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 11 Jun 2018 13:59:17 +1000 Subject: [PATCH 07/33] Removed redundant backslash between brackets --- src/PIL/PdfParser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index c0635ef31..f63d47eb2 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -824,7 +824,7 @@ class PdfParser: def read_indirect(self, ref, max_nesting=-1): offset, generation = self.xref_table[ref[0]] - check_format_condition(generation == ref[1], "expected to find generation %s for object ID %s in xref table, instead found generation %s at offset %s" \ + check_format_condition(generation == ref[1], "expected to find generation %s for object ID %s in xref table, instead found generation %s at offset %s" % (ref[1], ref[0], generation, offset)) value = self.get_value(self.buf, offset + self.start_offset, expect_indirect=IndirectReference(*ref), max_nesting=max_nesting)[0] self.cached_objects[ref] = value From e7815ccd621016c16d0ab296fa7906c710ad8983 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 15 Jun 2018 19:40:04 +1000 Subject: [PATCH 08/33] Block comment should start with '# ' --- Tests/test_imagefont.py | 2 +- Tests/test_imagefontctl.py | 2 +- src/PIL/PdfParser.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 0a36734d2..906f7b06f 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -413,7 +413,7 @@ class TestImageFont(PillowTestCase): im = Image.new(mode='RGB', size=(300, 100)) target = im.copy() draw = ImageDraw.Draw(im) - #should not crash here. + # should not crash here. draw.text((10, 10), '', font=font) self.assert_image_equal(im, target) diff --git a/Tests/test_imagefontctl.py b/Tests/test_imagefontctl.py index 89f9563f3..489ed40b5 100644 --- a/Tests/test_imagefontctl.py +++ b/Tests/test_imagefontctl.py @@ -11,7 +11,7 @@ FONT_PATH = "Tests/fonts/DejaVuSans.ttf" class TestImagecomplextext(PillowTestCase): def test_english(self): - #smoke test, this should not fail + # smoke test, this should not fail ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) im = Image.new(mode='RGB', size=(300, 100)) draw = ImageDraw.Draw(im) diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index f63d47eb2..9031330da 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -744,7 +744,7 @@ class PdfParser: m = cls.re_string_lit.match(data, offset) if m: return cls.get_literal_string(data, m.end()) - #return None, offset # fallback (only for debugging) + # return None, offset # fallback (only for debugging) raise PdfFormatError("unrecognized object: " + repr(data[offset:offset+32])) re_lit_str_token = re.compile(br"(\\[nrtbf()\\])|(\\[0-9]{1,3})|(\\(\r\n|\r|\n))|(\r\n|\r|\n)|(\()|(\))") From 58cc23695d29b58d5329a29c7b5b25ae5c620805 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 15 Jun 2018 19:37:33 +1000 Subject: [PATCH 09/33] Continuation line over-indented for visual indent --- Tests/test_imagefont.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 906f7b06f..e333346e9 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -210,10 +210,9 @@ class TestImageFont(PillowTestCase): ttf = self.get_font() # Act/Assert - self.assertRaises(AssertionError, - draw.multiline_text, (0, 0), TEST_TEXT, - font=ttf, - align="unknown") + self.assertRaises( + AssertionError, + draw.multiline_text, (0, 0), TEST_TEXT, font=ttf, align="unknown") def test_draw_align(self): im = Image.new('RGB', (300, 100), 'white') From aeab86c005bd5d710c34bb5874865d248da63b18 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 11 Jun 2018 15:51:12 +1000 Subject: [PATCH 10/33] Too many blank lines --- Tests/test_file_jpeg.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 2d9a9a091..c42d67885 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -364,7 +364,6 @@ class TestFileJpeg(PillowTestCase): with self.assertRaises(IOError): im.load() - def _n_qtables_helper(self, n, test_file): im = Image.open(test_file) f = self.tempfile('temp.jpg') From dcf6bc047b3f2e1ea180b921e1e9b58fb37032e0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 11 Jun 2018 16:00:57 +1000 Subject: [PATCH 11/33] Do not use bare except --- Tests/test_file_libtiff.py | 4 ++-- Tests/test_locale.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 05433d9b6..ce77e05de 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -31,7 +31,7 @@ class LibTiffTestCase(PillowTestCase): try: self.assertEqual(im._compression, 'group4') - except: + except AttributeError: print("No _compression") print(dir(im)) @@ -194,7 +194,7 @@ class TestFileLibTiff(LibTiffTestCase): for tag in im.tag_v2: try: del(core_items[tag]) - except: + except KeyError: pass # Type codes: diff --git a/Tests/test_locale.py b/Tests/test_locale.py index 142753791..5aef8427b 100644 --- a/Tests/test_locale.py +++ b/Tests/test_locale.py @@ -29,7 +29,7 @@ class TestLocale(PillowTestCase): Image.open(path) try: locale.setlocale(locale.LC_ALL, "polish") - except: + except locale.Error: unittest.skip('Polish locale not available') Image.open(path) From 32cebddd1ee185e807ab758afcafd82d29e6a309 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 13 Jun 2018 19:44:36 +1000 Subject: [PATCH 12/33] Multiple imports on one line --- src/PIL/_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PIL/_util.py b/src/PIL/_util.py index 6618c625f..e6989d69d 100644 --- a/src/PIL/_util.py +++ b/src/PIL/_util.py @@ -1,4 +1,5 @@ -import os, sys +import os +import sys py3 = sys.version_info.major >= 3 From c19d77abed4919791e9e5d9a362af8a73856e9cf Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 16 Jun 2018 10:06:45 +1000 Subject: [PATCH 13/33] Continuation line under-indented for visual indent --- Tests/test_color_lut.py | 148 +++++++++++++++++++---------------- Tests/test_image_resample.py | 4 +- 2 files changed, 82 insertions(+), 70 deletions(-) diff --git a/Tests/test_color_lut.py b/Tests/test_color_lut.py index c9793c950..e641c5ad3 100644 --- a/Tests/test_color_lut.py +++ b/Tests/test_color_lut.py @@ -38,112 +38,123 @@ class TestColorLut3DCoreAPI(PillowTestCase): im = Image.new('RGB', (10, 10), 0) with self.assertRaisesRegex(ValueError, "filter"): - im.im.color_lut_3d('RGB', Image.CUBIC, - *self.generate_identity_table(3, 3)) + im.im.color_lut_3d('RGB', + Image.CUBIC, + *self.generate_identity_table(3, 3)) with self.assertRaisesRegex(ValueError, "image mode"): - im.im.color_lut_3d('wrong', Image.LINEAR, - *self.generate_identity_table(3, 3)) + im.im.color_lut_3d('wrong', + Image.LINEAR, + *self.generate_identity_table(3, 3)) with self.assertRaisesRegex(ValueError, "table_channels"): - im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(5, 3)) + im.im.color_lut_3d('RGB', + Image.LINEAR, + *self.generate_identity_table(5, 3)) with self.assertRaisesRegex(ValueError, "table_channels"): - im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(1, 3)) + im.im.color_lut_3d('RGB', + Image.LINEAR, + *self.generate_identity_table(1, 3)) with self.assertRaisesRegex(ValueError, "table_channels"): - im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(2, 3)) + im.im.color_lut_3d('RGB', + Image.LINEAR, + *self.generate_identity_table(2, 3)) with self.assertRaisesRegex(ValueError, "Table size"): - im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, (1, 3, 3))) + im.im.color_lut_3d('RGB', + Image.LINEAR, + *self.generate_identity_table(3, (1, 3, 3))) with self.assertRaisesRegex(ValueError, "Table size"): - im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, (66, 3, 3))) + im.im.color_lut_3d('RGB', + Image.LINEAR, + *self.generate_identity_table(3, (66, 3, 3))) with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"): - im.im.color_lut_3d('RGB', Image.LINEAR, - 3, 2, 2, 2, [0, 0, 0] * 7) + im.im.color_lut_3d('RGB', + Image.LINEAR, + 3, 2, 2, 2, [0, 0, 0] * 7) with self.assertRaisesRegex(ValueError, r"size1D \* size2D \* size3D"): - im.im.color_lut_3d('RGB', Image.LINEAR, - 3, 2, 2, 2, [0, 0, 0] * 9) + im.im.color_lut_3d('RGB', + Image.LINEAR, + 3, 2, 2, 2, [0, 0, 0] * 9) with self.assertRaises(TypeError): - im.im.color_lut_3d('RGB', Image.LINEAR, - 3, 2, 2, 2, [0, 0, "0"] * 8) + im.im.color_lut_3d('RGB', + Image.LINEAR, + 3, 2, 2, 2, [0, 0, "0"] * 8) with self.assertRaises(TypeError): - im.im.color_lut_3d('RGB', Image.LINEAR, - 3, 2, 2, 2, 16) + im.im.color_lut_3d('RGB', + Image.LINEAR, + 3, 2, 2, 2, 16) def test_correct_args(self): im = Image.new('RGB', (10, 10), 0) im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, 3)) + *self.generate_identity_table(3, 3)) im.im.color_lut_3d('CMYK', Image.LINEAR, - *self.generate_identity_table(4, 3)) + *self.generate_identity_table(4, 3)) im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, (2, 3, 3))) + *self.generate_identity_table(3, (2, 3, 3))) im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, (65, 3, 3))) + *self.generate_identity_table(3, (65, 3, 3))) im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, (3, 65, 3))) + *self.generate_identity_table(3, (3, 65, 3))) im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, (3, 3, 65))) + *self.generate_identity_table(3, (3, 3, 65))) def test_wrong_mode(self): with self.assertRaisesRegex(ValueError, "wrong mode"): im = Image.new('L', (10, 10), 0) im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, 3)) + *self.generate_identity_table(3, 3)) with self.assertRaisesRegex(ValueError, "wrong mode"): im = Image.new('RGB', (10, 10), 0) im.im.color_lut_3d('L', Image.LINEAR, - *self.generate_identity_table(3, 3)) + *self.generate_identity_table(3, 3)) with self.assertRaisesRegex(ValueError, "wrong mode"): im = Image.new('L', (10, 10), 0) im.im.color_lut_3d('L', Image.LINEAR, - *self.generate_identity_table(3, 3)) + *self.generate_identity_table(3, 3)) with self.assertRaisesRegex(ValueError, "wrong mode"): im = Image.new('RGB', (10, 10), 0) im.im.color_lut_3d('RGBA', Image.LINEAR, - *self.generate_identity_table(3, 3)) + *self.generate_identity_table(3, 3)) with self.assertRaisesRegex(ValueError, "wrong mode"): im = Image.new('RGB', (10, 10), 0) im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(4, 3)) + *self.generate_identity_table(4, 3)) def test_correct_mode(self): im = Image.new('RGBA', (10, 10), 0) im.im.color_lut_3d('RGBA', Image.LINEAR, - *self.generate_identity_table(3, 3)) + *self.generate_identity_table(3, 3)) im = Image.new('RGBA', (10, 10), 0) im.im.color_lut_3d('RGBA', Image.LINEAR, - *self.generate_identity_table(4, 3)) + *self.generate_identity_table(4, 3)) im = Image.new('RGB', (10, 10), 0) im.im.color_lut_3d('HSV', Image.LINEAR, - *self.generate_identity_table(3, 3)) + *self.generate_identity_table(3, 3)) im = Image.new('RGB', (10, 10), 0) im.im.color_lut_3d('RGBA', Image.LINEAR, - *self.generate_identity_table(4, 3)) + *self.generate_identity_table(4, 3)) def test_identities(self): g = Image.linear_gradient('L') @@ -154,12 +165,12 @@ class TestColorLut3DCoreAPI(PillowTestCase): for size in [2, 3, 5, 7, 11, 16, 17]: self.assert_image_equal(im, im._new( im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, size)))) + *self.generate_identity_table(3, size)))) # Not so fast self.assert_image_equal(im, im._new( im.im.color_lut_3d('RGB', Image.LINEAR, - *self.generate_identity_table(3, (2, 2, 65))))) + *self.generate_identity_table(3, (2, 2, 65))))) def test_identities_4_channels(self): g = Image.linear_gradient('L') @@ -170,7 +181,7 @@ class TestColorLut3DCoreAPI(PillowTestCase): self.assert_image_equal( Image.merge('RGBA', (im.split()*2)[:4]), im._new(im.im.color_lut_3d('RGBA', Image.LINEAR, - *self.generate_identity_table(4, 17)))) + *self.generate_identity_table(4, 17)))) def test_copy_alpha_channel(self): g = Image.linear_gradient('L') @@ -180,7 +191,7 @@ class TestColorLut3DCoreAPI(PillowTestCase): self.assert_image_equal(im, im._new( im.im.color_lut_3d('RGBA', Image.LINEAR, - *self.generate_identity_table(3, 17)))) + *self.generate_identity_table(3, 17)))) def test_channels_order(self): g = Image.linear_gradient('L') @@ -191,13 +202,13 @@ class TestColorLut3DCoreAPI(PillowTestCase): self.assert_image_equal( Image.merge('RGB', im.split()[::-1]), im._new(im.im.color_lut_3d('RGB', Image.LINEAR, - 3, 2, 2, 2, [ - 0, 0, 0, 0, 0, 1, - 0, 1, 0, 0, 1, 1, + 3, 2, 2, 2, [ + 0, 0, 0, 0, 0, 1, + 0, 1, 0, 0, 1, 1, - 1, 0, 0, 1, 0, 1, - 1, 1, 0, 1, 1, 1, - ]))) + 1, 0, 0, 1, 0, 1, + 1, 1, 0, 1, 1, 1, + ]))) def test_overflow(self): g = Image.linear_gradient('L') @@ -205,14 +216,14 @@ class TestColorLut3DCoreAPI(PillowTestCase): g.transpose(Image.ROTATE_180)]) transformed = im._new(im.im.color_lut_3d('RGB', Image.LINEAR, - 3, 2, 2, 2, - [ - -1, -1, -1, 2, -1, -1, - -1, 2, -1, 2, 2, -1, + 3, 2, 2, 2, + [ + -1, -1, -1, 2, -1, -1, + -1, 2, -1, 2, 2, -1, - -1, -1, 2, 2, -1, 2, - -1, 2, 2, 2, 2, 2, - ])).load() + -1, -1, 2, 2, -1, 2, + -1, 2, 2, 2, 2, 2, + ])).load() self.assertEqual(transformed[0, 0], (0, 0, 255)) self.assertEqual(transformed[50, 50], (0, 0, 255)) self.assertEqual(transformed[255, 0], (0, 255, 255)) @@ -223,14 +234,14 @@ class TestColorLut3DCoreAPI(PillowTestCase): self.assertEqual(transformed[205, 205], (255, 255, 0)) transformed = im._new(im.im.color_lut_3d('RGB', Image.LINEAR, - 3, 2, 2, 2, - [ - -3, -3, -3, 5, -3, -3, - -3, 5, -3, 5, 5, -3, + 3, 2, 2, 2, + [ + -3, -3, -3, 5, -3, -3, + -3, 5, -3, 5, 5, -3, - -3, -3, 5, 5, -3, 5, - -3, 5, 5, 5, 5, 5, - ])).load() + -3, -3, 5, 5, -3, 5, + -3, 5, 5, 5, 5, 5, + ])).load() self.assertEqual(transformed[0, 0], (0, 0, 255)) self.assertEqual(transformed[50, 50], (0, 0, 255)) self.assertEqual(transformed[255, 0], (0, 255, 255)) @@ -366,22 +377,23 @@ class TestColorLut3DFilter(PillowTestCase): lut = ImageFilter.Color3DLUT( (3, 4, 5), array('f', [0, 0, 0, 0] * (3 * 4 * 5)), channels=4, target_mode='YCbCr', _copy_table=False) - self.assertEqual(repr(lut), + self.assertEqual( + repr(lut), "") class TestGenerateColorLut3D(PillowTestCase): def test_wrong_channels_count(self): with self.assertRaisesRegex(ValueError, "3 or 4 output channels"): - ImageFilter.Color3DLUT.generate(5, channels=2, - callback=lambda r, g, b: (r, g, b)) + ImageFilter.Color3DLUT.generate( + 5, channels=2, callback=lambda r, g, b: (r, g, b)) with self.assertRaisesRegex(ValueError, "should have either channels"): ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b, r)) with self.assertRaisesRegex(ValueError, "should have either channels"): - ImageFilter.Color3DLUT.generate(5, channels=4, - callback=lambda r, g, b: (r, g, b)) + ImageFilter.Color3DLUT.generate( + 5, channels=4, callback=lambda r, g, b: (r, g, b)) def test_3_channels(self): lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b)) @@ -392,8 +404,8 @@ class TestGenerateColorLut3D(PillowTestCase): 1.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, 0.25, 0.0, 0.5, 0.25, 0.0]) def test_4_channels(self): - lut = ImageFilter.Color3DLUT.generate(5, channels=4, - callback=lambda r, g, b: (b, r, g, (r+g+b) / 2)) + lut = ImageFilter.Color3DLUT.generate( + 5, channels=4, callback=lambda r, g, b: (b, r, g, (r+g+b) / 2)) self.assertEqual(tuple(lut.size), (5, 5, 5)) self.assertEqual(lut.name, "Color 3D LUT") self.assertEqual(lut.table[:24], [ diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index 1ecb6cda6..cf38c2345 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -245,8 +245,8 @@ class CoreResampleAlphaCorrectTest(PillowTestCase): for y in range(i.size[1]): used_colors = {px[x, y][0] for x in range(i.size[0])} self.assertEqual(256, len(used_colors), - 'All colors should present in resized image. ' - 'Only {} on {} line.'.format(len(used_colors), y)) + 'All colors should present in resized image. ' + 'Only {} on {} line.'.format(len(used_colors), y)) @unittest.skip("current implementation isn't precise enough") def test_levels_rgba(self): From 0e61d4be9f4cca7cdd24fe5487b264c7e7af7b8a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 15 Jun 2018 19:55:48 +1000 Subject: [PATCH 14/33] Removed unused variables --- Tests/test_file_libtiff.py | 2 +- src/PIL/GifImagePlugin.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index ce77e05de..4f2f9617e 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -525,7 +525,7 @@ class TestFileLibTiff(LibTiffTestCase): f.write(src.read()) im = Image.open(tmpfile) - count = im.n_frames + im.n_frames im.close() try: os.remove(tmpfile) # Windows PermissionError here! diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 1bfbb5ffd..e0da01129 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -543,7 +543,6 @@ def _write_local_header(fp, im, offset, flags): o8(0)) include_color_table = im.encoderinfo.get('include_color_table') if include_color_table: - palette = im.encoderinfo.get("palette", None) palette_bytes = _get_palette_bytes(im) color_table_size = _get_color_table_size(palette_bytes) if color_table_size: From e7cfa15216436e71ba2b17a006e78d9e4552d1a7 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 15 Jun 2018 23:20:24 +1000 Subject: [PATCH 15/33] Visually indented line with same indent as next logical line --- src/PIL/TiffImagePlugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 6f032f49d..a4f58b5ff 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -577,8 +577,8 @@ class ImageFileDirectory_v2(MutableMapping): # Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed. # No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple. # Don't mess with the legacy api, since it's frozen. - if ((info.length == 1) or - (info.length is None and len(values) == 1 and not legacy_api)): + if (info.length == 1) or \ + (info.length is None and len(values) == 1 and not legacy_api): # Don't mess with the legacy api, since it's frozen. if legacy_api and self.tagtype[tag] in [5, 10]: # rationals values = values, From 145589ef1425765ac1a0080440e18a3a9c5ea3bb Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 15 Jun 2018 23:44:22 +1000 Subject: [PATCH 16/33] Ambiguous variable name 'l' --- Tests/test_image_convert.py | 62 +++++++++++++++++++------------------ Tests/test_imagecms.py | 12 +++---- src/PIL/ContainerIO.py | 6 ++-- src/PIL/ImageStat.py | 4 +-- src/PIL/TiffImagePlugin.py | 10 +++--- 5 files changed, 48 insertions(+), 46 deletions(-) diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index c7c381382..14e634e9c 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -67,13 +67,13 @@ class TestImageConvert(PillowTestCase): f = self.tempfile('temp.png') - l = im.convert('L') - self.assertEqual(l.info['transparency'], 0) # undone - l.save(f) + im_l = im.convert('L') + self.assertEqual(im_l.info['transparency'], 0) # undone + im_l.save(f) - rgb = im.convert('RGB') - self.assertEqual(rgb.info['transparency'], (0, 0, 0)) # undone - rgb.save(f) + im_rgb = im.convert('RGB') + self.assertEqual(im_rgb.info['transparency'], (0, 0, 0)) # undone + im_rgb.save(f) # ref https://github.com/python-pillow/Pillow/issues/664 @@ -83,12 +83,12 @@ class TestImageConvert(PillowTestCase): im.info['transparency'] = 128 # Act - rgba = im.convert('RGBA') + im_rgba = im.convert('RGBA') # Assert - self.assertNotIn('transparency', rgba.info) + self.assertNotIn('transparency', im_rgba.info) # https://github.com/python-pillow/Pillow/issues/2702 - self.assertEqual(rgba.palette, None) + self.assertEqual(im_rgba.palette, None) def test_trns_l(self): im = hopper('L') @@ -96,19 +96,20 @@ class TestImageConvert(PillowTestCase): f = self.tempfile('temp.png') - rgb = im.convert('RGB') - self.assertEqual(rgb.info['transparency'], (128, 128, 128)) # undone - rgb.save(f) + im_rgb = im.convert('RGB') + self.assertEqual(im_rgb.info['transparency'], + (128, 128, 128)) # undone + im_rgb.save(f) - p = im.convert('P') - self.assertIn('transparency', p.info) - p.save(f) + im_p = im.convert('P') + self.assertIn('transparency', im_p.info) + im_p.save(f) - p = self.assert_warning( + im_p = self.assert_warning( UserWarning, im.convert, 'P', palette=Image.ADAPTIVE) - self.assertNotIn('transparency', p.info) - p.save(f) + self.assertNotIn('transparency', im_p.info) + im_p.save(f) def test_trns_RGB(self): im = hopper('RGB') @@ -116,23 +117,24 @@ class TestImageConvert(PillowTestCase): f = self.tempfile('temp.png') - l = im.convert('L') - self.assertEqual(l.info['transparency'], l.getpixel((0, 0))) # undone - l.save(f) + im_l = im.convert('L') + self.assertEqual(im_l.info['transparency'], + im_l.getpixel((0, 0))) # undone + im_l.save(f) - p = im.convert('P') - self.assertIn('transparency', p.info) - p.save(f) + im_p = im.convert('P') + self.assertIn('transparency', im_p.info) + im_p.save(f) - p = im.convert('RGBA') - self.assertNotIn('transparency', p.info) - p.save(f) + im_rgba = im.convert('RGBA') + self.assertNotIn('transparency', im_rgba.info) + im_rgba.save(f) - p = self.assert_warning( + im_p = self.assert_warning( UserWarning, im.convert, 'P', palette=Image.ADAPTIVE) - self.assertNotIn('transparency', p.info) - p.save(f) + self.assertNotIn('transparency', im_p.info) + im_p.save(f) def test_p_la(self): im = hopper('RGBA') diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index 4138f455f..2f4708689 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -196,13 +196,13 @@ class TestImageCms(PillowTestCase): # not a linear luminance map. so L != 128: self.assertEqual(k, (137, 128, 128)) - l = i_lab.getdata(0) - a = i_lab.getdata(1) - b = i_lab.getdata(2) + l_data = i_lab.getdata(0) + a_data = i_lab.getdata(1) + b_data = i_lab.getdata(2) - self.assertEqual(list(l), [137] * 100) - self.assertEqual(list(a), [128] * 100) - self.assertEqual(list(b), [128] * 100) + self.assertEqual(list(l_data), [137] * 100) + self.assertEqual(list(a_data), [128] * 100) + self.assertEqual(list(b_data), [128] * 100) def test_lab_color(self): psRGB = ImageCms.createProfile("sRGB") diff --git a/src/PIL/ContainerIO.py b/src/PIL/ContainerIO.py index 496ed6826..682ad9031 100644 --- a/src/PIL/ContainerIO.py +++ b/src/PIL/ContainerIO.py @@ -107,10 +107,10 @@ class ContainerIO(object): :returns: A list of 8-bit strings. """ - l = [] + lines = [] while True: s = self.readline() if not s: break - l.append(s) - return l + lines.append(s) + return lines diff --git a/src/PIL/ImageStat.py b/src/PIL/ImageStat.py index cd58fc8ff..d4b38d856 100644 --- a/src/PIL/ImageStat.py +++ b/src/PIL/ImageStat.py @@ -110,11 +110,11 @@ class Stat(object): v = [] for i in self.bands: s = 0 - l = self.count[i]//2 + half = self.count[i]//2 b = i * 256 for j in range(256): s = s + self.h[b+j] - if s > l: + if s > half: break v.append(j) return v diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index a4f58b5ff..14b66a1b9 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1245,7 +1245,7 @@ class TiffImageFile(ImageFile.ImageFile): self.info["resolution"] = xres, yres # build tile descriptors - x = y = l = 0 + x = y = layer = 0 self.tile = [] self.use_load_libtiff = False if STRIPOFFSETS in self.tag_v2: @@ -1305,7 +1305,7 @@ class TiffImageFile(ImageFile.ImageFile): else: for i, offset in enumerate(offsets): - a = self._decoder(rawmode, l, i) + a = self._decoder(rawmode, layer, i) self.tile.append( (self._compression, (0, min(y, ysize), w, min(y+h, ysize)), @@ -1315,7 +1315,7 @@ class TiffImageFile(ImageFile.ImageFile): y = y + h if y >= self.size[1]: x = y = 0 - l += 1 + layer += 1 a = None elif TILEOFFSETS in self.tag_v2: # tiled image @@ -1324,7 +1324,7 @@ class TiffImageFile(ImageFile.ImageFile): a = None for o in self.tag_v2[TILEOFFSETS]: if not a: - a = self._decoder(rawmode, l) + a = self._decoder(rawmode, layer) # FIXME: this doesn't work if the image size # is not a multiple of the tile size... self.tile.append( @@ -1336,7 +1336,7 @@ class TiffImageFile(ImageFile.ImageFile): x, y = 0, y + h if y >= self.size[1]: x = y = 0 - l += 1 + layer += 1 a = None else: if DEBUG: From 0832f9c58b6fecf16d4bfc128931cddd5ddb9e7a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 16 Jun 2018 09:10:58 +1000 Subject: [PATCH 17/33] Continuation line unaligned for hanging indent --- Tests/test_color_lut.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/test_color_lut.py b/Tests/test_color_lut.py index e641c5ad3..5a51b279f 100644 --- a/Tests/test_color_lut.py +++ b/Tests/test_color_lut.py @@ -27,8 +27,8 @@ class TestColorLut3DCoreAPI(PillowTestCase): g / float(size2D-1) if size2D != 1 else 0, ][:channels] for b in range(size3D) - for g in range(size2D) - for r in range(size1D) + for g in range(size2D) + for r in range(size1D) ] return ( channels, size1D, size2D, size3D, From ce5d0e72b2d8493c73c6ffaa02171345ad8a16a9 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 24 Jun 2018 21:55:22 +1000 Subject: [PATCH 18/33] Continuation line under-indented for visual indent --- Tests/test_file_webp_animated.py | 6 +- Tests/test_image_resize.py | 16 +- Tests/test_imageops_usm.py | 24 ++- Tests/test_imagepalette.py | 6 +- Tests/test_lib_pack.py | 327 +++++++++++++++++-------------- 5 files changed, 210 insertions(+), 169 deletions(-) diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index f98cde764..6b3dc1622 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -83,7 +83,8 @@ class TestFileWebpAnimation(PillowTestCase): temp_file1 = self.tempfile("temp.webp") frame1.copy().save(temp_file1, - save_all=True, append_images=[frame2], lossless=True) + save_all=True, append_images=[frame2], + lossless=True) check(temp_file1) # Tests appending using a generator @@ -92,7 +93,8 @@ class TestFileWebpAnimation(PillowTestCase): yield im temp_file2 = self.tempfile("temp_generator.webp") frame1.copy().save(temp_file2, - save_all=True, append_images=imGenerator([frame2]), lossless=True) + save_all=True, append_images=imGenerator([frame2]), + lossless=True) check(temp_file2) def test_timestamp_and_duration(self): diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py index 8d14b9008..535f1d77e 100644 --- a/Tests/test_image_resize.py +++ b/Tests/test_image_resize.py @@ -39,15 +39,15 @@ class TestImagingCoreResize(PillowTestCase): self.assertEqual(r.im.bands, im.im.bands) def test_reduce_filters(self): - for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING, - Image.BICUBIC, Image.LANCZOS]: + for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, + Image.HAMMING, Image.BICUBIC, Image.LANCZOS]: r = self.resize(hopper("RGB"), (15, 12), f) self.assertEqual(r.mode, "RGB") self.assertEqual(r.size, (15, 12)) def test_enlarge_filters(self): - for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING, - Image.BICUBIC, Image.LANCZOS]: + for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, + Image.HAMMING, Image.BICUBIC, Image.LANCZOS]: r = self.resize(hopper("RGB"), (212, 195), f) self.assertEqual(r.mode, "RGB") self.assertEqual(r.size, (212, 195)) @@ -66,8 +66,8 @@ class TestImagingCoreResize(PillowTestCase): } samples['dirty'].putpixel((1, 1), 128) - for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING, - Image.BICUBIC, Image.LANCZOS]: + for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, + Image.HAMMING, Image.BICUBIC, Image.LANCZOS]: # samples resized with current filter references = { name: self.resize(ch, (4, 4), f) @@ -90,8 +90,8 @@ class TestImagingCoreResize(PillowTestCase): self.assert_image_equal(ch, references[channels[i]]) def test_enlarge_zero(self): - for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING, - Image.BICUBIC, Image.LANCZOS]: + for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, + Image.HAMMING, Image.BICUBIC, Image.LANCZOS]: r = self.resize(Image.new('RGB', (0, 0), "white"), (212, 195), f) self.assertEqual(r.mode, "RGB") self.assertEqual(r.size, (212, 195)) diff --git a/Tests/test_imageops_usm.py b/Tests/test_imageops_usm.py index 2666d3482..20758e9f8 100644 --- a/Tests/test_imageops_usm.py +++ b/Tests/test_imageops_usm.py @@ -13,27 +13,25 @@ class TestImageOpsUsm(PillowTestCase): def test_ops_api(self): i = self.assert_warning(DeprecationWarning, - ImageOps.gaussian_blur, im, 2.0) + ImageOps.gaussian_blur, im, 2.0) + self.assertEqual(i.mode, "RGB") + self.assertEqual(i.size, (128, 128)) + + i = self.assert_warning(DeprecationWarning, ImageOps.box_blur, im, 1) + self.assertEqual(i.mode, "RGB") + self.assertEqual(i.size, (128, 128)) + + i = self.assert_warning(DeprecationWarning, ImageOps.gblur, im, 2.0) self.assertEqual(i.mode, "RGB") self.assertEqual(i.size, (128, 128)) i = self.assert_warning(DeprecationWarning, - ImageOps.box_blur, im, 1) + ImageOps.unsharp_mask, im, 2.0, 125, 8) self.assertEqual(i.mode, "RGB") self.assertEqual(i.size, (128, 128)) i = self.assert_warning(DeprecationWarning, - ImageOps.gblur, im, 2.0) - self.assertEqual(i.mode, "RGB") - self.assertEqual(i.size, (128, 128)) - - i = self.assert_warning(DeprecationWarning, - ImageOps.unsharp_mask, im, 2.0, 125, 8) - self.assertEqual(i.mode, "RGB") - self.assertEqual(i.size, (128, 128)) - - i = self.assert_warning(DeprecationWarning, - ImageOps.usm, im, 2.0, 125, 8) + ImageOps.usm, im, 2.0, 125, 8) self.assertEqual(i.mode, "RGB") self.assertEqual(i.size, (128, 128)) diff --git a/Tests/test_imagepalette.py b/Tests/test_imagepalette.py index 889f022ae..3b7087d7a 100644 --- a/Tests/test_imagepalette.py +++ b/Tests/test_imagepalette.py @@ -9,7 +9,7 @@ class TestImagePalette(PillowTestCase): ImagePalette.ImagePalette("RGB", list(range(256))*3) self.assertRaises(ValueError, - ImagePalette.ImagePalette, "RGB", list(range(256))*2) + ImagePalette.ImagePalette, "RGB", list(range(256))*2) def test_getcolor(self): @@ -66,7 +66,7 @@ class TestImagePalette(PillowTestCase): # Act self.assertRaises(NotImplementedError, - ImagePalette.make_linear_lut, black, white) + ImagePalette.make_linear_lut, black, white) def test_make_gamma_lut(self): # Arrange @@ -133,7 +133,7 @@ class TestImagePalette(PillowTestCase): def test_invalid_palette(self): self.assertRaises(IOError, - ImagePalette.load, "Tests/images/hopper.jpg") + ImagePalette.load, "Tests/images/hopper.jpg") if __name__ == '__main__': diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index 002db2e19..89c8e297f 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -57,14 +57,18 @@ class TestLibPack(PillowTestCase): def test_RGB(self): self.assert_pack("RGB", "RGB", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_pack("RGB", "RGBX", + self.assert_pack( + "RGB", "RGBX", b'\x01\x02\x03\xff\x05\x06\x07\xff', (1, 2, 3), (5, 6, 7)) - self.assert_pack("RGB", "XRGB", + self.assert_pack( + "RGB", "XRGB", b'\x00\x02\x03\x04\x00\x06\x07\x08', (2, 3, 4), (6, 7, 8)) self.assert_pack("RGB", "BGR", 3, (3, 2, 1), (6, 5, 4), (9, 8, 7)) - self.assert_pack("RGB", "BGRX", + self.assert_pack( + "RGB", "BGRX", b'\x01\x02\x03\x00\x05\x06\x07\x00', (3, 2, 1), (7, 6, 5)) - self.assert_pack("RGB", "XBGR", + self.assert_pack( + "RGB", "XBGR", b'\x00\x02\x03\x04\x00\x06\x07\x08', (4, 3, 2), (8, 7, 6)) self.assert_pack("RGB", "RGB;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) self.assert_pack("RGB", "R", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9)) @@ -72,17 +76,19 @@ class TestLibPack(PillowTestCase): self.assert_pack("RGB", "B", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3)) def test_RGBA(self): - self.assert_pack("RGBA", "RGBA", 4, - (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_pack("RGBA", "RGBA;L", 4, - (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) + self.assert_pack( + "RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) + self.assert_pack( + "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) self.assert_pack("RGBA", "RGB", 3, (1, 2, 3, 14), (4, 5, 6, 15), (7, 8, 9, 16)) self.assert_pack("RGBA", "BGR", 3, (3, 2, 1, 14), (6, 5, 4, 15), (9, 8, 7, 16)) - self.assert_pack("RGBA", "BGRA", 4, + self.assert_pack( + "RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) - self.assert_pack("RGBA", "ABGR", 4, - (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) - self.assert_pack("RGBA", "BGRa", 4, + self.assert_pack( + "RGBA", "ABGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) + self.assert_pack( + "RGBA", "BGRa", 4, (191, 127, 63, 4), (223, 191, 159, 8), (233, 212, 191, 12)) self.assert_pack("RGBA", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) self.assert_pack("RGBA", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) @@ -90,22 +96,24 @@ class TestLibPack(PillowTestCase): self.assert_pack("RGBA", "A", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) def test_RGBa(self): - self.assert_pack("RGBa", "RGBa", 4, - (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_pack("RGBa", "BGRa", 4, - (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) - self.assert_pack("RGBa", "aBGR", 4, - (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) + self.assert_pack( + "RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) + self.assert_pack( + "RGBa", "BGRa", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) + self.assert_pack( + "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) def test_RGBX(self): self.assert_pack("RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) self.assert_pack("RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) self.assert_pack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) self.assert_pack("RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)) - self.assert_pack("RGBX", "BGRX", + self.assert_pack( + "RGBX", "BGRX", b'\x01\x02\x03\x00\x05\x06\x07\x00\t\n\x0b\x00', (3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X)) - self.assert_pack("RGBX", "XBGR", + self.assert_pack( + "RGBX", "XBGR", b'\x00\x02\x03\x04\x00\x06\x07\x08\x00\n\x0b\x0c', (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X)) self.assert_pack("RGBX", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) @@ -115,19 +123,22 @@ class TestLibPack(PillowTestCase): def test_CMYK(self): self.assert_pack("CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_pack("CMYK", "CMYK;I", 4, + self.assert_pack( + "CMYK", "CMYK;I", 4, (254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243)) - self.assert_pack("CMYK", "CMYK;L", 4, - (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) + self.assert_pack( + "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) self.assert_pack("CMYK", "K", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) def test_YCbCr(self): self.assert_pack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) self.assert_pack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) - self.assert_pack("YCbCr", "YCbCrX", + self.assert_pack( + "YCbCr", "YCbCrX", b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff', (1, 2, 3), (5, 6, 7), (9, 10, 11)) - self.assert_pack("YCbCr", "YCbCrK", + self.assert_pack( + "YCbCr", "YCbCrK", b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff', (1, 2, 3), (5, 6, 7), (9, 10, 11)) self.assert_pack("YCbCr", "Y", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) @@ -135,8 +146,8 @@ class TestLibPack(PillowTestCase): self.assert_pack("YCbCr", "Cr", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) def test_LAB(self): - self.assert_pack("LAB", "LAB", 3, - (1, 130, 131), (4, 133, 134), (7, 136, 137)) + self.assert_pack( + "LAB", "LAB", 3, (1, 130, 131), (4, 133, 134), (7, 136, 137)) self.assert_pack("LAB", "L", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9)) self.assert_pack("LAB", "A", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9)) self.assert_pack("LAB", "B", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3)) @@ -149,35 +160,35 @@ class TestLibPack(PillowTestCase): def test_I(self): self.assert_pack("I", "I;16B", 2, 0x0102, 0x0304) - self.assert_pack("I", "I;32S", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - 0x01000083, -2097151999) + self.assert_pack( + "I", "I;32S", + b'\x83\x00\x00\x01\x01\x00\x00\x83', 0x01000083, -2097151999) if sys.byteorder == 'little': self.assert_pack("I", "I", 4, 0x04030201, 0x08070605) - self.assert_pack("I", "I;32NS", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - 0x01000083, -2097151999) + self.assert_pack( + "I", "I;32NS", + b'\x83\x00\x00\x01\x01\x00\x00\x83', 0x01000083, -2097151999) else: self.assert_pack("I", "I", 4, 0x01020304, 0x05060708) - self.assert_pack("I", "I;32NS", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - -2097151999, 0x01000083) + self.assert_pack( + "I", "I;32NS", + b'\x83\x00\x00\x01\x01\x00\x00\x83', -2097151999, 0x01000083) def test_F_float(self): - self.assert_pack("F", "F;32F", 4, - 1.539989614439558e-36, 4.063216068939723e-34) + self.assert_pack( + "F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34) if sys.byteorder == 'little': - self.assert_pack("F", "F", 4, - 1.539989614439558e-36, 4.063216068939723e-34) - self.assert_pack("F", "F;32NF", 4, - 1.539989614439558e-36, 4.063216068939723e-34) + self.assert_pack( + "F", "F", 4, 1.539989614439558e-36, 4.063216068939723e-34) + self.assert_pack( + "F", "F;32NF", 4, 1.539989614439558e-36, 4.063216068939723e-34) else: - self.assert_pack("F", "F", 4, - 2.387939260590663e-38, 6.301941157072183e-36) - self.assert_pack("F", "F;32NF", 4, - 2.387939260590663e-38, 6.301941157072183e-36) + self.assert_pack( + "F", "F", 4, 2.387939260590663e-38, 6.301941157072183e-36) + self.assert_pack( + "F", "F;32NF", 4, 2.387939260590663e-38, 6.301941157072183e-36) class TestLibUnpack(PillowTestCase): @@ -260,7 +271,8 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack("RGB", "BGRX", 4, (3, 2, 1), (7, 6, 5), (11, 10, 9)) self.assert_unpack("RGB", "XRGB", 4, (2, 3, 4), (6, 7, 8), (10, 11, 12)) self.assert_unpack("RGB", "XBGR", 4, (4, 3, 2), (8, 7, 6), (12, 11, 10)) - self.assert_unpack("RGB", "YCC;P", + self.assert_unpack( + "RGB", "YCC;P", b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12', # random data (127, 102, 0), (192, 227, 0), (213, 255, 170), (98, 255, 133)) self.assert_unpack("RGB", "R", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0)) @@ -269,48 +281,58 @@ class TestLibUnpack(PillowTestCase): def test_RGBA(self): self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)) - self.assert_unpack("RGBA", "LA;16B", 4, - (1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11)) - self.assert_unpack("RGBA", "RGBA", 4, - (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_unpack("RGBA", "RGBa", 4, + self.assert_unpack( + "RGBA", "LA;16B", 4, (1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11)) + self.assert_unpack( + "RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) + self.assert_unpack( + "RGBA", "RGBa", 4, (63, 127, 191, 4), (159, 191, 223, 8), (191, 212, 233, 12)) - self.assert_unpack("RGBA", "RGBa", + self.assert_unpack( + "RGBA", "RGBa", b'\x01\x02\x03\x00\x10\x20\x30\xff', (0, 0, 0, 0), (16, 32, 48, 255)) - self.assert_unpack("RGBA", "RGBa;16L", 8, + self.assert_unpack( + "RGBA", "RGBa;16L", 8, (63, 127, 191, 8), (159, 191, 223, 16), (191, 212, 233, 24)) - self.assert_unpack("RGBA", "RGBa;16L", + self.assert_unpack( + "RGBA", "RGBa;16L", b'\x88\x01\x88\x02\x88\x03\x88\x00' b'\x88\x10\x88\x20\x88\x30\x88\xff', (0, 0, 0, 0), (16, 32, 48, 255)) - self.assert_unpack("RGBA", "RGBa;16B", 8, + self.assert_unpack( + "RGBA", "RGBa;16B", 8, (36, 109, 182, 7), (153, 187, 221, 15), (188, 210, 232, 23)) - self.assert_unpack("RGBA", "RGBa;16B", + self.assert_unpack( + "RGBA", "RGBa;16B", b'\x01\x88\x02\x88\x03\x88\x00\x88' b'\x10\x88\x20\x88\x30\x88\xff\x88', (0, 0, 0, 0), (16, 32, 48, 255)) - self.assert_unpack("RGBA", "BGRa", 4, + self.assert_unpack( + "RGBA", "BGRa", 4, (191, 127, 63, 4), (223, 191, 159, 8), (233, 212, 191, 12)) - self.assert_unpack("RGBA", "BGRa", + self.assert_unpack( + "RGBA", "BGRa", b'\x01\x02\x03\x00\x10\x20\x30\xff', (0, 0, 0, 0), (48, 32, 16, 255)) - self.assert_unpack("RGBA", "RGBA;I", 4, + self.assert_unpack( + "RGBA", "RGBA;I", 4, (254, 253, 252, 4), (250, 249, 248, 8), (246, 245, 244, 12)) - self.assert_unpack("RGBA", "RGBA;L", 4, - (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) + self.assert_unpack( + "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) self.assert_unpack("RGBA", "RGBA;15", 2, (8, 131, 0, 0), (24, 0, 8, 0)) self.assert_unpack("RGBA", "BGRA;15", 2, (0, 131, 8, 0), (8, 0, 24, 0)) self.assert_unpack("RGBA", "RGBA;4B", 2, (17, 0, 34, 0), (51, 0, 68, 0)) self.assert_unpack("RGBA", "RGBA;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) self.assert_unpack("RGBA", "RGBA;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) - self.assert_unpack("RGBA", "BGRA", 4, - (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) - self.assert_unpack("RGBA", "ARGB", 4, - (2, 3, 4, 1), (6, 7, 8, 5), (10, 11, 12, 9)) - self.assert_unpack("RGBA", "ABGR", 4, - (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) - self.assert_unpack("RGBA", "YCCA;P", + self.assert_unpack( + "RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) + self.assert_unpack( + "RGBA", "ARGB", 4, (2, 3, 4, 1), (6, 7, 8, 5), (10, 11, 12, 9)) + self.assert_unpack( + "RGBA", "ABGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) + self.assert_unpack( + "RGBA", "YCCA;P", b']bE\x04\xdd\xbej\xed57T\xce\xac\xce:\x11', # random data (0, 161, 0, 4), (255, 255, 255, 237), (27, 158, 0, 206), (0, 118, 0, 17)) self.assert_unpack("RGBA", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) @@ -319,14 +341,14 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack("RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) def test_RGBa(self): - self.assert_unpack("RGBa", "RGBa", 4, - (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_unpack("RGBa", "BGRa", 4, - (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) - self.assert_unpack("RGBa", "aRGB", 4, - (2, 3, 4, 1), (6, 7, 8, 5), (10, 11, 12, 9)) - self.assert_unpack("RGBa", "aBGR", 4, - (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) + self.assert_unpack( + "RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) + self.assert_unpack( + "RGBa", "BGRa", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) + self.assert_unpack( + "RGBa", "aRGB", 4, (2, 3, 4, 1), (6, 7, 8, 5), (10, 11, 12, 9)) + self.assert_unpack( + "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) def test_RGBX(self): self.assert_unpack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) @@ -336,20 +358,21 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack("RGBX", "RGB;15", 2, (8, 131, 0, X), (24, 0, 8, X)) self.assert_unpack("RGBX", "BGR;15", 2, (0, 131, 8, X), (8, 0, 24, X)) self.assert_unpack("RGBX", "RGB;4B", 2, (17, 0, 34, X), (51, 0, 68, X)) - self.assert_unpack("RGBX", "RGBX", 4, - (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_unpack("RGBX", "RGBXX", 5, - (1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14)) - self.assert_unpack("RGBX", "RGBXXX", 6, - (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16)) - self.assert_unpack("RGBX", "RGBX;L", 4, - (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) + self.assert_unpack( + "RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) + self.assert_unpack( + "RGBX", "RGBXX", 5, (1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14)) + self.assert_unpack( + "RGBX", "RGBXXX", 6, (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16)) + self.assert_unpack( + "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) self.assert_unpack("RGBX", "RGBX;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) self.assert_unpack("RGBX", "RGBX;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) self.assert_unpack("RGBX", "BGRX", 4, (3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X)) self.assert_unpack("RGBX", "XRGB", 4, (2, 3, 4, X), (6, 7, 8, X), (10, 11, 12, X)) self.assert_unpack("RGBX", "XBGR", 4, (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X)) - self.assert_unpack("RGBX", "YCC;P", + self.assert_unpack( + "RGBX", "YCC;P", b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12', # random data (127, 102, 0, X), (192, 227, 0, X), (213, 255, 170, X), (98, 255, 133, X)) self.assert_unpack("RGBX", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) @@ -358,40 +381,47 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack("RGBX", "X", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) def test_CMYK(self): - self.assert_unpack("CMYK", "CMYK", 4, - (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_unpack("CMYK", "CMYKX", 5, - (1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14)) - self.assert_unpack("CMYK", "CMYKXX", 6, - (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16)) - self.assert_unpack("CMYK", "CMYK;I", 4, + self.assert_unpack( + "CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) + self.assert_unpack( + "CMYK", "CMYKX", 5, (1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14)) + self.assert_unpack( + "CMYK", "CMYKXX", 6, (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16)) + self.assert_unpack( + "CMYK", "CMYK;I", 4, (254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243)) - self.assert_unpack("CMYK", "CMYK;L", 4, - (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) + self.assert_unpack( + "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) self.assert_unpack("CMYK", "C", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) self.assert_unpack("CMYK", "M", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) self.assert_unpack("CMYK", "Y", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) self.assert_unpack("CMYK", "K", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) - self.assert_unpack("CMYK", "C;I", 1, - (254, 0, 0, 0), (253, 0, 0, 0), (252, 0, 0, 0)) - self.assert_unpack("CMYK", "M;I", 1, - (0, 254, 0, 0), (0, 253, 0, 0), (0, 252, 0, 0)) - self.assert_unpack("CMYK", "Y;I", 1, - (0, 0, 254, 0), (0, 0, 253, 0), (0, 0, 252, 0)) - self.assert_unpack("CMYK", "K;I", 1, - (0, 0, 0, 254), (0, 0, 0, 253), (0, 0, 0, 252)) + self.assert_unpack( + "CMYK", "C;I", 1, (254, 0, 0, 0), (253, 0, 0, 0), (252, 0, 0, 0)) + self.assert_unpack( + "CMYK", "M;I", 1, (0, 254, 0, 0), (0, 253, 0, 0), (0, 252, 0, 0)) + self.assert_unpack( + "CMYK", "Y;I", 1, (0, 0, 254, 0), (0, 0, 253, 0), (0, 0, 252, 0)) + self.assert_unpack( + "CMYK", "K;I", 1, (0, 0, 0, 254), (0, 0, 0, 253), (0, 0, 0, 252)) def test_YCbCr(self): - self.assert_unpack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_unpack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) - self.assert_unpack("YCbCr", "YCbCrK", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) - self.assert_unpack("YCbCr", "YCbCrX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) - self.assert_unpack("YCbCr", "YCbCrXX", 5, (1, 2, 3), (6, 7, 8), (11, 12, 13)) - self.assert_unpack("YCbCr", "YCbCrXXX", 6, (1, 2, 3), (7, 8, 9), (13, 14, 15)) + self.assert_unpack( + "YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) + self.assert_unpack( + "YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) + self.assert_unpack( + "YCbCr", "YCbCrK", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) + self.assert_unpack( + "YCbCr", "YCbCrX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) + self.assert_unpack( + "YCbCr", "YCbCrXX", 5, (1, 2, 3), (6, 7, 8), (11, 12, 13)) + self.assert_unpack( + "YCbCr", "YCbCrXXX", 6, (1, 2, 3), (7, 8, 9), (13, 14, 15)) def test_LAB(self): - self.assert_unpack("LAB", "LAB", 3, - (1, 130, 131), (4, 133, 134), (7, 136, 137)) + self.assert_unpack( + "LAB", "LAB", 3, (1, 130, 131), (4, 133, 134), (7, 136, 137)) self.assert_unpack("LAB", "L", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0)) self.assert_unpack("LAB", "A", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) self.assert_unpack("LAB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) @@ -410,30 +440,30 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack("I", "I;16B", 2, 0x0102, 0x0304) self.assert_unpack("I", "I;16BS", b'\x83\x01\x01\x83', -31999, 0x0183) self.assert_unpack("I", "I;32", 4, 0x04030201, 0x08070605) - self.assert_unpack("I", "I;32S", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - 0x01000083, -2097151999) + self.assert_unpack( + "I", "I;32S", + b'\x83\x00\x00\x01\x01\x00\x00\x83', 0x01000083, -2097151999) self.assert_unpack("I", "I;32B", 4, 0x01020304, 0x05060708) - self.assert_unpack("I", "I;32BS", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - -2097151999, 0x01000083) + self.assert_unpack( + "I", "I;32BS", + b'\x83\x00\x00\x01\x01\x00\x00\x83', -2097151999, 0x01000083) if sys.byteorder == 'little': self.assert_unpack("I", "I", 4, 0x04030201, 0x08070605) self.assert_unpack("I", "I;16N", 2, 0x0201, 0x0403) self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', 0x0183, -31999) self.assert_unpack("I", "I;32N", 4, 0x04030201, 0x08070605) - self.assert_unpack("I", "I;32NS", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - 0x01000083, -2097151999) + self.assert_unpack( + "I", "I;32NS", + b'\x83\x00\x00\x01\x01\x00\x00\x83', 0x01000083, -2097151999) else: self.assert_unpack("I", "I", 4, 0x01020304, 0x05060708) self.assert_unpack("I", "I;16N", 2, 0x0102, 0x0304) self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', -31999, 0x0183) self.assert_unpack("I", "I;32N", 4, 0x01020304, 0x05060708) - self.assert_unpack("I", "I;32NS", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - -2097151999, 0x01000083) + self.assert_unpack( + "I", "I;32NS", + b'\x83\x00\x00\x01\x01\x00\x00\x83', -2097151999, 0x01000083) def test_F_int(self): self.assert_unpack("F", "F;8", 1, 0x01, 0x02, 0x03, 0x04) @@ -443,55 +473,66 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack("F", "F;16B", 2, 0x0102, 0x0304) self.assert_unpack("F", "F;16BS", b'\x83\x01\x01\x83', -31999, 0x0183) self.assert_unpack("F", "F;32", 4, 67305984, 134678016) - self.assert_unpack("F", "F;32S", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - 16777348, -2097152000) + self.assert_unpack( + "F", "F;32S", + b'\x83\x00\x00\x01\x01\x00\x00\x83', 16777348, -2097152000) self.assert_unpack("F", "F;32B", 4, 0x01020304, 0x05060708) - self.assert_unpack("F", "F;32BS", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - -2097152000, 16777348) + self.assert_unpack( + "F", "F;32BS", + b'\x83\x00\x00\x01\x01\x00\x00\x83', -2097152000, 16777348) if sys.byteorder == 'little': self.assert_unpack("F", "F;16N", 2, 0x0201, 0x0403) self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', 0x0183, -31999) self.assert_unpack("F", "F;32N", 4, 67305984, 134678016) - self.assert_unpack("F", "F;32NS", - b'\x83\x00\x00\x01\x01\x00\x00\x83', - 16777348, -2097152000) + self.assert_unpack( + "F", "F;32NS", + b'\x83\x00\x00\x01\x01\x00\x00\x83', 16777348, -2097152000) else: self.assert_unpack("F", "F;16N", 2, 0x0102, 0x0304) self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', -31999, 0x0183) self.assert_unpack("F", "F;32N", 4, 0x01020304, 0x05060708) - self.assert_unpack("F", "F;32NS", + self.assert_unpack( + "F", "F;32NS", b'\x83\x00\x00\x01\x01\x00\x00\x83', -2097152000, 16777348) def test_F_float(self): - self.assert_unpack("F", "F;32F", 4, + self.assert_unpack( + "F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34) - self.assert_unpack("F", "F;32BF", 4, + self.assert_unpack( + "F", "F;32BF", 4, 2.387939260590663e-38, 6.301941157072183e-36) - self.assert_unpack("F", "F;64F", + self.assert_unpack( + "F", "F;64F", b'333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0', # by struct.pack 0.15000000596046448, -1234.5) - self.assert_unpack("F", "F;64BF", + self.assert_unpack( + "F", "F;64BF", b'?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00', # by struct.pack 0.15000000596046448, -1234.5) if sys.byteorder == 'little': - self.assert_unpack("F", "F", 4, + self.assert_unpack( + "F", "F", 4, 1.539989614439558e-36, 4.063216068939723e-34) - self.assert_unpack("F", "F;32NF", 4, + self.assert_unpack( + "F", "F;32NF", 4, 1.539989614439558e-36, 4.063216068939723e-34) - self.assert_unpack("F", "F;64NF", + self.assert_unpack( + "F", "F;64NF", b'333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0', 0.15000000596046448, -1234.5) else: - self.assert_unpack("F", "F", 4, + self.assert_unpack( + "F", "F", 4, 2.387939260590663e-38, 6.301941157072183e-36) - self.assert_unpack("F", "F;32NF", 4, + self.assert_unpack( + "F", "F;32NF", 4, 2.387939260590663e-38, 6.301941157072183e-36) - self.assert_unpack("F", "F;64NF", + self.assert_unpack( + "F", "F;64NF", b'?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00', 0.15000000596046448, -1234.5) From c2189235afc3fdc36cb781ee6bdcd3e6692f91aa Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 24 Jun 2018 22:32:25 +1000 Subject: [PATCH 19/33] Line too long --- Tests/helper.py | 6 +- Tests/test_color_lut.py | 3 +- Tests/test_file_gif.py | 3 +- Tests/test_file_libtiff.py | 17 ++- Tests/test_file_pdf.py | 19 ++- Tests/test_file_png.py | 6 +- Tests/test_file_tiff.py | 3 +- Tests/test_font_leaks.py | 3 +- Tests/test_image_access.py | 3 +- Tests/test_image_array.py | 6 +- Tests/test_image_convert.py | 3 +- Tests/test_image_resample.py | 31 ++-- Tests/test_image_rotate.py | 5 +- Tests/test_image_toqimage.py | 5 +- Tests/test_imagecms.py | 135 +++++++++++++----- Tests/test_imagecolor.py | 18 ++- Tests/test_imageenhance.py | 5 +- Tests/test_imagefile.py | 8 +- Tests/test_imagefont.py | 13 +- Tests/test_imagefont_bitmap.py | 3 +- Tests/test_imagefontctl.py | 12 +- Tests/test_imagemorph.py | 5 +- Tests/test_lib_pack.py | 155 +++++++++++++------- Tests/test_map.py | 3 +- Tests/test_numpy.py | 4 +- Tests/test_pdfparser.py | 61 +++++--- setup.py | 15 +- src/PIL/BmpImagePlugin.py | 92 ++++++++---- src/PIL/DdsImagePlugin.py | 3 +- src/PIL/FtexImagePlugin.py | 22 +-- src/PIL/GbrImagePlugin.py | 6 +- src/PIL/GifImagePlugin.py | 19 ++- src/PIL/ImageCms.py | 56 ++++---- src/PIL/ImageDraw.py | 3 +- src/PIL/ImageEnhance.py | 3 +- src/PIL/ImageFile.py | 35 +++-- src/PIL/ImageFont.py | 34 +++-- src/PIL/ImageMode.py | 3 +- src/PIL/ImageQt.py | 3 +- src/PIL/ImageTk.py | 3 +- src/PIL/Jpeg2KImagePlugin.py | 3 +- src/PIL/JpegImagePlugin.py | 3 +- src/PIL/MspImagePlugin.py | 5 +- src/PIL/PdfImagePlugin.py | 63 ++++++--- src/PIL/PdfParser.py | 251 +++++++++++++++++++++++---------- src/PIL/PngImagePlugin.py | 7 +- src/PIL/PpmImagePlugin.py | 3 +- src/PIL/SgiImagePlugin.py | 3 +- src/PIL/SunImagePlugin.py | 3 +- src/PIL/TiffImagePlugin.py | 3 +- src/PIL/TiffTags.py | 7 +- src/PIL/WmfImagePlugin.py | 3 +- 52 files changed, 805 insertions(+), 381 deletions(-) diff --git a/Tests/helper.py b/Tests/helper.py index 5dbdb66be..207f497d2 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -153,7 +153,8 @@ class PillowTestCase(unittest.TestCase): pass raise e - def assert_image_similar_tofile(self, a, filename, epsilon, msg=None, mode=None): + def assert_image_similar_tofile(self, a, filename, epsilon, msg=None, + mode=None): with Image.open(filename) as img: if mode: img = img.convert(mode) @@ -246,7 +247,8 @@ class PillowLeakTestCase(PillowTestCase): mem = getrusage(RUSAGE_SELF).ru_maxrss if sys.platform == 'darwin': # man 2 getrusage: - # ru_maxrss the maximum resident set size utilized (in bytes). + # ru_maxrss + # This is the maximum resident set size utilized (in bytes). return mem / 1024 # Kb else: # linux diff --git a/Tests/test_color_lut.py b/Tests/test_color_lut.py index 5a51b279f..6d0b76fed 100644 --- a/Tests/test_color_lut.py +++ b/Tests/test_color_lut.py @@ -410,7 +410,8 @@ class TestGenerateColorLut3D(PillowTestCase): self.assertEqual(lut.name, "Color 3D LUT") self.assertEqual(lut.table[:24], [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.125, 0.0, 0.5, 0.0, 0.25, - 0.0, 0.75, 0.0, 0.375, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0, 0.25, 0.125]) + 0.0, 0.75, 0.0, 0.375, 0.0, 1.0, 0.0, 0.5, 0.0, 0.0, 0.25, 0.125 + ]) def test_apply(self): lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b)) diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index b1006a630..086a0f5d0 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -402,7 +402,8 @@ class TestFileGif(PillowTestCase): def test_comment(self): im = Image.open(TEST_GIF) - self.assertEqual(im.info['comment'], b"File written by Adobe Photoshop\xa8 4.0") + self.assertEqual(im.info['comment'], + b"File written by Adobe Photoshop\xa8 4.0") out = self.tempfile('temp.gif') im = Image.new('L', (100, 100), '#000') diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 4f2f9617e..77caa0b9d 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -126,7 +126,8 @@ class TestFileLibTiff(LibTiffTestCase): im.tile[0][:3], ('tiff_adobe_deflate', (0, 0, 278, 374), 0)) im.load() - self.assert_image_equal_tofile(im, 'Tests/images/tiff_adobe_deflate.png') + self.assert_image_equal_tofile(im, + 'Tests/images/tiff_adobe_deflate.png') def test_write_metadata(self): """ Test metadata writing through libtiff """ @@ -217,7 +218,8 @@ class TestFileLibTiff(LibTiffTestCase): if info.length == 0: new_ifd[tag] = tuple(values[info.type] for _ in range(3)) else: - new_ifd[tag] = tuple(values[info.type] for _ in range(info.length)) + new_ifd[tag] = tuple(values[info.type] + for _ in range(info.length)) # Extra samples really doesn't make sense in this application. del(new_ifd[338]) @@ -578,10 +580,14 @@ 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))]) + self.assertEqual( + im.tile, + [('tiff_lzw', (0, 0, 100, 40), 0, ('RGBa;16N', 'tiff_lzw', False))] + ) im.load() - self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") + self.assert_image_equal_tofile( + im, "Tests/images/tiff_16bit_RGBa_target.png") def test_gimp_tiff(self): # Read TIFF JPEG images from GIMP [@PIL168] @@ -607,7 +613,8 @@ class TestFileLibTiff(LibTiffTestCase): im = Image.open("Tests/images/copyleft.tiff") self.assertEqual(im.mode, 'RGB') - self.assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode='RGB') + self.assert_image_equal_tofile(im, "Tests/images/copyleft.png", + mode='RGB') def test_lzw(self): im = Image.open("Tests/images/hopper_lzw.tif") diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index 3d359f445..f012fb9d8 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -20,7 +20,8 @@ class TestFilePdf(PillowTestCase): self.assertTrue(os.path.isfile(outfile)) self.assertGreater(os.path.getsize(outfile), 0) with PdfParser.PdfParser(outfile) as pdf: - if kwargs.get("append_images", False) or kwargs.get("append", False): + if kwargs.get("append_images", False) or \ + kwargs.get("append", False): self.assertGreater(len(pdf.pages), 1) else: self.assertGreater(len(pdf.pages), 0) @@ -116,7 +117,9 @@ class TestFilePdf(PillowTestCase): def test_pdf_open(self): # fail on a buffer full of null bytes - self.assertRaises(PdfParser.PdfFormatError, PdfParser.PdfParser, buf=bytearray(65536)) + self.assertRaises( + PdfParser.PdfFormatError, + PdfParser.PdfParser, buf=bytearray(65536)) # make an empty PDF object with PdfParser.PdfParser() as empty_pdf: @@ -153,7 +156,10 @@ class TestFilePdf(PillowTestCase): im = hopper("RGB") temp_dir = tempfile.mkdtemp() try: - self.assertRaises(IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True) + self.assertRaises(IOError, + im.save, + os.path.join(temp_dir, "nonexistent.pdf"), + append=True) finally: os.rmdir(temp_dir) @@ -204,7 +210,8 @@ class TestFilePdf(PillowTestCase): # append two images mode_CMYK = hopper("CMYK") mode_P = hopper("P") - mode_CMYK.save(pdf_filename, append=True, save_all=True, append_images=[mode_P]) + mode_CMYK.save(pdf_filename, + append=True, save_all=True, append_images=[mode_P]) # open the PDF again, check pages and info again with PdfParser.PdfParser(pdf_filename) as pdf: @@ -219,7 +226,9 @@ class TestFilePdf(PillowTestCase): def test_pdf_info(self): # make a PDF file - pdf_filename = self.helper_save_as_pdf("RGB", title="title", author="author", subject="subject", keywords="keywords", creator="creator", producer="producer") + pdf_filename = self.helper_save_as_pdf( + "RGB", title="title", author="author", subject="subject", + keywords="keywords", creator="creator", producer="producer") # open it, check pages and info with PdfParser.PdfParser(pdf_filename) as pdf: diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index bc2b557d2..e9dcd5203 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -355,7 +355,8 @@ class TestFilePng(PillowTestCase): broken_crc_chunk_data = chunk_data[:-1] + b'q' # break CRC image_data = HEAD + broken_crc_chunk_data + TAIL - self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data)) + self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, + BytesIO(image_data)) ImageFile.LOAD_TRUNCATED_IMAGES = True try: @@ -371,7 +372,8 @@ class TestFilePng(PillowTestCase): ImageFile.LOAD_TRUNCATED_IMAGES = True try: - self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data)) + self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, + BytesIO(image_data)) finally: ImageFile.LOAD_TRUNCATED_IMAGES = False diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index aac845e0f..79630c773 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -444,7 +444,8 @@ class TestFileTiff(PillowTestCase): for im in ims: yield im mp = io.BytesIO() - im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims)) + im.save(mp, format="TIFF", save_all=True, + append_images=imGenerator(ims)) mp.seek(0, os.SEEK_SET) reread = Image.open(mp) diff --git a/Tests/test_font_leaks.py b/Tests/test_font_leaks.py index 4de28a95a..f1ce44e6d 100644 --- a/Tests/test_font_leaks.py +++ b/Tests/test_font_leaks.py @@ -16,7 +16,8 @@ class TestTTypeFontLeak(PillowLeakTestCase): self._test_leak(lambda: draw.text((0, 0), "some text "*1024, # ~10k font=font, fill="black")) - @unittest.skipIf(not features.check('freetype2'), "Test requires freetype2") + @unittest.skipIf(not features.check('freetype2'), + "Test requires freetype2") def test_leak(self): ttype = ImageFont.truetype('Tests/fonts/FreeMono.ttf', 20) self._test_font(ttype) diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 9cc623856..7a9378bbd 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -294,7 +294,8 @@ int main(int argc, char* argv[]) compiler = ccompiler.new_compiler() compiler.add_include_dir(sysconfig.get_python_inc()) - libdir = sysconfig.get_config_var('LIBDIR') or sysconfig.get_python_inc().replace('include', 'libs') + libdir = (sysconfig.get_config_var('LIBDIR') or + sysconfig.get_python_inc().replace('include', 'libs')) print(libdir) compiler.add_library_dir(libdir) objects = compiler.compile(['embed_pil.c']) diff --git a/Tests/test_image_array.py b/Tests/test_image_array.py index 11c2648bb..7a86a3e54 100644 --- a/Tests/test_image_array.py +++ b/Tests/test_image_array.py @@ -15,9 +15,11 @@ class TestImageArray(PillowTestCase): self.assertEqual(test("L"), (3, (100, 128), '|u1', 12800)) # FIXME: wrong? - self.assertEqual(test("I"), (3, (100, 128), Image._ENDIAN + 'i4', 51200)) + self.assertEqual(test("I"), (3, (100, 128), + Image._ENDIAN + 'i4', 51200)) # FIXME: wrong? - self.assertEqual(test("F"), (3, (100, 128), Image._ENDIAN + 'f4', 51200)) + self.assertEqual(test("F"), (3, (100, 128), + Image._ENDIAN + 'f4', 51200)) self.assertEqual(test("LA"), (3, (100, 128, 2), '|u1', 25600)) self.assertEqual(test("RGB"), (3, (100, 128, 3), '|u1', 38400)) diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index 14e634e9c..ed971e698 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -193,7 +193,8 @@ class TestImageConvert(PillowTestCase): if converted_im.mode == 'RGB': self.assert_image_similar(converted_im, target, 3) else: - self.assert_image_similar(converted_im, target.getchannel(0), 1) + self.assert_image_similar(converted_im, + target.getchannel(0), 1) matrix_convert('RGB') matrix_convert('L') diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index cf38c2345..3687a1a2c 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -288,10 +288,14 @@ class CoreResampleAlphaCorrectTest(PillowTestCase): def test_dirty_pixels_rgba(self): case = self.make_dirty_case('RGBA', (255, 255, 0, 128), (0, 0, 255, 0)) self.run_dirty_case(case.resize((20, 20), Image.BOX), (255, 255, 0)) - self.run_dirty_case(case.resize((20, 20), Image.BILINEAR), (255, 255, 0)) - self.run_dirty_case(case.resize((20, 20), Image.HAMMING), (255, 255, 0)) - self.run_dirty_case(case.resize((20, 20), Image.BICUBIC), (255, 255, 0)) - self.run_dirty_case(case.resize((20, 20), Image.LANCZOS), (255, 255, 0)) + self.run_dirty_case(case.resize((20, 20), Image.BILINEAR), + (255, 255, 0)) + self.run_dirty_case(case.resize((20, 20), Image.HAMMING), + (255, 255, 0)) + self.run_dirty_case(case.resize((20, 20), Image.BICUBIC), + (255, 255, 0)) + self.run_dirty_case(case.resize((20, 20), Image.LANCZOS), + (255, 255, 0)) def test_dirty_pixels_la(self): case = self.make_dirty_case('LA', (255, 128), (0, 0)) @@ -367,23 +371,28 @@ class CoreResampleCoefficientsTest(PillowTestCase): im = Image.new('RGBA', (1280, 1280), (0x20, 0x40, 0x60, 0xff)) histogram = im.resize((256, 256), Image.BICUBIC).histogram() - self.assertEqual(histogram[0x100 * 0 + 0x20], 0x10000) # first channel - self.assertEqual(histogram[0x100 * 1 + 0x40], 0x10000) # second channel - self.assertEqual(histogram[0x100 * 2 + 0x60], 0x10000) # third channel - self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000) # fourth channel + # first channel + self.assertEqual(histogram[0x100 * 0 + 0x20], 0x10000) + # second channel + self.assertEqual(histogram[0x100 * 1 + 0x40], 0x10000) + # third channel + self.assertEqual(histogram[0x100 * 2 + 0x60], 0x10000) + # fourth channel + self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000) class CoreResampleBoxTest(PillowTestCase): def test_wrong_arguments(self): im = hopper() - for resample in (Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING, - Image.BICUBIC, Image.LANCZOS): + for resample in (Image.NEAREST, Image.BOX, Image.BILINEAR, + Image.HAMMING, Image.BICUBIC, Image.LANCZOS): im.resize((32, 32), resample, (0, 0, im.width, im.height)) im.resize((32, 32), resample, (20, 20, im.width, im.height)) im.resize((32, 32), resample, (20, 20, 20, 100)) im.resize((32, 32), resample, (20, 20, 100, 20)) - with self.assertRaisesRegex(TypeError, "must be sequence of length 4"): + with self.assertRaisesRegex(TypeError, + "must be sequence of length 4"): im.resize((32, 32), resample, (im.width, im.height)) with self.assertRaisesRegex(ValueError, "can't be negative"): diff --git a/Tests/test_image_rotate.py b/Tests/test_image_rotate.py index 8ddb5ddf8..17d394a02 100644 --- a/Tests/test_image_rotate.py +++ b/Tests/test_image_rotate.py @@ -95,8 +95,9 @@ class TestImageRotate(PillowTestCase): im = hopper() self.rotate(im, im.mode, 45, center=(0, 0)) self.rotate(im, im.mode, 45, translate=(im.size[0]/2, 0)) - self.rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0]/2, 0)) - + self.rotate(im, im.mode, 45, center=(0, 0), + translate=(im.size[0]/2, 0)) + def test_rotate_no_fill(self): im = Image.new('RGB', (100, 100), 'green') target = Image.open('Tests/images/rotate_45_no_fill.png') diff --git a/Tests/test_image_toqimage.py b/Tests/test_image_toqimage.py index 6d7715c80..c9971cf73 100644 --- a/Tests/test_image_toqimage.py +++ b/Tests/test_image_toqimage.py @@ -43,8 +43,9 @@ class TestToQImage(PillowQtTestCase, PillowTestCase): if mode == '1': # BW appears to not save correctly on QT4 and QT5 # kicks out errors on console: - # libpng warning: Invalid color type/bit depth combination in IHDR - # libpng error: Invalid IHDR data + # libpng warning: Invalid color type/bit depth combination + # in IHDR + # libpng error: Invalid IHDR data continue # Test saving the file diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index 2f4708689..1fdfe916d 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -286,53 +286,104 @@ class TestImageCms(PillowTestCase): self.assertEqual(truncate_tuple(tup1), truncate_tuple(tup2)) self.assertEqual(p.attributes, 4294967296) - assert_truncated_tuple_equal(p.blue_colorant, ((0.14306640625, 0.06060791015625, 0.7140960693359375), (0.1558847490315394, 0.06603820639433387, 0.06060791015625))) - assert_truncated_tuple_equal(p.blue_primary, ((0.14306641366715667, 0.06060790921083026, 0.7140960805782015), (0.15588475410450106, 0.06603820408959558, 0.06060790921083026))) + assert_truncated_tuple_equal( + p.blue_colorant, + ((0.14306640625, 0.06060791015625, 0.7140960693359375), + (0.1558847490315394, 0.06603820639433387, 0.06060791015625))) + assert_truncated_tuple_equal( + p.blue_primary, + ((0.14306641366715667, 0.06060790921083026, 0.7140960805782015), + (0.15588475410450106, 0.06603820408959558, 0.06060790921083026))) assert_truncated_tuple_equal(p.chromatic_adaptation, (((1.04791259765625, 0.0229339599609375, -0.050201416015625), (0.02960205078125, 0.9904632568359375, -0.0170745849609375), (-0.009246826171875, 0.0150604248046875, 0.7517852783203125)), ((1.0267159024652783, 0.022470062342089134, 0.0229339599609375), (0.02951378324103937, 0.9875098886387147, 0.9904632568359375), (-0.012205438066465256, 0.01987915407854985, 0.0150604248046875)))) self.assertIsNone(p.chromaticity) - self.assertEqual(p.clut, {0: (False, False, True), 1: (False, False, True), 2: (False, False, True), 3: (False, False, True)}) + self.assertEqual(p.clut, { + 0: (False, False, True), + 1: (False, False, True), + 2: (False, False, True), + 3: (False, False, True) + }) self.assertEqual(p.color_space, 'RGB') self.assertIsNone(p.colorant_table) self.assertIsNone(p.colorant_table_out) self.assertIsNone(p.colorimetric_intent) self.assertEqual(p.connection_space, 'XYZ ') - self.assertEqual(p.copyright, 'Copyright International Color Consortium, 2009') - self.assertEqual(p.creation_date, datetime.datetime(2009, 2, 27, 21, 36, 31)) + self.assertEqual(p.copyright, + 'Copyright International Color Consortium, 2009') + self.assertEqual(p.creation_date, + datetime.datetime(2009, 2, 27, 21, 36, 31)) self.assertEqual(p.device_class, 'mntr') - assert_truncated_tuple_equal(p.green_colorant, ((0.3851470947265625, 0.7168731689453125, 0.097076416015625), (0.32119769927720654, 0.5978443449048152, 0.7168731689453125))) - assert_truncated_tuple_equal(p.green_primary, ((0.3851470888162112, 0.7168731974161346, 0.09707641738998518), (0.32119768793686687, 0.5978443567149709, 0.7168731974161346))) + assert_truncated_tuple_equal( + p.green_colorant, + ((0.3851470947265625, 0.7168731689453125, 0.097076416015625), + (0.32119769927720654, 0.5978443449048152, 0.7168731689453125))) + assert_truncated_tuple_equal( + p.green_primary, + ((0.3851470888162112, 0.7168731974161346, 0.09707641738998518), + (0.32119768793686687, 0.5978443567149709, 0.7168731974161346))) self.assertEqual(p.header_flags, 0) self.assertEqual(p.header_manufacturer, '\x00\x00\x00\x00') self.assertEqual(p.header_model, '\x00\x00\x00\x00') - self.assertEqual(p.icc_measurement_condition, {'backing': (0.0, 0.0, 0.0), 'flare': 0.0, 'geo': 'unknown', 'observer': 1, 'illuminant_type': 'D65'}) + self.assertEqual(p.icc_measurement_condition, { + 'backing': (0.0, 0.0, 0.0), + 'flare': 0.0, + 'geo': 'unknown', + 'observer': 1, + 'illuminant_type': 'D65' + }) self.assertEqual(p.icc_version, 33554432) self.assertIsNone(p.icc_viewing_condition) - self.assertEqual(p.intent_supported, {0: (True, True, True), 1: (True, True, True), 2: (True, True, True), 3: (True, True, True)}) + self.assertEqual(p.intent_supported, { + 0: (True, True, True), + 1: (True, True, True), + 2: (True, True, True), + 3: (True, True, True) + }) self.assertTrue(p.is_matrix_shaper) self.assertEqual(p.luminance, ((0.0, 80.0, 0.0), (0.0, 1.0, 80.0))) self.assertIsNone(p.manufacturer) - assert_truncated_tuple_equal(p.media_black_point, ((0.012054443359375, 0.0124969482421875, 0.01031494140625), (0.34573304157549234, 0.35842450765864337, 0.0124969482421875))) - assert_truncated_tuple_equal(p.media_white_point, ((0.964202880859375, 1.0, 0.8249053955078125), (0.3457029219802284, 0.3585375327567059, 1.0))) - assert_truncated_tuple_equal((p.media_white_point_temperature,), (5000.722328847392,)) - self.assertEqual(p.model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB') + assert_truncated_tuple_equal( + p.media_black_point, + ((0.012054443359375, 0.0124969482421875, 0.01031494140625), + (0.34573304157549234, 0.35842450765864337, 0.0124969482421875))) + assert_truncated_tuple_equal( + p.media_white_point, + ((0.964202880859375, 1.0, 0.8249053955078125), + (0.3457029219802284, 0.3585375327567059, 1.0))) + assert_truncated_tuple_equal( + (p.media_white_point_temperature,), + (5000.722328847392,)) + self.assertEqual(p.model, + 'IEC 61966-2-1 Default RGB Colour Space - sRGB') self.assertEqual(p.pcs, 'XYZ') self.assertIsNone(p.perceptual_rendering_intent_gamut) - self.assertEqual(p.product_copyright, 'Copyright International Color Consortium, 2009') + self.assertEqual(p.product_copyright, + 'Copyright International Color Consortium, 2009') self.assertEqual(p.product_desc, 'sRGB IEC61966-2-1 black scaled') - self.assertEqual(p.product_description, 'sRGB IEC61966-2-1 black scaled') + self.assertEqual(p.product_description, + 'sRGB IEC61966-2-1 black scaled') self.assertEqual(p.product_manufacturer, '') - self.assertEqual(p.product_model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB') - self.assertEqual(p.profile_description, 'sRGB IEC61966-2-1 black scaled') - self.assertEqual(p.profile_id, b')\xf8=\xde\xaf\xf2U\xaexB\xfa\xe4\xca\x839\r') - assert_truncated_tuple_equal(p.red_colorant, ((0.436065673828125, 0.2224884033203125, 0.013916015625), (0.6484536316398539, 0.3308524880306778, 0.2224884033203125))) - assert_truncated_tuple_equal(p.red_primary, ((0.43606566581047446, 0.22248840582960838, 0.013916015621759925), (0.6484536250319214, 0.3308524944738204, 0.22248840582960838))) + self.assertEqual( + p.product_model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB') + self.assertEqual( + p.profile_description, 'sRGB IEC61966-2-1 black scaled') + self.assertEqual( + p.profile_id, b')\xf8=\xde\xaf\xf2U\xaexB\xfa\xe4\xca\x839\r') + assert_truncated_tuple_equal( + p.red_colorant, + ((0.436065673828125, 0.2224884033203125, 0.013916015625), + (0.6484536316398539, 0.3308524880306778, 0.2224884033203125))) + assert_truncated_tuple_equal( + p.red_primary, + ((0.43606566581047446, 0.22248840582960838, 0.013916015621759925), + (0.6484536250319214, 0.3308524944738204, 0.22248840582960838))) self.assertEqual(p.rendering_intent, 0) self.assertIsNone(p.saturation_rendering_intent_gamut) self.assertIsNone(p.screening_description) self.assertIsNone(p.target) self.assertEqual(p.technology, 'CRT ') self.assertEqual(p.version, 2.0) - self.assertEqual(p.viewing_condition, 'Reference Viewing Condition in IEC 61966-2-1') + self.assertEqual(p.viewing_condition, + 'Reference Viewing Condition in IEC 61966-2-1') self.assertEqual(p.xcolor_space, 'RGB ') def test_profile_typesafety(self): @@ -346,7 +397,8 @@ class TestImageCms(PillowTestCase): with self.assertRaises(TypeError): ImageCms.ImageCmsProfile(1).tobytes() - def assert_aux_channel_preserved(self, mode, transform_in_place, preserved_channel): + def assert_aux_channel_preserved(self, mode, + transform_in_place, preserved_channel): def create_test_image(): # set up test image with something interesting in the tested aux # channel. @@ -379,29 +431,35 @@ class TestImageCms(PillowTestCase): # create some transform, it doesn't matter which one source_profile = ImageCms.createProfile("sRGB") destination_profile = ImageCms.createProfile("sRGB") - t = ImageCms.buildTransform(source_profile, destination_profile, inMode=mode, outMode=mode) + t = ImageCms.buildTransform( + source_profile, destination_profile, inMode=mode, outMode=mode) # apply transform if transform_in_place: ImageCms.applyTransform(source_image, t, inPlace=True) result_image = source_image else: - result_image = ImageCms.applyTransform(source_image, t, inPlace=False) + result_image = ImageCms.applyTransform( + source_image, t, inPlace=False) result_image_aux = result_image.getchannel(preserved_channel) self.assert_image_equal(source_image_aux, result_image_aux) def test_preserve_auxiliary_channels_rgba(self): - self.assert_aux_channel_preserved(mode='RGBA', transform_in_place=False, preserved_channel='A') + self.assert_aux_channel_preserved(mode='RGBA', + transform_in_place=False, preserved_channel='A') def test_preserve_auxiliary_channels_rgba_in_place(self): - self.assert_aux_channel_preserved(mode='RGBA', transform_in_place=True, preserved_channel='A') + self.assert_aux_channel_preserved(mode='RGBA', + transform_in_place=True, preserved_channel='A') def test_preserve_auxiliary_channels_rgbx(self): - self.assert_aux_channel_preserved(mode='RGBX', transform_in_place=False, preserved_channel='X') + self.assert_aux_channel_preserved(mode='RGBX', + transform_in_place=False, preserved_channel='X') def test_preserve_auxiliary_channels_rgbx_in_place(self): - self.assert_aux_channel_preserved(mode='RGBX', transform_in_place=True, preserved_channel='X') + self.assert_aux_channel_preserved(mode='RGBX', + transform_in_place=True, preserved_channel='X') def test_auxiliary_channels_isolated(self): # test data in aux channels does not affect non-aux channels @@ -422,20 +480,29 @@ class TestImageCms(PillowTestCase): source_profile = ImageCms.createProfile(src_format[1]) destination_profile = ImageCms.createProfile(dst_format[1]) source_image = src_format[3] - test_transform = ImageCms.buildTransform(source_profile, destination_profile, inMode=src_format[0], outMode=dst_format[0]) + test_transform = ImageCms.buildTransform( + source_profile, destination_profile, + inMode=src_format[0], outMode=dst_format[0]) # test conversion from aux-ful source if transform_in_place: test_image = source_image.copy() - ImageCms.applyTransform(test_image, test_transform, inPlace=True) + ImageCms.applyTransform( + test_image, test_transform, inPlace=True) else: - test_image = ImageCms.applyTransform(source_image, test_transform, inPlace=False) + test_image = ImageCms.applyTransform( + source_image, test_transform, inPlace=False) # reference conversion from aux-less source - reference_transform = ImageCms.buildTransform(source_profile, destination_profile, inMode=src_format[2], outMode=dst_format[2]) - reference_image = ImageCms.applyTransform(source_image.convert(src_format[2]), reference_transform) + reference_transform = ImageCms.buildTransform( + source_profile, destination_profile, + inMode=src_format[2], outMode=dst_format[2]) + reference_image = ImageCms.applyTransform( + source_image.convert(src_format[2]), + reference_transform) - self.assert_image_equal(test_image.convert(dst_format[2]), reference_image) + self.assert_image_equal(test_image.convert(dst_format[2]), + reference_image) if __name__ == '__main__': diff --git a/Tests/test_imagecolor.py b/Tests/test_imagecolor.py index 0aac21278..1ea37544b 100644 --- a/Tests/test_imagecolor.py +++ b/Tests/test_imagecolor.py @@ -31,7 +31,8 @@ class TestImageColor(PillowTestCase): # case insensitivity self.assertEqual(ImageColor.getrgb("#DEF"), ImageColor.getrgb("#def")) - self.assertEqual(ImageColor.getrgb("#CDEF"), ImageColor.getrgb("#cdef")) + self.assertEqual(ImageColor.getrgb("#CDEF"), + ImageColor.getrgb("#cdef")) self.assertEqual(ImageColor.getrgb("#DEFDEF"), ImageColor.getrgb("#defdef")) self.assertEqual(ImageColor.getrgb("#CDEFCDEF"), @@ -80,18 +81,23 @@ class TestImageColor(PillowTestCase): self.assertEqual((255, 0, 0), ImageColor.getrgb("hsv(0,100%,100%)")) self.assertEqual((255, 0, 0), ImageColor.getrgb("hsv(360,100%,100%)")) - self.assertEqual((0, 255, 255), ImageColor.getrgb("hsv(180,100%,100%)")) + self.assertEqual((0, 255, 255), + ImageColor.getrgb("hsv(180,100%,100%)")) # alternate format self.assertEqual(ImageColor.getrgb("hsb(0,100%,50%)"), ImageColor.getrgb("hsv(0,100%,50%)")) # floats - self.assertEqual((254, 3, 3), ImageColor.getrgb("hsl(0.1,99.2%,50.3%)")) - self.assertEqual((255, 0, 0), ImageColor.getrgb("hsl(360.,100.0%,50%)")) + self.assertEqual((254, 3, 3), + ImageColor.getrgb("hsl(0.1,99.2%,50.3%)")) + self.assertEqual((255, 0, 0), + ImageColor.getrgb("hsl(360.,100.0%,50%)")) - self.assertEqual((253, 2, 2), ImageColor.getrgb("hsv(0.1,99.2%,99.3%)")) - self.assertEqual((255, 0, 0), ImageColor.getrgb("hsv(360.,100.0%,100%)")) + self.assertEqual((253, 2, 2), + ImageColor.getrgb("hsv(0.1,99.2%,99.3%)")) + self.assertEqual((255, 0, 0), + ImageColor.getrgb("hsv(360.,100.0%,100%)")) # case insensitivity self.assertEqual(ImageColor.getrgb("RGB(255,0,0)"), diff --git a/Tests/test_imageenhance.py b/Tests/test_imageenhance.py index e9727613b..54288f4db 100644 --- a/Tests/test_imageenhance.py +++ b/Tests/test_imageenhance.py @@ -45,8 +45,9 @@ class TestImageEnhance(PillowTestCase): for op in ['Color', 'Brightness', 'Contrast', 'Sharpness']: for amount in [0, 0.5, 1.0]: - self._check_alpha(getattr(ImageEnhance, op)(original).enhance(amount), - original, op, amount) + self._check_alpha( + getattr(ImageEnhance, op)(original).enhance(amount), + original, op, amount) if __name__ == '__main__': diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index 4b750af0d..837e81d30 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -215,12 +215,16 @@ class TestPyDecoder(PillowTestCase): buf = BytesIO(b'\x00'*255) im = MockImageFile(buf) - im.tile = [("MOCK", (xoff, yoff, xoff+xsize + 100, yoff+ysize), 32, None)] + im.tile = [ + ("MOCK", (xoff, yoff, xoff+xsize + 100, yoff+ysize), 32, None) + ] d = self.get_decoder() self.assertRaises(ValueError, im.load) - im.tile = [("MOCK", (xoff, yoff, xoff+xsize, yoff+ysize + 100), 32, None)] + im.tile = [ + ("MOCK", (xoff, yoff, xoff+xsize, yoff+ysize + 100), 32, None) + ] self.assertRaises(ValueError, im.load) def test_no_format(self): diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index e333346e9..f2116bdc4 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -67,8 +67,11 @@ class TestImageFont(PillowTestCase): } def setUp(self): - freetype_version = tuple(ImageFont.core.freetype2_version.split('.'))[:2] - self.metrics = self.METRICS.get(freetype_version, self.METRICS['Default']) + freetype_version = tuple( + ImageFont.core.freetype2_version.split('.') + )[:2] + self.metrics = self.METRICS.get(freetype_version, + self.METRICS['Default']) def get_font(self): return ImageFont.truetype(FONT_PATH, FONT_SIZE, @@ -202,7 +205,8 @@ class TestImageFont(PillowTestCase): target_img = Image.open(target) # Epsilon ~.5 fails with FreeType 2.7 - self.assert_image_similar(im, target_img, self.metrics['multiline']) + self.assert_image_similar(im, target_img, + self.metrics['multiline']) def test_unknown_align(self): im = Image.new(mode='RGB', size=(300, 100)) @@ -427,7 +431,8 @@ class TestImageFont(PillowTestCase): # Make a copy of FreeTypeFont so we can patch the original free_type_font = copy.deepcopy(ImageFont.FreeTypeFont) with SimplePatcher(ImageFont, '_FreeTypeFont', free_type_font): - def loadable_font(filepath, size, index, encoding, *args, **kwargs): + def loadable_font(filepath, size, index, encoding, + *args, **kwargs): if filepath == path_to_fake: return ImageFont._FreeTypeFont(FONT_PATH, size, index, encoding, *args, **kwargs) diff --git a/Tests/test_imagefont_bitmap.py b/Tests/test_imagefont_bitmap.py index bee415fd7..8376728a2 100644 --- a/Tests/test_imagefont_bitmap.py +++ b/Tests/test_imagefont_bitmap.py @@ -19,7 +19,8 @@ class TestImageFontBitmap(PillowTestCase): font='Tests/fonts/DejaVuSans-bitmap.ttf', size=24) size_outline = font_outline.getsize(text) size_bitmap = font_bitmap.getsize(text) - size_final = max(size_outline[0], size_bitmap[0]), max(size_outline[1], size_bitmap[1]) + size_final = (max(size_outline[0], size_bitmap[0]), + max(size_outline[1], size_bitmap[1])) im_bitmap = Image.new('RGB', size_final, (255, 255, 255)) im_outline = im_bitmap.copy() draw_bitmap = ImageDraw.Draw(im_bitmap) diff --git a/Tests/test_imagefontctl.py b/Tests/test_imagefontctl.py index 489ed40b5..04432b14f 100644 --- a/Tests/test_imagefontctl.py +++ b/Tests/test_imagefontctl.py @@ -30,7 +30,8 @@ class TestImagecomplextext(PillowTestCase): self.assert_image_similar(im, target_img, .5) def test_y_offset(self): - ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", FONT_SIZE) + ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", + FONT_SIZE) im = Image.new(mode='RGB', size=(300, 100)) draw = ImageDraw.Draw(im) @@ -70,7 +71,8 @@ class TestImagecomplextext(PillowTestCase): im = Image.new(mode='RGB', size=(300, 100)) draw = ImageDraw.Draw(im) - draw.text((0, 0), 'سلطنة عمان Oman', font=ttf, fill=500, direction='ltr') + draw.text((0, 0), 'سلطنة عمان Oman', + font=ttf, fill=500, direction='ltr') target = 'Tests/images/test_direction_ltr.png' target_img = Image.open(target) @@ -82,7 +84,8 @@ class TestImagecomplextext(PillowTestCase): im = Image.new(mode='RGB', size=(300, 100)) draw = ImageDraw.Draw(im) - draw.text((0, 0), 'Oman سلطنة عمان', font=ttf, fill=500, direction='rtl') + draw.text((0, 0), 'Oman سلطنة عمان', + font=ttf, fill=500, direction='rtl') target = 'Tests/images/test_direction_ltr.png' target_img = Image.open(target) @@ -120,7 +123,8 @@ class TestImagecomplextext(PillowTestCase): im = Image.new(mode='RGB', size=(300, 100)) draw = ImageDraw.Draw(im) - draw.text((0, 0), 'اللغة العربية', font=ttf, fill=500, features=['-fina', '-init', '-medi']) + draw.text((0, 0), 'اللغة العربية', font=ttf, fill=500, + features=['-fina', '-init', '-medi']) target = 'Tests/images/test_arabictext_features.png' target_img = Image.open(target) diff --git a/Tests/test_imagemorph.py b/Tests/test_imagemorph.py index 83fa0b5a9..dceadebf4 100644 --- a/Tests/test_imagemorph.py +++ b/Tests/test_imagemorph.py @@ -265,8 +265,9 @@ class MorphTests(PillowTestCase): # Act / Assert with self.assertRaises(Exception) as e: lb.build_lut() - self.assertEqual(str(e.exception), - 'Syntax error in pattern "a pattern with a syntax error"') + self.assertEqual( + str(e.exception), + 'Syntax error in pattern "a pattern with a syntax error"') def test_load_invalid_mrl(self): # Arrange diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index 89c8e297f..e0fcf264a 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -34,7 +34,8 @@ class TestLibPack(PillowTestCase): self.assert_pack("1", "1;R", b'\xaa', 0, X, 0, X, 0, X, 0, X) self.assert_pack("1", "1;IR", b'\xaa', X, 0, X, 0, X, 0, X, 0) - self.assert_pack("1", "L", b'\xff\x00\x00\xff\x00\x00', X, 0, 0, X, 0, 0) + self.assert_pack( + "1", "L", b'\xff\x00\x00\xff\x00\x00', X, 0, 0, X, 0, 0) def test_L(self): self.assert_pack("L", "L", 1, 1, 2, 3, 4) @@ -80,8 +81,10 @@ class TestLibPack(PillowTestCase): "RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) self.assert_pack( "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) - self.assert_pack("RGBA", "RGB", 3, (1, 2, 3, 14), (4, 5, 6, 15), (7, 8, 9, 16)) - self.assert_pack("RGBA", "BGR", 3, (3, 2, 1, 14), (6, 5, 4, 15), (9, 8, 7, 16)) + self.assert_pack( + "RGBA", "RGB", 3, (1, 2, 3, 14), (4, 5, 6, 15), (7, 8, 9, 16)) + self.assert_pack( + "RGBA", "BGR", 3, (3, 2, 1, 14), (6, 5, 4, 15), (9, 8, 7, 16)) self.assert_pack( "RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) @@ -90,10 +93,14 @@ class TestLibPack(PillowTestCase): self.assert_pack( "RGBA", "BGRa", 4, (191, 127, 63, 4), (223, 191, 159, 8), (233, 212, 191, 12)) - self.assert_pack("RGBA", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) - self.assert_pack("RGBA", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) - self.assert_pack("RGBA", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) - self.assert_pack("RGBA", "A", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) + self.assert_pack( + "RGBA", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) + self.assert_pack( + "RGBA", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) + self.assert_pack( + "RGBA", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) + self.assert_pack( + "RGBA", "A", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) def test_RGBa(self): self.assert_pack( @@ -104,10 +111,14 @@ class TestLibPack(PillowTestCase): "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) def test_RGBX(self): - self.assert_pack("RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_pack("RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) - self.assert_pack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) - self.assert_pack("RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)) + self.assert_pack( + "RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) + self.assert_pack( + "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) + self.assert_pack( + "RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) + self.assert_pack( + "RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)) self.assert_pack( "RGBX", "BGRX", b'\x01\x02\x03\x00\x05\x06\x07\x00\t\n\x0b\x00', @@ -116,23 +127,30 @@ class TestLibPack(PillowTestCase): "RGBX", "XBGR", b'\x00\x02\x03\x04\x00\x06\x07\x08\x00\n\x0b\x0c', (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X)) - self.assert_pack("RGBX", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) - self.assert_pack("RGBX", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) - self.assert_pack("RGBX", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) - self.assert_pack("RGBX", "X", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) + self.assert_pack("RGBX", "R", 1, + (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) + self.assert_pack("RGBX", "G", 1, + (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) + self.assert_pack("RGBX", "B", 1, + (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) + self.assert_pack("RGBX", "X", 1, + (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) def test_CMYK(self): - self.assert_pack("CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) + self.assert_pack("CMYK", "CMYK", 4, + (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) self.assert_pack( "CMYK", "CMYK;I", 4, (254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243)) self.assert_pack( "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) - self.assert_pack("CMYK", "K", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) + self.assert_pack("CMYK", "K", 1, + (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) def test_YCbCr(self): self.assert_pack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_pack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) + self.assert_pack("YCbCr", "YCbCr;L", 3, + (1, 4, 7), (2, 5, 8), (3, 6, 9)) self.assert_pack( "YCbCr", "YCbCrX", b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff', @@ -141,9 +159,12 @@ class TestLibPack(PillowTestCase): "YCbCr", "YCbCrK", b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff', (1, 2, 3), (5, 6, 7), (9, 10, 11)) - self.assert_pack("YCbCr", "Y", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) - self.assert_pack("YCbCr", "Cb", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) - self.assert_pack("YCbCr", "Cr", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) + self.assert_pack("YCbCr", "Y", 1, + (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) + self.assert_pack("YCbCr", "Cb", 1, + (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) + self.assert_pack("YCbCr", "Cr", 1, + (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) def test_LAB(self): self.assert_pack( @@ -269,8 +290,10 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack("RGB", "RGBX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) self.assert_unpack("RGB", "RGBX;L", 4, (1, 4, 7), (2, 5, 8), (3, 6, 9)) self.assert_unpack("RGB", "BGRX", 4, (3, 2, 1), (7, 6, 5), (11, 10, 9)) - self.assert_unpack("RGB", "XRGB", 4, (2, 3, 4), (6, 7, 8), (10, 11, 12)) - self.assert_unpack("RGB", "XBGR", 4, (4, 3, 2), (8, 7, 6), (12, 11, 10)) + self.assert_unpack( + "RGB", "XRGB", 4, (2, 3, 4), (6, 7, 8), (10, 11, 12)) + self.assert_unpack( + "RGB", "XBGR", 4, (4, 3, 2), (8, 7, 6), (12, 11, 10)) self.assert_unpack( "RGB", "YCC;P", b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12', # random data @@ -280,7 +303,8 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack("RGB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) def test_RGBA(self): - self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)) + self.assert_unpack( + "RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)) self.assert_unpack( "RGBA", "LA;16B", 4, (1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11)) self.assert_unpack( @@ -322,9 +346,12 @@ class TestLibUnpack(PillowTestCase): "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) self.assert_unpack("RGBA", "RGBA;15", 2, (8, 131, 0, 0), (24, 0, 8, 0)) self.assert_unpack("RGBA", "BGRA;15", 2, (0, 131, 8, 0), (8, 0, 24, 0)) - self.assert_unpack("RGBA", "RGBA;4B", 2, (17, 0, 34, 0), (51, 0, 68, 0)) - self.assert_unpack("RGBA", "RGBA;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) - self.assert_unpack("RGBA", "RGBA;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) + self.assert_unpack( + "RGBA", "RGBA;4B", 2, (17, 0, 34, 0), (51, 0, 68, 0)) + self.assert_unpack( + "RGBA", "RGBA;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) + self.assert_unpack( + "RGBA", "RGBA;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) self.assert_unpack( "RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) self.assert_unpack( @@ -335,10 +362,14 @@ class TestLibUnpack(PillowTestCase): "RGBA", "YCCA;P", b']bE\x04\xdd\xbej\xed57T\xce\xac\xce:\x11', # random data (0, 161, 0, 4), (255, 255, 255, 237), (27, 158, 0, 206), (0, 118, 0, 17)) - self.assert_unpack("RGBA", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) - self.assert_unpack("RGBA", "G", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) - self.assert_unpack("RGBA", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) - self.assert_unpack("RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) + self.assert_unpack( + "RGBA", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) + self.assert_unpack( + "RGBA", "G", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) + self.assert_unpack( + "RGBA", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) + self.assert_unpack( + "RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) def test_RGBa(self): self.assert_unpack( @@ -351,10 +382,13 @@ class TestLibUnpack(PillowTestCase): "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) def test_RGBX(self): - self.assert_unpack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) - self.assert_unpack("RGBX", "RGB;L", 3, (1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X)) + self.assert_unpack("RGBX", "RGB", 3, + (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) + self.assert_unpack("RGBX", "RGB;L", 3, + (1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X)) self.assert_unpack("RGBX", "RGB;16B", 6, (1, 3, 5, X), (7, 9, 11, X)) - self.assert_unpack("RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)) + self.assert_unpack("RGBX", "BGR", 3, + (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)) self.assert_unpack("RGBX", "RGB;15", 2, (8, 131, 0, X), (24, 0, 8, X)) self.assert_unpack("RGBX", "BGR;15", 2, (0, 131, 8, X), (8, 0, 24, X)) self.assert_unpack("RGBX", "RGB;4B", 2, (17, 0, 34, X), (51, 0, 68, X)) @@ -366,19 +400,28 @@ class TestLibUnpack(PillowTestCase): "RGBX", "RGBXXX", 6, (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16)) self.assert_unpack( "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) - self.assert_unpack("RGBX", "RGBX;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) - self.assert_unpack("RGBX", "RGBX;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) - self.assert_unpack("RGBX", "BGRX", 4, (3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X)) - self.assert_unpack("RGBX", "XRGB", 4, (2, 3, 4, X), (6, 7, 8, X), (10, 11, 12, X)) - self.assert_unpack("RGBX", "XBGR", 4, (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X)) + self.assert_unpack("RGBX", "RGBX;16L", 8, + (2, 4, 6, 8), (10, 12, 14, 16)) + self.assert_unpack("RGBX", "RGBX;16B", 8, + (1, 3, 5, 7), (9, 11, 13, 15)) + self.assert_unpack("RGBX", "BGRX", 4, + (3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X)) + self.assert_unpack("RGBX", "XRGB", 4, + (2, 3, 4, X), (6, 7, 8, X), (10, 11, 12, X)) + self.assert_unpack("RGBX", "XBGR", 4, + (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X)) self.assert_unpack( "RGBX", "YCC;P", b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12', # random data (127, 102, 0, X), (192, 227, 0, X), (213, 255, 170, X), (98, 255, 133, X)) - self.assert_unpack("RGBX", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) - self.assert_unpack("RGBX", "G", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) - self.assert_unpack("RGBX", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) - self.assert_unpack("RGBX", "X", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) + self.assert_unpack("RGBX", "R", 1, + (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) + self.assert_unpack("RGBX", "G", 1, + (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) + self.assert_unpack("RGBX", "B", 1, + (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) + self.assert_unpack("RGBX", "X", 1, + (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) def test_CMYK(self): self.assert_unpack( @@ -392,10 +435,14 @@ class TestLibUnpack(PillowTestCase): (254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243)) self.assert_unpack( "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)) - self.assert_unpack("CMYK", "C", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) - self.assert_unpack("CMYK", "M", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) - self.assert_unpack("CMYK", "Y", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) - self.assert_unpack("CMYK", "K", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) + self.assert_unpack("CMYK", "C", 1, + (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) + self.assert_unpack("CMYK", "M", 1, + (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) + self.assert_unpack("CMYK", "Y", 1, + (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) + self.assert_unpack("CMYK", "K", 1, + (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) self.assert_unpack( "CMYK", "C;I", 1, (254, 0, 0, 0), (253, 0, 0, 0), (252, 0, 0, 0)) self.assert_unpack( @@ -451,7 +498,8 @@ class TestLibUnpack(PillowTestCase): if sys.byteorder == 'little': self.assert_unpack("I", "I", 4, 0x04030201, 0x08070605) self.assert_unpack("I", "I;16N", 2, 0x0201, 0x0403) - self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', 0x0183, -31999) + self.assert_unpack("I", "I;16NS", + b'\x83\x01\x01\x83', 0x0183, -31999) self.assert_unpack("I", "I;32N", 4, 0x04030201, 0x08070605) self.assert_unpack( "I", "I;32NS", @@ -459,7 +507,8 @@ class TestLibUnpack(PillowTestCase): else: self.assert_unpack("I", "I", 4, 0x01020304, 0x05060708) self.assert_unpack("I", "I;16N", 2, 0x0102, 0x0304) - self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', -31999, 0x0183) + self.assert_unpack("I", "I;16NS", + b'\x83\x01\x01\x83', -31999, 0x0183) self.assert_unpack("I", "I;32N", 4, 0x01020304, 0x05060708) self.assert_unpack( "I", "I;32NS", @@ -483,14 +532,18 @@ class TestLibUnpack(PillowTestCase): if sys.byteorder == 'little': self.assert_unpack("F", "F;16N", 2, 0x0201, 0x0403) - self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', 0x0183, -31999) + self.assert_unpack( + "F", "F;16NS", + b'\x83\x01\x01\x83', 0x0183, -31999) self.assert_unpack("F", "F;32N", 4, 67305984, 134678016) self.assert_unpack( "F", "F;32NS", b'\x83\x00\x00\x01\x01\x00\x00\x83', 16777348, -2097152000) else: self.assert_unpack("F", "F;16N", 2, 0x0102, 0x0304) - self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', -31999, 0x0183) + self.assert_unpack( + "F", "F;16NS", + b'\x83\x01\x01\x83', -31999, 0x0183) self.assert_unpack("F", "F;32N", 4, 0x01020304, 0x05060708) self.assert_unpack( "F", "F;32NS", diff --git a/Tests/test_map.py b/Tests/test_map.py index 14bd835a2..8e3916d27 100644 --- a/Tests/test_map.py +++ b/Tests/test_map.py @@ -4,7 +4,8 @@ import sys from PIL import Image -@unittest.skipIf(sys.platform.startswith('win32'), "Win32 does not call map_buffer") +@unittest.skipIf(sys.platform.startswith('win32'), + "Win32 does not call map_buffer") class TestMap(PillowTestCase): def test_overflow(self): # There is the potential to overflow comparisons in map.c diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index 1501e54bb..4efcd2c51 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -124,7 +124,9 @@ class TestNumpy(PillowTestCase): def test_save_tiff_uint16(self): # Tests that we're getting the pixel value in the right byte order. pixel_value = 0x1234 - a = numpy.array([pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1], dtype=numpy.uint16) + a = numpy.array( + [pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1], + dtype=numpy.uint16) a.shape = TEST_IMAGE_SIZE img = Image.fromarray(a) diff --git a/Tests/test_pdfparser.py b/Tests/test_pdfparser.py index db97c97dd..42c813520 100644 --- a/Tests/test_pdfparser.py +++ b/Tests/test_pdfparser.py @@ -1,6 +1,8 @@ from helper import unittest, PillowTestCase -from PIL.PdfParser import IndirectObjectDef, IndirectReference, PdfBinary, PdfDict, PdfFormatError, PdfName, PdfParser, PdfStream, decode_text, encode_text, pdf_repr +from PIL.PdfParser import IndirectObjectDef, IndirectReference, PdfBinary, \ + PdfDict, PdfFormatError, PdfName, PdfParser, \ + PdfStream, decode_text, encode_text, pdf_repr class TestPdfParser(PillowTestCase): @@ -22,23 +24,35 @@ class TestPdfParser(PillowTestCase): self.assertNotEqual(IndirectObjectDef(1, 2), (1, 2)) def test_parsing(self): - self.assertEqual(PdfParser.interpret_name(b"Name#23Hash"), b"Name#Hash") + self.assertEqual(PdfParser.interpret_name(b"Name#23Hash"), + b"Name#Hash") self.assertEqual(PdfParser.interpret_name(b"Name#23Hash", as_text=True), "Name#Hash") - self.assertEqual(PdfParser.get_value(b"1 2 R ", 0), (IndirectReference(1, 2), 5)) + self.assertEqual(PdfParser.get_value(b"1 2 R ", 0), + (IndirectReference(1, 2), 5)) self.assertEqual(PdfParser.get_value(b"true[", 0), (True, 4)) self.assertEqual(PdfParser.get_value(b"false%", 0), (False, 5)) self.assertEqual(PdfParser.get_value(b"null<", 0), (None, 4)) - self.assertEqual(PdfParser.get_value(b"%cmt\n %cmt\n 123\n", 0), (123, 15)) - self.assertEqual(PdfParser.get_value(b"<901FA3>", 0), (b"\x90\x1F\xA3", 8)) - self.assertEqual(PdfParser.get_value(b"asd < 9 0 1 f A > qwe", 3), (b"\x90\x1F\xA0", 17)) + self.assertEqual(PdfParser.get_value(b"%cmt\n %cmt\n 123\n", 0), + (123, 15)) + self.assertEqual(PdfParser.get_value(b"<901FA3>", 0), + (b"\x90\x1F\xA3", 8)) + self.assertEqual(PdfParser.get_value(b"asd < 9 0 1 f A > qwe", 3), + (b"\x90\x1F\xA0", 17)) self.assertEqual(PdfParser.get_value(b"(asd)", 0), (b"asd", 5)) - self.assertEqual(PdfParser.get_value(b"(asd(qwe)zxc)zzz(aaa)", 0), (b"asd(qwe)zxc", 13)) - self.assertEqual(PdfParser.get_value(b"(Two \\\nwords.)", 0), (b"Two words.", 14)) - self.assertEqual(PdfParser.get_value(b"(Two\nlines.)", 0), (b"Two\nlines.", 12)) - self.assertEqual(PdfParser.get_value(b"(Two\r\nlines.)", 0), (b"Two\nlines.", 13)) - self.assertEqual(PdfParser.get_value(b"(Two\\nlines.)", 0), (b"Two\nlines.", 13)) - self.assertEqual(PdfParser.get_value(b"(One\\(paren).", 0), (b"One(paren", 12)) - self.assertEqual(PdfParser.get_value(b"(One\\)paren).", 0), (b"One)paren", 12)) + self.assertEqual(PdfParser.get_value(b"(asd(qwe)zxc)zzz(aaa)", 0), + (b"asd(qwe)zxc", 13)) + self.assertEqual(PdfParser.get_value(b"(Two \\\nwords.)", 0), + (b"Two words.", 14)) + self.assertEqual(PdfParser.get_value(b"(Two\nlines.)", 0), + (b"Two\nlines.", 12)) + self.assertEqual(PdfParser.get_value(b"(Two\r\nlines.)", 0), + (b"Two\nlines.", 13)) + self.assertEqual(PdfParser.get_value(b"(Two\\nlines.)", 0), + (b"Two\nlines.", 13)) + self.assertEqual(PdfParser.get_value(b"(One\\(paren).", 0), + (b"One(paren", 12)) + self.assertEqual(PdfParser.get_value(b"(One\\)paren).", 0), + (b"One)paren", 12)) self.assertEqual(PdfParser.get_value(b"(\\0053)", 0), (b"\x053", 7)) self.assertEqual(PdfParser.get_value(b"(\\053)", 0), (b"\x2B", 6)) self.assertEqual(PdfParser.get_value(b"(\\53)", 0), (b"\x2B", 5)) @@ -65,23 +79,30 @@ class TestPdfParser(PillowTestCase): def test_pdf_repr(self): self.assertEqual(bytes(IndirectReference(1, 2)), b"1 2 R") - self.assertEqual(bytes(IndirectObjectDef(*IndirectReference(1, 2))), b"1 2 obj") + self.assertEqual(bytes(IndirectObjectDef(*IndirectReference(1, 2))), + b"1 2 obj") self.assertEqual(bytes(PdfName(b"Name#Hash")), b"/Name#23Hash") self.assertEqual(bytes(PdfName("Name#Hash")), b"/Name#23Hash") - self.assertEqual(bytes(PdfDict({b"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>") - self.assertEqual(bytes(PdfDict({"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>") + self.assertEqual(bytes(PdfDict({b"Name": IndirectReference(1, 2)})), + b"<<\n/Name 1 2 R\n>>") + self.assertEqual(bytes(PdfDict({"Name": IndirectReference(1, 2)})), + b"<<\n/Name 1 2 R\n>>") self.assertEqual(pdf_repr(IndirectReference(1, 2)), b"1 2 R") - self.assertEqual(pdf_repr(IndirectObjectDef(*IndirectReference(1, 2))), b"1 2 obj") + self.assertEqual(pdf_repr(IndirectObjectDef(*IndirectReference(1, 2))), + b"1 2 obj") self.assertEqual(pdf_repr(PdfName(b"Name#Hash")), b"/Name#23Hash") self.assertEqual(pdf_repr(PdfName("Name#Hash")), b"/Name#23Hash") - self.assertEqual(pdf_repr(PdfDict({b"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>") - self.assertEqual(pdf_repr(PdfDict({"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>") + self.assertEqual(pdf_repr(PdfDict({b"Name": IndirectReference(1, 2)})), + b"<<\n/Name 1 2 R\n>>") + self.assertEqual(pdf_repr(PdfDict({"Name": IndirectReference(1, 2)})), + b"<<\n/Name 1 2 R\n>>") self.assertEqual(pdf_repr(123), b"123") self.assertEqual(pdf_repr(True), b"true") self.assertEqual(pdf_repr(False), b"false") self.assertEqual(pdf_repr(None), b"null") self.assertEqual(pdf_repr(b"a)/b\\(c"), br"(a\)/b\\\(c)") - self.assertEqual(pdf_repr([123, True, {"a": PdfName(b"b")}]), b"[ 123 true <<\n/a /b\n>> ]") + self.assertEqual(pdf_repr([123, True, {"a": PdfName(b"b")}]), + b"[ 123 true <<\n/a /b\n>> ]") self.assertEqual(pdf_repr(PdfBinary(b"\x90\x1F\xA0")), b"<901FA0>") diff --git a/setup.py b/setup.py index 761d552cc..9529787f9 100755 --- a/setup.py +++ b/setup.py @@ -424,7 +424,8 @@ class pil_build_ext(build_ext): best_path = None for name in os.listdir(program_files): if name.startswith('OpenJPEG '): - version = tuple(int(x) for x in name[9:].strip().split('.')) + version = tuple(int(x) for x in + name[9:].strip().split('.')) if version > best_version: best_version = version best_path = os.path.join(program_files, name) @@ -501,7 +502,8 @@ class pil_build_ext(build_ext): # possible. _add_directory(self.compiler.include_dirs, best_path, 0) feature.jpeg2000 = 'openjp2' - feature.openjpeg_version = '.'.join(str(x) for x in best_version) + feature.openjpeg_version = '.'.join(str(x) for x in + best_version) if feature.want('imagequant'): _dbg('Looking for imagequant') @@ -516,7 +518,8 @@ class pil_build_ext(build_ext): if _find_include_file(self, 'tiff.h'): if _find_library_file(self, "tiff"): feature.tiff = "tiff" - if sys.platform == "win32" and _find_library_file(self, "libtiff"): + if (sys.platform == "win32" and + _find_library_file(self, "libtiff")): feature.tiff = "libtiff" if (sys.platform == "darwin" and _find_library_file(self, "libtiff")): @@ -528,14 +531,16 @@ class pil_build_ext(build_ext): # look for freetype2 include files freetype_version = 0 for subdir in self.compiler.include_dirs: - _dbg('Checking for include file %s in %s', ("ft2build.h", subdir)) + _dbg('Checking for include file %s in %s', + ("ft2build.h", subdir)) if os.path.isfile(os.path.join(subdir, "ft2build.h")): _dbg('Found %s in %s', ("ft2build.h", subdir)) freetype_version = 21 subdir = os.path.join(subdir, "freetype2") break subdir = os.path.join(subdir, "freetype2") - _dbg('Checking for include file %s in %s', ("ft2build.h", subdir)) + _dbg('Checking for include file %s in %s', + ("ft2build.h", subdir)) if os.path.isfile(os.path.join(subdir, "ft2build.h")): _dbg('Found %s in %s', ("ft2build.h", subdir)) freetype_version = 21 diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index f9e5ee5c8..8b86f9a00 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -60,7 +60,14 @@ class BmpImageFile(ImageFile.ImageFile): format_description = "Windows Bitmap" format = "BMP" # --------------------------------------------------- BMP Compression values - COMPRESSIONS = {'RAW': 0, 'RLE8': 1, 'RLE4': 2, 'BITFIELDS': 3, 'JPEG': 4, 'PNG': 5} + COMPRESSIONS = { + 'RAW': 0, + 'RLE8': 1, + 'RLE4': 2, + 'BITFIELDS': 3, + 'JPEG': 4, + 'PNG': 5 + } RAW, RLE8, RLE4, BITFIELDS, JPEG, PNG = 0, 1, 2, 3, 4, 5 def _bitmap(self, header=0, offset=0): @@ -69,10 +76,13 @@ class BmpImageFile(ImageFile.ImageFile): if header: seek(header) file_info = {} - file_info['header_size'] = i32(read(4)) # read bmp header size @offset 14 (this is part of the header size) + # read bmp header size @offset 14 (this is part of the header size) + file_info['header_size'] = i32(read(4)) file_info['direction'] = -1 # --------------------- If requested, read header at a specific position - header_data = ImageFile._safe_read(self.fp, file_info['header_size'] - 4) # read the rest of the bmp header, without its size + # read the rest of the bmp header, without its size + header_data = ImageFile._safe_read(self.fp, + file_info['header_size'] - 4) # --------------------------------------------------- IBM OS/2 Bitmap v1 # ------ This format has different offsets because of width/height types if file_info['header_size'] == 12: @@ -88,12 +98,16 @@ class BmpImageFile(ImageFile.ImageFile): file_info['y_flip'] = i8(header_data[7]) == 0xff file_info['direction'] = 1 if file_info['y_flip'] else -1 file_info['width'] = i32(header_data[0:4]) - file_info['height'] = i32(header_data[4:8]) if not file_info['y_flip'] else 2**32 - i32(header_data[4:8]) + file_info['height'] = (i32(header_data[4:8]) + if not file_info['y_flip'] + else 2**32 - i32(header_data[4:8])) file_info['planes'] = i16(header_data[8:10]) file_info['bits'] = i16(header_data[10:12]) file_info['compression'] = i32(header_data[12:16]) - file_info['data_size'] = i32(header_data[16:20]) # byte size of pixel data - file_info['pixels_per_meter'] = (i32(header_data[20:24]), i32(header_data[24:28])) + # byte size of pixel data + file_info['data_size'] = i32(header_data[16:20]) + file_info['pixels_per_meter'] = (i32(header_data[20:24]), + i32(header_data[24:28])) file_info['colors'] = i32(header_data[28:32]) file_info['palette_padding'] = 4 self.info["dpi"] = tuple( @@ -101,21 +115,32 @@ class BmpImageFile(ImageFile.ImageFile): file_info['pixels_per_meter'])) if file_info['compression'] == self.BITFIELDS: if len(header_data) >= 52: - for idx, mask in enumerate(['r_mask', 'g_mask', 'b_mask', 'a_mask']): + for idx, mask in enumerate(['r_mask', + 'g_mask', + 'b_mask', + 'a_mask']): file_info[mask] = i32(header_data[36+idx*4:40+idx*4]) else: - # 40 byte headers only have the three components in the bitfields masks, + # 40 byte headers only have the three components in the + # bitfields masks, # ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx # See also https://github.com/python-pillow/Pillow/issues/1293 - # There is a 4th component in the RGBQuad, in the alpha location, but it - # is listed as a reserved component, and it is not generally an alpha channel + # There is a 4th component in the RGBQuad, in the alpha + # location, but it is listed as a reserved component, + # and it is not generally an alpha channel file_info['a_mask'] = 0x0 for mask in ['r_mask', 'g_mask', 'b_mask']: file_info[mask] = i32(read(4)) - file_info['rgb_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask']) - file_info['rgba_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask'], file_info['a_mask']) + file_info['rgb_mask'] = (file_info['r_mask'], + file_info['g_mask'], + file_info['b_mask']) + file_info['rgba_mask'] = (file_info['r_mask'], + file_info['g_mask'], + file_info['b_mask'], + file_info['a_mask']) else: - raise IOError("Unsupported BMP header type (%d)" % file_info['header_size']) + raise IOError("Unsupported BMP header type (%d)" % + file_info['header_size']) # ------------------ Special case : header is reported 40, which # ---------------------- is shorter than real size for bpp >= 16 self.size = file_info['width'], file_info['height'] @@ -127,11 +152,15 @@ class BmpImageFile(ImageFile.ImageFile): # ----------------------- Check bit depth for unusual unsupported values self.mode, raw_mode = BIT2MODE.get(file_info['bits'], (None, None)) if self.mode is None: - raise IOError("Unsupported BMP pixel depth (%d)" % file_info['bits']) + raise IOError("Unsupported BMP pixel depth (%d)" + % file_info['bits']) # ----------------- Process BMP with Bitfields compression (not palette) if file_info['compression'] == self.BITFIELDS: SUPPORTED = { - 32: [(0xff0000, 0xff00, 0xff, 0x0), (0xff0000, 0xff00, 0xff, 0xff000000), (0x0, 0x0, 0x0, 0x0), (0xff000000, 0xff0000, 0xff00, 0x0)], + 32: [(0xff0000, 0xff00, 0xff, 0x0), + (0xff0000, 0xff00, 0xff, 0xff000000), + (0x0, 0x0, 0x0, 0x0), + (0xff000000, 0xff0000, 0xff00, 0x0)], 24: [(0xff0000, 0xff00, 0xff)], 16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)] } @@ -145,11 +174,15 @@ class BmpImageFile(ImageFile.ImageFile): (16, (0x7c00, 0x3e0, 0x1f)): "BGR;15" } if file_info['bits'] in SUPPORTED: - if file_info['bits'] == 32 and file_info['rgba_mask'] in SUPPORTED[file_info['bits']]: + if file_info['bits'] == 32 and \ + file_info['rgba_mask'] in SUPPORTED[file_info['bits']]: raw_mode = MASK_MODES[(file_info['bits'], file_info['rgba_mask'])] self.mode = "RGBA" if raw_mode in ("BGRA",) else self.mode - elif file_info['bits'] in (24, 16) and file_info['rgb_mask'] in SUPPORTED[file_info['bits']]: - raw_mode = MASK_MODES[(file_info['bits'], file_info['rgb_mask'])] + elif (file_info['bits'] in (24, 16) and + file_info['rgb_mask'] in SUPPORTED[file_info['bits']]): + raw_mode = MASK_MODES[ + (file_info['bits'], file_info['rgb_mask']) + ] else: raise IOError("Unsupported BMP bitfields layout") else: @@ -158,17 +191,20 @@ class BmpImageFile(ImageFile.ImageFile): if file_info['bits'] == 32 and header == 22: # 32-bit .cur offset raw_mode, self.mode = "BGRA", "RGBA" else: - raise IOError("Unsupported BMP compression (%d)" % file_info['compression']) + raise IOError("Unsupported BMP compression (%d)" % + file_info['compression']) # ---------------- Once the header is processed, process the palette/LUT if self.mode == "P": # Paletted for 1, 4 and 8 bit images # ----------------------------------------------------- 1-bit images if not (0 < file_info['colors'] <= 65536): - raise IOError("Unsupported BMP Palette size (%d)" % file_info['colors']) + raise IOError("Unsupported BMP Palette size (%d)" % + file_info['colors']) else: padding = file_info['palette_padding'] palette = read(padding * file_info['colors']) greyscale = True - indices = (0, 255) if file_info['colors'] == 2 else list(range(file_info['colors'])) + indices = (0, 255) if file_info['colors'] == 2 else \ + list(range(file_info['colors'])) # ------------------ Check if greyscale and ignore palette if so for ind, val in enumerate(indices): rgb = palette[ind*padding:ind*padding + 3] @@ -180,13 +216,19 @@ class BmpImageFile(ImageFile.ImageFile): raw_mode = self.mode else: self.mode = "P" - self.palette = ImagePalette.raw("BGRX" if padding == 4 else "BGR", palette) + self.palette = ImagePalette.raw( + "BGRX" if padding == 4 else "BGR", palette) # ----------------------------- Finally set the tile data for the plugin self.info['compression'] = file_info['compression'] - self.tile = [('raw', (0, 0, file_info['width'], file_info['height']), offset or self.fp.tell(), - (raw_mode, ((file_info['width'] * file_info['bits'] + 31) >> 3) & (~3), file_info['direction']) - )] + self.tile = [ + ('raw', + (0, 0, file_info['width'], file_info['height']), + offset or self.fp.tell(), + (raw_mode, + ((file_info['width'] * file_info['bits'] + 31) >> 3) & (~3), + file_info['direction'])) + ] def _open(self): """ Open file, check magic number and read header """ diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index e755f94b9..3bd65c93d 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -142,7 +142,8 @@ class DdsImageFile(ImageFile.ImageFile): # ignoring flags which pertain to volume textures and cubemaps dxt10 = BytesIO(self.fp.read(20)) dxgi_format, dimension = struct.unpack("= 8 and i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1, 2) + return len(prefix) >= 8 and \ + i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1, 2) ## @@ -54,7 +55,8 @@ class GbrImageFile(ImageFile.ImageFile): if width <= 0 or height <= 0: raise SyntaxError("not a GIMP brush") if color_depth not in (1, 4): - raise SyntaxError("Unsupported GIMP brush color depth: %s" % color_depth) + raise SyntaxError( + "Unsupported GIMP brush color depth: %s" % color_depth) if version == 1: comment_length = header_size-20 diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index e0da01129..fec2f7663 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -397,7 +397,8 @@ def _write_multiple_frames(im, fp, palette): im_frames = [] frame_count = 0 - for imSequence in itertools.chain([im], im.encoderinfo.get("append_images", [])): + 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 im_frame = _normalize_mode(im_frame.copy()) @@ -413,17 +414,19 @@ 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']): + if _get_palette_bytes(im_frame) == \ + _get_palette_bytes(previous['im']): delta = ImageChops.subtract_modulo(im_frame, previous['im']) else: - delta = ImageChops.subtract_modulo(im_frame.convert('RGB'), - previous['im'].convert('RGB')) + delta = ImageChops.subtract_modulo( + im_frame.convert('RGB'), previous['im'].convert('RGB')) bbox = delta.getbbox() if not bbox: # This frame is identical to the previous frame if duration: - previous['encoderinfo']['duration'] += encoderinfo['duration'] + previous['encoderinfo']['duration'] += \ + encoderinfo['duration'] continue else: bbox = None @@ -525,7 +528,8 @@ def _write_local_header(fp, im, offset, flags): o8(transparency) + # transparency index o8(0)) - if "comment" in im.encoderinfo and 1 <= len(im.encoderinfo["comment"]) <= 255: + if "comment" in im.encoderinfo and \ + 1 <= len(im.encoderinfo["comment"]) <= 255: fp.write(b"!" + o8(254) + # extension intro o8(len(im.encoderinfo["comment"])) + @@ -691,7 +695,8 @@ def _get_global_header(im, info): for extensionKey in ["transparency", "duration", "loop", "comment"]: if info and extensionKey in info: if ((extensionKey == "duration" and info[extensionKey] == 0) or - (extensionKey == "comment" and not (1 <= len(info[extensionKey]) <= 255))): + (extensionKey == "comment" and + not (1 <= len(info[extensionKey]) <= 255))): continue version = b"89a" break diff --git a/src/PIL/ImageCms.py b/src/PIL/ImageCms.py index d82e30efc..4b6281f13 100644 --- a/src/PIL/ImageCms.py +++ b/src/PIL/ImageCms.py @@ -305,10 +305,10 @@ def profileToProfile( :param renderingIntent: Integer (0-3) specifying the rendering intent you wish to use for the transform - INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) - INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) - INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) - INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) + ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT) + ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1 + ImageCms.INTENT_SATURATION = 2 + ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3 see the pyCMS documentation for details on rendering intents and what they do. @@ -424,10 +424,10 @@ def buildTransform( :param renderingIntent: Integer (0-3) specifying the rendering intent you wish to use for the transform - INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) - INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) - INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) - INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) + ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT) + ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1 + ImageCms.INTENT_SATURATION = 2 + ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3 see the pyCMS documentation for details on rendering intents and what they do. @@ -512,20 +512,20 @@ def buildProofTransform( :param renderingIntent: Integer (0-3) specifying the rendering intent you wish to use for the input->proof (simulated) transform - INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) - INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) - INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) - INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) + ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT) + ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1 + ImageCms.INTENT_SATURATION = 2 + ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3 see the pyCMS documentation for details on rendering intents and what they do. - :param proofRenderingIntent: Integer (0-3) specifying the rendering intent you - wish to use for proof->output transform + :param proofRenderingIntent: Integer (0-3) specifying the rendering intent + you wish to use for proof->output transform - INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) - INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) - INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) - INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) + ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT) + ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1 + ImageCms.INTENT_SATURATION = 2 + ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3 see the pyCMS documentation for details on rendering intents and what they do. @@ -875,10 +875,10 @@ def getDefaultIntent(profile): :returns: Integer 0-3 specifying the default rendering intent for this profile. - INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) - INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) - INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) - INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) + ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT) + ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1 + ImageCms.INTENT_SATURATION = 2 + ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3 see the pyCMS documentation for details on rendering intents and what they do. @@ -913,15 +913,15 @@ def isIntentSupported(profile, intent, direction): :param intent: Integer (0-3) specifying the rendering intent you wish to use with this profile - INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) - INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) - INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) - INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) + ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT) + ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1 + ImageCms.INTENT_SATURATION = 2 + ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3 see the pyCMS documentation for details on rendering intents and what they do. - :param direction: Integer specifying if the profile is to be used for input, - output, or proof + :param direction: Integer specifying if the profile is to be used for + input, output, or proof INPUT = 0 (or use ImageCms.DIRECTION_INPUT) OUTPUT = 1 (or use ImageCms.DIRECTION_OUTPUT) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 920b977f4..bc8c0cf38 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -217,7 +217,8 @@ class ImageDraw(object): ink = fill if ink is not None: try: - mask, offset = font.getmask2(text, self.fontmode, *args, **kwargs) + mask, offset = font.getmask2(text, self.fontmode, + *args, **kwargs) xy = xy[0] + offset[0], xy[1] + offset[1] except AttributeError: try: diff --git a/src/PIL/ImageEnhance.py b/src/PIL/ImageEnhance.py index 11c9c3a06..1b78bfd9b 100644 --- a/src/PIL/ImageEnhance.py +++ b/src/PIL/ImageEnhance.py @@ -51,7 +51,8 @@ class Color(_Enhance): if 'A' in image.getbands(): self.intermediate_mode = 'LA' - self.degenerate = image.convert(self.intermediate_mode).convert(image.mode) + self.degenerate = image.convert( + self.intermediate_mode).convert(image.mode) class Contrast(_Enhance): diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 681dee524..bdcc43d1f 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -166,8 +166,9 @@ class ImageFile(Image.Image): if use_mmap: # try memory mapping decoder_name, extents, offset, args = self.tile[0] - if decoder_name == "raw" and len(args) >= 3 and args[0] == self.mode \ - and args[0] in Image._MAPMODES: + if decoder_name == "raw" and len(args) >= 3 and \ + args[0] == self.mode and \ + args[0] in Image._MAPMODES: try: if hasattr(Image.core, "map"): # use built-in mapper WIN32 only @@ -180,12 +181,14 @@ class ImageFile(Image.Image): # use mmap, if possible import mmap with open(self.filename, "r") as fp: - self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) + self.map = mmap.mmap(fp.fileno(), 0, + access=mmap.ACCESS_READ) self.im = Image.core.map_buffer( - self.map, self.size, decoder_name, extents, offset, args - ) + self.map, self.size, decoder_name, extents, + offset, args) readonly = 1 - # After trashing self.im, we might need to reload the palette data. + # After trashing self.im, + # we might need to reload the palette data. if self.palette: self.palette.dirty = 1 except (AttributeError, EnvironmentError, ImportError): @@ -217,7 +220,8 @@ class ImageFile(Image.Image): while True: try: s = read(self.decodermaxblock) - except (IndexError, struct.error): # truncated png/gif + except (IndexError, struct.error): + # truncated png/gif if LOAD_TRUNCATED_IMAGES: break else: @@ -229,7 +233,8 @@ class ImageFile(Image.Image): else: self.tile = [] raise IOError("image file is truncated " - "(%d bytes not processed)" % len(b)) + "(%d bytes not processed)" % + len(b)) b = b + s n, err_code = decoder.decode(b) @@ -588,10 +593,12 @@ class PyDecoder(object): """ Override to perform the decoding process. - :param buffer: A bytes object with the data to be decoded. If `handles_eof` - is set, then `buffer` will be empty and `self.fd` will be set. - :returns: A tuple of (bytes consumed, errcode). If finished with decoding - return <0 for the bytes consumed. Err codes are from `ERRORS` + :param buffer: A bytes object with the data to be decoded. + If `handles_eof` is set, then `buffer` will be empty and `self.fd` + will be set. + :returns: A tuple of (bytes consumed, errcode). + If finished with decoding return <0 for the bytes consumed. + Err codes are from `ERRORS` """ raise NotImplementedError() @@ -650,8 +657,8 @@ class PyDecoder(object): Convenience method to set the internal image from a stream of raw data :param data: Bytes to be set - :param rawmode: The rawmode to be used for the decoder. If not specified, - it will default to the mode of the image + :param rawmode: The rawmode to be used for the decoder. + If not specified, it will default to the mode of the image :returns: None """ diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 3ac29e8f6..099ccc4ff 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -141,7 +141,8 @@ class FreeTypeFont(object): self.layout_engine = layout_engine if isPath(font): - self.font = core.getfont(font, size, index, encoding, layout_engine=layout_engine) + self.font = core.getfont(font, size, index, encoding, + layout_engine=layout_engine) else: self.font_bytes = font.read() self.font = core.getfont( @@ -175,9 +176,11 @@ class FreeTypeFont(object): return self.font.getsize(text)[1] def getmask(self, text, mode="", direction=None, features=None): - return self.getmask2(text, mode, direction=direction, features=features)[0] + return self.getmask2(text, mode, direction=direction, + features=features)[0] - def getmask2(self, text, mode="", fill=Image.core.fill, direction=None, features=None, *args, **kwargs): + def getmask2(self, text, mode="", fill=Image.core.fill, direction=None, + features=None, *args, **kwargs): size, offset = self.font.getsize(text, direction, features) im = fill("L", size, 0) self.font.render(text, im.id, mode == "1", direction, features) @@ -194,12 +197,13 @@ class FreeTypeFont(object): :return: A FreeTypeFont object. """ - return FreeTypeFont(font=self.path if font is None else font, - size=self.size if size is None else size, - index=self.index if index is None else index, - encoding=self.encoding if encoding is None else encoding, - layout_engine=self.layout_engine if layout_engine is None else layout_engine - ) + return FreeTypeFont( + font=self.path if font is None else font, + size=self.size if size is None else size, + index=self.index if index is None else index, + encoding=self.encoding if encoding is None else encoding, + layout_engine=self.layout_engine if layout_engine is None else layout_engine + ) class TransposedFont(object): @@ -303,12 +307,16 @@ def truetype(font=None, size=10, index=0, encoding="", for walkfilename in walkfilenames: if ext and walkfilename == ttf_filename: fontpath = os.path.join(walkroot, walkfilename) - return FreeTypeFont(fontpath, size, index, encoding, layout_engine) - elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename: + return FreeTypeFont(fontpath, size, index, + encoding, layout_engine) + elif (not ext and + os.path.splitext(walkfilename)[0] == ttf_filename): fontpath = os.path.join(walkroot, walkfilename) if os.path.splitext(fontpath)[1] == '.ttf': - return FreeTypeFont(fontpath, size, index, encoding, layout_engine) - if not ext and first_font_with_a_different_extension is None: + return FreeTypeFont(fontpath, size, index, + encoding, layout_engine) + if not ext \ + and first_font_with_a_different_extension is None: first_font_with_a_different_extension = fontpath if first_font_with_a_different_extension: return FreeTypeFont(first_font_with_a_different_extension, size, diff --git a/src/PIL/ImageMode.py b/src/PIL/ImageMode.py index b227f2127..2b3377a14 100644 --- a/src/PIL/ImageMode.py +++ b/src/PIL/ImageMode.py @@ -42,7 +42,8 @@ def getmode(mode): for m, (basemode, basetype, bands) in Image._MODEINFO.items(): modes[m] = ModeDescriptor(m, bands, basemode, basetype) # extra experimental modes - modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L") + modes["RGBa"] = ModeDescriptor("RGBa", + ("R", "G", "B", "a"), "RGB", "L") modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L") modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L") modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L") diff --git a/src/PIL/ImageQt.py b/src/PIL/ImageQt.py index c9dc36312..2930c1d9c 100644 --- a/src/PIL/ImageQt.py +++ b/src/PIL/ImageQt.py @@ -119,7 +119,8 @@ def align8to32(bytes, width, mode): new_data = [] for i in range(len(bytes) // bytes_per_line): - new_data.append(bytes[i*bytes_per_line:(i+1)*bytes_per_line] + b'\x00' * extra_padding) + new_data.append(bytes[i*bytes_per_line:(i+1)*bytes_per_line] + + b'\x00' * extra_padding) return b''.join(new_data) diff --git a/src/PIL/ImageTk.py b/src/PIL/ImageTk.py index b5ad53df7..17bf32f62 100644 --- a/src/PIL/ImageTk.py +++ b/src/PIL/ImageTk.py @@ -195,7 +195,8 @@ class PhotoImage(object): # Pypy is using a ffi cdata element # (Pdb) self.tk.interp # - _imagingtk.tkinit(int(ffi.cast("uintptr_t", tk.interp)), 1) + _imagingtk.tkinit( + int(ffi.cast("uintptr_t", tk.interp)), 1) else: _imagingtk.tkinit(tk.interpaddr(), 1) except AttributeError: diff --git a/src/PIL/Jpeg2KImagePlugin.py b/src/PIL/Jpeg2KImagePlugin.py index 25fbefbca..7b170fe16 100644 --- a/src/PIL/Jpeg2KImagePlugin.py +++ b/src/PIL/Jpeg2KImagePlugin.py @@ -270,7 +270,8 @@ def _save(im, fp, filename): Image.register_open(Jpeg2KImageFile.format, Jpeg2KImageFile, _accept) Image.register_save(Jpeg2KImageFile.format, _save) -Image.register_extensions(Jpeg2KImageFile.format, [".jp2", ".j2k", ".jpc", ".jpf", ".jpx", ".j2c"]) +Image.register_extensions(Jpeg2KImageFile.format, + [".jp2", ".j2k", ".jpc", ".jpf", ".jpx", ".j2c"]) Image.register_mime(Jpeg2KImageFile.format, 'image/jp2') Image.register_mime(Jpeg2KImageFile.format, 'image/jpx') diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 97ef834d3..98c27010c 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -799,6 +799,7 @@ def jpeg_factory(fp=None, filename=None): Image.register_open(JpegImageFile.format, jpeg_factory, _accept) Image.register_save(JpegImageFile.format, _save) -Image.register_extensions(JpegImageFile.format, [".jfif", ".jpe", ".jpg", ".jpeg"]) +Image.register_extensions(JpegImageFile.format, + [".jfif", ".jpe", ".jpg", ".jpeg"]) Image.register_mime(JpegImageFile.format, "image/jpeg") diff --git a/src/PIL/MspImagePlugin.py b/src/PIL/MspImagePlugin.py index 9692d1162..b2c7a3d79 100644 --- a/src/PIL/MspImagePlugin.py +++ b/src/PIL/MspImagePlugin.py @@ -126,8 +126,9 @@ class MspDecoder(ImageFile.PyDecoder): continue row = self.fd.read(rowlen) if len(row) != rowlen: - raise IOError("Truncated MSP file, expected %d bytes on row %s", - (rowlen, x)) + raise IOError( + "Truncated MSP file, expected %d bytes on row %s", + (rowlen, x)) idx = 0 while idx < rowlen: runtype = i8(row[idx]) diff --git a/src/PIL/PdfImagePlugin.py b/src/PIL/PdfImagePlugin.py index 8538bcd49..d411bfc41 100644 --- a/src/PIL/PdfImagePlugin.py +++ b/src/PIL/PdfImagePlugin.py @@ -98,7 +98,8 @@ def _save(im, fp, filename, save_all=False): try: im_numberOfPages = im.n_frames except AttributeError: - # Image format does not have n_frames. It is a single frame image + # Image format does not have n_frames. + # It is a single frame image pass numberOfPages += im_numberOfPages for i in range(im_numberOfPages): @@ -115,9 +116,9 @@ def _save(im, fp, filename, save_all=False): for imSequence in ims: im_pages = ImageSequence.Iterator(imSequence) if save_all else [imSequence] for im in im_pages: - # FIXME: Should replace ASCIIHexDecode with RunLengthDecode (packbits) - # or LZWDecode (tiff/lzw compression). Note that PDF 1.2 also supports - # Flatedecode (zip compression). + # FIXME: Should replace ASCIIHexDecode with RunLengthDecode + # (packbits) or LZWDecode (tiff/lzw compression). Note that + # PDF 1.2 also supports Flatedecode (zip compression). bits = 8 params = None @@ -135,7 +136,12 @@ def _save(im, fp, filename, save_all=False): elif im.mode == "P": filter = "ASCIIHexDecode" palette = im.im.getpalette("RGB") - colorspace = [PdfParser.PdfName("Indexed"), PdfParser.PdfName("DeviceRGB"), 255, PdfParser.PdfBinary(palette)] + colorspace = [ + PdfParser.PdfName("Indexed"), + PdfParser.PdfName("DeviceRGB"), + 255, + PdfParser.PdfBinary(palette) + ] procset = "ImageI" # indexed color elif im.mode == "RGB": filter = "DCTDecode" @@ -166,7 +172,8 @@ def _save(im, fp, filename, save_all=False): elif filter == "FlateDecode": ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)]) elif filter == "RunLengthDecode": - ImageFile._save(im, op, [("packbits", (0, 0)+im.size, 0, im.mode)]) + ImageFile._save(im, op, + [("packbits", (0, 0)+im.size, 0, im.mode)]) else: raise ValueError("unsupported PDF filter (%s)" % filter) @@ -175,26 +182,37 @@ def _save(im, fp, filename, save_all=False): width, height = im.size - existing_pdf.write_obj(image_refs[pageNumber], stream=op.getvalue(), - Type=PdfParser.PdfName("XObject"), - Subtype=PdfParser.PdfName("Image"), - Width=width, # * 72.0 / resolution, - Height=height, # * 72.0 / resolution, - Filter=PdfParser.PdfName(filter), - BitsPerComponent=bits, - DecodeParams=params, - ColorSpace=colorspace) + existing_pdf.write_obj(image_refs[pageNumber], + stream=op.getvalue(), + Type=PdfParser.PdfName("XObject"), + Subtype=PdfParser.PdfName("Image"), + Width=width, # * 72.0 / resolution, + Height=height, # * 72.0 / resolution, + Filter=PdfParser.PdfName(filter), + BitsPerComponent=bits, + DecodeParams=params, + ColorSpace=colorspace) # # page existing_pdf.write_page(page_refs[pageNumber], - Resources=PdfParser.PdfDict( - ProcSet=[PdfParser.PdfName("PDF"), PdfParser.PdfName(procset)], - XObject=PdfParser.PdfDict(image=image_refs[pageNumber])), - MediaBox=[0, 0, int(width * 72.0 / resolution), int(height * 72.0 / resolution)], - Contents=contents_refs[pageNumber] - ) + Resources=PdfParser.PdfDict( + ProcSet=[ + PdfParser.PdfName("PDF"), + PdfParser.PdfName(procset) + ], + XObject=PdfParser.PdfDict( + image=image_refs[pageNumber] + ) + ), + MediaBox=[ + 0, + 0, + int(width * 72.0 / resolution), + int(height * 72.0 / resolution) + ], + Contents=contents_refs[pageNumber]) # # page contents @@ -204,7 +222,8 @@ def _save(im, fp, filename, save_all=False): int(width * 72.0 / resolution), int(height * 72.0 / resolution))) - existing_pdf.write_obj(contents_refs[pageNumber], stream=page_contents) + existing_pdf.write_obj(contents_refs[pageNumber], + stream=page_contents) pageNumber += 1 diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index 9031330da..971f44514 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -20,7 +20,8 @@ else: # Python 2.x return s # pragma: no cover -# see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set on page 656 +# see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set +# on page 656 def encode_text(s): return codecs.BOM_UTF16_BE + s.encode("utf_16_be") @@ -80,7 +81,8 @@ def decode_text(b): class PdfFormatError(RuntimeError): - """An error that probably indicates a syntactic or semantic error in the PDF file structure""" + """An error that probably indicates a syntactic or semantic error in the + PDF file structure""" pass @@ -89,7 +91,8 @@ def check_format_condition(condition, error_message): raise PdfFormatError(error_message) -class IndirectReference(collections.namedtuple("IndirectReferenceTuple", ["object_id", "generation"])): +class IndirectReference(collections.namedtuple("IndirectReferenceTuple", + ["object_id", "generation"])): def __str__(self): return "%s %s R" % self @@ -97,7 +100,9 @@ class IndirectReference(collections.namedtuple("IndirectReferenceTuple", ["objec return self.__str__().encode("us-ascii") def __eq__(self, other): - return other.__class__ is self.__class__ and other.object_id == self.object_id and other.generation == self.generation + return other.__class__ is self.__class__ and \ + other.object_id == self.object_id and \ + other.generation == self.generation def __ne__(self, other): return not (self == other) @@ -143,19 +148,26 @@ class XrefTable: elif key in self.deleted_entries: generation = self.deleted_entries[key] else: - raise IndexError("object ID " + str(key) + " cannot be deleted because it doesn't exist") + raise IndexError("object ID " + str(key) + + " cannot be deleted because it doesn't exist") def __contains__(self, key): return key in self.existing_entries or key in self.new_entries def __len__(self): - return len(set(self.existing_entries.keys()) | set(self.new_entries.keys()) | set(self.deleted_entries.keys())) + return len(set(self.existing_entries.keys()) | + set(self.new_entries.keys()) | + set(self.deleted_entries.keys())) def keys(self): - return (set(self.existing_entries.keys()) - set(self.deleted_entries.keys())) | set(self.new_entries.keys()) + return ( + set(self.existing_entries.keys()) - + set(self.deleted_entries.keys()) + ) | set(self.new_entries.keys()) def write(self, f): - keys = sorted(set(self.new_entries.keys()) | set(self.deleted_entries.keys())) + keys = sorted(set(self.new_entries.keys()) | + set(self.deleted_entries.keys())) deleted_keys = sorted(set(self.deleted_entries.keys())) startxref = f.tell() f.write(b"xref\n") @@ -172,10 +184,12 @@ class XrefTable: else: contiguous_keys = keys keys = None - f.write(make_bytes("%d %d\n" % (contiguous_keys[0], len(contiguous_keys)))) + f.write(make_bytes("%d %d\n" % + (contiguous_keys[0], len(contiguous_keys)))) for object_id in contiguous_keys: if object_id in self.new_entries: - f.write(make_bytes("%010d %05d n \n" % self.new_entries[object_id])) + f.write(make_bytes("%010d %05d n \n" % + self.new_entries[object_id])) else: this_deleted_object_id = deleted_keys.pop(0) check_format_condition(object_id == this_deleted_object_id, @@ -186,7 +200,9 @@ class XrefTable: next_in_linked_list = deleted_keys[0] except IndexError: next_in_linked_list = 0 - f.write(make_bytes("%010d %05d f \n" % (next_in_linked_list, self.deleted_entries[object_id]))) + f.write(make_bytes("%010d %05d f \n" % + (next_in_linked_list, + self.deleted_entries[object_id]))) return startxref @@ -203,7 +219,8 @@ class PdfName: return self.name.decode("us-ascii") def __eq__(self, other): - return (isinstance(other, PdfName) and other.name == self.name) or other == self.name + return (isinstance(other, PdfName) and other.name == self.name) or \ + other == self.name def __hash__(self): return hash(self.name) @@ -313,7 +330,9 @@ class PdfStream: expected_length = self.dictionary.Length return zlib.decompress(self.buf, bufsize=int(expected_length)) else: - raise NotImplementedError("stream filter %s unknown/unsupported" % repr(self.dictionary.Filter)) + raise NotImplementedError( + "stream filter %s unknown/unsupported" % + repr(self.dictionary.Filter)) def pdf_repr(x): @@ -323,7 +342,8 @@ def pdf_repr(x): return b"false" elif x is None: return b"null" - elif isinstance(x, PdfName) or isinstance(x, PdfDict) or isinstance(x, PdfArray) or isinstance(x, PdfBinary): + elif (isinstance(x, PdfName) or isinstance(x, PdfDict) or + isinstance(x, PdfArray) or isinstance(x, PdfBinary)): return bytes(x) elif isinstance(x, int): return str(x).encode("us-ascii") @@ -331,10 +351,15 @@ def pdf_repr(x): return bytes(PdfDict(x)) elif isinstance(x, list): return bytes(PdfArray(x)) - elif (py3 and isinstance(x, str)) or (not py3 and isinstance(x, unicode)): + elif ((py3 and isinstance(x, str)) or + (not py3 and isinstance(x, unicode))): return pdf_repr(encode_text(x)) elif isinstance(x, bytes): - return b"(" + x.replace(b"\\", b"\\\\").replace(b"(", b"\\(").replace(b")", b"\\)") + b")" # XXX escape more chars? handle binary garbage + # XXX escape more chars? handle binary garbage + x = x.replace(b"\\", b"\\\\") + x = x.replace(b"(", b"\\(") + x = x.replace(b")", b"\\)") + return b"(" + x + b")" else: return bytes(x) @@ -344,10 +369,13 @@ class PdfParser: Supports PDF up to 1.4 """ - def __init__(self, filename=None, f=None, buf=None, start_offset=0, mode="rb"): - # type: (PdfParser, str, file, Union[bytes, bytearray], int, str) -> None + def __init__(self, filename=None, f=None, + buf=None, start_offset=0, mode="rb"): + # type: (PdfParser, str, file, Union[bytes, bytearray], int, str) + # -> None if buf and f: - raise RuntimeError("specify buf or f or filename, but not both buf and f") + raise RuntimeError( + "specify buf or f or filename, but not both buf and f") self.filename = filename self.buf = buf self.f = f @@ -473,7 +501,8 @@ class PdfParser: if self.info: trailer_dict[b"Info"] = self.info_ref self.last_xref_section_offset = start_xref - self.f.write(b"trailer\n" + bytes(PdfDict(trailer_dict)) + make_bytes("\nstartxref\n%d\n%%%%EOF" % start_xref)) + self.f.write(b"trailer\n" + bytes(PdfDict(trailer_dict)) + + make_bytes("\nstartxref\n%d\n%%%%EOF" % start_xref)) def write_page(self, ref, *objs, **dict_obj): if isinstance(ref, int): @@ -535,13 +564,18 @@ class PdfParser: else: self.info = PdfDict(self.read_indirect(self.info_ref)) check_format_condition(b"Type" in self.root, "/Type missing in Root") - check_format_condition(self.root[b"Type"] == b"Catalog", "/Type in Root is not /Catalog") + check_format_condition(self.root[b"Type"] == b"Catalog", + "/Type in Root is not /Catalog") check_format_condition(b"Pages" in self.root, "/Pages missing in Root") - check_format_condition(isinstance(self.root[b"Pages"], IndirectReference), "/Pages in Root is not an indirect reference") + check_format_condition(isinstance(self.root[b"Pages"], + IndirectReference), + "/Pages in Root is not an indirect reference") self.pages_ref = self.root[b"Pages"] self.page_tree_root = self.read_indirect(self.pages_ref) self.pages = self.linearize_page_tree(self.page_tree_root) - # save the original list of page references in case the user modifies, adds or deletes some pages and we need to rewrite the pages and their list + # save the original list of page references + # in case the user modifies, adds or deletes some pages + # and we need to rewrite the pages and their list self.orig_pages = self.pages[:] def next_object_id(self, offset=None): @@ -562,10 +596,14 @@ class PdfParser: whitespace_mandatory = whitespace + b"+" newline_only = br"[\r\n]+" newline = whitespace_optional + newline_only + whitespace_optional - re_trailer_end = re.compile(whitespace_mandatory + br"trailer" + whitespace_optional + br"\<\<(.*\>\>)" + newline - + br"startxref" + newline + br"([0-9]+)" + newline + br"%%EOF" + whitespace_optional + br"$", re.DOTALL) - re_trailer_prev = re.compile(whitespace_optional + br"trailer" + whitespace_optional + br"\<\<(.*?\>\>)" + newline - + br"startxref" + newline + br"([0-9]+)" + newline + br"%%EOF" + whitespace_optional, re.DOTALL) + re_trailer_end = re.compile( + whitespace_mandatory + br"trailer" + whitespace_optional + + br"\<\<(.*\>\>)" + newline + br"startxref" + newline + br"([0-9]+)" + + newline + br"%%EOF" + whitespace_optional + br"$", re.DOTALL) + re_trailer_prev = re.compile( + whitespace_optional + br"trailer" + whitespace_optional + + br"\<\<(.*?\>\>)" + newline + br"startxref" + newline + br"([0-9]+)" + + newline + br"%%EOF" + whitespace_optional, re.DOTALL) def read_trailer(self): search_start_offset = len(self.buf) - 16384 @@ -589,19 +627,26 @@ class PdfParser: self.read_prev_trailer(self.trailer_dict[b"Prev"]) def read_prev_trailer(self, xref_section_offset): - trailer_offset = self.read_xref_table(xref_section_offset=xref_section_offset) - m = self.re_trailer_prev.search(self.buf[trailer_offset:trailer_offset+16384]) + trailer_offset = self.read_xref_table( + xref_section_offset=xref_section_offset) + m = self.re_trailer_prev.search( + self.buf[trailer_offset:trailer_offset+16384]) check_format_condition(m, "previous trailer not found") trailer_data = m.group(1) - check_format_condition(int(m.group(2)) == xref_section_offset, "xref section offset in previous trailer doesn't match what was expected") + check_format_condition(int(m.group(2)) == xref_section_offset, + "xref section offset in previous trailer " + "doesn't match what was expected") trailer_dict = self.interpret_trailer(trailer_data) if b"Prev" in trailer_dict: self.read_prev_trailer(trailer_dict[b"Prev"]) re_whitespace_optional = re.compile(whitespace_optional) - re_name = re.compile(whitespace_optional + br"/([!-$&'*-.0-;=?-Z\\^-z|~]+)(?=" + delimiter_or_ws + br")") + re_name = re.compile( + whitespace_optional + br"/([!-$&'*-.0-;=?-Z\\^-z|~]+)(?=" + + delimiter_or_ws + br")") re_dict_start = re.compile(whitespace_optional + br"\<\<") - re_dict_end = re.compile(whitespace_optional + br"\>\>" + whitespace_optional) + re_dict_end = re.compile( + whitespace_optional + br"\>\>" + whitespace_optional) @classmethod def interpret_trailer(cls, trailer_data): @@ -611,13 +656,21 @@ class PdfParser: m = cls.re_name.match(trailer_data, offset) if not m: m = cls.re_dict_end.match(trailer_data, offset) - check_format_condition(m and m.end() == len(trailer_data), "name not found in trailer, remaining data: " + repr(trailer_data[offset:])) + check_format_condition( + m and m.end() == len(trailer_data), + "name not found in trailer, remaining data: " + + repr(trailer_data[offset:])) break key = cls.interpret_name(m.group(1)) value, offset = cls.get_value(trailer_data, m.end()) trailer[key] = value - check_format_condition(b"Size" in trailer and isinstance(trailer[b"Size"], int), "/Size not in trailer or not an integer") - check_format_condition(b"Root" in trailer and isinstance(trailer[b"Root"], IndirectReference), "/Root not in trailer or not an indirect reference") + check_format_condition( + b"Size" in trailer and isinstance(trailer[b"Size"], int), + "/Size not in trailer or not an integer") + check_format_condition( + b"Root" in trailer and + isinstance(trailer[b"Root"], IndirectReference), + "/Root not in trailer or not an indirect reference") return trailer re_hashes_in_name = re.compile(br"([^#]*)(#([0-9a-fA-F]{2}))?") @@ -627,7 +680,8 @@ class PdfParser: name = b"" for m in cls.re_hashes_in_name.finditer(raw): if m.group(3): - name += m.group(1) + bytearray.fromhex(m.group(3).decode("us-ascii")) + name += m.group(1) + \ + bytearray.fromhex(m.group(3).decode("us-ascii")) else: name += m.group(1) if as_text: @@ -635,21 +689,37 @@ class PdfParser: else: return bytes(name) - re_null = re.compile(whitespace_optional + br"null(?=" + delimiter_or_ws + br")") - re_true = re.compile(whitespace_optional + br"true(?=" + delimiter_or_ws + br")") - re_false = re.compile(whitespace_optional + br"false(?=" + delimiter_or_ws + br")") - re_int = re.compile(whitespace_optional + br"([-+]?[0-9]+)(?=" + delimiter_or_ws + br")") - re_real = re.compile(whitespace_optional + br"([-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+))(?=" + delimiter_or_ws + br")") + re_null = re.compile( + whitespace_optional + br"null(?=" + delimiter_or_ws + br")") + re_true = re.compile( + whitespace_optional + br"true(?=" + delimiter_or_ws + br")") + re_false = re.compile( + whitespace_optional + br"false(?=" + delimiter_or_ws + br")") + re_int = re.compile( + whitespace_optional + br"([-+]?[0-9]+)(?=" + delimiter_or_ws + br")") + re_real = re.compile( + whitespace_optional + br"([-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+))(?=" + + delimiter_or_ws + br")") re_array_start = re.compile(whitespace_optional + br"\[") re_array_end = re.compile(whitespace_optional + br"]") - re_string_hex = re.compile(whitespace_optional + br"\<(" + whitespace_or_hex + br"*)\>") + re_string_hex = re.compile( + whitespace_optional + br"\<(" + whitespace_or_hex + br"*)\>") re_string_lit = re.compile(whitespace_optional + br"\(") - re_indirect_reference = re.compile(whitespace_optional + br"([-+]?[0-9]+)" + whitespace_mandatory + br"([-+]?[0-9]+)" + whitespace_mandatory + br"R(?=" + delimiter_or_ws + br")") - re_indirect_def_start = re.compile(whitespace_optional + br"([-+]?[0-9]+)" + whitespace_mandatory + br"([-+]?[0-9]+)" + whitespace_mandatory + br"obj(?=" + delimiter_or_ws + br")") - re_indirect_def_end = re.compile(whitespace_optional + br"endobj(?=" + delimiter_or_ws + br")") - re_comment = re.compile(br"(" + whitespace_optional + br"%[^\r\n]*" + newline + br")*") + re_indirect_reference = re.compile( + whitespace_optional + br"([-+]?[0-9]+)" + whitespace_mandatory + + br"([-+]?[0-9]+)" + whitespace_mandatory + br"R(?=" + delimiter_or_ws + + br")") + re_indirect_def_start = re.compile( + whitespace_optional + br"([-+]?[0-9]+)" + whitespace_mandatory + + br"([-+]?[0-9]+)" + whitespace_mandatory + br"obj(?=" + + delimiter_or_ws + br")") + re_indirect_def_end = re.compile( + whitespace_optional + br"endobj(?=" + delimiter_or_ws + br")") + re_comment = re.compile( + br"(" + whitespace_optional + br"%[^\r\n]*" + newline + br")*") re_stream_start = re.compile(whitespace_optional + br"stream\r?\n") - re_stream_end = re.compile(whitespace_optional + br"endstream(?=" + delimiter_or_ws + br")") + re_stream_end = re.compile( + whitespace_optional + br"endstream(?=" + delimiter_or_ws + br")") @classmethod def get_value(cls, data, offset, expect_indirect=None, max_nesting=-1): @@ -660,21 +730,34 @@ class PdfParser: offset = m.end() m = cls.re_indirect_def_start.match(data, offset) if m: - check_format_condition(int(m.group(1)) > 0, "indirect object definition: object ID must be greater than 0") - check_format_condition(int(m.group(2)) >= 0, "indirect object definition: generation must be non-negative") - check_format_condition(expect_indirect is None or expect_indirect == IndirectReference(int(m.group(1)), int(m.group(2))), + check_format_condition( + int(m.group(1)) > 0, + "indirect object definition: object ID must be greater than 0") + check_format_condition( + int(m.group(2)) >= 0, + "indirect object definition: generation must be non-negative") + check_format_condition( + expect_indirect is None or expect_indirect == + IndirectReference(int(m.group(1)), int(m.group(2))), "indirect object definition different than expected") - object, offset = cls.get_value(data, m.end(), max_nesting=max_nesting-1) + object, offset = cls.get_value( + data, m.end(), max_nesting=max_nesting-1) if offset is None: return object, None m = cls.re_indirect_def_end.match(data, offset) - check_format_condition(m, "indirect object definition end not found") + check_format_condition( + m, "indirect object definition end not found") return object, m.end() - check_format_condition(not expect_indirect, "indirect object definition not found") + check_format_condition( + not expect_indirect, "indirect object definition not found") m = cls.re_indirect_reference.match(data, offset) if m: - check_format_condition(int(m.group(1)) > 0, "indirect object reference: object ID must be greater than 0") - check_format_condition(int(m.group(2)) >= 0, "indirect object reference: generation must be non-negative") + check_format_condition( + int(m.group(1)) > 0, + "indirect object reference: object ID must be greater than 0") + check_format_condition( + int(m.group(2)) >= 0, + "indirect object reference: generation must be non-negative") return IndirectReference(int(m.group(1)), int(m.group(2))), m.end() m = cls.re_dict_start.match(data, offset) if m: @@ -682,10 +765,12 @@ class PdfParser: result = {} m = cls.re_dict_end.match(data, offset) while not m: - key, offset = cls.get_value(data, offset, max_nesting=max_nesting-1) + key, offset = cls.get_value( + data, offset, max_nesting=max_nesting-1) if offset is None: return result, None - value, offset = cls.get_value(data, offset, max_nesting=max_nesting-1) + value, offset = cls.get_value( + data, offset, max_nesting=max_nesting-1) result[key] = value if offset is None: return result, None @@ -696,7 +781,9 @@ class PdfParser: try: stream_len = int(result[b"Length"]) except (TypeError, KeyError, ValueError): - raise PdfFormatError("bad or missing Length in stream dict (%r)" % result.get(b"Length", None)) + raise PdfFormatError( + "bad or missing Length in stream dict (%r)" % + result.get(b"Length", None)) stream_data = data[m.end():m.end() + stream_len] m = cls.re_stream_end.match(data, m.end() + stream_len) check_format_condition(m, "stream end not found") @@ -711,7 +798,8 @@ class PdfParser: result = [] m = cls.re_array_end.match(data, offset) while not m: - value, offset = cls.get_value(data, offset, max_nesting=max_nesting-1) + value, offset = cls.get_value( + data, offset, max_nesting=max_nesting-1) result.append(value) if offset is None: return result, None @@ -734,18 +822,25 @@ class PdfParser: return int(m.group(1)), m.end() m = cls.re_real.match(data, offset) if m: - return float(m.group(1)), m.end() # XXX Decimal instead of float??? + # XXX Decimal instead of float??? + return float(m.group(1)), m.end() m = cls.re_string_hex.match(data, offset) if m: - hex_string = bytearray([b for b in m.group(1) if b in b"0123456789abcdefABCDEF"]) # filter out whitespace + # filter out whitespace + hex_string = bytearray([ + b for b in m.group(1) + if b in b"0123456789abcdefABCDEF" + ]) if len(hex_string) % 2 == 1: - hex_string.append(ord(b"0")) # append a 0 if the length is not even - yes, at the end + # append a 0 if the length is not even - yes, at the end + hex_string.append(ord(b"0")) return bytearray.fromhex(hex_string.decode("us-ascii")), m.end() m = cls.re_string_lit.match(data, offset) if m: return cls.get_literal_string(data, m.end()) # return None, offset # fallback (only for debugging) - raise PdfFormatError("unrecognized object: " + repr(data[offset:offset+32])) + raise PdfFormatError( + "unrecognized object: " + repr(data[offset:offset+32])) re_lit_str_token = re.compile(br"(\\[nrtbf()\\])|(\\[0-9]{1,3})|(\\(\r\n|\r|\n))|(\r\n|\r|\n)|(\()|(\))") escaped_chars = { @@ -792,19 +887,24 @@ class PdfParser: offset = m.end() raise PdfFormatError("unfinished literal string") - re_xref_section_start = re.compile(whitespace_optional + br"xref" + newline) - re_xref_subsection_start = re.compile(whitespace_optional + br"([0-9]+)" + whitespace_mandatory + br"([0-9]+)" + whitespace_optional + newline_only) + re_xref_section_start = re.compile( + whitespace_optional + br"xref" + newline) + re_xref_subsection_start = re.compile( + whitespace_optional + br"([0-9]+)" + whitespace_mandatory + + br"([0-9]+)" + whitespace_optional + newline_only) re_xref_entry = re.compile(br"([0-9]{10}) ([0-9]{5}) ([fn])( \r| \n|\r\n)") def read_xref_table(self, xref_section_offset): subsection_found = False - m = self.re_xref_section_start.match(self.buf, xref_section_offset + self.start_offset) + m = self.re_xref_section_start.match( + self.buf, xref_section_offset + self.start_offset) check_format_condition(m, "xref section start not found") offset = m.end() while True: m = self.re_xref_subsection_start.match(self.buf, offset) if not m: - check_format_condition(subsection_found, "xref subsection start not found") + check_format_condition( + subsection_found, "xref subsection start not found") break subsection_found = True offset = m.end() @@ -818,22 +918,31 @@ class PdfParser: generation = int(m.group(2)) if not is_free: new_entry = (int(m.group(1)), generation) - check_format_condition(i not in self.xref_table or self.xref_table[i] == new_entry, "xref entry duplicated (and not identical)") + check_format_condition( + i not in self.xref_table or + self.xref_table[i] == new_entry, + "xref entry duplicated (and not identical)") self.xref_table[i] = new_entry return offset def read_indirect(self, ref, max_nesting=-1): offset, generation = self.xref_table[ref[0]] - check_format_condition(generation == ref[1], "expected to find generation %s for object ID %s in xref table, instead found generation %s at offset %s" + check_format_condition( + generation == ref[1], + "expected to find generation %s for object ID %s in xref table, " + "instead found generation %s at offset %s" % (ref[1], ref[0], generation, offset)) - value = self.get_value(self.buf, offset + self.start_offset, expect_indirect=IndirectReference(*ref), max_nesting=max_nesting)[0] + value = self.get_value(self.buf, offset + self.start_offset, + expect_indirect=IndirectReference(*ref), + max_nesting=max_nesting)[0] self.cached_objects[ref] = value return value def linearize_page_tree(self, node=None): if node is None: node = self.page_tree_root - check_format_condition(node[b"Type"] == b"Pages", "/Type of page tree node is not /Pages") + check_format_condition( + node[b"Type"] == b"Pages", "/Type of page tree node is not /Pages") pages = [] for kid in node[b"Kids"]: kid_object = self.read_indirect(kid) diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 826061990..4f1f0f9cf 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -142,7 +142,8 @@ class ChunkStream(object): def crc(self, cid, data): "Read and verify checksum" - # Skip CRC checks for ancillary chunks if allowed to load truncated images + # Skip CRC checks for ancillary chunks if allowed to load truncated + # images # 5th byte of first char is 1 [specs, section 5.4] if ImageFile.LOAD_TRUNCATED_IMAGES and (i8(cid[0]) >> 5 & 1): self.crc_skip(cid, data) @@ -301,8 +302,8 @@ class PngStream(ChunkStream): def check_text_memory(self, chunklen): self.text_memory += chunklen if self.text_memory > MAX_TEXT_MEMORY: - raise ValueError("Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" % - self.text_memory) + raise ValueError("Too much memory used in text chunks: " + "%s>MAX_TEXT_MEMORY" % self.text_memory) def chunk_iCCP(self, pos, length): diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py index c599ba8d5..9866c9040 100644 --- a/src/PIL/PpmImagePlugin.py +++ b/src/PIL/PpmImagePlugin.py @@ -83,7 +83,8 @@ class PpmImageFile(ImageFile.ImageFile): if s not in b_whitespace: break if s == b"": - raise ValueError("File does not extend beyond magic number") + raise ValueError( + "File does not extend beyond magic number") if s != b"#": break s = self.fp.readline() diff --git a/src/PIL/SgiImagePlugin.py b/src/PIL/SgiImagePlugin.py index ef0f40ebd..113d44fac 100644 --- a/src/PIL/SgiImagePlugin.py +++ b/src/PIL/SgiImagePlugin.py @@ -222,6 +222,7 @@ Image.register_save(SgiImageFile.format, _save) Image.register_mime(SgiImageFile.format, "image/sgi") Image.register_mime(SgiImageFile.format, "image/rgb") -Image.register_extensions(SgiImageFile.format, [".bw", ".rgb", ".rgba", ".sgi"]) +Image.register_extensions(SgiImageFile.format, + [".bw", ".rgb", ".rgba", ".sgi"]) # End of file diff --git a/src/PIL/SunImagePlugin.py b/src/PIL/SunImagePlugin.py index 03b266bc4..3126bd9d6 100644 --- a/src/PIL/SunImagePlugin.py +++ b/src/PIL/SunImagePlugin.py @@ -94,7 +94,8 @@ class SunImageFile(ImageFile.ImageFile): raise SyntaxError("Unsupported Palette Type") offset = offset + palette_length - self.palette = ImagePalette.raw("RGB;L", self.fp.read(palette_length)) + self.palette = ImagePalette.raw("RGB;L", + self.fp.read(palette_length)) if self.mode == "L": self.mode = "P" rawmode = rawmode.replace('L', 'P') diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 14b66a1b9..94a028afa 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -431,7 +431,8 @@ class ImageFileDirectory_v2(MutableMapping): * self.tagtype = {} * Key: numerical tiff tag number - * Value: integer corresponding to the data type from `~PIL.TiffTags.TYPES` + * Value: integer corresponding to the data type from + ~PIL.TiffTags.TYPES` .. versionadded:: 3.0.0 """ diff --git a/src/PIL/TiffTags.py b/src/PIL/TiffTags.py index 427f3a489..ef19ee66e 100644 --- a/src/PIL/TiffTags.py +++ b/src/PIL/TiffTags.py @@ -23,7 +23,8 @@ from collections import namedtuple class TagInfo(namedtuple("_TagInfo", "value name type length enum")): __slots__ = [] - def __new__(cls, value=None, name="unknown", type=None, length=None, enum=None): + def __new__(cls, value=None, name="unknown", + type=None, length=None, enum=None): return super(TagInfo, cls).__new__( cls, value, name, type, length, enum or {}) @@ -72,8 +73,8 @@ TAGS_V2 = { 257: ("ImageLength", LONG, 1), 258: ("BitsPerSample", SHORT, 0), 259: ("Compression", SHORT, 1, - {"Uncompressed": 1, "CCITT 1d": 2, "Group 3 Fax": 3, "Group 4 Fax": 4, - "LZW": 5, "JPEG": 6, "PackBits": 32773}), + {"Uncompressed": 1, "CCITT 1d": 2, "Group 3 Fax": 3, + "Group 4 Fax": 4, "LZW": 5, "JPEG": 6, "PackBits": 32773}), 262: ("PhotometricInterpretation", SHORT, 1, {"WhiteIsZero": 0, "BlackIsZero": 1, "RGB": 2, "RGB Palette": 3, diff --git a/src/PIL/WmfImagePlugin.py b/src/PIL/WmfImagePlugin.py index 213584497..aeb19374d 100644 --- a/src/PIL/WmfImagePlugin.py +++ b/src/PIL/WmfImagePlugin.py @@ -22,7 +22,8 @@ from __future__ import print_function from . import Image, ImageFile -from ._binary import i16le as word, si16le as short, i32le as dword, si32le as _long +from ._binary import i16le as word, si16le as short, \ + i32le as dword, si32le as _long from ._util import py3 From 2630054266a3c2f069c6b1d8a4ce93dc777cc78b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 2 Jul 2018 19:26:07 +1000 Subject: [PATCH 20/33] Removed unused import --- src/PIL/TiffImagePlugin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 94a028afa..66b211cbf 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -45,7 +45,6 @@ from . import Image, ImageFile, ImagePalette, TiffTags from ._binary import i8, o8 from ._util import py3 -import collections from fractions import Fraction from numbers import Number, Rational From 4407cb65079a7d1150277e3b9a144996f56357c9 Mon Sep 17 00:00:00 2001 From: Hugo Date: Mon, 2 Jul 2018 22:41:16 +0300 Subject: [PATCH 21/33] Update CHANGES.rst --- CHANGES.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 0c31eb3c7..a6018ffb6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,21 @@ Changelog (Pillow) ================== +5.3.0 (unreleased) +------------------ + +- Tests: Add LA to TGA test modes #3222 + [danpla] + +- Skip outline if the draw operation fills with the same colour #2922 + [radarhere] + +- Flake8 fixes #3173 + [radarhere] + +- Avoid deprecated 'U' mode when opening files #2187 + [jdufresne] + 5.2.0 (2018-07-01) ------------------ From 937443f2a64564335b6e7439160742bc5939fd0c Mon Sep 17 00:00:00 2001 From: Alex Clark Date: Thu, 5 Jul 2018 18:27:01 -0400 Subject: [PATCH 22/33] =?UTF-8?q?Update=20examples=20=E2=80=A6=20[ci=20ski?= =?UTF-8?q?p]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update examples and remove "hide old releases" step, N/A on pypi.org. --- RELEASING.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 6541d69d5..77c866cd4 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -4,7 +4,7 @@ Released quarterly on the first day of January, April, July, October. -* [ ] Open a release ticket e.g. https://github.com/python-pillow/Pillow/issues/1174 +* [ ] Open a release ticket e.g. https://github.com/python-pillow/Pillow/issues/3154 * [ ] Develop and prepare release in ``master`` branch. * [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) and [AppVeyor CI](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in ``master`` branch. * [ ] Check that all of the wheel builds [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels) pass the tests in TravisCI. @@ -13,8 +13,8 @@ Released quarterly on the first day of January, April, July, October. * [ ] Run pre-release check via `make release-test` in a freshly cloned repo. * [ ] Create branch and tag for release e.g.: ``` - $ git branch 2.9.x - $ git tag 2.9.0 + $ git branch 5.2.x + $ git tag 5.2.0 $ git push --all $ git push --tags ``` @@ -23,8 +23,7 @@ Released quarterly on the first day of January, April, July, October. $ make sdist ``` * [ ] Create [binary distributions](#binary-distributions) -* [ ] Upload all binaries and source distributions with ``twine upload dist/Pillow-4.1.0-*`` -* [ ] Manually hide old versions on PyPI such that only the latest major release is visible when viewing https://pypi.org/project/Pillow/ (https://pypi.org/manage/project/Pillow/releases/) +* [ ] Upload all binaries and source distributions e.g. ``twine upload dist/Pillow-5.2.0-*`` ## Point Release @@ -32,17 +31,17 @@ Released as needed for security, installation or critical bug fixes. * [ ] Make necessary changes in ``master`` branch. * [ ] Update `CHANGES.rst`. -* [ ] Cherry pick individual commits from ``master`` branch to release branch e.g. ``2.9.x``. -* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) to confirm passing tests in release branch e.g. ``2.9.x``. +* [ ] Cherry pick individual commits from ``master`` branch to release branch e.g. ``5.2.x``. +* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) to confirm passing tests in release branch e.g. ``5.2.x``. * [ ] Checkout release branch e.g.: ``` - git checkout -t remotes/origin/2.9.x + git checkout -t remotes/origin/5.2.x ``` * [ ] In compliance with https://www.python.org/dev/peps/pep-0440/, update version identifier in `src/PIL/_version.py` * [ ] Run pre-release check via `make release-test`. * [ ] Create tag for release e.g.: ``` - $ git tag 2.9.1 + $ git tag 5.2.1 $ git push --tags ``` * [ ] Create source distributions e.g.: @@ -99,8 +98,8 @@ Released as needed privately to individual vendors for critical security-related ## Publicize Release -* [ ] Announce release availability via [Twitter](https://twitter.com/pythonpillow) e.g. https://twitter.com/aclark4life/status/583366798302691328. +* [ ] Announce release availability via [Twitter](https://twitter.com/pythonpillow) e.g. https://twitter.com/PythonPillow/status/1013789184354603010 ## Documentation -* [ ] Make sure the default version for Read the Docs is the latest release version, e.g. ``3.1.x`` rather than ``latest``: https://readthedocs.org/projects/pillow/versions/ +* [ ] Make sure the default version for Read the Docs is the latest release version, i.e. ``5.2.0`` rather than ``latest`` e.g. https://pillow.readthedocs.io/en/5.2.x/ From 63d8637bb8cbd90ce0372a221b2acdae505b053c Mon Sep 17 00:00:00 2001 From: tsennott Date: Fri, 6 Jul 2018 18:18:06 -0700 Subject: [PATCH 23/33] adding three-color feature to ImageOps.colorize --- src/PIL/ImageOps.py | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 25d491aff..33196d5ed 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -136,28 +136,50 @@ def autocontrast(image, cutoff=0, ignore=None): return _lut(image, lut) -def colorize(image, black, white): +def colorize(image, black, white, mid=None, midpoint=128): """ - Colorize grayscale image. The **black** and **white** - arguments should be RGB tuples; this function calculates a color - wedge mapping all black pixels in the source image to the first - color, and all white pixels to the second color. + Colorize grayscale image. + This function calculates a color wedge mapping all + black pixels in the source image to the first + color, and all white pixels to the second color. If + mid is specified, it uses three color mapping. + The **black** and **white** + arguments should be RGB tuples; optionally you can use + three color mapping by also specifying **mid**, and + optionally, **midpoint** (which is the integer value + in [0, 255] corresponding to the midpoint color, + default 128). :param image: The image to colorize. :param black: The color to use for black input pixels. :param white: The color to use for white input pixels. + :param mid: The color to use for midtone input pixels. + :param midpoint: the int value [0, 255] for the mid color. :return: An image. """ assert image.mode == "L" black = _color(black, "RGB") + if mid is not None: + mid = _color(mid, "RGB") white = _color(white, "RGB") red = [] green = [] blue = [] - for i in range(256): - red.append(black[0]+i*(white[0]-black[0])//255) - green.append(black[1]+i*(white[1]-black[1])//255) - blue.append(black[2]+i*(white[2]-black[2])//255) + if mid is None: + for i in range(256): + red.append(black[0] + i * (white[0] - black[0]) // 255) + green.append(black[1] + i * (white[1] - black[1]) // 255) + blue.append(black[2] + i * (white[2] - black[2]) // 255) + else: + for i in range(0, midpoint): + red.append(black[0] + i * (mid[0] - black[0]) // 255) + green.append(black[1] + i * (mid[1] - black[1]) // 255) + blue.append(black[2] + i * (mid[2] - black[2]) // 255) + for i in range(0, 256 - midpoint): + red.append(mid[0] + i * (white[0] - mid[0]) // 255) + green.append(mid[1] + i * (white[1] - mid[1]) // 255) + blue.append(mid[2] + i * (white[2] - mid[2]) // 255) + image = image.convert("RGB") return _lut(image, red + green + blue) From adf570a77ea802d86a59199a165aef6c053b852b Mon Sep 17 00:00:00 2001 From: tsennott Date: Fri, 6 Jul 2018 18:42:16 -0700 Subject: [PATCH 24/33] adding tests, updated docstring and comments --- Tests/test_imageops.py | 16 ++++++++++++++++ src/PIL/ImageOps.py | 8 ++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 11cf3619d..63ec0d2e4 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -94,6 +94,22 @@ class TestImageOps(PillowTestCase): newimg = ImageOps.scale(i, 0.5) self.assertEqual(newimg.size, (25, 25)) + def test_colorize(self): + # Test the colorizing function + + # Grab test image + i = hopper("L").resize((15, 16)) + + # Test original 2-color functionality + ImageOps.colorize(i, 'green', 'red') + + # Test new three color functionality (cyanotype colors) + ImageOps.colorize(i, + (32, 37, 79), + (255, 255, 255), + (35, 52, 121), + 40) + if __name__ == '__main__': unittest.main() diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 33196d5ed..29dec124d 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -147,8 +147,8 @@ def colorize(image, black, white, mid=None, midpoint=128): arguments should be RGB tuples; optionally you can use three color mapping by also specifying **mid**, and optionally, **midpoint** (which is the integer value - in [0, 255] corresponding to the midpoint color, - default 128). + in [1, 254] corresponding to where the midpoint color + should be mapped (0 being black and 255 being white). :param image: The image to colorize. :param black: The color to use for black input pixels. @@ -158,10 +158,14 @@ def colorize(image, black, white, mid=None, midpoint=128): :return: An image. """ assert image.mode == "L" + + # Define colors from arguments black = _color(black, "RGB") if mid is not None: mid = _color(mid, "RGB") white = _color(white, "RGB") + + # Create the mapping red = [] green = [] blue = [] From 3c6fd275c8965d85ee89dfff608420e638feec21 Mon Sep 17 00:00:00 2001 From: tsennott Date: Fri, 6 Jul 2018 19:09:57 -0700 Subject: [PATCH 25/33] added assert for midpoint range --- src/PIL/ImageOps.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 29dec124d..133f9a8b8 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -154,10 +154,11 @@ def colorize(image, black, white, mid=None, midpoint=128): :param black: The color to use for black input pixels. :param white: The color to use for white input pixels. :param mid: The color to use for midtone input pixels. - :param midpoint: the int value [0, 255] for the mid color. + :param midpoint: the int value in [1, 254] for the mid color. :return: An image. """ assert image.mode == "L" + assert 1 <= midpoint <= 254 # Define colors from arguments black = _color(black, "RGB") From b19c460568675268145ce9f8ea2cfb42c357a5f0 Mon Sep 17 00:00:00 2001 From: tsennott Date: Fri, 6 Jul 2018 19:49:07 -0700 Subject: [PATCH 26/33] fixed mapping function, now smooth --- src/PIL/ImageOps.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 133f9a8b8..e5ce71060 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -136,7 +136,7 @@ def autocontrast(image, cutoff=0, ignore=None): return _lut(image, lut) -def colorize(image, black, white, mid=None, midpoint=128): +def colorize(image, black, white, mid=None, midpoint=127): """ Colorize grayscale image. This function calculates a color wedge mapping all @@ -176,14 +176,16 @@ def colorize(image, black, white, mid=None, midpoint=128): green.append(black[1] + i * (white[1] - black[1]) // 255) blue.append(black[2] + i * (white[2] - black[2]) // 255) else: - for i in range(0, midpoint): - red.append(black[0] + i * (mid[0] - black[0]) // 255) - green.append(black[1] + i * (mid[1] - black[1]) // 255) - blue.append(black[2] + i * (mid[2] - black[2]) // 255) - for i in range(0, 256 - midpoint): - red.append(mid[0] + i * (white[0] - mid[0]) // 255) - green.append(mid[1] + i * (white[1] - mid[1]) // 255) - blue.append(mid[2] + i * (white[2] - mid[2]) // 255) + range1 = range(0, midpoint) + range2 = range(0, 256 - midpoint) + for i in range1: + red.append(black[0] + i * (mid[0] - black[0]) // len(range1)) + green.append(black[1] + i * (mid[1] - black[1]) // len(range1)) + blue.append(black[2] + i * (mid[2] - black[2]) // len(range1)) + for i in range2: + red.append(mid[0] + i * (white[0] - mid[0]) // len(range2)) + green.append(mid[1] + i * (white[1] - mid[1]) // len(range2)) + blue.append(mid[2] + i * (white[2] - mid[2]) // len(range2)) image = image.convert("RGB") return _lut(image, red + green + blue) From 837d8683332a14cdd5234cfebe026235417d1a6a Mon Sep 17 00:00:00 2001 From: tsennott Date: Sat, 7 Jul 2018 02:40:25 -0700 Subject: [PATCH 27/33] updated test to assert equality with reference images --- Tests/images/bw_gradient.png | Bin 0 -> 1926 bytes Tests/images/bw_gradient_2color.png | Bin 0 -> 179 bytes Tests/images/bw_gradient_3color.png | Bin 0 -> 246 bytes Tests/test_imageops.py | 24 +++++++++++++++--------- 4 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 Tests/images/bw_gradient.png create mode 100644 Tests/images/bw_gradient_2color.png create mode 100644 Tests/images/bw_gradient_3color.png diff --git a/Tests/images/bw_gradient.png b/Tests/images/bw_gradient.png new file mode 100644 index 0000000000000000000000000000000000000000..0b7275dc19cb188d0b1c65334593fe5adc948476 GIT binary patch literal 1926 zcmb_dU5MO798WEN9aa&2Qjm~?Qqf6fl592^ZauEqv%AvVo!g~7-#R-pyBlwlNt4{| z-aUx=B2^#zAmWqagCHXKpwb76S_Sb%DiqN-K@cp0FQS4t*^gN3T|Ew$-RxxM_y79+ ze=~D_ZRNy~xd-MHMLE)J)LV*j=zck#yWM?EcF?C^trGtp)L>)zgIK!iwHuj6_M*$cAdw(~$%13VKvEA*vd%Vn7E#grSQ~q)tDYjFz%4Zq*;3#*%L}t)J%!HjLqL zs1Ge&q&)+9o@YSQFijv4Alr^}G6HcnKl4!M8BN0^4@ImN9!W=R<~2=bIw>JaO1E(~ zrAZQIj7VZ29Tp{xfsB^8WHTL%gEMOI0grf`XA+A_tYj$&O8BmBqo_n@`SO;`Xj`_O#Tvn4{KjkDBX&+J#zP;MhK zIJlp(P1qL$kp_ZEmMu;Fd%o%WYpLjl1G$j3P8?U8%f5p=#{s5}3bl__hZ|ugTf05o zKd1P)>1YtDW1(R}i@i|OXdwbFDVR)$yHL143MTf$K9^2!qKgSE6Wx4BQohuabnj1m z#$FXk@OR65VY&xrdxBM$6uE3d851jv$VA>~f zkIN(0&< zi|41OKRzult$wq<)b2lb?Fzd4l6sf_)zM!U^Q&`>cTaxv=Y!g7Z@UjI)!XmA_{kp^ zzx%BF+e=@5z4~o%-{mXU-hbxRH$HfB<%J8Yt;;{G>fggh-nwx6rI&wEj(&0Ym1Fmu ieSP8C^Vh%pcAY} zZ+$AZ@2z(&tK_?Kool@2KC}~K_+Z|`uE6<_ l(Zi{NVUmDcg9;iq{@%pDQw3)GKLC1!!PC{xWt~$(698i!XOaK_ literal 0 HcmV?d00001 diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 63ec0d2e4..c63e75574 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -1,6 +1,7 @@ from helper import unittest, PillowTestCase, hopper from PIL import ImageOps +from PIL import Image class TestImageOps(PillowTestCase): @@ -97,18 +98,23 @@ class TestImageOps(PillowTestCase): def test_colorize(self): # Test the colorizing function - # Grab test image - i = hopper("L").resize((15, 16)) + # Grab test image (10px black, 256px gradient, 10px white) + im = Image.open("Tests/images/bw_gradient.png") + im = im.convert("L") # Test original 2-color functionality - ImageOps.colorize(i, 'green', 'red') + out_2color = ImageOps.colorize(im, 'red', 'green') - # Test new three color functionality (cyanotype colors) - ImageOps.colorize(i, - (32, 37, 79), - (255, 255, 255), - (35, 52, 121), - 40) + # Test new three color functionality, with midpoint offset + out_3color = ImageOps.colorize(im, 'red', 'green', 'yellow', 100) + + # Assert 2-color + ref_2color = Image.open("Tests/images/bw_gradient_2color.png") + self.assert_image_equal(out_2color, ref_2color) + + # Assert 3-color + ref_3color = Image.open("Tests/images/bw_gradient_3color.png") + self.assert_image_equal(out_3color, ref_3color) if __name__ == '__main__': From 4a6ec5ca72ed832578aeff7b80a5254dc6214801 Mon Sep 17 00:00:00 2001 From: tsennott Date: Sat, 7 Jul 2018 18:19:26 -0700 Subject: [PATCH 28/33] updated colorize to allow optional black/white positions; enhanced tests --- Tests/images/bw_gradient.png | Bin 1926 -> 102 bytes Tests/images/bw_gradient_2color.png | Bin 179 -> 0 bytes Tests/images/bw_gradient_3color.png | Bin 246 -> 0 bytes Tests/test_imageops.py | 84 +++++++++++++++++++--- src/PIL/ImageOps.py | 106 ++++++++++++++++++++-------- 5 files changed, 148 insertions(+), 42 deletions(-) delete mode 100644 Tests/images/bw_gradient_2color.png delete mode 100644 Tests/images/bw_gradient_3color.png diff --git a/Tests/images/bw_gradient.png b/Tests/images/bw_gradient.png index 0b7275dc19cb188d0b1c65334593fe5adc948476..79c921486f8dc91f7c6f6bab36ba8ba302ed9b6f 100644 GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5xHv#$-PijWKuXus#WAE}&f5!)f(#5i%^S-8 px%#v93$e=hZjU`?*}%5|8QZ?gVHD1NS6l`%z|+;wWt~$(69Dsx9MAv& literal 1926 zcmb_dU5MO798WEN9aa&2Qjm~?Qqf6fl592^ZauEqv%AvVo!g~7-#R-pyBlwlNt4{| z-aUx=B2^#zAmWqagCHXKpwb76S_Sb%DiqN-K@cp0FQS4t*^gN3T|Ew$-RxxM_y79+ ze=~D_ZRNy~xd-MHMLE)J)LV*j=zck#yWM?EcF?C^trGtp)L>)zgIK!iwHuj6_M*$cAdw(~$%13VKvEA*vd%Vn7E#grSQ~q)tDYjFz%4Zq*;3#*%L}t)J%!HjLqL zs1Ge&q&)+9o@YSQFijv4Alr^}G6HcnKl4!M8BN0^4@ImN9!W=R<~2=bIw>JaO1E(~ zrAZQIj7VZ29Tp{xfsB^8WHTL%gEMOI0grf`XA+A_tYj$&O8BmBqo_n@`SO;`Xj`_O#Tvn4{KjkDBX&+J#zP;MhK zIJlp(P1qL$kp_ZEmMu;Fd%o%WYpLjl1G$j3P8?U8%f5p=#{s5}3bl__hZ|ugTf05o zKd1P)>1YtDW1(R}i@i|OXdwbFDVR)$yHL143MTf$K9^2!qKgSE6Wx4BQohuabnj1m z#$FXk@OR65VY&xrdxBM$6uE3d851jv$VA>~f zkIN(0&< zi|41OKRzult$wq<)b2lb?Fzd4l6sf_)zM!U^Q&`>cTaxv=Y!g7Z@UjI)!XmA_{kp^ zzx%BF+e=@5z4~o%-{mXU-hbxRH$HfB<%J8Yt;;{G>fggh-nwx6rI&wEj(&0Ym1Fmu ieSP8C^Vh%pcAY} zZ+$AZ@2z(&tK_?Kool@2KC}~K_+Z|`uE6<_ l(Zi{NVUmDcg9;iq{@%pDQw3)GKLC1!!PC{xWt~$(698i!XOaK_ diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index c63e75574..d1be04046 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -98,23 +98,85 @@ class TestImageOps(PillowTestCase): def test_colorize(self): # Test the colorizing function - # Grab test image (10px black, 256px gradient, 10px white) + # Open test image (256px by 10px, black to white) im = Image.open("Tests/images/bw_gradient.png") im = im.convert("L") - # Test original 2-color functionality - out_2color = ImageOps.colorize(im, 'red', 'green') + # Create image with original 2-color functionality + im_2c = ImageOps.colorize(im, 'red', 'green') - # Test new three color functionality, with midpoint offset - out_3color = ImageOps.colorize(im, 'red', 'green', 'yellow', 100) + # Create image with original 2-color functionality with offsets + im_2c_offset = ImageOps.colorize(im, + black='red', + white='green', + blackpoint=50, + whitepoint=200) - # Assert 2-color - ref_2color = Image.open("Tests/images/bw_gradient_2color.png") - self.assert_image_equal(out_2color, ref_2color) + # Create image with new three color functionality with offsets + im_3c_offset = ImageOps.colorize(im, + black='red', + white='green', + mid='blue', + blackpoint=50, + whitepoint=200, + midpoint=100) - # Assert 3-color - ref_3color = Image.open("Tests/images/bw_gradient_3color.png") - self.assert_image_equal(out_3color, ref_3color) + # Define function for approximate equality of tuples + def tuple_approx_equal(actual, target, thresh): + value = True + for i, target in enumerate(target): + value *= (target - thresh <= actual[i] <= target + thresh) + return value + + # Test output image (2-color) + left = (0, 1) + middle = (127, 1) + right = (255, 1) + self.assertTrue(tuple_approx_equal(im_2c.getpixel(left), + (255, 0, 0), thresh=1), + '2-color image black incorrect') + self.assertTrue(tuple_approx_equal(im_2c.getpixel(middle), + (127, 63, 0), thresh=1), + '2-color image mid incorrect') + self.assertTrue(tuple_approx_equal(im_2c.getpixel(right), + (0, 127, 0), thresh=1), + '2-color image white incorrect') + + # Test output image (2-color) with offsets + left = (25, 1) + middle = (125, 1) + right = (225, 1) + self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(left), + (255, 0, 0), thresh=1), + '2-color image (with offset) black incorrect') + self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(middle), + (127, 63, 0), thresh=1), + '2-color image (with offset) mid incorrect') + self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(right), + (0, 127, 0), thresh=1), + '2-color image (with offset) white incorrect') + + # Test output image (3-color) with offsets + left = (25, 1) + left_middle = (75, 1) + middle = (100, 1) + right_middle = (150, 1) + right = (225, 1) + self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(left), + (255, 0, 0), thresh=1), + '3-color image (with offset) black incorrect') + self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(left_middle), + (127, 0, 127), thresh=1), + '3-color image (with offset) low-mid incorrect') + self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(middle), + (0, 0, 255), thresh=1), + '3-color image (with offset) mid incorrect') + self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(right_middle), + (0, 63, 127), thresh=1), + '3-color image (with offset) high-mid incorrect') + self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(right), + (0, 127, 0), thresh=1), + '3-color image (with offset) white incorrect') if __name__ == '__main__': diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index e5ce71060..4e6baf8c9 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -136,57 +136,101 @@ def autocontrast(image, cutoff=0, ignore=None): return _lut(image, lut) -def colorize(image, black, white, mid=None, midpoint=127): +def colorize(image, black, white, mid=None, blackpoint=0, + whitepoint=255, midpoint=127): """ Colorize grayscale image. - This function calculates a color wedge mapping all - black pixels in the source image to the first - color, and all white pixels to the second color. If - mid is specified, it uses three color mapping. - The **black** and **white** - arguments should be RGB tuples; optionally you can use - three color mapping by also specifying **mid**, and - optionally, **midpoint** (which is the integer value - in [1, 254] corresponding to where the midpoint color - should be mapped (0 being black and 255 being white). + This function calculates a color wedge which maps all black pixels in + the source image to the first color and all white pixels to the + second color. If **mid** is specified, it uses three-color mapping. + The **black** and **white** arguments should be RGB tuples or color names; + optionally you can use three-color mapping by also specifying **mid**. + Mapping positions for any of the colors can be specified + (e.g. **blackpoint**), where these parameters are the integer + value in [0, 255] corresponding to where the corresponding color + should be mapped. :param image: The image to colorize. :param black: The color to use for black input pixels. :param white: The color to use for white input pixels. :param mid: The color to use for midtone input pixels. - :param midpoint: the int value in [1, 254] for the mid color. + :param blackpoint: an int value [0, 255] for the black mapping. + :param whitepoint: an int value [0, 255] for the white mapping. + :param midpoint: an int value [0, 255] for the midtone mapping. :return: An image. """ + + # Initial asserts assert image.mode == "L" - assert 1 <= midpoint <= 254 + assert 0 <= whitepoint <= 255 + assert 0 <= blackpoint <= 255 + assert 0 <= midpoint <= 255 + assert blackpoint <= whitepoint + if mid is not None: + assert blackpoint <= midpoint + assert whitepoint >= midpoint # Define colors from arguments black = _color(black, "RGB") + white = _color(white, "RGB") if mid is not None: mid = _color(mid, "RGB") - white = _color(white, "RGB") - # Create the mapping + # Empty lists for the mapping red = [] green = [] blue = [] - if mid is None: - for i in range(256): - red.append(black[0] + i * (white[0] - black[0]) // 255) - green.append(black[1] + i * (white[1] - black[1]) // 255) - blue.append(black[2] + i * (white[2] - black[2]) // 255) - else: - range1 = range(0, midpoint) - range2 = range(0, 256 - midpoint) - for i in range1: - red.append(black[0] + i * (mid[0] - black[0]) // len(range1)) - green.append(black[1] + i * (mid[1] - black[1]) // len(range1)) - blue.append(black[2] + i * (mid[2] - black[2]) // len(range1)) - for i in range2: - red.append(mid[0] + i * (white[0] - mid[0]) // len(range2)) - green.append(mid[1] + i * (white[1] - mid[1]) // len(range2)) - blue.append(mid[2] + i * (white[2] - mid[2]) // len(range2)) + # Create the mapping (2-color) + if mid is None: + + # Define ranges + range_low = range(0, blackpoint) + range_map = range(0, whitepoint - blackpoint) + range_high = range(0, 256 - whitepoint) + + # Map + for i in range_low: + red.append(black[0]) + green.append(black[1]) + blue.append(black[2]) + for i in range_map: + red.append(black[0] + i * (white[0] - black[0]) // len(range_map)) + green.append(black[1] + i * (white[1] - black[1]) // len(range_map)) + blue.append(black[2] + i * (white[2] - black[2]) // len(range_map)) + for i in range_high: + red.append(white[0]) + green.append(white[1]) + blue.append(white[2]) + + # Create the mapping (3-color) + else: + + # Define ranges + range_low = range(0, blackpoint) + range_map1 = range(0, midpoint - blackpoint) + range_map2 = range(0, whitepoint - midpoint) + range_high = range(0, 256 - whitepoint) + + # Map + for i in range_low: + red.append(black[0]) + green.append(black[1]) + blue.append(black[2]) + for i in range_map1: + red.append(black[0] + i * (mid[0] - black[0]) // len(range_map1)) + green.append(black[1] + i * (mid[1] - black[1]) // len(range_map1)) + blue.append(black[2] + i * (mid[2] - black[2]) // len(range_map1)) + for i in range_map2: + red.append(mid[0] + i * (white[0] - mid[0]) // len(range_map2)) + green.append(mid[1] + i * (white[1] - mid[1]) // len(range_map2)) + blue.append(mid[2] + i * (white[2] - mid[2]) // len(range_map2)) + for i in range_high: + red.append(white[0]) + green.append(white[1]) + blue.append(white[2]) + + # Return converted image image = image.convert("RGB") return _lut(image, red + green + blue) From 1eed17c70e4a37039e30c78dfb472af7bc47c667 Mon Sep 17 00:00:00 2001 From: tsennott Date: Sun, 8 Jul 2018 20:09:39 -0700 Subject: [PATCH 29/33] tightened up colorize(); split tests; moved tuple comparison fcn to helper.py --- Tests/helper.py | 9 ++++ Tests/test_imageops.py | 109 ++++++++++++++++++++++------------------- src/PIL/ImageOps.py | 47 ++++++------------ 3 files changed, 83 insertions(+), 82 deletions(-) diff --git a/Tests/helper.py b/Tests/helper.py index 207f497d2..834589723 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -307,6 +307,15 @@ def hopper(mode=None, cache={}): return im.copy() +def tuple_approx_equal(actual, target, threshold): + """Tests if tuple actual has values within threshold from tuple target""" + + value = True + for i, target in enumerate(target): + value *= (target - threshold <= actual[i] <= target + threshold) + return value + + def command_succeeds(cmd): """ Runs the command, which must be a list of strings. Returns True if the diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index d1be04046..07e4dd343 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -1,4 +1,4 @@ -from helper import unittest, PillowTestCase, hopper +from helper import unittest, PillowTestCase, hopper, tuple_approx_equal from PIL import ImageOps from PIL import Image @@ -95,87 +95,94 @@ class TestImageOps(PillowTestCase): newimg = ImageOps.scale(i, 0.5) self.assertEqual(newimg.size, (25, 25)) - def test_colorize(self): - # Test the colorizing function + def test_colorize_2color(self): + # Test the colorizing function with 2-color functionality # Open test image (256px by 10px, black to white) im = Image.open("Tests/images/bw_gradient.png") im = im.convert("L") # Create image with original 2-color functionality - im_2c = ImageOps.colorize(im, 'red', 'green') - - # Create image with original 2-color functionality with offsets - im_2c_offset = ImageOps.colorize(im, - black='red', - white='green', - blackpoint=50, - whitepoint=200) - - # Create image with new three color functionality with offsets - im_3c_offset = ImageOps.colorize(im, - black='red', - white='green', - mid='blue', - blackpoint=50, - whitepoint=200, - midpoint=100) - - # Define function for approximate equality of tuples - def tuple_approx_equal(actual, target, thresh): - value = True - for i, target in enumerate(target): - value *= (target - thresh <= actual[i] <= target + thresh) - return value + im_test = ImageOps.colorize(im, 'red', 'green') # Test output image (2-color) left = (0, 1) middle = (127, 1) right = (255, 1) - self.assertTrue(tuple_approx_equal(im_2c.getpixel(left), - (255, 0, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), threshold=1), '2-color image black incorrect') - self.assertTrue(tuple_approx_equal(im_2c.getpixel(middle), - (127, 63, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), + (127, 63, 0), threshold=1), '2-color image mid incorrect') - self.assertTrue(tuple_approx_equal(im_2c.getpixel(right), - (0, 127, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), threshold=1), '2-color image white incorrect') + def test_colorize_2color_offset(self): + # Test the colorizing function with 2-color functionality and offset + + # Open test image (256px by 10px, black to white) + im = Image.open("Tests/images/bw_gradient.png") + im = im.convert("L") + + # Create image with original 2-color functionality with offsets + im_test = ImageOps.colorize(im, + black='red', + white='green', + blackpoint=50, + whitepoint=100) + # Test output image (2-color) with offsets left = (25, 1) - middle = (125, 1) - right = (225, 1) - self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(left), - (255, 0, 0), thresh=1), + middle = (75, 1) + right = (125, 1) + self.assertTrue(tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), threshold=1), '2-color image (with offset) black incorrect') - self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(middle), - (127, 63, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), + (127, 63, 0), threshold=1), '2-color image (with offset) mid incorrect') - self.assertTrue(tuple_approx_equal(im_2c_offset.getpixel(right), - (0, 127, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), threshold=1), '2-color image (with offset) white incorrect') + def test_colorize_3color_offset(self): + # Test the colorizing function with 3-color functionality and offset + + # Open test image (256px by 10px, black to white) + im = Image.open("Tests/images/bw_gradient.png") + im = im.convert("L") + + # Create image with new three color functionality with offsets + im_test = ImageOps.colorize(im, + black='red', + white='green', + mid='blue', + blackpoint=50, + whitepoint=200, + midpoint=100) + # Test output image (3-color) with offsets left = (25, 1) left_middle = (75, 1) middle = (100, 1) right_middle = (150, 1) right = (225, 1) - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(left), - (255, 0, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), threshold=1), '3-color image (with offset) black incorrect') - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(left_middle), - (127, 0, 127), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(left_middle), + (127, 0, 127), threshold=1), '3-color image (with offset) low-mid incorrect') - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(middle), - (0, 0, 255), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), + (0, 0, 255), threshold=1), '3-color image (with offset) mid incorrect') - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(right_middle), - (0, 63, 127), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(right_middle), + (0, 63, 127), threshold=1), '3-color image (with offset) high-mid incorrect') - self.assertTrue(tuple_approx_equal(im_3c_offset.getpixel(right), - (0, 127, 0), thresh=1), + self.assertTrue(tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), threshold=1), '3-color image (with offset) white incorrect') diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 4e6baf8c9..0ba7ce069 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -162,13 +162,10 @@ def colorize(image, black, white, mid=None, blackpoint=0, # Initial asserts assert image.mode == "L" - assert 0 <= whitepoint <= 255 - assert 0 <= blackpoint <= 255 - assert 0 <= midpoint <= 255 - assert blackpoint <= whitepoint - if mid is not None: - assert blackpoint <= midpoint - assert whitepoint >= midpoint + if mid is None: + assert 0 <= blackpoint <= whitepoint <= 255 + else: + assert 0 <= blackpoint <= midpoint <= whitepoint <= 255 # Define colors from arguments black = _color(black, "RGB") @@ -181,42 +178,28 @@ def colorize(image, black, white, mid=None, blackpoint=0, green = [] blue = [] + # Create the low-end values + for i in range(0, blackpoint): + red.append(black[0]) + green.append(black[1]) + blue.append(black[2]) + # Create the mapping (2-color) if mid is None: - # Define ranges - range_low = range(0, blackpoint) range_map = range(0, whitepoint - blackpoint) - range_high = range(0, 256 - whitepoint) - # Map - for i in range_low: - red.append(black[0]) - green.append(black[1]) - blue.append(black[2]) for i in range_map: red.append(black[0] + i * (white[0] - black[0]) // len(range_map)) green.append(black[1] + i * (white[1] - black[1]) // len(range_map)) blue.append(black[2] + i * (white[2] - black[2]) // len(range_map)) - for i in range_high: - red.append(white[0]) - green.append(white[1]) - blue.append(white[2]) # Create the mapping (3-color) else: - # Define ranges - range_low = range(0, blackpoint) range_map1 = range(0, midpoint - blackpoint) range_map2 = range(0, whitepoint - midpoint) - range_high = range(0, 256 - whitepoint) - # Map - for i in range_low: - red.append(black[0]) - green.append(black[1]) - blue.append(black[2]) for i in range_map1: red.append(black[0] + i * (mid[0] - black[0]) // len(range_map1)) green.append(black[1] + i * (mid[1] - black[1]) // len(range_map1)) @@ -225,10 +208,12 @@ def colorize(image, black, white, mid=None, blackpoint=0, red.append(mid[0] + i * (white[0] - mid[0]) // len(range_map2)) green.append(mid[1] + i * (white[1] - mid[1]) // len(range_map2)) blue.append(mid[2] + i * (white[2] - mid[2]) // len(range_map2)) - for i in range_high: - red.append(white[0]) - green.append(white[1]) - blue.append(white[2]) + + # Create the high-end values + for i in range(0, 256 - whitepoint): + red.append(white[0]) + green.append(white[1]) + blue.append(white[2]) # Return converted image image = image.convert("RGB") From 50d6611587424394be1fdd93255b32f96ea7e34f Mon Sep 17 00:00:00 2001 From: tsennott Date: Mon, 9 Jul 2018 07:04:48 -0700 Subject: [PATCH 30/33] moved tuple test to assert method in PillowTestCase; added docs --- Tests/helper.py | 19 ++++----- Tests/test_imageops.py | 79 +++++++++++++++++++++---------------- docs/releasenotes/5.3.0.rst | 39 ++++++++++++++++++ docs/releasenotes/index.rst | 1 + src/PIL/ImageOps.py | 5 ++- 5 files changed, 98 insertions(+), 45 deletions(-) create mode 100644 docs/releasenotes/5.3.0.rst diff --git a/Tests/helper.py b/Tests/helper.py index 834589723..b6ef6dc13 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -192,6 +192,16 @@ class PillowTestCase(unittest.TestCase): def assert_not_all_same(self, items, msg=None): self.assertFalse(items.count(items[0]) == len(items), msg) + def assert_tuple_approx_equal(self, actuals, targets, threshold, msg): + """Tests if actuals has values within threshold from targets""" + + value = True + for i, target in enumerate(targets): + value *= (target - threshold <= actuals[i] <= target + threshold) + + self.assertTrue(value, + msg + ': ' + repr(actuals) + ' != ' + repr(targets)) + def skipKnownBadTest(self, msg=None, platform=None, travis=None, interpreter=None): # Skip if platform/travis matches, and @@ -307,15 +317,6 @@ def hopper(mode=None, cache={}): return im.copy() -def tuple_approx_equal(actual, target, threshold): - """Tests if tuple actual has values within threshold from tuple target""" - - value = True - for i, target in enumerate(target): - value *= (target - threshold <= actual[i] <= target + threshold) - return value - - def command_succeeds(cmd): """ Runs the command, which must be a list of strings. Returns True if the diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 07e4dd343..9c4da2463 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -1,4 +1,4 @@ -from helper import unittest, PillowTestCase, hopper, tuple_approx_equal +from helper import unittest, PillowTestCase, hopper from PIL import ImageOps from PIL import Image @@ -109,15 +109,18 @@ class TestImageOps(PillowTestCase): left = (0, 1) middle = (127, 1) right = (255, 1) - self.assertTrue(tuple_approx_equal(im_test.getpixel(left), - (255, 0, 0), threshold=1), - '2-color image black incorrect') - self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), - (127, 63, 0), threshold=1), - '2-color image mid incorrect') - self.assertTrue(tuple_approx_equal(im_test.getpixel(right), - (0, 127, 0), threshold=1), - '2-color image white incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), + threshold=1, + msg='black test pixel incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(middle), + (127, 63, 0), + threshold=1, + msg='mid test pixel incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), + threshold=1, + msg='white test pixel incorrect') def test_colorize_2color_offset(self): # Test the colorizing function with 2-color functionality and offset @@ -137,15 +140,18 @@ class TestImageOps(PillowTestCase): left = (25, 1) middle = (75, 1) right = (125, 1) - self.assertTrue(tuple_approx_equal(im_test.getpixel(left), - (255, 0, 0), threshold=1), - '2-color image (with offset) black incorrect') - self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), - (127, 63, 0), threshold=1), - '2-color image (with offset) mid incorrect') - self.assertTrue(tuple_approx_equal(im_test.getpixel(right), - (0, 127, 0), threshold=1), - '2-color image (with offset) white incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), + threshold=1, + msg='black test pixel incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(middle), + (127, 63, 0), + threshold=1, + msg='mid test pixel incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), + threshold=1, + msg='white test pixel incorrect') def test_colorize_3color_offset(self): # Test the colorizing function with 3-color functionality and offset @@ -169,21 +175,26 @@ class TestImageOps(PillowTestCase): middle = (100, 1) right_middle = (150, 1) right = (225, 1) - self.assertTrue(tuple_approx_equal(im_test.getpixel(left), - (255, 0, 0), threshold=1), - '3-color image (with offset) black incorrect') - self.assertTrue(tuple_approx_equal(im_test.getpixel(left_middle), - (127, 0, 127), threshold=1), - '3-color image (with offset) low-mid incorrect') - self.assertTrue(tuple_approx_equal(im_test.getpixel(middle), - (0, 0, 255), threshold=1), - '3-color image (with offset) mid incorrect') - self.assertTrue(tuple_approx_equal(im_test.getpixel(right_middle), - (0, 63, 127), threshold=1), - '3-color image (with offset) high-mid incorrect') - self.assertTrue(tuple_approx_equal(im_test.getpixel(right), - (0, 127, 0), threshold=1), - '3-color image (with offset) white incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(left), + (255, 0, 0), + threshold=1, + msg='black test pixel incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(left_middle), + (127, 0, 127), + threshold=1, + msg='low-mid test pixel incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(middle), + (0, 0, 255), + threshold=1, + msg='mid incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(right_middle), + (0, 63, 127), + threshold=1, + msg='high-mid test pixel incorrect') + self.assert_tuple_approx_equal(im_test.getpixel(right), + (0, 127, 0), + threshold=1, + msg='white test pixel incorrect') if __name__ == '__main__': diff --git a/docs/releasenotes/5.3.0.rst b/docs/releasenotes/5.3.0.rst new file mode 100644 index 000000000..9869b6a7a --- /dev/null +++ b/docs/releasenotes/5.3.0.rst @@ -0,0 +1,39 @@ +5.3.0 +----- + +API Changes +=========== + +Deprecations +^^^^^^^^^^^^ + +These version constants have been deprecated. ``VERSION`` will be removed in +Pillow 6.0.0, and ``PILLOW_VERSION`` will be removed after that. + +* ``PIL.VERSION`` (old PIL version 1.1.7) +* ``PIL.PILLOW_VERSION`` +* ``PIL.Image.VERSION`` +* ``PIL.Image.PILLOW_VERSION`` + +Use ``PIL.__version__`` instead. + +API Additions +============= + +ImageOps.colorize +^^^^^^^^^^^^^^^^^ + +Previously ``ImageOps.colorize`` only supported two-color mapping with +``black`` and ``white`` arguments being mapped to 0 and 255 respectively. +Now it supports three-color mapping with the optional ``mid`` parameter, and +the positions for all three color arguments can each be optionally specified +(``blackpoint``, ``whitepoint`` and ``midpoint``). +For example, with all optional arguments:: + ImageOps.colorize(im, black=(32, 37, 79), white='white', mid=(59, 101, 175), + blackpoint=15, whitepoint=240, midpoint=100) + + + +Other Changes +============= + diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index 16e5c1d85..fc8d686eb 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -6,6 +6,7 @@ Release Notes .. toctree:: :maxdepth: 2 + 5.3.0 5.2.0 5.1.0 5.0.0 diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 0ba7ce069..9b470062a 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -147,8 +147,9 @@ def colorize(image, black, white, mid=None, blackpoint=0, optionally you can use three-color mapping by also specifying **mid**. Mapping positions for any of the colors can be specified (e.g. **blackpoint**), where these parameters are the integer - value in [0, 255] corresponding to where the corresponding color - should be mapped. + value corresponding to where the corresponding color should be mapped. + These parameters must have logical order, such that + **blackpoint** <= **midpoint** <= **whitepoint** (if **mid** is specified). :param image: The image to colorize. :param black: The color to use for black input pixels. From 87f042626f91c344efd669c76a243b74e76fe7c9 Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 11 Jul 2018 20:28:23 +0300 Subject: [PATCH 31/33] Update CHANGES.rst --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index a6018ffb6..b4bbfbb60 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 5.3.0 (unreleased) ------------------ +- Add three-color support to ImageOps.colorize #3242 + [tsennott] + - Tests: Add LA to TGA test modes #3222 [danpla] From 448beaa9aac674ec06c15a81ad6582ca34e623e9 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 12 Jul 2018 19:48:59 +1000 Subject: [PATCH 32/33] Improved wording [ci skip] --- src/libImaging/Draw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libImaging/Draw.c b/src/libImaging/Draw.c index 7b7c5fac0..a3bb92309 100644 --- a/src/libImaging/Draw.c +++ b/src/libImaging/Draw.c @@ -434,7 +434,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, } for (i = 0; i < n; i++) { - /* This causes that the pixels of horizontal edges are drawn twice :( + /* This causes the pixels of horizontal edges to be drawn twice :( * but without it there are inconsistencies in ellipses */ if (e[i].ymin == e[i].ymax) { (*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink); From 44a4219283a0c38e3eb5be7fae7c0715794c312a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 14 Jul 2018 18:55:13 +1000 Subject: [PATCH 33/33] Added test for converting GIF with RGBA palette to P --- Tests/test_image_convert.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index ed971e698..1e208d80c 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -136,6 +136,17 @@ class TestImageConvert(PillowTestCase): self.assertNotIn('transparency', im_p.info) im_p.save(f) + def test_gif_with_rgba_palette_to_p(self): + # See https://github.com/python-pillow/Pillow/issues/2433 + im = Image.open('Tests/images/hopper.gif') + im.info['transparency'] = 255 + im.load() + self.assertEqual(im.palette.mode, 'RGBA') + im_p = im.convert('P') + + # Should not raise ValueError: unrecognized raw mode + im_p.load() + def test_p_la(self): im = hopper('RGBA') alpha = hopper('L')