Image Module - class Image ########################## .. note:: All source images in this document are derived from https://www.pexels.com (CC0 License). .. |srcimg01| image:: _static/exams/data/srcimg01.jpg :width: 20% .. |srcimg02| image:: _static/exams/data/srcimg02.jpg :width: 20% .. |srcimg03| image:: _static/exams/data/srcimg03.jpg :width: 20% .. |srcimg04| image:: _static/exams/data/srcimg04.jpg :width: 20% .. |srcimg05| image:: _static/exams/data/srcimg05.jpg :width: 20% .. |srcimg06| image:: _static/exams/data/srcimg06.jpg :width: 20% .. |srcimg07| image:: _static/exams/data/srcimg07.jpg :width: 20% .. |srcimg08| image:: _static/exams/data/srcimg08.jpg :width: 20% .. |srcimg09| image:: _static/exams/data/srcimg09.png :width: 20% .. |srcimg10| image:: _static/exams/data/srcimg10.png :width: 20% .. |srcimg11| image:: _static/exams/data/srcimg11.png :width: 20% .. |srcimg12| image:: _static/exams/data/srcimg12.jpg :width: 20% .. |srcimg13| image:: _static/exams/data/srcimg13.jpg :width: 20% .. |srcimg14| image:: _static/exams/data/srcimg14.jpg :width: 20% .. |srcimg15| image:: _static/exams/data/srcimg15.jpg :width: 20% .. |srcimg16| image:: _static/exams/data/srcimg16.jpg :width: 20% .. |srcimg17| image:: _static/exams/data/srcimg17.jpg :width: 20% .. |srcimg24| image:: _static/exams/data/srcimg24.jpg :width: 40% Methods ******* convert ======= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.convert, http://effbot.org/imagingbook/image.htm#tag-Image.Image.convert .. _convert_mode: **convert(mode)** .. list-table:: * - srcimg03.jpg |srcimg03| .. |im.convert_m.res1| image:: _static/exams/result/im_convert_m_L_01.jpg .. |im.convert_m.res2| image:: _static/exams/result/im_convert_m_1_01.jpg .. |im.convert_m.res3| image:: _static/exams/result/im_convert_m_in_01.png .. |im.convert_m.res4| image:: _static/exams/result/im_convert_m_RGB_01.jpg .. list-table:: :widths: 10 10 10 * - .. literalinclude:: _static/exams/im_convert_m_01.py - im_convert_m_L_01.jpg |im.convert_m.res1| - im_convert_m_1_01.jpg |im.convert_m.res2| * - .. literalinclude:: _static/exams/im_convert_m_02.py - im_convert_m_in_01.png |im.convert_m.res3| - im_convert_m_RGB_01.jpg |im.convert_m.res4| .. _convert_P: **convert("P", \*\*options)** .. list-table:: * - srcimg04.jpg |srcimg04| .. |im.convert_P.res1| image:: _static/exams/result/im_convert_P_01.png .. |im.convert_P.res2| image:: _static/exams/result/im_convert_P_02.png .. |im.convert_P.res3| image:: _static/exams/result/im_convert_P_03.png .. list-table:: :widths: 30 10 * - .. literalinclude:: _static/exams/im_convert_P_01.py - |im.convert_P.res1| * - .. literalinclude:: _static/exams/im_convert_P_02.py - |im.convert_P.res2| * - .. literalinclude:: _static/exams/im_convert_P_03.py - |im.convert_P.res3| **convert(mode, matrix)** .. list-table:: * - srcimg03.jpg |srcimg03| .. |im.convert_mm.res1| image:: _static/exams/result/im_convert_mm_01.jpg .. list-table:: :widths: 30 10 * - .. literalinclude:: _static/exams/im_convert_mm_01.py - |im.convert_mm.res1| copy ==== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.copy, http://effbot.org/imagingbook/image.htm#tag-Image.Image.copy .. code-block:: pycon >>> from PIL import Image >>> >>> srcimg = Image.new("L", (2, 2), 128) >>> cloned = srcimg.copy() >>> cloned.putdata((0, 64, 128, 192)) >>> >>> srcimg.tobytes("raw") # not changed b'\x80\x80\x80\x80' >>> cloned.tobytes("raw") b'\x00@\x80\xc0' crop ==== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.crop, http://effbot.org/imagingbook/image.htm#tag-Image.Image.crop .. list-table:: * - srcimg11.png |srcimg11| .. |im.crop.res1| image:: _static/exams/result/im_crop_01.jpg .. list-table:: :widths: 30 10 * - .. literalinclude:: _static/exams/im_crop_01.py - |im.crop.res1| draft ===== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.draft, http://effbot.org/imagingbook/image.htm#tag-Image.Image.draft The official documents says: "*For example, you can use this method to convert a color JPEG to greyscale while loading it*": .. code-block:: pycon >>> from PIL import Image >>> >>> img = Image.open("data/srcimg01.jpg") >>> img >>> img.decoderconfig, img.mode, img.size, img.tile ((), 'RGB', (670, 445), [('jpeg', (0, 0, 670, 445), 0, ('RGB', ''))]) >>> img.draft("L", (img.width // 4, img.height // 4)) >>> img.decoderconfig, img.mode, img.size, img.tile ((4, 0), 'L', (168, 112), [('jpeg', (0, 0, 168, 112), 0, ('L', ''))]) >>> img.show() but normally you should not depend on this method very much, because: *This method is not implemented for most images. It is currently implemented only for JPEG and PCD images*. To convert mode, simply use :ref:`convert(mode) `, and to resize image, simply use :ref:`resize `. filter ====== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.filter, http://effbot.org/imagingbook/image.htm#tag-Image.Image.filter See :ref:`ImageFilter`. getbands ======== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getbands, http://effbot.org/imagingbook/image.htm#tag-Image.Image.getbands .. code-block:: pycon >>> from glob import iglob >>> from PIL import Image >>> >>> for fn in iglob("data/*.[jp][pn]g"): ... img = Image.open(fn) ... print("{}: {}".format(fn, img.getbands())) ... data/mask_circle_01.jpg: ('L',) - snip - data/srcimg08.jpg: ('R', 'G', 'B') data/srcimg09.png: ('R', 'G', 'B', 'A') data/srcimg10.png: ('R', 'G', 'B') - snip - getbbox ======= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getbbox, http://effbot.org/imagingbook/image.htm#tag-Image.Image.getbbox .. code-block:: pycon >>> from glob import iglob >>> from PIL import Image >>> >>> for fn in iglob("data/*.[jp][pn]g"): ... img = Image.open(fn) ... print("{}: {}".format(fn, img.getbbox())) ... data/mask_circle_01.jpg: (0, 0, 256, 256) - snip - data/srcimg16.jpg: (0, 0, 675, 500) data/srcimg17.jpg: (0, 0, 967, 750) getcolors, getpalette ===================== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getcolors, http://effbot.org/imagingbook/image.htm#tag-Image.Image.getcolors, https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getpalette getcolors and getpalette with "P" mode: .. code-block:: pycon >>> from PIL import Image >>> img = Image.open('data/srcimg06.jpg') >>> img = img.convert("P", palette=Image.ADAPTIVE, colors=16) >>> # >>> img.width * img.height 280350 >>> # pixel values are represented by indexes: >>> data = list(img.getdata()) >>> len(data) # == img.width * img.height, that is, these are not [(r, g, b), ...] 280350 >>> data[50:70] [7, 7, 7, 7, 7, 7, 7, 7, 13, 7, 7, 7, 7, 7, 7, 13, 13, 13, 7, 7] >>> # getcolors returns unsorted list of (count, color) tuples. >>> # If the maxcolors value is exceeded, the method stops counting and returns None. >>> clrs = img.getcolors() >>> len(clrs) 16 >>> clrs.sort(key=lambda x: x[1]) # sort by color >>> >>> # show up colors and palette >>> p_nzero = img.getpalette()[:len(clrs) * 3] >>> for v in [(clrs[i // 3], (p_nzero[i], p_nzero[i + 1], p_nzero[i + 2])) ... for i in range(0, len(p_nzero), 3)]: ... print(v) ... ((24270, 0), (227, 230, 229)) ((8860, 1), (212, 210, 208)) ((24091, 2), (190, 201, 214)) ((25088, 3), (167, 188, 206)) ((15363, 4), (199, 157, 148)) ((6508, 5), (143, 163, 172)) ((4955, 6), (118, 150, 170)) ((27667, 7), (88, 140, 199)) ((20889, 8), (224, 101, 150)) ((23184, 9), (136, 102, 92)) ((16386, 10), (188, 50, 112)) ((16948, 11), (133, 34, 70)) ((17653, 12), (82, 106, 93)) ((11588, 13), (44, 99, 157)) ((20856, 14), (51, 63, 49)) ((16044, 15), (25, 21, 13)) getcolors and getpalette with "L" mode: .. code-block:: pycon >>> from PIL import Image >>> img = Image.open('data/srcimg06.jpg').convert("L") >>> # getcolors returns unsorted list of (count, color) tuples. >>> # If the maxcolors value is exceeded, the method stops counting and returns None. >>> clrs = img.getcolors() >>> len(clrs) 256 >>> print("\n".join(map(str, clrs))) (826, 0) (537, 1) (450, 2) - snip - (106, 253) (62, 254) (1, 255) >>> img.getpalette() is None True getdata ======= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getdata, http://effbot.org/imagingbook/image.htm#tag-Image.Image.getdata .. code-block:: pycon >>> from PIL import Image >>> img = Image.open('data/srcimg06.jpg') >>> grn = img.getdata(band=1) # get green >>> upth, lwth = 0, 0 >>> for c in grn: # grn is a sequence-like object. ... if c < 128: ... lwth += 1 ... else: ... upth += 1 ... >>> print("upper={}, lower={}".format(upth, lwth)) upper=144495, lower=135855 .. code-block:: pycon >>> # pixel data to numpy array >>> import numpy as np >>> from PIL import Image >>> img = Image.open('data/srcimg06.jpg') >>> red = np.array(img.getdata(band=0)) # get red >>> grn = np.array(img.getdata(band=1)) # get green >>> blu = np.array(img.getdata(band=2)) # get blur >>> >>> red array([ 14, 25, 28, ..., 96, 118, 124]) >>> red[red < 50] = 0 >>> red array([ 0, 0, 0, ..., 96, 118, 124]) .. code-block:: pycon >>> # pixel data to numpy array >>> import numpy as np >>> from PIL import Image >>> img = Image.open('data/srcimg06.jpg') >>> rawpb1 = np.array(img.getdata(), dtype=np.uint8).reshape((img.height, img.width, 3)) >>> rawpb1.shape (450, 623, 3) >>> rawpb1 array([[[ 14, 74, 160], [ 25, 85, 171], [ 28, 90, 175], ..., [ 6, 52, 130], [ 10, 53, 131], [ 7, 49, 125]], --- snip --- [[151, 67, 82], [102, 32, 43], [146, 95, 100], ..., [ 96, 92, 55], [118, 112, 78], [124, 120, 85]]], dtype=uint8) >>> >>> # you can use numpy.asarray: >>> rawpb2 = np.asarray(img) >>> rawpb2.shape (450, 623, 3) >>> rawpb2 array([[[ 14, 74, 160], [ 25, 85, 171], [ 28, 90, 175], ..., [ 6, 52, 130], [ 10, 53, 131], [ 7, 49, 125]], --- snip --- [[151, 67, 82], [102, 32, 43], [146, 95, 100], ..., [ 96, 92, 55], [118, 112, 78], [124, 120, 85]]], dtype=uint8) >>> >>> # identical? >>> np.all(rawpb1 == rawpb2) True .. code-block:: pycon >>> # pixel data to numpy array >>> import numpy as np >>> from PIL import Image >>> img = Image.open('data/srcimg06.jpg').convert("L") # as grayscale >>> gray = np.array(img.getdata()) >>> >>> gray array([ 65, 76, 81, ..., 88, 109, 117]) >>> gray[gray < 70] = 0 >>> gray array([ 0, 76, 81, ..., 88, 109, 117]) See also: `putdata `_. getextrema ========== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getextrema, http://effbot.org/imagingbook/image.htm#tag-Image.Image.getextrema .. code-block:: pycon >>> from PIL import Image >>> img = Image.open('data/mask_grad_01.jpg') # L (i.e., single band) >>> img.getextrema() (0, 255) >>> img = Image.open('data/srcimg02.jpg') # RBG (i.e., multiple bands) >>> img.getextrema() ((0, 255), (0, 236), (0, 245)) >>> img = Image.open('data/srcimg04.jpg') # RBG >>> img.getextrema() ((3, 255), (0, 255), (0, 255)) >>> img = Image.open('data/srcimg06.jpg') # RBG >>> img.getextrema() ((0, 255), (0, 255), (0, 255)) getpixel ======== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getpixel, http://effbot.org/imagingbook/image.htm#tag-Image.Image.getpixel .. code-block:: pycon >>> from PIL import Image >>> img1 = Image.open('data/mask_grad_01.jpg') # L >>> img1.getpixel((10, 20)) 20 >>> img2 = Image.open('data/srcimg06.jpg') # RBG >>> img2.getpixel((10, 20)) (127, 144, 198) histogram ========= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.histogram, http://effbot.org/imagingbook/image.htm#tag-Image.Image.histogram .. list-table:: * - srcimg03.jpg |srcimg03| .. code-block:: pycon >>> from PIL import Image >>> fn = 'data/srcimg03.jpg' >>> simg = Image.open(fn) >>> r, g, b = simg.split() >>> len(r.histogram()) 256 >>> r.histogram() [2402, 236, 214, 258, 234, ...(snip)..., 16366] .. |im.histogram.res1| image:: _static/exams/result/im_histogram_01.jpg To visualize this list, for example: .. list-table:: * - .. literalinclude:: _static/exams/im_histogram_01.py - |im.histogram.res1| offset ====== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.offset, http://effbot.org/imagingbook/image.htm#tag-Image.Image.offset This method that have been marked as deprecated for many releases have been removed at Pillow 3.0.0 (actually is still defined but raise NotImplementedError). Use `ImageChops.offset() `_ instead. paste ===== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.paste, http://effbot.org/imagingbook/image.htm#tag-Image.Image.paste .. |im.paste.res1| image:: _static/exams/result/im_paste_01.jpg .. |im.paste.res2| image:: _static/exams/result/im_paste_02.jpg .. |im.paste.res3| image:: _static/exams/result/im_paste_03.jpg .. |im.paste.res4| image:: _static/exams/result/im_paste_04.jpg .. list-table:: * - srcimg12.jpg |srcimg12| - srcimg13.jpg |srcimg13| .. literalinclude:: _static/exams/im_paste_01.py .. list-table:: * - (0, 0) |im.paste.res1| - (50, 50) |im.paste.res2| - (50, 50) with mask |im.paste.res3| - (50, 50) with mask (circle) |im.paste.res4| point ====== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.point, http://effbot.org/imagingbook/image.htm#tag-Image.Image.point .. |im.point.res1| image:: _static/exams/result/im_point_01.jpg :width: 40% .. |im.point.res2| image:: _static/exams/result/im_point_02.jpg :width: 40% .. |im.point.res3| image:: _static/exams/result/im_point_03.jpg :width: 40% .. list-table:: * - srcimg04.jpg |srcimg04| .. list-table:: * - .. literalinclude:: _static/exams/im_point_01.py - | im_point_01.jpg |im.point.res1| | im_point_02.jpg |im.point.res2| | im_point_03.jpg |im.point.res3| putalpha ======== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.putalpha, http://effbot.org/imagingbook/image.htm#tag-Image.Image.putalpha .. |im.putalpha.res1| image:: _static/exams/result/im_putalpha_01.png .. |im.putalpha.res2| image:: _static/exams/result/im_putalpha_02.png .. list-table:: * - srcimg12.jpg |srcimg12| .. list-table:: :widths: 15 10 * - .. literalinclude:: _static/exams/im_putalpha_01.py - |im.putalpha.res1| .. list-table:: :widths: 15 10 * - .. literalinclude:: _static/exams/im_putalpha_02.py - |im.putalpha.res2| putdata ======== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.putdata, http://effbot.org/imagingbook/image.htm#tag-Image.Image.putdata .. |im.putdata.res1| image:: _static/exams/result/im_putdata_01.jpg .. |im.putdata.res2| image:: _static/exams/result/im_putdata_02.jpg .. |im.putdata.res3| image:: _static/exams/result/im_putdata_03.jpg .. |im.putdata.res4| image:: _static/exams/result/im_putdata_04.jpg .. list-table:: :widths: 80 10 * - .. literalinclude:: _static/exams/im_putdata_01.py - |im.putdata.res1| * - .. literalinclude:: _static/exams/im_putdata_02.py - |im.putdata.res2| * - .. literalinclude:: _static/exams/im_putdata_03.py - |im.putdata.res3| * - .. literalinclude:: _static/exams/im_putdata_04.py - |im.putdata.res4| .. code-block:: pycon >>> # from bytes >>> from PIL import Image >>> >>> rawpixelbytes = b'\xa0\xfe\xfe\xa0' >>> >>> # with frombytes >>> img1 = Image.frombytes("L", (2, 2), rawpixelbytes) >>> >>> # putdata after new >>> img2 = Image.new("L", (2, 2)) >>> img2.putdata(rawpixelbytes) >>> >>> # identical? >>> img1.tobytes("raw"), img2.tobytes("raw"), img1.tobytes("raw") == img2.tobytes("raw") (b'\xa0\xfe\xfe\xa0', b'\xa0\xfe\xfe\xa0', True) >>> >>> # putdata after new with scale=0.5 >>> hex(0xa0 // 2), chr(0xa0 // 2), hex(0xfe // 2) ('0x50', 'P', '0x7f') >>> img3 = Image.new("L", (2, 2)) >>> img3.putdata(rawpixelbytes, scale=1/2.) >>> img3.tobytes("raw") b'P\x7f\x7fP' >>> >>> # putdata after new with offset=-0x10 >>> hex(0xa0 - 0x10), hex(0xfe - 0x10) ('0x90', '0xee') >>> img4 = Image.new("L", (2, 2)) >>> img4.putdata(rawpixelbytes, offset=-0x10) >>> img4.tobytes("raw") b'\x90\xee\xee\x90' See also: `frombytes `_, `frombuffer `_, `fromarray `_. putpalette, remap_palette ========================= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.putpalette, https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.remap_palette .. note:: See also: `getcolors, getpalette <#getcolors-getpalette>`_. remap_palette will change both pixel value and palette (in other words, indexes as pixel values will follow new palette table): .. code-block:: pycon >>> import os >>> from PIL import Image >>> >>> img = Image.open('data/srcimg06.jpg') >>> img = img.convert("P", palette=Image.ADAPTIVE, colors=16) >>> img.save('result/p_adaptive16_orig.png') >>> os.stat('result/p_adaptive16_orig.png').st_size 76348 >>> # pixel values are represented by indexes: >>> data = list(img.getdata()) >>> data[50:70] [7, 7, 7, 7, 7, 7, 7, 7, 13, 7, 7, 7, 7, 7, 7, 13, 13, 13, 7, 7] >>> clrs = img.getcolors() >>> len(clrs) 16 >>> >>> # show up colors and palette >>> srcpalette = img.getpalette() >>> p_nzero = srcpalette[:len(clrs) * 3] >>> clrs.sort(key=lambda x: x[1]) # sort by color, for showing >>> for v in [(clrs[i // 3], (p_nzero[i], p_nzero[i + 1], p_nzero[i + 2])) ... for i in range(0, len(p_nzero), 3)]: ... print(v) ... ((24270, 0), (227, 230, 229)) ((8860, 1), (212, 210, 208)) ((24091, 2), (190, 201, 214)) ((25088, 3), (167, 188, 206)) ((15363, 4), (199, 157, 148)) ((6508, 5), (143, 163, 172)) ((4955, 6), (118, 150, 170)) ((27667, 7), (88, 140, 199)) ((20889, 8), (224, 101, 150)) ((23184, 9), (136, 102, 92)) ((16386, 10), (188, 50, 112)) ((16948, 11), (133, 34, 70)) ((17653, 12), (82, 106, 93)) ((11588, 13), (44, 99, 157)) ((20856, 14), (51, 63, 49)) ((16044, 15), (25, 21, 13)) >>> # build new palette ordered by occurrence, and create new image with it >>> clrs.sort(key=lambda x: -x[0]) # sort by occurrence >>> img = img.remap_palette([c for oc, c in clrs]) >>> img.save('result/p_adaptive16_remapped.png') >>> os.stat('result/p_adaptive16_remapped.png').st_size 72098 >>> >>> # --- show up again for new image >>> data = list(img.getdata()) >>> data[50:70] [0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0] >>> clrs = img.getcolors() >>> p_nzero = img.getpalette()[:len(clrs) * 3] >>> clrs.sort(key=lambda x: x[1]) # sort by color, for showing >>> for v in [(clrs[i // 3], (p_nzero[i], p_nzero[i + 1], p_nzero[i + 2])) ... for i in range(0, len(p_nzero), 3)]: ... print(v) ... ((27667, 0), (88, 140, 199)) ((25088, 1), (167, 188, 206)) ((24270, 2), (227, 230, 229)) ((24091, 3), (190, 201, 214)) ((23184, 4), (136, 102, 92)) ((20889, 5), (224, 101, 150)) ((20856, 6), (51, 63, 49)) ((17653, 7), (82, 106, 93)) ((16948, 8), (133, 34, 70)) ((16386, 9), (188, 50, 112)) ((16044, 10), (25, 21, 13)) ((15363, 11), (199, 157, 148)) ((11588, 12), (44, 99, 157)) ((8860, 13), (212, 210, 208)) ((6508, 14), (143, 163, 172)) ((4955, 15), (118, 150, 170)) .. |srcimg06_100| image:: _static/exams/data/srcimg06.jpg .. |p_adaptive16_orig| image:: _static/exams/result/p_adaptive16_orig.png .. |p_adaptive16_remap| image:: _static/exams/result/p_adaptive16_remapped.png .. |p_adaptive16_newpalette| image:: _static/exams/result/p_adaptive16_newpalette.png .. list-table:: * - | |srcimg06_100| | original - | |p_adaptive16_orig| | convert("P") - | |p_adaptive16_remap| | remap_palette Meanwhile, putpalette replace only the colors of the palette: >>> from PIL import Image >>> >>> img = Image.open('data/srcimg06.jpg') >>> img = img.convert("P", palette=Image.ADAPTIVE, colors=16) >>> data = list(img.getdata()) >>> data[50:70] [7, 7, 7, 7, 7, 7, 7, 7, 13, 7, 7, 7, 7, 7, 7, 13, 13, 13, 7, 7] >>> clrs = img.getcolors() >>> len(clrs) 16 >>> >>> # sort the colors of the palette ordered by occurrence >>> # (Of course, this is nonsence. Just an example.) >>> srcpalette = img.getpalette() >>> newpalette = [] >>> for oc, c in sorted(clrs, key=lambda x: -x[0]): ... newpalette.extend([srcpalette[c * 3], srcpalette[c * 3 + 1], srcpalette[c * 3 + 2]]) ... >>> newpalette.extend((768 - len(newpalette)) * [0]) >>> >>> # result image is no longer the same photo. >>> img.putpalette(newpalette) >>> data = list(img.getdata()) >>> data[50:70] # not changed [7, 7, 7, 7, 7, 7, 7, 7, 13, 7, 7, 7, 7, 7, 7, 13, 13, 13, 7, 7] >>> img.save('result/p_adaptive16_newpalette.png') .. list-table:: * - | |srcimg06_100| | original - | |p_adaptive16_orig| | convert("P") - | |p_adaptive16_newpalette| | putpalette putpixel ======== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.putpixel, http://effbot.org/imagingbook/image.htm#tag-Image.Image.putpixel .. note:: This method is relatively slow. For more extensive changes, use `paste() <#paste>`_ or the `ImageDraw module `_ instead. And also, if you want to put data as a whole image, see `putdata() <#putdata>`_. For single band: .. code-block:: pycon >>> from PIL import Image >>> >>> img = Image.new("L", (4, 4)) # single band >>> for y in range(4): ... for x in range(4): ... img.putpixel((x, y), y * 64) ... >>> list(img.getdata()) [0, 0, 0, 0, 64, 64, 64, 64, 128, 128, 128, 128, 192, 192, 192, 192] You can also use `PixelAccess `_ (but fairly slow, too): .. code-block:: pycon >>> from PIL import Image >>> >>> img = Image.new("L", (4, 4)) # single band >>> px = img.load() >>> for y in range(4): ... for x in range(4): ... px[(x, y)] = y * 64 ... >>> list(img.getdata()) [0, 0, 0, 0, 64, 64, 64, 64, 128, 128, 128, 128, 192, 192, 192, 192] For multiple bands: .. code-block:: pycon >>> from PIL import Image >>> >>> img = Image.new("RGB", (4, 4)) # multiple bands >>> for y in range(4): ... for x in range(4): ... img.putpixel( ... (x, y), ... ((y + 1) * 64, y * 64, 255 - (y * 64))) ... >>> print("\n".join(list(map(str, img.getdata())))) (64, 0, 255) (64, 0, 255) (64, 0, 255) (64, 0, 255) (128, 64, 191) (128, 64, 191) (128, 64, 191) (128, 64, 191) (192, 128, 127) (192, 128, 127) (192, 128, 127) (192, 128, 127) (255, 192, 63) (255, 192, 63) (255, 192, 63) (255, 192, 63) You can also use `PixelAccess `_ (but fairly slow, too): .. code-block:: pycon >>> from PIL import Image >>> >>> img = Image.new("RGB", (4, 4)) # multiple bands >>> px = img.load() >>> for y in range(4): ... for x in range(4): ... px[(x, y)] = ((y + 1) * 64, y * 64, 255 - (y * 64)) ... >>> print("\n".join(list(map(str, img.getdata())))) (64, 0, 255) (64, 0, 255) (64, 0, 255) (64, 0, 255) (128, 64, 191) (128, 64, 191) (128, 64, 191) (128, 64, 191) (192, 128, 127) (192, 128, 127) (192, 128, 127) (192, 128, 127) (255, 192, 63) (255, 192, 63) (255, 192, 63) (255, 192, 63) quantize ======== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.quantize, http://effbot.org/imagingbook/image.htm#tag-Image.Image.quantize .. note:: This method of original PIL is deprecated because this is identical to :ref:`convert("P", \*\*options) `, but in the case of Pillow, these are not the same each other. Pillow version is for `color quantization `_, as its name claims so that. (Strictly speaking, :ref:`convert("P", \*\*options) ` will also do `color quantization `_, so the differences are those scope. For example, you can't select quantizer method if you are using :ref:`convert("P", \*\*options) `.) .. note:: It seems that the argument *method* can be: * method=0: `median cut `_ * method=1: `maximum coverage `_ * method=2: `octree `_ * method=3: `libpngquant `_ , but official documents (which is the same as the docstring of python source code) and `C source code `_ comment doesn't say so. I can't say for sure. The argument *kmeans* seems that it is for `k-means clustering `_, and I can't say for sure about this, too. *kmeans* is likely used only by mode=0(median cut), 1(maximum coverage), and it seems k-means logic is applied after processing "median cut" or "maximum coverage" while `changes <= (kmeans - 1) `_. Sorry, I can't understand at all about these. At least, zero *kmeans* value is no effect, larger *kmeans* increase the times of call of k-means logic. And I can't sure these spec is frozen or not. .. code-block:: pycon >>> from PIL import Image >>> >>> img = Image.open('data/srcimg06.jpg') >>> dimg = img.quantize( ... colors=32, ... method=0, # median cut ... kmeans=5) >>> len(dimg.getcolors()) 32 >>> dimg.save("result/im_quantize_32_0_5.png") >>> dimg = img.quantize( ... colors=32, ... method=1, # maximum coverage ... kmeans=5) >>> len(dimg.getcolors()) 32 >>> dimg.save("result/im_quantize_32_1_5.png") >>> dimg = img.quantize( ... colors=32, ... method=2) # octree >>> len(dimg.getcolors()) 32 >>> dimg.save("result/im_quantize_32_2.png") .. |im_quantize_32_0_5| image:: _static/exams/result/im_quantize_32_0_5.png .. |im_quantize_32_1_5| image:: _static/exams/result/im_quantize_32_1_5.png .. |im_quantize_32_2| image:: _static/exams/result/im_quantize_32_2.png .. list-table:: * - | |srcimg06_100| | original - | |im_quantize_32_0_5| | 32, 0, 5 - | |im_quantize_32_1_5| | 32, 1, 5 - | |im_quantize_32_2| | 32, 2 .. _im_resize: resize ====== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.resize, http://effbot.org/imagingbook/image.htm#tag-Image.Image.resize About *resample*, see `Filters `_. .. code-block:: python from PIL import Image img = Image.open('data/srcimg13.jpg') # * "resize" returns new image. # * "resize" streches image without considering aspect ratio. img = img.resize((img.width // 4, img.height * 2)) rotate ====== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.rotate, http://effbot.org/imagingbook/image.htm#tag-Image.Image.rotate About *resample*, see `Filters `_. .. |im.rotate.res1| image:: _static/exams/result/im_rotate_r-10.jpg .. |im.rotate.res2| image:: _static/exams/result/im_rotate_r-10_expand.jpg .. |im.rotate.res3| image:: _static/exams/result/im_rotate_r-10m.png .. |im.rotate.res4| image:: _static/exams/result/im_rotate_r-10m_expand.png .. list-table:: * - srcimg14.jpg |srcimg14| (size=(912, 684)) .. literalinclude:: _static/exams/im_rotate_01.py .. list-table:: * - rotate=-10 => result size=(912, 684) |im.rotate.res1| - rotate=-10, expand=True => result size=(1017, 833) |im.rotate.res2| .. literalinclude:: _static/exams/im_rotate_02.py .. list-table:: * - rotate=-10 => result size=(912, 684) |im.rotate.res3| - rotate=-10, expand=True => result size=(1017, 833) |im.rotate.res4| save ==== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.save, http://effbot.org/imagingbook/image.htm#tag-Image.Image.save Saves this image under the given filename: .. code-block:: python from PIL import Image img = Image.new("RGB", (16, 16)) img.save("out.jpg") If the filename extension is not a standard, you can pass *format* argument explicitly: .. code-block:: python from PIL import Image img = Image.new("RGB", (16, 16)) img.save("out.thumbnail", "JPEG") Possible formats are described in `Image file formats `_. Each format writer sometimes takes additional keyword arguments: .. code-block:: python from PIL import Image img = Image.new("RGB", (16, 16)) img.save("out.thumbnail", "JPEG", quality=75) Those specifications are also described in `Image file formats `_. You can use a file object instead of a filename: .. code-block:: python from PIL import Image img = Image.new("RGB", (16, 16)) with open("out.thumbnail", "wb") as fo: img.save(fo, "JPEG", quality=75) The file object must implement the seek, tell, and write methods, and be opened in binary mode. In other words, you can also use file-like object like :code:`io.BytesIO`: .. list-table:: :widths: 25 10 * - .. literalinclude:: _static/exams/im_save_01.py - | | `result/encoded_image_01.html <_static/exams/result/encoded_image_01.html>`_ seek, tell ========== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.seek, https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.tell, http://effbot.org/imagingbook/image.htm#tag-Image.Image.seek, http://effbot.org/imagingbook/image.htm#tag-Image.Image.tell :file:`ImageChops_blend_02.gif`: see `blend `_. .. code-block:: pycon >>> from PIL import Image >>> # ImageChops_blend_02.gif has 33 frames. >>> img = Image.open("result/ImageChops_blend_02.gif") >>> img.tell() 0 >>> img.seek(img.tell() + 1) >>> img.tell() 1 >>> img.show() >>> # convert RGB before save as jpeg to avoid "IOError: cannot write mode P as JPEG" >>> img.convert("RGB").save("frame1.jpg") >>> for i in range(31): img.seek(img.tell() + 1) ... >>> img.seek(img.tell() + 1) Traceback (most recent call last): File "", line 1, in File "c:\Python27\lib\site-packages\PIL\GifImagePlugin.py", line 132, in seek raise EOFError("no more images in GIF file") EOFError: no more images in GIF file See also: `ImageSequence `_. show ==== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.show, http://effbot.org/imagingbook/image.htm#tag-Image.Image.show Displays this image. This method is **mainly intended for debugging purposes**. .. code-block:: pycon >>> from PIL import Image, ImageDraw, ImageChops >>> >>> dia = 128 >>> circle = Image.new("L", (dia * 4, dia * 4), 0) >>> dctx = ImageDraw.Draw(circle) >>> dctx.ellipse([dia, dia, dia * 3, dia * 3], fill=255) >>> del dctx >>> >>> offset = dia // 2 >>> r = ImageChops.offset(circle, offset, offset) >>> #r.show() >>> g = ImageChops.offset(circle, -offset, offset) >>> #g.show() >>> b = ImageChops.offset(circle, 0, -offset) >>> #b.show() >>> >>> dimg = Image.merge("RGB", (r, g, b)) >>> #dimg.show() >>> mask = Image.eval(dimg.convert("L"), lambda p: 255 if p > 0 else 0) >>> #mask.show() >>> dimg.putalpha(mask) >>> dimg.show() If you use Windows, and you encounter the trouble like: *Windows Photo Viewer can’t open this picture because either the picture is deleted, or it’s in a location that isn’t available.* or in Japanese edition: *この画像が削除されたか、利用出来ない場所にあるため、Windows フォトビューワーでこの画像を開けません。* , you can replace the viewer as you like with inserting the following codes in your debuggee code: .. list-table:: * - .. code-block:: python :caption: "without cleanup temporary" version from PIL import ImageShow class _WindowsViewer_NoDelTemp(ImageShow.Viewer): format = "BMP" def get_command(self, file, **options): # defined as the following in original WindowsViewer # (of PIL version '1.1.7', Pillow version = '4.1.1'): # # return ('start "Pillow" /WAIT "%s" ' # '&& ping -n 2 127.0.0.1 >NUL ' # '&& del /f "%s"' % (file, file)) return ("""start "Pillow" /WAIT "%s" """ % (file, )) # you have to cleanup temporary files manually... ImageShow.register(_WindowsViewer_NoDelTemp, order=-1) - .. code-block:: python :caption: "simply change the retry count of ping" version :emphasize-lines: 8 from PIL import ImageShow class _WindowsViewer2(ImageShow.Viewer): format = "BMP" def get_command(self, file, **options): return ('start "Pillow" /WAIT "%s" ' '&& ping -n 5 127.0.0.1 >NUL ' # "-n 2" -> "-n 5" '&& del /f "%s"' % (file, file)) ImageShow.register(_WindowsViewer2, order=-1) * - .. code-block:: python :caption: "too much but without 'start'" version from PIL import ImageShow class _WindowsViewer3(ImageShow.Viewer): format = "BMP" def get_command(self, file, **options): import os, subprocess, atexit, win32process atexit.register( subprocess.Popen, ["python", "-c", "import time, os ; time.sleep(5); os.remove('%s')" % \ file.replace(os.sep, "/")], creationflags=subprocess.CREATE_NEW_PROCESS_GROUP | \ win32process.DETACHED_PROCESS, close_fds=True) return ("""start "Pillow" /WAIT "%s" """ % (file, )) ImageShow.register(_WindowsViewer3, order=-1) - | split ===== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.split, http://effbot.org/imagingbook/image.htm#tag-Image.Image.split .. list-table:: * - srcimg24.jpg |srcimg24| .. |im.split.res1| image:: _static/exams/result/im_split_01_rL.jpg .. |im.split.res2| image:: _static/exams/result/im_split_01_gL.jpg .. |im.split.res3| image:: _static/exams/result/im_split_01_bL.jpg .. |im.split.res4| image:: _static/exams/result/im_split_01_r.jpg .. |im.split.res5| image:: _static/exams/result/im_split_01_g.jpg .. |im.split.res6| image:: _static/exams/result/im_split_01_b.jpg .. literalinclude:: _static/exams/im_split_01.py .. list-table:: * - im_split_01_rL.jpg |im.split.res1| - im_split_01_gL.jpg |im.split.res2| - im_split_01_bL.jpg |im.split.res3| * - im_split_01_r.jpg |im.split.res4| - im_split_01_g.jpg |im.split.res5| - im_split_01_b.jpg |im.split.res6| thumbnail ========= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.thumbnail, http://effbot.org/imagingbook/image.htm#tag-Image.Image.thumbnail About *resample*, see `Filters `_. .. literalinclude:: _static/exams/create_thumbnails.py tobitmap ======== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.tobitmap, http://effbot.org/imagingbook/image.htm#tag-Image.Image.tobitmap .. code-block:: pycon >>> from io import BytesIO >>> from PIL import Image >>> >>> img = Image.frombytes("L", (16, 16), b'''\ ... \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\ ... \xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\ ... \xff\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\xff\ ... \xff\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\ ... \xff\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\xff\ ... \xff\x00\x00\x00\x00\xff\x00\x00\x00\x00\xff\x00\x00\x00\x00\xff\ ... \xff\x00\x00\x00\x00\x00\xff\x00\x00\xff\x00\x00\x00\x00\x00\xff\ ... \xff\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\ ... \xff\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\ ... \xff\x00\x00\x00\x00\x00\xff\x00\x00\xff\x00\x00\x00\x00\x00\xff\ ... \xff\x00\x00\x00\x00\xff\x00\x00\x00\x00\xff\x00\x00\x00\x00\xff\ ... \xff\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\xff\ ... \xff\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\xff\ ... \xff\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\xff\ ... \xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\ ... \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff''') >>> >>> xbm = img.convert("1").tobitmap("fubar") # "xbm" format (X11 bitmap) >>> print(xbm.decode('ascii')) #define fubar_width 16 #define fubar_height 16 static char fubar_bits[] = { 0xff,0xff,0x03,0xc0,0x05,0xa0,0x09,0x90,0x11,0x88,0x21,0x84,0x41,0x82,0x81, 0x81,0x81,0x81,0x41,0x82,0x21,0x84,0x11,0x88,0x09,0x90,0x05,0xa0,0x03,0xc0, 0xff,0xff }; >>> >>> # xbm can be read by XbmImagePlugin >>> dimg = Image.open(BytesIO(xbm)) >>> _TAB = [" ", "O"] >>> _NLT = ["\n", ""] >>> print("".join([ ... (_TAB[v > 0] + _NLT[bool((i + 1) % dimg.width)]) ... for i, v in enumerate(dimg.getdata())])) OOOOOOOOOOOOOOOO OO OO O O O O O O O O O O O O O O O O O O O O O OO O O OO O O O O O O O O O O O O O O O O O O O O O OO OO OOOOOOOOOOOOOOOO tobytes ======= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.tobytes, http://effbot.org/imagingbook/image.htm#tag-Image.Image.tobytes .. note:: Basically, you should regard this method as just for use by plugin authors, or just for debugging, or testing purpose. This method just returns the raw image data from the internal storage. See `save <#save>`_, or `getdata <#getdata>`_, they might be what you want. .. code-block:: pycon >>> from PIL import Image >>> >>> img = Image.frombytes("L", (2, 2), b'\xff\x00\xff\x00') >>> mode = "L" >>> img = img.convert(mode) >>> >>> img.tobytes("hex", mode) b'ff00ff00' >>> img.tobytes("eps", mode) b'ff00ff00' >>> img.tobytes("xbm", mode) b'0x01,0x01\n' >>> >>> img.tobytes("raw", mode) b'\xff\x00\xff\x00' >>> >>> img.tobytes("gif", mode) b'\x07\x00\xff\x01\xf8\x07 ' >>> img.tobytes("jpeg", mode) b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\t\t\x08\n\x0c\x14\r\x0c\x0b\x0b\x0c\x19\x12\x13\x0f\x14\x1d\x1a\x1f\x1e\x1d\x1a\x1c\x1c $.\' ",#\x1c\x1c(7),01444\x1f\'9=82<.342\xff\xc0\x00\x0b\x08\x00\x02\x00\x02\x01\x01\x11\x00\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01}\x01\x02\x03\x00\x04\x11\x05\x12!1A\x06\x13Qa\x07"q\x142\x81\x91\xa1\x08#B\xb1\xc1\x15R\xd1\xf0$3br\x82\t\n\x16\x17\x18\x19\x1a%&\'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x08\x01\x01\x00\x00?\x00\xf1\xff\x00\x1d\xff\x00\xc9C\xf1/\xfd\x85n\xbf\xf4kW\xff\xd9' >>> img.tobytes("pcx", mode) b'\xc1\xff\x00\xc1\xff\x00' >>> img.tobytes("zip", mode) b'x\x9cc\xf8\xcf\xc0\xc4\xc0\x00\x00\x05\x07\x01\x02' tostring ======== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.tostring, http://effbot.org/imagingbook/image.htm#tag-Image.Image.tostring This method that have been marked as deprecated for many releases have been removed at Pillow 3.0.0 (actually is still defined but raise NotImplementedError). Use `tobytes() <#tobytes>`_ instead. (But also note that original PIL has no :code:`tobytes` but has only :code:`tostring`.) transform ========= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.transform, http://effbot.org/imagingbook/image.htm#tag-Image.Image.transform About *resample*, see `Filters `_. transform(size, EXTENT, data) ----------------------------- .. list-table:: * - srcimg16.jpg |srcimg16| .. |im.transform.EXTENT.res1| image:: _static/exams/result/im_transform_EXTENT_01.jpg :width: 40% .. |im.transform.EXTENT.res2| image:: _static/exams/result/im_transform_EXTENT_02.jpg :width: 40% .. list-table:: * - .. literalinclude:: _static/exams/im_transform_EXTENT_01.py - | expand to original size |im.transform.EXTENT.res1| | to cropped size |im.transform.EXTENT.res2| transform(size, AFFINE, data) ----------------------------- .. list-table:: * - srcimg15.jpg |srcimg15| .. |im.transform.AFFINE.res1| image:: _static/exams/result/im_transform_AFFINE__shear1.jpg :width: 40% .. |im.transform.AFFINE.res2| image:: _static/exams/result/im_transform_AFFINE__shear2.jpg :width: 40% .. |im.transform.AFFINE.res3| image:: _static/exams/result/im_transform_AFFINE__rotate.jpg :width: 40% .. list-table:: * - .. literalinclude:: _static/exams/im_transform_AFFINE_01.py - | shear1 |im.transform.AFFINE.res1| | shear2 |im.transform.AFFINE.res2| | rotate |im.transform.AFFINE.res3| transform(size, QUAD, data) --------------------------- .. list-table:: * - srcimg17.jpg |srcimg17| .. |im.transform.QUAD.res1| image:: _static/exams/result/im_transform_QUAD_01.jpg .. list-table:: * - .. literalinclude:: _static/exams/im_transform_QUAD_01.py - |im.transform.QUAD.res1| transform(size, MESH, data) --------------------------- .. list-table:: * - srcimg17.jpg |srcimg17| .. |im.transform.MESH.res1| image:: _static/exams/result/im_transform_MESH_01.jpg .. list-table:: * - .. literalinclude:: _static/exams/im_transform_MESH_01.py - |im.transform.MESH.res1| transform(size, PERSPECTIVE, data) ---------------------------------- Data is a 8-tuple *(a, b, c, d, e, f, g, h)* which contains the coefficients for a perspective transform. .. math:: \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{pmatrix} (a x + b y + c)/(g x + h y + 1) \\ (d x + e y + f)/(g x + h y + 1) \end{pmatrix} But how do we get these coefficients? Don't worry, because above equation can be solved if we know four relationships between :math:`\begin{pmatrix} x' \\ y' \end{pmatrix}` and :math:`\begin{pmatrix} x \\ y \end{pmatrix}`: .. math:: \begin{cases} x_{1} a + y_{1} b + 1c + 0d + 0e + 0f - x_{1} x'_{1} g - x'_{1} y_{1} h = x'_{1} \\ 0a + 0b + 0c + x_{1} d + y_{1} e + 1f - x_{1} y'_{1} g - y_{1} y'_{1} h = y'_{1} \end{cases} \begin{cases} x_{2} a + y_{2} b + 1c + 0d + 0e + 0f - x_{2} x'_{2} g - x'_{2} y_{2} h = x'_{2} \\ 0a + 0b + 0c + x_{2} d + y_{2} e + 1f - x_{2} y'_{2} g - y_{2} y'_{2} h = y'_{2} \end{cases} \begin{cases} x_{3} a + y_{3} b + 1c + 0d + 0e + 0f - x_{3} x'_{3} g - x'_{3} y_{3} h = x'_{3} \\ 0a + 0b + 0c + x_{3} d + y_{3} e + 1f - x_{3} y'_{3} g - y_{3} y'_{3} h = y'_{3} \end{cases} \begin{cases} x_{4} a + y_{4} b + 1c + 0d + 0e + 0f - x_{4} x'_{4} g - x'_{4} y_{4} h = x'_{4} \\ 0a + 0b + 0c + x_{4} d + y_{4} e + 1f - x_{4} y'_{4} g - y_{4} y'_{4} h = y'_{4} \end{cases} That is: .. math:: \begin{pmatrix} x_{1} & y_{1} & 1 & 0 & 0 & 0 & -x_{1} x'_{1} & -x'_{1} y_{1} \\ 0 & 0 & 0 & x_{1} & y_{1} & 1 & -x_{1} y'_{1} & -y_{1} y'_{1} \\ x_{2} & y_{2} & 1 & 0 & 0 & 0 & -x_{2} x'_{2} & -x'_{2} y_{2} \\ 0 & 0 & 0 & x_{2} & y_{2} & 1 & -x_{2} y'_{2} & -y_{2} y'_{2} \\ x_{3} & y_{3} & 1 & 0 & 0 & 0 & -x_{3} x'_{3} & -x'_{3} y_{3} \\ 0 & 0 & 0 & x_{3} & y_{3} & 1 & -x_{3} y'_{3} & -y_{3} y'_{3} \\ x_{4} & y_{4} & 1 & 0 & 0 & 0 & -x_{4} x'_{4} & -x'_{4} y_{4} \\ 0 & 0 & 0 & x_{4} & y_{4} & 1 & -x_{4} y'_{4} & -y_{4} y'_{4} \end{pmatrix} \begin{pmatrix} a \\ b \\ c \\ d \\ e \\ f \\ g \\ h \end{pmatrix} = \begin{pmatrix} x'_{1} \\ y'_{1} \\ x'_{2} \\ y'_{2} \\ x'_{3} \\ y'_{3} \\ x'_{4} \\ y'_{4} \end{pmatrix} .. list-table:: * - srcimg17.jpg |srcimg17| .. |im.transform.PERSPECTIVE.res1| image:: _static/exams/result/im_transform_PERSPECTIVE_01.jpg .. list-table:: * - .. literalinclude:: _static/exams/im_transform_PERSPECTIVE_01.py - |im.transform.PERSPECTIVE.res1| transpose ========= :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.transpose, http://effbot.org/imagingbook/image.htm#tag-Image.Image.transpose .. list-table:: * - srcimg14.jpg |srcimg14| .. literalinclude:: _static/exams/im_transpose_01.py .. |im.transpose.res1| image:: _static/exams/result/im_transpose_FLIP_LEFT_RIGHT.jpg .. |im.transpose.res2| image:: _static/exams/result/im_transpose_FLIP_TOP_BOTTOM.jpg .. |im.transpose.res3| image:: _static/exams/result/im_transpose_ROTATE_90.jpg .. |im.transpose.res4| image:: _static/exams/result/im_transpose_ROTATE_180.jpg .. |im.transpose.res5| image:: _static/exams/result/im_transpose_ROTATE_270.jpg .. |im.transpose.res6| image:: _static/exams/result/im_transpose_TRANSPOSE.jpg .. list-table:: * - FLIP_LEFT_RIGHT |im.transpose.res1| - FLIP_TOP_BOTTOM |im.transpose.res2| - ROTATE_90 |im.transpose.res3| * - ROTATE_180 |im.transpose.res4| - ROTATE_270 |im.transpose.res5| - TRANSPOSE |im.transpose.res6| verify ====== :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.verify, http://effbot.org/imagingbook/image.htm#tag-Image.Image.verify .. code-block:: pycon >>> from io import BytesIO >>> from PIL import Image >>> >>> simg = Image.open("data/srcimg09.png") >>> dimg = BytesIO() >>> simg.save(dimg, "PNG") >>> >>> # make dimg be malformed >>> dimgrawbytes = dimg.getvalue() >>> dimg = BytesIO(dimgrawbytes[:len(dimgrawbytes) // 2]) >>> # open brokened >>> brokenimg = Image.open(dimg) # => success >>> # call verify >>> brokenimg.verify() Traceback (most recent call last): File "c:\Python35\lib\site-packages\PIL\PngImagePlugin.py", line 144, in crc crc2 = i16(self.fp.read(2)), i16(self.fp.read(2)) File "c:\Python35\lib\site-packages\PIL\_binary.py", line 70, in i16be return unpack(">H", c[o:o+2])[0] struct.error: unpack requires a bytes object of length 2 During handling of the above exception, another exception occurred: Traceback (most recent call last): File "", line 1, in File "c:\Python35\lib\site-packages\PIL\PngImagePlugin.py", line 570, in verify self.png.verify() File "c:\Python35\lib\site-packages\PIL\PngImagePlugin.py", line 172, in verify self.crc(cid, ImageFile._safe_read(self.fp, length)) File "c:\Python35\lib\site-packages\PIL\PngImagePlugin.py", line 150, in crc % cid) File "", line None SyntaxError: broken PNG file (incomplete checksum in b'IDAT') .. note:: If you need to load the image after using this method, you must reopen the image file. Attributes ********** :doc: https://pillow.readthedocs.io/en/latest/reference/Image.html#attributes, http://effbot.org/imagingbook/image.htm#attributes .. code-block:: pycon >>> from PIL import Image >>> img1 = Image.open("data/srcimg01.jpg") >>> img1.format, img1.mode, img1.size ('JPEG', 'RGB', (670, 445)) >>> img1.width, img1.height # == img1.size (670, 445) >>> img1.info {'jfif_version': (1, 1), 'jfif': 257, 'jfif_unit': 0, 'jfif_density': (1, 1)} >>> img2 = Image.open("data/srcimg09.png") >>> img2.format, img2.mode, img2.size ('PNG', 'RGBA', (540, 432)) >>> img2.width, img2.height # == img2.size (540, 432) >>> img2.info {} >>> img2.palette >>> img2.convert("P", palette=Image.WEB).palette