aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Pillow/py2
diff options
context:
space:
mode:
authorshumkovnd <shumkovnd@yandex-team.com>2023-11-10 14:39:34 +0300
committershumkovnd <shumkovnd@yandex-team.com>2023-11-10 16:42:24 +0300
commit77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch)
treec51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/Pillow/py2
parentdd6d20cadb65582270ac23f4b3b14ae189704b9d (diff)
downloadydb-77eb2d3fdcec5c978c64e025ced2764c57c00285.tar.gz
KIKIMR-19287: add task_stats_drawing script
Diffstat (limited to 'contrib/python/Pillow/py2')
-rw-r--r--contrib/python/Pillow/py2/CHANGES.rst5421
-rw-r--r--contrib/python/Pillow/py2/LICENSE16
-rw-r--r--contrib/python/Pillow/py2/PIL/BdfFontFile.py114
-rw-r--r--contrib/python/Pillow/py2/PIL/BlpImagePlugin.py420
-rw-r--r--contrib/python/Pillow/py2/PIL/BmpImagePlugin.py381
-rw-r--r--contrib/python/Pillow/py2/PIL/BufrStubImagePlugin.py73
-rw-r--r--contrib/python/Pillow/py2/PIL/ContainerIO.py117
-rw-r--r--contrib/python/Pillow/py2/PIL/CurImagePlugin.py81
-rw-r--r--contrib/python/Pillow/py2/PIL/DcxImagePlugin.py99
-rw-r--r--contrib/python/Pillow/py2/PIL/DdsImagePlugin.py178
-rw-r--r--contrib/python/Pillow/py2/PIL/EpsImagePlugin.py433
-rw-r--r--contrib/python/Pillow/py2/PIL/ExifTags.py314
-rw-r--r--contrib/python/Pillow/py2/PIL/FitsStubImagePlugin.py76
-rw-r--r--contrib/python/Pillow/py2/PIL/FliImagePlugin.py181
-rw-r--r--contrib/python/Pillow/py2/PIL/FontFile.py115
-rw-r--r--contrib/python/Pillow/py2/PIL/FpxImagePlugin.py249
-rw-r--r--contrib/python/Pillow/py2/PIL/FtexImagePlugin.py106
-rw-r--r--contrib/python/Pillow/py2/PIL/GbrImagePlugin.py96
-rw-r--r--contrib/python/Pillow/py2/PIL/GdImageFile.py90
-rw-r--r--contrib/python/Pillow/py2/PIL/GifImagePlugin.py884
-rw-r--r--contrib/python/Pillow/py2/PIL/GimpGradientFile.py139
-rw-r--r--contrib/python/Pillow/py2/PIL/GimpPaletteFile.py58
-rw-r--r--contrib/python/Pillow/py2/PIL/GribStubImagePlugin.py74
-rw-r--r--contrib/python/Pillow/py2/PIL/Hdf5StubImagePlugin.py73
-rw-r--r--contrib/python/Pillow/py2/PIL/IcnsImagePlugin.py377
-rw-r--r--contrib/python/Pillow/py2/PIL/IcoImagePlugin.py327
-rw-r--r--contrib/python/Pillow/py2/PIL/ImImagePlugin.py374
-rw-r--r--contrib/python/Pillow/py2/PIL/Image.py3343
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageChops.py292
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageCms.py991
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageColor.py298
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageDraw.py565
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageDraw2.py107
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageEnhance.py103
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageFile.py685
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageFilter.py538
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageFont.py851
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageGrab.py92
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageMath.py271
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageMode.py64
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageMorph.py247
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageOps.py551
-rw-r--r--contrib/python/Pillow/py2/PIL/ImagePalette.py221
-rw-r--r--contrib/python/Pillow/py2/PIL/ImagePath.py19
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageSequence.py78
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageShow.py224
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageStat.py147
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageTransform.py102
-rw-r--r--contrib/python/Pillow/py2/PIL/ImageWin.py230
-rw-r--r--contrib/python/Pillow/py2/PIL/ImtImagePlugin.py98
-rw-r--r--contrib/python/Pillow/py2/PIL/IptcImagePlugin.py233
-rw-r--r--contrib/python/Pillow/py2/PIL/Jpeg2KImagePlugin.py308
-rw-r--r--contrib/python/Pillow/py2/PIL/JpegImagePlugin.py817
-rw-r--r--contrib/python/Pillow/py2/PIL/JpegPresets.py244
-rw-r--r--contrib/python/Pillow/py2/PIL/McIdasImagePlugin.py79
-rw-r--r--contrib/python/Pillow/py2/PIL/MicImagePlugin.py118
-rw-r--r--contrib/python/Pillow/py2/PIL/MpegImagePlugin.py88
-rw-r--r--contrib/python/Pillow/py2/PIL/MpoImagePlugin.py142
-rw-r--r--contrib/python/Pillow/py2/PIL/MspImagePlugin.py198
-rw-r--r--contrib/python/Pillow/py2/PIL/PSDraw.py238
-rw-r--r--contrib/python/Pillow/py2/PIL/PaletteFile.py55
-rw-r--r--contrib/python/Pillow/py2/PIL/PalmImagePlugin.py230
-rw-r--r--contrib/python/Pillow/py2/PIL/PcdImagePlugin.py69
-rw-r--r--contrib/python/Pillow/py2/PIL/PcfFontFile.py240
-rw-r--r--contrib/python/Pillow/py2/PIL/PcxImagePlugin.py210
-rw-r--r--contrib/python/Pillow/py2/PIL/PdfImagePlugin.py248
-rw-r--r--contrib/python/Pillow/py2/PIL/PdfParser.py1043
-rw-r--r--contrib/python/Pillow/py2/PIL/PixarImagePlugin.py75
-rw-r--r--contrib/python/Pillow/py2/PIL/PngImagePlugin.py958
-rw-r--r--contrib/python/Pillow/py2/PIL/PpmImagePlugin.py168
-rw-r--r--contrib/python/Pillow/py2/PIL/PsdImagePlugin.py319
-rw-r--r--contrib/python/Pillow/py2/PIL/PyAccess.py346
-rw-r--r--contrib/python/Pillow/py2/PIL/SgiImagePlugin.py235
-rw-r--r--contrib/python/Pillow/py2/PIL/SpiderImagePlugin.py326
-rw-r--r--contrib/python/Pillow/py2/PIL/SunImagePlugin.py140
-rw-r--r--contrib/python/Pillow/py2/PIL/TarIO.py73
-rw-r--r--contrib/python/Pillow/py2/PIL/TgaImagePlugin.py251
-rw-r--r--contrib/python/Pillow/py2/PIL/TiffImagePlugin.py1947
-rw-r--r--contrib/python/Pillow/py2/PIL/TiffTags.py499
-rw-r--r--contrib/python/Pillow/py2/PIL/WalImageFile.py129
-rw-r--r--contrib/python/Pillow/py2/PIL/WebPImagePlugin.py360
-rw-r--r--contrib/python/Pillow/py2/PIL/WmfImagePlugin.py173
-rw-r--r--contrib/python/Pillow/py2/PIL/XVThumbImagePlugin.py82
-rw-r--r--contrib/python/Pillow/py2/PIL/XbmImagePlugin.py98
-rw-r--r--contrib/python/Pillow/py2/PIL/XpmImagePlugin.py134
-rw-r--r--contrib/python/Pillow/py2/PIL/__init__.py73
-rw-r--r--contrib/python/Pillow/py2/PIL/__main__.py9
-rw-r--r--contrib/python/Pillow/py2/PIL/_binary.py99
-rw-r--r--contrib/python/Pillow/py2/PIL/_util.py43
-rw-r--r--contrib/python/Pillow/py2/PIL/_version.py2
-rw-r--r--contrib/python/Pillow/py2/PIL/features.py169
-rw-r--r--contrib/python/Pillow/py2/README.rst87
-rw-r--r--contrib/python/Pillow/py2/RELEASING.md105
-rw-r--r--contrib/python/Pillow/py2/_imaging.c3989
-rw-r--r--contrib/python/Pillow/py2/_imagingcms.c1644
-rw-r--r--contrib/python/Pillow/py2/_imagingft.c1317
-rw-r--r--contrib/python/Pillow/py2/_imagingmath.c304
-rw-r--r--contrib/python/Pillow/py2/_imagingmorph.c304
-rw-r--r--contrib/python/Pillow/py2/_webp.c877
-rw-r--r--contrib/python/Pillow/py2/decode.c917
-rw-r--r--contrib/python/Pillow/py2/display.c828
-rw-r--r--contrib/python/Pillow/py2/encode.c1256
-rw-r--r--contrib/python/Pillow/py2/libImaging/Access.c249
-rw-r--r--contrib/python/Pillow/py2/libImaging/AlphaComposite.c87
-rw-r--r--contrib/python/Pillow/py2/libImaging/Bands.c310
-rw-r--r--contrib/python/Pillow/py2/libImaging/BcnDecode.c856
-rw-r--r--contrib/python/Pillow/py2/libImaging/Bit.h30
-rw-r--r--contrib/python/Pillow/py2/libImaging/BitDecode.c138
-rw-r--r--contrib/python/Pillow/py2/libImaging/Blend.c80
-rw-r--r--contrib/python/Pillow/py2/libImaging/BoxBlur.c310
-rw-r--r--contrib/python/Pillow/py2/libImaging/Chops.c148
-rw-r--r--contrib/python/Pillow/py2/libImaging/ColorLUT.c168
-rw-r--r--contrib/python/Pillow/py2/libImaging/Convert.c1737
-rw-r--r--contrib/python/Pillow/py2/libImaging/ConvertYCbCr.c387
-rw-r--r--contrib/python/Pillow/py2/libImaging/Copy.c58
-rw-r--r--contrib/python/Pillow/py2/libImaging/Crop.c61
-rw-r--r--contrib/python/Pillow/py2/libImaging/Dib.c300
-rw-r--r--contrib/python/Pillow/py2/libImaging/Draw.c1187
-rw-r--r--contrib/python/Pillow/py2/libImaging/Effects.c150
-rw-r--r--contrib/python/Pillow/py2/libImaging/EpsEncode.c80
-rw-r--r--contrib/python/Pillow/py2/libImaging/File.c84
-rw-r--r--contrib/python/Pillow/py2/libImaging/Fill.c111
-rw-r--r--contrib/python/Pillow/py2/libImaging/Filter.c357
-rw-r--r--contrib/python/Pillow/py2/libImaging/FliDecode.c216
-rw-r--r--contrib/python/Pillow/py2/libImaging/Geometry.c1069
-rw-r--r--contrib/python/Pillow/py2/libImaging/GetBBox.c320
-rw-r--r--contrib/python/Pillow/py2/libImaging/Gif.h109
-rw-r--r--contrib/python/Pillow/py2/libImaging/GifDecode.c297
-rw-r--r--contrib/python/Pillow/py2/libImaging/GifEncode.c320
-rw-r--r--contrib/python/Pillow/py2/libImaging/HexDecode.c67
-rw-r--r--contrib/python/Pillow/py2/libImaging/Histo.c177
-rw-r--r--contrib/python/Pillow/py2/libImaging/ImDib.h57
-rw-r--r--contrib/python/Pillow/py2/libImaging/ImPlatform.h86
-rw-r--r--contrib/python/Pillow/py2/libImaging/Imaging.h547
-rw-r--r--contrib/python/Pillow/py2/libImaging/ImagingUtils.h47
-rw-r--r--contrib/python/Pillow/py2/libImaging/Jpeg.h116
-rw-r--r--contrib/python/Pillow/py2/libImaging/Jpeg2K.h102
-rw-r--r--contrib/python/Pillow/py2/libImaging/Jpeg2KDecode.c828
-rw-r--r--contrib/python/Pillow/py2/libImaging/Jpeg2KEncode.c630
-rw-r--r--contrib/python/Pillow/py2/libImaging/JpegDecode.c315
-rw-r--r--contrib/python/Pillow/py2/libImaging/JpegEncode.c340
-rw-r--r--contrib/python/Pillow/py2/libImaging/Matrix.c74
-rw-r--r--contrib/python/Pillow/py2/libImaging/ModeFilter.c78
-rw-r--r--contrib/python/Pillow/py2/libImaging/Negative.c42
-rw-r--r--contrib/python/Pillow/py2/libImaging/Offset.c61
-rw-r--r--contrib/python/Pillow/py2/libImaging/Pack.c681
-rw-r--r--contrib/python/Pillow/py2/libImaging/PackDecode.c92
-rw-r--r--contrib/python/Pillow/py2/libImaging/Palette.c318
-rw-r--r--contrib/python/Pillow/py2/libImaging/Paste.c544
-rw-r--r--contrib/python/Pillow/py2/libImaging/PcdDecode.c78
-rw-r--r--contrib/python/Pillow/py2/libImaging/PcxDecode.c92
-rw-r--r--contrib/python/Pillow/py2/libImaging/PcxEncode.c191
-rw-r--r--contrib/python/Pillow/py2/libImaging/Point.c265
-rw-r--r--contrib/python/Pillow/py2/libImaging/Quant.c1695
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantHash.c303
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantHash.h40
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantHeap.c154
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantHeap.h27
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantOctree.c490
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantOctree.h14
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantPngQuant.c110
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantPngQuant.h15
-rw-r--r--contrib/python/Pillow/py2/libImaging/QuantTypes.h32
-rw-r--r--contrib/python/Pillow/py2/libImaging/RankFilter.c113
-rw-r--r--contrib/python/Pillow/py2/libImaging/Raw.h15
-rw-r--r--contrib/python/Pillow/py2/libImaging/RawDecode.c96
-rw-r--r--contrib/python/Pillow/py2/libImaging/RawEncode.c89
-rw-r--r--contrib/python/Pillow/py2/libImaging/Resample.c695
-rw-r--r--contrib/python/Pillow/py2/libImaging/Sgi.h40
-rw-r--r--contrib/python/Pillow/py2/libImaging/SgiRleDecode.c205
-rw-r--r--contrib/python/Pillow/py2/libImaging/Storage.c594
-rw-r--r--contrib/python/Pillow/py2/libImaging/SunRleDecode.c146
-rw-r--r--contrib/python/Pillow/py2/libImaging/TgaRleDecode.c118
-rw-r--r--contrib/python/Pillow/py2/libImaging/TgaRleEncode.c153
-rw-r--r--contrib/python/Pillow/py2/libImaging/TiffDecode.c682
-rw-r--r--contrib/python/Pillow/py2/libImaging/TiffDecode.h64
-rw-r--r--contrib/python/Pillow/py2/libImaging/Unpack.c1533
-rw-r--r--contrib/python/Pillow/py2/libImaging/UnpackYCC.c162
-rw-r--r--contrib/python/Pillow/py2/libImaging/UnsharpMask.c95
-rw-r--r--contrib/python/Pillow/py2/libImaging/XbmDecode.c81
-rw-r--r--contrib/python/Pillow/py2/libImaging/XbmEncode.c106
-rw-r--r--contrib/python/Pillow/py2/libImaging/Zip.h62
-rw-r--r--contrib/python/Pillow/py2/libImaging/ZipDecode.c298
-rw-r--r--contrib/python/Pillow/py2/libImaging/ZipEncode.c375
-rw-r--r--contrib/python/Pillow/py2/libImaging/codec_fd.c79
-rw-r--r--contrib/python/Pillow/py2/libImaging/raqm.h180
-rw-r--r--contrib/python/Pillow/py2/map.c388
-rw-r--r--contrib/python/Pillow/py2/outline.c192
-rw-r--r--contrib/python/Pillow/py2/path.c632
-rw-r--r--contrib/python/Pillow/py2/py3.h56
-rw-r--r--contrib/python/Pillow/py2/ya.make237
191 files changed, 69292 insertions, 0 deletions
diff --git a/contrib/python/Pillow/py2/CHANGES.rst b/contrib/python/Pillow/py2/CHANGES.rst
new file mode 100644
index 0000000000..e85716f804
--- /dev/null
+++ b/contrib/python/Pillow/py2/CHANGES.rst
@@ -0,0 +1,5421 @@
+
+Changelog (Pillow)
+==================
+
+6.2.2 (2020-01-02)
+------------------
+
+- This is the last Pillow release to support Python 2.7 #3642
+
+- Overflow checks for realloc for tiff decoding. CVE TBD
+ [wiredfool, radarhere]
+
+- Catch SGI buffer overrun. CVE TBD
+ [radarhere]
+
+- Catch PCX P mode buffer overrun. CVE TBD
+ [radarhere]
+
+- Catch FLI buffer overrun. CVE TBD
+ [radarhere]
+
+- Raise an error for an invalid number of bands in FPX image. CVE-2019-19911
+ [wiredfool, radarhere]
+
+6.2.1 (2019-10-21)
+------------------
+
+- Add support for Python 3.8 #4141
+ [hugovk]
+
+6.2.0 (2019-10-01)
+------------------
+
+- Catch buffer overruns #4104
+ [radarhere]
+
+- Initialize rows_per_strip when RowsPerStrip tag is missing #4034
+ [cgohlke, radarhere]
+
+- Raise error if TIFF dimension is a string #4103
+ [radarhere]
+
+- Added decompression bomb checks #4102
+ [radarhere]
+
+- Fix ImageGrab.grab DPI scaling on Windows 10 version 1607+ #4000
+ [nulano, radarhere]
+
+- Corrected negative seeks #4101
+ [radarhere]
+
+- Added argument to capture all screens on Windows #3950
+ [nulano, radarhere]
+
+- Updated warning to specify when Image.frombuffer defaults will change #4086
+ [radarhere]
+
+- Changed WindowsViewer format to PNG #4080
+ [radarhere]
+
+- Use TIFF orientation #4063
+ [radarhere]
+
+- Raise the same error if a truncated image is loaded a second time #3965
+ [radarhere]
+
+- Lazily use ImageFileDirectory_v1 values from Exif #4031
+ [radarhere]
+
+- Improved HSV conversion #4004
+ [radarhere]
+
+- Added text stroking #3978
+ [radarhere, hugovk]
+
+- No more deprecated bdist_wininst .exe installers #4029
+ [hugovk]
+
+- Do not allow floodfill to extend into negative coordinates #4017
+ [radarhere]
+
+- Fixed arc drawing bug for a non-whole number of degrees #4014
+ [radarhere]
+
+- Fix bug when merging identical images to GIF with a list of durations #4003
+ [djy0, radarhere]
+
+- Fix bug in TIFF loading of BufferedReader #3998
+ [chadawagner]
+
+- Added fallback for finding ld on MinGW Cygwin #4019
+ [radarhere]
+
+- Remove indirect dependencies from requirements.txt #3976
+ [hugovk]
+
+- Depends: Update libwebp to 1.0.3 #3983, libimagequant to 2.12.5 #3993, freetype to 2.10.1 #3991
+ [radarhere]
+
+- Change overflow check to use PY_SSIZE_T_MAX #3964
+ [radarhere]
+
+- Report reason for pytest skips #3942
+ [hugovk]
+
+6.1.0 (2019-07-01)
+------------------
+
+- Deprecate Image.__del__ #3929
+ [jdufresne]
+
+- Tiff: Add support for JPEG quality #3886
+ [olt]
+
+- Respect the PKG_CONFIG environment variable when building #3928
+ [chewi]
+
+- Use explicit memcpy() to avoid unaligned memory accesses #3225
+ [DerDakon]
+
+- Improve encoding of TIFF tags #3861
+ [olt]
+
+- Update Py_UNICODE to Py_UCS4 #3780
+ [nulano]
+
+- Consider I;16 pixel size when drawing #3899
+ [radarhere]
+
+- Add TIFFTAG_SAMPLEFORMAT to blocklist #3926
+ [cgohlke, radarhere]
+
+- Create GIF deltas from background colour of GIF frames if disposal mode is 2 #3708
+ [sircinnamon, radarhere]
+
+- Added ImageSequence all_frames #3778
+ [radarhere]
+
+- Use unsigned int to store TIFF IFD offsets #3923
+ [cgohlke]
+
+- Include CPPFLAGS when searching for libraries #3819
+ [jefferyto]
+
+- Updated TIFF tile descriptors to match current decoding functionality #3795
+ [dmnisson]
+
+- Added an ``image.entropy()`` method (second revision) #3608
+ [fish2000]
+
+- Pass the correct types to PyArg_ParseTuple #3880
+ [QuLogic]
+
+- Fixed crash when loading non-font bytes #3912
+ [radarhere]
+
+- Fix SPARC memory alignment issues in Pack/Unpack functions #3858
+ [kulikjak]
+
+- Added CMYK;16B and CMYK;16N unpackers #3913
+ [radarhere]
+
+- Fixed bugs in calculating text size #3864
+ [radarhere]
+
+- Add __main__.py to output basic format and support information #3870
+ [jdufresne]
+
+- Added variation font support #3802
+ [radarhere]
+
+- Do not down-convert if image is LA when showing with PNG format #3869
+ [radarhere]
+
+- Improve handling of PSD frames #3759
+ [radarhere]
+
+- Improved ICO and ICNS loading #3897
+ [radarhere]
+
+- Changed Preview application path so that it is no longer static #3896
+ [radarhere]
+
+- Corrected ttb text positioning #3856
+ [radarhere]
+
+- Handle unexpected ICO image sizes #3836
+ [radarhere]
+
+- Fixed bits value for RGB;16N unpackers #3837
+ [kkopachev]
+
+- Travis CI: Add Fedora 30, remove Fedora 28 #3821
+ [hugovk]
+
+- Added reading of CMYK;16L TIFF images #3817
+ [radarhere]
+
+- Fixed dimensions of 1-bit PDFs #3827
+ [radarhere]
+
+- Fixed opening mmap image through Path on Windows #3825
+ [radarhere]
+
+- Fixed ImageDraw arc gaps #3824
+ [radarhere]
+
+- Expand GIF to include frames with extents outside the image size #3822
+ [radarhere]
+
+- Fixed ImageTk getimage #3814
+ [radarhere]
+
+- Fixed bug in decoding large images #3791
+ [radarhere]
+
+- Fixed reading APP13 marker without Photoshop data #3771
+ [radarhere]
+
+- Added option to include layered windows in ImageGrab.grab on Windows #3808
+ [radarhere]
+
+- Detect libimagequant when installed by pacman on MingW #3812
+ [radarhere]
+
+- Fixed raqm layout bug #3787
+ [radarhere]
+
+- Fixed loading font with non-Unicode path on Windows #3785
+ [radarhere]
+
+- Travis CI: Upgrade PyPy from 6.0.0 to 7.1.1 #3783
+ [hugovk, johnthagen]
+
+- Depends: Updated openjpeg to 2.3.1 #3794, raqm to 0.7.0 #3877, libimagequant to 2.12.3 #3889
+ [radarhere]
+
+- Fix numpy bool bug #3790
+ [radarhere]
+
+6.0.0 (2019-04-01)
+------------------
+
+- Python 2.7 support will be removed in Pillow 7.0.0 #3682
+ [hugovk]
+
+- Add EXIF class #3625
+ [radarhere]
+
+- Add ImageOps exif_transpose method #3687
+ [radarhere]
+
+- Added warnings to deprecated CMSProfile attributes #3615
+ [hugovk]
+
+- Documented reading TIFF multiframe images #3720
+ [akuchling]
+
+- Improved speed of opening an MPO file #3658
+ [Glandos]
+
+- Update palette in quantize #3721
+ [radarhere]
+
+- Improvements to TIFF is_animated and n_frames #3714
+ [radarhere]
+
+- Fixed incompatible pointer type warnings #3754
+ [radarhere]
+
+- Improvements to PA and LA conversion and palette operations #3728
+ [radarhere]
+
+- Consistent DPI rounding #3709
+ [radarhere]
+
+- Change size of MPO image to match frame #3588
+ [radarhere]
+
+- Read Photoshop resolution data #3701
+ [radarhere]
+
+- Ensure image is mutable before saving #3724
+ [radarhere]
+
+- Correct remap_palette documentation #3740
+ [radarhere]
+
+- Promote P images to PA in putalpha #3726
+ [radarhere]
+
+- Allow RGB and RGBA values for new P images #3719
+ [radarhere]
+
+- Fixed TIFF bug when seeking backwards and then forwards #3713
+ [radarhere]
+
+- Cache EXIF information #3498
+ [Glandos]
+
+- Added transparency for all PNG greyscale modes #3744
+ [radarhere]
+
+- Fix deprecation warnings in Python 3.8 #3749
+ [radarhere]
+
+- Fixed GIF bug when rewinding to a non-zero frame #3716
+ [radarhere]
+
+- Only close original fp in __del__ and __exit__ if original fp is exclusive #3683
+ [radarhere]
+
+- Fix BytesWarning in Tests/test_numpy.py #3725
+ [jdufresne]
+
+- Add missing MIME types and extensions #3520
+ [pirate486743186]
+
+- Add I;16 PNG save #3566
+ [radarhere]
+
+- Add support for BMP RGBA bitfield compression #3705
+ [radarhere]
+
+- Added ability to set language for text rendering #3693
+ [iwsfutcmd]
+
+- Only close exclusive fp on Image __exit__ #3698
+ [radarhere]
+
+- Changed EPS subprocess stdout from devnull to None #3635
+ [radarhere]
+
+- Add reading old-JPEG compressed TIFFs #3489
+ [kkopachev]
+
+- Add EXIF support for PNG #3674
+ [radarhere]
+
+- Add option to set dither param on quantize #3699
+ [glasnt]
+
+- Add reading of DDS uncompressed RGB data #3673
+ [radarhere]
+
+- Correct length of Tiff BYTE tags #3672
+ [radarhere]
+
+- Add DIB saving and loading through Image open #3691
+ [radarhere]
+
+- Removed deprecated VERSION #3624
+ [hugovk]
+
+- Fix 'BytesWarning: Comparison between bytes and string' in PdfDict #3580
+ [jdufresne]
+
+- Do not resize in Image.thumbnail if already the destination size #3632
+ [radarhere]
+
+- Replace .seek() magic numbers with io.SEEK_* constants #3572
+ [jdufresne]
+
+- Make ContainerIO.isatty() return a bool, not int #3568
+ [jdufresne]
+
+- Add support to all transpose operations for I;16 modes #3563, #3741
+ [radarhere]
+
+- Deprecate support for PyQt4 and PySide #3655
+ [hugovk, radarhere]
+
+- Add TIFF compression codecs: LZMA, Zstd, WebP #3555
+ [cgohlke]
+
+- Fixed pickling of iTXt class with protocol > 1 #3537
+ [radarhere]
+
+- _util.isPath returns True for pathlib.Path objects #3616
+ [wbadart]
+
+- Remove unnecessary unittest.main() boilerplate from test files #3631
+ [jdufresne]
+
+- Exif: Seek to IFD offset #3584
+ [radarhere]
+
+- Deprecate PIL.*ImagePlugin.__version__ attributes #3628
+ [jdufresne]
+
+- Docs: Add note about ImageDraw operations that exceed image bounds #3620
+ [radarhere]
+
+- Allow for unknown PNG chunks after image data #3558
+ [radarhere]
+
+- Changed EPS subprocess stdin from devnull to None #3611
+ [radarhere]
+
+- Fix possible integer overflow #3609
+ [cgohlke]
+
+- Catch BaseException for resource cleanup handlers #3574
+ [jdufresne]
+
+- Improve pytest configuration to allow specific tests as CLI args #3579
+ [jdufresne]
+
+- Drop support for Python 3.4 #3596
+ [hugovk]
+
+- Remove deprecated PIL.OleFileIO #3598
+ [hugovk]
+
+- Remove deprecated ImageOps undocumented functions #3599
+ [hugovk]
+
+- Depends: Update libwebp to 1.0.2 #3602
+ [radarhere]
+
+- Detect MIME types #3525
+ [radarhere]
+
+5.4.1 (2019-01-06)
+------------------
+
+- File closing: Only close __fp if not fp #3540
+ [radarhere]
+
+- Fix build for Termux #3529
+ [pslacerda]
+
+- PNG: Detect MIME types #3525
+ [radarhere]
+
+- PNG: Handle IDAT chunks after image end #3532
+ [radarhere]
+
+5.4.0 (2019-01-01)
+------------------
+
+- Docs: Improved ImageChops documentation #3522
+ [radarhere]
+
+- Allow RGB and RGBA values for P image putpixel #3519
+ [radarhere]
+
+- Add APNG extension to PNG plugin #3501
+ [pirate486743186, radarhere]
+
+- Lookup ld.so.cache instead of hardcoding search paths #3245
+ [pslacerda]
+
+- Added custom string TIFF tags #3513
+ [radarhere]
+
+- Improve setup.py configuration #3395
+ [diorcety]
+
+- Read textual chunks located after IDAT chunks for PNG #3506
+ [radarhere]
+
+- Performance: Don't try to hash value if enum is empty #3503
+ [Glandos]
+
+- Added custom int and float TIFF tags #3350
+ [radarhere]
+
+- Fixes for issues reported by static code analysis #3393
+ [frenzymadness]
+
+- GIF: Wait until mode is normalized to copy im.info into encoderinfo #3187
+ [radarhere]
+
+- Docs: Add page of deprecations and removals #3486
+ [hugovk]
+
+- Travis CI: Upgrade PyPy from 5.8.0 to 6.0 #3488
+ [hugovk]
+
+- Travis CI: Allow lint job to fail #3467
+ [hugovk]
+
+- Resolve __fp when closing and deleting #3261
+ [radarhere]
+
+- Close exclusive fp before discarding #3461
+ [radarhere]
+
+- Updated open files documentation #3490
+ [radarhere]
+
+- Added libjpeg_turbo to check_feature #3493
+ [radarhere]
+
+- Change color table index background to tuple when saving as WebP #3471
+ [radarhere]
+
+- Allow arbitrary number of comment extension subblocks #3479
+ [radarhere]
+
+- Ensure previous FLI frame is loaded before seeking to the next #3478
+ [radarhere]
+
+- ImageShow improvements #3450
+ [radarhere]
+
+- Depends: Update libimagequant to 2.12.2 #3442, libtiff to 4.0.10 #3458, libwebp to 1.0.1 #3468, Tk Tcl to 8.6.9 #3465
+ [radarhere]
+
+- Check quality_layers type #3464
+ [radarhere]
+
+- Add context manager, __del__ and close methods to TarIO #3455
+ [radarhere]
+
+- Test: Do not play sound when running screencapture command #3454
+ [radarhere]
+
+- Close exclusive fp on open exception #3456
+ [radarhere]
+
+- Only close existing fp in WebP if fp is exclusive #3418
+ [radarhere]
+
+- Docs: Re-add the downloads badge #3443
+ [hugovk]
+
+- Added negative index to PixelAccess #3406
+ [Nazime]
+
+- Change tuple background to global color table index when saving as GIF #3385
+ [radarhere]
+
+- Test: Improved ImageGrab tests #3424
+ [radarhere]
+
+- Flake8 fixes #3422, #3440
+ [radarhere, hugovk]
+
+- Only ask for YCbCr->RGB libtiff conversion for jpeg-compressed tiffs #3417
+ [kkopachev]
+
+- Optimise ImageOps.fit by combining resize and crop #3409
+ [homm]
+
+5.3.0 (2018-10-01)
+------------------
+
+- Changed Image size property to be read-only by default #3203
+ [radarhere]
+
+- Add warnings if image file identification fails due to lack of WebP support #3169
+ [radarhere, hugovk]
+
+- Hide the Ghostscript progress dialog popup on Windows #3378
+ [hugovk]
+
+- Adding support to reading tiled and YcbCr jpeg tiffs through libtiff #3227
+ [kkopachev]
+
+- Fixed None as TIFF compression argument #3310
+ [radarhere]
+
+- Changed GIF seek to remove previous info items #3324
+ [radarhere]
+
+- Improved PDF document info #3274
+ [radarhere]
+
+- Add line width parameter to rectangle and ellipse-based shapes #3094
+ [hugovk, radarhere]
+
+- Fixed decompression bomb check in _crop #3313
+ [dinkolubina, hugovk]
+
+- Added support to ImageDraw.floodfill for non-RGB colors #3377
+ [radarhere]
+
+- Tests: Avoid catching unexpected exceptions in tests #2203
+ [jdufresne]
+
+- Use TextIOWrapper.detach() instead of NoCloseStream #2214
+ [jdufresne]
+
+- Added transparency to matrix conversion #3205
+ [radarhere]
+
+- Added ImageOps pad method #3364
+ [radarhere]
+
+- Give correct extrema for I;16 format images #3359
+ [bz2]
+
+- Added PySide2 #3279
+ [radarhere]
+
+- Corrected TIFF tags #3369
+ [radarhere]
+
+- CI: Install CFFI and pycparser without any PYTHONOPTIMIZE #3374
+ [hugovk]
+
+- Read/Save RGB webp as RGB (instead of RGBX) #3298
+ [kkopachev]
+
+- ImageDraw: Add line joints #3250
+ [radarhere]
+
+- Improved performance of ImageDraw floodfill method #3294
+ [yo1995]
+
+- Fix builds with --parallel #3272
+ [hsoft]
+
+- Add more raw Tiff modes (RGBaX, RGBaXX, RGBAX, RGBAXX) #3335
+ [homm]
+
+- Close existing WebP fp before setting new fp #3341
+ [radarhere]
+
+- Add orientation, compression and id_section as TGA save keyword arguments #3327
+ [radarhere]
+
+- Convert int values of RATIONAL TIFF tags to floats #3338
+ [radarhere, wiredfool]
+
+- Fix code for PYTHONOPTIMIZE #3233
+ [hugovk]
+
+- Changed ImageFilter.Kernel to subclass ImageFilter.BuiltinFilter, instead of the other way around #3273
+ [radarhere]
+
+- Remove unused draw.draw_line, draw.draw_point and font.getabc methods #3232
+ [hugovk]
+
+- Tests: Added ImageFilter tests #3295
+ [radarhere]
+
+- Tests: Added ImageChops tests #3230
+ [hugovk, radarhere]
+
+- AppVeyor: Download lib if not present in pillow-depends #3316
+ [radarhere]
+
+- Travis CI: Add Python 3.7 and Xenial #3234
+ [hugovk]
+
+- Docs: Added documentation for NumPy conversion #3301
+ [radarhere]
+
+- Depends: Update libimagequant to 2.12.1 #3281
+ [radarhere]
+
+- Add three-color support to ImageOps.colorize #3242
+ [tsennott]
+
+- 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, #3380
+ [radarhere]
+
+- Avoid deprecated 'U' mode when opening files #2187
+ [jdufresne]
+
+5.2.0 (2018-07-01)
+------------------
+
+- Fixed saving a multiframe image as a single frame PDF #3137
+ [radarhere]
+
+- If a Qt version is already imported, attempt to use it first #3143
+ [radarhere]
+
+- Fix transform fill color for alpha images #3147
+ [fozcode]
+
+- TGA: Add support for writing RLE data #3186
+ [danpla]
+
+- TGA: Read and write LA data #3178
+ [danpla]
+
+- QuantOctree.c: Remove erroneous attempt to average over an empty range #3196
+ [tkoeppe]
+
+- Changed ICNS format tests to pass on OS X 10.11 #3202
+ [radarhere]
+
+- Fixed bug in ImageDraw.multiline_textsize() #3114
+ [tianyu139]
+
+- Added getsize_multiline support for PIL.ImageFont #3113
+ [tianyu139]
+
+- Added ImageFile get_format_mimetype method #3190
+ [radarhere]
+
+- Changed mmap file pointer to use context manager #3216
+ [radarhere]
+
+- Changed ellipse point calculations to be more evenly distributed #3142
+ [radarhere]
+
+- Only extract first Exif segment #2946
+ [hugovk]
+
+- Tests: Test ImageDraw2, WalImageFile #3135, #2989
+ [hugovk]
+
+- Remove unnecessary '#if 0' code #3075
+ [hugovk]
+
+- Tests: Added GD tests #1817
+ [radarhere]
+
+- Fix collections ABCs DeprecationWarning in Python 3.7 #3123
+ [hugovk]
+
+- unpack_from is faster than unpack of slice #3201
+ [landfillbaby]
+
+- Docs: Add coordinate system links and file handling links in documentation #3204, #3214
+ [radarhere]
+
+- Tests: TestFilePng: Fix test_save_l_transparency() #3182
+ [danpla]
+
+- Docs: Correct argument name #3171
+ [radarhere]
+
+- Docs: Update CMake download URL #3166
+ [radarhere]
+
+- Docs: Improve Image.transform documentation #3164
+ [radarhere]
+
+- Fix transform fillcolor argument when image mode is RGBA or LA #3163
+ [radarhere]
+
+- Tests: More specific Exception testing #3158
+ [radarhere]
+
+- Add getrgb HSB/HSV color strings #3148
+ [radarhere]
+
+- Allow float values in getrgb HSL color string #3146
+ [radarhere]
+
+- AppVeyor: Upgrade to Python 2.7.15 and 3.4.4 #3140
+ [radarhere]
+
+- AppVeyor: Upgrade to PyPy 6.0.0 #3133
+ [hugovk]
+
+- Deprecate PILLOW_VERSION and VERSION #3090
+ [hugovk]
+
+- Support Python 3.7 #3076
+ [hugovk]
+
+- Depends: Update freetype to 2.9.1, libjpeg to 9c, libwebp to 1.0.0 #3121, #3136, #3108
+ [radarhere]
+
+- Build macOS wheels with Xcode 6.4, supporting older macOS versions #3068
+ [wiredfool]
+
+- Fix _i2f compilation on some GCC versions #3067
+ [homm]
+
+- Changed encoderinfo to have priority over info when saving GIF images #3086
+ [radarhere]
+
+- Rename PIL.version to PIL._version and remove it from module #3083
+ [homm]
+
+- Enable background colour parameter on rotate #3057
+ [storesource]
+
+- Remove unnecessary ``#if 1`` directive #3072
+ [jdufresne]
+
+- Remove unused Python class, Path #3070
+ [jdufresne]
+
+- Fix dereferencing type-punned pointer will break strict-aliasing #3069
+ [jdufresne]
+
+5.1.0 (2018-04-02)
+------------------
+
+- Close fp before return in ImagingSavePPM #3061
+ [kathryndavies]
+
+- Added documentation for ICNS append_images #3051
+ [radarhere]
+
+- Docs: Move intro text below its header #3021
+ [hugovk]
+
+- CI: Rename appveyor.yml as .appveyor.yml #2978
+ [hugovk]
+
+- Fix TypeError for JPEG2000 parser feed #3042
+ [hugovk]
+
+- Certain corrupted jpegs can result in no data read #3023
+ [kkopachev]
+
+- Add support for BLP file format #3007
+ [jleclanche]
+
+- Simplify version checks #2998
+ [hugovk]
+
+- Fix "invalid escape sequence" warning on Python 3.6+ #2996
+ [timgraham]
+
+- Allow append_images to set .icns scaled images #3005
+ [radarhere]
+
+- Support appending to existing PDFs #2965
+ [vashek]
+
+- Fix and improve efficient saving of ICNS on macOS #3004
+ [radarhere]
+
+- Build: Enable pip cache in AppVeyor build #3009
+ [thijstriemstra]
+
+- Trim trailing whitespace #2985
+ [Metallicow]
+
+- Docs: Correct reference to Image.new method #3000
+ [radarhere]
+
+- Rearrange ImageFilter classes into alphabetical order #2990
+ [radarhere]
+
+- Test: Remove duplicate line #2983
+ [radarhere]
+
+- Build: Update AppVeyor PyPy version #3003
+ [radarhere]
+
+- Tiff: Open 8 bit Tiffs with 5 or 6 channels, discarding extra channels #2938
+ [homm]
+
+- Readme: Added Twitter badge #2930
+ [hugovk]
+
+- Removed __main__ code from ImageCms #2942
+ [radarhere]
+
+- Test: Changed assert statements to unittest calls #2961
+ [radarhere]
+
+- Depends: Update libimagequant to 2.11.10, raqm to 0.5.0, freetype to 2.9 #3036, #3017, #2957
+ [radarhere]
+
+- Remove _imaging.crc32 in favor of builtin Python crc32 implementation #2935
+ [wiredfool]
+
+- Move Tk directory to src directory #2928
+ [hugovk]
+
+- Enable pip cache in Travis CI #2933
+ [jdufresne]
+
+- Remove unused and duplicate imports #2927
+ [radarhere]
+
+- Docs: Changed documentation references to 2.x to 2.7 #2921
+ [radarhere]
+
+- Fix memory leak when opening webp files #2974
+ [wiredfool]
+
+- Setup: Fix "TypeError: 'NoneType' object is not iterable" for PPC and CRUX #2951
+ [hugovk]
+
+- Setup: Add libdirs for ppc64le and armv7l #2968
+ [nehaljwani]
+
+5.0.0 (2018-01-01)
+------------------
+
+- Docs: Added docstrings from documentation #2914
+ [radarhere]
+
+- Test: Switch from nose to pytest #2815
+ [hugovk]
+
+- Rework Source directory layout, preventing accidental import of PIL. #2911
+ [wiredfool]
+
+- Dynamically link libraqm #2753
+ [wiredfool]
+
+- Removed scripts directory #2901
+ [wiredfool]
+
+- TIFF: Run all compressed tiffs through libtiff decoder #2899
+ [wiredfool]
+
+- GIF: Add disposal option when saving GIFs #2902
+ [linnil1, wiredfool]
+
+- EPS: Allow for an empty line in EPS header data #2903
+ [radarhere]
+
+- PNG: Add support for sRGB and cHRM chunks, permit sRGB when no iCCP chunk present #2898
+ [wiredfool]
+
+- Dependencies: Update Tk Tcl to 8.6.8 #2905
+ [radarhere]
+
+- Decompression bomb error now raised for images 2x larger than a decompression bomb warning #2583
+ [wiredfool]
+
+- Test: avoid random failure in test_effect_noise #2894
+ [hugovk]
+
+- Increased epsilon for test_file_eps.py:test_showpage due to Arch update. #2896
+ [wiredfool]
+
+- Removed check parameter from _save in BmpImagePlugin, PngImagePlugin, ImImagePlugin, PalmImagePlugin, and PcxImagePlugin. #2873
+ [radarhere]
+
+- Make PngImagePlugin.add_text() zip argument type bool #2890
+ [jdufresne]
+
+- Depends: Updated libwebp to 0.6.1 #2880
+ [radarhere]
+
+- Remove unnecessary bool() calls in Image.registered_extensions and skipKnownBadTests #2891
+ [jdufresne]
+
+- Fix count of BITSPERSAMPLE items in broken TIFF files #2883
+ [homm]
+
+- Fillcolor parameter for Image.Transform #2852
+ [wiredfool]
+
+- Test: Display differences for test failures #2862
+ [wiredfool]
+
+- Added executable flag to file with shebang line #2884
+ [radarhere]
+
+- Setup: Specify compatible Python versions for pip #2877
+ [hugovk]
+
+- Dependencies: Updated libimagequant to 2.11.4 #2878
+ [radarhere]
+
+- Setup: Warn if trying to install for Py3.7 on Windows #2855
+ [hugovk]
+
+- Doc: Fonts can be loaded from a file-like object, not just filename #2861
+ [robin-norwood]
+
+- Add eog support for Ubuntu Image Viewer #2864
+ [NafisFaysal]
+
+- Test: Test on 3.7-dev on Travis CI #2870
+ [hugovk]
+
+- Dependencies: Update libtiff to 4.0.9 #2871
+ [radarhere]
+
+- Setup: Replace deprecated platform.dist with file existence check #2869
+ [wiredfool]
+
+- Build: Fix setup.py on Debian #2853
+ [wiredfool]
+
+- Docs: Correct error in ImageDraw documentation #2858
+ [meribold]
+
+- Test: Drop Ubuntu Precise, Fedora 24, Fedora 25, add Fedora 27, Centos 7, Amazon v2 CI Support #2854, #2843, #2895, #2897
+ [wiredfool]
+
+- Dependencies: Updated libimagequant to 2.11.3 #2849
+ [radarhere]
+
+- Test: Fix test_image.py to use tempfile #2841
+ [radarhere]
+
+- Replace PIL.OleFileIO deprecation warning with descriptive ImportError #2833
+ [hugovk]
+
+- WebP: Add support for animated WebP files #2761
+ [jd20]
+
+- PDF: Set encoderinfo for images when saving multi-page PDF. Fixes #2804. #2805
+ [ixio]
+
+- Allow the olefile dependency to be optional #2789
+ [jdufresne]
+
+- GIF: Permit LZW code lengths up to 12 bits in GIF decode #2813
+ [wiredfool]
+
+- Fix unterminated string and unchecked exception in _font_text_asBytes. #2825
+ [wiredfool]
+
+- PPM: Use fixed list of whitespace, rather relying on locale, fixes #272. #2831
+ [markmiscavage]
+
+- Added support for generators when using append_images #2829, #2835
+ [radarhere]
+
+- Doc: Correct PixelAccess.rst #2824
+ [hasahmed]
+
+- Depends: Update raqm to 0.3.0 #2822
+ [radarhere]
+
+- Docs: Link to maintained version of aggdraw #2809
+ [hugovk]
+
+- Include license file in the generated wheel packages #2801
+ [jdufresne]
+
+- Depends: Update openjpeg to 2.3.0 #2791
+ [radarhere]
+
+- Add option to Makefile to build and install with C coverage #2781
+ [hugovk]
+
+- Add context manager support to ImageFile.Parser and PngImagePlugin.ChunkStream #2793
+ [radarhere]
+
+- ImageDraw.textsize: fix zero length error #2788
+ [wiredfool, hugovk]
+
+4.3.0 (2017-10-02)
+------------------
+
+- Fix warning on pointer cast in isblock #2775, #2778
+ [cgohlke]
+
+- Doc: Added macOS High Sierra tested Pillow version #2777
+ [radarhere]
+
+- Use correct Windows handle type on 64 bit in imagingcms #2774
+ [cgohlke]
+
+- 64 Bit Windows fix for block storage #2773
+ [cgohlke]
+
+- Fix "expression result unused" warning #2764
+ [radarhere]
+
+- Add 16bit Read/Write and RLE read support to SgiImageFile #2769
+ [jbltx, wiredfool]
+
+- Block & array hybrid storage #2738
+ [homm]
+
+- Common seek frame position check #1849
+ [radarhere]
+
+- Doc: Add note about aspect ratio to Image thumbnail script #2281
+ [wilsonge]
+
+- Fix ValueError: invalid version number '1.0.0rc1' in scipy release candidate #2771
+ [cgohlke]
+
+- Unfreeze requirements.txt #2766
+ [hugovk]
+
+- Test: ResourceWarning tests #2756
+ [hugovk]
+
+- Use n_frames to determine is_animated if possible #2315
+ [radarhere]
+
+- Doc: Corrected parameters in documentation #2768
+ [radarhere]
+
+- Avoid unnecessary Image operations #1891
+ [radarhere]
+
+- Added register_extensions method #1860
+ [radarhere]
+
+- Fix TIFF support for I;16S, I;16BS, and I;32BS rawmodes #2748
+ [wiredfool]
+
+- Fixed doc syntax in ImageDraw #2752
+ [radarhere]
+
+- Fixed support for building on Windows/msys2. Added Appveyor CI coverage for python3 on msys2 #2746
+ [wiredfool]
+
+- Fix ValueError in Exif/Tiff IFD #2719
+ [wiredfool]
+
+- Use pathlib2 for Path objects on Python < 3.4 #2291
+ [asergi]
+
+- Export only required properties in unsafe_ptrs #2740
+ [homm]
+
+- Alpha composite fixes #2709
+ [homm]
+
+- Faster Transpose operations, added 'Transverse' option #2730
+ [homm]
+
+- Deprecate ImageOps undocumented functions gaussian_blur, gblur, unsharp_mask, usm and box_blur in favor of ImageFilter implementations #2735
+ [homm]
+
+- Dependencies: Updated freetype to 2.8.1 #2741
+ [radarhere]
+
+- Bug: Player skipped first image #2742
+ [radarhere]
+
+- Faster filter operations for Kernel, Gaussian, and Unsharp Mask filters #2679
+ [homm]
+
+- EPS: Add showpage to force rendering of some EPS images #2636
+ [kaplun]
+
+- DOC: Fix type of palette parameter in Image.quantize. #2703
+ [kkopachev]
+
+- DOC: Fix Ico docs to match code #2712
+ [hugovk]
+
+- Added file pointer save to SpiderImagePlugin #2647
+ [radarhere]
+
+- Add targa version 2 footer #2713
+ [jhultgre]
+
+- Removed redundant lines #2714
+ [radarhere]
+
+- Travis CI: Use default pypy/pypy3 #2721
+ [hugovk]
+
+- Fix for SystemError when rendering an empty string, added in 4.2.0 #2706
+ [wiredfool]
+
+- Fix for memory leaks in font handling added in 4.2.0 #2634
+ [wiredfool]
+
+- Tests: cleanup, more tests. Fixed WMF save handler #2689
+ [radarhere]
+
+- Removed debugging interface for Image.core.grabclipboard #2708
+ [radarhere]
+
+- Doc syntax fix #2710
+ [radarhere]
+
+- Faster packing and unpacking for RGB, LA, and related storage modes #2693
+ [homm]
+
+- Use RGBX rawmode for RGB JPEG images where possible #1989
+ [homm]
+
+- Remove palettes from non-palette modes in _new #2704
+ [wiredfool]
+
+- Delete transparency info when convert'ing RGB/L to RGBA #2633
+ [olt]
+
+- Code tweaks to ease type annotations #2687
+ [neiljp]
+
+- Fixed incorrect use of 's#' to byteslike object #2691
+ [wiredfool]
+
+- Fix JPEG subsampling labels for subsampling=2 #2698
+ [homm]
+
+- Region of interest (box) for resampling #2254
+ [homm]
+
+- Basic support for Termux (android) in setup.py #2684
+ [wiredfool]
+
+- Bug: Fix Image.fromarray for numpy.bool type. #2683
+ [wiredfool]
+
+- CI: Add Fedora 24 and 26 to Docker tests
+ [wiredfool]
+
+- JPEG: Fix ZeroDivisionError when EXIF contains invalid DPI (0/0). #2667
+ [vytisb]
+
+- Depends: Updated openjpeg to 2.2.0 #2669
+ [radarhere]
+
+- Depends: Updated Tk Tcl to 8.6.7 #2668
+ [radarhere]
+
+- Depends: Updated libimagequant to 2.10.2 #2660
+ [radarhere]
+
+- Test: Added test for ImImagePlugin tell() #2675
+ [radarhere]
+
+- Test: Additional tests for SGIImagePlugin #2659
+ [radarhere]
+
+- New Image.getchannel method #2661
+ [homm]
+
+- Remove unused im.copy2 and core.copy methods #2657
+ [homm]
+
+- Fast Image.merge() #2677
+ [homm]
+
+- Fast Image.split() #2676
+ [homm]
+
+- Fast image allocation #2655
+ [homm]
+
+- Storage cleanup #2654
+ [homm]
+
+- FLI: Use frame count from FLI header #2674
+ [radarhere]
+
+- Test: Test animated FLI file #2650
+ [hugovk]
+
+- Bug: Fixed uninitialized memory in bc5 decoding #2648
+ [ifeherva]
+
+- Moved SgiImagePlugin save error to before the start of write operations #2646
+ [radarhere]
+
+- Move createfontdatachunk.py so isn't installed globally #2645
+ [hugovk]
+
+- Bug: Fix unexpected keyword argument 'align' #2641
+ [hugovk]
+
+- Add newlines to error message for clarity #2640
+ [hugovk]
+
+- Docs: Updated redirected URL #2637
+ [radarhere]
+
+- Bug: Fix JPEG DPI when EXIF is invalid #2632
+ [wiredfool]
+
+- Bug: Fix for font getsize on empty string #2624
+ [radarhere]
+
+- Docs: Improved ImageDraw documentation #2626
+ [radarhere]
+
+- Docs: Corrected alpha_composite args documentation #2627
+ [radarhere]
+
+- Docs: added the description of the filename attribute to images.rst #2621
+ [dasdachs]
+
+- Dependencies: Updated libimagequant to 2.10.1 #2616
+ [radarhere]
+
+- PDF: Renamed parameter to not shadow built-in dict #2612
+ [kijeong]
+
+4.2.1 (2017-07-06)
+------------------
+
+- CI: Fix version specification and test on CI for PyPy/Windows #2608
+ [wiredfool]
+
+4.2.0 (2017-07-01)
+------------------
+
+- Doc: Clarified Image.save:append_images documentation #2604
+ [radarhere]
+
+- CI: Amazon Linux and Centos6 docker images added to Travis CI #2585
+ [wiredfool]
+
+- Image.alpha_composite added #2595
+ [wiredfool]
+
+- Complex Text Support #2576
+ [ShamsaHamed, Fahad-Alsaidi, wiredfool]
+
+- Added threshold parameter to ImageDraw.floodfill #2599
+ [nediamond]
+
+- Added dBATCH parameter to ghostscript command #2588
+ [radarhere]
+
+- JPEG: Adjust buffer size when icc_profile > MAXBLOCK #2596
+ [Darou]
+
+- Specify Pillow Version in one place #2517
+ [wiredfool]
+
+- CI: Change the owner of the TRAVIS_BUILD_DIR, fixing broken docker runs #2587
+ [wiredfool]
+
+- Fix truncated PNG loading for some images, Fix memory leak on truncated PNG images. #2541, #2598
+ [homm]
+
+- Add decompression bomb check to Image.crop #2410
+ [wiredfool]
+
+- ImageFile: Ensure that the ``err_code`` variable is initialized in case of exception. #2363
+ [alexkiro]
+
+- Tiff: Support append_images for saving multipage TIFFs #2406
+ [blochl]
+
+- Doc: Clarify that draft is only implemented for JPEG and PCD #2409
+ [wiredfool]
+
+- Test: MicImagePlugin #2447
+ [hugovk]
+
+- Use round() instead of floor() to eliminate zero coefficients in resample #2558
+ [homm]
+
+- Remove deprecated code #2549
+ [hugovk]
+
+- Added append_images to PDF saving #2526
+ [radarhere]
+
+- Remove unused function core image function new_array #2548
+ [hugovk]
+
+- Remove unnecessary calls to dict.keys() #2551
+ [jdufresne]
+
+- Add more ImageDraw.py tests and remove unused Draw.c code #2533
+ [hugovk]
+
+- Test: More tests for ImageMorph #2554
+ [hugovk]
+
+- Test: McIDAS area file #2552
+ [radarhere]
+
+- Update Feature Detection #2520
+ [wiredfool]
+
+- CI: Update pypy on Travis CI #2573
+ [hugovk]
+
+- ImageMorph: Fix wrong expected size of MRLs read from disk #2561
+ [dov]
+
+- Docs: Update install docs for FreeBSD #2546
+ [wiredfool]
+
+- Build: Ignore OpenJpeg 1.5 on FreeBSD #2544
+ [melvyn-sopacua]
+
+- Remove 'not yet implemented' methods from PIL 1.1.4 #2538
+ [hugovk]
+
+- Dependencies: Update FreeType to 2.8, LibTIFF to 4.0.8 and libimagequant to 2.9.1 #2535 #2537 #2540
+ [radarhere]
+
+- Raise TypeError and not also UnboundLocalError in ImageFile.Parser() #2525
+ [joshblum]
+
+- Test: Use Codecov for coverage #2528
+ [hugovk]
+
+- Use PNG for Image.show() #2527
+ [HinTak, wiredfool]
+
+- Remove WITH_DEBUG compilation flag #2522
+ [wiredfool]
+
+- Fix return value on parameter parse error in _webp.c #2521
+ [adw1n]
+
+- Set executable flag on scripts with shebang line #2295
+ [radarhere]
+
+- Flake8 #2460
+ [radarhere]
+
+- Doc: Release Process Changes #2516
+ [wiredfool]
+
+- CI: Added region for s3 deployment on appveyor #2515
+ [wiredfool]
+
+- Doc: Updated references to point to existing files #2507
+ [radarhere]
+
+- Return copy on Image crop if crop dimensions match the image #2471
+ [radarhere]
+
+- Test: Optimize CI speed #2464, #2466
+ [hugovk]
+
+4.1.1 (2017-04-28)
+------------------
+
+- Undef PySlice_GetIndicesEx, see https://bugs.python.org/issue29943 #2493
+ [cgohlke]
+
+- Fix for file with DPI in EXIF but not metadata, and XResolution is an int rather than tuple #2484
+ [hugovk]
+
+- Docs: Removed broken download counter badge #2487
+ [hugovk]
+
+- Docs: Fixed rst syntax error #2477
+ [thebjorn]
+
+4.1.0 (2017-04-03)
+------------------
+
+- Close files after loading if possible #2330
+ [homm, wiredfool]
+
+- Fix Image Access to be reloadable when embedding the Python interpreter #2296
+ [wiredfool, cgohlke]
+
+- Fetch DPI from EXIF if not specified in JPEG header #2449, #2472
+ [hugovk]
+
+- Removed winbuild checksum verification #2468
+ [radarhere]
+
+- Git: Set ContainerIO test file as binary #2469
+ [cgohlke]
+
+- Remove superfluous import of FixTk #2455
+ [cgohlke)
+
+- Fix import of tkinter/Tkinter #2456
+ [cgohlke)
+
+- Pure Python Decoders, including Python decoder to fix for MSP images #1938
+ [wiredfool, hugovk]
+
+- Reorganized GifImagePlugin, fixes #2314. #2374
+ [radarhere, wiredfool]
+
+- Doc: Reordered operating systems in Compatibility Matrix #2436
+ [radarhere]
+
+- Test: Additional tests for BufrStub, Eps, Container, GribStub, IPTC, Wmf, XVThumb, ImageDraw, ImageMorph, ImageShow #2425
+ [radarhere]
+
+- Health fixes #2437
+ [radarhere]
+
+- Test: Correctness tests ContainerIO, XVThumbImagePlugin, BufrStubImagePlugin, GribStubImagePlugin, FitsStubImagePlugin, Hdf5StubImagePlugin, PixarImageFile, PsdImageFile #2443, #2442, #2441, #2440, #2431, #2430, #2428, #2427
+ [hugovk]
+
+- Remove unused imports #1822
+ [radarhere]
+
+- Replaced KeyError catch with dictionary get method #2424
+ [radarhere]
+
+- Test: Removed unrunnable code in test_image_toqimage #2415
+ [hugovk]
+
+- Removed use of spaces in TIFF kwargs names, deprecated in 2.7 #1390
+ [radarhere]
+
+- Removed deprecated ImageDraw setink, setfill, setfont methods #2220
+ [jdufresne]
+
+- Send unwanted subprocess output to /dev/null #2253
+ [jdufresne]
+
+- Fix division by zero when creating 0x0 image from numpy array #2419
+ [hugovk]
+
+- Test: Added matrix convert tests #2381
+ [hugovk]
+
+- Replaced broken URL to partners.adobe.com #2413
+ [radarhere]
+
+- Removed unused private functions in setup.py and build_dep.py #2414
+ [radarhere]
+
+- Test: Fixed Qt tests for QT5 and saving 1 bit PNG #2394
+ [wiredfool]
+
+- Test: docker builds for Arch and Debian Stretch #2394
+ [wiredfool]
+
+- Updated libwebp to 0.6.0 on appveyor #2395
+ [radarhere]
+
+- More explicit error message when saving to a file with invalid extension #2399
+ [ces42]
+
+- Docs: Update some http urls to https #2403
+ [hugovk]
+
+- Preserve aux/alpha channels when performing Imagecms transforms #2355
+ [gunjambi]
+
+- Test linear and radial gradient effects #2382
+ [hugovk]
+
+- Test ImageDraw.Outline and and ImageDraw.Shape #2389
+ [hugovk]
+
+- Added PySide to ImageQt documentation #2392
+ [radarhere]
+
+- BUG: Empty image mode no longer causes a crash #2380
+ [evalapply]
+
+- Exclude .travis and contents from manifest #2386
+ [radarhere]
+
+- Remove 'MIT-like' from license #2145
+ [wiredfool]
+
+- Tests: Add tests for several Image operations #2379
+ [radarhere]
+
+- PNG: Moved iCCP chunk before PLTE chunk when saving as PNG, restricted chunks known value/ordering #2347
+ [radarhere]
+
+- Default to inch-interpretation for missing ResolutionUnit in TiffImagePlugin #2365
+ [lambdafu]
+
+- Bug: Fixed segfault when using ImagingTk on pypy Issue #2376, #2359.
+ [wiredfool]
+
+- Bug: Fixed Integer overflow using ImagingTk on 32 bit platforms #2359
+ [wiredfool, QuLogic]
+
+- Tests: Added docker images for testing alternate platforms. See also https://github.com/python-pillow/docker-images. #2368
+ [wiredfool]
+
+- Removed PIL 1.0 era TK readme that concerns Windows 95/NT #2360
+ [wiredfool]
+
+- Prevent ``nose -v`` printing docstrings #2369
+ [hugovk]
+
+- Replaced absolute PIL imports with relative imports #2349
+ [radarhere]
+
+- Added context managers for file handling #2307
+ [radarhere]
+
+- Expose registered file extensions in Image #2343
+ [iggomez, radarhere]
+
+- Make mode descriptor cache initialization thread-safe. #2351
+ [gunjambi]
+
+- Updated Windows test dependencies: Freetype 2.7.1, zlib 1.2.11 #2331, #2332, #2357
+ [radarhere]
+
+- Followed upstream pngquant packaging reorg to libimagquant #2354
+ [radarhere]
+
+- Fix invalid string escapes #2352
+ [hugovk]
+
+- Add test for crop operation with no argument #2333
+ [radarhere]
+
+4.0.0 (2017-01-01)
+------------------
+
+- Refactor out postprocessing hack to load_end in PcdImageFile
+ [wiredfool]
+
+- Add center and translate option to Image.rotate. #2328
+ [lambdafu]
+
+- Test: Relax WMF test condition, fixes #2323. #2327
+ [wiredfool]
+
+- Allow 0 size images, Fixes #2259, Reverts to pre-3.4 behavior. #2262
+ [wiredfool]
+
+- SGI: Save uncompressed SGI/BW/RGB/RGBA files #2325
+ [jbltx]
+
+- Depends: Updated pngquant to 2.8.2 #2319
+ [radarhere]
+
+- Test: Added correctness tests for opening SGI images #2324
+ [wiredfool]
+
+- Allow passing a list or tuple of individual frame durations when saving a GIF #2298
+ [Xdynix]
+
+- Unified different GIF optimize conditions #2196
+ [radarhere]
+
+- Build: Refactor dependency installation #2305
+ [hugovk]
+
+- Test: Add python 3.6 to travis, tox #2304
+ [hugovk]
+
+- Test: Fix coveralls coverage for Python+C #2300
+ [hugovk]
+
+- Remove executable bit and shebang from OleFileIO.py #2308
+ [jwilk, radarhere]
+
+- PyPy: Buffer interface workaround #2294
+ [wiredfool]
+
+- Test: Switch to Ubuntu Trusty 14.04 on Travis CI #2294
+
+- Remove vendored version of olefile Python package in favor of upstream #2199
+ [jdufresne]
+
+- Updated comments to use print as a function #2234
+ [radarhere]
+
+- Set executable flag on selftest.py, setup.py and added shebang line #2282, #2277
+ [radarhere, homm]
+
+- Test: Increase epsilon for FreeType 2.7 as rendering is slightly different. #2286
+ [hugovk]
+
+- Test: Faster assert_image_similar #2279
+ [homm]
+
+- Removed deprecated internal "stretch" method #2276
+ [homm]
+
+- Removed the handles_eof flag in decode.c #2223
+ [wiredfool]
+
+- Tiff: Fix for writing Tiff to BytesIO using libtiff #2263
+ [wiredfool]
+
+- Doc: Design docs #2269
+ [wiredfool]
+
+- Test: Move tests requiring libtiff to test_file_libtiff #2273
+ [wiredfool]
+
+- Update Maxblock heuristic #2275
+ [wiredfool]
+
+- Fix for 2-bit palette corruption #2274
+ [pdknsk, wiredfool]
+
+- Tiff: Update info.icc_profile when using libtiff reader. #2193
+ [lambdafu]
+
+- Test: Fix bug in test_ifd_rational_save when libtiff is not available #2270
+ [ChristopherHogan]
+
+- ICO: Only save relevant sizes #2267
+ [hugovk]
+
+- ICO: Allow saving .ico files of 256x256 instead of 255x255 #2265
+ [hugovk]
+
+- Fix TIFFImagePlugin ICC color profile saving. #2087
+ [cskau]
+
+- Doc: Improved description of ImageOps.deform resample parameter #2256
+ [radarhere]
+
+- EMF: support negative bounding box coordinates #2249
+ [glexey]
+
+- Close file if opened in WalImageFile #2216
+ [radarhere]
+
+- Use Image._new() instead of _makeself() #2248
+ [homm]
+
+- SunImagePlugin fixes #2241
+ [wiredfool]
+
+- Use minimal scale for jpeg drafts #2240
+ [homm]
+
+- Updated dependency scripts to use FreeType 2.7, OpenJpeg 2.1.2, WebP 0.5.2 and Tcl/Tk 8.6.6 #2235, #2236, #2237, #2290, #2302
+ [radarhere]
+
+- Fix "invalid escape sequence" bytestring warnings in Python 3.6 #2186
+ [timgraham]
+
+- Removed support for Python 2.6 and Python 3.2 #2192
+ [jdufresne]
+
+- Setup: Raise custom exceptions when required/requested dependencies are not found #2213
+ [wiredfool]
+
+- Use a context manager in FontFile.save() to ensure file is always closed #2226
+ [jdufresne]
+
+- Fixed bug in saving to fp-objects in Python >= 3.4 #2227
+ [radarhere]
+
+- Use a context manager in ImageFont._load_pilfont() to ensure file is always closed #2232
+ [jdufresne]
+
+- Use generator expressions instead of list comprehension #2225
+ [jdufresne]
+
+- Close file after reading in ImagePalette.load() #2215
+ [jdufresne]
+
+- Changed behaviour of default box argument for paste method to match docs #2211
+ [radarhere]
+
+- Add support for another BMP bitfield #2221
+ [jmerdich]
+
+- Added missing top-level test __main__ #2222
+ [radarhere]
+
+- Replaced range(len()) #2197
+ [radarhere]
+
+- Fix for ImageQt Segfault, fixes #1370 #2182
+ [wiredfool]
+
+- Setup: Close file in setup.py after finished reading #2208
+ [jdufresne]
+
+- Setup: optionally use pkg-config (when present) to detect dependencies #2074
+ [garbas]
+
+- Search for tkinter first in builtins #2210
+ [matthew-brett]
+
+- Tests: Replace try/except/fail pattern with TestCase.assertRaises() #2200
+ [jdufresne]
+
+- Tests: Remove unused, open files at top level of tests #2188
+ [jdufresne]
+
+- Replace type() equality checks with isinstance #2184
+ [jdufresne]
+
+- Doc: Move ICO out of the list of read-only file formats #2180
+ [alexwlchan]
+
+- Doc: Fix formatting, too-short title underlines and malformed table #2175
+ [hugovk]
+
+- Fix BytesWarnings #2172
+ [jdufresne]
+
+- Use Integer division to eliminate deprecation warning. #2168
+ [mastermatt]
+
+- Doc: Update compatibility matrix
+ [daavve, wiredfool]
+
+
+3.4.2 (2016-10-18)
+------------------
+
+- Fix Resample coefficient calculation #2162
+ [homm]
+
+
+3.4.1 (2016-10-04)
+------------------
+
+- Allow lists as arguments for Image.new() #2149
+ [homm]
+
+- Fix fix for map.c overflow #2151 (also in 3.3.3)
+ [wiredfool]
+
+3.4.0 (2016-10-03)
+------------------
+
+- Removed Image.core.open_ppm, added negative image size checks in Image.py. #2146
+ [wiredfool]
+
+- Windows build: fetch dependencies from pillow-depends #2095
+ [hugovk]
+
+- Add TIFF save_all writer. #2140
+ [lambdafu, vashek]
+
+- Move libtiff fd duplication to _load_libtiff #2141
+ [sekrause]
+
+- Speed up GIF save optimization step, fixes #2093. #2133
+ [wiredfool]
+
+- Fix for ImageCms Segfault, Issue #2037. #2131
+ [wiredfool]
+
+- Make Image.crop an immediate operation, not lazy. #2138
+ [wiredfool]
+
+- Skip empty values in ImageFileDirectory #2024
+ [homm]
+
+- Force reloading palette when using mmap in ImageFile. #2139
+ [lambdafu]
+
+- Fix "invalid escape sequence" warning in Python 3.6 #2136
+ [timgraham]
+
+- Update documentation about drafts #2137
+ [radarhere]
+
+- Converted documentation parameter format, comments to docstrings #2021
+ [radarhere]
+
+- Fixed typos #2128 #2142
+ [radarhere]
+
+- Renamed references to OS X to macOS #2125 2130
+ [radarhere]
+
+- Use truth value when checking for progressive and optimize option on save #2115, #2129
+ [radarhere]
+
+- Convert DPI to ints when saving as JPEG #2102
+ [radarhere]
+
+- Added append_images parameter to GIF saving #2103
+ [radarhere]
+
+- Speedup paste with masks up to 80% #2015
+ [homm]
+
+- Rewrite DDS decoders in C, add DXT3 and BC7 decoders #2068
+ [Mischanix]
+
+- Fix PyArg_ParseTuple format in getink() #2070
+ [arjennienhuis]
+
+- Fix saving originally missing TIFF tags. #2111
+ [anntzer]
+
+- Allow pathlib.Path in Image.open on Python 2.7 #2110
+ [patricksnape]
+
+- Use modern base64 interface over deprecated #2121
+ [hugovk]
+
+- ImageColor.getrgb hexadecimal RGBA #2114
+ [homm]
+
+- Test fix for bigendian machines #2092
+ [wiredfool]
+
+- Resampling lookups, trailing empty coefficients, precision #2008
+ [homm]
+
+- Add (un)packing between RGBA and BGRa #2057
+ [arjennienhuis]
+
+- Added return for J2k (and fpx) Load to return a pixel access object #2061
+ [wiredfool]
+
+- Skip failing numpy tests on Pypy <= 5.3.1 #2090
+ [arjennienhuis]
+
+- Show warning when trying to save RGBA image as JPEG #2010
+ [homm]
+
+- Respect pixel centers during transform #2022
+ [homm]
+
+- TOC for supported file formats #2056
+ [polarize]
+
+- Fix conversion of bit images to numpy arrays Fixes #350, #2058
+ [matthew-brett]
+
+- Add ImageOps.scale to expand or contract a PIL image by a factor #2011
+ [vlmath]
+
+- Flake8 fixes #2050
+ [hugovk]
+
+- Updated freetype to 2.6.5 on Appveyor builds #2035
+ [radarhere]
+
+- PCX encoder fixes #2023, pr #2041
+ [homm]
+
+- Docs: Windows console prompts are > #2031
+ [techtonik]
+
+- Expose Pillow package version as PIL.__version__ #2027
+ [techtonik]
+
+- Add Box and Hamming filters for resampling #1959
+ [homm]
+
+- Retain a reference to core image object in PyAccess #2009
+ [homm]
+
+3.3.3 (2016-10-04)
+------------------
+
+- Fix fix for map.c overflow #2151
+ [wiredfool]
+
+3.3.2 (2016-10-03)
+------------------
+
+- Fix negative image sizes in Storage.c #2146
+ [wiredfool]
+
+- Fix integer overflow in map.c #2146
+ [wiredfool]
+
+3.3.1 (2016-08-18)
+------------------
+
+- Fix C90 compilation error for Tcl / Tk rewrite #2033
+ [matthew-brett]
+
+- Fix image loading when rotating by 0 deg #2052
+ [homm]
+
+3.3.0 (2016-07-01)
+------------------
+
+- Fixed enums for Resolution Unit and Predictor in TiffTags.py #1998
+ [wiredfool]
+
+- Fix issue converting P mode to LA #1986
+ [didrix]
+
+- Moved test_j2k_overflow to check_j2k_overflow, prevent DOS of our 32bit testing machines #1995
+ [wiredfool]
+
+- Skip CRC checks in PNG files when LOAD_TRUNCATED_IMAGES is enabled #1991
+ [kkopachev]
+
+- Added CMYK mode for opening EPS files #1826
+ [radarhere]
+
+- Docs: OSX build instruction clarification #1994
+ [wiredfool]
+
+- Docs: Filter comparison table #1993
+ [homm]
+
+- Removal of pthread based Incremental.c, new interface for file decoders/encoders to access the python file. Fixes assorted J2k Hangs. #1934
+ [wiredfool]
+
+- Skip unnecessary passes when resizing #1954
+ [homm]
+
+- Removed duplicate code in ImagePalette #1832
+ [radarhere]
+
+- test_imagecms: Reduce precision of extended info due to 32 bit machine precision #1990
+ [AbdealiJK]
+
+- Binary Tiff Metadata/ICC profile. #1988
+ [wiredfool]
+
+- Ignore large text blocks in PNG if LOAD_TRUNCATED_IMAGES is enabled #1970
+ [homm]
+
+- Replace index = index+1 in docs with +=1
+ [cclauss]
+
+- Skip extra 0xff00 in jpeg #1977
+ [kkopachev]
+
+- Use bytearray for palette mutable storage #1985
+ [radarhere, wiredfool]
+
+- Added additional uint modes for Image.fromarray, more extensive tests of fromarray #1984
+ [mairsbw, wiredfool]
+
+- Fix for program importing PyQt4 when PyQt5 also installed #1942
+ [hugovk]
+
+- Changed depends/install_*.sh urls to point to github pillow-depends repo #1983
+ [wiredfool]
+
+- Allow ICC profile from ``encoderinfo`` while saving PNGs #1909
+ [homm]
+
+- Fix integer overflow on ILP32 systems (32-bit Linux). #1975
+ [lambdafu]
+
+- Change function declaration to match Tcl_CmdProc type #1966
+ [homm]
+
+- Integer overflow checks on all calls to *alloc #1781
+ [wiredfool]
+
+- Change equals method on Image so it short circuits #1967
+ [mattBoros]
+
+- Runtime loading of TCL/TK libraries, eliminating build time dependency. #1932
+ [matthew-brett]
+
+- Cleanup of transform methods #1941
+ [homm]
+
+- Fix "Fatal Python error: UNREF invalid object" in debug builds #1936
+ [wiredfool]
+
+- Setup fixes for Alpine linux #1937
+ [wiredfool]
+
+- Split resample into horizontal + vertical passes #1933
+ [homm]
+
+- Box blur with premultiplied alpha #1914
+ [homm]
+
+- Add libimagequant support in quantize() #1889
+ [rr-]
+
+- Added internal Premultiplied luminosity (La) mode #1912
+ [homm]
+
+- Fixed point integer resample #1881
+ [homm]
+
+- Removed docs/BUILDME script #1924
+ [radarhere]
+
+- Moved comments to docstrings #1926
+ [hugovk]
+
+- Include Python.h before wchar.h so _GNU_SOURCE is set consistently #1906
+ [hugovk]
+
+- Updated example decoder in documentation #1899
+ [radarhere]
+
+- Added support for GIF comment extension #1896
+ [radarhere]
+
+- Removed support for pre- 1.5.2 list form of Image info in Image.new #1897
+ [radarhere]
+
+- Fix typos in TIFF tags #1918
+ [radarhere]
+
+- Skip tests that require libtiff if it is not installed #1893 (fixes #1866)
+ [wiredfool]
+
+- Skip test when icc profile is not available, fixes #1887. #1892
+ [doko42]
+
+- Make deprecated functions raise NotImplementedError instead of Exception. #1862, #1890
+ [daniel-leicht, radarhere]
+
+- Replaced os.system with subprocess.call in setup.py #1879
+ [radarhere]
+
+- Corrected Image show documentation #1886
+ [radarhere]
+
+- Added check for executable permissions to ImageShow #1880
+ [radarhere]
+
+- Fixed tutorial code and added explanation #1877
+ [radarhere]
+
+- Added OS X support for ImageGrab grabclipboard #1837
+ [radarhere]
+
+- Combined duplicate code in ImageTk #1856
+ [radarhere]
+
+- Added --disable-platform-guessing option to setup.py build extension #1861
+ [angeloc]
+
+- Fixed loading Transparent PNGs with a transparent black color #1840
+ [olt]
+
+- Add support for LA mode in Image.fromarray #1865
+ [pierriko]
+
+- Make ImageFile load images in read-only mode #1864
+ [hdante]
+
+- Added _accept hook for XVThumbImagePlugin #1853
+ [radarhere]
+
+- Test TIFF with LZW compression #1855, TGA RLE file #1854
+ [hugovk]
+
+- Improved SpiderImagePlugin help text #1863
+ [radarhere]
+
+- Updated Sphinx project description #1870
+ [radarhere]
+
+- Remove support for Python 3.0 from _imaging.c #1851
+ [radarhere]
+
+- Jpeg qtables are unsigned chars #1814, #1921
+ [thebostik]
+
+- Added additional EXIF tags #1841, TIFF Tags #1821
+ [radarhere]
+
+- Changed documentation to refer to ImageSequence Iterator #1833
+ [radarhere]
+
+- Fix Fedora prerequisites in installation docs, depends script #1842
+ [living180]
+
+- Added _accept hook for PixarImagePlugin #1843
+ [radarhere]
+
+- Removed outdated scanner classifier #1823
+ [radarhere]
+
+- Combined identical error messages in _imaging #1825
+ [radarhere]
+
+- Added debug option for setup.py to trace header and library finding #1790
+ [wiredfool]
+
+- Fix doc building on travis #1820, #1844
+ [wiredfool]
+
+- Fix for DIB/BMP images #1813, #1847
+ [wiredfool]
+
+- Add PixarImagePlugin file extension #1809
+ [radarhere]
+
+- Catch struct.errors when verifying png files #1805
+ [wiredfool]
+
+- SpiderImagePlugin: raise an error when seeking in a non-stack file #1794
+ [radarhere, jmichalon]
+
+- Added support for 2/4 bpp Tiff grayscale images #1789
+ [zwhfly]
+
+- Removed unused variable from selftest #1788
+ [radarhere]
+
+- Added warning for as_dict method (deprecated in 3.0.0) #1799
+ [radarhere]
+
+- Removed powf support for older Python versions #1784
+ [radarhere]
+
+- Health fixes #1625 #1903
+ [radarhere]
+
+3.2.0 (2016-04-01)
+------------------
+
+- Added install docs for Fedora 23 and FreeBSD #1729, #1739, #1792
+ [koobs, zandermartin, wiredfool]
+
+- Fixed TIFF multiframe load when the frames have different compression types #1782
+ [radarhere, geka000]
+
+- Added __copy__ method to Image #1772
+ [radarhere]
+
+- Updated dates in PIL license in OleFileIO README #1787
+ [radarhere]
+
+- Corrected Tiff tag names #1786
+ [radarhere]
+
+- Fixed documented name of JPEG property #1783
+ [radarhere]
+
+- Fixed UnboundLocalError when loading a corrupt jpeg2k file #1780
+ [wiredfool]
+
+- Fixed integer overflow in path.c #1773
+ [wiredfool, nedwill]
+
+- Added debug to command line help text for pilprint #1766
+ [radarhere]
+
+- Expose many more fields in ICC Profiles #1756
+ [lambdafu]
+
+- Documentation changes, URL update, transpose, release checklist
+ [radarhere]
+
+- Fixed saving to nonexistant files specified by pathlib.Path objects #1748 (fixes #1747)
+ [radarhere]
+
+- Round Image.crop arguments to the nearest integer #1745 (fixes #1744)
+ [hugovk]
+
+- Fix uninitialized variable warning in _imaging.c:getink #1663 (fixes #486)
+ [wiredfool]
+
+- Disable multiprocessing install on cygwin #1700 (fixes #1690)
+ [wiredfool]
+
+- Fix the error reported when libz is not found #1764
+ [wiredfool]
+
+- More general error check to avoid Symbol not found: _PyUnicodeUCS2_AsLatin1String on OS X #1761
+ [wiredfool]
+
+- Added py35 to tox envlist #1724
+ [radarhere]
+
+- Fix EXIF tag name typos #1736
+ [zarlant, radarhere]
+
+- Updated freetype to 2.6.3, Tk/Tcl to 8.6.5 and 8.5.19 #1725, #1752
+ [radarhere]
+
+- Add a loader for the FTEX format from Independence War 2: Edge of Chaos #1688
+ [jleclanche]
+
+- Improved alpha_composite documentation #1698
+ [radarhere]
+
+- Extend ImageDraw.text method to pass on multiline_text method specific arguments #1647
+ [radarhere]
+
+- Allow ImageSequence to seek to zero #1686
+ [radarhere]
+
+- ImageSequence Iterator is now an iterator #1649
+ [radarhere]
+
+- Updated windows test builds to jpeg9b #1673
+ [radarhere]
+
+- Fixed support for .gbr version 1 images, added support for version 2 in GbrImagePlugin #1653
+ [wiredfool]
+
+- Clarified which YCbCr format is used #1677
+ [radarhere]
+
+- Added TiffTags documentation, Moved windows build documentation to winbuild/ #1667
+ [wiredfool]
+
+- Add tests for OLE file based formats #1678
+ [radarhere]
+
+- Add TIFF IFD test #1671
+ [radarhere]
+
+- Add a basic DDS image plugin with more tests #1654
+ [jleclanche, hugovk, wiredfool]
+
+- Fix incorrect conditional in encode.c #1638
+ [manisandro]
+
+
+3.1.2 (2016-04-01)
+------------------
+
+- Fixed an integer overflow in Jpeg2KEncode.c causing a buffer overflow. CVE-2016-3076
+ [wiredfool]
+
+3.1.1 (2016-02-04)
+------------------
+
+- Fixed an integer overflow in Resample.c causing writes in the Python heap.
+ [nedwill]
+
+- Fixed a buffer overflow in PcdDecode.c causing a segfault when opening PhotoCD files. CVE-2016-2533
+ [wiredfool]
+
+- Fixed a buffer overflow in FliDecode.c causing a segfault when opening FLI files. CVE-2016-0775
+ [wiredfool]
+
+- Fixed a buffer overflow in TiffDecode.c causing an arbitrary amount of memory to be overwritten when opening a specially crafted invalid TIFF file. CVE-2016-0740
+ [wiredfool]
+
+
+3.1.0 (2016-01-04)
+------------------
+
+- Fixing test failures on Python 2.6/Windows #1633
+ [wiredfool]
+
+- Limit metadata tags when writing using libtiff #1620
+ [wiredfool]
+
+- Rolling back exif support to pre-3.0 format #1627
+ [wiredfool]
+
+- Fix Divide by zero in Exif, add IFDRational class #1531
+ [wiredfool]
+
+- Catch the IFD error near the source #1622
+ [wiredfool]
+
+- Added release notes for 3.1.0 #1623
+ [radarhere]
+
+- Updated spacing to be consistent between multiline methods #1624
+ [radarhere]
+
+- Let EditorConfig take care of some basic formatting #1489
+ [hugovk]
+
+- Restore gpsexif data to the v1 form #1619
+ [wiredfool]
+
+- Add /usr/local include and library directories for freebsd #1613
+ [leforestier]
+
+- Updated installation docs for new versions of dependencies #1611
+ [radarhere]
+
+- Removed unrunnable test file #1610
+ [radarhere]
+
+- Changed register calls to use format property #1608
+ [radarhere]
+
+- Added field type constants to TiffTags #1596
+ [radarhere]
+
+- Allow saving RowsPerStrip with libtiff #1594
+ [wiredfool]
+
+- Enabled conversion to numpy array for HSV images #1578
+ [cartisan]
+
+- Changed some urls in the docs to use https #1580
+ [hugovk]
+
+- Removed logger.exception from ImageFile.py #1590
+ [radarhere]
+
+- Removed warnings module check #1587
+ [radarhere]
+
+- Changed arcs, chords and pie slices to use floats #1577
+ [radarhere]
+
+- Update unit test asserts #1584, #1598
+ [radarhere]
+
+- Fix command to invoke ghostscript for eps files #1478
+ [baumatron, radarhere]
+
+- Consistent multiline text spacing #1574
+ [wiredfool, hugovk]
+
+- Removed unused lines in BDFFontFile #1530
+ [radarhere]
+
+- Changed ImageQt import of Image #1560
+ [radarhere, ericfrederich]
+
+- Throw TypeError if no cursors were found in .cur file #1556
+ [radarhere]
+
+- Fix crash in ImageTk.PhotoImage on win-amd64 #1553
+ [cgohlke]
+
+- ExtraSamples tag should be a SHORT, not a BYTE #1555
+ [Nexuapex]
+
+- Docs and code health fixes #1565 #1566 #1581 #1586 #1591 #1621
+ [radarhere]
+
+- Updated freetype to 2.6.2 #1564
+ [radarhere]
+
+- Updated WebP to 0.5.0 for Travis #1515 #1609
+ [radarhere]
+
+- Fix missing 'version' key value in __array_interface__ #1519
+ [mattip]
+
+- Replaced os.popen with subprocess.Popen to pilprint script #1523
+ [radarhere]
+
+- Catch OverflowError in SpiderImagePlugin #1545
+ [radarhere, MrShark]
+
+- Fix the definition of icc_profile in TiffTags #1539
+ [wiredfool]
+
+- Remove old _imagingtiff.c and pilplus stuff #1499
+ [hugovk]
+
+- Fix Exception when requiring jpeg #1501
+ [hansmosh]
+
+- Dependency scripts for Debian and Ubuntu #1486
+ [wiredfool]
+
+- Added Usage message to painter script #1482
+ [radarhere]
+
+- Add tag info for iccprofile, fixes #1462. #1465
+ [wiredfool]
+
+- Added some requirements for make release-test #1451
+ [wiredfool]
+
+- Flatten tiff metadata value SAMPLEFORMAT to initial value #1467 (fixes #1466)
+ [wiredfool]
+
+- Fix handling of pathlib in Image.save #1464 (fixes #1460)
+ [wiredfool]
+
+- Make tests more robust #1469
+ [hugovk]
+
+- Use correctly sized pointers for windows handle types #1458
+ [nu744]
+
+3.0.0 (2015-10-01)
+------------------
+
+- Check flush method existence for file-like object #1398
+ [mrTable, radarhere]
+
+- Added PDF multipage saving #1445
+ [radarhere]
+
+- Removed deprecated code, Image.tostring, Image.fromstring, Image.offset, ImageDraw.setink, ImageDraw.setfill, ImageFileIO, ImageFont.FreeTypeFont and ImageFont.truetype ``file`` kwarg, ImagePalette private _make functions, ImageWin.fromstring and ImageWin.tostring #1343
+ [radarhere]
+
+- Load more broken images #1428
+ [homm]
+
+- Require zlib and libjpeg #1439
+ [wiredfool]
+
+- Preserve alpha when converting from a QImage to a Pillow Image by using png instead of ppm #1429
+ [ericfrederich]
+
+- Qt needs 32 bit aligned image data #1430
+ [ericfrederich]
+
+- Tiff ImageFileDirectory rewrite #1419
+ [anntzer, wiredfool, homm]
+
+- Removed spammy debug logging #1423
+ [wiredfool]
+
+- Save as GiF89a with support for animation parameters #1384
+ [radarhere]
+
+- Correct convert matrix docs #1426
+ [wiredfool]
+
+- Catch TypeError in _getexif #1414
+ [radarhere, wiredfool]
+
+- Fix for UnicodeDecodeError in TiffImagePlugin #1416
+ [bogdan199, wiredfool]
+
+- Dedup code in image.open #1415
+ [wiredfool]
+
+- Skip any number extraneous chars at the end of JPEG chunks #1337
+ [homm]
+
+- Single threaded build for pypy3, refactor #1413
+ [wiredfool]
+
+- Fix loading of truncated images with LOAD_TRUNCATED_IMAGES enabled #1366
+ [homm]
+
+- Documentation update for concepts: bands #1406
+ [merriam]
+
+- Add Solaris/SmartOS include and library directories #1356
+ [njones11]
+
+- Improved handling of getink color #1387
+ [radarhere]
+
+- Disable compiler optimizations for topalette and tobilevel functions for all msvc versions #1402 (fixes #1357)
+ [cgohlke]
+
+- Skip ImageFont_bitmap test if _imagingft C module is not installed #1409
+ [homm]
+
+- Add param documentation to ImagePalette #1381
+ [bwrsandman]
+
+- Corrected scripts path #1407
+ [radarhere]
+
+- Updated libtiff to 4.0.6 #1405, #1421
+ [radarhere]
+
+- Updated Platform Support for Yosemite #1403
+ [radarhere]
+
+- Fixed infinite loop on truncated file #1401
+ [radarhere]
+
+- Check that images are L mode in ImageMorph methods #1400
+ [radarhere]
+
+- In tutorial of pasting images, add to mask text #1389
+ [merriam]
+
+- Style/health fixes #1391, #1397, #1417, #1418
+ [radarhere]
+
+- Test on Python 3.5 dev and 3.6 nightly #1361
+ [hugovk]
+
+- Fix fast rotate operations #1373
+ [radarhere]
+
+- Added support for pathlib Path objects to open and save #1372
+ [radarhere]
+
+- Changed register calls to use format property #1333
+ [radarhere]
+
+- Added support for ImageGrab.grab to OS X #1367, #1443
+ [radarhere, hugovk]
+
+- Fixed PSDraw stdout Python 3 compatibility #1365
+ [radarhere]
+
+- Added Python 3.3 to AppVeyor #1363
+ [radarhere]
+
+- Treat MPO with unknown header as base JPEG file #1350
+ [hugovk, radarhere]
+
+- Added various tests #1330, #1344
+ [radarhere]
+
+- More ImageFont tests #1327
+ [hugovk]
+
+- Use logging instead of print #1207
+ [anntzer]
+
+2.9.0 (2015-07-01)
+------------------
+
+- Added test for GimpPaletteFile #1324
+ [radarhere]
+
+- Merged gifmaker script to allow saving of multi-frame GIF images #1320
+ [radarhere]
+
+- Added is_animated property to multi-frame formats #1319
+ [radarhere]
+
+- Fixed ValueError in Python 2.6 #1315 #1316
+ [cgohlke, radarhere]
+
+- Fixed tox test script path #1308
+ [radarhere]
+
+- Added width and height properties #1304
+ [radarhere]
+
+- Update tiff and tk tcl 8.5 versions #1303
+ [radarhere, wiredfool]
+
+- Add functions to convert: Image <-> QImage; Image <-> QPixmap #1217
+ [radarhere, rominf]
+
+- Remove duplicate code in gifmaker script #1294
+ [radarhere]
+
+- Multiline text in ImageDraw #1177
+ [allo-, radarhere]
+
+- Automated Windows CI/build support #1278
+ [wiredfool]
+
+- Removed support for Tk versions earlier than 8.4 #1288
+ [radarhere]
+
+- Fixed polygon edge drawing #1255 (fixes #1252)
+ [radarhere]
+
+- Check prefix length in _accept methods #1267
+ [radarhere]
+
+- Register MIME type for BMP #1277
+ [coldmind]
+
+- Adjusted ImageQt use of unicode() for 2/3 compatibility #1218
+ [radarhere]
+
+- Identify XBM file created with filename including underscore #1230 (fixes #1229)
+ [hugovk]
+
+- Copy image when saving in GifImagePlugin #1231 (fixes #718)
+ [radarhere]
+
+- Removed support for FreeType 2.0 #1247
+ [radarhere]
+
+- Added background saving to GifImagePlugin #1273
+ [radarhere]
+
+- Provide n_frames attribute to multi-frame formats #1261
+ [anntzer, radarhere]
+
+- Add duration and loop set to GifImagePlugin #1172, #1269
+ [radarhere]
+
+- Ico files are little endian #1232
+ [wiredfool]
+
+- Upgrade olefile from 0.30 to 0.42b #1226
+ [radarhere, decalage2]
+
+- Setting transparency value to 0 when the tRNS contains only null byte(s) #1239
+ [juztin]
+
+- Separated out feature checking from selftest #1233
+ [radarhere]
+
+- Style/health fixes
+ [radarhere]
+
+- Update WebP from 0.4.1 to 0.4.3 #1235
+ [radarhere]
+
+- Release GIL during image load (decode) #1224
+ [lkesteloot]
+
+- Added icns save #1185
+ [radarhere]
+
+- Fix putdata memory leak #1196
+ [benoit-pierre]
+
+- Keep user-specified ordering of icon sizes #1193
+ [karimbahgat]
+
+- Tiff: allow writing floating point tag values #1113
+ [bpedersen2]
+
+2.8.2 (2015-06-06)
+------------------
+
+- Bug fix: Fixed Tiff handling of bad EXIF data
+ [radarhere]
+
+2.8.1 (2015-04-02)
+------------------
+
+- Bug fix: Catch struct.error on invalid JPEG, fixes #1163. #1165
+ [wiredfool, hugovk]
+
+2.8.0 (2015-04-01)
+------------------
+
+- Fix 32-bit BMP loading (RGBA or RGBX) #1125
+ [artscoop]
+
+- Fix UnboundLocalError in ImageFile #1131
+ [davarisg]
+
+- Re-enable test image caching #982
+ [hugovk, homm]
+
+- Fix: Cannot identify EPS images #1152 (fixes #1104)
+ [hugovk]
+
+- Configure setuptools to run nosetests, fixes #729
+ [aclark4life]
+
+- Style/health fixes
+ [radarhere, hugovk]
+
+- Add support for HTTP response objects to Image.open() #1151
+ [mfitzp]
+
+- Improve reference docs for PIL.ImageDraw.Draw.pieslice() #1145
+ [audreyr]
+
+- Added copy method font_variant() and accessible properties to truetype() #1123
+ [radarhere]
+
+- Fix ImagingEffectNoise #1128
+ [hugovk]
+
+- Remove unreachable code #1126
+ [hugovk]
+
+- Let Python do the endian stuff + tests #1121
+ [amoibos, radarhere]
+
+- Fix webp decode memory leak #1114
+ [benoit-pierre]
+
+- Fast path for opaque pixels in RGBa unpacker #1088
+ [bgilbert]
+
+- Enable basic support for 'RGBa' raw encoding/decoding #1096
+ [immerrr]
+
+- Fix pickling L mode images with no palette, #1095
+ [hugovk]
+
+- iPython display hook #1091
+ [wiredfool]
+
+- Adjust buffer size when quality=keep #1079 (fixes #148 again)
+ [wiredfool]
+
+- Fix for corrupted bitmaps embedded in truetype fonts #1072
+ [jackyyf, wiredfool]
+
+2.7.0 (2015-01-01)
+------------------
+
+- Split Sane into a separate repo: https://github.com/python-pillow/Sane
+ [hugovk]
+
+- Look for OS X and Linux fonts in common places #1054
+ [charleslaw]
+
+- Fix CVE-2014-9601, potential PNG decompression DOS #1060
+ [wiredfool]
+
+- Use underscores, not spaces, in TIFF tag kwargs #1044, #1058
+ [anntzer, hugovk]
+
+- Update PSDraw for Python3, add tests #1055
+ [hugovk]
+
+- Use Bicubic filtering by default for thumbnails. Don't use Jpeg Draft mode for thumbnails #1029
+ [homm]
+
+- Fix MSVC compiler error: Use Py_ssize_t instead of ssize_t #1051
+ [cgohlke]
+
+- Fix compiler error: MSVC needs variables defined at the start of the block #1048
+ [cgohlke]
+
+- The GIF Palette optimization algorithm is only applicable to mode='P' or 'L' #993
+ [moriyoshi]
+
+- Use PySide as an alternative to PyQt4/5 #1024
+ [holg]
+
+- Replace affine-based im.resize implementation with convolution-based im.stretch #997
+ [homm]
+
+- Replace Gaussian Blur implementation with iterated fast box blur. #961 Note: Radius parameter is interpreted differently than before.
+ [homm]
+
+- Better docs explaining import _imaging failure #1016, build #1017, mode #1018, PyAccess, PixelAccess objects #1019 Image.quantize #1020 and Image.save #1021
+ [wiredfool]
+
+- Fix for saving TIFF image into an io.BytesIO buffer #1011
+ [mfergie]
+
+- Fix antialias compilation on debug versions of Python #1010
+ [wiredfool]
+
+- Fix for Image.putdata segfault #1009
+ [wiredfool]
+
+- Ico save, additional tests #1007
+ [exherb]
+
+- Use PyQt4 if it has already been imported, otherwise prefer PyQt5 #1003
+ [AurelienBallier]
+
+- Speedup resample implementation up to 2.5 times #977
+ [homm]
+
+- Speed up rotation by using cache aware loops, added transpose to rotations #994
+ [homm]
+
+- Fix Bicubic interpolation #970
+ [homm]
+
+- Support for 4-bit greyscale TIFF images #980
+ [hugovk]
+
+- Updated manifest #957
+ [wiredfool]
+
+- Fix PyPy 2.4 regression #958
+ [wiredfool]
+
+- Webp Metadata Skip Test comments #954
+ [wiredfool]
+
+- Fixes for things rpmlint complains about #942
+ [manisandro]
+
+2.6.2 (2015-01-01)
+------------------
+
+- Fix CVE-2014-9601, potential PNG decompression DOS #1060
+ [wiredfool]
+
+- Fix Regression in PyPy 2.4 in streamio #958
+ [wiredfool]
+
+2.6.1 (2014-10-11)
+------------------
+
+- Fix SciPy regression in Image.resize #945
+ [wiredfool]
+
+- Fix manifest to include all test files.
+ [aclark4life]
+
+2.6.0 (2014-10-01)
+------------------
+
+- Relax precision of ImageDraw tests for x86, GimpGradient for PPC #930
+ [wiredfool]
+
+2.6.0-rc1 (2014-09-29)
+----------------------
+
+- Use redistributable image for testing #884
+ [hugovk]
+
+- Use redistributable ICC profiles for testing, skip if not available #923
+ [wiredfool]
+
+- Additional documentation for JPEG info and save options #922
+ [wiredfool]
+
+- Fix JPEG Encoding memory leak when exif or qtables were specified #921
+ [wiredfool]
+
+- Image.tobytes() and Image.tostring() documentation update #916 #917
+ [mgedmin]
+
+- On Windows, do not execute convert.exe without specifying path #912
+ [cgohlke]
+
+- Fix msvc build error #911
+ [cgohlke]
+
+- Fix for handling P + transparency -> RGBA conversions #904
+ [wiredfool]
+
+- Retain alpha in ImageEnhance operations #909
+ [wiredfool]
+
+- Jpeg2k Decode/encode memory leak fix #898
+ [joshware, wiredfool]
+
+- EpsFilePlugin Speed improvements #886
+ [wiredfool, karstenw]
+
+- Don't resize if already the right size #892
+ [radarhere]
+
+- Fix for reading multipage TIFFs #885
+ [kostrom, wiredfool]
+
+- Correctly handle saving gray and CMYK JPEGs with quality=keep #857
+ [etienned]
+
+- Correct duplicate Tiff Metadata and Exif tag values
+ [hugovk]
+
+- Windows fixes #871
+ [wiredfool]
+
+- Fix TGA files with image ID field #856
+ [megabuz]
+
+- Fixed wrong P-mode of small, unoptimized L-mode GIF #843
+ [uvNikita]
+
+- Fixed CVE-2014-3598, a DOS in the Jpeg2KImagePlugin
+ [Andrew Drake]
+
+- Fixed CVE-2014-3589, a DOS in the IcnsImagePlugin
+ [Andrew Drake]
+
+- setup.py: Close open file handle before deleting #844
+ [divergentdave]
+
+- Return Profile with Transformed Images #837
+ [wiredfool]
+
+- Changed docstring to refer to the correct function #836
+ [MatMoore]
+
+- Adding coverage support for C code tests #833
+ [wiredfool]
+
+- PyPy performance improvements #821
+ [wiredfool]
+
+- Added support for reading MPO files #822
+ [Feneric]
+
+- Added support for encoding and decoding iTXt chunks #818
+ [dolda2000]
+
+- HSV Support #816
+ [wiredfool]
+
+- Removed unusable ImagePalette.new()
+ [hugovk]
+
+- Fix Scrambled XPM #808
+ [wiredfool]
+
+- Doc cleanup
+ [wiredfool]
+
+- Fix ``ImageStat`` docs #796
+ [akx]
+
+- Added docs for ExifTags #794
+ [Wintermute3]
+
+- More tests for CurImagePlugin, DcxImagePlugin, Effects.c, GimpGradientFile, ImageFont, ImageMath, ImagePalette, IptcImagePlugin, SpiderImagePlugin, SgiImagePlugin, XpmImagePlugin and _util
+ [hugovk]
+
+- Fix return value of FreeTypeFont.textsize() does not include font offsets #784
+ [tk0miya]
+
+- Fix dispose calculations for animated GIFs #765
+ [larsjsol]
+
+- Added class checking to Image __eq__ function #775
+ [radarhere, hugovk]
+
+- Test PalmImagePlugin and method to skip known bad tests #776
+ [hugovk, wiredfool]
+
+2.5.3 (2014-08-18)
+------------------
+
+- Fixed CVE-2014-3598, a DOS in the Jpeg2KImagePlugin (backport)
+ [Andrew Drake]
+
+
+2.5.2 (2014-08-13)
+------------------
+
+- Fixed CVE-2014-3589, a DOS in the IcnsImagePlugin (backport)
+ [Andrew Drake]
+
+2.5.1 (2014-07-10)
+------------------
+
+- Fixed install issue if Multiprocessing.Pool is not available
+ [wiredfool]
+
+- 32bit mult overflow fix #782
+ [wiredfool]
+
+2.5.0 (2014-07-01)
+------------------
+
+- Imagedraw rewrite #737
+ [terseus, wiredfool]
+
+- Add support for multithreaded test execution #755
+ [wiredfool]
+
+- Prevent shell injection #748
+ [mbrown1413, wiredfool]
+
+- Support for Resolution in BMP files #734
+ [gcq]
+
+- Fix error in setup.py for Python 3 #744
+ [matthew-brett]
+
+- Pyroma fix and add Python 3.4 to setup metadata #742
+ [wirefool]
+
+- Top level flake8 fixes #741
+ [aclark4life]
+
+- Remove obsolete Animated Raster Graphics (ARG) support #736
+ [hugovk]
+
+- Fix test_imagedraw failures #727
+ [cgohlke]
+
+- Fix AttributeError: class Image has no attribute 'DEBUG' #726
+ [cgohlke]
+
+- Fix msvc warning: 'inline' : macro redefinition #725
+ [cgohlke]
+
+- Cleanup #654
+ [dvska, hugovk, wiredfool]
+
+- 16-bit monochrome support for JPEG2000 #730
+ [videan42]
+
+- Fixed ImagePalette.save
+ [brightpisces]
+
+- Support JPEG qtables #677
+ [csinchok]
+
+- Add binary morphology addon
+ [dov, wiredfool]
+
+- Decompression bomb protection #674
+ [hugovk]
+
+- Put images in a single directory #708
+ [hugovk]
+
+- Support OpenJpeg 2.1 #681
+ [al45tair, wiredfool]
+
+- Remove unistd.h #include for all platforms #704
+ [wiredfool]
+
+- Use unittest for tests
+ [hugovk]
+
+- ImageCms fixes
+ [hugovk]
+
+- Added more ImageDraw tests
+ [hugovk]
+
+- Added tests for Spider files
+ [hugovk]
+
+- Use libtiff to write any compressed tiff files #669
+ [wiredfool]
+
+- Support for pickling Image objects
+ [hugovk]
+
+- Fixed resolution handling for EPS thumbnails #619
+ [eliempje]
+
+- Fixed rendering of some binary EPS files (Issue #302)
+ [eliempje]
+
+- Rename variables not to use built-in function names #670
+ [hugovk]
+
+- Ignore junk JPEG markers
+ [hugovk]
+
+- Change default interpolation for Image.thumbnail to Image.ANTIALIAS
+ [hugovk]
+
+- Add tests and fixes for saving PDFs
+ [hugovk]
+
+- Remove transparency resource after P->RGBA conversion
+ [hugovk]
+
+- Clean up preprocessor cruft for Windows #652
+ [CounterPillow]
+
+- Adjust Homebrew freetype detection logic #656
+ [jacknagel]
+
+- Added Image.close, context manager support
+ [wiredfool]
+
+- Added support for 16 bit PGM files
+ [wiredfool]
+
+- Updated OleFileIO to version 0.30 from upstream #618
+ [hugovk]
+
+- Added support for additional TIFF floating point format
+ [Hijackal]
+
+- Have the tempfile use a suffix with a dot
+ [wiredfool]
+
+- Fix variable name used for transparency manipulations #604
+ [nijel]
+
+2.4.0 (2014-04-01)
+------------------
+
+- Indexed Transparency handled for conversions between L, RGB, and P modes #574 (fixes #510)
+ [wiredfool]
+
+- Conversions enabled from RGBA->P #574 (fixes #544)
+ [wiredfool]
+
+- Improved icns support #565
+ [al45tair]
+
+- Fix libtiff leaking open files #580 (fixes #526)
+ [wiredfool]
+
+- Fixes for Jpeg encoding in Python 3 #578 (fixes #577)
+ [wiredfool]
+
+- Added support for JPEG 2000 #547
+ [al45tair]
+
+- Add more detailed error messages to Image.py #566
+ [larsmans]
+
+- Avoid conflicting _expand functions in PIL & MINGW, fixes #538
+ [aclark4life]
+
+- Merge from Philippe Lagadec’s OleFileIO_PL fork #512
+ [vadmium]
+
+- Fix ImageColor.getcolor #534
+ [homm]
+
+- Make ICO files work with the ImageFile.Parser interface #525 (fixes #522)
+ [wiredfool]
+
+- Handle 32bit compiled python on 64bit architecture #521
+ [choppsv1]
+
+- Fix support for characters >128 using .pcf or .pil fonts in Py3k #517 (fixes #505)
+ [wiredfool]
+
+- Skip CFFI test earlier if it's not installed #516
+ [wiredfool]
+
+- Fixed opening and saving odd sized .pcx files #535 (fixes #523)
+ [wiredfool]
+
+- Fixed palette handling when converting from mode P->RGB->P
+ [d-schmidt]
+
+- Fixed saving mode P image as a PNG with transparency = palette color 0
+ [d-schmidt]
+
+- Improve heuristic used when saving progressive and optimized JPEGs with high quality values #504
+ [e98cuenc]
+
+- Fixed DOS with invalid palette size or invalid image size in BMP file
+ [wiredfool]
+
+- Added support for BMP version 4 and 5
+ [eddwardo, wiredfool]
+
+- Fix segfault in getfont when passed a memory resident font
+ [wiredfool]
+
+- Fix crash on Saving a PNG when icc-profile is None #496
+ [brutasse]
+
+- Cffi+Python implementation of the PixelAccess object
+ [wiredfool]
+
+- PixelAccess returns unsigned ints for I16 mode
+ [wiredfool]
+
+- Minor patch on booleans + Travis #474
+ [sciunto]
+
+- Look in multiarch paths in GNU platforms #511
+ [pinotree]
+
+- Add arch support for pcc64, s390, s390x, armv7l, aarch64 #475
+ [manisandro]
+
+- Add arch support for ppc
+ [wiredfool]
+
+- Correctly quote file names for WindowsViewer command
+ [cgohlke]
+
+- Prefer homebrew freetype over X11 freetype (but still allow both) #466
+ [dmckeone]
+
+2.3.2 (2014-08-13)
+------------------
+
+- Fixed CVE-2014-3589, a DOS in the IcnsImagePlugin (backport)
+ [Andrew Drake]
+
+2.3.1 (2014-03-14)
+------------------
+
+- Fix insecure use of tempfile.mktemp (CVE-2014-1932 CVE-2014-1933)
+ [wiredfool]
+
+2.3.0 (2014-01-01)
+------------------
+
+- Stop leaking filename parameter passed to getfont #459
+ [jpharvey]
+
+- Report availability of LIBTIFF during setup and selftest
+ [cgohlke]
+
+- Fix msvc build error C1189: "No Target Architecture" #460
+ [cgohlke]
+
+- Fix memory leak in font_getsize
+ [wiredfool]
+
+- Correctly prioritize include and library paths #442
+ [ohanar]
+
+- Image.point fixes for numpy.array and docs #441
+ [wiredfool]
+
+- Save the transparency header by default for PNGs #424
+ [wiredfool]
+
+- Support for PNG tRNS header when converting from RGB->RGBA #423
+ [wiredfool]
+
+- PyQT5 Support #418
+ [wiredfool]
+
+- Updates for saving color tiffs w/compression using libtiff #417
+ [wiredfool]
+
+- 2gigapix image fixes and redux
+ [wiredfool]
+
+- Save arbitrary tags in Tiff image files #369
+ [wiredfool]
+
+- Quote filenames and title before using on command line #398
+ [tmccombs]
+
+- Fixed Viewer.show to return properly #399
+ [tmccombs]
+
+- Documentation fixes
+ [wiredfool]
+
+- Fixed memory leak saving images as webp when webpmux is available #429
+ [cezarsa]
+
+- Fix compiling with FreeType 2.5.1 #427
+ [stromnov]
+
+- Adds directories for NetBSD #411
+ [deepy]
+
+- Support RGBA TIFF with missing ExtraSamples tag #393
+ [cgohlke]
+
+- Lossless WEBP Support #390
+ [wiredfool]
+
+- Take compression as an option in the save call for tiffs #389
+ [wiredfool]
+
+- Add support for saving lossless WebP. Just pass 'lossless=True' to save() #386
+ [liftoff]
+
+- LCMS support upgraded from version 1 to version 2 #380 (fixes #343)
+ [wiredfool]
+
+- Added more raw decoder 16 bit pixel formats #379
+ [svanheulen]
+
+- Document remaining Image* modules listed in PIL handbook
+ [irksep]
+
+- Document ImageEnhance, ImageFile, ImageFilter, ImageFont, ImageGrab, ImageMath, and ImageOps
+ [irksep]
+
+- Port and update docs for Image, ImageChops, ImageColor, and ImageDraw
+ [irksep]
+
+- Move or copy content from README.rst to docs/
+ [irksep]
+
+- Respect CFLAGS/LDFLAGS when searching for headers/libs
+ [iElectric]
+
+- Port PIL Handbook tutorial and appendices
+ [irksep]
+
+- Alpha Premultiplication support for transform and resize #364
+ [wiredfool]
+
+- Fixes to make Pypy 2.1.0 work on Ubuntu 12.04/64 #359
+ [wiredfool]
+
+2.2.2 (2013-12-11)
+------------------
+
+- Fix compiling with FreeType 2.5.1 #427
+ [stromnov]
+
+2.2.1 (2013-10-02)
+------------------
+
+- Error installing Pillow 2.2.0 on Mac OS X (due to hard dep on brew) #357 (fixes #356)
+ [wiredfool]
+
+2.2.0 (2013-10-02)
+------------------
+
+- Bug in image transformations resulting from uninitialized memory #348 (fixes #254)
+ [nikmolnar]
+
+- Fix for encoding of b_whitespace #346 (similar to closed issue #272)
+ [mhogg]
+
+- Add numpy array interface support for 16 and 32 bit integer modes #347 (fixes #273)
+ [cgohlke]
+
+- Partial fix for #290: Add preliminary support for TIFF tags.
+ [wiredfool]
+
+- Fix #251 and #326: circumvent classification of pngtest_bad.png as malware
+ [cgohlke]
+
+- Add typedef uint64_t for MSVC #339
+ [cgohlke]
+
+- setup.py: better support for C_INCLUDE_PATH, LD_RUN_PATH, etc. #336 (fixes #329)
+ [nu774]
+
+- _imagingcms.c: include windef.h to fix build issue on MSVC #335 (fixes #328)
+ [nu774]
+
+- Automatically discover homebrew include/ and lib/ paths on OS X #330
+ [donspaulding]
+
+- Fix bytes which should be bytearray #325
+ [manisandro]
+
+- Add respective paths for C_INCLUDE_PATH, LD_RUN_PATH (rpath) to build
+ if specified as environment variables #324
+ [seanupton]
+
+- Fix #312 + gif optimize improvement
+ [d-schmidt]
+
+- Be more tolerant of tag read failures #320
+ [ericbuehl]
+
+- Catch truncated zTXt errors #321 (fixes #318)
+ [vytisb]
+
+- Fix IOError when saving progressive JPEGs #313
+ [e98cuenc]
+
+- Add RGBA support to ImageColor #309
+ [yoavweiss]
+
+- Test for ``str``, not ``"utf-8"`` #306 (fixes #304)
+ [mjpieters]
+
+- Fix missing import os in _util.py #303
+ [mnowotka]
+
+- Added missing exif tags #300
+ [freyes]
+
+- Fail on all import errors #298, #299 (fixes #297)
+ [macfreek, wiredfool]
+
+- Fixed Windows fallback (wasn't using correct file in Windows fonts) #295
+ [lmollea]
+
+- Moved ImageFile and ImageFileIO comments to docstrings #293
+ [freyes]
+
+- Restore compatibility with ISO C #289
+ [cgohlke]
+
+- Use correct format character for C int type #288
+ [cgohlke]
+
+- Allocate enough memory to hold pointers in encode.c #287
+ [cgohlke]
+
+- Fillorder double shuffling bug when FillOrder ==2 and decoding using libtiff #284 (fixes #279)
+ [wiredfool]
+
+- Moved Image module comments to docstrings.
+ [freyes]
+
+- Add 16-bit TIFF support #277 (fixes #274)
+ [wiredfool]
+
+- Ignore high ascii characters in string.whitespace #276 (fixes #272)
+ [wiredfool]
+
+- Added clean/build to tox to make it behave like Travis #275
+ [freyes]
+
+- Adding support for metadata in webp images #271
+ [heynemann]
+
+2.1.0 (2013-07-02)
+------------------
+
+- Add /usr/bin/env python shebangs to all scripts in /Scripts #197
+ [mgorny]
+
+- Add several TIFF decoders and encoders #268
+ [megabuz]
+
+- Added support for alpha transparent webp images.
+
+- Adding Python 3 support for StringIO.
+
+- Adding Python3 basestring compatibility without changing basestring.
+
+- Fix webp encode errors on win-amd64 #259
+ [cgohlke]
+
+- Better fix for ZeroDivisionError in ImageOps.fit for image.size height is 1 #267
+ [chrispbailey]
+
+- Better support for ICO images.
+
+- Changed PY_VERSION_HEX #190 (fixes #166)
+
+- Changes to put everything under the PIL namespace #191
+ [wiredfool]
+
+- Changing StringIO to BytesIO.
+
+- Cleanup whitespace.
+ [Arfrever]
+
+- Don't skip 'import site' on initialization when running tests for inplace builds.
+ [cgohlke]
+
+- Enable warnings for test suite #227
+ [wiredfool]
+
+- Fix for ZeroDivisionError in ImageOps.fit for image.size == (1,1) #255
+ [pterk]
+
+- Fix for if isinstance(filter, collections.Callable) crash. Python bug #7624 on <2.6.6
+
+- Remove double typedef declaration #194 (fixes #193)
+ [evertrol]
+
+- Fix msvc compile errors (#230).
+
+- Fix rendered characters have been chipped for some TrueType fonts
+ [tk0miya]
+
+- Fix usage of pilfont.py script #184
+ [fabiomcosta]
+
+- Fresh start for docs, generated by sphinx-apidoc.
+
+- Introduce --enable-x and fail if it is given and x is not available.
+
+- Partial work to add a wrapper for WebPGetFeatures to correctly support #220 (fixes #204)
+
+- Significant performance improvement of ``alpha_composite`` function #156
+ [homm]
+
+- Support explicitly disabling features via --disable-* options #240
+ [mgorny]
+
+- Support selftest.py --installed, fixes #263
+
+- Transparent WebP Support #220 (fixes #204)
+ [euangoddard, wiredfool]
+
+- Use PyCapsule for py3.1 #238 (fixes #237)
+ [wiredfool]
+
+- Workaround for: https://bugs.python.org/issue16754 in 3.2.x < 3.2.4 and 3.3.0.
+
+2.0.0 (2013-03-15)
+------------------
+
+.. Note:: Special thanks to Christoph Gohlke and Eric Soroos for assisting with a pre-PyCon 2013 release!
+
+- Many other bug fixes and enhancements by many other people.
+
+- Add Python 3 support. (Pillow >= 2.0.0 supports Python 2.6, 2.7, 3.2, 3.3. Pillow < 2.0.0 supports Python 2.4, 2.5, 2.6, 2.7.)
+ [fluggo]
+
+- Add PyPy support (experimental, please see #67)
+
+- Add WebP support #96
+ [lqs]
+
+- Add Tiff G3/G4 support (experimental)
+ [wiredfool]
+
+- Backport PIL's PNG/Zip improvements #95, #97
+ [olt]
+
+- Various 64-bit and Windows fixes.
+ [cgohlke]
+
+- Add testing suite.
+ [cgohlke, fluggo]
+
+- Added support for PNG images with transparency palette.
+ [d-schmidt]
+
+1.7.8 (2012-11-01)
+------------------
+
+- Removed doctests.py that made tests of other packages fail.
+ [thomasdesvenain]
+
+- Fix opening psd files with RGBA layers when A mode is not of type 65535 but 3.
+ Fixes #3
+ [thomasdesvenain]
+
+
+1.7.7 (2012-04-04)
+------------------
+
+- UNDEF more types before including windows headers
+ [mattip]
+
+1.7.6 (2012-01-20)
+------------------
+
+- Bug fix: freetype not found on Mac OS X with case-sensitive filesystem
+ [gjo]
+
+- Bug fix: Backport fix to split() after open() (regression introduced in PIL 1.1.7).
+ [sfllaw]
+
+1.7.5 (2011-09-07)
+------------------
+
+- Fix for sys.platform = "linux3"
+ [blueyed]
+
+- Package cleanup and additional documentation
+ [aclark4life]
+
+1.7.4 (2011-07-21)
+------------------
+
+- Fix brown bag release
+ [aclark4life]
+
+1.7.3 (2011-07-20)
+------------------
+
+- Fix : resize need int values, append int conversion in thumbnail method
+ [harobed]
+
+1.7.2 (2011-06-02)
+------------------
+
+- Bug fix: Python 2.4 compat
+ [aclark4life]
+
+1.7.1 (2011-05-31)
+------------------
+
+- More multi-arch support
+ [SteveM, regebro, barry, aclark4life]
+
+1.7.0 (2011-05-27)
+------------------
+
+- Add support for multi-arch library directory /usr/lib/x86_64-linux-gnu
+ [aclark4life]
+
+1.6 (12/01/2010)
+----------------
+
+- Bug fix: /usr/x11/include should be added to include_dirs not library_dirs
+ [elro]
+
+- Doc fixes
+ [aclark4life]
+
+1.5 (11/28/2010)
+----------------
+
+- Module and package fixes
+ [aclark4life]
+
+1.4 (11/28/2010)
+----------------
+
+- Doc fixes
+ [aclark4life]
+
+1.3 (11/28/2010)
+----------------
+
+- Add support for /lib64 and /usr/lib64 library directories on Linux
+ [aclark4life]
+
+- Doc fixes
+ [aclark4life]
+
+1.2 (08/02/2010)
+----------------
+
+- On OS X also check for freetype2 in the X11 path
+ [jezdez]
+
+- Doc fixes
+ [aclark4life]
+
+1.1 (07/31/2010)
+----------------
+
+- Removed setuptools_hg requirement
+ [aclark4life]
+
+- Doc fixes
+ [aclark4life]
+
+1.0 (07/30/2010)
+----------------
+
+- Remove support for ``import Image``, etc. from the standard namespace. ``from PIL import Image`` etc. now required.
+- Forked PIL based on `Hanno Schlichting's re-packaging <https://dist.plone.org/thirdparty/PIL-1.1.7.tar.gz>`_
+ [aclark4life]
+
+Pre-fork
+--------
+
+0.2b5-1.1.7
++++++++++++
+
+::
+
+ -*- coding: utf-8 -*-
+
+ The Python Imaging Library
+ $Id$
+
+ ACKNOWLEDGEMENTS: PIL wouldn't be what it is without the help of:
+ David Ascher, Phil Austin, Douglas Bagnall, Larry Bates, Anthony
+ Baxter, William Baxter, Denis Benoit, Jan Blom, Duncan Booth, Alexey
+ Borzenkov, Jeff Breidenbach, Roger Burnham, Zac Burns, Gene Cash,
+ Kevin Cazabon, Fred Clare, Greg Coats, Chris Cogdon, Greg Couch, Bill
+ Crutchfield, Abel Deuring, Tim Docker, Fred Drake, Graham Dumpleton,
+ Matthew Ellis, Eric Etheridge, Daniel Fetchinson, Robin Friedrich,
+ Pier Paolo Glave, Federico Di Gregorio, Markus Gritsch, Daniel
+ Haertle, Greg Hamilton, Mark Hammond, Bernhard Herzog, Rob Hooft, Bob
+ Ippolito, Jack Jansen, Bill Janssen, Edward Jones, Richard Jones,
+ HÃ¥kan Karlsson, Robert Kern, David Kirtley, Bob Klimek, Matthias
+ Klose, Andrew Kuchling, Magnus Källström, Victor Lacina, Ben Last,
+ Hamish Lawson, Cesare Leonardi, Andrew MacIntyre, Jan Matejek, Naveen
+ Michaud-Agrawal, Gordon McMillan, Skip Montanaro, Fredrik Nehr,
+ Russell Nelson, Luciano Nocera, Travis Oliphant, Piet van Oostrum,
+ Richard Oudkerk, Paul Pharr, Andres Polit, Conrado Porto Lopes Gouvêa,
+ Eric Raymond, Victor Reijs, Bertil Reinhammar, Nicholas Riley, Don
+ Rozenberg, Toby Sargeant, Barry Scott, Les Schaffer, Joel Shprentz,
+ Klamer Shutte, Gene Skonicki, Niki Spahiev, D. Alan Stewart, Perry
+ Stoll, Paul Svensson, Ulrik Svensson, Miki Tebeka, Michael van
+ Tellingen, Ivan Tkatchev, Dan Torop, Adam Twardoch, Rune Uhlin, Dmitry
+ Vasiliev, Sasha Voynow, Charles Waldman, Collin Winter, Dan Wolfe,
+ Ka-Ping Yee, and many others (if your name should be on this list, let
+ me know.)
+
+ *** Changes from release 1.1.6 to 1.1.7 ***
+
+ This section may not be fully complete. For changes since this file
+ was last updated, see the repository revision history:
+
+ https://bitbucket.org/effbot/pil-2009-raclette/commits/all
+
+ (1.1.7 final)
+
+ + Set GIF loop info property to the number of iterations if a NETSCAPE
+ loop extension is present, instead of always setting it to 1 (from
+ Valentino Volonghi).
+
+ (1.1.7c1 released)
+
+ + Improved PNG compression (from Alexey Borzenkov).
+
+ + Read interlaced PNG files (from Conrado Porto Lopes Gouvêa)
+
+ + Added various TGA improvements from Alexey Borzenkov, including
+ support for specifying image orientation.
+
+ + Bumped block threshold to 16 megabytes, made size estimation a bit
+ more accurate. This speeds up allocation of large images.
+
+ + Fixed rounding error in ImagingDrawWideLine.
+
+ "gormish" writes: ImagingDrawWideLine() in Draw.c has a bug in every
+ version I've seen, which leads to different width lines depending on
+ the order of the points in the line. This is especially bad at some
+ angles where a 'width=2' line can completely disappear.
+
+ + Added support for RGBA mode to the SGI module (based on code by
+ Karsten Hiddemann).
+
+ + Handle repeated IPTC tags (adapted from a patch by Eric Bruning).
+
+ Eric writes: According to the specification, some IPTC tags can be
+ repeated, e.g., tag 2:25 (keywords). PIL 1.1.6 only retained the last
+ instance of that tag. Below is a patch to store all tags. If there are
+ multiple tag instances, they are stored in a (python) list. Single tag
+ instances remain as strings.
+
+ + Fixed potential crash in ImageFilter for small target images
+ (reported by Zac Burns and Daniel Fetchinson).
+
+ + Use BMP instead of JPEG as temporary show format on Mac OS X.
+
+ + Fixed putpixel/new for I;16 with colors > 255.
+
+ + Added integer power support to ImagingMath.
+
+ + Added limited support for I;16L mode (explicit little endian).
+
+ + Moved WMF support into Image.core; enable WMF rendering by default
+ if renderer is available.
+
+ + Mark the ARG plugin as obsolete.
+
+ + Added version query mechanism to ImageCms and ImageFont, for
+ debugging.
+
+ + Added (experimental) ImageCms function for fetching the ICC profile
+ for the current display (currently Windows only).
+
+ Added HWND/HDC support to ImageCms.get_display_profile().
+
+ + Added WMF renderer (Windows only).
+
+ + Added ImagePointHandler and ImageTransformHandler mixins; made
+ ImageCmsTransform work with im.point.
+
+ + Fixed potential endless loop in the XVThumbnail reader (from Nikolai
+ Ugelvik).
+
+ + Added Kevin Cazabon's pyCMS package.
+
+ The C code has been moved to _imagingcms.c, the Python interface
+ module is installed as PIL.ImageCMS.
+
+ Added support for in-memory ICC profiles.
+
+ Unified buildTransform and buildTransformFromOpenProfiles.
+
+ The profile can now be either a filename, a profile object, or a
+ file-like object containing an in-memory profile.
+
+ Additional fixes from Florian Böch:
+
+ Very nice - it just needs LCMS flags support so we can use black
+ point compensation and softproofing :) See attached patches. They
+ also fix a naming issue which could cause confusion - display
+ profile (ImageCms wording) actually means proof profile (lcms
+ wording), so I changed variable names and docstrings where
+ applicable. Patches are tested under Python 2.6.
+
+ + Improved support for layer names in PSD files (from Sylvain Baubeau)
+
+ Sylvain writes: I needed to be able to retrieve the names of the
+ layers in a PSD files. But PsdImagePlugin.py didn't do the job so I
+ wrote this very small patch.
+
+ + Improved RGBA support for ImageTk for 8.4 and newer (from Con
+ Radchenko).
+
+ This replaces the slow run-length based encoding model with true
+ compositing at the Tk level.
+
+ + Added support for 16- and 32-bit images to McIdas loader.
+
+ Based on file samples and stand-alone reader code provided by Craig
+ Swank.
+
+ + Added ImagePalette support to putpalette.
+
+ + Fixed problem with incremental parsing of PNG files.
+
+ + Make selftest.py report non-zero status on failure (from Mark
+ Sienkiewicz)
+
+ + Add big endian save support and multipage infrastructure to the TIFF
+ writer (from Sebastian Haase).
+
+ + Handle files with GPS IFD but no basic EXIF IFD (reported by Kurt
+ Schwehr).
+
+ + Added zTXT support (from Andrew Kuchling via Lowell Alleman).
+
+ + Fixed potential infinite loop bug in ImageFont (from Guilherme Polo).
+
+ + Added sample ICC profiles (from Kevin Cazabon)
+
+ + Fixed array interface for I, F, and RGBA/RGBX images.
+
+ + Added Chroma subsampling support for JPEG (from Justin Huff).
+
+ Justin writes: Attached is a patch (against PIL 1.1.6) to provide
+ control over the chroma subsampling done by the JPEG encoder. This
+ is often useful for reducing compression artifacts around edges of
+ clipart and text.
+
+ + Added USM/Gaussian Blur code from Kevin Cazabon.
+
+ + Fixed bug w. uninitialized image data when cropping outside the
+ source image.
+
+ + Use ImageShow to implement the Image.show method.
+
+ Most notably, this picks the 'display' utility when available. It
+ also allows application code to register new display utilities via
+ the ImageShow registry.
+
+ + Release the GIL in the PNG compressor (from Michael van Tellingen).
+
+ + Revised JPEG CMYK handling.
+
+ Always assume Adobe behaviour, both when reading and writing (based on
+ a patch by Kevin Cazabon, and test data by Tim V. and Charlie Clark, and
+ additional debugging by Michael van Tellingen).
+
+ + Support for preserving ICC profiles (by Florian Böch via Tim Hatch).
+
+ Florian writes:
+
+ It's a beta, so still needs some testing, but should allow you to:
+ - retain embedded ICC profiles when saving from/to JPEG, PNG, TIFF.
+ Existing code doesn't need to be changed.
+ - access embedded profiles in JPEG, PNG, PSD, TIFF.
+
+ It also includes patches for TIFF to retain IPTC, Photoshop and XMP
+ metadata when saving as TIFF again, read/write TIFF resolution
+ information correctly, and to correct inverted CMYK JPEG files.
+
+ + Fixed potential memory leak in median cut quantizer (from Evgeny Salmin).
+
+ + Fixed OverflowError when reading upside-down BMP images.
+
+ + Added resolution save option for PDF files.
+
+ Andreas Kostyrka writes: I've included a patched PdfImagePlugin.py
+ based on 1.1.6 as included in Ubuntu, that supports a "resolution"
+ save option. Not great, but it makes the PDF saving more useful by
+ allowing PDFs that are not exactly 72dpi.
+
+ + Look for Tcl/Tk include files in version-specific include directory
+ (from Encolpe Degoute).
+
+ + Fixed grayscale rounding error in ImageColor.getcolor (from Tim
+ Hatch).
+
+ + Fixed calculation of mean value in ImageEnhance.Contrast (reported
+ by "roop" and Scott David Daniels).
+
+ + Fixed truetype positioning when first character has a negative left
+ bearing (from Ned Batchelder):
+
+ Ned writes: In PIL 1.1.6, ImageDraw.text will position the string
+ incorrectly if the first character has a negative left bearing. To
+ see the problem, show a string like "///" in an italic font. The
+ first slash will be clipped at the left, and the string will be
+ mis-positioned.
+
+ + Fixed resolution unit bug in tiff reader/writer (based on code by
+ Florian Höch, Gary Bloom, and others).
+
+ + Added simple transparency support for RGB images (reported by
+ Sebastian Spaeth).
+
+ + Added support for Unicode filenames in ImageFont.truetype (from Donn
+ Ingle).
+
+ + Fixed potential crash in ImageFont.getname method (from Donn Ingle).
+
+ + Fixed encoding issue in PIL/WalImageFile (from Santiago M. Mola).
+
+ *** Changes from release 1.1.5 to 1.1.6 ***
+
+ (1.1.6 released)
+
+ + Fixed some 64-bit compatibility warnings for Python 2.5.
+
+ + Added threading support for the Sane driver (from Abel Deuring).
+
+ (1.1.6b2 released)
+
+ + Added experimental "floodfill" function to the ImageDraw module
+ (based on code by Eric Raymond).
+
+ + The default arguments for "frombuffer" doesn't match "fromstring"
+ and the documentation; this is a bug, and will most likely be fixed
+ in a future version. In this release, PIL prints a warning message
+ instead. To silence the warning, change any calls of the form
+ "frombuffer(mode, size, data)" to
+
+ frombuffer(mode, size, data, "raw", mode, 0, 1)
+
+ + Added "fromarray" function, which takes an object implementing the
+ NumPy array interface and creates a PIL Image from it. (from Travis
+ Oliphant).
+
+ + Added NumPy array interface support (__array_interface__) to the
+ Image class (based on code by Travis Oliphant).
+
+ This allows you to easily convert between PIL image memories and
+ NumPy arrays:
+
+ import numpy, Image
+
+ im = Image.open('hopper.jpg')
+
+ a = numpy.asarray(im) # a is readonly
+
+ im = Image.fromarray(a)
+
+ + Fixed CMYK polarity for JPEG images, by treating all images as
+ "Adobe CMYK" images. (thanks to Cesare Leonardi and Kevin Cazabon
+ for samples, debugging, and patches).
+
+ (1.1.6b1 released)
+
+ + Added 'expand' option to the Image 'rotate' method. If true, the
+ output image is made large enough to hold the entire rotated image.
+
+ + Changed the ImageDraw 'line' method to always draw the last pixel in
+ a polyline, independent of line angle.
+
+ + Fixed bearing calculation and clipping in the ImageFont truetype
+ renderer; this could lead to clipped text, or crashes in the low-
+ level _imagingft module. (based on input from Adam Twardoch and
+ others).
+
+ + Added ImageQt wrapper module, for converting PIL Image objects to
+ QImage objects in an efficient way.
+
+ + Fixed 'getmodebands' to return the number of bands also for "PA"
+ and "LA" modes. Added 'getmodebandnames' helper that return the
+ band names.
+
+ (1.1.6a2 released)
+
+ + Added float/double support to the TIFF loader (from Russell
+ Nelson).
+
+ + Fixed broken use of realloc() in path.c (from Jan Matejek)
+
+ + Added save support for Spider images (from William Baxter).
+
+ + Fixed broken 'paste' and 'resize' operations in pildriver
+ (from Bill Janssen).
+
+ + Added support for duplex scanning to the Sane interface (Abel
+ Deuring).
+
+ (1.1.6a1 released)
+
+ + Fixed a memory leak in "convert(mode)", when converting from
+ L to P.
+
+ + Added pixel access object. The "load" method now returns a
+ access object that can be used to directly get and set pixel
+ values, using ordinary [x, y] notation:
+
+ pixel = im.load()
+ v = pixel[x, y]
+ pixel[x, y] = v
+
+ If you're accessing more than a few pixels, this is a lot
+ faster than using getpixel/putpixel.
+
+ + Fixed building on Cygwin (from Miki Tebeka).
+
+ + Fixed "point(callable)" on unloaded images (reported by HÃ¥kan
+ Karlsson).
+
+ + Fixed size bug in ImageWin.ImageWindow constructor (from Victor
+ Reijs)
+
+ + Fixed ImageMath float() and int() operations for Python 2.4
+ (reported by Don Rozenberg).
+
+ + Fixed "RuntimeError: encoder error -8 in tostring" problem for
+ wide "RGB", "I", and "F" images.
+
+ + Fixed line width calculation.
+
+ (1.1.6a0 released)
+
+ + Fixed byte order issue in Image.paste(ink) (from Ka-Ping Yee).
+
+ + Fixed off-by-0.5 errors in the ANTIALIAS code (based on input
+ from Douglas Bagnall).
+
+ + Added buffer interface support to the Path constructor. If
+ a buffer is provided, it is assumed to contain a flat array
+ of float coordinates (e.g. array.array('f', seq)).
+
+ + Added new ImageMath module.
+
+ + Fixed ImageOps.equalize when used with a small number of distinct
+ values (reported by David Kirtley).
+
+ + Fixed potential integer division in PSDraw.image (from Eric Etheridge).
+
+ *** Changes from release 1.1 to 1.1.5 ***
+
+ (1.1.5c2 and 1.1.5 final released)
+
+ + Added experimental PERSPECTIVE transform method (from Jeff Breiden-
+ bach).
+
+ (1.1.5c1 released)
+
+ + Make sure "thumbnail" never generates zero-wide or zero-high images
+ (reported by Gene Skonicki)
+
+ + Fixed a "getcolors" bug that could result in a zero count for some
+ colors (reported by Richard Oudkerk).
+
+ + Changed default "convert" palette to avoid "rounding errors" when
+ round-tripping white source pixels (reported by Henryk Gerlach and
+ Jeff Epler).
+
+ (1.1.5b3 released)
+
+ + Don't crash in "quantize" method if the number of colors requested
+ is larger than 256. This release raises a ValueError exception;
+ future versions may return a mode "RGB" image instead (reported
+ by Richard Oudkerk).
+
+ + Added WBMP read/write support (based on code by Duncan Booth).
+
+ (1.1.5b2 released)
+
+ + Added DPI read/write support to the PNG codec. The decoder sets
+ the info["dpi"] attribute for PNG files with appropriate resolution
+ settings. The encoder uses the "dpi" option (based on code by Niki
+ Spahiev).
+
+ + Added limited support for "point" mappings from mode "I" to mode "L".
+ Only 16-bit values are supported (other values are clipped), the lookup
+ table must contain exactly 65536 entries, and the mode argument must be
+ set to "L".
+
+ + Added support for Mac OS X icns files (based on code by Bob Ippolito).
+
+ + Added "ModeFilter" support to the ImageFilter module.
+
+ + Added support for Spider images (from William Baxter). See the
+ comments in PIL/SpiderImagePlugin.py for more information on this
+ format.
+
+ (1.1.5b1 released)
+
+ + Added new Sane release (from Ralph Heinkel). See the Sane/README
+ and Sane/CHANGES files for more information.
+
+ + Added experimental PngInfo chunk container to the PngImageFile
+ module. This can be used to add arbitrary chunks to a PNG file.
+ Create a PngInfo instance, use "add" or "add_text" to add chunks,
+ and pass the instance as the "pnginfo" option when saving the
+ file.
+
+ + Added "getpalette" method. This returns the palette as a list,
+ or None if the image has no palette. To modify the palette, use
+ "getpalette" to fetch the current palette, modify the list, and
+ put it back using "putpalette".
+
+ + Added optional flattening to the ImagePath "tolist" method.
+ tolist() or tolist(0) returns a list of 2-tuples, as before.
+ tolist(1) returns a flattened list instead.
+
+ (1.1.5a5 released)
+
+ + Fixed BILINEAR/BICUBIC/ANTIALIAS filtering for mode "LA".
+
+ + Added "getcolors()" method. This is similar to the existing histo-
+ gram method, but looks at color values instead of individual layers,
+ and returns an unsorted list of (count, color) tuples.
+
+ By default, the method returns None if finds more than 256 colors.
+ If you need to look for more colors, you can pass in a limit (this
+ is used to allocate internal tables, so you probably don't want to
+ pass in too large values).
+
+ + Build improvements: Fixed building under AIX, improved detection of
+ FreeType2 and Mac OS X framework libraries, and more. Many thanks
+ to everyone who helped test the new "setup.py" script!
+
+ (1.1.5a4 released)
+
+ + The "save" method now looks for a file format driver before
+ creating the file.
+
+ + Don't use antialiased truetype fonts when drawing in mode "P", "I",
+ and "F" images.
+
+ + Rewrote the "setup.py" file. The new version scans for available
+ support libraries, and configures both the libImaging core library
+ and the bindings in one step.
+
+ To use specific versions of the libraries, edit the ROOT variables
+ in the setup.py file.
+
+ + Removed threaded "show" viewer; use the old "show" implementation
+ instead (Windows).
+
+ + Added deprecation warnings to Image.offset, ImageDraw.setink, and
+ ImageDraw.setfill.
+
+ + Added width option to ImageDraw.line(). The current implementation
+ works best for straight lines; it does not support line joins, so
+ polylines won't look good.
+
+ + ImageDraw.Draw is now a factory function instead of a class. If
+ you need to create custom draw classes, inherit from the ImageDraw
+ class. All other code should use the factory function.
+
+ + Fixed loading of certain PCX files (problem reported by Greg
+ Hamilton, who also provided samples).
+
+ + Changed _imagingft.c to require FreeType 2.1 or newer. The
+ module can still be built with earlier versions; see comments
+ in _imagingft.c for details.
+
+ (1.1.5a3 released)
+
+ + Added 'getim' method, which returns a PyCObject wrapping an
+ Imaging pointer. The description string is set to IMAGING_MAGIC.
+ See Imaging.h for pointer and string declarations.
+
+ + Fixed reading of TIFF JPEG images (problem reported by Ulrik
+ Svensson).
+
+ + Made ImageColor work under Python 1.5.2
+
+ + Fixed division by zero "equalize" on very small images (from
+ Douglas Bagnall).
+
+ (1.1.5a2 released)
+
+ + The "paste" method now supports the alternative "paste(im, mask)"
+ syntax (in this case, the box defaults to im's bounding box).
+
+ + The "ImageFile.Parser" class now works also for PNG files with
+ more than one IDAT block.
+
+ + Added DPI read/write to the TIFF codec, and fixed writing of
+ rational values. The decoder sets the info["dpi"] attribute
+ for TIFF files with appropriate resolution settings. The
+ encoder uses the "dpi" option.
+
+ + Disable interlacing for small (or narrow) GIF images, to
+ work around what appears to be a hard-to-find bug in PIL's
+ GIF encoder.
+
+ + Fixed writing of mode "P" PDF images. Made mode "1" PDF
+ images smaller.
+
+ + Made the XBM reader a bit more robust; the file may now start
+ with a few whitespace characters.
+
+ + Added support for enhanced metafiles to the WMF driver. The
+ separate PILWMF kit lets you render both placeable WMF files
+ and EMF files as raster images. See
+
+ http://effbot.org/downloads#pilwmf
+
+ (1.1.5a1 released)
+
+ + Replaced broken WMF driver with a WMF stub plugin (see below).
+
+ + Fixed writing of mode "1", "L", and "CMYK" PDF images (based on
+ input from Nicholas Riley and others).
+
+ + Fixed adaptive palette conversion for zero-width or zero-height
+ images (from Chris Cogdon)
+
+ + Fixed reading of PNG images from QuickTime 6 (from Paul Pharr)
+
+ + Added support for StubImageFile plugins, including stub plugins
+ for BUFR, FITS, GRIB, and HDF5 files. A stub plugin can identify
+ a given file format, but relies on application code to open and
+ save files in that format.
+
+ + Added optional "encoding" argument to the ImageFont.truetype
+ factory. This argument can be used to specify non-Unicode character
+ maps for fonts that support that. For example, to draw text using
+ the Microsoft Symbol font, use:
+
+ font = ImageFont.truetype("symbol.ttf", 16, encoding="symb")
+ draw.text((0, 0), unichr(0xF000 + 0xAA))
+
+ (note that the symbol font uses characters in the 0xF000-0xF0FF
+ range)
+
+ Common encodings are "unic" (Unicode), "symb" (Microsoft Symbol),
+ "ADOB" (Adobe Standard), "ADBE" (Adobe Expert), and "armn" (Apple
+ Roman). See the FreeType documentation for more information.
+
+ + Made "putalpha" a bit more robust; you can now attach an alpha
+ layer to a plain "L" or "RGB" image, and you can also specify
+ constant alphas instead of alpha layers (using integers or colour
+ names).
+
+ + Added experimental "LA" mode support.
+
+ An "LA" image is an "L" image with an attached transparency layer.
+ Note that support for "LA" is not complete; some operations may
+ fail or produce unexpected results.
+
+ + Added "RankFilter", "MinFilter", "MedianFilter", and "MaxFilter"
+ classes to the ImageFilter module.
+
+ + Improved support for applications using multiple threads; PIL
+ now releases the global interpreter lock for many CPU-intensive
+ operations (based on work by Kevin Cazabon).
+
+ + Ignore Unicode characters in the PCF loader (from Andres Polit)
+
+ + Fixed typo in OleFileIO.loadfat, which could affect loading of
+ FlashPix and Image Composer images (Daniel Haertle)
+
+ + Fixed building on platforms that have Freetype but don't have
+ Tcl/Tk (Jack Jansen, Luciano Nocera, Piet van Oostrum and others)
+
+ + Added EXIF GPSInfo read support for JPEG files. To extract
+ GPSInfo information, open the file, extract the exif dictionary,
+ and check for the key 0x8825 (GPSInfo). If present, it contains
+ a dictionary mapping GPS keys to GPS values. For a list of keys,
+ see the EXIF specification.
+
+ The "ExifTags" module contains a GPSTAGS dictionary mapping GPS
+ tags to tag names.
+
+ + Added DPI read support to the PCX and DCX codecs (info["dpi"]).
+
+ + The "show" methods now uses a built-in image viewer on Windows.
+ This viewer creates an instance of the ImageWindow class (see
+ below) and keeps it running in a separate thread. NOTE: This
+ was disabled in 1.1.5a4.
+
+ + Added experimental "Window" and "ImageWindow" classes to the
+ ImageWin module. These classes allow you to create a WCK-style
+ toplevel window, and use it to display raster data.
+
+ + Fixed some Python 1.5.2 issues (to build under 1.5.2, use the
+ Makefile.pre.in/Setup.in approach)
+
+ + Added support for the TIFF FillOrder tag. PIL can read mode "1",
+ "L", "P" and "RGB" images with non-standard FillOrder (based on
+ input from Jeff Breidenbach).
+
+ (1.1.4 final released)
+
+ + Fixed ImageTk build problem on Unix.
+
+ (1.1.4b2 released)
+
+ + Improved building on Mac OS X (from Jack Jansen).
+
+ + Improved building on Windows with MinGW (from Klamer Shutte).
+
+ + If no font is specified, ImageDraw now uses the embedded default
+ font. Use the "load" or "truetype" methods to load a real font.
+
+ + Added embedded default font to the ImageFont module (currently
+ an 8-pixel Courier font, taken from the X window distribution).
+
+ (1.1.4b1 released)
+
+ + Added experimental EXIF support for JPEG files. To extract EXIF
+ information from a JPEG file, open the file as usual, and call the
+ "_getexif" method. If successful, this method returns a dictionary
+ mapping EXIF TIFF tags to values. If the file does not contain EXIF
+ data, the "_getexif" method returns None.
+
+ The "ExifTags" module contains a dictionary mapping tags to tag
+ names.
+
+ This interface will most likely change in future versions.
+
+ + Fixed a bug when using the "transparency" option with the GIF
+ writer.
+
+ + Added limited support for "bitfield compression" in BMP files
+ and DIB buffers, for 15-bit, 16-bit, and 32-bit images. This
+ also fixes a problem with ImageGrab module when copying screen-
+ dumps from the clipboard on 15/16/32-bit displays.
+
+ + Added experimental WAL (Quake 2 textures) loader. To use this
+ loader, import WalImageFile and call the "open" method in that
+ module.
+
+ (1.1.4a4 released)
+
+ + Added updated SANE driver (Andrew Kuchling, Abel Deuring)
+
+ + Use Python's "mmap" module on non-Windows platforms to read some
+ uncompressed formats using memory mapping. Also added a "frombuffer"
+ function that allows you to access the contents of an existing string
+ or buffer object as if it were an image object.
+
+ + Fixed a memory leak that could appear when processing mode "P"
+ images (from Pier Paolo Glave)
+
+ + Ignore Unicode characters in the BDF loader (from Graham Dumpleton)
+
+ (1.1.4a3 released; windows only)
+
+ + Added experimental RGBA-on-RGB drawing support. To use RGBA
+ colours on an RGB image, pass "RGBA" as the second string to
+ the ImageDraw.Draw constructor.
+
+ + Added support for non-ASCII strings (Latin-1) and Unicode
+ to the truetype font renderer.
+
+ + The ImageWin "Dib" object can now be constructed directly from
+ an image object.
+
+ + The ImageWin module now allows you use window handles as well
+ as device contexts. To use a window handle, wrap the handle in
+ an ImageWin.HWND object, and pass in this object instead of the
+ device context.
+
+ (1.1.4a2 released)
+
+ + Improved support for 16-bit unsigned integer images (mode "I;16").
+ This includes TIFF reader support, and support for "getextrema"
+ and "point" (from Klamer Shutte).
+
+ + Made the BdfFontFile reader a bit more robust (from Kevin Cazabon
+ and Dmitry Vasiliev)
+
+ + Changed TIFF writer to always write Compression tag, even when
+ using the default compression (from Greg Couch).
+
+ + Added "show" support for Mac OS X (from Dan Wolfe).
+
+ + Added clipboard support to the "ImageGrab" module (Windows only).
+ The "grabclipboard" function returns an Image object, a list of
+ filenames (not in 1.1.4), or None if neither was found.
+
+ (1.1.4a1 released)
+
+ + Improved support for drawing RGB data in palette images. You can
+ now use RGB tuples or colour names (see below) when drawing in a
+ mode "P" image. The drawing layer automatically assigns color
+ indexes, as long as you don't use more than 256 unique colours.
+
+ + Moved self test from MiniTest/test.py to ./selftest.py.
+
+ + Added support for CSS3-style color strings to most places that
+ accept colour codes/tuples. This includes the "ImageDraw" module,
+ the Image "new" function, and the Image "paste" method.
+
+ Colour strings can use one of the following formats: "#f00",
+ "#ff0000", "rgb(255,0,0)", "rgb(100%,0%,0%)", "hsl(0, 100%, 50%)",
+ or "red" (most X11-style colour names are supported). See the
+ documentation for the "ImageColor" module for more information.
+
+ + Fixed DCX decoder (based on input from Larry Bates)
+
+ + Added "IptcImagePlugin.getiptcinfo" helper to extract IPTC/NAA
+ newsphoto properties from JPEG, TIFF, or IPTC files.
+
+ + Support for TrueType/OpenType fonts has been added to
+ the standard distribution. You need the freetype 2.0
+ library.
+
+ + Made the PCX reader a bit more robust when reading 2-bit
+ and 4-bit PCX images with odd image sizes.
+
+ + Added "Kernel" class to the ImageFilter module. This class
+ allows you to filter images with user-defined 3x3 and 5x5
+ convolution kernels.
+
+ + Added "putdata" support for mode "I", "F" and "RGB".
+
+ + The GIF writer now supports the transparency option (from
+ Denis Benoit).
+
+ + A HTML version of the module documentation is now shipped
+ with the source code distribution. You'll find the files in
+ the Doc subdirectory.
+
+ + Added support for Palm pixmaps (from Bill Janssen). This
+ change was listed for 1.1.3, but the "PalmImagePlugin" driver
+ didn't make it into the distribution.
+
+ + Improved decoder error messages.
+
+ (1.1.3 final released)
+
+ + Made setup.py look for old versions of zlib. For some back-
+ ground, see: https://zlib.net/advisory-2002-03-11.txt
+
+ (1.1.3c2 released)
+
+ + Added setup.py file (tested on Unix and Windows). You still
+ need to build libImaging/imaging.lib in the traditional way,
+ but the setup.py script takes care of the rest.
+
+ The old Setup.in/Makefile.pre.in build method is still
+ supported.
+
+ + Fixed segmentation violation in ANTIALIAS filter (an internal
+ buffer wasn't properly allocated).
+
+ (1.1.3c1 released)
+
+ + Added ANTIALIAS downsampling filter for high-quality "resize"
+ and "thumbnail" operations. Also added filter option to the
+ "thumbnail" operation; the default value is NEAREST, but this
+ will most likely change in future versions.
+
+ + Fixed plugin loader to be more robust if the __file__
+ variable isn't set.
+
+ + Added seek/tell support (for layers) to the PhotoShop
+ loader. Layer 0 is the main image.
+
+ + Added new (but experimental) "ImageOps" module, which provides
+ shortcuts for commonly used operations on entire images.
+
+ + Don't mess up when loading PNG images if the decoder leaves
+ data in the output buffer. This could cause internal errors
+ on some PNG images, with some versions of ZLIB. (Bug report
+ and patch provided by Bernhard Herzog.)
+
+ + Don't mess up on Unicode filenames.
+
+ + Don't mess up when drawing on big endian platforms.
+
+ + Made the TIFF loader a bit more robust; it can now read some
+ more slightly broken TIFF files (based on input from Ted Wright,
+ Bob Klimek, and D. Alan Stewart)
+
+ + Added OS/2 EMX build files (from Andrew MacIntyre)
+
+ + Change "ImageFont" to reject image files if they don't have the
+ right mode. Older versions could leak memory for "P" images.
+ (Bug reported by Markus Gritsch).
+
+ + Renamed some internal functions to avoid potential build
+ problem on Mac OS X.
+
+ + Added DL_EXPORT where relevant (for Cygwin, based on input
+ from Robert Yodlowski)
+
+ + (re)moved bogus __init__ call in BdfFontFile (bug spotted
+ by Fred Clare)
+
+ + Added "ImageGrab" support (Windows only)
+
+ + Added support for XBM hotspots (based on code contributed by
+ Bernhard Herzog).
+
+ + Added write support for more TIFF tags, namely the Artist,
+ Copyright, DateTime, ResolutionUnit, Software, XResolution and
+ YResolution tags (from Greg Couch)
+
+ + Added TransposedFont wrapper to ImageFont module
+
+ + Added "optimize" flag to GIF encoder. If optimize is present
+ and non-zero, PIL will work harder to create a small file.
+
+ + Raise "EOFError" (not IndexError) when reading beyond the
+ end of a TIFF sequence.
+
+ + Support rewind ("seek(0)") for GIF and TIFF sequences.
+
+ + Load grayscale GIF images as mode "L"
+
+ + Added DPI read/write support to the JPEG codec. The decoder
+ sets the info["dpi"] attribute for JPEG files with JFIF dpi
+ settings. The encoder uses the "dpi" option:
+
+ im = Image.open("file.jpg")
+ dpi = im.info["dpi"] # raises KeyError if DPI not known
+ im.save("out.jpg", dpi=dpi)
+
+ Note that PIL doesn't always preserve the "info" attribute
+ for normal image operations.
+
+ (1.1.2c1 and 1.1.2 final released)
+
+ + Adapted to Python 2.1. Among other things, all uses of the
+ "regex" module have been replaced with "re".
+
+ + Fixed attribute error when reading large PNG files (this bug
+ was introduced in maintenance code released after the 1.1.1
+ release)
+
+ + Ignore non-string objects in sys.path
+
+ + Fixed Image.transform(EXTENT) for negative xoffsets
+
+ + Fixed loading of image plugins if PIL is installed as a package.
+ (The plugin loader now always looks in the directory where the
+ Image.py module itself is found, even if that directory isn't on
+ the standard search path)
+
+ + The Png plugin has been added to the list of preloaded standard
+ formats
+
+ + Fixed bitmap/text drawing in fill mode.
+
+ + Fixed "getextrema" to work also for multiband images.
+
+ + Added transparency support for L and P images to the PNG codec.
+
+ + Improved support for read-only images. The "load" method now
+ sets the "readonly" attribute for memory-mapped images. Operations
+ that modifies an image in place (such as "paste" and drawing operations)
+ creates an in-memory copy of the image, if necessary. (before this
+ change, any attempt to modify a memory-mapped image resulted in a
+ core dump...)
+
+ + Added special cases for lists everywhere PIL expects a sequence.
+ This should speed up things like "putdata" and drawing operations.
+
+ + The Image.offset method is deprecated. Use the ImageChops.offset
+ function instead.
+
+ + Changed ImageChops operators to copy palette and info dictionary
+ from the first image argument.
+
+ (1.1.1 released)
+
+ + Additional fixes for Python 1.6/2.0, including TIFF "save" bug.
+
+ + Changed "init" to properly load plugins when PIL is used as a
+ package.
+
+ + Fixed broken "show" method (on Unix)
+
+ *** Changes from release 1.0 to 1.1 ***
+
+ + Adapted to Python 1.6 ("append" and other method changes)
+
+ + Fixed Image.paste when pasting with solid colour and matte
+ layers ("L" or "RGBA" masks) (bug reported by Robert Kern)
+
+ + To make it easier to distribute prebuilt versions of PIL,
+ the tkinit binding stuff has been moved to a separate
+ extension module, named "_imagingtk".
+
+ *** Changes from release 0.3b2 to 1.0 final ***
+
+ + If there's no 16-bit integer (like on a Cray T3E), set
+ INT16 to the smallest integer available. Most of the
+ library works just fine anyway (from Bill Crutchfield)
+
+ + Tweaks to make drawing work on big-endian platforms.
+
+ (1.0c2 released)
+
+ + If PIL is built with the WITH_TKINTER flag, ImageTk can
+ automatically hook into a standard Tkinter build. You
+ no longer need to build your own Tkinter to use the
+ ImageTk module.
+
+ The old way still works, though. For more information,
+ see Tk/install.txt.
+
+ + Some tweaks to ImageTk to support multiple Tk interpreters
+ (from Greg Couch).
+
+ + ImageFont "load_path" now scans directory mentioned in .pth
+ files (from Richard Jones).
+
+ (1.0c1 released)
+
+ + The TIFF plugin has been rewritten. The new plugin fully
+ supports all major PIL image modes (including F and I).
+
+ + The ImageFile module now includes a Parser class, which can
+ be used to incrementally decode an image file (while down-
+ loading it from the net, for example). See the handbook for
+ details.
+
+ + "show" now converts non-standard modes to "L" or "RGB" (as
+ appropriate), rather than writing weird things to disk for
+ "xv" to choke upon. (bug reported by Les Schaffer).
+
+ (1.0b2 released)
+
+ + Major speedups for rotate, transform(EXTENT), and transform(AFFINE)
+ when using nearest neighbour resampling.
+
+ + Modified ImageDraw to be compatible with the Arrow graphics
+ interface. See the handbook for details.
+
+ + PIL now automatically loads file codecs when used as a package
+ (from The Dragon De Monsyne). Also included an __init__.py file
+ in the standard distribution.
+
+ + The GIF encoder has been modified to produce much smaller files.
+
+ PIL now uses a run-length encoding method to encode GIF files.
+ On a random selection of GIF images grabbed from the web, this
+ version makes the images about twice as large as the original
+ LZW files, where the earlier version made them over 5 times
+ larger. YMMV, of course.
+
+ + Added PCX write support (works with "1", "P", "L", and "RGB")
+
+ + Added "bitmap" and "textsize" methods to ImageDraw.
+
+ + Improved font rendering code. Fixed a bug or two, and moved
+ most of the time critical stuff to C.
+
+ + Removed "bdf2pil.py". Use "pilfont.py" instead!
+
+ + Improved 16-bit support (still experimental, though).
+
+ The following methods now support "I;16" and "I;16B" images:
+ "getpixel", "copy", "convert" (to and from mode "I"), "resize",
+ "rotate", and "transform" with nearest neighbour filters, and
+ "save" using the IM format. The "new" and "open" functions
+ also work as expected. On Windows, 16-bit files are memory
+ mapped.
+
+ NOTE: ALL other operations are still UNDEFINED on 16-bit images.
+
+ + The "paste" method now supports constant sources.
+
+ Just pass a colour value (a number or a tuple, depending on
+ the target image mode) instead of the source image.
+
+ This was in fact implemented in an inefficient way in
+ earlier versions (the "paste" method generated a temporary
+ source image if you passed it a colour instead of an image).
+ In this version, this is handled on the C level instead.
+
+ + Added experimental "RGBa" mode support.
+
+ An "RGBa" image is an RGBA image where the colour components
+ have have been premultiplied with the alpha value. PIL allows
+ you to convert an RGBA image to an RGBa image, and to paste
+ RGBa images on top of RGB images. Since this saves a bunch
+ of multiplications and shifts, it is typically about twice
+ as fast an ordinary RGBA paste.
+
+ + Eliminated extra conversion step when pasting "RGBA" or "RGBa"
+ images on top of "RGB" images.
+
+ + Fixed Image.BICUBIC resampling for "RGB" images.
+
+ + Fixed PCX image file handler to properly read 8-bit PCX
+ files (bug introduced in 1.0b1, reported by Bernhard
+ Herzog)
+
+ + Fixed PSDraw "image" method to restore the coordinate
+ system.
+
+ + Fixed "blend" problem when applied to images that was
+ not already loaded (reported by Edward C. Jones)
+
+ + Fixed -f option to "pilconvert.py" (from Anthony Baxter)
+
+ (1.0b1 released)
+
+ + Added Toby J. Sargeant's quantization package. To enable
+ quantization, use the "palette" option to "convert":
+
+ imOut = im.convert("P", palette=Image.ADAPTIVE)
+
+ This can be used with "L", "P", and "RGB" images. In this
+ version, dithering cannot be used with adaptive palettes.
+
+ Note: ADAPTIVE currently maps to median cut quantization
+ with 256 colours. The quantization package also contains
+ a maximum coverage quantizer, which will be supported by
+ future versions of PIL.
+
+ + Added Eric S. Raymond's "pildriver" image calculator to the
+ distribution. See the docstring for more information.
+
+ + The "offset" method no longer dumps core if given positive
+ offsets (from Charles Waldman).
+
+ + Fixed a resource leak that could cause ImageWin to run out of
+ GDI resources (from Roger Burnham).
+
+ + Added "arc", "chord", and "pieslice" methods to ImageDraw (inspired
+ by code contributed by Richard Jones).
+
+ + Added experimental 16-bit support, via modes "I;16" (little endian
+ data) and "I;16B" (big endian). Only a few methods properly support
+ such images (see above).
+
+ + Added XV thumbnail file handler (from Gene Cash).
+
+ + Fixed BMP image file handler to handle palette images with small
+ palettes (from Rob Hooft).
+
+ + Fixed Sun raster file handler for palette images (from Charles
+ Waldman).
+
+ + Improved various internal error messages.
+
+ + Fixed Path constructor to handle arbitrary sequence objects. This
+ also affects the ImageDraw class (from Richard Jones).
+
+ + Fixed a bug in JpegDecode that caused PIL to report "decoder error
+ -2" for some progressive JPEG files (reported by Magnus Källström,
+ who also provided samples).
+
+ + Fixed a bug in JpegImagePlugin that caused PIL to hang when loading
+ JPEG files using 16-bit quantization tables.
+
+ + The Image "transform" method now supports Image.QUAD transforms.
+ The data argument is an 8-tuple giving the upper left, lower
+ left, lower right, and upper right corner of the source quadri-
+ lateral. Also added Image.MESH transform which takes a list
+ of quadrilaterals.
+
+ + The Image "resize", "rotate", and "transform" methods now support
+ Image.BILINEAR (2x2) and Image.BICUBIC (4x4) resampling filters.
+ Filters can be used with all transform methods.
+
+ + The ImageDraw "rectangle" method now includes both the right
+ and the bottom edges when drawing filled rectangles.
+
+ + The TGA decoder now works properly for runlength encoded images
+ which have more than one byte per pixel.
+
+ + "getbands" on an YCbCr image now returns ("Y", "Cb", "Cr")
+
+ + Some file drivers didn't handle the optional "modify" argument
+ to the load method. This resulted in exceptions when you used
+ "paste" (and other methods that modify an image in place) on a
+ newly opened file.
+
+ *** Changes from release 0.2 (b5) to 0.3 (b2) ***
+
+ (0.3b2 released)
+
+ The test suite includes 825 individual tests.
+
+ + An Image "getbands" method has been added. It returns a tuple
+ containing the individual band names for this image. To figure
+ out how many bands an image has, use "len(im.getbands())".
+
+ + An Image "putpixel" method has been added.
+
+ + The Image "point" method can now be used to convert "L" images
+ to any other format, via a lookup table. That table should
+ contain 256 values for each band in the output image.
+
+ + Some file drivers (including FLI/FLC, GIF, and IM) accidentally
+ overwrote the offset method with an internal attribute. All
+ drivers have been updated to use private attributes where
+ possible.
+
+ + The Image "histogram" method now works for "I" and "F" images.
+ For these modes, PIL divides the range between the min and
+ max values used in the image into 256 bins. You can also
+ pass in your own min and max values via the "extrema" option:
+
+ h = im.histogram(extrema=(0, 255))
+
+ + An Image "getextrema" method has been added. It returns the
+ min and max values used in the image. In this release, this
+ works for single band images only.
+
+ + Changed the PNG driver to load and save mode "I" images as
+ 16-bit images. When saving, values outside the range 0..65535
+ are clipped.
+
+ + Fixed ImageFont.py to work with the new "pilfont" compiler.
+
+ + Added JPEG "save" and "draft" support for mode "YCbCr" images.
+ Note that if you save an "YCbCr" image as a JPEG file and read
+ it back, it is read as an RGB file. To get around this, you
+ can use the "draft" method:
+
+ im = Image.open("color.jpg")
+ im.draft("YCbCr", im.size)
+
+ + Read "RGBA" TGA images. Also fixed the orientation bug; all
+ images should now come out the right way.
+
+ + Changed mode name (and internal representation) from "YCrCb"
+ to "YCbCr" (!)
+ *** WARNING: MAY BREAK EXISTING CODE ***
+
+ (0.3b1 released)
+
+ The test suite includes 750 individual tests.
+
+ + The "pilfont" package is now included in the standard PIL
+ distribution. The pilfont utility can be used to convert
+ X BDF and PCF raster font files to a format understood by
+ the ImageFont module.
+
+ + GIF files are now interlaced by default. To write a
+ non-interlaced file, pass interlace=0 to the "save"
+ method.
+
+ + The default string format has changed for the "fromstring"
+ and "tostring" methods.
+ *** WARNING: MAY BREAK EXISTING CODE ***
+
+ NOTE: If no extra arguments are given, the first line in
+ the string buffer is the top line of the image, instead of
+ the bottom line. For RGB images, the string now contains
+ 3 bytes per pixel instead of 4. These changes were made
+ to make the methods compatible with the "fromstring"
+ factory function.
+
+ To get the old behaviour, use the following syntax:
+
+ data = im.tostring("raw", "RGBX", 0, -1)
+ im.fromstring(data, "raw", "RGBX", 0, -1)
+
+ + "new" no longer gives a MemoryError if the width or height
+ is zero (this only happened on platforms where malloc(0)
+ or calloc(0) returns NULL).
+
+ + "new" now adds a default palette object to "P" images.
+
+ + You can now convert directly between all modes supported by
+ PIL. When converting colour images to "P", PIL defaults to
+ a "web" palette and dithering. When converting greyscale
+ images to "1", PIL uses a thresholding and dithering.
+
+ + Added a "dither" option to "convert". By default, "convert"
+ uses floyd-steinberg error diffusion for "P" and "1" targets,
+ so this option is only used to *disable* dithering. Allowed
+ values are NONE (no dithering) or FLOYDSTEINBERG (default).
+
+ imOut = im.convert("P", dither=Image.NONE)
+
+ + Added a full set of "I" decoders. You can use "fromstring"
+ (and file decoders) to read any standard integer type as an
+ "I" image.
+
+ + Added some support for "YCbCr" images (creation, conversion
+ from/to "L" and "RGB", IM YCC load/save)
+
+ + "getpixel" now works properly with fractional coordinates.
+
+ + ImageDraw "setink" now works with "I", "F", "RGB", "RGBA",
+ "RGBX", "CMYK", and "YCbCr" images.
+
+ + ImImagePlugin no longer attaches palettes to "RGB" images.
+
+ + Various minor fixes.
+
+ (0.3a4 released)
+
+ + Added experimental IPTC/NAA support.
+
+ + Eliminated AttributeError exceptions after "crop" (from
+ Skip Montanaro)
+
+ + Reads some uncompressed formats via memory mapping (this
+ is currently supported on Win32 only)
+
+ + Fixed some last minute glitches in the last alpha release
+ (Types instead of types in Image.py, version numbers, etc.)
+
+ + Eliminated some more bogus compiler warnings.
+
+ + Various fixes to make PIL compile and run smoother on Macs
+ (from Jack Jansen).
+
+ + Fixed "fromstring" and "tostring" for mode "I" images.
+
+ (0.3a3 released)
+
+ The test suite includes 530 individual tests.
+
+ + Eliminated unexpected side-effect in "paste" with matte. "paste"
+ now works properly also if compiled with "gcc".
+
+ + Adapted to Python 1.5 (build issues only)
+
+ + Fixed the ImageDraw "point" method to draw also the last
+ point (!).
+
+ + Added "I" and "RGBX" support to Image.new.
+
+ + The plugin path is now properly prepended to the module search
+ path when a plugin module is imported.
+
+ + Added "draw" method to the ImageWin.Dib class. This is used by
+ Topaz to print images on Windows printers.
+
+ + "convert" now supports conversions from "P" to "1" and "F".
+
+ + "paste" can now take a colour instead of an image as the first argument.
+ The colour must match the colour argument given to the new function, and
+ match the mode of the target image.
+
+ + Fixed "paste" to allow a mask also for mode "F" images.
+
+ + The BMP driver now saves mode "1" images. When loading images, the mode
+ is set to "L" for 8-bit files with greyscale palettes, and to "P" for
+ other 8-bit files.
+
+ + The IM driver now reads and saves "1" images (file modes "0 1" or "L 1").
+
+ + The JPEG and GIF drivers now saves "1" images. For JPEG, the image
+ is saved as 8-bit greyscale (it will load as mode "L"). For GIF, the
+ image will be loaded as a "P" image.
+
+ + Fixed a potential buffer overrun in the GIF encoder.
+
+ (0.3a2 released)
+
+ The test suite includes 400 individual tests.
+
+ + Improvements to the test suite revealed a number of minor bugs, which
+ are all fixed. Note that crop/paste, 32-bit ImageDraw, and ImageFont
+ are still weak spots in this release.
+
+ + Added "putpalette" method to the Image class. You can use this
+ to add or modify the palette for "P" and "L" images. If a palette
+ is added to an "L" image, it is automatically converted to a "P"
+ image.
+
+ + Fixed ImageDraw to properly handle 32-bit image memories
+ ("RGB", "RGBA", "CMYK", "F")
+
+ + Fixed "fromstring" and "tostring" not to mess up the mode attribute
+ in default mode.
+
+ + Changed ImPlatform.h to work on CRAY's (don't have one at home, so I
+ haven't tried it). The previous version assumed that either "short"
+ or "int" were 16-bit wide. PIL still won't compile on platforms where
+ neither "short", "int" nor "long" are 32-bit wide.
+
+ + Added file= and data= keyword arguments to PhotoImage and BitmapImage.
+ This allows you to use them as drop-in replacements for the corre-
+ sponding Tkinter classes.
+
+ + Removed bogus references to the crack coder (ImagingCrack).
+
+ (0.3a1 released)
+
+ + Make sure image is loaded in "tostring".
+
+ + Added floating point packer (native 32-bit floats only).
+
+ *** Changes from release 0.1b1 to 0.2 (b5) ***
+
+ + Modified "fromstring" and "tostring" methods to use file codecs.
+ Also added "fromstring" factory method to create an image directly
+ from data in a string.
+
+ + Added support for 32-bit floating point images (mode "F"). You
+ can convert between "L" and "F" images, and apply a subset of the
+ available image processing methods on the "F" image. You can also
+ read virtually any data format into a floating point image memory;
+ see the section on "Decoding Floating Point Data" in the handbook
+ for more information.
+
+ (0.2b5 released; on windows only)
+
+ + Fixed the tobitmap() method to work properly for small bitmaps.
+
+ + Added RMS and standard deviation to the ImageStat.Stat class. Also
+ modified the constructor to take an optional feature mask, and also
+ to accept either an image or a list containing the histogram data.
+
+ + The BitmapImage code in ImageTk can now use a special bitmap
+ decoder, which has to be patched into Tk. See the "Tk/pilbitmap.txt"
+ file for details. If not installed, bitmaps are transferred to Tk as
+ XBM strings.
+
+ + The PhotoImage code in ImageTk now uses a Tcl command ("PyImagingPaste")
+ instead of a special image type. This gives somewhat better performance,
+ and also allows PIL to support transparency.
+ *** WARNING: TKAPPINIT MUST BE MODIFIED ***
+
+ + ImageTk now honours the alpha layer in RGBA images. Only fully
+ transparent pixels are made transparent (that is, the alpha layer
+ is treated as a mask). To treat the alpha laters as a matte, you
+ must paste the image on the background before handing it over to
+ ImageTk.
+
+ + Added McIdas reader (supports 8-bit images only).
+
+ + PIL now preloads drivers for BMP, GIF, JPEG, PPM, and TIFF. As
+ long as you only load and save these formats, you don't have to
+ wait for a full scan for drivers. To force scanning, call the
+ Image.init() function.
+
+ + The "seek" and "tell" methods are now always available, also for
+ single-frame images.
+
+ + Added optional mask argument to histogram method. The mask may
+ be an "1" or "L" image with the same size as the original image.
+ Only pixels where the mask is non-zero are included in the
+ histogram.
+
+ + The "paste" method now allows you to specify only the lower left
+ corner (a 2-tuple), instead of the full region (a 4-tuple).
+
+ + Reverted to old plugin scanning model; now scans all directory
+ names in the path when looking for plugins.
+
+ + Added PIXAR raster support. Only uncompressed ("dumped") RGB
+ images can currently be read (based on information provided
+ by Greg Coats).
+
+ + Added FlashPix (FPX) read support. Reads all pixel formats, but
+ only the highest resolution is read, and the viewing transform is
+ currently ignored.
+
+ + Made PNG encoding somewhat more efficient in "optimize" mode; a
+ bug in 0.2b4 didn't enable all predictor filters when optimized
+ storage were requested.
+
+ + Added Microsoft Image Composer (MIC) read support. When opened,
+ the first sprite in the file is loaded. You can use the seek method
+ to load additional sprites from the file.
+
+ + Properly reads "P" and "CMYK" PSD images.
+
+ + "pilconvert" no longer optimizes by default; use the -o option to
+ make the file as small as possible (at the expense of speed); use
+ the -q option to set the quality when compressing to JPEG.
+
+ + Fixed "crop" not to drop the palette for "P" images.
+
+ + Added and verified FLC support.
+
+ + Paste with "L" or "RGBA" alpha is now several times faster on most
+ platforms.
+
+ + Changed Image.new() to initialize the image to black, as described
+ in the handbook. To get an uninitialized image, use None as the
+ colour.
+
+ + Fixed the PDF encoder to produce a valid header; Acrobat no longer
+ complains when you load PDF images created by PIL.
+
+ + PIL only scans fully-qualified directory names in the path when
+ looking for plugins.
+ *** WARNING: MAY BREAK EXISTING CODE ***
+
+ + Faster implementation of "save" used when filename is given,
+ or when file object has "fileno" and "flush" methods.
+
+ + Don't crash in "crop" if region extends outside the source image.
+
+ + Eliminated a massive memory leak in the "save" function.
+
+ + The GIF decoder doesn't crash if the code size is set to an illegal
+ value. This could happen since another bug didn't handle local
+ palettes properly if they didn't have the same size as the
+ global palette (not very common).
+
+ + Added predictor support (TIFF 6.0 section 14) to the TIFF decoder.
+
+ + Fixed palette and padding problems in BMP driver. Now properly
+ writes "1", "L", "P" and "RGB" images.
+
+ + Fixed getpixel()/getdata() to return correct pixel values.
+
+ + Added PSD (PhotoShop) read support. Reads both uncompressed
+ and compressed images of most types.
+
+ + Added GIF write support (writes "uncompressed" GIF files only,
+ due to unresolvable licensing issues). The "gifmaker.py" script
+ can be used to create GIF animations.
+
+ + Reads 8-bit "L" and "P" TGA images. Also reads 16-bit "RGB"
+ images.
+
+ + Added FLI read support. This driver has only been tested
+ on a few FLI samples.
+
+ + Reads 2-bit and 4-bit PCX images.
+
+ + Added MSP read and write support. Both version 1 and 2 can be
+ read, but only version 1 (uncompressed) files are written.
+
+ + Fixed a bug in the FLI/FLC identification code that caused the
+ driver to raise an exception when parsing valid FLI/FLC files.
+
+ + Improved performance when loading file format plugins, and when
+ opening files.
+
+ + Added GIF animation support, via the "seek" and "tell" methods.
+ You can use "player.py" to play an animated GIF file.
+
+ + Removed MNG support, since the spec is changing faster than I
+ can change the code. I've added support for the experimental
+ ARG format instead. Contact me for more information on this
+ format.
+
+ + Added keyword options to the "save" method. The following options
+ are currently supported:
+
+ format option description
+ --------------------------------------------------------
+ JPEG optimize minimize output file at the
+ expense of compression speed.
+
+ JPEG progressive enable progressive output. the
+ option value is ignored.
+
+ JPEG quality set compression quality (1-100).
+ the default value is 75.
+
+ JPEG smooth smooth dithered images. value
+ is strength (1-100). default is
+ off (0).
+
+ PNG optimize minimize output file at the
+ expense of compression speed.
+
+ Expect more options in future releases. Also note that
+ file writers silently ignore unknown options.
+
+ + Plugged memory leaks in the PNG and TIFF decoders.
+
+ + Added PNG write support.
+
+ + (internal) RGB unpackers and converters now set the pad byte
+ to 255 (full opacity).
+
+ + Properly handles the "transparency" property for GIF, PNG
+ and XPM files.
+
+ + Added a "putalpha" method, allowing you to attach a "1" or "L"
+ image as the alpha layer to an "RGBA" image.
+
+ + Various improvements to the sample scripts:
+
+ "pilconvert" Carries out some extra tricks in order to make
+ the resulting file as small as possible.
+
+ "explode" (NEW) Split an image sequence into individual frames.
+
+ "gifmaker" (NEW) Convert a sequence file into a GIF animation.
+ Note that the GIF encoder create "uncompressed" GIF
+ files, so animations created by this script are
+ rather large (typically 2-5 times the compressed
+ sizes).
+
+ "image2py" (NEW) Convert a single image to a python module. See
+ comments in this script for details.
+
+ "player" If multiple images are given on the command line,
+ they are interpreted as frames in a sequence. The
+ script assumes that they all have the same size.
+ Also note that this script now can play FLI/FLC
+ and GIF animations.
+
+ This player can also execute embedded Python
+ animation applets (ARG format only).
+
+ "viewer" Transparent images ("P" with transparency property,
+ and "RGBA") are superimposed on the standard Tk back-
+ ground.
+
+ + Fixed colour argument to "new". For multilayer images, pass a
+ tuple: (Red, Green, Blue), (Red, Green, Blue, Alpha), or (Cyan,
+ Magenta, Yellow, Black).
+
+ + Added XPM (X pixmap) read support.
+
+ (0.2b3 released)
+
+ + Added MNG (multi-image network graphics) read support. "Ming"
+ is a proposed animation standard, based on the PNG file format.
+
+ You can use the "player" sample script to display some flavours
+ of this format. The MNG standard is still under development,
+ as is this driver. More information, including sample files,
+ can be found at <ftp://swrinde.nde.swri.edu/pub/mng>
+
+ + Added a "verify" method to images loaded from file. This method
+ scans the file for errors, without actually decoding the image
+ data, and raises a suitable exception if it finds any problems.
+ Currently implemented for PNG and MNG files only.
+
+ + Added support for interlaced GIF images.
+
+ + Added PNG read support -- if linked with the ZLIB compression library,
+ PIL reads all kinds of PNG images, except interlaced files.
+
+ + Improved PNG identification support -- doesn't mess up on unknown
+ chunks, identifies all possible PNG modes, and verifies checksum
+ on PNG header chunks.
+
+ + Added an experimental reader for placable Windows Meta Files (WMF).
+ This reader is still very incomplete, but it illustrates how PIL's
+ drawing capabilities can be used to render vector and metafile
+ formats.
+
+ + Added restricted drivers for images from Image Tools (greyscale
+ only) and LabEye/IFUNC (common interchange modes only).
+
+ + Some minor improvements to the sample scripts provided in the
+ "Scripts" directory.
+
+ + The test images have been moved to the "Images" directory.
+
+ (0.2b2 released)
+ (0.2b1 released; Windows only)
+
+ + Fixed filling of complex polygons. The ImageDraw "line" and
+ "polygon" methods also accept Path objects.
+
+ + The ImageTk "PhotoImage" object can now be constructed directly
+ from an image. You can also pass the object itself to Tkinter,
+ instead of using the "image" attribute. Finally, using "paste"
+ on a displayed image automatically updates the display.
+
+ + The ImageTk "BitmapImage" object allows you to create transparent
+ overlays from 1-bit images. You can pass the object itself to
+ Tkinter. The constructor takes the same arguments as the Tkinter
+ BitmapImage class; use the "foreground" option to set the colour
+ of the overlay.
+
+ + Added a "putdata" method to the Image class. This can be used to
+ load a 1-layer image with data from a sequence object or a string.
+ An optional floating point scale and offset can be used to adjust
+ the data to fit into the 8-bit pixel range. Also see the "getdata"
+ method.
+
+ + Added the EXTENT method to the Image "transform" method. This can
+ be used to quickly crop, stretch, shrink, or mirror a subregion
+ from another image.
+
+ + Adapted to Python 1.4.
+
+ + Added a project makefile for Visual C++ 4.x. This allows you to
+ easily build a dynamically linked version of PIL for Windows 95
+ and NT.
+
+ + A Tk "booster" patch for Windows is available. It gives dramatic
+ performance improvements for some displays. Has been tested with
+ Tk 4.2 only, but is likely to work with Tk 4.1 as well. See the Tk
+ subdirectory for details.
+
+ + You can now save 1-bit images in the XBM format. In addition, the
+ Image class now provides a "tobitmap" method which returns a string
+ containing an XBM representation of the image. Quite handy to use
+ with Tk.
+
+ + More conversions, including "RGB" to "1" and more.
+
+ (0.2a1 released)
+
+ + Where earlier versions accepted lists, this version accepts arbitrary
+ Python sequences (including strings, in some cases). A few resource
+ leaks were plugged in the process.
+
+ + The Image "paste" method now allows the box to extend outside
+ the target image. The size of the box, the image to be pasted,
+ and the optional mask must still match.
+
+ + The ImageDraw module now supports filled polygons, outlined and
+ filled ellipses, and text. Font support is rudimentary, though.
+
+ + The Image "point" method now takes an optional mode argument,
+ allowing you to convert the image while translating it. Currently,
+ this can only be used to convert "L" or "P" images to "1" images
+ (creating thresholded images or "matte" masks).
+
+ + An Image "getpixel" method has been added. For single band images,
+ it returns the pixel value at a given position as an integer.
+ For n-band images, it returns an n-tuple of integers.
+
+ + An Image "getdata" method has been added. It returns a sequence
+ object representing the image as a 1-dimensional array. Only len()
+ and [] can be used with this sequence. This method returns a
+ reference to the existing image data, so changes in the image
+ will be immediately reflected in the sequence object.
+
+ + Fixed alignment problems in the Windows BMP writer.
+
+ + If converting an "RGB" image to "RGB" or "L", you can give a second
+ argument containing a colour conversion matrix.
+
+ + An Image "getbbox" method has been added. It returns the bounding
+ box of data in an image, considering the value 0 as background.
+
+ + An Image "offset" method has been added. It returns a new image
+ where the contents of the image have been offset the given distance
+ in X and/or Y direction. Data wraps between edges.
+
+ + Saves PDF images. The driver creates a binary PDF 1.1 files, using
+ JPEG compression for "L", "RGB", and "CMYK" images, and hex encoding
+ (same as for PostScript) for other formats.
+
+ + The "paste" method now accepts "1" masks. Zero means transparent,
+ any other pixel value means opaque. This is faster than using an
+ "L" transparency mask.
+
+ + Properly writes EPS files (and properly prints images to postscript
+ printers as well).
+
+ + Reads 4-bit BMP files, as well as 4 and 8-bit Windows ICO and CUR
+ files. Cursor animations are not supported.
+
+ + Fixed alignment problems in the Sun raster loader.
+
+ + Added "draft" and "thumbnail" methods. The draft method is used
+ to optimize loading of JPEG and PCD files, the thumbnail method is
+ used to create a thumbnail representation of an image.
+
+ + Added Windows display support, via the ImageWin class (see the
+ handbook for details).
+
+ + Added raster conversion for EPS files. This requires GNU or Aladdin
+ Ghostscript, and probably works on UNIX only.
+
+ + Reads PhotoCD (PCD) images. The base resolution (768x512) can be
+ read from a PhotoCD file.
+
+ + Eliminated some compiler warnings. Bindings now compile cleanly in C++
+ mode. Note that the Imaging library itself must be compiled in C mode.
+
+ + Added "bdf2pil.py", which converts BDF fonts into images with associated
+ metrics. This is definitely work in progress. For info, see description
+ in script for details.
+
+ + Fixed a bug in the "ImageEnhance.py" module.
+
+ + Fixed a bug in the netpbm save hack in "GifImagePlugin.py"
+
+ + Fixed 90 and 270 degree rotation of rectangular images.
+
+ + Properly reads 8-bit TIFF palette-color images.
+
+ + Reads plane separated RGB and CMYK TIFF images.
+
+ + Added driver debug mode. This is enabled by setting Image.DEBUG
+ to a non-zero value. Try the -D option to "pilfile.py" and see what
+ happens.
+
+ + Don't crash on "atend" constructs in PostScript files.
+
+ + Only the Image module imports _imaging directly. Other modules
+ should refer to the binding module as "Image.core".
+
+ *** Changes from release 0.0 to 0.1 (b1) ***
+
+ + A handbook is available (distributed separately).
+
+ + The coordinate system is changed so that (0,0) is now located
+ in the upper left corner. This is in compliancy with ISO 12087
+ and 90% of all other image processing and graphics libraries.
+
+ + Modes "1" (bilevel) and "P" (palette) have been introduced. Note
+ that bilevel images are stored with one byte per pixel.
+
+ + The Image "crop" and "paste" methods now accepts None as the
+ box argument, to refer to the full image (self, that is).
+
+ + The Image "crop" method now works properly.
+
+ + The Image "point" method is now available. You can use either a
+ lookup table or a function taking one argument.
+
+ + The Image join function has been renamed to "merge".
+
+ + An Image "composite" function has been added. It is identical
+ to copy() followed by paste(mask).
+
+ + An Image "eval" function has been added. It is currently identical
+ to point(function); that is, only a single image can be processed.
+
+ + A set of channel operations has been added. See the "ImageChops"
+ module, test_chops.py, and the handbook for details.
+
+ + Added the "pilconvert" utility, which converts image files. Note
+ that the number of output formats are still quite restricted.
+
+ + Added the "pilfile" utility, which quickly identifies image files
+ (without loading them, in most cases).
+
+ + Added the "pilprint" utility, which prints image files to Postscript
+ printers.
+
+ + Added a rudimentary version of the "pilview" utility, which is
+ simple image viewer based on Tk. Only File/Exit and Image/Next
+ works properly.
+
+ + An interface to Tk has been added. See "Lib/ImageTk.py" and README
+ for details.
+
+ + An interface to Jack Jansen's Img library has been added (thanks to
+ Jack). This allows you to read images through the Img extensions file
+ format handlers. See the file "Lib/ImgExtImagePlugin.py" for details.
+
+ + Postscript printing is provided through the PSDraw module. See the
+ handbook for details.
diff --git a/contrib/python/Pillow/py2/LICENSE b/contrib/python/Pillow/py2/LICENSE
new file mode 100644
index 0000000000..ab8b0c111e
--- /dev/null
+++ b/contrib/python/Pillow/py2/LICENSE
@@ -0,0 +1,16 @@
+The Python Imaging Library (PIL) is
+
+ Copyright © 1997-2011 by Secret Labs AB
+ Copyright © 1995-2011 by Fredrik Lundh
+
+Pillow is the friendly PIL fork. It is
+
+ Copyright © 2010-2020 by Alex Clark and contributors
+
+Like PIL, Pillow is licensed under the open source PIL Software License:
+
+By obtaining, using, and/or copying this software and/or its associated documentation, you agree that you have read, understood, and will comply with the following terms and conditions:
+
+Permission to use, copy, modify, and distribute this software and its associated documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies, and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Secret Labs AB or the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.
+
+SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/contrib/python/Pillow/py2/PIL/BdfFontFile.py b/contrib/python/Pillow/py2/PIL/BdfFontFile.py
new file mode 100644
index 0000000000..fdf2c097e1
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/BdfFontFile.py
@@ -0,0 +1,114 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# bitmap distribution font (bdf) file parser
+#
+# history:
+# 1996-05-16 fl created (as bdf2pil)
+# 1997-08-25 fl converted to FontFile driver
+# 2001-05-25 fl removed bogus __init__ call
+# 2002-11-20 fl robustification (from Kevin Cazabon, Dmitry Vasiliev)
+# 2003-04-22 fl more robustification (from Graham Dumpleton)
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1997-2003 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import print_function
+
+from . import FontFile, Image
+
+# --------------------------------------------------------------------
+# parse X Bitmap Distribution Format (BDF)
+# --------------------------------------------------------------------
+
+bdf_slant = {
+ "R": "Roman",
+ "I": "Italic",
+ "O": "Oblique",
+ "RI": "Reverse Italic",
+ "RO": "Reverse Oblique",
+ "OT": "Other",
+}
+
+bdf_spacing = {"P": "Proportional", "M": "Monospaced", "C": "Cell"}
+
+
+def bdf_char(f):
+ # skip to STARTCHAR
+ while True:
+ s = f.readline()
+ if not s:
+ return None
+ if s[:9] == b"STARTCHAR":
+ break
+ id = s[9:].strip().decode("ascii")
+
+ # load symbol properties
+ props = {}
+ while True:
+ s = f.readline()
+ if not s or s[:6] == b"BITMAP":
+ break
+ i = s.find(b" ")
+ props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
+
+ # load bitmap
+ bitmap = []
+ while True:
+ s = f.readline()
+ if not s or s[:7] == b"ENDCHAR":
+ break
+ bitmap.append(s[:-1])
+ bitmap = b"".join(bitmap)
+
+ [x, y, l, d] = [int(p) for p in props["BBX"].split()]
+ [dx, dy] = [int(p) for p in props["DWIDTH"].split()]
+
+ bbox = (dx, dy), (l, -d - y, x + l, -d), (0, 0, x, y)
+
+ try:
+ im = Image.frombytes("1", (x, y), bitmap, "hex", "1")
+ except ValueError:
+ # deal with zero-width characters
+ im = Image.new("1", (x, y))
+
+ return id, int(props["ENCODING"]), bbox, im
+
+
+##
+# Font file plugin for the X11 BDF format.
+
+
+class BdfFontFile(FontFile.FontFile):
+ def __init__(self, fp):
+
+ FontFile.FontFile.__init__(self)
+
+ s = fp.readline()
+ if s[:13] != b"STARTFONT 2.1":
+ raise SyntaxError("not a valid BDF file")
+
+ props = {}
+ comments = []
+
+ while True:
+ s = fp.readline()
+ if not s or s[:13] == b"ENDPROPERTIES":
+ break
+ i = s.find(b" ")
+ props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
+ if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
+ if s.find(b"LogicalFontDescription") < 0:
+ comments.append(s[i + 1 : -1].decode("ascii"))
+
+ while True:
+ c = bdf_char(fp)
+ if not c:
+ break
+ id, ch, (xy, dst, src), im = c
+ if 0 <= ch < len(self.glyph):
+ self.glyph[ch] = xy, dst, src, im
diff --git a/contrib/python/Pillow/py2/PIL/BlpImagePlugin.py b/contrib/python/Pillow/py2/PIL/BlpImagePlugin.py
new file mode 100644
index 0000000000..dd17451585
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/BlpImagePlugin.py
@@ -0,0 +1,420 @@
+"""
+Blizzard Mipmap Format (.blp)
+Jerome Leclanche <jerome@leclan.ch>
+
+The contents of this file are hereby released in the public domain (CC0)
+Full text of the CC0 license:
+ https://creativecommons.org/publicdomain/zero/1.0/
+
+BLP1 files, used mostly in Warcraft III, are not fully supported.
+All types of BLP2 files used in World of Warcraft are supported.
+
+The BLP file structure consists of a header, up to 16 mipmaps of the
+texture
+
+Texture sizes must be powers of two, though the two dimensions do
+not have to be equal; 512x256 is valid, but 512x200 is not.
+The first mipmap (mipmap #0) is the full size image; each subsequent
+mipmap halves both dimensions. The final mipmap should be 1x1.
+
+BLP files come in many different flavours:
+* JPEG-compressed (type == 0) - only supported for BLP1.
+* RAW images (type == 1, encoding == 1). Each mipmap is stored as an
+ array of 8-bit values, one per pixel, left to right, top to bottom.
+ Each value is an index to the palette.
+* DXT-compressed (type == 1, encoding == 2):
+- DXT1 compression is used if alpha_encoding == 0.
+ - An additional alpha bit is used if alpha_depth == 1.
+ - DXT3 compression is used if alpha_encoding == 1.
+ - DXT5 compression is used if alpha_encoding == 7.
+"""
+
+import struct
+from io import BytesIO
+
+from . import Image, ImageFile
+
+BLP_FORMAT_JPEG = 0
+
+BLP_ENCODING_UNCOMPRESSED = 1
+BLP_ENCODING_DXT = 2
+BLP_ENCODING_UNCOMPRESSED_RAW_BGRA = 3
+
+BLP_ALPHA_ENCODING_DXT1 = 0
+BLP_ALPHA_ENCODING_DXT3 = 1
+BLP_ALPHA_ENCODING_DXT5 = 7
+
+
+def unpack_565(i):
+ return (((i >> 11) & 0x1F) << 3, ((i >> 5) & 0x3F) << 2, (i & 0x1F) << 3)
+
+
+def decode_dxt1(data, alpha=False):
+ """
+ input: one "row" of data (i.e. will produce 4*width pixels)
+ """
+
+ blocks = len(data) // 8 # number of blocks in row
+ ret = (bytearray(), bytearray(), bytearray(), bytearray())
+
+ for block in range(blocks):
+ # Decode next 8-byte block.
+ idx = block * 8
+ color0, color1, bits = struct.unpack_from("<HHI", data, idx)
+
+ r0, g0, b0 = unpack_565(color0)
+ r1, g1, b1 = unpack_565(color1)
+
+ # Decode this block into 4x4 pixels
+ # Accumulate the results onto our 4 row accumulators
+ for j in range(4):
+ for i in range(4):
+ # get next control op and generate a pixel
+
+ control = bits & 3
+ bits = bits >> 2
+
+ a = 0xFF
+ if control == 0:
+ r, g, b = r0, g0, b0
+ elif control == 1:
+ r, g, b = r1, g1, b1
+ elif control == 2:
+ if color0 > color1:
+ r = (2 * r0 + r1) // 3
+ g = (2 * g0 + g1) // 3
+ b = (2 * b0 + b1) // 3
+ else:
+ r = (r0 + r1) // 2
+ g = (g0 + g1) // 2
+ b = (b0 + b1) // 2
+ elif control == 3:
+ if color0 > color1:
+ r = (2 * r1 + r0) // 3
+ g = (2 * g1 + g0) // 3
+ b = (2 * b1 + b0) // 3
+ else:
+ r, g, b, a = 0, 0, 0, 0
+
+ if alpha:
+ ret[j].extend([r, g, b, a])
+ else:
+ ret[j].extend([r, g, b])
+
+ return ret
+
+
+def decode_dxt3(data):
+ """
+ input: one "row" of data (i.e. will produce 4*width pixels)
+ """
+
+ blocks = len(data) // 16 # number of blocks in row
+ ret = (bytearray(), bytearray(), bytearray(), bytearray())
+
+ for block in range(blocks):
+ idx = block * 16
+ block = data[idx : idx + 16]
+ # Decode next 16-byte block.
+ bits = struct.unpack_from("<8B", block)
+ color0, color1 = struct.unpack_from("<HH", block, 8)
+
+ (code,) = struct.unpack_from("<I", block, 12)
+
+ r0, g0, b0 = unpack_565(color0)
+ r1, g1, b1 = unpack_565(color1)
+
+ for j in range(4):
+ high = False # Do we want the higher bits?
+ for i in range(4):
+ alphacode_index = (4 * j + i) // 2
+ a = bits[alphacode_index]
+ if high:
+ high = False
+ a >>= 4
+ else:
+ high = True
+ a &= 0xF
+ a *= 17 # We get a value between 0 and 15
+
+ color_code = (code >> 2 * (4 * j + i)) & 0x03
+
+ if color_code == 0:
+ r, g, b = r0, g0, b0
+ elif color_code == 1:
+ r, g, b = r1, g1, b1
+ elif color_code == 2:
+ r = (2 * r0 + r1) // 3
+ g = (2 * g0 + g1) // 3
+ b = (2 * b0 + b1) // 3
+ elif color_code == 3:
+ r = (2 * r1 + r0) // 3
+ g = (2 * g1 + g0) // 3
+ b = (2 * b1 + b0) // 3
+
+ ret[j].extend([r, g, b, a])
+
+ return ret
+
+
+def decode_dxt5(data):
+ """
+ input: one "row" of data (i.e. will produce 4 * width pixels)
+ """
+
+ blocks = len(data) // 16 # number of blocks in row
+ ret = (bytearray(), bytearray(), bytearray(), bytearray())
+
+ for block in range(blocks):
+ idx = block * 16
+ block = data[idx : idx + 16]
+ # Decode next 16-byte block.
+ a0, a1 = struct.unpack_from("<BB", block)
+
+ bits = struct.unpack_from("<6B", block, 2)
+ alphacode1 = bits[2] | (bits[3] << 8) | (bits[4] << 16) | (bits[5] << 24)
+ alphacode2 = bits[0] | (bits[1] << 8)
+
+ color0, color1 = struct.unpack_from("<HH", block, 8)
+
+ (code,) = struct.unpack_from("<I", block, 12)
+
+ r0, g0, b0 = unpack_565(color0)
+ r1, g1, b1 = unpack_565(color1)
+
+ for j in range(4):
+ for i in range(4):
+ # get next control op and generate a pixel
+ alphacode_index = 3 * (4 * j + i)
+
+ if alphacode_index <= 12:
+ alphacode = (alphacode2 >> alphacode_index) & 0x07
+ elif alphacode_index == 15:
+ alphacode = (alphacode2 >> 15) | ((alphacode1 << 1) & 0x06)
+ else: # alphacode_index >= 18 and alphacode_index <= 45
+ alphacode = (alphacode1 >> (alphacode_index - 16)) & 0x07
+
+ if alphacode == 0:
+ a = a0
+ elif alphacode == 1:
+ a = a1
+ elif a0 > a1:
+ a = ((8 - alphacode) * a0 + (alphacode - 1) * a1) // 7
+ elif alphacode == 6:
+ a = 0
+ elif alphacode == 7:
+ a = 255
+ else:
+ a = ((6 - alphacode) * a0 + (alphacode - 1) * a1) // 5
+
+ color_code = (code >> 2 * (4 * j + i)) & 0x03
+
+ if color_code == 0:
+ r, g, b = r0, g0, b0
+ elif color_code == 1:
+ r, g, b = r1, g1, b1
+ elif color_code == 2:
+ r = (2 * r0 + r1) // 3
+ g = (2 * g0 + g1) // 3
+ b = (2 * b0 + b1) // 3
+ elif color_code == 3:
+ r = (2 * r1 + r0) // 3
+ g = (2 * g1 + g0) // 3
+ b = (2 * b1 + b0) // 3
+
+ ret[j].extend([r, g, b, a])
+
+ return ret
+
+
+class BLPFormatError(NotImplementedError):
+ pass
+
+
+class BlpImageFile(ImageFile.ImageFile):
+ """
+ Blizzard Mipmap Format
+ """
+
+ format = "BLP"
+ format_description = "Blizzard Mipmap Format"
+
+ def _open(self):
+ self.magic = self.fp.read(4)
+ self._read_blp_header()
+
+ if self.magic == b"BLP1":
+ decoder = "BLP1"
+ self.mode = "RGB"
+ elif self.magic == b"BLP2":
+ decoder = "BLP2"
+ self.mode = "RGBA" if self._blp_alpha_depth else "RGB"
+ else:
+ raise BLPFormatError("Bad BLP magic %r" % (self.magic))
+
+ self.tile = [(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]
+
+ def _read_blp_header(self):
+ (self._blp_compression,) = struct.unpack("<i", self.fp.read(4))
+
+ (self._blp_encoding,) = struct.unpack("<b", self.fp.read(1))
+ (self._blp_alpha_depth,) = struct.unpack("<b", self.fp.read(1))
+ (self._blp_alpha_encoding,) = struct.unpack("<b", self.fp.read(1))
+ (self._blp_mips,) = struct.unpack("<b", self.fp.read(1))
+
+ self._size = struct.unpack("<II", self.fp.read(8))
+
+ if self.magic == b"BLP1":
+ # Only present for BLP1
+ (self._blp_encoding,) = struct.unpack("<i", self.fp.read(4))
+ (self._blp_subtype,) = struct.unpack("<i", self.fp.read(4))
+
+ self._blp_offsets = struct.unpack("<16I", self.fp.read(16 * 4))
+ self._blp_lengths = struct.unpack("<16I", self.fp.read(16 * 4))
+
+
+class _BLPBaseDecoder(ImageFile.PyDecoder):
+ _pulls_fd = True
+
+ def decode(self, buffer):
+ try:
+ self.fd.seek(0)
+ self.magic = self.fd.read(4)
+ self._read_blp_header()
+ self._load()
+ except struct.error:
+ raise IOError("Truncated Blp file")
+ return 0, 0
+
+ def _read_palette(self):
+ ret = []
+ for i in range(256):
+ try:
+ b, g, r, a = struct.unpack("<4B", self.fd.read(4))
+ except struct.error:
+ break
+ ret.append((b, g, r, a))
+ return ret
+
+ def _read_blp_header(self):
+ (self._blp_compression,) = struct.unpack("<i", self.fd.read(4))
+
+ (self._blp_encoding,) = struct.unpack("<b", self.fd.read(1))
+ (self._blp_alpha_depth,) = struct.unpack("<b", self.fd.read(1))
+ (self._blp_alpha_encoding,) = struct.unpack("<b", self.fd.read(1))
+ (self._blp_mips,) = struct.unpack("<b", self.fd.read(1))
+
+ self.size = struct.unpack("<II", self.fd.read(8))
+
+ if self.magic == b"BLP1":
+ # Only present for BLP1
+ (self._blp_encoding,) = struct.unpack("<i", self.fd.read(4))
+ (self._blp_subtype,) = struct.unpack("<i", self.fd.read(4))
+
+ self._blp_offsets = struct.unpack("<16I", self.fd.read(16 * 4))
+ self._blp_lengths = struct.unpack("<16I", self.fd.read(16 * 4))
+
+
+class BLP1Decoder(_BLPBaseDecoder):
+ def _load(self):
+ if self._blp_compression == BLP_FORMAT_JPEG:
+ self._decode_jpeg_stream()
+
+ elif self._blp_compression == 1:
+ if self._blp_encoding in (4, 5):
+ data = bytearray()
+ palette = self._read_palette()
+ _data = BytesIO(self.fd.read(self._blp_lengths[0]))
+ while True:
+ try:
+ (offset,) = struct.unpack("<B", _data.read(1))
+ except struct.error:
+ break
+ b, g, r, a = palette[offset]
+ data.extend([r, g, b])
+
+ self.set_as_raw(bytes(data))
+ else:
+ raise BLPFormatError(
+ "Unsupported BLP encoding %r" % (self._blp_encoding)
+ )
+ else:
+ raise BLPFormatError(
+ "Unsupported BLP compression %r" % (self._blp_encoding)
+ )
+
+ def _decode_jpeg_stream(self):
+ from PIL.JpegImagePlugin import JpegImageFile
+
+ (jpeg_header_size,) = struct.unpack("<I", self.fd.read(4))
+ jpeg_header = self.fd.read(jpeg_header_size)
+ self.fd.read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
+ data = self.fd.read(self._blp_lengths[0])
+ data = jpeg_header + data
+ data = BytesIO(data)
+ image = JpegImageFile(data)
+ self.tile = image.tile # :/
+ self.fd = image.fp
+ self.mode = image.mode
+
+
+class BLP2Decoder(_BLPBaseDecoder):
+ def _load(self):
+ palette = self._read_palette()
+
+ data = bytearray()
+ self.fd.seek(self._blp_offsets[0])
+
+ if self._blp_compression == 1:
+ # Uncompressed or DirectX compression
+
+ if self._blp_encoding == BLP_ENCODING_UNCOMPRESSED:
+ _data = BytesIO(self.fd.read(self._blp_lengths[0]))
+ while True:
+ try:
+ (offset,) = struct.unpack("<B", _data.read(1))
+ except struct.error:
+ break
+ b, g, r, a = palette[offset]
+ data.extend((r, g, b))
+
+ elif self._blp_encoding == BLP_ENCODING_DXT:
+ if self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT1:
+ linesize = (self.size[0] + 3) // 4 * 8
+ for yb in range((self.size[1] + 3) // 4):
+ for d in decode_dxt1(
+ self.fd.read(linesize), alpha=bool(self._blp_alpha_depth)
+ ):
+ data += d
+
+ elif self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT3:
+ linesize = (self.size[0] + 3) // 4 * 16
+ for yb in range((self.size[1] + 3) // 4):
+ for d in decode_dxt3(self.fd.read(linesize)):
+ data += d
+
+ elif self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT5:
+ linesize = (self.size[0] + 3) // 4 * 16
+ for yb in range((self.size[1] + 3) // 4):
+ for d in decode_dxt5(self.fd.read(linesize)):
+ data += d
+ else:
+ raise BLPFormatError(
+ "Unsupported alpha encoding %r" % (self._blp_alpha_encoding)
+ )
+ else:
+ raise BLPFormatError("Unknown BLP encoding %r" % (self._blp_encoding))
+
+ else:
+ raise BLPFormatError("Unknown BLP compression %r" % (self._blp_compression))
+
+ self.set_as_raw(bytes(data))
+
+
+Image.register_open(
+ BlpImageFile.format, BlpImageFile, lambda p: p[:4] in (b"BLP1", b"BLP2")
+)
+Image.register_extension(BlpImageFile.format, ".blp")
+
+Image.register_decoder("BLP1", BLP1Decoder)
+Image.register_decoder("BLP2", BLP2Decoder)
diff --git a/contrib/python/Pillow/py2/PIL/BmpImagePlugin.py b/contrib/python/Pillow/py2/PIL/BmpImagePlugin.py
new file mode 100644
index 0000000000..8426e2497b
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/BmpImagePlugin.py
@@ -0,0 +1,381 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# BMP file handler
+#
+# Windows (and OS/2) native bitmap storage format.
+#
+# history:
+# 1995-09-01 fl Created
+# 1996-04-30 fl Added save
+# 1997-08-27 fl Fixed save of 1-bit images
+# 1998-03-06 fl Load P images as L where possible
+# 1998-07-03 fl Load P images as 1 where possible
+# 1998-12-29 fl Handle small palettes
+# 2002-12-30 fl Fixed load of 1-bit palette images
+# 2003-04-21 fl Fixed load of 1-bit monochrome images
+# 2003-04-23 fl Added limited support for BI_BITFIELDS compression
+#
+# Copyright (c) 1997-2003 by Secret Labs AB
+# Copyright (c) 1995-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8, i16le as i16, i32le as i32, o8, o16le as o16, o32le as o32
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.7"
+
+#
+# --------------------------------------------------------------------
+# Read BMP file
+
+BIT2MODE = {
+ # bits => mode, rawmode
+ 1: ("P", "P;1"),
+ 4: ("P", "P;4"),
+ 8: ("P", "P"),
+ 16: ("RGB", "BGR;15"),
+ 24: ("RGB", "BGR"),
+ 32: ("RGB", "BGRX"),
+}
+
+
+def _accept(prefix):
+ return prefix[:2] == b"BM"
+
+
+def _dib_accept(prefix):
+ return i32(prefix[:4]) in [12, 40, 64, 108, 124]
+
+
+# =============================================================================
+# Image plugin for the Windows BMP format.
+# =============================================================================
+class BmpImageFile(ImageFile.ImageFile):
+ """ Image plugin for the Windows Bitmap format (BMP) """
+
+ # ------------------------------------------------------------- Description
+ format_description = "Windows Bitmap"
+ format = "BMP"
+
+ # -------------------------------------------------- BMP Compression values
+ COMPRESSIONS = {"RAW": 0, "RLE8": 1, "RLE4": 2, "BITFIELDS": 3, "JPEG": 4, "PNG": 5}
+ for k, v in COMPRESSIONS.items():
+ vars()[k] = v
+
+ def _bitmap(self, header=0, offset=0):
+ """ Read relevant info about the BMP """
+ read, seek = self.fp.read, self.fp.seek
+ if header:
+ seek(header)
+ file_info = {}
+ # 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
+ # 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:
+ file_info["width"] = i16(header_data[0:2])
+ file_info["height"] = i16(header_data[2:4])
+ file_info["planes"] = i16(header_data[4:6])
+ file_info["bits"] = i16(header_data[6:8])
+ file_info["compression"] = self.RAW
+ file_info["palette_padding"] = 3
+
+ # --------------------------------------------- Windows Bitmap v2 to v5
+ # v3, OS/2 v2, v4, v5
+ elif file_info["header_size"] in (40, 64, 108, 124):
+ 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["planes"] = i16(header_data[8:10])
+ file_info["bits"] = i16(header_data[10:12])
+ file_info["compression"] = i32(header_data[12:16])
+ # 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(
+ int(x / 39.3701 + 0.5) for x in 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"]
+ ):
+ 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, 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
+ 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"],
+ )
+ else:
+ 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"]
+
+ # ------- If color count was not found in the header, compute from bits
+ file_info["colors"] = (
+ file_info["colors"]
+ if file_info.get("colors", 0)
+ else (1 << file_info["bits"])
+ )
+
+ # ------------------------------- Check abnormal values for DOS attacks
+ if file_info["width"] * file_info["height"] > 2 ** 31:
+ raise IOError("Unsupported BMP Size: (%dx%d)" % self.size)
+
+ # ---------------------- 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"])
+
+ # ---------------- Process BMP with Bitfields compression (not palette)
+ if file_info["compression"] == self.BITFIELDS:
+ SUPPORTED = {
+ 32: [
+ (0xFF0000, 0xFF00, 0xFF, 0x0),
+ (0xFF0000, 0xFF00, 0xFF, 0xFF000000),
+ (0xFF, 0xFF00, 0xFF0000, 0xFF000000),
+ (0x0, 0x0, 0x0, 0x0),
+ (0xFF000000, 0xFF0000, 0xFF00, 0x0),
+ ],
+ 24: [(0xFF0000, 0xFF00, 0xFF)],
+ 16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],
+ }
+ MASK_MODES = {
+ (32, (0xFF0000, 0xFF00, 0xFF, 0x0)): "BGRX",
+ (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): "XBGR",
+ (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): "RGBA",
+ (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): "BGRA",
+ (32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
+ (24, (0xFF0000, 0xFF00, 0xFF)): "BGR",
+ (16, (0xF800, 0x7E0, 0x1F)): "BGR;16",
+ (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"]]
+ ):
+ raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])]
+ self.mode = "RGBA" if "A" in raw_mode 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"])]
+ else:
+ raise IOError("Unsupported BMP bitfields layout")
+ else:
+ raise IOError("Unsupported BMP bitfields layout")
+ elif file_info["compression"] == self.RAW:
+ 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"])
+
+ # --------------- 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"])
+ 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"]))
+ )
+
+ # ----------------- Check if greyscale and ignore palette if so
+ for ind, val in enumerate(indices):
+ rgb = palette[ind * padding : ind * padding + 3]
+ if rgb != o8(val) * 3:
+ greyscale = False
+
+ # ------- If all colors are grey, white or black, ditch palette
+ if greyscale:
+ self.mode = "1" if file_info["colors"] == 2 else "L"
+ raw_mode = self.mode
+ else:
+ self.mode = "P"
+ 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"],
+ ),
+ )
+ ]
+
+ def _open(self):
+ """ Open file, check magic number and read header """
+ # read 14 bytes: magic number, filesize, reserved, header final offset
+ head_data = self.fp.read(14)
+ # choke if the file does not have the required magic bytes
+ if head_data[0:2] != b"BM":
+ raise SyntaxError("Not a BMP file")
+ # read the start position of the BMP image data (u32)
+ offset = i32(head_data[10:14])
+ # load bitmap information (offset=raster info)
+ self._bitmap(offset=offset)
+
+
+# =============================================================================
+# Image plugin for the DIB format (BMP alias)
+# =============================================================================
+class DibImageFile(BmpImageFile):
+
+ format = "DIB"
+ format_description = "Windows Bitmap"
+
+ def _open(self):
+ self._bitmap()
+
+
+#
+# --------------------------------------------------------------------
+# Write BMP file
+
+
+SAVE = {
+ "1": ("1", 1, 2),
+ "L": ("L", 8, 256),
+ "P": ("P", 8, 256),
+ "RGB": ("BGR", 24, 0),
+ "RGBA": ("BGRA", 32, 0),
+}
+
+
+def _dib_save(im, fp, filename):
+ _save(im, fp, filename, False)
+
+
+def _save(im, fp, filename, bitmap_header=True):
+ try:
+ rawmode, bits, colors = SAVE[im.mode]
+ except KeyError:
+ raise IOError("cannot write mode %s as BMP" % im.mode)
+
+ info = im.encoderinfo
+
+ dpi = info.get("dpi", (96, 96))
+
+ # 1 meter == 39.3701 inches
+ ppm = tuple(map(lambda x: int(x * 39.3701 + 0.5), dpi))
+
+ stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)
+ header = 40 # or 64 for OS/2 version 2
+ image = stride * im.size[1]
+
+ # bitmap header
+ if bitmap_header:
+ offset = 14 + header + colors * 4
+ fp.write(
+ b"BM"
+ + o32(offset + image) # file type (magic)
+ + o32(0) # file size
+ + o32(offset) # reserved
+ ) # image data offset
+
+ # bitmap info header
+ fp.write(
+ o32(header) # info header size
+ + o32(im.size[0]) # width
+ + o32(im.size[1]) # height
+ + o16(1) # planes
+ + o16(bits) # depth
+ + o32(0) # compression (0=uncompressed)
+ + o32(image) # size of bitmap
+ + o32(ppm[0]) # resolution
+ + o32(ppm[1]) # resolution
+ + o32(colors) # colors used
+ + o32(colors) # colors important
+ )
+
+ fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
+
+ if im.mode == "1":
+ for i in (0, 255):
+ fp.write(o8(i) * 4)
+ elif im.mode == "L":
+ for i in range(256):
+ fp.write(o8(i) * 4)
+ elif im.mode == "P":
+ fp.write(im.im.getpalette("RGB", "BGRX"))
+
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))])
+
+
+#
+# --------------------------------------------------------------------
+# Registry
+
+
+Image.register_open(BmpImageFile.format, BmpImageFile, _accept)
+Image.register_save(BmpImageFile.format, _save)
+
+Image.register_extension(BmpImageFile.format, ".bmp")
+
+Image.register_mime(BmpImageFile.format, "image/bmp")
+
+Image.register_open(DibImageFile.format, DibImageFile, _dib_accept)
+Image.register_save(DibImageFile.format, _dib_save)
+
+Image.register_extension(DibImageFile.format, ".dib")
+
+Image.register_mime(DibImageFile.format, "image/bmp")
diff --git a/contrib/python/Pillow/py2/PIL/BufrStubImagePlugin.py b/contrib/python/Pillow/py2/PIL/BufrStubImagePlugin.py
new file mode 100644
index 0000000000..56cac3bb14
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/BufrStubImagePlugin.py
@@ -0,0 +1,73 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# BUFR stub adapter
+#
+# Copyright (c) 1996-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFile
+
+_handler = None
+
+
+def register_handler(handler):
+ """
+ Install application-specific BUFR image handler.
+
+ :param handler: Handler object.
+ """
+ global _handler
+ _handler = handler
+
+
+# --------------------------------------------------------------------
+# Image adapter
+
+
+def _accept(prefix):
+ return prefix[:4] == b"BUFR" or prefix[:4] == b"ZCZC"
+
+
+class BufrStubImageFile(ImageFile.StubImageFile):
+
+ format = "BUFR"
+ format_description = "BUFR"
+
+ def _open(self):
+
+ offset = self.fp.tell()
+
+ if not _accept(self.fp.read(4)):
+ raise SyntaxError("Not a BUFR file")
+
+ self.fp.seek(offset)
+
+ # make something up
+ self.mode = "F"
+ self._size = 1, 1
+
+ loader = self._load()
+ if loader:
+ loader.open(self)
+
+ def _load(self):
+ return _handler
+
+
+def _save(im, fp, filename):
+ if _handler is None or not hasattr("_handler", "save"):
+ raise IOError("BUFR save handler not installed")
+ _handler.save(im, fp, filename)
+
+
+# --------------------------------------------------------------------
+# Registry
+
+Image.register_open(BufrStubImageFile.format, BufrStubImageFile, _accept)
+Image.register_save(BufrStubImageFile.format, _save)
+
+Image.register_extension(BufrStubImageFile.format, ".bufr")
diff --git a/contrib/python/Pillow/py2/PIL/ContainerIO.py b/contrib/python/Pillow/py2/PIL/ContainerIO.py
new file mode 100644
index 0000000000..3cf9d82d2c
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ContainerIO.py
@@ -0,0 +1,117 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# a class to read from a container file
+#
+# History:
+# 1995-06-18 fl Created
+# 1995-09-07 fl Added readline(), readlines()
+#
+# Copyright (c) 1997-2001 by Secret Labs AB
+# Copyright (c) 1995 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+##
+# A file object that provides read access to a part of an existing
+# file (for example a TAR file).
+
+import io
+
+
+class ContainerIO(object):
+ def __init__(self, file, offset, length):
+ """
+ Create file object.
+
+ :param file: Existing file.
+ :param offset: Start of region, in bytes.
+ :param length: Size of region, in bytes.
+ """
+ self.fh = file
+ self.pos = 0
+ self.offset = offset
+ self.length = length
+ self.fh.seek(offset)
+
+ ##
+ # Always false.
+
+ def isatty(self):
+ return False
+
+ def seek(self, offset, mode=io.SEEK_SET):
+ """
+ Move file pointer.
+
+ :param offset: Offset in bytes.
+ :param mode: Starting position. Use 0 for beginning of region, 1
+ for current offset, and 2 for end of region. You cannot move
+ the pointer outside the defined region.
+ """
+ if mode == 1:
+ self.pos = self.pos + offset
+ elif mode == 2:
+ self.pos = self.length + offset
+ else:
+ self.pos = offset
+ # clamp
+ self.pos = max(0, min(self.pos, self.length))
+ self.fh.seek(self.offset + self.pos)
+
+ def tell(self):
+ """
+ Get current file pointer.
+
+ :returns: Offset from start of region, in bytes.
+ """
+ return self.pos
+
+ def read(self, n=0):
+ """
+ Read data.
+
+ :param n: Number of bytes to read. If omitted or zero,
+ read until end of region.
+ :returns: An 8-bit string.
+ """
+ if n:
+ n = min(n, self.length - self.pos)
+ else:
+ n = self.length - self.pos
+ if not n: # EOF
+ return ""
+ self.pos = self.pos + n
+ return self.fh.read(n)
+
+ def readline(self):
+ """
+ Read a line of text.
+
+ :returns: An 8-bit string.
+ """
+ s = ""
+ while True:
+ c = self.read(1)
+ if not c:
+ break
+ s = s + c
+ if c == "\n":
+ break
+ return s
+
+ def readlines(self):
+ """
+ Read multiple lines of text.
+
+ :returns: A list of 8-bit strings.
+ """
+ lines = []
+ while True:
+ s = self.readline()
+ if not s:
+ break
+ lines.append(s)
+ return lines
diff --git a/contrib/python/Pillow/py2/PIL/CurImagePlugin.py b/contrib/python/Pillow/py2/PIL/CurImagePlugin.py
new file mode 100644
index 0000000000..9e2d8c96f7
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/CurImagePlugin.py
@@ -0,0 +1,81 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Windows Cursor support for PIL
+#
+# notes:
+# uses BmpImagePlugin.py to read the bitmap data.
+#
+# history:
+# 96-05-27 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import print_function
+
+from . import BmpImagePlugin, Image
+from ._binary import i8, i16le as i16, i32le as i32
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+#
+# --------------------------------------------------------------------
+
+
+def _accept(prefix):
+ return prefix[:4] == b"\0\0\2\0"
+
+
+##
+# Image plugin for Windows Cursor files.
+
+
+class CurImageFile(BmpImagePlugin.BmpImageFile):
+
+ format = "CUR"
+ format_description = "Windows Cursor"
+
+ def _open(self):
+
+ offset = self.fp.tell()
+
+ # check magic
+ s = self.fp.read(6)
+ if not _accept(s):
+ raise SyntaxError("not a CUR file")
+
+ # pick the largest cursor in the file
+ m = b""
+ for i in range(i16(s[4:])):
+ s = self.fp.read(16)
+ if not m:
+ m = s
+ elif i8(s[0]) > i8(m[0]) and i8(s[1]) > i8(m[1]):
+ m = s
+ if not m:
+ raise TypeError("No cursors were found")
+
+ # load as bitmap
+ self._bitmap(i32(m[12:]) + offset)
+
+ # patch up the bitmap height
+ self._size = self.size[0], self.size[1] // 2
+ d, e, o, a = self.tile[0]
+ self.tile[0] = d, (0, 0) + self.size, o, a
+
+ return
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_open(CurImageFile.format, CurImageFile, _accept)
+
+Image.register_extension(CurImageFile.format, ".cur")
diff --git a/contrib/python/Pillow/py2/PIL/DcxImagePlugin.py b/contrib/python/Pillow/py2/PIL/DcxImagePlugin.py
new file mode 100644
index 0000000000..57c321417b
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/DcxImagePlugin.py
@@ -0,0 +1,99 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# DCX file handling
+#
+# DCX is a container file format defined by Intel, commonly used
+# for fax applications. Each DCX file consists of a directory
+# (a list of file offsets) followed by a set of (usually 1-bit)
+# PCX files.
+#
+# History:
+# 1995-09-09 fl Created
+# 1996-03-20 fl Properly derived from PcxImageFile.
+# 1998-07-15 fl Renamed offset attribute to avoid name clash
+# 2002-07-30 fl Fixed file handling
+#
+# Copyright (c) 1997-98 by Secret Labs AB.
+# Copyright (c) 1995-96 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+from ._binary import i32le as i32
+from .PcxImagePlugin import PcxImageFile
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.2"
+
+MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then?
+
+
+def _accept(prefix):
+ return len(prefix) >= 4 and i32(prefix) == MAGIC
+
+
+##
+# Image plugin for the Intel DCX format.
+
+
+class DcxImageFile(PcxImageFile):
+
+ format = "DCX"
+ format_description = "Intel DCX"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+
+ # Header
+ s = self.fp.read(4)
+ if i32(s) != MAGIC:
+ raise SyntaxError("not a DCX file")
+
+ # Component directory
+ self._offset = []
+ for i in range(1024):
+ offset = i32(self.fp.read(4))
+ if not offset:
+ break
+ self._offset.append(offset)
+
+ self.__fp = self.fp
+ self.frame = None
+ self.seek(0)
+
+ @property
+ def n_frames(self):
+ return len(self._offset)
+
+ @property
+ def is_animated(self):
+ return len(self._offset) > 1
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+ self.frame = frame
+ self.fp = self.__fp
+ self.fp.seek(self._offset[frame])
+ PcxImageFile._open(self)
+
+ def tell(self):
+ return self.frame
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+Image.register_open(DcxImageFile.format, DcxImageFile, _accept)
+
+Image.register_extension(DcxImageFile.format, ".dcx")
diff --git a/contrib/python/Pillow/py2/PIL/DdsImagePlugin.py b/contrib/python/Pillow/py2/PIL/DdsImagePlugin.py
new file mode 100644
index 0000000000..e6622d14f0
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/DdsImagePlugin.py
@@ -0,0 +1,178 @@
+"""
+A Pillow loader for .dds files (S3TC-compressed aka DXTC)
+Jerome Leclanche <jerome@leclan.ch>
+
+Documentation:
+ https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt
+
+The contents of this file are hereby released in the public domain (CC0)
+Full text of the CC0 license:
+ https://creativecommons.org/publicdomain/zero/1.0/
+"""
+
+import struct
+from io import BytesIO
+
+from . import Image, ImageFile
+
+# Magic ("DDS ")
+DDS_MAGIC = 0x20534444
+
+# DDS flags
+DDSD_CAPS = 0x1
+DDSD_HEIGHT = 0x2
+DDSD_WIDTH = 0x4
+DDSD_PITCH = 0x8
+DDSD_PIXELFORMAT = 0x1000
+DDSD_MIPMAPCOUNT = 0x20000
+DDSD_LINEARSIZE = 0x80000
+DDSD_DEPTH = 0x800000
+
+# DDS caps
+DDSCAPS_COMPLEX = 0x8
+DDSCAPS_TEXTURE = 0x1000
+DDSCAPS_MIPMAP = 0x400000
+
+DDSCAPS2_CUBEMAP = 0x200
+DDSCAPS2_CUBEMAP_POSITIVEX = 0x400
+DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800
+DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000
+DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000
+DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000
+DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000
+DDSCAPS2_VOLUME = 0x200000
+
+# Pixel Format
+DDPF_ALPHAPIXELS = 0x1
+DDPF_ALPHA = 0x2
+DDPF_FOURCC = 0x4
+DDPF_PALETTEINDEXED8 = 0x20
+DDPF_RGB = 0x40
+DDPF_LUMINANCE = 0x20000
+
+
+# dds.h
+
+DDS_FOURCC = DDPF_FOURCC
+DDS_RGB = DDPF_RGB
+DDS_RGBA = DDPF_RGB | DDPF_ALPHAPIXELS
+DDS_LUMINANCE = DDPF_LUMINANCE
+DDS_LUMINANCEA = DDPF_LUMINANCE | DDPF_ALPHAPIXELS
+DDS_ALPHA = DDPF_ALPHA
+DDS_PAL8 = DDPF_PALETTEINDEXED8
+
+DDS_HEADER_FLAGS_TEXTURE = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
+DDS_HEADER_FLAGS_MIPMAP = DDSD_MIPMAPCOUNT
+DDS_HEADER_FLAGS_VOLUME = DDSD_DEPTH
+DDS_HEADER_FLAGS_PITCH = DDSD_PITCH
+DDS_HEADER_FLAGS_LINEARSIZE = DDSD_LINEARSIZE
+
+DDS_HEIGHT = DDSD_HEIGHT
+DDS_WIDTH = DDSD_WIDTH
+
+DDS_SURFACE_FLAGS_TEXTURE = DDSCAPS_TEXTURE
+DDS_SURFACE_FLAGS_MIPMAP = DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
+DDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS_COMPLEX
+
+DDS_CUBEMAP_POSITIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
+DDS_CUBEMAP_NEGATIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
+DDS_CUBEMAP_POSITIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
+DDS_CUBEMAP_NEGATIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
+DDS_CUBEMAP_POSITIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
+DDS_CUBEMAP_NEGATIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
+
+
+# DXT1
+DXT1_FOURCC = 0x31545844
+
+# DXT3
+DXT3_FOURCC = 0x33545844
+
+# DXT5
+DXT5_FOURCC = 0x35545844
+
+
+# dxgiformat.h
+
+DXGI_FORMAT_BC7_TYPELESS = 97
+DXGI_FORMAT_BC7_UNORM = 98
+DXGI_FORMAT_BC7_UNORM_SRGB = 99
+
+
+class DdsImageFile(ImageFile.ImageFile):
+ format = "DDS"
+ format_description = "DirectDraw Surface"
+
+ def _open(self):
+ magic, header_size = struct.unpack("<II", self.fp.read(8))
+ if header_size != 124:
+ raise IOError("Unsupported header size %r" % (header_size))
+ header_bytes = self.fp.read(header_size - 4)
+ if len(header_bytes) != 120:
+ raise IOError("Incomplete header: %s bytes" % len(header_bytes))
+ header = BytesIO(header_bytes)
+
+ flags, height, width = struct.unpack("<3I", header.read(12))
+ self._size = (width, height)
+ self.mode = "RGBA"
+
+ pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
+ struct.unpack("<11I", header.read(44)) # reserved
+
+ # pixel format
+ pfsize, pfflags = struct.unpack("<2I", header.read(8))
+ fourcc = header.read(4)
+ (bitcount,) = struct.unpack("<I", header.read(4))
+ masks = struct.unpack("<4I", header.read(16))
+ if pfflags & 0x40:
+ # DDPF_RGB - Texture contains uncompressed RGB data
+ masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)}
+ rawmode = ""
+ if bitcount == 32:
+ rawmode += masks[0xFF000000]
+ rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]
+
+ self.tile = [("raw", (0, 0) + self.size, 0, (rawmode, 0, 1))]
+ else:
+ data_start = header_size + 4
+ n = 0
+ if fourcc == b"DXT1":
+ self.pixel_format = "DXT1"
+ n = 1
+ elif fourcc == b"DXT3":
+ self.pixel_format = "DXT3"
+ n = 2
+ elif fourcc == b"DXT5":
+ self.pixel_format = "DXT5"
+ n = 3
+ elif fourcc == b"DX10":
+ data_start += 20
+ # ignoring flags which pertain to volume textures and cubemaps
+ dxt10 = BytesIO(self.fp.read(20))
+ dxgi_format, dimension = struct.unpack("<II", dxt10.read(8))
+ if dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):
+ self.pixel_format = "BC7"
+ n = 7
+ elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:
+ self.pixel_format = "BC7"
+ self.im_info["gamma"] = 1 / 2.2
+ n = 7
+ else:
+ raise NotImplementedError(
+ "Unimplemented DXGI format %d" % (dxgi_format)
+ )
+ else:
+ raise NotImplementedError("Unimplemented pixel format %r" % (fourcc))
+
+ self.tile = [("bcn", (0, 0) + self.size, data_start, (n))]
+
+ def load_seek(self, pos):
+ pass
+
+
+def _validate(prefix):
+ return prefix[:4] == b"DDS "
+
+
+Image.register_open(DdsImageFile.format, DdsImageFile, _validate)
+Image.register_extension(DdsImageFile.format, ".dds")
diff --git a/contrib/python/Pillow/py2/PIL/EpsImagePlugin.py b/contrib/python/Pillow/py2/PIL/EpsImagePlugin.py
new file mode 100644
index 0000000000..219f2dbb89
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/EpsImagePlugin.py
@@ -0,0 +1,433 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# EPS file handling
+#
+# History:
+# 1995-09-01 fl Created (0.1)
+# 1996-05-18 fl Don't choke on "atend" fields, Ghostscript interface (0.2)
+# 1996-08-22 fl Don't choke on floating point BoundingBox values
+# 1996-08-23 fl Handle files from Macintosh (0.3)
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.4)
+# 2003-09-07 fl Check gs.close status (from Federico Di Gregorio) (0.5)
+# 2014-05-07 e Handling of EPS with binary preview and fixed resolution
+# resizing
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+import os
+import re
+import sys
+
+from . import Image, ImageFile
+from ._binary import i32le as i32
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.5"
+
+#
+# --------------------------------------------------------------------
+
+split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
+field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
+
+gs_windows_binary = None
+if sys.platform.startswith("win"):
+ import shutil
+
+ if hasattr(shutil, "which"):
+ which = shutil.which
+ else:
+ # Python 2
+ import distutils.spawn
+
+ which = distutils.spawn.find_executable
+ for binary in ("gswin32c", "gswin64c", "gs"):
+ if which(binary) is not None:
+ gs_windows_binary = binary
+ break
+ else:
+ gs_windows_binary = False
+
+
+def has_ghostscript():
+ if gs_windows_binary:
+ return True
+ if not sys.platform.startswith("win"):
+ import subprocess
+
+ try:
+ with open(os.devnull, "wb") as devnull:
+ subprocess.check_call(["gs", "--version"], stdout=devnull)
+ return True
+ except OSError:
+ # No Ghostscript
+ pass
+ return False
+
+
+def Ghostscript(tile, size, fp, scale=1):
+ """Render an image using Ghostscript"""
+
+ # Unpack decoder tile
+ decoder, tile, offset, data = tile[0]
+ length, bbox = data
+
+ # Hack to support hi-res rendering
+ scale = int(scale) or 1
+ # orig_size = size
+ # orig_bbox = bbox
+ size = (size[0] * scale, size[1] * scale)
+ # resolution is dependent on bbox and size
+ res = (
+ float((72.0 * size[0]) / (bbox[2] - bbox[0])),
+ float((72.0 * size[1]) / (bbox[3] - bbox[1])),
+ )
+
+ import subprocess
+ import tempfile
+
+ out_fd, outfile = tempfile.mkstemp()
+ os.close(out_fd)
+
+ infile_temp = None
+ if hasattr(fp, "name") and os.path.exists(fp.name):
+ infile = fp.name
+ else:
+ in_fd, infile_temp = tempfile.mkstemp()
+ os.close(in_fd)
+ infile = infile_temp
+
+ # Ignore length and offset!
+ # Ghostscript can read it
+ # Copy whole file to read in Ghostscript
+ with open(infile_temp, "wb") as f:
+ # fetch length of fp
+ fp.seek(0, io.SEEK_END)
+ fsize = fp.tell()
+ # ensure start position
+ # go back
+ fp.seek(0)
+ lengthfile = fsize
+ while lengthfile > 0:
+ s = fp.read(min(lengthfile, 100 * 1024))
+ if not s:
+ break
+ lengthfile -= len(s)
+ f.write(s)
+
+ # Build Ghostscript command
+ command = [
+ "gs",
+ "-q", # quiet mode
+ "-g%dx%d" % size, # set output geometry (pixels)
+ "-r%fx%f" % res, # set input DPI (dots per inch)
+ "-dBATCH", # exit after processing
+ "-dNOPAUSE", # don't pause between pages
+ "-dSAFER", # safe mode
+ "-sDEVICE=ppmraw", # ppm driver
+ "-sOutputFile=%s" % outfile, # output file
+ # adjust for image origin
+ "-c",
+ "%d %d translate" % (-bbox[0], -bbox[1]),
+ "-f",
+ infile, # input file
+ # showpage (see https://bugs.ghostscript.com/show_bug.cgi?id=698272)
+ "-c",
+ "showpage",
+ ]
+
+ if gs_windows_binary is not None:
+ if not gs_windows_binary:
+ raise WindowsError("Unable to locate Ghostscript on paths")
+ command[0] = gs_windows_binary
+
+ # push data through Ghostscript
+ try:
+ startupinfo = None
+ if sys.platform.startswith("win"):
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ subprocess.check_call(command, startupinfo=startupinfo)
+ im = Image.open(outfile)
+ im.load()
+ finally:
+ try:
+ os.unlink(outfile)
+ if infile_temp:
+ os.unlink(infile_temp)
+ except OSError:
+ pass
+
+ return im.im.copy()
+
+
+class PSFile(object):
+ """
+ Wrapper for bytesio object that treats either CR or LF as end of line.
+ """
+
+ def __init__(self, fp):
+ self.fp = fp
+ self.char = None
+
+ def seek(self, offset, whence=io.SEEK_SET):
+ self.char = None
+ self.fp.seek(offset, whence)
+
+ def readline(self):
+ s = self.char or b""
+ self.char = None
+
+ c = self.fp.read(1)
+ while c not in b"\r\n":
+ s = s + c
+ c = self.fp.read(1)
+
+ self.char = self.fp.read(1)
+ # line endings can be 1 or 2 of \r \n, in either order
+ if self.char in b"\r\n":
+ self.char = None
+
+ return s.decode("latin-1")
+
+
+def _accept(prefix):
+ return prefix[:4] == b"%!PS" or (len(prefix) >= 4 and i32(prefix) == 0xC6D3D0C5)
+
+
+##
+# Image plugin for Encapsulated Postscript. This plugin supports only
+# a few variants of this format.
+
+
+class EpsImageFile(ImageFile.ImageFile):
+ """EPS File Parser for the Python Imaging Library"""
+
+ format = "EPS"
+ format_description = "Encapsulated Postscript"
+
+ mode_map = {1: "L", 2: "LAB", 3: "RGB", 4: "CMYK"}
+
+ def _open(self):
+ (length, offset) = self._find_offset(self.fp)
+
+ # Rewrap the open file pointer in something that will
+ # convert line endings and decode to latin-1.
+ fp = PSFile(self.fp)
+
+ # go to offset - start of "%!PS"
+ fp.seek(offset)
+
+ box = None
+
+ self.mode = "RGB"
+ self._size = 1, 1 # FIXME: huh?
+
+ #
+ # Load EPS header
+
+ s_raw = fp.readline()
+ s = s_raw.strip("\r\n")
+
+ while s_raw:
+ if s:
+ if len(s) > 255:
+ raise SyntaxError("not an EPS file")
+
+ try:
+ m = split.match(s)
+ except re.error:
+ raise SyntaxError("not an EPS file")
+
+ if m:
+ k, v = m.group(1, 2)
+ self.info[k] = v
+ if k == "BoundingBox":
+ try:
+ # Note: The DSC spec says that BoundingBox
+ # fields should be integers, but some drivers
+ # put floating point values there anyway.
+ box = [int(float(i)) for i in v.split()]
+ self._size = box[2] - box[0], box[3] - box[1]
+ self.tile = [
+ ("eps", (0, 0) + self.size, offset, (length, box))
+ ]
+ except Exception:
+ pass
+
+ else:
+ m = field.match(s)
+ if m:
+ k = m.group(1)
+
+ if k == "EndComments":
+ break
+ if k[:8] == "PS-Adobe":
+ self.info[k[:8]] = k[9:]
+ else:
+ self.info[k] = ""
+ elif s[0] == "%":
+ # handle non-DSC Postscript comments that some
+ # tools mistakenly put in the Comments section
+ pass
+ else:
+ raise IOError("bad EPS header")
+
+ s_raw = fp.readline()
+ s = s_raw.strip("\r\n")
+
+ if s and s[:1] != "%":
+ break
+
+ #
+ # Scan for an "ImageData" descriptor
+
+ while s[:1] == "%":
+
+ if len(s) > 255:
+ raise SyntaxError("not an EPS file")
+
+ if s[:11] == "%ImageData:":
+ # Encoded bitmapped image.
+ x, y, bi, mo = s[11:].split(None, 7)[:4]
+
+ if int(bi) != 8:
+ break
+ try:
+ self.mode = self.mode_map[int(mo)]
+ except ValueError:
+ break
+
+ self._size = int(x), int(y)
+ return
+
+ s = fp.readline().strip("\r\n")
+ if not s:
+ break
+
+ if not box:
+ raise IOError("cannot determine EPS bounding box")
+
+ def _find_offset(self, fp):
+
+ s = fp.read(160)
+
+ if s[:4] == b"%!PS":
+ # for HEAD without binary preview
+ fp.seek(0, io.SEEK_END)
+ length = fp.tell()
+ offset = 0
+ elif i32(s[0:4]) == 0xC6D3D0C5:
+ # FIX for: Some EPS file not handled correctly / issue #302
+ # EPS can contain binary data
+ # or start directly with latin coding
+ # more info see:
+ # https://web.archive.org/web/20160528181353/http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
+ offset = i32(s[4:8])
+ length = i32(s[8:12])
+ else:
+ raise SyntaxError("not an EPS file")
+
+ return (length, offset)
+
+ def load(self, scale=1):
+ # Load EPS via Ghostscript
+ if not self.tile:
+ return
+ self.im = Ghostscript(self.tile, self.size, self.fp, scale)
+ self.mode = self.im.mode
+ self._size = self.im.size
+ self.tile = []
+
+ def load_seek(self, *args, **kwargs):
+ # we can't incrementally load, so force ImageFile.parser to
+ # use our custom load method by defining this method.
+ pass
+
+
+#
+# --------------------------------------------------------------------
+
+
+def _save(im, fp, filename, eps=1):
+ """EPS Writer for the Python Imaging Library."""
+
+ #
+ # make sure image data is available
+ im.load()
+
+ #
+ # determine postscript image mode
+ if im.mode == "L":
+ operator = (8, 1, "image")
+ elif im.mode == "RGB":
+ operator = (8, 3, "false 3 colorimage")
+ elif im.mode == "CMYK":
+ operator = (8, 4, "false 4 colorimage")
+ else:
+ raise ValueError("image mode is not supported")
+
+ base_fp = fp
+ wrapped_fp = False
+ if fp != sys.stdout:
+ if sys.version_info.major > 2:
+ fp = io.TextIOWrapper(fp, encoding="latin-1")
+ wrapped_fp = True
+
+ try:
+ if eps:
+ #
+ # write EPS header
+ fp.write("%!PS-Adobe-3.0 EPSF-3.0\n")
+ fp.write("%%Creator: PIL 0.1 EpsEncode\n")
+ # fp.write("%%CreationDate: %s"...)
+ fp.write("%%%%BoundingBox: 0 0 %d %d\n" % im.size)
+ fp.write("%%Pages: 1\n")
+ fp.write("%%EndComments\n")
+ fp.write("%%Page: 1 1\n")
+ fp.write("%%ImageData: %d %d " % im.size)
+ fp.write('%d %d 0 1 1 "%s"\n' % operator)
+
+ #
+ # image header
+ fp.write("gsave\n")
+ fp.write("10 dict begin\n")
+ fp.write("/buf %d string def\n" % (im.size[0] * operator[1]))
+ fp.write("%d %d scale\n" % im.size)
+ fp.write("%d %d 8\n" % im.size) # <= bits
+ fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1]))
+ fp.write("{ currentfile buf readhexstring pop } bind\n")
+ fp.write(operator[2] + "\n")
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+ ImageFile._save(im, base_fp, [("eps", (0, 0) + im.size, 0, None)])
+
+ fp.write("\n%%%%EndBinary\n")
+ fp.write("grestore end\n")
+ if hasattr(fp, "flush"):
+ fp.flush()
+ finally:
+ if wrapped_fp:
+ fp.detach()
+
+
+#
+# --------------------------------------------------------------------
+
+
+Image.register_open(EpsImageFile.format, EpsImageFile, _accept)
+
+Image.register_save(EpsImageFile.format, _save)
+
+Image.register_extensions(EpsImageFile.format, [".ps", ".eps"])
+
+Image.register_mime(EpsImageFile.format, "application/postscript")
diff --git a/contrib/python/Pillow/py2/PIL/ExifTags.py b/contrib/python/Pillow/py2/PIL/ExifTags.py
new file mode 100644
index 0000000000..47a981e0f4
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ExifTags.py
@@ -0,0 +1,314 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# EXIF tags
+#
+# Copyright (c) 2003 by Secret Labs AB
+#
+# See the README file for information on usage and redistribution.
+#
+
+##
+# This module provides constants and clear-text names for various
+# well-known EXIF tags.
+##
+
+##
+# Maps EXIF tags to tag names.
+
+TAGS = {
+ # possibly incomplete
+ 0x000B: "ProcessingSoftware",
+ 0x00FE: "NewSubfileType",
+ 0x00FF: "SubfileType",
+ 0x0100: "ImageWidth",
+ 0x0101: "ImageLength",
+ 0x0102: "BitsPerSample",
+ 0x0103: "Compression",
+ 0x0106: "PhotometricInterpretation",
+ 0x0107: "Thresholding",
+ 0x0108: "CellWidth",
+ 0x0109: "CellLength",
+ 0x010A: "FillOrder",
+ 0x010D: "DocumentName",
+ 0x010E: "ImageDescription",
+ 0x010F: "Make",
+ 0x0110: "Model",
+ 0x0111: "StripOffsets",
+ 0x0112: "Orientation",
+ 0x0115: "SamplesPerPixel",
+ 0x0116: "RowsPerStrip",
+ 0x0117: "StripByteCounts",
+ 0x0118: "MinSampleValue",
+ 0x0119: "MaxSampleValue",
+ 0x011A: "XResolution",
+ 0x011B: "YResolution",
+ 0x011C: "PlanarConfiguration",
+ 0x011D: "PageName",
+ 0x0120: "FreeOffsets",
+ 0x0121: "FreeByteCounts",
+ 0x0122: "GrayResponseUnit",
+ 0x0123: "GrayResponseCurve",
+ 0x0124: "T4Options",
+ 0x0125: "T6Options",
+ 0x0128: "ResolutionUnit",
+ 0x0129: "PageNumber",
+ 0x012D: "TransferFunction",
+ 0x0131: "Software",
+ 0x0132: "DateTime",
+ 0x013B: "Artist",
+ 0x013C: "HostComputer",
+ 0x013D: "Predictor",
+ 0x013E: "WhitePoint",
+ 0x013F: "PrimaryChromaticities",
+ 0x0140: "ColorMap",
+ 0x0141: "HalftoneHints",
+ 0x0142: "TileWidth",
+ 0x0143: "TileLength",
+ 0x0144: "TileOffsets",
+ 0x0145: "TileByteCounts",
+ 0x014A: "SubIFDs",
+ 0x014C: "InkSet",
+ 0x014D: "InkNames",
+ 0x014E: "NumberOfInks",
+ 0x0150: "DotRange",
+ 0x0151: "TargetPrinter",
+ 0x0152: "ExtraSamples",
+ 0x0153: "SampleFormat",
+ 0x0154: "SMinSampleValue",
+ 0x0155: "SMaxSampleValue",
+ 0x0156: "TransferRange",
+ 0x0157: "ClipPath",
+ 0x0158: "XClipPathUnits",
+ 0x0159: "YClipPathUnits",
+ 0x015A: "Indexed",
+ 0x015B: "JPEGTables",
+ 0x015F: "OPIProxy",
+ 0x0200: "JPEGProc",
+ 0x0201: "JpegIFOffset",
+ 0x0202: "JpegIFByteCount",
+ 0x0203: "JpegRestartInterval",
+ 0x0205: "JpegLosslessPredictors",
+ 0x0206: "JpegPointTransforms",
+ 0x0207: "JpegQTables",
+ 0x0208: "JpegDCTables",
+ 0x0209: "JpegACTables",
+ 0x0211: "YCbCrCoefficients",
+ 0x0212: "YCbCrSubSampling",
+ 0x0213: "YCbCrPositioning",
+ 0x0214: "ReferenceBlackWhite",
+ 0x02BC: "XMLPacket",
+ 0x1000: "RelatedImageFileFormat",
+ 0x1001: "RelatedImageWidth",
+ 0x1002: "RelatedImageLength",
+ 0x4746: "Rating",
+ 0x4749: "RatingPercent",
+ 0x800D: "ImageID",
+ 0x828D: "CFARepeatPatternDim",
+ 0x828E: "CFAPattern",
+ 0x828F: "BatteryLevel",
+ 0x8298: "Copyright",
+ 0x829A: "ExposureTime",
+ 0x829D: "FNumber",
+ 0x83BB: "IPTCNAA",
+ 0x8649: "ImageResources",
+ 0x8769: "ExifOffset",
+ 0x8773: "InterColorProfile",
+ 0x8822: "ExposureProgram",
+ 0x8824: "SpectralSensitivity",
+ 0x8825: "GPSInfo",
+ 0x8827: "ISOSpeedRatings",
+ 0x8828: "OECF",
+ 0x8829: "Interlace",
+ 0x882A: "TimeZoneOffset",
+ 0x882B: "SelfTimerMode",
+ 0x9000: "ExifVersion",
+ 0x9003: "DateTimeOriginal",
+ 0x9004: "DateTimeDigitized",
+ 0x9101: "ComponentsConfiguration",
+ 0x9102: "CompressedBitsPerPixel",
+ 0x9201: "ShutterSpeedValue",
+ 0x9202: "ApertureValue",
+ 0x9203: "BrightnessValue",
+ 0x9204: "ExposureBiasValue",
+ 0x9205: "MaxApertureValue",
+ 0x9206: "SubjectDistance",
+ 0x9207: "MeteringMode",
+ 0x9208: "LightSource",
+ 0x9209: "Flash",
+ 0x920A: "FocalLength",
+ 0x920B: "FlashEnergy",
+ 0x920C: "SpatialFrequencyResponse",
+ 0x920D: "Noise",
+ 0x9211: "ImageNumber",
+ 0x9212: "SecurityClassification",
+ 0x9213: "ImageHistory",
+ 0x9214: "SubjectLocation",
+ 0x9215: "ExposureIndex",
+ 0x9216: "TIFF/EPStandardID",
+ 0x927C: "MakerNote",
+ 0x9286: "UserComment",
+ 0x9290: "SubsecTime",
+ 0x9291: "SubsecTimeOriginal",
+ 0x9292: "SubsecTimeDigitized",
+ 0x9C9B: "XPTitle",
+ 0x9C9C: "XPComment",
+ 0x9C9D: "XPAuthor",
+ 0x9C9E: "XPKeywords",
+ 0x9C9F: "XPSubject",
+ 0xA000: "FlashPixVersion",
+ 0xA001: "ColorSpace",
+ 0xA002: "ExifImageWidth",
+ 0xA003: "ExifImageHeight",
+ 0xA004: "RelatedSoundFile",
+ 0xA005: "ExifInteroperabilityOffset",
+ 0xA20B: "FlashEnergy",
+ 0xA20C: "SpatialFrequencyResponse",
+ 0xA20E: "FocalPlaneXResolution",
+ 0xA20F: "FocalPlaneYResolution",
+ 0xA210: "FocalPlaneResolutionUnit",
+ 0xA214: "SubjectLocation",
+ 0xA215: "ExposureIndex",
+ 0xA217: "SensingMethod",
+ 0xA300: "FileSource",
+ 0xA301: "SceneType",
+ 0xA302: "CFAPattern",
+ 0xA401: "CustomRendered",
+ 0xA402: "ExposureMode",
+ 0xA403: "WhiteBalance",
+ 0xA404: "DigitalZoomRatio",
+ 0xA405: "FocalLengthIn35mmFilm",
+ 0xA406: "SceneCaptureType",
+ 0xA407: "GainControl",
+ 0xA408: "Contrast",
+ 0xA409: "Saturation",
+ 0xA40A: "Sharpness",
+ 0xA40B: "DeviceSettingDescription",
+ 0xA40C: "SubjectDistanceRange",
+ 0xA420: "ImageUniqueID",
+ 0xA430: "CameraOwnerName",
+ 0xA431: "BodySerialNumber",
+ 0xA432: "LensSpecification",
+ 0xA433: "LensMake",
+ 0xA434: "LensModel",
+ 0xA435: "LensSerialNumber",
+ 0xA500: "Gamma",
+ 0xC4A5: "PrintImageMatching",
+ 0xC612: "DNGVersion",
+ 0xC613: "DNGBackwardVersion",
+ 0xC614: "UniqueCameraModel",
+ 0xC615: "LocalizedCameraModel",
+ 0xC616: "CFAPlaneColor",
+ 0xC617: "CFALayout",
+ 0xC618: "LinearizationTable",
+ 0xC619: "BlackLevelRepeatDim",
+ 0xC61A: "BlackLevel",
+ 0xC61B: "BlackLevelDeltaH",
+ 0xC61C: "BlackLevelDeltaV",
+ 0xC61D: "WhiteLevel",
+ 0xC61E: "DefaultScale",
+ 0xC61F: "DefaultCropOrigin",
+ 0xC620: "DefaultCropSize",
+ 0xC621: "ColorMatrix1",
+ 0xC622: "ColorMatrix2",
+ 0xC623: "CameraCalibration1",
+ 0xC624: "CameraCalibration2",
+ 0xC625: "ReductionMatrix1",
+ 0xC626: "ReductionMatrix2",
+ 0xC627: "AnalogBalance",
+ 0xC628: "AsShotNeutral",
+ 0xC629: "AsShotWhiteXY",
+ 0xC62A: "BaselineExposure",
+ 0xC62B: "BaselineNoise",
+ 0xC62C: "BaselineSharpness",
+ 0xC62D: "BayerGreenSplit",
+ 0xC62E: "LinearResponseLimit",
+ 0xC62F: "CameraSerialNumber",
+ 0xC630: "LensInfo",
+ 0xC631: "ChromaBlurRadius",
+ 0xC632: "AntiAliasStrength",
+ 0xC633: "ShadowScale",
+ 0xC634: "DNGPrivateData",
+ 0xC635: "MakerNoteSafety",
+ 0xC65A: "CalibrationIlluminant1",
+ 0xC65B: "CalibrationIlluminant2",
+ 0xC65C: "BestQualityScale",
+ 0xC65D: "RawDataUniqueID",
+ 0xC68B: "OriginalRawFileName",
+ 0xC68C: "OriginalRawFileData",
+ 0xC68D: "ActiveArea",
+ 0xC68E: "MaskedAreas",
+ 0xC68F: "AsShotICCProfile",
+ 0xC690: "AsShotPreProfileMatrix",
+ 0xC691: "CurrentICCProfile",
+ 0xC692: "CurrentPreProfileMatrix",
+ 0xC6BF: "ColorimetricReference",
+ 0xC6F3: "CameraCalibrationSignature",
+ 0xC6F4: "ProfileCalibrationSignature",
+ 0xC6F6: "AsShotProfileName",
+ 0xC6F7: "NoiseReductionApplied",
+ 0xC6F8: "ProfileName",
+ 0xC6F9: "ProfileHueSatMapDims",
+ 0xC6FA: "ProfileHueSatMapData1",
+ 0xC6FB: "ProfileHueSatMapData2",
+ 0xC6FC: "ProfileToneCurve",
+ 0xC6FD: "ProfileEmbedPolicy",
+ 0xC6FE: "ProfileCopyright",
+ 0xC714: "ForwardMatrix1",
+ 0xC715: "ForwardMatrix2",
+ 0xC716: "PreviewApplicationName",
+ 0xC717: "PreviewApplicationVersion",
+ 0xC718: "PreviewSettingsName",
+ 0xC719: "PreviewSettingsDigest",
+ 0xC71A: "PreviewColorSpace",
+ 0xC71B: "PreviewDateTime",
+ 0xC71C: "RawImageDigest",
+ 0xC71D: "OriginalRawFileDigest",
+ 0xC71E: "SubTileBlockSize",
+ 0xC71F: "RowInterleaveFactor",
+ 0xC725: "ProfileLookTableDims",
+ 0xC726: "ProfileLookTableData",
+ 0xC740: "OpcodeList1",
+ 0xC741: "OpcodeList2",
+ 0xC74E: "OpcodeList3",
+ 0xC761: "NoiseProfile",
+}
+
+##
+# Maps EXIF GPS tags to tag names.
+
+GPSTAGS = {
+ 0: "GPSVersionID",
+ 1: "GPSLatitudeRef",
+ 2: "GPSLatitude",
+ 3: "GPSLongitudeRef",
+ 4: "GPSLongitude",
+ 5: "GPSAltitudeRef",
+ 6: "GPSAltitude",
+ 7: "GPSTimeStamp",
+ 8: "GPSSatellites",
+ 9: "GPSStatus",
+ 10: "GPSMeasureMode",
+ 11: "GPSDOP",
+ 12: "GPSSpeedRef",
+ 13: "GPSSpeed",
+ 14: "GPSTrackRef",
+ 15: "GPSTrack",
+ 16: "GPSImgDirectionRef",
+ 17: "GPSImgDirection",
+ 18: "GPSMapDatum",
+ 19: "GPSDestLatitudeRef",
+ 20: "GPSDestLatitude",
+ 21: "GPSDestLongitudeRef",
+ 22: "GPSDestLongitude",
+ 23: "GPSDestBearingRef",
+ 24: "GPSDestBearing",
+ 25: "GPSDestDistanceRef",
+ 26: "GPSDestDistance",
+ 27: "GPSProcessingMethod",
+ 28: "GPSAreaInformation",
+ 29: "GPSDateStamp",
+ 30: "GPSDifferential",
+ 31: "GPSHPositioningError",
+}
diff --git a/contrib/python/Pillow/py2/PIL/FitsStubImagePlugin.py b/contrib/python/Pillow/py2/PIL/FitsStubImagePlugin.py
new file mode 100644
index 0000000000..7e6d35ee56
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/FitsStubImagePlugin.py
@@ -0,0 +1,76 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# FITS stub adapter
+#
+# Copyright (c) 1998-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFile
+
+_handler = None
+
+
+def register_handler(handler):
+ """
+ Install application-specific FITS image handler.
+
+ :param handler: Handler object.
+ """
+ global _handler
+ _handler = handler
+
+
+# --------------------------------------------------------------------
+# Image adapter
+
+
+def _accept(prefix):
+ return prefix[:6] == b"SIMPLE"
+
+
+class FITSStubImageFile(ImageFile.StubImageFile):
+
+ format = "FITS"
+ format_description = "FITS"
+
+ def _open(self):
+
+ offset = self.fp.tell()
+
+ if not _accept(self.fp.read(6)):
+ raise SyntaxError("Not a FITS file")
+
+ # FIXME: add more sanity checks here; mandatory header items
+ # include SIMPLE, BITPIX, NAXIS, etc.
+
+ self.fp.seek(offset)
+
+ # make something up
+ self.mode = "F"
+ self._size = 1, 1
+
+ loader = self._load()
+ if loader:
+ loader.open(self)
+
+ def _load(self):
+ return _handler
+
+
+def _save(im, fp, filename):
+ if _handler is None or not hasattr("_handler", "save"):
+ raise IOError("FITS save handler not installed")
+ _handler.save(im, fp, filename)
+
+
+# --------------------------------------------------------------------
+# Registry
+
+Image.register_open(FITSStubImageFile.format, FITSStubImageFile, _accept)
+Image.register_save(FITSStubImageFile.format, _save)
+
+Image.register_extensions(FITSStubImageFile.format, [".fit", ".fits"])
diff --git a/contrib/python/Pillow/py2/PIL/FliImagePlugin.py b/contrib/python/Pillow/py2/PIL/FliImagePlugin.py
new file mode 100644
index 0000000000..82015e2fc1
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/FliImagePlugin.py
@@ -0,0 +1,181 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# FLI/FLC file handling.
+#
+# History:
+# 95-09-01 fl Created
+# 97-01-03 fl Fixed parser, setup decoder tile
+# 98-07-15 fl Renamed offset attribute to avoid name clash
+#
+# Copyright (c) Secret Labs AB 1997-98.
+# Copyright (c) Fredrik Lundh 1995-97.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8, i16le as i16, i32le as i32, o8
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.2"
+
+
+#
+# decoder
+
+
+def _accept(prefix):
+ return len(prefix) >= 6 and i16(prefix[4:6]) in [0xAF11, 0xAF12]
+
+
+##
+# Image plugin for the FLI/FLC animation format. Use the <b>seek</b>
+# method to load individual frames.
+
+
+class FliImageFile(ImageFile.ImageFile):
+
+ format = "FLI"
+ format_description = "Autodesk FLI/FLC Animation"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+
+ # HEAD
+ s = self.fp.read(128)
+ magic = i16(s[4:6])
+ if not (
+ magic in [0xAF11, 0xAF12]
+ and i16(s[14:16]) in [0, 3] # flags
+ and s[20:22] == b"\x00\x00" # reserved
+ ):
+ raise SyntaxError("not an FLI/FLC file")
+
+ # frames
+ self.__framecount = i16(s[6:8])
+
+ # image characteristics
+ self.mode = "P"
+ self._size = i16(s[8:10]), i16(s[10:12])
+
+ # animation speed
+ duration = i32(s[16:20])
+ if magic == 0xAF11:
+ duration = (duration * 1000) // 70
+ self.info["duration"] = duration
+
+ # look for palette
+ palette = [(a, a, a) for a in range(256)]
+
+ s = self.fp.read(16)
+
+ self.__offset = 128
+
+ if i16(s[4:6]) == 0xF100:
+ # prefix chunk; ignore it
+ self.__offset = self.__offset + i32(s)
+ s = self.fp.read(16)
+
+ if i16(s[4:6]) == 0xF1FA:
+ # look for palette chunk
+ s = self.fp.read(6)
+ if i16(s[4:6]) == 11:
+ self._palette(palette, 2)
+ elif i16(s[4:6]) == 4:
+ self._palette(palette, 0)
+
+ palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette]
+ self.palette = ImagePalette.raw("RGB", b"".join(palette))
+
+ # set things up to decode first frame
+ self.__frame = -1
+ self.__fp = self.fp
+ self.__rewind = self.fp.tell()
+ self.seek(0)
+
+ def _palette(self, palette, shift):
+ # load palette
+
+ i = 0
+ for e in range(i16(self.fp.read(2))):
+ s = self.fp.read(2)
+ i = i + i8(s[0])
+ n = i8(s[1])
+ if n == 0:
+ n = 256
+ s = self.fp.read(n * 3)
+ for n in range(0, len(s), 3):
+ r = i8(s[n]) << shift
+ g = i8(s[n + 1]) << shift
+ b = i8(s[n + 2]) << shift
+ palette[i] = (r, g, b)
+ i += 1
+
+ @property
+ def n_frames(self):
+ return self.__framecount
+
+ @property
+ def is_animated(self):
+ return self.__framecount > 1
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+ if frame < self.__frame:
+ self._seek(0)
+
+ for f in range(self.__frame + 1, frame + 1):
+ self._seek(f)
+
+ def _seek(self, frame):
+ if frame == 0:
+ self.__frame = -1
+ self.__fp.seek(self.__rewind)
+ self.__offset = 128
+ else:
+ # ensure that the previous frame was loaded
+ self.load()
+
+ if frame != self.__frame + 1:
+ raise ValueError("cannot seek to frame %d" % frame)
+ self.__frame = frame
+
+ # move to next frame
+ self.fp = self.__fp
+ self.fp.seek(self.__offset)
+
+ s = self.fp.read(4)
+ if not s:
+ raise EOFError
+
+ framesize = i32(s)
+
+ self.decodermaxblock = framesize
+ self.tile = [("fli", (0, 0) + self.size, self.__offset, None)]
+
+ self.__offset += framesize
+
+ def tell(self):
+ return self.__frame
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+#
+# registry
+
+Image.register_open(FliImageFile.format, FliImageFile, _accept)
+
+Image.register_extensions(FliImageFile.format, [".fli", ".flc"])
diff --git a/contrib/python/Pillow/py2/PIL/FontFile.py b/contrib/python/Pillow/py2/PIL/FontFile.py
new file mode 100644
index 0000000000..e57c2f3fd3
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/FontFile.py
@@ -0,0 +1,115 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# base class for raster font file parsers
+#
+# history:
+# 1997-06-05 fl created
+# 1997-08-19 fl restrict image width
+#
+# Copyright (c) 1997-1998 by Secret Labs AB
+# Copyright (c) 1997-1998 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import print_function
+
+import os
+
+from . import Image, _binary
+
+WIDTH = 800
+
+
+def puti16(fp, values):
+ # write network order (big-endian) 16-bit sequence
+ for v in values:
+ if v < 0:
+ v += 65536
+ fp.write(_binary.o16be(v))
+
+
+##
+# Base class for raster font file handlers.
+
+
+class FontFile(object):
+
+ bitmap = None
+
+ def __init__(self):
+
+ self.info = {}
+ self.glyph = [None] * 256
+
+ def __getitem__(self, ix):
+ return self.glyph[ix]
+
+ def compile(self):
+ """Create metrics and bitmap"""
+
+ if self.bitmap:
+ return
+
+ # create bitmap large enough to hold all data
+ h = w = maxwidth = 0
+ lines = 1
+ for glyph in self:
+ if glyph:
+ d, dst, src, im = glyph
+ h = max(h, src[3] - src[1])
+ w = w + (src[2] - src[0])
+ if w > WIDTH:
+ lines += 1
+ w = src[2] - src[0]
+ maxwidth = max(maxwidth, w)
+
+ xsize = maxwidth
+ ysize = lines * h
+
+ if xsize == 0 and ysize == 0:
+ return ""
+
+ self.ysize = h
+
+ # paste glyphs into bitmap
+ self.bitmap = Image.new("1", (xsize, ysize))
+ self.metrics = [None] * 256
+ x = y = 0
+ for i in range(256):
+ glyph = self[i]
+ if glyph:
+ d, dst, src, im = glyph
+ xx = src[2] - src[0]
+ # yy = src[3] - src[1]
+ x0, y0 = x, y
+ x = x + xx
+ if x > WIDTH:
+ x, y = 0, y + h
+ x0, y0 = x, y
+ x = xx
+ s = src[0] + x0, src[1] + y0, src[2] + x0, src[3] + y0
+ self.bitmap.paste(im.crop(src), s)
+ self.metrics[i] = d, dst, s
+
+ def save(self, filename):
+ """Save font"""
+
+ self.compile()
+
+ # font data
+ self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG")
+
+ # font metrics
+ with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
+ fp.write(b"PILfont\n")
+ fp.write((";;;;;;%d;\n" % self.ysize).encode("ascii")) # HACK!!!
+ fp.write(b"DATA\n")
+ for id in range(256):
+ m = self.metrics[id]
+ if not m:
+ puti16(fp, [0] * 10)
+ else:
+ puti16(fp, m[0] + m[1] + m[2])
diff --git a/contrib/python/Pillow/py2/PIL/FpxImagePlugin.py b/contrib/python/Pillow/py2/PIL/FpxImagePlugin.py
new file mode 100644
index 0000000000..8555a6b75a
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/FpxImagePlugin.py
@@ -0,0 +1,249 @@
+#
+# THIS IS WORK IN PROGRESS
+#
+# The Python Imaging Library.
+# $Id$
+#
+# FlashPix support for PIL
+#
+# History:
+# 97-01-25 fl Created (reads uncompressed RGB images only)
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import print_function
+
+import olefile
+
+from . import Image, ImageFile
+from ._binary import i8, i32le as i32
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+# we map from colour field tuples to (mode, rawmode) descriptors
+MODES = {
+ # opacity
+ (0x00007FFE): ("A", "L"),
+ # monochrome
+ (0x00010000,): ("L", "L"),
+ (0x00018000, 0x00017FFE): ("RGBA", "LA"),
+ # photo YCC
+ (0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"),
+ (0x00028000, 0x00028001, 0x00028002, 0x00027FFE): ("RGBA", "YCCA;P"),
+ # standard RGB (NIFRGB)
+ (0x00030000, 0x00030001, 0x00030002): ("RGB", "RGB"),
+ (0x00038000, 0x00038001, 0x00038002, 0x00037FFE): ("RGBA", "RGBA"),
+}
+
+
+#
+# --------------------------------------------------------------------
+
+
+def _accept(prefix):
+ return prefix[:8] == olefile.MAGIC
+
+
+##
+# Image plugin for the FlashPix images.
+
+
+class FpxImageFile(ImageFile.ImageFile):
+
+ format = "FPX"
+ format_description = "FlashPix"
+
+ def _open(self):
+ #
+ # read the OLE directory and see if this is a likely
+ # to be a FlashPix file
+
+ try:
+ self.ole = olefile.OleFileIO(self.fp)
+ except IOError:
+ raise SyntaxError("not an FPX file; invalid OLE file")
+
+ if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
+ raise SyntaxError("not an FPX file; bad root CLSID")
+
+ self._open_index(1)
+
+ def _open_index(self, index=1):
+ #
+ # get the Image Contents Property Set
+
+ prop = self.ole.getproperties(
+ ["Data Object Store %06d" % index, "\005Image Contents"]
+ )
+
+ # size (highest resolution)
+
+ self._size = prop[0x1000002], prop[0x1000003]
+
+ size = max(self.size)
+ i = 1
+ while size > 64:
+ size = size / 2
+ i += 1
+ self.maxid = i - 1
+
+ # mode. instead of using a single field for this, flashpix
+ # requires you to specify the mode for each channel in each
+ # resolution subimage, and leaves it to the decoder to make
+ # sure that they all match. for now, we'll cheat and assume
+ # that this is always the case.
+
+ id = self.maxid << 16
+
+ s = prop[0x2000002 | id]
+
+ colors = []
+ bands = i32(s, 4)
+ if bands > 4:
+ raise IOError("Invalid number of bands")
+ for i in range(bands):
+ # note: for now, we ignore the "uncalibrated" flag
+ colors.append(i32(s, 8 + i * 4) & 0x7FFFFFFF)
+
+ self.mode, self.rawmode = MODES[tuple(colors)]
+
+ # load JPEG tables, if any
+ self.jpeg = {}
+ for i in range(256):
+ id = 0x3000001 | (i << 16)
+ if id in prop:
+ self.jpeg[i] = prop[id]
+
+ self._open_subimage(1, self.maxid)
+
+ def _open_subimage(self, index=1, subimage=0):
+ #
+ # setup tile descriptors for a given subimage
+
+ stream = [
+ "Data Object Store %06d" % index,
+ "Resolution %04d" % subimage,
+ "Subimage 0000 Header",
+ ]
+
+ fp = self.ole.openstream(stream)
+
+ # skip prefix
+ fp.read(28)
+
+ # header stream
+ s = fp.read(36)
+
+ size = i32(s, 4), i32(s, 8)
+ # tilecount = i32(s, 12)
+ tilesize = i32(s, 16), i32(s, 20)
+ # channels = i32(s, 24)
+ offset = i32(s, 28)
+ length = i32(s, 32)
+
+ if size != self.size:
+ raise IOError("subimage mismatch")
+
+ # get tile descriptors
+ fp.seek(28 + offset)
+ s = fp.read(i32(s, 12) * length)
+
+ x = y = 0
+ xsize, ysize = size
+ xtile, ytile = tilesize
+ self.tile = []
+
+ for i in range(0, len(s), length):
+
+ compression = i32(s, i + 8)
+
+ if compression == 0:
+ self.tile.append(
+ (
+ "raw",
+ (x, y, x + xtile, y + ytile),
+ i32(s, i) + 28,
+ (self.rawmode),
+ )
+ )
+
+ elif compression == 1:
+
+ # FIXME: the fill decoder is not implemented
+ self.tile.append(
+ (
+ "fill",
+ (x, y, x + xtile, y + ytile),
+ i32(s, i) + 28,
+ (self.rawmode, s[12:16]),
+ )
+ )
+
+ elif compression == 2:
+
+ internal_color_conversion = i8(s[14])
+ jpeg_tables = i8(s[15])
+ rawmode = self.rawmode
+
+ if internal_color_conversion:
+ # The image is stored as usual (usually YCbCr).
+ if rawmode == "RGBA":
+ # For "RGBA", data is stored as YCbCrA based on
+ # negative RGB. The following trick works around
+ # this problem :
+ jpegmode, rawmode = "YCbCrK", "CMYK"
+ else:
+ jpegmode = None # let the decoder decide
+
+ else:
+ # The image is stored as defined by rawmode
+ jpegmode = rawmode
+
+ self.tile.append(
+ (
+ "jpeg",
+ (x, y, x + xtile, y + ytile),
+ i32(s, i) + 28,
+ (rawmode, jpegmode),
+ )
+ )
+
+ # FIXME: jpeg tables are tile dependent; the prefix
+ # data must be placed in the tile descriptor itself!
+
+ if jpeg_tables:
+ self.tile_prefix = self.jpeg[jpeg_tables]
+
+ else:
+ raise IOError("unknown/invalid compression")
+
+ x = x + xtile
+ if x >= xsize:
+ x, y = 0, y + ytile
+ if y >= ysize:
+ break # isn't really required
+
+ self.stream = stream
+ self.fp = None
+
+ def load(self):
+
+ if not self.fp:
+ self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"])
+
+ return ImageFile.ImageFile.load(self)
+
+
+#
+# --------------------------------------------------------------------
+
+
+Image.register_open(FpxImageFile.format, FpxImageFile, _accept)
+
+Image.register_extension(FpxImageFile.format, ".fpx")
diff --git a/contrib/python/Pillow/py2/PIL/FtexImagePlugin.py b/contrib/python/Pillow/py2/PIL/FtexImagePlugin.py
new file mode 100644
index 0000000000..096ccacac6
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/FtexImagePlugin.py
@@ -0,0 +1,106 @@
+"""
+A Pillow loader for .ftc and .ftu files (FTEX)
+Jerome Leclanche <jerome@leclan.ch>
+
+The contents of this file are hereby released in the public domain (CC0)
+Full text of the CC0 license:
+ https://creativecommons.org/publicdomain/zero/1.0/
+
+Independence War 2: Edge Of Chaos - Texture File Format - 16 October 2001
+
+The textures used for 3D objects in Independence War 2: Edge Of Chaos are in a
+packed custom format called FTEX. This file format uses file extensions FTC
+and FTU.
+* FTC files are compressed textures (using standard texture compression).
+* FTU files are not compressed.
+Texture File Format
+The FTC and FTU texture files both use the same format. This
+has the following structure:
+{header}
+{format_directory}
+{data}
+Where:
+{header} = {
+ u32:magic,
+ u32:version,
+ u32:width,
+ u32:height,
+ u32:mipmap_count,
+ u32:format_count
+}
+
+* The "magic" number is "FTEX".
+* "width" and "height" are the dimensions of the texture.
+* "mipmap_count" is the number of mipmaps in the texture.
+* "format_count" is the number of texture formats (different versions of the
+same texture) in this file.
+
+{format_directory} = format_count * { u32:format, u32:where }
+
+The format value is 0 for DXT1 compressed textures and 1 for 24-bit RGB
+uncompressed textures.
+The texture data for a format starts at the position "where" in the file.
+
+Each set of texture data in the file has the following structure:
+{data} = format_count * { u32:mipmap_size, mipmap_size * { u8 } }
+* "mipmap_size" is the number of bytes in that mip level. For compressed
+textures this is the size of the texture data compressed with DXT1. For 24 bit
+uncompressed textures, this is 3 * width * height. Following this are the image
+bytes for that mipmap level.
+
+Note: All data is stored in little-Endian (Intel) byte order.
+"""
+
+import struct
+from io import BytesIO
+
+from . import Image, ImageFile
+
+MAGIC = b"FTEX"
+FORMAT_DXT1 = 0
+FORMAT_UNCOMPRESSED = 1
+
+
+class FtexImageFile(ImageFile.ImageFile):
+ format = "FTEX"
+ format_description = "Texture File Format (IW2:EOC)"
+
+ def _open(self):
+ struct.unpack("<I", self.fp.read(4)) # magic
+ struct.unpack("<i", self.fp.read(4)) # version
+ self._size = struct.unpack("<2i", self.fp.read(8))
+ mipmap_count, format_count = struct.unpack("<2i", self.fp.read(8))
+
+ self.mode = "RGB"
+
+ # Only support single-format files.
+ # I don't know of any multi-format file.
+ assert format_count == 1
+
+ format, where = struct.unpack("<2i", self.fp.read(8))
+ self.fp.seek(where)
+ (mipmap_size,) = struct.unpack("<i", self.fp.read(4))
+
+ data = self.fp.read(mipmap_size)
+
+ if format == FORMAT_DXT1:
+ self.mode = "RGBA"
+ self.tile = [("bcn", (0, 0) + self.size, 0, (1))]
+ elif format == FORMAT_UNCOMPRESSED:
+ self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))]
+ else:
+ raise ValueError("Invalid texture compression format: %r" % (format))
+
+ self.fp.close()
+ self.fp = BytesIO(data)
+
+ def load_seek(self, pos):
+ pass
+
+
+def _validate(prefix):
+ return prefix[:4] == MAGIC
+
+
+Image.register_open(FtexImageFile.format, FtexImageFile, _validate)
+Image.register_extensions(FtexImageFile.format, [".ftc", ".ftu"])
diff --git a/contrib/python/Pillow/py2/PIL/GbrImagePlugin.py b/contrib/python/Pillow/py2/PIL/GbrImagePlugin.py
new file mode 100644
index 0000000000..2de56aadf0
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/GbrImagePlugin.py
@@ -0,0 +1,96 @@
+#
+# The Python Imaging Library
+#
+# load a GIMP brush file
+#
+# History:
+# 96-03-14 fl Created
+# 16-01-08 es Version 2
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+# Copyright (c) Eric Soroos 2016.
+#
+# See the README file for information on usage and redistribution.
+#
+#
+# See https://github.com/GNOME/gimp/blob/master/devel-docs/gbr.txt for
+# format documentation.
+#
+# This code Interprets version 1 and 2 .gbr files.
+# Version 1 files are obsolete, and should not be used for new
+# brushes.
+# Version 2 files are saved by GIMP v2.8 (at least)
+# Version 3 files have a format specifier of 18 for 16bit floats in
+# the color depth field. This is currently unsupported by Pillow.
+
+from . import Image, ImageFile
+from ._binary import i32be as i32
+
+
+def _accept(prefix):
+ return len(prefix) >= 8 and i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1, 2)
+
+
+##
+# Image plugin for the GIMP brush format.
+
+
+class GbrImageFile(ImageFile.ImageFile):
+
+ format = "GBR"
+ format_description = "GIMP brush file"
+
+ def _open(self):
+ header_size = i32(self.fp.read(4))
+ version = i32(self.fp.read(4))
+ if header_size < 20:
+ raise SyntaxError("not a GIMP brush")
+ if version not in (1, 2):
+ raise SyntaxError("Unsupported GIMP brush version: %s" % version)
+
+ width = i32(self.fp.read(4))
+ height = i32(self.fp.read(4))
+ color_depth = i32(self.fp.read(4))
+ 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)
+
+ if version == 1:
+ comment_length = header_size - 20
+ else:
+ comment_length = header_size - 28
+ magic_number = self.fp.read(4)
+ if magic_number != b"GIMP":
+ raise SyntaxError("not a GIMP brush, bad magic number")
+ self.info["spacing"] = i32(self.fp.read(4))
+
+ comment = self.fp.read(comment_length)[:-1]
+
+ if color_depth == 1:
+ self.mode = "L"
+ else:
+ self.mode = "RGBA"
+
+ self._size = width, height
+
+ self.info["comment"] = comment
+
+ # Image might not be small
+ Image._decompression_bomb_check(self.size)
+
+ # Data is an uncompressed block of w * h * bytes/pixel
+ self._data_size = width * height * color_depth
+
+ def load(self):
+ self.im = Image.core.new(self.mode, self.size)
+ self.frombytes(self.fp.read(self._data_size))
+
+
+#
+# registry
+
+
+Image.register_open(GbrImageFile.format, GbrImageFile, _accept)
+Image.register_extension(GbrImageFile.format, ".gbr")
diff --git a/contrib/python/Pillow/py2/PIL/GdImageFile.py b/contrib/python/Pillow/py2/PIL/GdImageFile.py
new file mode 100644
index 0000000000..2d492358c1
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/GdImageFile.py
@@ -0,0 +1,90 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# GD file handling
+#
+# History:
+# 1996-04-12 fl Created
+#
+# Copyright (c) 1997 by Secret Labs AB.
+# Copyright (c) 1996 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+# NOTE: This format cannot be automatically recognized, so the
+# class is not registered for use with Image.open(). To open a
+# gd file, use the GdImageFile.open() function instead.
+
+# THE GD FORMAT IS NOT DESIGNED FOR DATA INTERCHANGE. This
+# implementation is provided for convenience and demonstrational
+# purposes only.
+
+
+from . import ImageFile, ImagePalette
+from ._binary import i8, i16be as i16, i32be as i32
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+
+##
+# Image plugin for the GD uncompressed format. Note that this format
+# is not supported by the standard <b>Image.open</b> function. To use
+# this plugin, you have to import the <b>GdImageFile</b> module and
+# use the <b>GdImageFile.open</b> function.
+
+
+class GdImageFile(ImageFile.ImageFile):
+
+ format = "GD"
+ format_description = "GD uncompressed images"
+
+ def _open(self):
+
+ # Header
+ s = self.fp.read(1037)
+
+ if not i16(s[:2]) in [65534, 65535]:
+ raise SyntaxError("Not a valid GD 2.x .gd file")
+
+ self.mode = "L" # FIXME: "P"
+ self._size = i16(s[2:4]), i16(s[4:6])
+
+ trueColor = i8(s[6])
+ trueColorOffset = 2 if trueColor else 0
+
+ # transparency index
+ tindex = i32(s[7 + trueColorOffset : 7 + trueColorOffset + 4])
+ if tindex < 256:
+ self.info["transparency"] = tindex
+
+ self.palette = ImagePalette.raw(
+ "XBGR", s[7 + trueColorOffset + 4 : 7 + trueColorOffset + 4 + 256 * 4]
+ )
+
+ self.tile = [
+ ("raw", (0, 0) + self.size, 7 + trueColorOffset + 4 + 256 * 4, ("L", 0, 1))
+ ]
+
+
+def open(fp, mode="r"):
+ """
+ Load texture from a GD image file.
+
+ :param filename: GD file name, or an opened file handle.
+ :param mode: Optional mode. In this version, if the mode argument
+ is given, it must be "r".
+ :returns: An image instance.
+ :raises IOError: If the image could not be read.
+ """
+ if mode != "r":
+ raise ValueError("bad mode")
+
+ try:
+ return GdImageFile(fp)
+ except SyntaxError:
+ raise IOError("cannot identify this image file")
diff --git a/contrib/python/Pillow/py2/PIL/GifImagePlugin.py b/contrib/python/Pillow/py2/PIL/GifImagePlugin.py
new file mode 100644
index 0000000000..9d8e96feee
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/GifImagePlugin.py
@@ -0,0 +1,884 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# GIF file handling
+#
+# History:
+# 1995-09-01 fl Created
+# 1996-12-14 fl Added interlace support
+# 1996-12-30 fl Added animation support
+# 1997-01-05 fl Added write support, fixed local colour map bug
+# 1997-02-23 fl Make sure to load raster data in getdata()
+# 1997-07-05 fl Support external decoder (0.4)
+# 1998-07-09 fl Handle all modes when saving (0.5)
+# 1998-07-15 fl Renamed offset attribute to avoid name clash
+# 2001-04-16 fl Added rewind support (seek to frame 0) (0.6)
+# 2001-04-17 fl Added palette optimization (0.7)
+# 2002-06-06 fl Added transparency support for save (0.8)
+# 2004-02-24 fl Disable interlacing for small images
+#
+# Copyright (c) 1997-2004 by Secret Labs AB
+# Copyright (c) 1995-2004 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import itertools
+
+from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence
+from ._binary import i8, i16le as i16, o8, o16le as o16
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.9"
+
+
+# --------------------------------------------------------------------
+# Identify/read GIF files
+
+
+def _accept(prefix):
+ return prefix[:6] in [b"GIF87a", b"GIF89a"]
+
+
+##
+# Image plugin for GIF images. This plugin supports both GIF87 and
+# GIF89 images.
+
+
+class GifImageFile(ImageFile.ImageFile):
+
+ format = "GIF"
+ format_description = "Compuserve GIF"
+ _close_exclusive_fp_after_loading = False
+
+ global_palette = None
+
+ def data(self):
+ s = self.fp.read(1)
+ if s and i8(s):
+ return self.fp.read(i8(s))
+ return None
+
+ def _open(self):
+
+ # Screen
+ s = self.fp.read(13)
+ if s[:6] not in [b"GIF87a", b"GIF89a"]:
+ raise SyntaxError("not a GIF file")
+
+ self.info["version"] = s[:6]
+ self._size = i16(s[6:]), i16(s[8:])
+ self.tile = []
+ flags = i8(s[10])
+ bits = (flags & 7) + 1
+
+ if flags & 128:
+ # get global palette
+ self.info["background"] = i8(s[11])
+ # check if palette contains colour indices
+ p = self.fp.read(3 << bits)
+ for i in range(0, len(p), 3):
+ if not (i // 3 == i8(p[i]) == i8(p[i + 1]) == i8(p[i + 2])):
+ p = ImagePalette.raw("RGB", p)
+ self.global_palette = self.palette = p
+ break
+
+ self.__fp = self.fp # FIXME: hack
+ self.__rewind = self.fp.tell()
+ self._n_frames = None
+ self._is_animated = None
+ self._seek(0) # get ready to read first frame
+
+ @property
+ def n_frames(self):
+ if self._n_frames is None:
+ current = self.tell()
+ try:
+ while True:
+ self.seek(self.tell() + 1)
+ except EOFError:
+ self._n_frames = self.tell() + 1
+ self.seek(current)
+ return self._n_frames
+
+ @property
+ def is_animated(self):
+ if self._is_animated is None:
+ if self._n_frames is not None:
+ self._is_animated = self._n_frames != 1
+ else:
+ current = self.tell()
+
+ try:
+ self.seek(1)
+ self._is_animated = True
+ except EOFError:
+ self._is_animated = False
+
+ self.seek(current)
+ return self._is_animated
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+ if frame < self.__frame:
+ if frame != 0:
+ self.im = None
+ self._seek(0)
+
+ last_frame = self.__frame
+ for f in range(self.__frame + 1, frame + 1):
+ try:
+ self._seek(f)
+ except EOFError:
+ self.seek(last_frame)
+ raise EOFError("no more images in GIF file")
+
+ def _seek(self, frame):
+
+ if frame == 0:
+ # rewind
+ self.__offset = 0
+ self.dispose = None
+ self.dispose_extent = [0, 0, 0, 0] # x0, y0, x1, y1
+ self.__frame = -1
+ self.__fp.seek(self.__rewind)
+ self._prev_im = None
+ self.disposal_method = 0
+ else:
+ # ensure that the previous frame was loaded
+ if not self.im:
+ self.load()
+
+ if frame != self.__frame + 1:
+ raise ValueError("cannot seek to frame %d" % frame)
+ self.__frame = frame
+
+ self.tile = []
+
+ self.fp = self.__fp
+ if self.__offset:
+ # backup to last frame
+ self.fp.seek(self.__offset)
+ while self.data():
+ pass
+ self.__offset = 0
+
+ if self.dispose:
+ self.im.paste(self.dispose, self.dispose_extent)
+
+ from copy import copy
+
+ self.palette = copy(self.global_palette)
+
+ info = {}
+ while True:
+
+ s = self.fp.read(1)
+ if not s or s == b";":
+ break
+
+ elif s == b"!":
+ #
+ # extensions
+ #
+ s = self.fp.read(1)
+ block = self.data()
+ if i8(s) == 249:
+ #
+ # graphic control extension
+ #
+ flags = i8(block[0])
+ if flags & 1:
+ info["transparency"] = i8(block[3])
+ info["duration"] = i16(block[1:3]) * 10
+
+ # disposal method - find the value of bits 4 - 6
+ dispose_bits = 0b00011100 & flags
+ dispose_bits = dispose_bits >> 2
+ if dispose_bits:
+ # only set the dispose if it is not
+ # unspecified. I'm not sure if this is
+ # correct, but it seems to prevent the last
+ # frame from looking odd for some animations
+ self.disposal_method = dispose_bits
+ elif i8(s) == 254:
+ #
+ # comment extension
+ #
+ while block:
+ if "comment" in info:
+ info["comment"] += block
+ else:
+ info["comment"] = block
+ block = self.data()
+ continue
+ elif i8(s) == 255:
+ #
+ # application extension
+ #
+ info["extension"] = block, self.fp.tell()
+ if block[:11] == b"NETSCAPE2.0":
+ block = self.data()
+ if len(block) >= 3 and i8(block[0]) == 1:
+ info["loop"] = i16(block[1:3])
+ while self.data():
+ pass
+
+ elif s == b",":
+ #
+ # local image
+ #
+ s = self.fp.read(9)
+
+ # extent
+ x0, y0 = i16(s[0:]), i16(s[2:])
+ x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:])
+ if x1 > self.size[0] or y1 > self.size[1]:
+ self._size = max(x1, self.size[0]), max(y1, self.size[1])
+ self.dispose_extent = x0, y0, x1, y1
+ flags = i8(s[8])
+
+ interlace = (flags & 64) != 0
+
+ if flags & 128:
+ bits = (flags & 7) + 1
+ self.palette = ImagePalette.raw("RGB", self.fp.read(3 << bits))
+
+ # image data
+ bits = i8(self.fp.read(1))
+ self.__offset = self.fp.tell()
+ self.tile = [
+ ("gif", (x0, y0, x1, y1), self.__offset, (bits, interlace))
+ ]
+ break
+
+ else:
+ pass
+ # raise IOError, "illegal GIF tag `%x`" % i8(s)
+
+ try:
+ if self.disposal_method < 2:
+ # do not dispose or none specified
+ self.dispose = None
+ elif self.disposal_method == 2:
+ # replace with background colour
+ Image._decompression_bomb_check(self.size)
+ self.dispose = Image.core.fill("P", self.size, self.info["background"])
+ else:
+ # replace with previous contents
+ if self.im:
+ self.dispose = self.im.copy()
+
+ # only dispose the extent in this frame
+ if self.dispose:
+ self.dispose = self._crop(self.dispose, self.dispose_extent)
+ except (AttributeError, KeyError):
+ pass
+
+ if not self.tile:
+ # self.__fp = None
+ raise EOFError
+
+ for k in ["transparency", "duration", "comment", "extension", "loop"]:
+ if k in info:
+ self.info[k] = info[k]
+ elif k in self.info:
+ del self.info[k]
+
+ self.mode = "L"
+ if self.palette:
+ self.mode = "P"
+
+ def tell(self):
+ return self.__frame
+
+ def load_end(self):
+ ImageFile.ImageFile.load_end(self)
+
+ # if the disposal method is 'do not dispose', transparent
+ # pixels should show the content of the previous frame
+ if self._prev_im and self.disposal_method == 1:
+ # we do this by pasting the updated area onto the previous
+ # frame which we then use as the current image content
+ updated = self._crop(self.im, self.dispose_extent)
+ self._prev_im.paste(updated, self.dispose_extent, updated.convert("RGBA"))
+ self.im = self._prev_im
+ self._prev_im = self.im.copy()
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+# --------------------------------------------------------------------
+# Write GIF files
+
+
+RAWMODE = {"1": "L", "L": "L", "P": "P"}
+
+
+def _normalize_mode(im, initial_call=False):
+ """
+ Takes an image (or frame), returns an image in a mode that is appropriate
+ for saving in a Gif.
+
+ It may return the original image, or it may return an image converted to
+ palette or 'L' mode.
+
+ UNDONE: What is the point of mucking with the initial call palette, for
+ an image that shouldn't have a palette, or it would be a mode 'P' and
+ get returned in the RAWMODE clause.
+
+ :param im: Image object
+ :param initial_call: Default false, set to true for a single frame.
+ :returns: Image object
+ """
+ if im.mode in RAWMODE:
+ im.load()
+ return im
+ if Image.getmodebase(im.mode) == "RGB":
+ if initial_call:
+ palette_size = 256
+ if im.palette:
+ palette_size = len(im.palette.getdata()[1]) // 3
+ return im.convert("P", palette=Image.ADAPTIVE, colors=palette_size)
+ else:
+ return im.convert("P")
+ return im.convert("L")
+
+
+def _normalize_palette(im, palette, info):
+ """
+ Normalizes the palette for image.
+ - Sets the palette to the incoming palette, if provided.
+ - Ensures that there's a palette for L mode images
+ - Optimizes the palette if necessary/desired.
+
+ :param im: Image object
+ :param palette: bytes object containing the source palette, or ....
+ :param info: encoderinfo
+ :returns: Image object
+ """
+ source_palette = None
+ if palette:
+ # a bytes palette
+ if isinstance(palette, (bytes, bytearray, list)):
+ source_palette = bytearray(palette[:768])
+ if isinstance(palette, ImagePalette.ImagePalette):
+ source_palette = bytearray(
+ itertools.chain.from_iterable(
+ zip(
+ palette.palette[:256],
+ palette.palette[256:512],
+ palette.palette[512:768],
+ )
+ )
+ )
+
+ if im.mode == "P":
+ if not source_palette:
+ source_palette = im.im.getpalette("RGB")[:768]
+ else: # L-mode
+ if not source_palette:
+ source_palette = bytearray(i // 3 for i in range(768))
+ im.palette = ImagePalette.ImagePalette("RGB", palette=source_palette)
+
+ used_palette_colors = _get_optimize(im, info)
+ if used_palette_colors is not None:
+ return im.remap_palette(used_palette_colors, source_palette)
+
+ im.palette.palette = source_palette
+ return im
+
+
+def _write_single_frame(im, fp, palette):
+ im_out = _normalize_mode(im, True)
+ for k, v in im_out.info.items():
+ im.encoderinfo.setdefault(k, v)
+ im_out = _normalize_palette(im_out, palette, im.encoderinfo)
+
+ for s in _get_global_header(im_out, im.encoderinfo):
+ fp.write(s)
+
+ # local image header
+ flags = 0
+ if get_interlace(im):
+ flags = flags | 64
+ _write_local_header(fp, im, (0, 0), flags)
+
+ im_out.encoderconfig = (8, get_interlace(im))
+ ImageFile._save(im_out, fp, [("gif", (0, 0) + im.size, 0, RAWMODE[im_out.mode])])
+
+ fp.write(b"\0") # end of image data
+
+
+def _write_multiple_frames(im, fp, palette):
+
+ duration = im.encoderinfo.get("duration", im.info.get("duration"))
+ disposal = im.encoderinfo.get("disposal", im.info.get("disposal"))
+
+ im_frames = []
+ frame_count = 0
+ background_im = None
+ for imSequence in itertools.chain([im], im.encoderinfo.get("append_images", [])):
+ for im_frame in ImageSequence.Iterator(imSequence):
+ # a copy is required here since seek can still mutate the image
+ im_frame = _normalize_mode(im_frame.copy())
+ if frame_count == 0:
+ for k, v in im_frame.info.items():
+ im.encoderinfo.setdefault(k, v)
+ im_frame = _normalize_palette(im_frame, palette, im.encoderinfo)
+
+ encoderinfo = im.encoderinfo.copy()
+ if isinstance(duration, (list, tuple)):
+ encoderinfo["duration"] = duration[frame_count]
+ if isinstance(disposal, (list, tuple)):
+ encoderinfo["disposal"] = disposal[frame_count]
+ frame_count += 1
+
+ if im_frames:
+ # delta frame
+ previous = im_frames[-1]
+ if encoderinfo.get("disposal") == 2:
+ if background_im is None:
+ background = _get_background(
+ im,
+ im.encoderinfo.get("background", im.info.get("background")),
+ )
+ background_im = Image.new("P", im_frame.size, background)
+ background_im.putpalette(im_frames[0]["im"].palette)
+ base_im = background_im
+ else:
+ base_im = previous["im"]
+ if _get_palette_bytes(im_frame) == _get_palette_bytes(base_im):
+ delta = ImageChops.subtract_modulo(im_frame, base_im)
+ else:
+ delta = ImageChops.subtract_modulo(
+ im_frame.convert("RGB"), base_im.convert("RGB")
+ )
+ bbox = delta.getbbox()
+ if not bbox:
+ # This frame is identical to the previous frame
+ if duration:
+ previous["encoderinfo"]["duration"] += encoderinfo["duration"]
+ continue
+ else:
+ bbox = None
+ im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo})
+
+ if len(im_frames) > 1:
+ for frame_data in im_frames:
+ im_frame = frame_data["im"]
+ if not frame_data["bbox"]:
+ # global header
+ for s in _get_global_header(im_frame, frame_data["encoderinfo"]):
+ fp.write(s)
+ offset = (0, 0)
+ else:
+ # compress difference
+ frame_data["encoderinfo"]["include_color_table"] = True
+
+ im_frame = im_frame.crop(frame_data["bbox"])
+ offset = frame_data["bbox"][:2]
+ _write_frame_data(fp, im_frame, offset, frame_data["encoderinfo"])
+ return True
+ elif "duration" in im.encoderinfo and isinstance(
+ im.encoderinfo["duration"], (list, tuple)
+ ):
+ # Since multiple frames will not be written, add together the frame durations
+ im.encoderinfo["duration"] = sum(im.encoderinfo["duration"])
+
+
+def _save_all(im, fp, filename):
+ _save(im, fp, filename, save_all=True)
+
+
+def _save(im, fp, filename, save_all=False):
+ # header
+ if "palette" in im.encoderinfo or "palette" in im.info:
+ palette = im.encoderinfo.get("palette", im.info.get("palette"))
+ else:
+ palette = None
+ im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
+
+ if not save_all or not _write_multiple_frames(im, fp, palette):
+ _write_single_frame(im, fp, palette)
+
+ fp.write(b";") # end of file
+
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+
+def get_interlace(im):
+ interlace = im.encoderinfo.get("interlace", 1)
+
+ # workaround for @PIL153
+ if min(im.size) < 16:
+ interlace = 0
+
+ return interlace
+
+
+def _write_local_header(fp, im, offset, flags):
+ transparent_color_exists = False
+ try:
+ transparency = im.encoderinfo["transparency"]
+ except KeyError:
+ pass
+ else:
+ transparency = int(transparency)
+ # optimize the block away if transparent color is not used
+ transparent_color_exists = True
+
+ used_palette_colors = _get_optimize(im, im.encoderinfo)
+ if used_palette_colors is not None:
+ # adjust the transparency index after optimize
+ try:
+ transparency = used_palette_colors.index(transparency)
+ except ValueError:
+ transparent_color_exists = False
+
+ if "duration" in im.encoderinfo:
+ duration = int(im.encoderinfo["duration"] / 10)
+ else:
+ duration = 0
+
+ disposal = int(im.encoderinfo.get("disposal", 0))
+
+ if transparent_color_exists or duration != 0 or disposal:
+ packed_flag = 1 if transparent_color_exists else 0
+ packed_flag |= disposal << 2
+ if not transparent_color_exists:
+ transparency = 0
+
+ fp.write(
+ b"!"
+ + o8(249) # extension intro
+ + o8(4) # length
+ + o8(packed_flag) # packed fields
+ + o16(duration) # duration
+ + o8(transparency) # transparency index
+ + o8(0)
+ )
+
+ if "comment" in im.encoderinfo and 1 <= len(im.encoderinfo["comment"]):
+ fp.write(b"!" + o8(254)) # extension intro
+ for i in range(0, len(im.encoderinfo["comment"]), 255):
+ subblock = im.encoderinfo["comment"][i : i + 255]
+ fp.write(o8(len(subblock)) + subblock)
+ fp.write(o8(0))
+ if "loop" in im.encoderinfo:
+ number_of_loops = im.encoderinfo["loop"]
+ fp.write(
+ b"!"
+ + o8(255) # extension intro
+ + o8(11)
+ + b"NETSCAPE2.0"
+ + o8(3)
+ + o8(1)
+ + o16(number_of_loops) # number of loops
+ + o8(0)
+ )
+ include_color_table = im.encoderinfo.get("include_color_table")
+ if include_color_table:
+ palette_bytes = _get_palette_bytes(im)
+ color_table_size = _get_color_table_size(palette_bytes)
+ if color_table_size:
+ flags = flags | 128 # local color table flag
+ flags = flags | color_table_size
+
+ fp.write(
+ b","
+ + o16(offset[0]) # offset
+ + o16(offset[1])
+ + o16(im.size[0]) # size
+ + o16(im.size[1])
+ + o8(flags) # flags
+ )
+ if include_color_table and color_table_size:
+ fp.write(_get_header_palette(palette_bytes))
+ fp.write(o8(8)) # bits
+
+
+def _save_netpbm(im, fp, filename):
+
+ # Unused by default.
+ # To use, uncomment the register_save call at the end of the file.
+ #
+ # If you need real GIF compression and/or RGB quantization, you
+ # can use the external NETPBM/PBMPLUS utilities. See comments
+ # below for information on how to enable this.
+
+ import os
+ from subprocess import Popen, check_call, PIPE, CalledProcessError
+
+ tempfile = im._dump()
+
+ with open(filename, "wb") as f:
+ if im.mode != "RGB":
+ with open(os.devnull, "wb") as devnull:
+ check_call(["ppmtogif", tempfile], stdout=f, stderr=devnull)
+ else:
+ # Pipe ppmquant output into ppmtogif
+ # "ppmquant 256 %s | ppmtogif > %s" % (tempfile, filename)
+ quant_cmd = ["ppmquant", "256", tempfile]
+ togif_cmd = ["ppmtogif"]
+ with open(os.devnull, "wb") as devnull:
+ quant_proc = Popen(quant_cmd, stdout=PIPE, stderr=devnull)
+ togif_proc = Popen(
+ togif_cmd, stdin=quant_proc.stdout, stdout=f, stderr=devnull
+ )
+
+ # Allow ppmquant to receive SIGPIPE if ppmtogif exits
+ quant_proc.stdout.close()
+
+ retcode = quant_proc.wait()
+ if retcode:
+ raise CalledProcessError(retcode, quant_cmd)
+
+ retcode = togif_proc.wait()
+ if retcode:
+ raise CalledProcessError(retcode, togif_cmd)
+
+ try:
+ os.unlink(tempfile)
+ except OSError:
+ pass
+
+
+# Force optimization so that we can test performance against
+# cases where it took lots of memory and time previously.
+_FORCE_OPTIMIZE = False
+
+
+def _get_optimize(im, info):
+ """
+ Palette optimization is a potentially expensive operation.
+
+ This function determines if the palette should be optimized using
+ some heuristics, then returns the list of palette entries in use.
+
+ :param im: Image object
+ :param info: encoderinfo
+ :returns: list of indexes of palette entries in use, or None
+ """
+ if im.mode in ("P", "L") and info and info.get("optimize", 0):
+ # Potentially expensive operation.
+
+ # The palette saves 3 bytes per color not used, but palette
+ # lengths are restricted to 3*(2**N) bytes. Max saving would
+ # be 768 -> 6 bytes if we went all the way down to 2 colors.
+ # * If we're over 128 colors, we can't save any space.
+ # * If there aren't any holes, it's not worth collapsing.
+ # * If we have a 'large' image, the palette is in the noise.
+
+ # create the new palette if not every color is used
+ optimise = _FORCE_OPTIMIZE or im.mode == "L"
+ if optimise or im.width * im.height < 512 * 512:
+ # check which colors are used
+ used_palette_colors = []
+ for i, count in enumerate(im.histogram()):
+ if count:
+ used_palette_colors.append(i)
+
+ if optimise or (
+ len(used_palette_colors) <= 128
+ and max(used_palette_colors) > len(used_palette_colors)
+ ):
+ return used_palette_colors
+
+
+def _get_color_table_size(palette_bytes):
+ # calculate the palette size for the header
+ import math
+
+ if not palette_bytes:
+ return 0
+ elif len(palette_bytes) < 9:
+ return 1
+ else:
+ return int(math.ceil(math.log(len(palette_bytes) // 3, 2))) - 1
+
+
+def _get_header_palette(palette_bytes):
+ """
+ Returns the palette, null padded to the next power of 2 (*3) bytes
+ suitable for direct inclusion in the GIF header
+
+ :param palette_bytes: Unpadded palette bytes, in RGBRGB form
+ :returns: Null padded palette
+ """
+ color_table_size = _get_color_table_size(palette_bytes)
+
+ # add the missing amount of bytes
+ # the palette has to be 2<<n in size
+ actual_target_size_diff = (2 << color_table_size) - len(palette_bytes) // 3
+ if actual_target_size_diff > 0:
+ palette_bytes += o8(0) * 3 * actual_target_size_diff
+ return palette_bytes
+
+
+def _get_palette_bytes(im):
+ """
+ Gets the palette for inclusion in the gif header
+
+ :param im: Image object
+ :returns: Bytes, len<=768 suitable for inclusion in gif header
+ """
+ return im.palette.palette
+
+
+def _get_background(im, infoBackground):
+ background = 0
+ if infoBackground:
+ background = infoBackground
+ if isinstance(background, tuple):
+ # WebPImagePlugin stores an RGBA value in info["background"]
+ # So it must be converted to the same format as GifImagePlugin's
+ # info["background"] - a global color table index
+ background = im.palette.getcolor(background)
+ return background
+
+
+def _get_global_header(im, info):
+ """Return a list of strings representing a GIF header"""
+
+ # Header Block
+ # http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
+
+ version = b"87a"
+ 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)
+ ):
+ continue
+ version = b"89a"
+ break
+ else:
+ if im.info.get("version") == b"89a":
+ version = b"89a"
+
+ background = _get_background(im, info.get("background"))
+
+ palette_bytes = _get_palette_bytes(im)
+ color_table_size = _get_color_table_size(palette_bytes)
+
+ return [
+ b"GIF" # signature
+ + version # version
+ + o16(im.size[0]) # canvas width
+ + o16(im.size[1]), # canvas height
+ # Logical Screen Descriptor
+ # size of global color table + global color table flag
+ o8(color_table_size + 128), # packed fields
+ # background + reserved/aspect
+ o8(background) + o8(0),
+ # Global Color Table
+ _get_header_palette(palette_bytes),
+ ]
+
+
+def _write_frame_data(fp, im_frame, offset, params):
+ try:
+ im_frame.encoderinfo = params
+
+ # local image header
+ _write_local_header(fp, im_frame, offset, 0)
+
+ ImageFile._save(
+ im_frame, fp, [("gif", (0, 0) + im_frame.size, 0, RAWMODE[im_frame.mode])]
+ )
+
+ fp.write(b"\0") # end of image data
+ finally:
+ del im_frame.encoderinfo
+
+
+# --------------------------------------------------------------------
+# Legacy GIF utilities
+
+
+def getheader(im, palette=None, info=None):
+ """
+ Legacy Method to get Gif data from image.
+
+ Warning:: May modify image data.
+
+ :param im: Image object
+ :param palette: bytes object containing the source palette, or ....
+ :param info: encoderinfo
+ :returns: tuple of(list of header items, optimized palette)
+
+ """
+ used_palette_colors = _get_optimize(im, info)
+
+ if info is None:
+ info = {}
+
+ if "background" not in info and "background" in im.info:
+ info["background"] = im.info["background"]
+
+ im_mod = _normalize_palette(im, palette, info)
+ im.palette = im_mod.palette
+ im.im = im_mod.im
+ header = _get_global_header(im, info)
+
+ return header, used_palette_colors
+
+
+# To specify duration, add the time in milliseconds to getdata(),
+# e.g. getdata(im_frame, duration=1000)
+def getdata(im, offset=(0, 0), **params):
+ """
+ Legacy Method
+
+ Return a list of strings representing this image.
+ The first string is a local image header, the rest contains
+ encoded image data.
+
+ :param im: Image object
+ :param offset: Tuple of (x, y) pixels. Defaults to (0,0)
+ :param \\**params: E.g. duration or other encoder info parameters
+ :returns: List of Bytes containing gif encoded frame data
+
+ """
+
+ class Collector(object):
+ data = []
+
+ def write(self, data):
+ self.data.append(data)
+
+ im.load() # make sure raster data is available
+
+ fp = Collector()
+
+ _write_frame_data(fp, im, offset, params)
+
+ return fp.data
+
+
+# --------------------------------------------------------------------
+# Registry
+
+Image.register_open(GifImageFile.format, GifImageFile, _accept)
+Image.register_save(GifImageFile.format, _save)
+Image.register_save_all(GifImageFile.format, _save_all)
+Image.register_extension(GifImageFile.format, ".gif")
+Image.register_mime(GifImageFile.format, "image/gif")
+
+#
+# Uncomment the following line if you wish to use NETPBM/PBMPLUS
+# instead of the built-in "uncompressed" GIF encoder
+
+# Image.register_save(GifImageFile.format, _save_netpbm)
diff --git a/contrib/python/Pillow/py2/PIL/GimpGradientFile.py b/contrib/python/Pillow/py2/PIL/GimpGradientFile.py
new file mode 100644
index 0000000000..f48e7f76ef
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/GimpGradientFile.py
@@ -0,0 +1,139 @@
+#
+# Python Imaging Library
+# $Id$
+#
+# stuff to read (and render) GIMP gradient files
+#
+# History:
+# 97-08-23 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from math import log, pi, sin, sqrt
+
+from ._binary import o8
+
+# --------------------------------------------------------------------
+# Stuff to translate curve segments to palette values (derived from
+# the corresponding code in GIMP, written by Federico Mena Quintero.
+# See the GIMP distribution for more information.)
+#
+
+EPSILON = 1e-10
+
+
+def linear(middle, pos):
+ if pos <= middle:
+ if middle < EPSILON:
+ return 0.0
+ else:
+ return 0.5 * pos / middle
+ else:
+ pos = pos - middle
+ middle = 1.0 - middle
+ if middle < EPSILON:
+ return 1.0
+ else:
+ return 0.5 + 0.5 * pos / middle
+
+
+def curved(middle, pos):
+ return pos ** (log(0.5) / log(max(middle, EPSILON)))
+
+
+def sine(middle, pos):
+ return (sin((-pi / 2.0) + pi * linear(middle, pos)) + 1.0) / 2.0
+
+
+def sphere_increasing(middle, pos):
+ return sqrt(1.0 - (linear(middle, pos) - 1.0) ** 2)
+
+
+def sphere_decreasing(middle, pos):
+ return 1.0 - sqrt(1.0 - linear(middle, pos) ** 2)
+
+
+SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing]
+
+
+class GradientFile(object):
+
+ gradient = None
+
+ def getpalette(self, entries=256):
+
+ palette = []
+
+ ix = 0
+ x0, x1, xm, rgb0, rgb1, segment = self.gradient[ix]
+
+ for i in range(entries):
+
+ x = i / float(entries - 1)
+
+ while x1 < x:
+ ix += 1
+ x0, x1, xm, rgb0, rgb1, segment = self.gradient[ix]
+
+ w = x1 - x0
+
+ if w < EPSILON:
+ scale = segment(0.5, 0.5)
+ else:
+ scale = segment((xm - x0) / w, (x - x0) / w)
+
+ # expand to RGBA
+ r = o8(int(255 * ((rgb1[0] - rgb0[0]) * scale + rgb0[0]) + 0.5))
+ g = o8(int(255 * ((rgb1[1] - rgb0[1]) * scale + rgb0[1]) + 0.5))
+ b = o8(int(255 * ((rgb1[2] - rgb0[2]) * scale + rgb0[2]) + 0.5))
+ a = o8(int(255 * ((rgb1[3] - rgb0[3]) * scale + rgb0[3]) + 0.5))
+
+ # add to palette
+ palette.append(r + g + b + a)
+
+ return b"".join(palette), "RGBA"
+
+
+##
+# File handler for GIMP's gradient format.
+
+
+class GimpGradientFile(GradientFile):
+ def __init__(self, fp):
+
+ if fp.readline()[:13] != b"GIMP Gradient":
+ raise SyntaxError("not a GIMP gradient file")
+
+ line = fp.readline()
+
+ # GIMP 1.2 gradient files don't contain a name, but GIMP 1.3 files do
+ if line.startswith(b"Name: "):
+ line = fp.readline().strip()
+
+ count = int(line)
+
+ gradient = []
+
+ for i in range(count):
+
+ s = fp.readline().split()
+ w = [float(x) for x in s[:11]]
+
+ x0, x1 = w[0], w[2]
+ xm = w[1]
+ rgb0 = w[3:7]
+ rgb1 = w[7:11]
+
+ segment = SEGMENTS[int(s[11])]
+ cspace = int(s[12])
+
+ if cspace != 0:
+ raise IOError("cannot handle HSV colour space")
+
+ gradient.append((x0, x1, xm, rgb0, rgb1, segment))
+
+ self.gradient = gradient
diff --git a/contrib/python/Pillow/py2/PIL/GimpPaletteFile.py b/contrib/python/Pillow/py2/PIL/GimpPaletteFile.py
new file mode 100644
index 0000000000..2994bbeab8
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/GimpPaletteFile.py
@@ -0,0 +1,58 @@
+#
+# Python Imaging Library
+# $Id$
+#
+# stuff to read GIMP palette files
+#
+# History:
+# 1997-08-23 fl Created
+# 2004-09-07 fl Support GIMP 2.0 palette files.
+#
+# Copyright (c) Secret Labs AB 1997-2004. All rights reserved.
+# Copyright (c) Fredrik Lundh 1997-2004.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import re
+
+from ._binary import o8
+
+##
+# File handler for GIMP's palette format.
+
+
+class GimpPaletteFile(object):
+
+ rawmode = "RGB"
+
+ def __init__(self, fp):
+
+ self.palette = [o8(i) * 3 for i in range(256)]
+
+ if fp.readline()[:12] != b"GIMP Palette":
+ raise SyntaxError("not a GIMP palette file")
+
+ for i in range(256):
+
+ s = fp.readline()
+ if not s:
+ break
+
+ # skip fields and comment lines
+ if re.match(br"\w+:|#", s):
+ continue
+ if len(s) > 100:
+ raise SyntaxError("bad palette file")
+
+ v = tuple(map(int, s.split()[:3]))
+ if len(v) != 3:
+ raise ValueError("bad palette entry")
+
+ self.palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2])
+
+ self.palette = b"".join(self.palette)
+
+ def getpalette(self):
+
+ return self.palette, self.rawmode
diff --git a/contrib/python/Pillow/py2/PIL/GribStubImagePlugin.py b/contrib/python/Pillow/py2/PIL/GribStubImagePlugin.py
new file mode 100644
index 0000000000..8a24a9829f
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/GribStubImagePlugin.py
@@ -0,0 +1,74 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# GRIB stub adapter
+#
+# Copyright (c) 1996-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFile
+from ._binary import i8
+
+_handler = None
+
+
+def register_handler(handler):
+ """
+ Install application-specific GRIB image handler.
+
+ :param handler: Handler object.
+ """
+ global _handler
+ _handler = handler
+
+
+# --------------------------------------------------------------------
+# Image adapter
+
+
+def _accept(prefix):
+ return prefix[0:4] == b"GRIB" and i8(prefix[7]) == 1
+
+
+class GribStubImageFile(ImageFile.StubImageFile):
+
+ format = "GRIB"
+ format_description = "GRIB"
+
+ def _open(self):
+
+ offset = self.fp.tell()
+
+ if not _accept(self.fp.read(8)):
+ raise SyntaxError("Not a GRIB file")
+
+ self.fp.seek(offset)
+
+ # make something up
+ self.mode = "F"
+ self._size = 1, 1
+
+ loader = self._load()
+ if loader:
+ loader.open(self)
+
+ def _load(self):
+ return _handler
+
+
+def _save(im, fp, filename):
+ if _handler is None or not hasattr("_handler", "save"):
+ raise IOError("GRIB save handler not installed")
+ _handler.save(im, fp, filename)
+
+
+# --------------------------------------------------------------------
+# Registry
+
+Image.register_open(GribStubImageFile.format, GribStubImageFile, _accept)
+Image.register_save(GribStubImageFile.format, _save)
+
+Image.register_extension(GribStubImageFile.format, ".grib")
diff --git a/contrib/python/Pillow/py2/PIL/Hdf5StubImagePlugin.py b/contrib/python/Pillow/py2/PIL/Hdf5StubImagePlugin.py
new file mode 100644
index 0000000000..a3ea12f999
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/Hdf5StubImagePlugin.py
@@ -0,0 +1,73 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# HDF5 stub adapter
+#
+# Copyright (c) 2000-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFile
+
+_handler = None
+
+
+def register_handler(handler):
+ """
+ Install application-specific HDF5 image handler.
+
+ :param handler: Handler object.
+ """
+ global _handler
+ _handler = handler
+
+
+# --------------------------------------------------------------------
+# Image adapter
+
+
+def _accept(prefix):
+ return prefix[:8] == b"\x89HDF\r\n\x1a\n"
+
+
+class HDF5StubImageFile(ImageFile.StubImageFile):
+
+ format = "HDF5"
+ format_description = "HDF5"
+
+ def _open(self):
+
+ offset = self.fp.tell()
+
+ if not _accept(self.fp.read(8)):
+ raise SyntaxError("Not an HDF file")
+
+ self.fp.seek(offset)
+
+ # make something up
+ self.mode = "F"
+ self._size = 1, 1
+
+ loader = self._load()
+ if loader:
+ loader.open(self)
+
+ def _load(self):
+ return _handler
+
+
+def _save(im, fp, filename):
+ if _handler is None or not hasattr("_handler", "save"):
+ raise IOError("HDF5 save handler not installed")
+ _handler.save(im, fp, filename)
+
+
+# --------------------------------------------------------------------
+# Registry
+
+Image.register_open(HDF5StubImageFile.format, HDF5StubImageFile, _accept)
+Image.register_save(HDF5StubImageFile.format, _save)
+
+Image.register_extensions(HDF5StubImageFile.format, [".h5", ".hdf"])
diff --git a/contrib/python/Pillow/py2/PIL/IcnsImagePlugin.py b/contrib/python/Pillow/py2/PIL/IcnsImagePlugin.py
new file mode 100644
index 0000000000..75ea18b6b5
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/IcnsImagePlugin.py
@@ -0,0 +1,377 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# macOS icns file decoder, based on icns.py by Bob Ippolito.
+#
+# history:
+# 2004-10-09 fl Turned into a PIL plugin; removed 2.3 dependencies.
+#
+# Copyright (c) 2004 by Bob Ippolito.
+# Copyright (c) 2004 by Secret Labs.
+# Copyright (c) 2004 by Fredrik Lundh.
+# Copyright (c) 2014 by Alastair Houghton.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+import os
+import shutil
+import struct
+import sys
+import tempfile
+
+from PIL import Image, ImageFile, PngImagePlugin
+from PIL._binary import i8
+
+enable_jpeg2k = hasattr(Image.core, "jp2klib_version")
+if enable_jpeg2k:
+ from PIL import Jpeg2KImagePlugin
+
+HEADERSIZE = 8
+
+
+def nextheader(fobj):
+ return struct.unpack(">4sI", fobj.read(HEADERSIZE))
+
+
+def read_32t(fobj, start_length, size):
+ # The 128x128 icon seems to have an extra header for some reason.
+ (start, length) = start_length
+ fobj.seek(start)
+ sig = fobj.read(4)
+ if sig != b"\x00\x00\x00\x00":
+ raise SyntaxError("Unknown signature, expecting 0x00000000")
+ return read_32(fobj, (start + 4, length - 4), size)
+
+
+def read_32(fobj, start_length, size):
+ """
+ Read a 32bit RGB icon resource. Seems to be either uncompressed or
+ an RLE packbits-like scheme.
+ """
+ (start, length) = start_length
+ fobj.seek(start)
+ pixel_size = (size[0] * size[2], size[1] * size[2])
+ sizesq = pixel_size[0] * pixel_size[1]
+ if length == sizesq * 3:
+ # uncompressed ("RGBRGBGB")
+ indata = fobj.read(length)
+ im = Image.frombuffer("RGB", pixel_size, indata, "raw", "RGB", 0, 1)
+ else:
+ # decode image
+ im = Image.new("RGB", pixel_size, None)
+ for band_ix in range(3):
+ data = []
+ bytesleft = sizesq
+ while bytesleft > 0:
+ byte = fobj.read(1)
+ if not byte:
+ break
+ byte = i8(byte)
+ if byte & 0x80:
+ blocksize = byte - 125
+ byte = fobj.read(1)
+ for i in range(blocksize):
+ data.append(byte)
+ else:
+ blocksize = byte + 1
+ data.append(fobj.read(blocksize))
+ bytesleft -= blocksize
+ if bytesleft <= 0:
+ break
+ if bytesleft != 0:
+ raise SyntaxError("Error reading channel [%r left]" % bytesleft)
+ band = Image.frombuffer("L", pixel_size, b"".join(data), "raw", "L", 0, 1)
+ im.im.putband(band.im, band_ix)
+ return {"RGB": im}
+
+
+def read_mk(fobj, start_length, size):
+ # Alpha masks seem to be uncompressed
+ start = start_length[0]
+ fobj.seek(start)
+ pixel_size = (size[0] * size[2], size[1] * size[2])
+ sizesq = pixel_size[0] * pixel_size[1]
+ band = Image.frombuffer("L", pixel_size, fobj.read(sizesq), "raw", "L", 0, 1)
+ return {"A": band}
+
+
+def read_png_or_jpeg2000(fobj, start_length, size):
+ (start, length) = start_length
+ fobj.seek(start)
+ sig = fobj.read(12)
+ if sig[:8] == b"\x89PNG\x0d\x0a\x1a\x0a":
+ fobj.seek(start)
+ im = PngImagePlugin.PngImageFile(fobj)
+ return {"RGBA": im}
+ elif (
+ sig[:4] == b"\xff\x4f\xff\x51"
+ or sig[:4] == b"\x0d\x0a\x87\x0a"
+ or sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a"
+ ):
+ if not enable_jpeg2k:
+ raise ValueError(
+ "Unsupported icon subimage format (rebuild PIL "
+ "with JPEG 2000 support to fix this)"
+ )
+ # j2k, jpc or j2c
+ fobj.seek(start)
+ jp2kstream = fobj.read(length)
+ f = io.BytesIO(jp2kstream)
+ im = Jpeg2KImagePlugin.Jpeg2KImageFile(f)
+ if im.mode != "RGBA":
+ im = im.convert("RGBA")
+ return {"RGBA": im}
+ else:
+ raise ValueError("Unsupported icon subimage format")
+
+
+class IcnsFile(object):
+
+ SIZES = {
+ (512, 512, 2): [(b"ic10", read_png_or_jpeg2000)],
+ (512, 512, 1): [(b"ic09", read_png_or_jpeg2000)],
+ (256, 256, 2): [(b"ic14", read_png_or_jpeg2000)],
+ (256, 256, 1): [(b"ic08", read_png_or_jpeg2000)],
+ (128, 128, 2): [(b"ic13", read_png_or_jpeg2000)],
+ (128, 128, 1): [
+ (b"ic07", read_png_or_jpeg2000),
+ (b"it32", read_32t),
+ (b"t8mk", read_mk),
+ ],
+ (64, 64, 1): [(b"icp6", read_png_or_jpeg2000)],
+ (32, 32, 2): [(b"ic12", read_png_or_jpeg2000)],
+ (48, 48, 1): [(b"ih32", read_32), (b"h8mk", read_mk)],
+ (32, 32, 1): [
+ (b"icp5", read_png_or_jpeg2000),
+ (b"il32", read_32),
+ (b"l8mk", read_mk),
+ ],
+ (16, 16, 2): [(b"ic11", read_png_or_jpeg2000)],
+ (16, 16, 1): [
+ (b"icp4", read_png_or_jpeg2000),
+ (b"is32", read_32),
+ (b"s8mk", read_mk),
+ ],
+ }
+
+ def __init__(self, fobj):
+ """
+ fobj is a file-like object as an icns resource
+ """
+ # signature : (start, length)
+ self.dct = dct = {}
+ self.fobj = fobj
+ sig, filesize = nextheader(fobj)
+ if sig != b"icns":
+ raise SyntaxError("not an icns file")
+ i = HEADERSIZE
+ while i < filesize:
+ sig, blocksize = nextheader(fobj)
+ if blocksize <= 0:
+ raise SyntaxError("invalid block header")
+ i += HEADERSIZE
+ blocksize -= HEADERSIZE
+ dct[sig] = (i, blocksize)
+ fobj.seek(blocksize, io.SEEK_CUR)
+ i += blocksize
+
+ def itersizes(self):
+ sizes = []
+ for size, fmts in self.SIZES.items():
+ for (fmt, reader) in fmts:
+ if fmt in self.dct:
+ sizes.append(size)
+ break
+ return sizes
+
+ def bestsize(self):
+ sizes = self.itersizes()
+ if not sizes:
+ raise SyntaxError("No 32bit icon resources found")
+ return max(sizes)
+
+ def dataforsize(self, size):
+ """
+ Get an icon resource as {channel: array}. Note that
+ the arrays are bottom-up like windows bitmaps and will likely
+ need to be flipped or transposed in some way.
+ """
+ dct = {}
+ for code, reader in self.SIZES[size]:
+ desc = self.dct.get(code)
+ if desc is not None:
+ dct.update(reader(self.fobj, desc, size))
+ return dct
+
+ def getimage(self, size=None):
+ if size is None:
+ size = self.bestsize()
+ if len(size) == 2:
+ size = (size[0], size[1], 1)
+ channels = self.dataforsize(size)
+
+ im = channels.get("RGBA", None)
+ if im:
+ return im
+
+ im = channels.get("RGB").copy()
+ try:
+ im.putalpha(channels["A"])
+ except KeyError:
+ pass
+ return im
+
+
+##
+# Image plugin for Mac OS icons.
+
+
+class IcnsImageFile(ImageFile.ImageFile):
+ """
+ PIL image support for Mac OS .icns files.
+ Chooses the best resolution, but will possibly load
+ a different size image if you mutate the size attribute
+ before calling 'load'.
+
+ The info dictionary has a key 'sizes' that is a list
+ of sizes that the icns file has.
+ """
+
+ format = "ICNS"
+ format_description = "Mac OS icns resource"
+
+ def _open(self):
+ self.icns = IcnsFile(self.fp)
+ self.mode = "RGBA"
+ self.info["sizes"] = self.icns.itersizes()
+ self.best_size = self.icns.bestsize()
+ self.size = (
+ self.best_size[0] * self.best_size[2],
+ self.best_size[1] * self.best_size[2],
+ )
+
+ @property
+ def size(self):
+ return self._size
+
+ @size.setter
+ def size(self, value):
+ info_size = value
+ if info_size not in self.info["sizes"] and len(info_size) == 2:
+ info_size = (info_size[0], info_size[1], 1)
+ if (
+ info_size not in self.info["sizes"]
+ and len(info_size) == 3
+ and info_size[2] == 1
+ ):
+ simple_sizes = [
+ (size[0] * size[2], size[1] * size[2]) for size in self.info["sizes"]
+ ]
+ if value in simple_sizes:
+ info_size = self.info["sizes"][simple_sizes.index(value)]
+ if info_size not in self.info["sizes"]:
+ raise ValueError("This is not one of the allowed sizes of this image")
+ self._size = value
+
+ def load(self):
+ if len(self.size) == 3:
+ self.best_size = self.size
+ self.size = (
+ self.best_size[0] * self.best_size[2],
+ self.best_size[1] * self.best_size[2],
+ )
+
+ Image.Image.load(self)
+ if self.im and self.im.size == self.size:
+ # Already loaded
+ return
+ self.load_prepare()
+ # This is likely NOT the best way to do it, but whatever.
+ im = self.icns.getimage(self.best_size)
+
+ # If this is a PNG or JPEG 2000, it won't be loaded yet
+ im.load()
+
+ self.im = im.im
+ self.mode = im.mode
+ self.size = im.size
+ self.load_end()
+
+
+def _save(im, fp, filename):
+ """
+ Saves the image as a series of PNG files,
+ that are then converted to a .icns file
+ using the macOS command line utility 'iconutil'.
+
+ macOS only.
+ """
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+ # create the temporary set of pngs
+ iconset = tempfile.mkdtemp(".iconset")
+ provided_images = {im.width: im for im in im.encoderinfo.get("append_images", [])}
+ last_w = None
+ second_path = None
+ for w in [16, 32, 128, 256, 512]:
+ prefix = "icon_{}x{}".format(w, w)
+
+ first_path = os.path.join(iconset, prefix + ".png")
+ if last_w == w:
+ shutil.copyfile(second_path, first_path)
+ else:
+ im_w = provided_images.get(w, im.resize((w, w), Image.LANCZOS))
+ im_w.save(first_path)
+
+ second_path = os.path.join(iconset, prefix + "@2x.png")
+ im_w2 = provided_images.get(w * 2, im.resize((w * 2, w * 2), Image.LANCZOS))
+ im_w2.save(second_path)
+ last_w = w * 2
+
+ # iconutil -c icns -o {} {}
+ from subprocess import Popen, PIPE, CalledProcessError
+
+ convert_cmd = ["iconutil", "-c", "icns", "-o", filename, iconset]
+ with open(os.devnull, "wb") as devnull:
+ convert_proc = Popen(convert_cmd, stdout=PIPE, stderr=devnull)
+
+ convert_proc.stdout.close()
+
+ retcode = convert_proc.wait()
+
+ # remove the temporary files
+ shutil.rmtree(iconset)
+
+ if retcode:
+ raise CalledProcessError(retcode, convert_cmd)
+
+
+Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == b"icns")
+Image.register_extension(IcnsImageFile.format, ".icns")
+
+if sys.platform == "darwin":
+ Image.register_save(IcnsImageFile.format, _save)
+
+ Image.register_mime(IcnsImageFile.format, "image/icns")
+
+
+if __name__ == "__main__":
+
+ if len(sys.argv) < 2:
+ print("Syntax: python IcnsImagePlugin.py [file]")
+ sys.exit()
+
+ imf = IcnsImageFile(open(sys.argv[1], "rb"))
+ for size in imf.info["sizes"]:
+ imf.size = size
+ imf.load()
+ im = imf.im
+ im.save("out-%s-%s-%s.png" % size)
+ im = Image.open(sys.argv[1])
+ im.save("out.png")
+ if sys.platform == "windows":
+ os.startfile("out.png")
diff --git a/contrib/python/Pillow/py2/PIL/IcoImagePlugin.py b/contrib/python/Pillow/py2/PIL/IcoImagePlugin.py
new file mode 100644
index 0000000000..148e604f89
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/IcoImagePlugin.py
@@ -0,0 +1,327 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Windows Icon support for PIL
+#
+# History:
+# 96-05-27 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+# This plugin is a refactored version of Win32IconImagePlugin by Bryan Davis
+# <casadebender@gmail.com>.
+# https://code.google.com/archive/p/casadebender/wikis/Win32IconImagePlugin.wiki
+#
+# Icon format references:
+# * https://en.wikipedia.org/wiki/ICO_(file_format)
+# * https://msdn.microsoft.com/en-us/library/ms997538.aspx
+
+
+import struct
+import warnings
+from io import BytesIO
+from math import ceil, log
+
+from . import BmpImagePlugin, Image, ImageFile, PngImagePlugin
+from ._binary import i8, i16le as i16, i32le as i32
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+#
+# --------------------------------------------------------------------
+
+_MAGIC = b"\0\0\1\0"
+
+
+def _save(im, fp, filename):
+ fp.write(_MAGIC) # (2+2)
+ sizes = im.encoderinfo.get(
+ "sizes",
+ [(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)],
+ )
+ width, height = im.size
+ sizes = filter(
+ lambda x: False
+ if (x[0] > width or x[1] > height or x[0] > 256 or x[1] > 256)
+ else True,
+ sizes,
+ )
+ sizes = list(sizes)
+ fp.write(struct.pack("<H", len(sizes))) # idCount(2)
+ offset = fp.tell() + len(sizes) * 16
+ for size in sizes:
+ width, height = size
+ # 0 means 256
+ fp.write(struct.pack("B", width if width < 256 else 0)) # bWidth(1)
+ fp.write(struct.pack("B", height if height < 256 else 0)) # bHeight(1)
+ fp.write(b"\0") # bColorCount(1)
+ fp.write(b"\0") # bReserved(1)
+ fp.write(b"\0\0") # wPlanes(2)
+ fp.write(struct.pack("<H", 32)) # wBitCount(2)
+
+ image_io = BytesIO()
+ tmp = im.copy()
+ tmp.thumbnail(size, Image.LANCZOS)
+ tmp.save(image_io, "png")
+ image_io.seek(0)
+ image_bytes = image_io.read()
+ bytes_len = len(image_bytes)
+ fp.write(struct.pack("<I", bytes_len)) # dwBytesInRes(4)
+ fp.write(struct.pack("<I", offset)) # dwImageOffset(4)
+ current = fp.tell()
+ fp.seek(offset)
+ fp.write(image_bytes)
+ offset = offset + bytes_len
+ fp.seek(current)
+
+
+def _accept(prefix):
+ return prefix[:4] == _MAGIC
+
+
+class IcoFile(object):
+ def __init__(self, buf):
+ """
+ Parse image from file-like object containing ico file data
+ """
+
+ # check magic
+ s = buf.read(6)
+ if not _accept(s):
+ raise SyntaxError("not an ICO file")
+
+ self.buf = buf
+ self.entry = []
+
+ # Number of items in file
+ self.nb_items = i16(s[4:])
+
+ # Get headers for each item
+ for i in range(self.nb_items):
+ s = buf.read(16)
+
+ icon_header = {
+ "width": i8(s[0]),
+ "height": i8(s[1]),
+ "nb_color": i8(s[2]), # No. of colors in image (0 if >=8bpp)
+ "reserved": i8(s[3]),
+ "planes": i16(s[4:]),
+ "bpp": i16(s[6:]),
+ "size": i32(s[8:]),
+ "offset": i32(s[12:]),
+ }
+
+ # See Wikipedia
+ for j in ("width", "height"):
+ if not icon_header[j]:
+ icon_header[j] = 256
+
+ # See Wikipedia notes about color depth.
+ # We need this just to differ images with equal sizes
+ icon_header["color_depth"] = (
+ icon_header["bpp"]
+ or (
+ icon_header["nb_color"] != 0
+ and ceil(log(icon_header["nb_color"], 2))
+ )
+ or 256
+ )
+
+ icon_header["dim"] = (icon_header["width"], icon_header["height"])
+ icon_header["square"] = icon_header["width"] * icon_header["height"]
+
+ self.entry.append(icon_header)
+
+ self.entry = sorted(self.entry, key=lambda x: x["color_depth"])
+ # ICO images are usually squares
+ # self.entry = sorted(self.entry, key=lambda x: x['width'])
+ self.entry = sorted(self.entry, key=lambda x: x["square"])
+ self.entry.reverse()
+
+ def sizes(self):
+ """
+ Get a list of all available icon sizes and color depths.
+ """
+ return {(h["width"], h["height"]) for h in self.entry}
+
+ def getentryindex(self, size, bpp=False):
+ for (i, h) in enumerate(self.entry):
+ if size == h["dim"] and (bpp is False or bpp == h["color_depth"]):
+ return i
+ return 0
+
+ def getimage(self, size, bpp=False):
+ """
+ Get an image from the icon
+ """
+ return self.frame(self.getentryindex(size, bpp))
+
+ def frame(self, idx):
+ """
+ Get an image from frame idx
+ """
+
+ header = self.entry[idx]
+
+ self.buf.seek(header["offset"])
+ data = self.buf.read(8)
+ self.buf.seek(header["offset"])
+
+ if data[:8] == PngImagePlugin._MAGIC:
+ # png frame
+ im = PngImagePlugin.PngImageFile(self.buf)
+ else:
+ # XOR + AND mask bmp frame
+ im = BmpImagePlugin.DibImageFile(self.buf)
+ Image._decompression_bomb_check(im.size)
+
+ # change tile dimension to only encompass XOR image
+ im._size = (im.size[0], int(im.size[1] / 2))
+ d, e, o, a = im.tile[0]
+ im.tile[0] = d, (0, 0) + im.size, o, a
+
+ # figure out where AND mask image starts
+ mode = a[0]
+ bpp = 8
+ for k, v in BmpImagePlugin.BIT2MODE.items():
+ if mode == v[1]:
+ bpp = k
+ break
+
+ if 32 == bpp:
+ # 32-bit color depth icon image allows semitransparent areas
+ # PIL's DIB format ignores transparency bits, recover them.
+ # The DIB is packed in BGRX byte order where X is the alpha
+ # channel.
+
+ # Back up to start of bmp data
+ self.buf.seek(o)
+ # extract every 4th byte (eg. 3,7,11,15,...)
+ alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4]
+
+ # convert to an 8bpp grayscale image
+ mask = Image.frombuffer(
+ "L", # 8bpp
+ im.size, # (w, h)
+ alpha_bytes, # source chars
+ "raw", # raw decoder
+ ("L", 0, -1), # 8bpp inverted, unpadded, reversed
+ )
+ else:
+ # get AND image from end of bitmap
+ w = im.size[0]
+ if (w % 32) > 0:
+ # bitmap row data is aligned to word boundaries
+ w += 32 - (im.size[0] % 32)
+
+ # the total mask data is
+ # padded row size * height / bits per char
+
+ and_mask_offset = o + int(im.size[0] * im.size[1] * (bpp / 8.0))
+ total_bytes = int((w * im.size[1]) / 8)
+
+ self.buf.seek(and_mask_offset)
+ mask_data = self.buf.read(total_bytes)
+
+ # convert raw data to image
+ mask = Image.frombuffer(
+ "1", # 1 bpp
+ im.size, # (w, h)
+ mask_data, # source chars
+ "raw", # raw decoder
+ ("1;I", int(w / 8), -1), # 1bpp inverted, padded, reversed
+ )
+
+ # now we have two images, im is XOR image and mask is AND image
+
+ # apply mask image as alpha channel
+ im = im.convert("RGBA")
+ im.putalpha(mask)
+
+ return im
+
+
+##
+# Image plugin for Windows Icon files.
+
+
+class IcoImageFile(ImageFile.ImageFile):
+ """
+ PIL read-only image support for Microsoft Windows .ico files.
+
+ By default the largest resolution image in the file will be loaded. This
+ can be changed by altering the 'size' attribute before calling 'load'.
+
+ The info dictionary has a key 'sizes' that is a list of the sizes available
+ in the icon file.
+
+ Handles classic, XP and Vista icon formats.
+
+ When saving, PNG compression is used. Support for this was only added in
+ Windows Vista.
+
+ This plugin is a refactored version of Win32IconImagePlugin by Bryan Davis
+ <casadebender@gmail.com>.
+ https://code.google.com/archive/p/casadebender/wikis/Win32IconImagePlugin.wiki
+ """
+
+ format = "ICO"
+ format_description = "Windows Icon"
+
+ def _open(self):
+ self.ico = IcoFile(self.fp)
+ self.info["sizes"] = self.ico.sizes()
+ self.size = self.ico.entry[0]["dim"]
+ self.load()
+
+ @property
+ def size(self):
+ return self._size
+
+ @size.setter
+ def size(self, value):
+ if value not in self.info["sizes"]:
+ raise ValueError("This is not one of the allowed sizes of this image")
+ self._size = value
+
+ def load(self):
+ if self.im and self.im.size == self.size:
+ # Already loaded
+ return
+ im = self.ico.getimage(self.size)
+ # if tile is PNG, it won't really be loaded yet
+ im.load()
+ self.im = im.im
+ self.mode = im.mode
+ if im.size != self.size:
+ warnings.warn("Image was not the expected size")
+
+ index = self.ico.getentryindex(self.size)
+ sizes = list(self.info["sizes"])
+ sizes[index] = im.size
+ self.info["sizes"] = set(sizes)
+
+ self.size = im.size
+
+ def load_seek(self):
+ # Flag the ImageFile.Parser so that it
+ # just does all the decode at the end.
+ pass
+
+
+#
+# --------------------------------------------------------------------
+
+
+Image.register_open(IcoImageFile.format, IcoImageFile, _accept)
+Image.register_save(IcoImageFile.format, _save)
+Image.register_extension(IcoImageFile.format, ".ico")
+
+Image.register_mime(IcoImageFile.format, "image/x-icon")
diff --git a/contrib/python/Pillow/py2/PIL/ImImagePlugin.py b/contrib/python/Pillow/py2/PIL/ImImagePlugin.py
new file mode 100644
index 0000000000..77127fae6f
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImImagePlugin.py
@@ -0,0 +1,374 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# IFUNC IM file handling for PIL
+#
+# history:
+# 1995-09-01 fl Created.
+# 1997-01-03 fl Save palette images
+# 1997-01-08 fl Added sequence support
+# 1997-01-23 fl Added P and RGB save support
+# 1997-05-31 fl Read floating point images
+# 1997-06-22 fl Save floating point images
+# 1997-08-27 fl Read and save 1-bit images
+# 1998-06-25 fl Added support for RGB+LUT images
+# 1998-07-02 fl Added support for YCC images
+# 1998-07-15 fl Renamed offset attribute to avoid name clash
+# 1998-12-29 fl Added I;16 support
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.7)
+# 2003-09-26 fl Added LA/PA support
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-2001 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import re
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.7"
+
+
+# --------------------------------------------------------------------
+# Standard tags
+
+COMMENT = "Comment"
+DATE = "Date"
+EQUIPMENT = "Digitalization equipment"
+FRAMES = "File size (no of images)"
+LUT = "Lut"
+NAME = "Name"
+SCALE = "Scale (x,y)"
+SIZE = "Image size (x*y)"
+MODE = "Image type"
+
+TAGS = {
+ COMMENT: 0,
+ DATE: 0,
+ EQUIPMENT: 0,
+ FRAMES: 0,
+ LUT: 0,
+ NAME: 0,
+ SCALE: 0,
+ SIZE: 0,
+ MODE: 0,
+}
+
+OPEN = {
+ # ifunc93/p3cfunc formats
+ "0 1 image": ("1", "1"),
+ "L 1 image": ("1", "1"),
+ "Greyscale image": ("L", "L"),
+ "Grayscale image": ("L", "L"),
+ "RGB image": ("RGB", "RGB;L"),
+ "RLB image": ("RGB", "RLB"),
+ "RYB image": ("RGB", "RLB"),
+ "B1 image": ("1", "1"),
+ "B2 image": ("P", "P;2"),
+ "B4 image": ("P", "P;4"),
+ "X 24 image": ("RGB", "RGB"),
+ "L 32 S image": ("I", "I;32"),
+ "L 32 F image": ("F", "F;32"),
+ # old p3cfunc formats
+ "RGB3 image": ("RGB", "RGB;T"),
+ "RYB3 image": ("RGB", "RYB;T"),
+ # extensions
+ "LA image": ("LA", "LA;L"),
+ "PA image": ("LA", "PA;L"),
+ "RGBA image": ("RGBA", "RGBA;L"),
+ "RGBX image": ("RGBX", "RGBX;L"),
+ "CMYK image": ("CMYK", "CMYK;L"),
+ "YCC image": ("YCbCr", "YCbCr;L"),
+}
+
+# ifunc95 extensions
+for i in ["8", "8S", "16", "16S", "32", "32F"]:
+ OPEN["L %s image" % i] = ("F", "F;%s" % i)
+ OPEN["L*%s image" % i] = ("F", "F;%s" % i)
+for i in ["16", "16L", "16B"]:
+ OPEN["L %s image" % i] = ("I;%s" % i, "I;%s" % i)
+ OPEN["L*%s image" % i] = ("I;%s" % i, "I;%s" % i)
+for i in ["32S"]:
+ OPEN["L %s image" % i] = ("I", "I;%s" % i)
+ OPEN["L*%s image" % i] = ("I", "I;%s" % i)
+for i in range(2, 33):
+ OPEN["L*%s image" % i] = ("F", "F;%s" % i)
+
+
+# --------------------------------------------------------------------
+# Read IM directory
+
+split = re.compile(br"^([A-Za-z][^:]*):[ \t]*(.*)[ \t]*$")
+
+
+def number(s):
+ try:
+ return int(s)
+ except ValueError:
+ return float(s)
+
+
+##
+# Image plugin for the IFUNC IM file format.
+
+
+class ImImageFile(ImageFile.ImageFile):
+
+ format = "IM"
+ format_description = "IFUNC Image Memory"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+
+ # Quick rejection: if there's not an LF among the first
+ # 100 bytes, this is (probably) not a text header.
+
+ if b"\n" not in self.fp.read(100):
+ raise SyntaxError("not an IM file")
+ self.fp.seek(0)
+
+ n = 0
+
+ # Default values
+ self.info[MODE] = "L"
+ self.info[SIZE] = (512, 512)
+ self.info[FRAMES] = 1
+
+ self.rawmode = "L"
+
+ while True:
+
+ s = self.fp.read(1)
+
+ # Some versions of IFUNC uses \n\r instead of \r\n...
+ if s == b"\r":
+ continue
+
+ if not s or s == b"\0" or s == b"\x1A":
+ break
+
+ # FIXME: this may read whole file if not a text file
+ s = s + self.fp.readline()
+
+ if len(s) > 100:
+ raise SyntaxError("not an IM file")
+
+ if s[-2:] == b"\r\n":
+ s = s[:-2]
+ elif s[-1:] == b"\n":
+ s = s[:-1]
+
+ try:
+ m = split.match(s)
+ except re.error:
+ raise SyntaxError("not an IM file")
+
+ if m:
+
+ k, v = m.group(1, 2)
+
+ # Don't know if this is the correct encoding,
+ # but a decent guess (I guess)
+ k = k.decode("latin-1", "replace")
+ v = v.decode("latin-1", "replace")
+
+ # Convert value as appropriate
+ if k in [FRAMES, SCALE, SIZE]:
+ v = v.replace("*", ",")
+ v = tuple(map(number, v.split(",")))
+ if len(v) == 1:
+ v = v[0]
+ elif k == MODE and v in OPEN:
+ v, self.rawmode = OPEN[v]
+
+ # Add to dictionary. Note that COMMENT tags are
+ # combined into a list of strings.
+ if k == COMMENT:
+ if k in self.info:
+ self.info[k].append(v)
+ else:
+ self.info[k] = [v]
+ else:
+ self.info[k] = v
+
+ if k in TAGS:
+ n += 1
+
+ else:
+
+ raise SyntaxError(
+ "Syntax error in IM header: " + s.decode("ascii", "replace")
+ )
+
+ if not n:
+ raise SyntaxError("Not an IM file")
+
+ # Basic attributes
+ self._size = self.info[SIZE]
+ self.mode = self.info[MODE]
+
+ # Skip forward to start of image data
+ while s and s[0:1] != b"\x1A":
+ s = self.fp.read(1)
+ if not s:
+ raise SyntaxError("File truncated")
+
+ if LUT in self.info:
+ # convert lookup table to palette or lut attribute
+ palette = self.fp.read(768)
+ greyscale = 1 # greyscale palette
+ linear = 1 # linear greyscale palette
+ for i in range(256):
+ if palette[i] == palette[i + 256] == palette[i + 512]:
+ if i8(palette[i]) != i:
+ linear = 0
+ else:
+ greyscale = 0
+ if self.mode in ["L", "LA", "P", "PA"]:
+ if greyscale:
+ if not linear:
+ self.lut = [i8(c) for c in palette[:256]]
+ else:
+ if self.mode in ["L", "P"]:
+ self.mode = self.rawmode = "P"
+ elif self.mode in ["LA", "PA"]:
+ self.mode = "PA"
+ self.rawmode = "PA;L"
+ self.palette = ImagePalette.raw("RGB;L", palette)
+ elif self.mode == "RGB":
+ if not greyscale or not linear:
+ self.lut = [i8(c) for c in palette]
+
+ self.frame = 0
+
+ self.__offset = offs = self.fp.tell()
+
+ self.__fp = self.fp # FIXME: hack
+
+ if self.rawmode[:2] == "F;":
+
+ # ifunc95 formats
+ try:
+ # use bit decoder (if necessary)
+ bits = int(self.rawmode[2:])
+ if bits not in [8, 16, 32]:
+ self.tile = [("bit", (0, 0) + self.size, offs, (bits, 8, 3, 0, -1))]
+ return
+ except ValueError:
+ pass
+
+ if self.rawmode in ["RGB;T", "RYB;T"]:
+ # Old LabEye/3PC files. Would be very surprised if anyone
+ # ever stumbled upon such a file ;-)
+ size = self.size[0] * self.size[1]
+ self.tile = [
+ ("raw", (0, 0) + self.size, offs, ("G", 0, -1)),
+ ("raw", (0, 0) + self.size, offs + size, ("R", 0, -1)),
+ ("raw", (0, 0) + self.size, offs + 2 * size, ("B", 0, -1)),
+ ]
+ else:
+ # LabEye/IFUNC files
+ self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))]
+
+ @property
+ def n_frames(self):
+ return self.info[FRAMES]
+
+ @property
+ def is_animated(self):
+ return self.info[FRAMES] > 1
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+
+ self.frame = frame
+
+ if self.mode == "1":
+ bits = 1
+ else:
+ bits = 8 * len(self.mode)
+
+ size = ((self.size[0] * bits + 7) // 8) * self.size[1]
+ offs = self.__offset + frame * size
+
+ self.fp = self.__fp
+
+ self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))]
+
+ def tell(self):
+ return self.frame
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+#
+# --------------------------------------------------------------------
+# Save IM files
+
+
+SAVE = {
+ # mode: (im type, raw mode)
+ "1": ("0 1", "1"),
+ "L": ("Greyscale", "L"),
+ "LA": ("LA", "LA;L"),
+ "P": ("Greyscale", "P"),
+ "PA": ("LA", "PA;L"),
+ "I": ("L 32S", "I;32S"),
+ "I;16": ("L 16", "I;16"),
+ "I;16L": ("L 16L", "I;16L"),
+ "I;16B": ("L 16B", "I;16B"),
+ "F": ("L 32F", "F;32F"),
+ "RGB": ("RGB", "RGB;L"),
+ "RGBA": ("RGBA", "RGBA;L"),
+ "RGBX": ("RGBX", "RGBX;L"),
+ "CMYK": ("CMYK", "CMYK;L"),
+ "YCbCr": ("YCC", "YCbCr;L"),
+}
+
+
+def _save(im, fp, filename):
+
+ try:
+ image_type, rawmode = SAVE[im.mode]
+ except KeyError:
+ raise ValueError("Cannot save %s images as IM" % im.mode)
+
+ frames = im.encoderinfo.get("frames", 1)
+
+ fp.write(("Image type: %s image\r\n" % image_type).encode("ascii"))
+ if filename:
+ fp.write(("Name: %s\r\n" % filename).encode("ascii"))
+ fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode("ascii"))
+ fp.write(("File size (no of images): %d\r\n" % frames).encode("ascii"))
+ if im.mode in ["P", "PA"]:
+ fp.write(b"Lut: 1\r\n")
+ fp.write(b"\000" * (511 - fp.tell()) + b"\032")
+ if im.mode in ["P", "PA"]:
+ fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, -1))])
+
+
+#
+# --------------------------------------------------------------------
+# Registry
+
+
+Image.register_open(ImImageFile.format, ImImageFile)
+Image.register_save(ImImageFile.format, _save)
+
+Image.register_extension(ImImageFile.format, ".im")
diff --git a/contrib/python/Pillow/py2/PIL/Image.py b/contrib/python/Pillow/py2/PIL/Image.py
new file mode 100644
index 0000000000..3fbe8c8b28
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/Image.py
@@ -0,0 +1,3343 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# the Image class wrapper
+#
+# partial release history:
+# 1995-09-09 fl Created
+# 1996-03-11 fl PIL release 0.0 (proof of concept)
+# 1996-04-30 fl PIL release 0.1b1
+# 1999-07-28 fl PIL release 1.0 final
+# 2000-06-07 fl PIL release 1.1
+# 2000-10-20 fl PIL release 1.1.1
+# 2001-05-07 fl PIL release 1.1.2
+# 2002-03-15 fl PIL release 1.1.3
+# 2003-05-10 fl PIL release 1.1.4
+# 2005-03-28 fl PIL release 1.1.5
+# 2006-12-02 fl PIL release 1.1.6
+# 2009-11-15 fl PIL release 1.1.7
+#
+# Copyright (c) 1997-2009 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1995-2009 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import atexit
+import io
+import logging
+import math
+import numbers
+import os
+import struct
+import sys
+import warnings
+
+# VERSION was removed in Pillow 6.0.0.
+# PILLOW_VERSION is deprecated and will be removed in Pillow 7.0.0.
+# Use __version__ instead.
+from . import PILLOW_VERSION, ImageMode, TiffTags, __version__, _plugins
+from ._binary import i8, i32le
+from ._util import deferred_error, isPath, isStringType, py3
+
+try:
+ import builtins
+except ImportError:
+ import __builtin__
+
+ builtins = __builtin__
+
+
+try:
+ # Python 3
+ from collections.abc import Callable, MutableMapping
+except ImportError:
+ # Python 2.7
+ from collections import Callable, MutableMapping
+
+
+# Silence warning
+assert PILLOW_VERSION
+
+logger = logging.getLogger(__name__)
+
+
+class DecompressionBombWarning(RuntimeWarning):
+ pass
+
+
+class DecompressionBombError(Exception):
+ pass
+
+
+class _imaging_not_installed(object):
+ # module placeholder
+ def __getattr__(self, id):
+ raise ImportError("The _imaging C module is not installed")
+
+
+# Limit to around a quarter gigabyte for a 24 bit (3 bpp) image
+MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 // 4 // 3)
+
+
+try:
+ # If the _imaging C module is not present, Pillow will not load.
+ # Note that other modules should not refer to _imaging directly;
+ # import Image and use the Image.core variable instead.
+ # Also note that Image.core is not a publicly documented interface,
+ # and should be considered private and subject to change.
+ from . import _imaging as core
+
+ if __version__ != getattr(core, "PILLOW_VERSION", None):
+ raise ImportError(
+ "The _imaging extension was built for another version of Pillow or PIL:\n"
+ "Core version: %s\n"
+ "Pillow version: %s" % (getattr(core, "PILLOW_VERSION", None), __version__)
+ )
+
+except ImportError as v:
+ core = _imaging_not_installed()
+ # Explanations for ways that we know we might have an import error
+ if str(v).startswith("Module use of python"):
+ # The _imaging C module is present, but not compiled for
+ # the right version (windows only). Print a warning, if
+ # possible.
+ warnings.warn(
+ "The _imaging extension was built for another version of Python.",
+ RuntimeWarning,
+ )
+ elif str(v).startswith("The _imaging extension"):
+ warnings.warn(str(v), RuntimeWarning)
+ elif "Symbol not found: _PyUnicodeUCS2_" in str(v):
+ # should match _PyUnicodeUCS2_FromString and
+ # _PyUnicodeUCS2_AsLatin1String
+ warnings.warn(
+ "The _imaging extension was built for Python with UCS2 support; "
+ "recompile Pillow or build Python --without-wide-unicode. ",
+ RuntimeWarning,
+ )
+ elif "Symbol not found: _PyUnicodeUCS4_" in str(v):
+ # should match _PyUnicodeUCS4_FromString and
+ # _PyUnicodeUCS4_AsLatin1String
+ warnings.warn(
+ "The _imaging extension was built for Python with UCS4 support; "
+ "recompile Pillow or build Python --with-wide-unicode. ",
+ RuntimeWarning,
+ )
+ # Fail here anyway. Don't let people run with a mostly broken Pillow.
+ # see docs/porting.rst
+ raise
+
+
+# works everywhere, win for pypy, not cpython
+USE_CFFI_ACCESS = hasattr(sys, "pypy_version_info")
+try:
+ import cffi
+except ImportError:
+ cffi = None
+
+try:
+ from pathlib import Path
+
+ HAS_PATHLIB = True
+except ImportError:
+ try:
+ from pathlib2 import Path
+
+ HAS_PATHLIB = True
+ except ImportError:
+ HAS_PATHLIB = False
+
+
+def isImageType(t):
+ """
+ Checks if an object is an image object.
+
+ .. warning::
+
+ This function is for internal use only.
+
+ :param t: object to check if it's an image
+ :returns: True if the object is an image
+ """
+ return hasattr(t, "im")
+
+
+#
+# Constants
+
+NONE = 0
+
+# transpose
+FLIP_LEFT_RIGHT = 0
+FLIP_TOP_BOTTOM = 1
+ROTATE_90 = 2
+ROTATE_180 = 3
+ROTATE_270 = 4
+TRANSPOSE = 5
+TRANSVERSE = 6
+
+# transforms (also defined in Imaging.h)
+AFFINE = 0
+EXTENT = 1
+PERSPECTIVE = 2
+QUAD = 3
+MESH = 4
+
+# resampling filters (also defined in Imaging.h)
+NEAREST = NONE = 0
+BOX = 4
+BILINEAR = LINEAR = 2
+HAMMING = 5
+BICUBIC = CUBIC = 3
+LANCZOS = ANTIALIAS = 1
+
+# dithers
+NEAREST = NONE = 0
+ORDERED = 1 # Not yet implemented
+RASTERIZE = 2 # Not yet implemented
+FLOYDSTEINBERG = 3 # default
+
+# palettes/quantizers
+WEB = 0
+ADAPTIVE = 1
+
+MEDIANCUT = 0
+MAXCOVERAGE = 1
+FASTOCTREE = 2
+LIBIMAGEQUANT = 3
+
+# categories
+NORMAL = 0
+SEQUENCE = 1
+CONTAINER = 2
+
+if hasattr(core, "DEFAULT_STRATEGY"):
+ DEFAULT_STRATEGY = core.DEFAULT_STRATEGY
+ FILTERED = core.FILTERED
+ HUFFMAN_ONLY = core.HUFFMAN_ONLY
+ RLE = core.RLE
+ FIXED = core.FIXED
+
+
+# --------------------------------------------------------------------
+# Registries
+
+ID = []
+OPEN = {}
+MIME = {}
+SAVE = {}
+SAVE_ALL = {}
+EXTENSION = {}
+DECODERS = {}
+ENCODERS = {}
+
+# --------------------------------------------------------------------
+# Modes supported by this version
+
+_MODEINFO = {
+ # NOTE: this table will be removed in future versions. use
+ # getmode* functions or ImageMode descriptors instead.
+ # official modes
+ "1": ("L", "L", ("1",)),
+ "L": ("L", "L", ("L",)),
+ "I": ("L", "I", ("I",)),
+ "F": ("L", "F", ("F",)),
+ "P": ("P", "L", ("P",)),
+ "RGB": ("RGB", "L", ("R", "G", "B")),
+ "RGBX": ("RGB", "L", ("R", "G", "B", "X")),
+ "RGBA": ("RGB", "L", ("R", "G", "B", "A")),
+ "CMYK": ("RGB", "L", ("C", "M", "Y", "K")),
+ "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")),
+ "LAB": ("RGB", "L", ("L", "A", "B")),
+ "HSV": ("RGB", "L", ("H", "S", "V")),
+ # Experimental modes include I;16, I;16L, I;16B, RGBa, BGR;15, and
+ # BGR;24. Use these modes only if you know exactly what you're
+ # doing...
+}
+
+if sys.byteorder == "little":
+ _ENDIAN = "<"
+else:
+ _ENDIAN = ">"
+
+_MODE_CONV = {
+ # official modes
+ "1": ("|b1", None), # Bits need to be extended to bytes
+ "L": ("|u1", None),
+ "LA": ("|u1", 2),
+ "I": (_ENDIAN + "i4", None),
+ "F": (_ENDIAN + "f4", None),
+ "P": ("|u1", None),
+ "RGB": ("|u1", 3),
+ "RGBX": ("|u1", 4),
+ "RGBA": ("|u1", 4),
+ "CMYK": ("|u1", 4),
+ "YCbCr": ("|u1", 3),
+ "LAB": ("|u1", 3), # UNDONE - unsigned |u1i1i1
+ "HSV": ("|u1", 3),
+ # I;16 == I;16L, and I;32 == I;32L
+ "I;16": ("<u2", None),
+ "I;16B": (">u2", None),
+ "I;16L": ("<u2", None),
+ "I;16S": ("<i2", None),
+ "I;16BS": (">i2", None),
+ "I;16LS": ("<i2", None),
+ "I;32": ("<u4", None),
+ "I;32B": (">u4", None),
+ "I;32L": ("<u4", None),
+ "I;32S": ("<i4", None),
+ "I;32BS": (">i4", None),
+ "I;32LS": ("<i4", None),
+}
+
+
+def _conv_type_shape(im):
+ typ, extra = _MODE_CONV[im.mode]
+ if extra is None:
+ return (im.size[1], im.size[0]), typ
+ else:
+ return (im.size[1], im.size[0], extra), typ
+
+
+MODES = sorted(_MODEINFO)
+
+# raw modes that may be memory mapped. NOTE: if you change this, you
+# may have to modify the stride calculation in map.c too!
+_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B")
+
+
+def getmodebase(mode):
+ """
+ Gets the "base" mode for given mode. This function returns "L" for
+ images that contain grayscale data, and "RGB" for images that
+ contain color data.
+
+ :param mode: Input mode.
+ :returns: "L" or "RGB".
+ :exception KeyError: If the input mode was not a standard mode.
+ """
+ return ImageMode.getmode(mode).basemode
+
+
+def getmodetype(mode):
+ """
+ Gets the storage type mode. Given a mode, this function returns a
+ single-layer mode suitable for storing individual bands.
+
+ :param mode: Input mode.
+ :returns: "L", "I", or "F".
+ :exception KeyError: If the input mode was not a standard mode.
+ """
+ return ImageMode.getmode(mode).basetype
+
+
+def getmodebandnames(mode):
+ """
+ Gets a list of individual band names. Given a mode, this function returns
+ a tuple containing the names of individual bands (use
+ :py:method:`~PIL.Image.getmodetype` to get the mode used to store each
+ individual band.
+
+ :param mode: Input mode.
+ :returns: A tuple containing band names. The length of the tuple
+ gives the number of bands in an image of the given mode.
+ :exception KeyError: If the input mode was not a standard mode.
+ """
+ return ImageMode.getmode(mode).bands
+
+
+def getmodebands(mode):
+ """
+ Gets the number of individual bands for this mode.
+
+ :param mode: Input mode.
+ :returns: The number of bands in this mode.
+ :exception KeyError: If the input mode was not a standard mode.
+ """
+ return len(ImageMode.getmode(mode).bands)
+
+
+# --------------------------------------------------------------------
+# Helpers
+
+_initialized = 0
+
+
+def preinit():
+ """Explicitly load standard file format drivers."""
+
+ global _initialized
+ if _initialized >= 1:
+ return
+
+ try:
+ from . import BmpImagePlugin
+
+ assert BmpImagePlugin
+ except ImportError:
+ pass
+ try:
+ from . import GifImagePlugin
+
+ assert GifImagePlugin
+ except ImportError:
+ pass
+ try:
+ from . import JpegImagePlugin
+
+ assert JpegImagePlugin
+ except ImportError:
+ pass
+ try:
+ from . import PpmImagePlugin
+
+ assert PpmImagePlugin
+ except ImportError:
+ pass
+ try:
+ from . import PngImagePlugin
+
+ assert PngImagePlugin
+ except ImportError:
+ pass
+ # try:
+ # import TiffImagePlugin
+ # assert TiffImagePlugin
+ # except ImportError:
+ # pass
+
+ _initialized = 1
+
+
+def init():
+ """
+ Explicitly initializes the Python Imaging Library. This function
+ loads all available file format drivers.
+ """
+
+ global _initialized
+ if _initialized >= 2:
+ return 0
+
+ for plugin in _plugins:
+ try:
+ logger.debug("Importing %s", plugin)
+ __import__("PIL.%s" % plugin, globals(), locals(), [])
+ except ImportError as e:
+ logger.debug("Image: failed to import %s: %s", plugin, e)
+
+ if OPEN or SAVE:
+ _initialized = 2
+ return 1
+
+
+# --------------------------------------------------------------------
+# Codec factories (used by tobytes/frombytes and ImageFile.load)
+
+
+def _getdecoder(mode, decoder_name, args, extra=()):
+
+ # tweak arguments
+ if args is None:
+ args = ()
+ elif not isinstance(args, tuple):
+ args = (args,)
+
+ try:
+ decoder = DECODERS[decoder_name]
+ return decoder(mode, *args + extra)
+ except KeyError:
+ pass
+ try:
+ # get decoder
+ decoder = getattr(core, decoder_name + "_decoder")
+ return decoder(mode, *args + extra)
+ except AttributeError:
+ raise IOError("decoder %s not available" % decoder_name)
+
+
+def _getencoder(mode, encoder_name, args, extra=()):
+
+ # tweak arguments
+ if args is None:
+ args = ()
+ elif not isinstance(args, tuple):
+ args = (args,)
+
+ try:
+ encoder = ENCODERS[encoder_name]
+ return encoder(mode, *args + extra)
+ except KeyError:
+ pass
+ try:
+ # get encoder
+ encoder = getattr(core, encoder_name + "_encoder")
+ return encoder(mode, *args + extra)
+ except AttributeError:
+ raise IOError("encoder %s not available" % encoder_name)
+
+
+# --------------------------------------------------------------------
+# Simple expression analyzer
+
+
+def coerce_e(value):
+ return value if isinstance(value, _E) else _E(value)
+
+
+class _E(object):
+ def __init__(self, data):
+ self.data = data
+
+ def __add__(self, other):
+ return _E((self.data, "__add__", coerce_e(other).data))
+
+ def __mul__(self, other):
+ return _E((self.data, "__mul__", coerce_e(other).data))
+
+
+def _getscaleoffset(expr):
+ stub = ["stub"]
+ data = expr(_E(stub)).data
+ try:
+ (a, b, c) = data # simplified syntax
+ if a is stub and b == "__mul__" and isinstance(c, numbers.Number):
+ return c, 0.0
+ if a is stub and b == "__add__" and isinstance(c, numbers.Number):
+ return 1.0, c
+ except TypeError:
+ pass
+ try:
+ ((a, b, c), d, e) = data # full syntax
+ if (
+ a is stub
+ and b == "__mul__"
+ and isinstance(c, numbers.Number)
+ and d == "__add__"
+ and isinstance(e, numbers.Number)
+ ):
+ return c, e
+ except TypeError:
+ pass
+ raise ValueError("illegal expression")
+
+
+# --------------------------------------------------------------------
+# Implementation wrapper
+
+
+class Image(object):
+ """
+ This class represents an image object. To create
+ :py:class:`~PIL.Image.Image` objects, use the appropriate factory
+ functions. There's hardly ever any reason to call the Image constructor
+ directly.
+
+ * :py:func:`~PIL.Image.open`
+ * :py:func:`~PIL.Image.new`
+ * :py:func:`~PIL.Image.frombytes`
+ """
+
+ format = None
+ format_description = None
+ _close_exclusive_fp_after_loading = True
+
+ def __init__(self):
+ # FIXME: take "new" parameters / other image?
+ # FIXME: turn mode and size into delegating properties?
+ self.im = None
+ self.mode = ""
+ self._size = (0, 0)
+ self.palette = None
+ self.info = {}
+ self.category = NORMAL
+ self.readonly = 0
+ self.pyaccess = None
+ self._exif = None
+
+ @property
+ def width(self):
+ return self.size[0]
+
+ @property
+ def height(self):
+ return self.size[1]
+
+ @property
+ def size(self):
+ return self._size
+
+ def _new(self, im):
+ new = Image()
+ new.im = im
+ new.mode = im.mode
+ new._size = im.size
+ if im.mode in ("P", "PA"):
+ if self.palette:
+ new.palette = self.palette.copy()
+ else:
+ from . import ImagePalette
+
+ new.palette = ImagePalette.ImagePalette()
+ new.info = self.info.copy()
+ return new
+
+ # Context manager support
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ if hasattr(self, "fp") and getattr(self, "_exclusive_fp", False):
+ if hasattr(self, "_close__fp"):
+ self._close__fp()
+ if self.fp:
+ self.fp.close()
+ self.fp = None
+
+ def close(self):
+ """
+ Closes the file pointer, if possible.
+
+ This operation will destroy the image core and release its memory.
+ The image data will be unusable afterward.
+
+ This function is only required to close images that have not
+ had their file read and closed by the
+ :py:meth:`~PIL.Image.Image.load` method. See
+ :ref:`file-handling` for more information.
+ """
+ try:
+ if hasattr(self, "_close__fp"):
+ self._close__fp()
+ self.fp.close()
+ self.fp = None
+ except Exception as msg:
+ logger.debug("Error closing: %s", msg)
+
+ if getattr(self, "map", None):
+ self.map = None
+
+ # Instead of simply setting to None, we're setting up a
+ # deferred error that will better explain that the core image
+ # object is gone.
+ self.im = deferred_error(ValueError("Operation on closed image"))
+
+ if sys.version_info.major >= 3:
+
+ def __del__(self):
+ self.__exit__()
+
+ def _copy(self):
+ self.load()
+ self.im = self.im.copy()
+ self.pyaccess = None
+ self.readonly = 0
+
+ def _ensure_mutable(self):
+ if self.readonly:
+ self._copy()
+ else:
+ self.load()
+
+ def _dump(self, file=None, format=None, **options):
+ import tempfile
+
+ suffix = ""
+ if format:
+ suffix = "." + format
+
+ if not file:
+ f, filename = tempfile.mkstemp(suffix)
+ os.close(f)
+ else:
+ filename = file
+ if not filename.endswith(suffix):
+ filename = filename + suffix
+
+ self.load()
+
+ if not format or format == "PPM":
+ self.im.save_ppm(filename)
+ else:
+ self.save(filename, format, **options)
+
+ return filename
+
+ def __eq__(self, other):
+ return (
+ self.__class__ is other.__class__
+ and self.mode == other.mode
+ and self.size == other.size
+ and self.info == other.info
+ and self.category == other.category
+ and self.readonly == other.readonly
+ and self.getpalette() == other.getpalette()
+ and self.tobytes() == other.tobytes()
+ )
+
+ def __ne__(self, other):
+ eq = self == other
+ return not eq
+
+ def __repr__(self):
+ return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % (
+ self.__class__.__module__,
+ self.__class__.__name__,
+ self.mode,
+ self.size[0],
+ self.size[1],
+ id(self),
+ )
+
+ def _repr_png_(self):
+ """ iPython display hook support
+
+ :returns: png version of the image as bytes
+ """
+ b = io.BytesIO()
+ self.save(b, "PNG")
+ return b.getvalue()
+
+ @property
+ def __array_interface__(self):
+ # numpy array interface support
+ new = {}
+ shape, typestr = _conv_type_shape(self)
+ new["shape"] = shape
+ new["typestr"] = typestr
+ new["version"] = 3
+ if self.mode == "1":
+ # Binary images need to be extended from bits to bytes
+ # See: https://github.com/python-pillow/Pillow/issues/350
+ new["data"] = self.tobytes("raw", "L")
+ else:
+ new["data"] = self.tobytes()
+ return new
+
+ def __getstate__(self):
+ return [self.info, self.mode, self.size, self.getpalette(), self.tobytes()]
+
+ def __setstate__(self, state):
+ Image.__init__(self)
+ self.tile = []
+ info, mode, size, palette, data = state
+ self.info = info
+ self.mode = mode
+ self._size = size
+ self.im = core.new(mode, size)
+ if mode in ("L", "LA", "P", "PA") and palette:
+ self.putpalette(palette)
+ self.frombytes(data)
+
+ def tobytes(self, encoder_name="raw", *args):
+ """
+ Return image as a bytes object.
+
+ .. warning::
+
+ This method returns the raw image data from the internal
+ storage. For compressed image data (e.g. PNG, JPEG) use
+ :meth:`~.save`, with a BytesIO parameter for in-memory
+ data.
+
+ :param encoder_name: What encoder to use. The default is to
+ use the standard "raw" encoder.
+ :param args: Extra arguments to the encoder.
+ :rtype: A bytes object.
+ """
+
+ # may pass tuple instead of argument list
+ if len(args) == 1 and isinstance(args[0], tuple):
+ args = args[0]
+
+ if encoder_name == "raw" and args == ():
+ args = self.mode
+
+ self.load()
+
+ # unpack data
+ e = _getencoder(self.mode, encoder_name, args)
+ e.setimage(self.im)
+
+ bufsize = max(65536, self.size[0] * 4) # see RawEncode.c
+
+ data = []
+ while True:
+ l, s, d = e.encode(bufsize)
+ data.append(d)
+ if s:
+ break
+ if s < 0:
+ raise RuntimeError("encoder error %d in tobytes" % s)
+
+ return b"".join(data)
+
+ def tostring(self, *args, **kw):
+ raise NotImplementedError(
+ "tostring() has been removed. Please call tobytes() instead."
+ )
+
+ def tobitmap(self, name="image"):
+ """
+ Returns the image converted to an X11 bitmap.
+
+ .. note:: This method only works for mode "1" images.
+
+ :param name: The name prefix to use for the bitmap variables.
+ :returns: A string containing an X11 bitmap.
+ :raises ValueError: If the mode is not "1"
+ """
+
+ self.load()
+ if self.mode != "1":
+ raise ValueError("not a bitmap")
+ data = self.tobytes("xbm")
+ return b"".join(
+ [
+ ("#define %s_width %d\n" % (name, self.size[0])).encode("ascii"),
+ ("#define %s_height %d\n" % (name, self.size[1])).encode("ascii"),
+ ("static char %s_bits[] = {\n" % name).encode("ascii"),
+ data,
+ b"};",
+ ]
+ )
+
+ def frombytes(self, data, decoder_name="raw", *args):
+ """
+ Loads this image with pixel data from a bytes object.
+
+ This method is similar to the :py:func:`~PIL.Image.frombytes` function,
+ but loads data into this image instead of creating a new image object.
+ """
+
+ # may pass tuple instead of argument list
+ if len(args) == 1 and isinstance(args[0], tuple):
+ args = args[0]
+
+ # default format
+ if decoder_name == "raw" and args == ():
+ args = self.mode
+
+ # unpack data
+ d = _getdecoder(self.mode, decoder_name, args)
+ d.setimage(self.im)
+ s = d.decode(data)
+
+ if s[0] >= 0:
+ raise ValueError("not enough image data")
+ if s[1] != 0:
+ raise ValueError("cannot decode image data")
+
+ def fromstring(self, *args, **kw):
+ raise NotImplementedError(
+ "fromstring() has been removed. Please call frombytes() instead."
+ )
+
+ def load(self):
+ """
+ Allocates storage for the image and loads the pixel data. In
+ normal cases, you don't need to call this method, since the
+ Image class automatically loads an opened image when it is
+ accessed for the first time.
+
+ If the file associated with the image was opened by Pillow, then this
+ method will close it. The exception to this is if the image has
+ multiple frames, in which case the file will be left open for seek
+ operations. See :ref:`file-handling` for more information.
+
+ :returns: An image access object.
+ :rtype: :ref:`PixelAccess` or :py:class:`PIL.PyAccess`
+ """
+ if self.im and self.palette and self.palette.dirty:
+ # realize palette
+ self.im.putpalette(*self.palette.getdata())
+ self.palette.dirty = 0
+ self.palette.mode = "RGB"
+ self.palette.rawmode = None
+ if "transparency" in self.info:
+ if isinstance(self.info["transparency"], int):
+ self.im.putpalettealpha(self.info["transparency"], 0)
+ else:
+ self.im.putpalettealphas(self.info["transparency"])
+ self.palette.mode = "RGBA"
+
+ if self.im:
+ if cffi and USE_CFFI_ACCESS:
+ if self.pyaccess:
+ return self.pyaccess
+ from . import PyAccess
+
+ self.pyaccess = PyAccess.new(self, self.readonly)
+ if self.pyaccess:
+ return self.pyaccess
+ return self.im.pixel_access(self.readonly)
+
+ def verify(self):
+ """
+ Verifies the contents of a file. For data read from a file, this
+ method attempts to determine if the file is broken, without
+ actually decoding the image data. If this method finds any
+ problems, it raises suitable exceptions. If you need to load
+ the image after using this method, you must reopen the image
+ file.
+ """
+ pass
+
+ def convert(self, mode=None, matrix=None, dither=None, palette=WEB, colors=256):
+ """
+ Returns a converted copy of this image. For the "P" mode, this
+ method translates pixels through the palette. If mode is
+ omitted, a mode is chosen so that all information in the image
+ and the palette can be represented without a palette.
+
+ The current version supports all possible conversions between
+ "L", "RGB" and "CMYK." The **matrix** argument only supports "L"
+ and "RGB".
+
+ When translating a color image to greyscale (mode "L"),
+ the library uses the ITU-R 601-2 luma transform::
+
+ L = R * 299/1000 + G * 587/1000 + B * 114/1000
+
+ The default method of converting a greyscale ("L") or "RGB"
+ image into a bilevel (mode "1") image uses Floyd-Steinberg
+ dither to approximate the original image luminosity levels. If
+ dither is NONE, all values larger than 128 are set to 255 (white),
+ all other values to 0 (black). To use other thresholds, use the
+ :py:meth:`~PIL.Image.Image.point` method.
+
+ When converting from "RGBA" to "P" without a **matrix** argument,
+ this passes the operation to :py:meth:`~PIL.Image.Image.quantize`,
+ and **dither** and **palette** are ignored.
+
+ :param mode: The requested mode. See: :ref:`concept-modes`.
+ :param matrix: An optional conversion matrix. If given, this
+ should be 4- or 12-tuple containing floating point values.
+ :param dither: Dithering method, used when converting from
+ mode "RGB" to "P" or from "RGB" or "L" to "1".
+ Available methods are NONE or FLOYDSTEINBERG (default).
+ Note that this is not used when **matrix** is supplied.
+ :param palette: Palette to use when converting from mode "RGB"
+ to "P". Available palettes are WEB or ADAPTIVE.
+ :param colors: Number of colors to use for the ADAPTIVE palette.
+ Defaults to 256.
+ :rtype: :py:class:`~PIL.Image.Image`
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ self.load()
+
+ if not mode and self.mode == "P":
+ # determine default mode
+ if self.palette:
+ mode = self.palette.mode
+ else:
+ mode = "RGB"
+ if not mode or (mode == self.mode and not matrix):
+ return self.copy()
+
+ has_transparency = self.info.get("transparency") is not None
+ if matrix:
+ # matrix conversion
+ if mode not in ("L", "RGB"):
+ raise ValueError("illegal conversion")
+ im = self.im.convert_matrix(mode, matrix)
+ new = self._new(im)
+ if has_transparency and self.im.bands == 3:
+ transparency = new.info["transparency"]
+
+ def convert_transparency(m, v):
+ v = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * 0.5
+ return max(0, min(255, int(v)))
+
+ if mode == "L":
+ transparency = convert_transparency(matrix, transparency)
+ elif len(mode) == 3:
+ transparency = tuple(
+ [
+ convert_transparency(
+ matrix[i * 4 : i * 4 + 4], transparency
+ )
+ for i in range(0, len(transparency))
+ ]
+ )
+ new.info["transparency"] = transparency
+ return new
+
+ if mode == "P" and self.mode == "RGBA":
+ return self.quantize(colors)
+
+ trns = None
+ delete_trns = False
+ # transparency handling
+ if has_transparency:
+ if self.mode in ("1", "L", "I", "RGB") and mode == "RGBA":
+ # Use transparent conversion to promote from transparent
+ # color to an alpha channel.
+ new_im = self._new(
+ self.im.convert_transparent(mode, self.info["transparency"])
+ )
+ del new_im.info["transparency"]
+ return new_im
+ elif self.mode in ("L", "RGB", "P") and mode in ("L", "RGB", "P"):
+ t = self.info["transparency"]
+ if isinstance(t, bytes):
+ # Dragons. This can't be represented by a single color
+ warnings.warn(
+ "Palette images with Transparency expressed in bytes should be "
+ "converted to RGBA images"
+ )
+ delete_trns = True
+ else:
+ # get the new transparency color.
+ # use existing conversions
+ trns_im = Image()._new(core.new(self.mode, (1, 1)))
+ if self.mode == "P":
+ trns_im.putpalette(self.palette)
+ if isinstance(t, tuple):
+ try:
+ t = trns_im.palette.getcolor(t)
+ except Exception:
+ raise ValueError(
+ "Couldn't allocate a palette color for transparency"
+ )
+ trns_im.putpixel((0, 0), t)
+
+ if mode in ("L", "RGB"):
+ trns_im = trns_im.convert(mode)
+ else:
+ # can't just retrieve the palette number, got to do it
+ # after quantization.
+ trns_im = trns_im.convert("RGB")
+ trns = trns_im.getpixel((0, 0))
+
+ elif self.mode == "P" and mode == "RGBA":
+ t = self.info["transparency"]
+ delete_trns = True
+
+ if isinstance(t, bytes):
+ self.im.putpalettealphas(t)
+ elif isinstance(t, int):
+ self.im.putpalettealpha(t, 0)
+ else:
+ raise ValueError("Transparency for P mode should be bytes or int")
+
+ if mode == "P" and palette == ADAPTIVE:
+ im = self.im.quantize(colors)
+ new = self._new(im)
+ from . import ImagePalette
+
+ new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB"))
+ if delete_trns:
+ # This could possibly happen if we requantize to fewer colors.
+ # The transparency would be totally off in that case.
+ del new.info["transparency"]
+ if trns is not None:
+ try:
+ new.info["transparency"] = new.palette.getcolor(trns)
+ except Exception:
+ # if we can't make a transparent color, don't leave the old
+ # transparency hanging around to mess us up.
+ del new.info["transparency"]
+ warnings.warn("Couldn't allocate palette entry for transparency")
+ return new
+
+ # colorspace conversion
+ if dither is None:
+ dither = FLOYDSTEINBERG
+
+ try:
+ im = self.im.convert(mode, dither)
+ except ValueError:
+ try:
+ # normalize source image and try again
+ im = self.im.convert(getmodebase(self.mode))
+ im = im.convert(mode, dither)
+ except KeyError:
+ raise ValueError("illegal conversion")
+
+ new_im = self._new(im)
+ if delete_trns:
+ # crash fail if we leave a bytes transparency in an rgb/l mode.
+ del new_im.info["transparency"]
+ if trns is not None:
+ if new_im.mode == "P":
+ try:
+ new_im.info["transparency"] = new_im.palette.getcolor(trns)
+ except Exception:
+ del new_im.info["transparency"]
+ warnings.warn("Couldn't allocate palette entry for transparency")
+ else:
+ new_im.info["transparency"] = trns
+ return new_im
+
+ def quantize(self, colors=256, method=None, kmeans=0, palette=None, dither=1):
+ """
+ Convert the image to 'P' mode with the specified number
+ of colors.
+
+ :param colors: The desired number of colors, <= 256
+ :param method: 0 = median cut
+ 1 = maximum coverage
+ 2 = fast octree
+ 3 = libimagequant
+ :param kmeans: Integer
+ :param palette: Quantize to the palette of given
+ :py:class:`PIL.Image.Image`.
+ :param dither: Dithering method, used when converting from
+ mode "RGB" to "P" or from "RGB" or "L" to "1".
+ Available methods are NONE or FLOYDSTEINBERG (default).
+ Default: 1 (legacy setting)
+ :returns: A new image
+
+ """
+
+ self.load()
+
+ if method is None:
+ # defaults:
+ method = 0
+ if self.mode == "RGBA":
+ method = 2
+
+ if self.mode == "RGBA" and method not in (2, 3):
+ # Caller specified an invalid mode.
+ raise ValueError(
+ "Fast Octree (method == 2) and libimagequant (method == 3) "
+ "are the only valid methods for quantizing RGBA images"
+ )
+
+ if palette:
+ # use palette from reference image
+ palette.load()
+ if palette.mode != "P":
+ raise ValueError("bad mode for palette image")
+ if self.mode != "RGB" and self.mode != "L":
+ raise ValueError(
+ "only RGB or L mode images can be quantized to a palette"
+ )
+ im = self.im.convert("P", dither, palette.im)
+ return self._new(im)
+
+ im = self._new(self.im.quantize(colors, method, kmeans))
+
+ from . import ImagePalette
+
+ mode = im.im.getpalettemode()
+ im.palette = ImagePalette.ImagePalette(mode, im.im.getpalette(mode, mode))
+
+ return im
+
+ def copy(self):
+ """
+ Copies this image. Use this method if you wish to paste things
+ into an image, but still retain the original.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+ self.load()
+ return self._new(self.im.copy())
+
+ __copy__ = copy
+
+ def crop(self, box=None):
+ """
+ Returns a rectangular region from this image. The box is a
+ 4-tuple defining the left, upper, right, and lower pixel
+ coordinate. See :ref:`coordinate-system`.
+
+ Note: Prior to Pillow 3.4.0, this was a lazy operation.
+
+ :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
+ :rtype: :py:class:`~PIL.Image.Image`
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ if box is None:
+ return self.copy()
+
+ self.load()
+ return self._new(self._crop(self.im, box))
+
+ def _crop(self, im, box):
+ """
+ Returns a rectangular region from the core image object im.
+
+ This is equivalent to calling im.crop((x0, y0, x1, y1)), but
+ includes additional sanity checks.
+
+ :param im: a core image object
+ :param box: The crop rectangle, as a (left, upper, right, lower)-tuple.
+ :returns: A core image object.
+ """
+
+ x0, y0, x1, y1 = map(int, map(round, box))
+
+ absolute_values = (abs(x1 - x0), abs(y1 - y0))
+
+ _decompression_bomb_check(absolute_values)
+
+ return im.crop((x0, y0, x1, y1))
+
+ def draft(self, mode, size):
+ """
+ Configures the image file loader so it returns a version of the
+ image that as closely as possible matches the given mode and
+ size. For example, you can use this method to convert a color
+ JPEG to greyscale while loading it, or to extract a 128x192
+ version from a PCD file.
+
+ Note that this method modifies the :py:class:`~PIL.Image.Image` object
+ in place. If the image has already been loaded, this method has no
+ effect.
+
+ Note: This method is not implemented for most images. It is
+ currently implemented only for JPEG and PCD images.
+
+ :param mode: The requested mode.
+ :param size: The requested size.
+ """
+ pass
+
+ def _expand(self, xmargin, ymargin=None):
+ if ymargin is None:
+ ymargin = xmargin
+ self.load()
+ return self._new(self.im.expand(xmargin, ymargin, 0))
+
+ def filter(self, filter):
+ """
+ Filters this image using the given filter. For a list of
+ available filters, see the :py:mod:`~PIL.ImageFilter` module.
+
+ :param filter: Filter kernel.
+ :returns: An :py:class:`~PIL.Image.Image` object. """
+
+ from . import ImageFilter
+
+ self.load()
+
+ if isinstance(filter, Callable):
+ filter = filter()
+ if not hasattr(filter, "filter"):
+ raise TypeError(
+ "filter argument should be ImageFilter.Filter instance or class"
+ )
+
+ multiband = isinstance(filter, ImageFilter.MultibandFilter)
+ if self.im.bands == 1 or multiband:
+ return self._new(filter.filter(self.im))
+
+ ims = []
+ for c in range(self.im.bands):
+ ims.append(self._new(filter.filter(self.im.getband(c))))
+ return merge(self.mode, ims)
+
+ def getbands(self):
+ """
+ Returns a tuple containing the name of each band in this image.
+ For example, **getbands** on an RGB image returns ("R", "G", "B").
+
+ :returns: A tuple containing band names.
+ :rtype: tuple
+ """
+ return ImageMode.getmode(self.mode).bands
+
+ def getbbox(self):
+ """
+ Calculates the bounding box of the non-zero regions in the
+ image.
+
+ :returns: The bounding box is returned as a 4-tuple defining the
+ left, upper, right, and lower pixel coordinate. See
+ :ref:`coordinate-system`. If the image is completely empty, this
+ method returns None.
+
+ """
+
+ self.load()
+ return self.im.getbbox()
+
+ def getcolors(self, maxcolors=256):
+ """
+ Returns a list of colors used in this image.
+
+ :param maxcolors: Maximum number of colors. If this number is
+ exceeded, this method returns None. The default limit is
+ 256 colors.
+ :returns: An unsorted list of (count, pixel) values.
+ """
+
+ self.load()
+ if self.mode in ("1", "L", "P"):
+ h = self.im.histogram()
+ out = []
+ for i in range(256):
+ if h[i]:
+ out.append((h[i], i))
+ if len(out) > maxcolors:
+ return None
+ return out
+ return self.im.getcolors(maxcolors)
+
+ def getdata(self, band=None):
+ """
+ Returns the contents of this image as a sequence object
+ containing pixel values. The sequence object is flattened, so
+ that values for line one follow directly after the values of
+ line zero, and so on.
+
+ Note that the sequence object returned by this method is an
+ internal PIL data type, which only supports certain sequence
+ operations. To convert it to an ordinary sequence (e.g. for
+ printing), use **list(im.getdata())**.
+
+ :param band: What band to return. The default is to return
+ all bands. To return a single band, pass in the index
+ value (e.g. 0 to get the "R" band from an "RGB" image).
+ :returns: A sequence-like object.
+ """
+
+ self.load()
+ if band is not None:
+ return self.im.getband(band)
+ return self.im # could be abused
+
+ def getextrema(self):
+ """
+ Gets the the minimum and maximum pixel values for each band in
+ the image.
+
+ :returns: For a single-band image, a 2-tuple containing the
+ minimum and maximum pixel value. For a multi-band image,
+ a tuple containing one 2-tuple for each band.
+ """
+
+ self.load()
+ if self.im.bands > 1:
+ extrema = []
+ for i in range(self.im.bands):
+ extrema.append(self.im.getband(i).getextrema())
+ return tuple(extrema)
+ return self.im.getextrema()
+
+ def getexif(self):
+ if self._exif is None:
+ self._exif = Exif()
+ self._exif.load(self.info.get("exif"))
+ return self._exif
+
+ def getim(self):
+ """
+ Returns a capsule that points to the internal image memory.
+
+ :returns: A capsule object.
+ """
+
+ self.load()
+ return self.im.ptr
+
+ def getpalette(self):
+ """
+ Returns the image palette as a list.
+
+ :returns: A list of color values [r, g, b, ...], or None if the
+ image has no palette.
+ """
+
+ self.load()
+ try:
+ if py3:
+ return list(self.im.getpalette())
+ else:
+ return [i8(c) for c in self.im.getpalette()]
+ except ValueError:
+ return None # no palette
+
+ def getpixel(self, xy):
+ """
+ Returns the pixel value at a given position.
+
+ :param xy: The coordinate, given as (x, y). See
+ :ref:`coordinate-system`.
+ :returns: The pixel value. If the image is a multi-layer image,
+ this method returns a tuple.
+ """
+
+ self.load()
+ if self.pyaccess:
+ return self.pyaccess.getpixel(xy)
+ return self.im.getpixel(xy)
+
+ def getprojection(self):
+ """
+ Get projection to x and y axes
+
+ :returns: Two sequences, indicating where there are non-zero
+ pixels along the X-axis and the Y-axis, respectively.
+ """
+
+ self.load()
+ x, y = self.im.getprojection()
+ return [i8(c) for c in x], [i8(c) for c in y]
+
+ def histogram(self, mask=None, extrema=None):
+ """
+ Returns a histogram for the image. The histogram is returned as
+ a list of pixel counts, one for each pixel value in the source
+ image. If the image has more than one band, the histograms for
+ all bands are concatenated (for example, the histogram for an
+ "RGB" image contains 768 values).
+
+ A bilevel image (mode "1") is treated as a greyscale ("L") image
+ by this method.
+
+ If a mask is provided, the method returns a histogram for those
+ parts of the image where the mask image is non-zero. The mask
+ image must have the same size as the image, and be either a
+ bi-level image (mode "1") or a greyscale image ("L").
+
+ :param mask: An optional mask.
+ :param extrema: An optional tuple of manually-specified extrema.
+ :returns: A list containing pixel counts.
+ """
+ self.load()
+ if mask:
+ mask.load()
+ return self.im.histogram((0, 0), mask.im)
+ if self.mode in ("I", "F"):
+ if extrema is None:
+ extrema = self.getextrema()
+ return self.im.histogram(extrema)
+ return self.im.histogram()
+
+ def entropy(self, mask=None, extrema=None):
+ """
+ Calculates and returns the entropy for the image.
+
+ A bilevel image (mode "1") is treated as a greyscale ("L")
+ image by this method.
+
+ If a mask is provided, the method employs the histogram for
+ those parts of the image where the mask image is non-zero.
+ The mask image must have the same size as the image, and be
+ either a bi-level image (mode "1") or a greyscale image ("L").
+
+ :param mask: An optional mask.
+ :param extrema: An optional tuple of manually-specified extrema.
+ :returns: A float value representing the image entropy
+ """
+ self.load()
+ if mask:
+ mask.load()
+ return self.im.entropy((0, 0), mask.im)
+ if self.mode in ("I", "F"):
+ if extrema is None:
+ extrema = self.getextrema()
+ return self.im.entropy(extrema)
+ return self.im.entropy()
+
+ def offset(self, xoffset, yoffset=None):
+ raise NotImplementedError(
+ "offset() has been removed. Please call ImageChops.offset() instead."
+ )
+
+ def paste(self, im, box=None, mask=None):
+ """
+ Pastes another image into this image. The box argument is either
+ a 2-tuple giving the upper left corner, a 4-tuple defining the
+ left, upper, right, and lower pixel coordinate, or None (same as
+ (0, 0)). See :ref:`coordinate-system`. If a 4-tuple is given, the size
+ of the pasted image must match the size of the region.
+
+ If the modes don't match, the pasted image is converted to the mode of
+ this image (see the :py:meth:`~PIL.Image.Image.convert` method for
+ details).
+
+ Instead of an image, the source can be a integer or tuple
+ containing pixel values. The method then fills the region
+ with the given color. When creating RGB images, you can
+ also use color strings as supported by the ImageColor module.
+
+ If a mask is given, this method updates only the regions
+ indicated by the mask. You can use either "1", "L" or "RGBA"
+ images (in the latter case, the alpha band is used as mask).
+ Where the mask is 255, the given image is copied as is. Where
+ the mask is 0, the current value is preserved. Intermediate
+ values will mix the two images together, including their alpha
+ channels if they have them.
+
+ See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to
+ combine images with respect to their alpha channels.
+
+ :param im: Source image or pixel value (integer or tuple).
+ :param box: An optional 4-tuple giving the region to paste into.
+ If a 2-tuple is used instead, it's treated as the upper left
+ corner. If omitted or None, the source is pasted into the
+ upper left corner.
+
+ If an image is given as the second argument and there is no
+ third, the box defaults to (0, 0), and the second argument
+ is interpreted as a mask image.
+ :param mask: An optional mask image.
+ """
+
+ if isImageType(box) and mask is None:
+ # abbreviated paste(im, mask) syntax
+ mask = box
+ box = None
+
+ if box is None:
+ box = (0, 0)
+
+ if len(box) == 2:
+ # upper left corner given; get size from image or mask
+ if isImageType(im):
+ size = im.size
+ elif isImageType(mask):
+ size = mask.size
+ else:
+ # FIXME: use self.size here?
+ raise ValueError("cannot determine region size; use 4-item box")
+ box += (box[0] + size[0], box[1] + size[1])
+
+ if isStringType(im):
+ from . import ImageColor
+
+ im = ImageColor.getcolor(im, self.mode)
+
+ elif isImageType(im):
+ im.load()
+ if self.mode != im.mode:
+ if self.mode != "RGB" or im.mode not in ("RGBA", "RGBa"):
+ # should use an adapter for this!
+ im = im.convert(self.mode)
+ im = im.im
+
+ self._ensure_mutable()
+
+ if mask:
+ mask.load()
+ self.im.paste(im, box, mask.im)
+ else:
+ self.im.paste(im, box)
+
+ def alpha_composite(self, im, dest=(0, 0), source=(0, 0)):
+ """ 'In-place' analog of Image.alpha_composite. Composites an image
+ onto this image.
+
+ :param im: image to composite over this one
+ :param dest: Optional 2 tuple (left, top) specifying the upper
+ left corner in this (destination) image.
+ :param source: Optional 2 (left, top) tuple for the upper left
+ corner in the overlay source image, or 4 tuple (left, top, right,
+ bottom) for the bounds of the source rectangle
+
+ Performance Note: Not currently implemented in-place in the core layer.
+ """
+
+ if not isinstance(source, (list, tuple)):
+ raise ValueError("Source must be a tuple")
+ if not isinstance(dest, (list, tuple)):
+ raise ValueError("Destination must be a tuple")
+ if not len(source) in (2, 4):
+ raise ValueError("Source must be a 2 or 4-tuple")
+ if not len(dest) == 2:
+ raise ValueError("Destination must be a 2-tuple")
+ if min(source) < 0:
+ raise ValueError("Source must be non-negative")
+ if min(dest) < 0:
+ raise ValueError("Destination must be non-negative")
+
+ if len(source) == 2:
+ source = source + im.size
+
+ # over image, crop if it's not the whole thing.
+ if source == (0, 0) + im.size:
+ overlay = im
+ else:
+ overlay = im.crop(source)
+
+ # target for the paste
+ box = dest + (dest[0] + overlay.width, dest[1] + overlay.height)
+
+ # destination image. don't copy if we're using the whole image.
+ if box == (0, 0) + self.size:
+ background = self
+ else:
+ background = self.crop(box)
+
+ result = alpha_composite(background, overlay)
+ self.paste(result, box)
+
+ def point(self, lut, mode=None):
+ """
+ Maps this image through a lookup table or function.
+
+ :param lut: A lookup table, containing 256 (or 65536 if
+ self.mode=="I" and mode == "L") values per band in the
+ image. A function can be used instead, it should take a
+ single argument. The function is called once for each
+ possible pixel value, and the resulting table is applied to
+ all bands of the image.
+ :param mode: Output mode (default is same as input). In the
+ current version, this can only be used if the source image
+ has mode "L" or "P", and the output has mode "1" or the
+ source image mode is "I" and the output mode is "L".
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ self.load()
+
+ if isinstance(lut, ImagePointHandler):
+ return lut.point(self)
+
+ if callable(lut):
+ # if it isn't a list, it should be a function
+ if self.mode in ("I", "I;16", "F"):
+ # check if the function can be used with point_transform
+ # UNDONE wiredfool -- I think this prevents us from ever doing
+ # a gamma function point transform on > 8bit images.
+ scale, offset = _getscaleoffset(lut)
+ return self._new(self.im.point_transform(scale, offset))
+ # for other modes, convert the function to a table
+ lut = [lut(i) for i in range(256)] * self.im.bands
+
+ if self.mode == "F":
+ # FIXME: _imaging returns a confusing error message for this case
+ raise ValueError("point operation not supported for this mode")
+
+ return self._new(self.im.point(lut, mode))
+
+ def putalpha(self, alpha):
+ """
+ Adds or replaces the alpha layer in this image. If the image
+ does not have an alpha layer, it's converted to "LA" or "RGBA".
+ The new layer must be either "L" or "1".
+
+ :param alpha: The new alpha layer. This can either be an "L" or "1"
+ image having the same size as this image, or an integer or
+ other color value.
+ """
+
+ self._ensure_mutable()
+
+ if self.mode not in ("LA", "PA", "RGBA"):
+ # attempt to promote self to a matching alpha mode
+ try:
+ mode = getmodebase(self.mode) + "A"
+ try:
+ self.im.setmode(mode)
+ except (AttributeError, ValueError):
+ # do things the hard way
+ im = self.im.convert(mode)
+ if im.mode not in ("LA", "PA", "RGBA"):
+ raise ValueError # sanity check
+ self.im = im
+ self.pyaccess = None
+ self.mode = self.im.mode
+ except (KeyError, ValueError):
+ raise ValueError("illegal image mode")
+
+ if self.mode in ("LA", "PA"):
+ band = 1
+ else:
+ band = 3
+
+ if isImageType(alpha):
+ # alpha layer
+ if alpha.mode not in ("1", "L"):
+ raise ValueError("illegal image mode")
+ alpha.load()
+ if alpha.mode == "1":
+ alpha = alpha.convert("L")
+ else:
+ # constant alpha
+ try:
+ self.im.fillband(band, alpha)
+ except (AttributeError, ValueError):
+ # do things the hard way
+ alpha = new("L", self.size, alpha)
+ else:
+ return
+
+ self.im.putband(alpha.im, band)
+
+ def putdata(self, data, scale=1.0, offset=0.0):
+ """
+ Copies pixel data to this image. This method copies data from a
+ sequence object into the image, starting at the upper left
+ corner (0, 0), and continuing until either the image or the
+ sequence ends. The scale and offset values are used to adjust
+ the sequence values: **pixel = value*scale + offset**.
+
+ :param data: A sequence object.
+ :param scale: An optional scale value. The default is 1.0.
+ :param offset: An optional offset value. The default is 0.0.
+ """
+
+ self._ensure_mutable()
+
+ self.im.putdata(data, scale, offset)
+
+ def putpalette(self, data, rawmode="RGB"):
+ """
+ Attaches a palette to this image. The image must be a "P",
+ "PA", "L" or "LA" image, and the palette sequence must contain
+ 768 integer values, where each group of three values represent
+ the red, green, and blue values for the corresponding pixel
+ index. Instead of an integer sequence, you can use an 8-bit
+ string.
+
+ :param data: A palette sequence (either a list or a string).
+ :param rawmode: The raw mode of the palette.
+ """
+ from . import ImagePalette
+
+ if self.mode not in ("L", "LA", "P", "PA"):
+ raise ValueError("illegal image mode")
+ self.load()
+ if isinstance(data, ImagePalette.ImagePalette):
+ palette = ImagePalette.raw(data.rawmode, data.palette)
+ else:
+ if not isinstance(data, bytes):
+ if py3:
+ data = bytes(data)
+ else:
+ data = "".join(chr(x) for x in data)
+ palette = ImagePalette.raw(rawmode, data)
+ self.mode = "PA" if "A" in self.mode else "P"
+ self.palette = palette
+ self.palette.mode = "RGB"
+ self.load() # install new palette
+
+ def putpixel(self, xy, value):
+ """
+ Modifies the pixel at the given position. The color is given as
+ a single numerical value for single-band images, and a tuple for
+ multi-band images. In addition to this, RGB and RGBA tuples are
+ accepted for P images.
+
+ Note that this method is relatively slow. For more extensive changes,
+ use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw`
+ module instead.
+
+ See:
+
+ * :py:meth:`~PIL.Image.Image.paste`
+ * :py:meth:`~PIL.Image.Image.putdata`
+ * :py:mod:`~PIL.ImageDraw`
+
+ :param xy: The pixel coordinate, given as (x, y). See
+ :ref:`coordinate-system`.
+ :param value: The pixel value.
+ """
+
+ if self.readonly:
+ self._copy()
+ self.load()
+
+ if self.pyaccess:
+ return self.pyaccess.putpixel(xy, value)
+
+ if (
+ self.mode == "P"
+ and isinstance(value, (list, tuple))
+ and len(value) in [3, 4]
+ ):
+ # RGB or RGBA value for a P image
+ value = self.palette.getcolor(value)
+ return self.im.putpixel(xy, value)
+
+ def remap_palette(self, dest_map, source_palette=None):
+ """
+ Rewrites the image to reorder the palette.
+
+ :param dest_map: A list of indexes into the original palette.
+ e.g. [1,0] would swap a two item palette, and list(range(256))
+ is the identity transform.
+ :param source_palette: Bytes or None.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+
+ """
+ from . import ImagePalette
+
+ if self.mode not in ("L", "P"):
+ raise ValueError("illegal image mode")
+
+ if source_palette is None:
+ if self.mode == "P":
+ real_source_palette = self.im.getpalette("RGB")[:768]
+ else: # L-mode
+ real_source_palette = bytearray(i // 3 for i in range(768))
+ else:
+ real_source_palette = source_palette
+
+ palette_bytes = b""
+ new_positions = [0] * 256
+
+ # pick only the used colors from the palette
+ for i, oldPosition in enumerate(dest_map):
+ palette_bytes += real_source_palette[oldPosition * 3 : oldPosition * 3 + 3]
+ new_positions[oldPosition] = i
+
+ # replace the palette color id of all pixel with the new id
+
+ # Palette images are [0..255], mapped through a 1 or 3
+ # byte/color map. We need to remap the whole image
+ # from palette 1 to palette 2. New_positions is
+ # an array of indexes into palette 1. Palette 2 is
+ # palette 1 with any holes removed.
+
+ # We're going to leverage the convert mechanism to use the
+ # C code to remap the image from palette 1 to palette 2,
+ # by forcing the source image into 'L' mode and adding a
+ # mapping 'L' mode palette, then converting back to 'L'
+ # sans palette thus converting the image bytes, then
+ # assigning the optimized RGB palette.
+
+ # perf reference, 9500x4000 gif, w/~135 colors
+ # 14 sec prepatch, 1 sec postpatch with optimization forced.
+
+ mapping_palette = bytearray(new_positions)
+
+ m_im = self.copy()
+ m_im.mode = "P"
+
+ m_im.palette = ImagePalette.ImagePalette(
+ "RGB", palette=mapping_palette * 3, size=768
+ )
+ # possibly set palette dirty, then
+ # m_im.putpalette(mapping_palette, 'L') # converts to 'P'
+ # or just force it.
+ # UNDONE -- this is part of the general issue with palettes
+ m_im.im.putpalette(*m_im.palette.getdata())
+
+ m_im = m_im.convert("L")
+
+ # Internally, we require 768 bytes for a palette.
+ new_palette_bytes = palette_bytes + (768 - len(palette_bytes)) * b"\x00"
+ m_im.putpalette(new_palette_bytes)
+ m_im.palette = ImagePalette.ImagePalette(
+ "RGB", palette=palette_bytes, size=len(palette_bytes)
+ )
+
+ return m_im
+
+ def resize(self, size, resample=NEAREST, box=None):
+ """
+ Returns a resized copy of this image.
+
+ :param size: The requested size in pixels, as a 2-tuple:
+ (width, height).
+ :param resample: An optional resampling filter. This can be
+ one of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BOX`,
+ :py:attr:`PIL.Image.BILINEAR`, :py:attr:`PIL.Image.HAMMING`,
+ :py:attr:`PIL.Image.BICUBIC` or :py:attr:`PIL.Image.LANCZOS`.
+ If omitted, or if the image has mode "1" or "P", it is
+ set :py:attr:`PIL.Image.NEAREST`.
+ See: :ref:`concept-filters`.
+ :param box: An optional 4-tuple of floats giving the region
+ of the source image which should be scaled.
+ The values should be within (0, 0, width, height) rectangle.
+ If omitted or None, the entire source is used.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ if resample not in (NEAREST, BILINEAR, BICUBIC, LANCZOS, BOX, HAMMING):
+ message = "Unknown resampling filter ({}).".format(resample)
+
+ filters = [
+ "{} ({})".format(filter[1], filter[0])
+ for filter in (
+ (NEAREST, "Image.NEAREST"),
+ (LANCZOS, "Image.LANCZOS"),
+ (BILINEAR, "Image.BILINEAR"),
+ (BICUBIC, "Image.BICUBIC"),
+ (BOX, "Image.BOX"),
+ (HAMMING, "Image.HAMMING"),
+ )
+ ]
+ raise ValueError(
+ message + " Use " + ", ".join(filters[:-1]) + " or " + filters[-1]
+ )
+
+ size = tuple(size)
+
+ if box is None:
+ box = (0, 0) + self.size
+ else:
+ box = tuple(box)
+
+ if self.size == size and box == (0, 0) + self.size:
+ return self.copy()
+
+ if self.mode in ("1", "P"):
+ resample = NEAREST
+
+ if self.mode in ["LA", "RGBA"]:
+ im = self.convert(self.mode[:-1] + "a")
+ im = im.resize(size, resample, box)
+ return im.convert(self.mode)
+
+ self.load()
+
+ return self._new(self.im.resize(size, resample, box))
+
+ def rotate(
+ self,
+ angle,
+ resample=NEAREST,
+ expand=0,
+ center=None,
+ translate=None,
+ fillcolor=None,
+ ):
+ """
+ Returns a rotated copy of this image. This method returns a
+ copy of this image, rotated the given number of degrees counter
+ clockwise around its centre.
+
+ :param angle: In degrees counter clockwise.
+ :param resample: An optional resampling filter. This can be
+ one of :py:attr:`PIL.Image.NEAREST` (use nearest neighbour),
+ :py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2
+ environment), or :py:attr:`PIL.Image.BICUBIC`
+ (cubic spline interpolation in a 4x4 environment).
+ If omitted, or if the image has mode "1" or "P", it is
+ set :py:attr:`PIL.Image.NEAREST`. See :ref:`concept-filters`.
+ :param expand: Optional expansion flag. If true, expands the output
+ image to make it large enough to hold the entire rotated image.
+ If false or omitted, make the output image the same size as the
+ input image. Note that the expand flag assumes rotation around
+ the center and no translation.
+ :param center: Optional center of rotation (a 2-tuple). Origin is
+ the upper left corner. Default is the center of the image.
+ :param translate: An optional post-rotate translation (a 2-tuple).
+ :param fillcolor: An optional color for area outside the rotated image.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ angle = angle % 360.0
+
+ # Fast paths regardless of filter, as long as we're not
+ # translating or changing the center.
+ if not (center or translate):
+ if angle == 0:
+ return self.copy()
+ if angle == 180:
+ return self.transpose(ROTATE_180)
+ if angle == 90 and expand:
+ return self.transpose(ROTATE_90)
+ if angle == 270 and expand:
+ return self.transpose(ROTATE_270)
+
+ # Calculate the affine matrix. Note that this is the reverse
+ # transformation (from destination image to source) because we
+ # want to interpolate the (discrete) destination pixel from
+ # the local area around the (floating) source pixel.
+
+ # The matrix we actually want (note that it operates from the right):
+ # (1, 0, tx) (1, 0, cx) ( cos a, sin a, 0) (1, 0, -cx)
+ # (0, 1, ty) * (0, 1, cy) * (-sin a, cos a, 0) * (0, 1, -cy)
+ # (0, 0, 1) (0, 0, 1) ( 0, 0, 1) (0, 0, 1)
+
+ # The reverse matrix is thus:
+ # (1, 0, cx) ( cos -a, sin -a, 0) (1, 0, -cx) (1, 0, -tx)
+ # (0, 1, cy) * (-sin -a, cos -a, 0) * (0, 1, -cy) * (0, 1, -ty)
+ # (0, 0, 1) ( 0, 0, 1) (0, 0, 1) (0, 0, 1)
+
+ # In any case, the final translation may be updated at the end to
+ # compensate for the expand flag.
+
+ w, h = self.size
+
+ if translate is None:
+ post_trans = (0, 0)
+ else:
+ post_trans = translate
+ if center is None:
+ # FIXME These should be rounded to ints?
+ rotn_center = (w / 2.0, h / 2.0)
+ else:
+ rotn_center = center
+
+ angle = -math.radians(angle)
+ matrix = [
+ round(math.cos(angle), 15),
+ round(math.sin(angle), 15),
+ 0.0,
+ round(-math.sin(angle), 15),
+ round(math.cos(angle), 15),
+ 0.0,
+ ]
+
+ def transform(x, y, matrix):
+ (a, b, c, d, e, f) = matrix
+ return a * x + b * y + c, d * x + e * y + f
+
+ matrix[2], matrix[5] = transform(
+ -rotn_center[0] - post_trans[0], -rotn_center[1] - post_trans[1], matrix
+ )
+ matrix[2] += rotn_center[0]
+ matrix[5] += rotn_center[1]
+
+ if expand:
+ # calculate output size
+ xx = []
+ yy = []
+ for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
+ x, y = transform(x, y, matrix)
+ xx.append(x)
+ yy.append(y)
+ nw = int(math.ceil(max(xx)) - math.floor(min(xx)))
+ nh = int(math.ceil(max(yy)) - math.floor(min(yy)))
+
+ # We multiply a translation matrix from the right. Because of its
+ # special form, this is the same as taking the image of the
+ # translation vector as new translation vector.
+ matrix[2], matrix[5] = transform(-(nw - w) / 2.0, -(nh - h) / 2.0, matrix)
+ w, h = nw, nh
+
+ return self.transform((w, h), AFFINE, matrix, resample, fillcolor=fillcolor)
+
+ def save(self, fp, format=None, **params):
+ """
+ Saves this image under the given filename. If no format is
+ specified, the format to use is determined from the filename
+ extension, if possible.
+
+ Keyword options can be used to provide additional instructions
+ to the writer. If a writer doesn't recognise an option, it is
+ silently ignored. The available options are described in the
+ :doc:`image format documentation
+ <../handbook/image-file-formats>` for each writer.
+
+ You can use a file object instead of a filename. In this case,
+ you must always specify the format. The file object must
+ implement the ``seek``, ``tell``, and ``write``
+ methods, and be opened in binary mode.
+
+ :param fp: A filename (string), pathlib.Path object or file object.
+ :param format: Optional format override. If omitted, the
+ format to use is determined from the filename extension.
+ If a file object was used instead of a filename, this
+ parameter should always be used.
+ :param params: Extra parameters to the image writer.
+ :returns: None
+ :exception ValueError: If the output format could not be determined
+ from the file name. Use the format option to solve this.
+ :exception IOError: If the file could not be written. The file
+ may have been created, and may contain partial data.
+ """
+
+ filename = ""
+ open_fp = False
+ if isPath(fp):
+ filename = fp
+ open_fp = True
+ elif HAS_PATHLIB and isinstance(fp, Path):
+ filename = str(fp)
+ open_fp = True
+ if not filename and hasattr(fp, "name") and isPath(fp.name):
+ # only set the name for metadata purposes
+ filename = fp.name
+
+ # may mutate self!
+ self._ensure_mutable()
+
+ save_all = params.pop("save_all", False)
+ self.encoderinfo = params
+ self.encoderconfig = ()
+
+ preinit()
+
+ ext = os.path.splitext(filename)[1].lower()
+
+ if not format:
+ if ext not in EXTENSION:
+ init()
+ try:
+ format = EXTENSION[ext]
+ except KeyError:
+ raise ValueError("unknown file extension: {}".format(ext))
+
+ if format.upper() not in SAVE:
+ init()
+ if save_all:
+ save_handler = SAVE_ALL[format.upper()]
+ else:
+ save_handler = SAVE[format.upper()]
+
+ if open_fp:
+ if params.get("append", False):
+ # Open also for reading ("+"), because TIFF save_all
+ # writer needs to go back and edit the written data.
+ fp = builtins.open(filename, "r+b")
+ else:
+ fp = builtins.open(filename, "w+b")
+
+ try:
+ save_handler(self, fp, filename)
+ finally:
+ # do what we can to clean up
+ if open_fp:
+ fp.close()
+
+ def seek(self, frame):
+ """
+ Seeks to the given frame in this sequence file. If you seek
+ beyond the end of the sequence, the method raises an
+ **EOFError** exception. When a sequence file is opened, the
+ library automatically seeks to frame 0.
+
+ See :py:meth:`~PIL.Image.Image.tell`.
+
+ :param frame: Frame number, starting at 0.
+ :exception EOFError: If the call attempts to seek beyond the end
+ of the sequence.
+ """
+
+ # overridden by file handlers
+ if frame != 0:
+ raise EOFError
+
+ def show(self, title=None, command=None):
+ """
+ Displays this image. This method is mainly intended for
+ debugging purposes.
+
+ The image is first saved to a temporary file. By default, it will be in
+ PNG format.
+
+ On Unix, the image is then opened using the **display**, **eog** or
+ **xv** utility, depending on which one can be found.
+
+ On macOS, the image is opened with the native Preview application.
+
+ On Windows, the image is opened with the standard PNG display utility.
+
+ :param title: Optional title to use for the image window,
+ where possible.
+ :param command: command used to show the image
+ """
+
+ _show(self, title=title, command=command)
+
+ def split(self):
+ """
+ Split this image into individual bands. This method returns a
+ tuple of individual image bands from an image. For example,
+ splitting an "RGB" image creates three new images each
+ containing a copy of one of the original bands (red, green,
+ blue).
+
+ If you need only one band, :py:meth:`~PIL.Image.Image.getchannel`
+ method can be more convenient and faster.
+
+ :returns: A tuple containing bands.
+ """
+
+ self.load()
+ if self.im.bands == 1:
+ ims = [self.copy()]
+ else:
+ ims = map(self._new, self.im.split())
+ return tuple(ims)
+
+ def getchannel(self, channel):
+ """
+ Returns an image containing a single channel of the source image.
+
+ :param channel: What channel to return. Could be index
+ (0 for "R" channel of "RGB") or channel name
+ ("A" for alpha channel of "RGBA").
+ :returns: An image in "L" mode.
+
+ .. versionadded:: 4.3.0
+ """
+ self.load()
+
+ if isStringType(channel):
+ try:
+ channel = self.getbands().index(channel)
+ except ValueError:
+ raise ValueError('The image has no channel "{}"'.format(channel))
+
+ return self._new(self.im.getband(channel))
+
+ def tell(self):
+ """
+ Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
+
+ :returns: Frame number, starting with 0.
+ """
+ return 0
+
+ def thumbnail(self, size, resample=BICUBIC):
+ """
+ Make this image into a thumbnail. This method modifies the
+ image to contain a thumbnail version of itself, no larger than
+ the given size. This method calculates an appropriate thumbnail
+ size to preserve the aspect of the image, calls the
+ :py:meth:`~PIL.Image.Image.draft` method to configure the file reader
+ (where applicable), and finally resizes the image.
+
+ Note that this function modifies the :py:class:`~PIL.Image.Image`
+ object in place. If you need to use the full resolution image as well,
+ apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original
+ image.
+
+ :param size: Requested size.
+ :param resample: Optional resampling filter. This can be one
+ of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`,
+ :py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.LANCZOS`.
+ If omitted, it defaults to :py:attr:`PIL.Image.BICUBIC`.
+ (was :py:attr:`PIL.Image.NEAREST` prior to version 2.5.0)
+ :returns: None
+ """
+
+ # preserve aspect ratio
+ x, y = self.size
+ if x > size[0]:
+ y = int(max(y * size[0] / x, 1))
+ x = int(size[0])
+ if y > size[1]:
+ x = int(max(x * size[1] / y, 1))
+ y = int(size[1])
+ size = x, y
+
+ if size == self.size:
+ return
+
+ self.draft(None, size)
+
+ if self.size != size:
+ im = self.resize(size, resample)
+
+ self.im = im.im
+ self._size = size
+ self.mode = self.im.mode
+
+ self.readonly = 0
+ self.pyaccess = None
+
+ # FIXME: the different transform methods need further explanation
+ # instead of bloating the method docs, add a separate chapter.
+ def transform(
+ self, size, method, data=None, resample=NEAREST, fill=1, fillcolor=None
+ ):
+ """
+ Transforms this image. This method creates a new image with the
+ given size, and the same mode as the original, and copies data
+ to the new image using the given transform.
+
+ :param size: The output size.
+ :param method: The transformation method. This is one of
+ :py:attr:`PIL.Image.EXTENT` (cut out a rectangular subregion),
+ :py:attr:`PIL.Image.AFFINE` (affine transform),
+ :py:attr:`PIL.Image.PERSPECTIVE` (perspective transform),
+ :py:attr:`PIL.Image.QUAD` (map a quadrilateral to a rectangle), or
+ :py:attr:`PIL.Image.MESH` (map a number of source quadrilaterals
+ in one operation).
+
+ It may also be an :py:class:`~PIL.Image.ImageTransformHandler`
+ object::
+ class Example(Image.ImageTransformHandler):
+ def transform(size, method, data, resample, fill=1):
+ # Return result
+
+ It may also be an object with a :py:meth:`~method.getdata` method
+ that returns a tuple supplying new **method** and **data** values::
+ class Example(object):
+ def getdata(self):
+ method = Image.EXTENT
+ data = (0, 0, 100, 100)
+ return method, data
+ :param data: Extra data to the transformation method.
+ :param resample: Optional resampling filter. It can be one of
+ :py:attr:`PIL.Image.NEAREST` (use nearest neighbour),
+ :py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2
+ environment), or :py:attr:`PIL.Image.BICUBIC` (cubic spline
+ interpolation in a 4x4 environment). If omitted, or if the image
+ has mode "1" or "P", it is set to :py:attr:`PIL.Image.NEAREST`.
+ :param fill: If **method** is an
+ :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of
+ the arguments passed to it. Otherwise, it is unused.
+ :param fillcolor: Optional fill color for the area outside the
+ transform in the output image.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ if self.mode == "LA":
+ return (
+ self.convert("La")
+ .transform(size, method, data, resample, fill, fillcolor)
+ .convert("LA")
+ )
+
+ if self.mode == "RGBA":
+ return (
+ self.convert("RGBa")
+ .transform(size, method, data, resample, fill, fillcolor)
+ .convert("RGBA")
+ )
+
+ if isinstance(method, ImageTransformHandler):
+ return method.transform(size, self, resample=resample, fill=fill)
+
+ if hasattr(method, "getdata"):
+ # compatibility w. old-style transform objects
+ method, data = method.getdata()
+
+ if data is None:
+ raise ValueError("missing method data")
+
+ im = new(self.mode, size, fillcolor)
+ if method == MESH:
+ # list of quads
+ for box, quad in data:
+ im.__transformer(box, self, QUAD, quad, resample, fillcolor is None)
+ else:
+ im.__transformer(
+ (0, 0) + size, self, method, data, resample, fillcolor is None
+ )
+
+ return im
+
+ def __transformer(self, box, image, method, data, resample=NEAREST, fill=1):
+ w = box[2] - box[0]
+ h = box[3] - box[1]
+
+ if method == AFFINE:
+ data = data[0:6]
+
+ elif method == EXTENT:
+ # convert extent to an affine transform
+ x0, y0, x1, y1 = data
+ xs = float(x1 - x0) / w
+ ys = float(y1 - y0) / h
+ method = AFFINE
+ data = (xs, 0, x0, 0, ys, y0)
+
+ elif method == PERSPECTIVE:
+ data = data[0:8]
+
+ elif method == QUAD:
+ # quadrilateral warp. data specifies the four corners
+ # given as NW, SW, SE, and NE.
+ nw = data[0:2]
+ sw = data[2:4]
+ se = data[4:6]
+ ne = data[6:8]
+ x0, y0 = nw
+ As = 1.0 / w
+ At = 1.0 / h
+ data = (
+ x0,
+ (ne[0] - x0) * As,
+ (sw[0] - x0) * At,
+ (se[0] - sw[0] - ne[0] + x0) * As * At,
+ y0,
+ (ne[1] - y0) * As,
+ (sw[1] - y0) * At,
+ (se[1] - sw[1] - ne[1] + y0) * As * At,
+ )
+
+ else:
+ raise ValueError("unknown transformation method")
+
+ if resample not in (NEAREST, BILINEAR, BICUBIC):
+ if resample in (BOX, HAMMING, LANCZOS):
+ message = {
+ BOX: "Image.BOX",
+ HAMMING: "Image.HAMMING",
+ LANCZOS: "Image.LANCZOS/Image.ANTIALIAS",
+ }[resample] + " ({}) cannot be used.".format(resample)
+ else:
+ message = "Unknown resampling filter ({}).".format(resample)
+
+ filters = [
+ "{} ({})".format(filter[1], filter[0])
+ for filter in (
+ (NEAREST, "Image.NEAREST"),
+ (BILINEAR, "Image.BILINEAR"),
+ (BICUBIC, "Image.BICUBIC"),
+ )
+ ]
+ raise ValueError(
+ message + " Use " + ", ".join(filters[:-1]) + " or " + filters[-1]
+ )
+
+ image.load()
+
+ self.load()
+
+ if image.mode in ("1", "P"):
+ resample = NEAREST
+
+ self.im.transform2(box, image.im, method, data, resample, fill)
+
+ def transpose(self, method):
+ """
+ Transpose image (flip or rotate in 90 degree steps)
+
+ :param method: One of :py:attr:`PIL.Image.FLIP_LEFT_RIGHT`,
+ :py:attr:`PIL.Image.FLIP_TOP_BOTTOM`, :py:attr:`PIL.Image.ROTATE_90`,
+ :py:attr:`PIL.Image.ROTATE_180`, :py:attr:`PIL.Image.ROTATE_270`,
+ :py:attr:`PIL.Image.TRANSPOSE` or :py:attr:`PIL.Image.TRANSVERSE`.
+ :returns: Returns a flipped or rotated copy of this image.
+ """
+
+ self.load()
+ return self._new(self.im.transpose(method))
+
+ def effect_spread(self, distance):
+ """
+ Randomly spread pixels in an image.
+
+ :param distance: Distance to spread pixels.
+ """
+ self.load()
+ return self._new(self.im.effect_spread(distance))
+
+ def toqimage(self):
+ """Returns a QImage copy of this image"""
+ from . import ImageQt
+
+ if not ImageQt.qt_is_installed:
+ raise ImportError("Qt bindings are not installed")
+ return ImageQt.toqimage(self)
+
+ def toqpixmap(self):
+ """Returns a QPixmap copy of this image"""
+ from . import ImageQt
+
+ if not ImageQt.qt_is_installed:
+ raise ImportError("Qt bindings are not installed")
+ return ImageQt.toqpixmap(self)
+
+
+# --------------------------------------------------------------------
+# Abstract handlers.
+
+
+class ImagePointHandler(object):
+ # used as a mixin by point transforms (for use with im.point)
+ pass
+
+
+class ImageTransformHandler(object):
+ # used as a mixin by geometry transforms (for use with im.transform)
+ pass
+
+
+# --------------------------------------------------------------------
+# Factories
+
+#
+# Debugging
+
+
+def _wedge():
+ """Create greyscale wedge (for debugging only)"""
+
+ return Image()._new(core.wedge("L"))
+
+
+def _check_size(size):
+ """
+ Common check to enforce type and sanity check on size tuples
+
+ :param size: Should be a 2 tuple of (width, height)
+ :returns: True, or raises a ValueError
+ """
+
+ if not isinstance(size, (list, tuple)):
+ raise ValueError("Size must be a tuple")
+ if len(size) != 2:
+ raise ValueError("Size must be a tuple of length 2")
+ if size[0] < 0 or size[1] < 0:
+ raise ValueError("Width and height must be >= 0")
+
+ return True
+
+
+def new(mode, size, color=0):
+ """
+ Creates a new image with the given mode and size.
+
+ :param mode: The mode to use for the new image. See:
+ :ref:`concept-modes`.
+ :param size: A 2-tuple, containing (width, height) in pixels.
+ :param color: What color to use for the image. Default is black.
+ If given, this should be a single integer or floating point value
+ for single-band modes, and a tuple for multi-band modes (one value
+ per band). When creating RGB images, you can also use color
+ strings as supported by the ImageColor module. If the color is
+ None, the image is not initialised.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ _check_size(size)
+
+ if color is None:
+ # don't initialize
+ return Image()._new(core.new(mode, size))
+
+ if isStringType(color):
+ # css3-style specifier
+
+ from . import ImageColor
+
+ color = ImageColor.getcolor(color, mode)
+
+ im = Image()
+ if mode == "P" and isinstance(color, (list, tuple)) and len(color) in [3, 4]:
+ # RGB or RGBA value for a P image
+ from . import ImagePalette
+
+ im.palette = ImagePalette.ImagePalette()
+ color = im.palette.getcolor(color)
+ return im._new(core.fill(mode, size, color))
+
+
+def frombytes(mode, size, data, decoder_name="raw", *args):
+ """
+ Creates a copy of an image memory from pixel data in a buffer.
+
+ In its simplest form, this function takes three arguments
+ (mode, size, and unpacked pixel data).
+
+ You can also use any pixel decoder supported by PIL. For more
+ information on available decoders, see the section
+ :ref:`Writing Your Own File Decoder <file-decoders>`.
+
+ Note that this function decodes pixel data only, not entire images.
+ If you have an entire image in a string, wrap it in a
+ :py:class:`~io.BytesIO` object, and use :py:func:`~PIL.Image.open` to load
+ it.
+
+ :param mode: The image mode. See: :ref:`concept-modes`.
+ :param size: The image size.
+ :param data: A byte buffer containing raw data for the given mode.
+ :param decoder_name: What decoder to use.
+ :param args: Additional parameters for the given decoder.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ _check_size(size)
+
+ # may pass tuple instead of argument list
+ if len(args) == 1 and isinstance(args[0], tuple):
+ args = args[0]
+
+ if decoder_name == "raw" and args == ():
+ args = mode
+
+ im = new(mode, size)
+ im.frombytes(data, decoder_name, args)
+ return im
+
+
+def fromstring(*args, **kw):
+ raise NotImplementedError(
+ "fromstring() has been removed. Please call frombytes() instead."
+ )
+
+
+def frombuffer(mode, size, data, decoder_name="raw", *args):
+ """
+ Creates an image memory referencing pixel data in a byte buffer.
+
+ This function is similar to :py:func:`~PIL.Image.frombytes`, but uses data
+ in the byte buffer, where possible. This means that changes to the
+ original buffer object are reflected in this image). Not all modes can
+ share memory; supported modes include "L", "RGBX", "RGBA", and "CMYK".
+
+ Note that this function decodes pixel data only, not entire images.
+ If you have an entire image file in a string, wrap it in a
+ **BytesIO** object, and use :py:func:`~PIL.Image.open` to load it.
+
+ In the current version, the default parameters used for the "raw" decoder
+ differs from that used for :py:func:`~PIL.Image.frombytes`. This is a
+ bug, and will probably be fixed in a future release. The current release
+ issues a warning if you do this; to disable the warning, you should provide
+ the full set of parameters. See below for details.
+
+ :param mode: The image mode. See: :ref:`concept-modes`.
+ :param size: The image size.
+ :param data: A bytes or other buffer object containing raw
+ data for the given mode.
+ :param decoder_name: What decoder to use.
+ :param args: Additional parameters for the given decoder. For the
+ default encoder ("raw"), it's recommended that you provide the
+ full set of parameters::
+
+ frombuffer(mode, size, data, "raw", mode, 0, 1)
+
+ :returns: An :py:class:`~PIL.Image.Image` object.
+
+ .. versionadded:: 1.1.4
+ """
+
+ _check_size(size)
+
+ # may pass tuple instead of argument list
+ if len(args) == 1 and isinstance(args[0], tuple):
+ args = args[0]
+
+ if decoder_name == "raw":
+ if args == ():
+ warnings.warn(
+ "the frombuffer defaults will change in Pillow 7.0.0; "
+ "for portability, change the call to read:\n"
+ " frombuffer(mode, size, data, 'raw', mode, 0, 1)",
+ RuntimeWarning,
+ stacklevel=2,
+ )
+ args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6
+ if args[0] in _MAPMODES:
+ im = new(mode, (1, 1))
+ im = im._new(core.map_buffer(data, size, decoder_name, None, 0, args))
+ im.readonly = 1
+ return im
+
+ return frombytes(mode, size, data, decoder_name, args)
+
+
+def fromarray(obj, mode=None):
+ """
+ Creates an image memory from an object exporting the array interface
+ (using the buffer protocol).
+
+ If **obj** is not contiguous, then the tobytes method is called
+ and :py:func:`~PIL.Image.frombuffer` is used.
+
+ If you have an image in NumPy::
+
+ from PIL import Image
+ import numpy as np
+ im = Image.open('hopper.jpg')
+ a = np.asarray(im)
+
+ Then this can be used to convert it to a Pillow image::
+
+ im = Image.fromarray(a)
+
+ :param obj: Object with array interface
+ :param mode: Mode to use (will be determined from type if None)
+ See: :ref:`concept-modes`.
+ :returns: An image object.
+
+ .. versionadded:: 1.1.6
+ """
+ arr = obj.__array_interface__
+ shape = arr["shape"]
+ ndim = len(shape)
+ strides = arr.get("strides", None)
+ if mode is None:
+ try:
+ typekey = (1, 1) + shape[2:], arr["typestr"]
+ mode, rawmode = _fromarray_typemap[typekey]
+ except KeyError:
+ raise TypeError("Cannot handle this data type")
+ else:
+ rawmode = mode
+ if mode in ["1", "L", "I", "P", "F"]:
+ ndmax = 2
+ elif mode == "RGB":
+ ndmax = 3
+ else:
+ ndmax = 4
+ if ndim > ndmax:
+ raise ValueError("Too many dimensions: %d > %d." % (ndim, ndmax))
+
+ size = shape[1], shape[0]
+ if strides is not None:
+ if hasattr(obj, "tobytes"):
+ obj = obj.tobytes()
+ else:
+ obj = obj.tostring()
+
+ return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
+
+
+def fromqimage(im):
+ """Creates an image instance from a QImage image"""
+ from . import ImageQt
+
+ if not ImageQt.qt_is_installed:
+ raise ImportError("Qt bindings are not installed")
+ return ImageQt.fromqimage(im)
+
+
+def fromqpixmap(im):
+ """Creates an image instance from a QPixmap image"""
+ from . import ImageQt
+
+ if not ImageQt.qt_is_installed:
+ raise ImportError("Qt bindings are not installed")
+ return ImageQt.fromqpixmap(im)
+
+
+_fromarray_typemap = {
+ # (shape, typestr) => mode, rawmode
+ # first two members of shape are set to one
+ ((1, 1), "|b1"): ("1", "1;8"),
+ ((1, 1), "|u1"): ("L", "L"),
+ ((1, 1), "|i1"): ("I", "I;8"),
+ ((1, 1), "<u2"): ("I", "I;16"),
+ ((1, 1), ">u2"): ("I", "I;16B"),
+ ((1, 1), "<i2"): ("I", "I;16S"),
+ ((1, 1), ">i2"): ("I", "I;16BS"),
+ ((1, 1), "<u4"): ("I", "I;32"),
+ ((1, 1), ">u4"): ("I", "I;32B"),
+ ((1, 1), "<i4"): ("I", "I;32S"),
+ ((1, 1), ">i4"): ("I", "I;32BS"),
+ ((1, 1), "<f4"): ("F", "F;32F"),
+ ((1, 1), ">f4"): ("F", "F;32BF"),
+ ((1, 1), "<f8"): ("F", "F;64F"),
+ ((1, 1), ">f8"): ("F", "F;64BF"),
+ ((1, 1, 2), "|u1"): ("LA", "LA"),
+ ((1, 1, 3), "|u1"): ("RGB", "RGB"),
+ ((1, 1, 4), "|u1"): ("RGBA", "RGBA"),
+}
+
+# shortcuts
+_fromarray_typemap[((1, 1), _ENDIAN + "i4")] = ("I", "I")
+_fromarray_typemap[((1, 1), _ENDIAN + "f4")] = ("F", "F")
+
+
+def _decompression_bomb_check(size):
+ if MAX_IMAGE_PIXELS is None:
+ return
+
+ pixels = size[0] * size[1]
+
+ if pixels > 2 * MAX_IMAGE_PIXELS:
+ raise DecompressionBombError(
+ "Image size (%d pixels) exceeds limit of %d pixels, "
+ "could be decompression bomb DOS attack." % (pixels, 2 * MAX_IMAGE_PIXELS)
+ )
+
+ if pixels > MAX_IMAGE_PIXELS:
+ warnings.warn(
+ "Image size (%d pixels) exceeds limit of %d pixels, "
+ "could be decompression bomb DOS attack." % (pixels, MAX_IMAGE_PIXELS),
+ DecompressionBombWarning,
+ )
+
+
+def open(fp, mode="r"):
+ """
+ Opens and identifies the given image file.
+
+ This is a lazy operation; this function identifies the file, but
+ the file remains open and the actual image data is not read from
+ the file until you try to process the data (or call the
+ :py:meth:`~PIL.Image.Image.load` method). See
+ :py:func:`~PIL.Image.new`. See :ref:`file-handling`.
+
+ :param fp: A filename (string), pathlib.Path object or a file object.
+ The file object must implement :py:meth:`~file.read`,
+ :py:meth:`~file.seek`, and :py:meth:`~file.tell` methods,
+ and be opened in binary mode.
+ :param mode: The mode. If given, this argument must be "r".
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ :exception IOError: If the file cannot be found, or the image cannot be
+ opened and identified.
+ """
+
+ if mode != "r":
+ raise ValueError("bad mode %r" % mode)
+
+ exclusive_fp = False
+ filename = ""
+ if HAS_PATHLIB and isinstance(fp, Path):
+ filename = str(fp.resolve())
+ elif isPath(fp):
+ filename = fp
+
+ if filename:
+ fp = builtins.open(filename, "rb")
+ exclusive_fp = True
+
+ try:
+ fp.seek(0)
+ except (AttributeError, io.UnsupportedOperation):
+ fp = io.BytesIO(fp.read())
+ exclusive_fp = True
+
+ prefix = fp.read(16)
+
+ preinit()
+
+ accept_warnings = []
+
+ def _open_core(fp, filename, prefix):
+ for i in ID:
+ try:
+ factory, accept = OPEN[i]
+ result = not accept or accept(prefix)
+ if type(result) in [str, bytes]:
+ accept_warnings.append(result)
+ elif result:
+ fp.seek(0)
+ im = factory(fp, filename)
+ _decompression_bomb_check(im.size)
+ return im
+ except (SyntaxError, IndexError, TypeError, struct.error):
+ # Leave disabled by default, spams the logs with image
+ # opening failures that are entirely expected.
+ # logger.debug("", exc_info=True)
+ continue
+ except BaseException:
+ if exclusive_fp:
+ fp.close()
+ raise
+ return None
+
+ im = _open_core(fp, filename, prefix)
+
+ if im is None:
+ if init():
+ im = _open_core(fp, filename, prefix)
+
+ if im:
+ im._exclusive_fp = exclusive_fp
+ return im
+
+ if exclusive_fp:
+ fp.close()
+ for message in accept_warnings:
+ warnings.warn(message)
+ raise IOError("cannot identify image file %r" % (filename if filename else fp))
+
+
+#
+# Image processing.
+
+
+def alpha_composite(im1, im2):
+ """
+ Alpha composite im2 over im1.
+
+ :param im1: The first image. Must have mode RGBA.
+ :param im2: The second image. Must have mode RGBA, and the same size as
+ the first image.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ im1.load()
+ im2.load()
+ return im1._new(core.alpha_composite(im1.im, im2.im))
+
+
+def blend(im1, im2, alpha):
+ """
+ Creates a new image by interpolating between two input images, using
+ a constant alpha.::
+
+ out = image1 * (1.0 - alpha) + image2 * alpha
+
+ :param im1: The first image.
+ :param im2: The second image. Must have the same mode and size as
+ the first image.
+ :param alpha: The interpolation alpha factor. If alpha is 0.0, a
+ copy of the first image is returned. If alpha is 1.0, a copy of
+ the second image is returned. There are no restrictions on the
+ alpha value. If necessary, the result is clipped to fit into
+ the allowed output range.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ im1.load()
+ im2.load()
+ return im1._new(core.blend(im1.im, im2.im, alpha))
+
+
+def composite(image1, image2, mask):
+ """
+ Create composite image by blending images using a transparency mask.
+
+ :param image1: The first image.
+ :param image2: The second image. Must have the same mode and
+ size as the first image.
+ :param mask: A mask image. This image can have mode
+ "1", "L", or "RGBA", and must have the same size as the
+ other two images.
+ """
+
+ image = image2.copy()
+ image.paste(image1, None, mask)
+ return image
+
+
+def eval(image, *args):
+ """
+ Applies the function (which should take one argument) to each pixel
+ in the given image. If the image has more than one band, the same
+ function is applied to each band. Note that the function is
+ evaluated once for each possible pixel value, so you cannot use
+ random components or other generators.
+
+ :param image: The input image.
+ :param function: A function object, taking one integer argument.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ return image.point(args[0])
+
+
+def merge(mode, bands):
+ """
+ Merge a set of single band images into a new multiband image.
+
+ :param mode: The mode to use for the output image. See:
+ :ref:`concept-modes`.
+ :param bands: A sequence containing one single-band image for
+ each band in the output image. All bands must have the
+ same size.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+
+ if getmodebands(mode) != len(bands) or "*" in mode:
+ raise ValueError("wrong number of bands")
+ for band in bands[1:]:
+ if band.mode != getmodetype(mode):
+ raise ValueError("mode mismatch")
+ if band.size != bands[0].size:
+ raise ValueError("size mismatch")
+ for band in bands:
+ band.load()
+ return bands[0]._new(core.merge(mode, *[b.im for b in bands]))
+
+
+# --------------------------------------------------------------------
+# Plugin registry
+
+
+def register_open(id, factory, accept=None):
+ """
+ Register an image file plugin. This function should not be used
+ in application code.
+
+ :param id: An image format identifier.
+ :param factory: An image file factory method.
+ :param accept: An optional function that can be used to quickly
+ reject images having another format.
+ """
+ id = id.upper()
+ ID.append(id)
+ OPEN[id] = factory, accept
+
+
+def register_mime(id, mimetype):
+ """
+ Registers an image MIME type. This function should not be used
+ in application code.
+
+ :param id: An image format identifier.
+ :param mimetype: The image MIME type for this format.
+ """
+ MIME[id.upper()] = mimetype
+
+
+def register_save(id, driver):
+ """
+ Registers an image save function. This function should not be
+ used in application code.
+
+ :param id: An image format identifier.
+ :param driver: A function to save images in this format.
+ """
+ SAVE[id.upper()] = driver
+
+
+def register_save_all(id, driver):
+ """
+ Registers an image function to save all the frames
+ of a multiframe format. This function should not be
+ used in application code.
+
+ :param id: An image format identifier.
+ :param driver: A function to save images in this format.
+ """
+ SAVE_ALL[id.upper()] = driver
+
+
+def register_extension(id, extension):
+ """
+ Registers an image extension. This function should not be
+ used in application code.
+
+ :param id: An image format identifier.
+ :param extension: An extension used for this format.
+ """
+ EXTENSION[extension.lower()] = id.upper()
+
+
+def register_extensions(id, extensions):
+ """
+ Registers image extensions. This function should not be
+ used in application code.
+
+ :param id: An image format identifier.
+ :param extensions: A list of extensions used for this format.
+ """
+ for extension in extensions:
+ register_extension(id, extension)
+
+
+def registered_extensions():
+ """
+ Returns a dictionary containing all file extensions belonging
+ to registered plugins
+ """
+ if not EXTENSION:
+ init()
+ return EXTENSION
+
+
+def register_decoder(name, decoder):
+ """
+ Registers an image decoder. This function should not be
+ used in application code.
+
+ :param name: The name of the decoder
+ :param decoder: A callable(mode, args) that returns an
+ ImageFile.PyDecoder object
+
+ .. versionadded:: 4.1.0
+ """
+ DECODERS[name] = decoder
+
+
+def register_encoder(name, encoder):
+ """
+ Registers an image encoder. This function should not be
+ used in application code.
+
+ :param name: The name of the encoder
+ :param encoder: A callable(mode, args) that returns an
+ ImageFile.PyEncoder object
+
+ .. versionadded:: 4.1.0
+ """
+ ENCODERS[name] = encoder
+
+
+# --------------------------------------------------------------------
+# Simple display support. User code may override this.
+
+
+def _show(image, **options):
+ # override me, as necessary
+ _showxv(image, **options)
+
+
+def _showxv(image, title=None, **options):
+ from . import ImageShow
+
+ ImageShow.show(image, title, **options)
+
+
+# --------------------------------------------------------------------
+# Effects
+
+
+def effect_mandelbrot(size, extent, quality):
+ """
+ Generate a Mandelbrot set covering the given extent.
+
+ :param size: The requested size in pixels, as a 2-tuple:
+ (width, height).
+ :param extent: The extent to cover, as a 4-tuple:
+ (x0, y0, x1, y2).
+ :param quality: Quality.
+ """
+ return Image()._new(core.effect_mandelbrot(size, extent, quality))
+
+
+def effect_noise(size, sigma):
+ """
+ Generate Gaussian noise centered around 128.
+
+ :param size: The requested size in pixels, as a 2-tuple:
+ (width, height).
+ :param sigma: Standard deviation of noise.
+ """
+ return Image()._new(core.effect_noise(size, sigma))
+
+
+def linear_gradient(mode):
+ """
+ Generate 256x256 linear gradient from black to white, top to bottom.
+
+ :param mode: Input mode.
+ """
+ return Image()._new(core.linear_gradient(mode))
+
+
+def radial_gradient(mode):
+ """
+ Generate 256x256 radial gradient from black to white, centre to edge.
+
+ :param mode: Input mode.
+ """
+ return Image()._new(core.radial_gradient(mode))
+
+
+# --------------------------------------------------------------------
+# Resources
+
+
+def _apply_env_variables(env=None):
+ if env is None:
+ env = os.environ
+
+ for var_name, setter in [
+ ("PILLOW_ALIGNMENT", core.set_alignment),
+ ("PILLOW_BLOCK_SIZE", core.set_block_size),
+ ("PILLOW_BLOCKS_MAX", core.set_blocks_max),
+ ]:
+ if var_name not in env:
+ continue
+
+ var = env[var_name].lower()
+
+ units = 1
+ for postfix, mul in [("k", 1024), ("m", 1024 * 1024)]:
+ if var.endswith(postfix):
+ units = mul
+ var = var[: -len(postfix)]
+
+ try:
+ var = int(var) * units
+ except ValueError:
+ warnings.warn("{} is not int".format(var_name))
+ continue
+
+ try:
+ setter(var)
+ except ValueError as e:
+ warnings.warn("{}: {}".format(var_name, e))
+
+
+_apply_env_variables()
+atexit.register(core.clear_cache)
+
+
+class Exif(MutableMapping):
+ endian = "<"
+
+ def __init__(self):
+ self._data = {}
+ self._ifds = {}
+ self._info = None
+ self._loaded_exif = None
+
+ def _fixup(self, value):
+ try:
+ if len(value) == 1 and not isinstance(value, dict):
+ return value[0]
+ except Exception:
+ pass
+ return value
+
+ def _fixup_dict(self, src_dict):
+ # Helper function for _getexif()
+ # returns a dict with any single item tuples/lists as individual values
+ return {k: self._fixup(v) for k, v in src_dict.items()}
+
+ def _get_ifd_dict(self, tag):
+ try:
+ # an offset pointer to the location of the nested embedded IFD.
+ # It should be a long, but may be corrupted.
+ self.fp.seek(self[tag])
+ except (KeyError, TypeError):
+ pass
+ else:
+ from . import TiffImagePlugin
+
+ info = TiffImagePlugin.ImageFileDirectory_v1(self.head)
+ info.load(self.fp)
+ return self._fixup_dict(info)
+
+ def load(self, data):
+ # Extract EXIF information. This is highly experimental,
+ # and is likely to be replaced with something better in a future
+ # version.
+
+ # The EXIF record consists of a TIFF file embedded in a JPEG
+ # application marker (!).
+ if data == self._loaded_exif:
+ return
+ self._loaded_exif = data
+ self._data.clear()
+ self._ifds.clear()
+ self._info = None
+ if not data:
+ return
+
+ self.fp = io.BytesIO(data[6:])
+ self.head = self.fp.read(8)
+ # process dictionary
+ from . import TiffImagePlugin
+
+ self._info = TiffImagePlugin.ImageFileDirectory_v1(self.head)
+ self.endian = self._info._endian
+ self.fp.seek(self._info.next)
+ self._info.load(self.fp)
+
+ # get EXIF extension
+ ifd = self._get_ifd_dict(0x8769)
+ if ifd:
+ self._data.update(ifd)
+ self._ifds[0x8769] = ifd
+
+ def tobytes(self, offset=0):
+ from . import TiffImagePlugin
+
+ if self.endian == "<":
+ head = b"II\x2A\x00\x08\x00\x00\x00"
+ else:
+ head = b"MM\x00\x2A\x00\x00\x00\x08"
+ ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head)
+ for tag, value in self.items():
+ ifd[tag] = value
+ return b"Exif\x00\x00" + head + ifd.tobytes(offset)
+
+ def get_ifd(self, tag):
+ if tag not in self._ifds and tag in self:
+ if tag in [0x8825, 0xA005]:
+ # gpsinfo, interop
+ self._ifds[tag] = self._get_ifd_dict(tag)
+ elif tag == 0x927C: # makernote
+ from .TiffImagePlugin import ImageFileDirectory_v2
+
+ if self[0x927C][:8] == b"FUJIFILM":
+ exif_data = self[0x927C]
+ ifd_offset = i32le(exif_data[8:12])
+ ifd_data = exif_data[ifd_offset:]
+
+ makernote = {}
+ for i in range(0, struct.unpack("<H", ifd_data[:2])[0]):
+ ifd_tag, typ, count, data = struct.unpack(
+ "<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2]
+ )
+ try:
+ unit_size, handler = ImageFileDirectory_v2._load_dispatch[
+ typ
+ ]
+ except KeyError:
+ continue
+ size = count * unit_size
+ if size > 4:
+ (offset,) = struct.unpack("<L", data)
+ data = ifd_data[offset - 12 : offset + size - 12]
+ else:
+ data = data[:size]
+
+ if len(data) != size:
+ warnings.warn(
+ "Possibly corrupt EXIF MakerNote data. "
+ "Expecting to read %d bytes but only got %d."
+ " Skipping tag %s" % (size, len(data), ifd_tag)
+ )
+ continue
+
+ if not data:
+ continue
+
+ makernote[ifd_tag] = handler(
+ ImageFileDirectory_v2(), data, False
+ )
+ self._ifds[0x927C] = dict(self._fixup_dict(makernote))
+ elif self.get(0x010F) == "Nintendo":
+ ifd_data = self[0x927C]
+
+ makernote = {}
+ for i in range(0, struct.unpack(">H", ifd_data[:2])[0]):
+ ifd_tag, typ, count, data = struct.unpack(
+ ">HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2]
+ )
+ if ifd_tag == 0x1101:
+ # CameraInfo
+ (offset,) = struct.unpack(">L", data)
+ self.fp.seek(offset)
+
+ camerainfo = {"ModelID": self.fp.read(4)}
+
+ self.fp.read(4)
+ # Seconds since 2000
+ camerainfo["TimeStamp"] = i32le(self.fp.read(12))
+
+ self.fp.read(4)
+ camerainfo["InternalSerialNumber"] = self.fp.read(4)
+
+ self.fp.read(12)
+ parallax = self.fp.read(4)
+ handler = ImageFileDirectory_v2._load_dispatch[
+ TiffTags.FLOAT
+ ][1]
+ camerainfo["Parallax"] = handler(
+ ImageFileDirectory_v2(), parallax, False
+ )
+
+ self.fp.read(4)
+ camerainfo["Category"] = self.fp.read(2)
+
+ makernote = {0x1101: dict(self._fixup_dict(camerainfo))}
+ self._ifds[0x927C] = makernote
+ return self._ifds.get(tag, {})
+
+ def __str__(self):
+ if self._info is not None:
+ # Load all keys into self._data
+ for tag in self._info.keys():
+ self[tag]
+
+ return str(self._data)
+
+ def __len__(self):
+ keys = set(self._data)
+ if self._info is not None:
+ keys.update(self._info)
+ return len(keys)
+
+ def __getitem__(self, tag):
+ if self._info is not None and tag not in self._data and tag in self._info:
+ self._data[tag] = self._fixup(self._info[tag])
+ if tag == 0x8825:
+ self._data[tag] = self.get_ifd(tag)
+ del self._info[tag]
+ return self._data[tag]
+
+ def __contains__(self, tag):
+ return tag in self._data or (self._info is not None and tag in self._info)
+
+ if not py3:
+
+ def has_key(self, tag):
+ return tag in self
+
+ def __setitem__(self, tag, value):
+ if self._info is not None and tag in self._info:
+ del self._info[tag]
+ self._data[tag] = value
+
+ def __delitem__(self, tag):
+ if self._info is not None and tag in self._info:
+ del self._info[tag]
+ del self._data[tag]
+
+ def __iter__(self):
+ keys = set(self._data)
+ if self._info is not None:
+ keys.update(self._info)
+ return iter(keys)
diff --git a/contrib/python/Pillow/py2/PIL/ImageChops.py b/contrib/python/Pillow/py2/PIL/ImageChops.py
new file mode 100644
index 0000000000..b1f71b5e71
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageChops.py
@@ -0,0 +1,292 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# standard channel operations
+#
+# History:
+# 1996-03-24 fl Created
+# 1996-08-13 fl Added logical operations (for "1" images)
+# 2000-10-12 fl Added offset method (from Image.py)
+#
+# Copyright (c) 1997-2000 by Secret Labs AB
+# Copyright (c) 1996-2000 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+
+
+def constant(image, value):
+ """Fill a channel with a given grey level.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ return Image.new("L", image.size, value)
+
+
+def duplicate(image):
+ """Copy a channel. Alias for :py:meth:`PIL.Image.Image.copy`.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ return image.copy()
+
+
+def invert(image):
+ """
+ Invert an image (channel).
+
+ .. code-block:: python
+
+ out = MAX - image
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image.load()
+ return image._new(image.im.chop_invert())
+
+
+def lighter(image1, image2):
+ """
+ Compares the two images, pixel by pixel, and returns a new image containing
+ the lighter values. At least one of the images must have mode "1".
+
+ .. code-block:: python
+
+ out = max(image1, image2)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_lighter(image2.im))
+
+
+def darker(image1, image2):
+ """
+ Compares the two images, pixel by pixel, and returns a new image containing
+ the darker values. At least one of the images must have mode "1".
+
+ .. code-block:: python
+
+ out = min(image1, image2)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_darker(image2.im))
+
+
+def difference(image1, image2):
+ """
+ Returns the absolute value of the pixel-by-pixel difference between the two
+ images. At least one of the images must have mode "1".
+
+ .. code-block:: python
+
+ out = abs(image1 - image2)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_difference(image2.im))
+
+
+def multiply(image1, image2):
+ """
+ Superimposes two images on top of each other.
+
+ If you multiply an image with a solid black image, the result is black. If
+ you multiply with a solid white image, the image is unaffected. At least
+ one of the images must have mode "1".
+
+ .. code-block:: python
+
+ out = image1 * image2 / MAX
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_multiply(image2.im))
+
+
+def screen(image1, image2):
+ """
+ Superimposes two inverted images on top of each other. At least one of the
+ images must have mode "1".
+
+ .. code-block:: python
+
+ out = MAX - ((MAX - image1) * (MAX - image2) / MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_screen(image2.im))
+
+
+def add(image1, image2, scale=1.0, offset=0):
+ """
+ Adds two images, dividing the result by scale and adding the
+ offset. If omitted, scale defaults to 1.0, and offset to 0.0.
+ At least one of the images must have mode "1".
+
+ .. code-block:: python
+
+ out = ((image1 + image2) / scale + offset)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_add(image2.im, scale, offset))
+
+
+def subtract(image1, image2, scale=1.0, offset=0):
+ """
+ Subtracts two images, dividing the result by scale and adding the offset.
+ If omitted, scale defaults to 1.0, and offset to 0.0. At least one of the
+ images must have mode "1".
+
+ .. code-block:: python
+
+ out = ((image1 - image2) / scale + offset)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_subtract(image2.im, scale, offset))
+
+
+def add_modulo(image1, image2):
+ """Add two images, without clipping the result. At least one of the images
+ must have mode "1".
+
+ .. code-block:: python
+
+ out = ((image1 + image2) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_add_modulo(image2.im))
+
+
+def subtract_modulo(image1, image2):
+ """Subtract two images, without clipping the result. At least one of the
+ images must have mode "1".
+
+ .. code-block:: python
+
+ out = ((image1 - image2) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_subtract_modulo(image2.im))
+
+
+def logical_and(image1, image2):
+ """Logical AND between two images. At least one of the images must have
+ mode "1".
+
+ .. code-block:: python
+
+ out = ((image1 and image2) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_and(image2.im))
+
+
+def logical_or(image1, image2):
+ """Logical OR between two images. At least one of the images must have
+ mode "1".
+
+ .. code-block:: python
+
+ out = ((image1 or image2) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_or(image2.im))
+
+
+def logical_xor(image1, image2):
+ """Logical XOR between two images. At least one of the images must have
+ mode "1".
+
+ .. code-block:: python
+
+ out = ((bool(image1) != bool(image2)) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_xor(image2.im))
+
+
+def blend(image1, image2, alpha):
+ """Blend images using constant transparency weight. Alias for
+ :py:meth:`PIL.Image.Image.blend`.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ return Image.blend(image1, image2, alpha)
+
+
+def composite(image1, image2, mask):
+ """Create composite using transparency mask. Alias for
+ :py:meth:`PIL.Image.Image.composite`.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ return Image.composite(image1, image2, mask)
+
+
+def offset(image, xoffset, yoffset=None):
+ """Returns a copy of the image where data has been offset by the given
+ distances. Data wraps around the edges. If **yoffset** is omitted, it
+ is assumed to be equal to **xoffset**.
+
+ :param xoffset: The horizontal distance.
+ :param yoffset: The vertical distance. If omitted, both
+ distances are set to the same value.
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ if yoffset is None:
+ yoffset = xoffset
+ image.load()
+ return image._new(image.im.offset(xoffset, yoffset))
diff --git a/contrib/python/Pillow/py2/PIL/ImageCms.py b/contrib/python/Pillow/py2/PIL/ImageCms.py
new file mode 100644
index 0000000000..ed4eefc0d0
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageCms.py
@@ -0,0 +1,991 @@
+# The Python Imaging Library.
+# $Id$
+
+# Optional color management support, based on Kevin Cazabon's PyCMS
+# library.
+
+# History:
+
+# 2009-03-08 fl Added to PIL.
+
+# Copyright (C) 2002-2003 Kevin Cazabon
+# Copyright (c) 2009 by Fredrik Lundh
+# Copyright (c) 2013 by Eric Soroos
+
+# See the README file for information on usage and redistribution. See
+# below for the original description.
+
+from __future__ import print_function
+
+import sys
+
+from PIL import Image
+from PIL._util import isStringType
+
+try:
+ from PIL import _imagingcms
+except ImportError as ex:
+ # Allow error import for doc purposes, but error out when accessing
+ # anything in core.
+ from ._util import deferred_error
+
+ _imagingcms = deferred_error(ex)
+
+DESCRIPTION = """
+pyCMS
+
+ a Python / PIL interface to the littleCMS ICC Color Management System
+ Copyright (C) 2002-2003 Kevin Cazabon
+ kevin@cazabon.com
+ http://www.cazabon.com
+
+ pyCMS home page: http://www.cazabon.com/pyCMS
+ littleCMS home page: http://www.littlecms.com
+ (littleCMS is Copyright (C) 1998-2001 Marti Maria)
+
+ Originally released under LGPL. Graciously donated to PIL in
+ March 2009, for distribution under the standard PIL license
+
+ The pyCMS.py module provides a "clean" interface between Python/PIL and
+ pyCMSdll, taking care of some of the more complex handling of the direct
+ pyCMSdll functions, as well as error-checking and making sure that all
+ relevant data is kept together.
+
+ While it is possible to call pyCMSdll functions directly, it's not highly
+ recommended.
+
+ Version History:
+
+ 1.0.0 pil Oct 2013 Port to LCMS 2.
+
+ 0.1.0 pil mod March 10, 2009
+
+ Renamed display profile to proof profile. The proof
+ profile is the profile of the device that is being
+ simulated, not the profile of the device which is
+ actually used to display/print the final simulation
+ (that'd be the output profile) - also see LCMSAPI.txt
+ input colorspace -> using 'renderingIntent' -> proof
+ colorspace -> using 'proofRenderingIntent' -> output
+ colorspace
+
+ Added LCMS FLAGS support.
+ Added FLAGS["SOFTPROOFING"] as default flag for
+ buildProofTransform (otherwise the proof profile/intent
+ would be ignored).
+
+ 0.1.0 pil March 2009 - added to PIL, as PIL.ImageCms
+
+ 0.0.2 alpha Jan 6, 2002
+
+ Added try/except statements around type() checks of
+ potential CObjects... Python won't let you use type()
+ on them, and raises a TypeError (stupid, if you ask
+ me!)
+
+ Added buildProofTransformFromOpenProfiles() function.
+ Additional fixes in DLL, see DLL code for details.
+
+ 0.0.1 alpha first public release, Dec. 26, 2002
+
+ Known to-do list with current version (of Python interface, not pyCMSdll):
+
+ none
+
+"""
+
+VERSION = "1.0.0 pil"
+
+# --------------------------------------------------------------------.
+
+core = _imagingcms
+
+#
+# intent/direction values
+
+INTENT_PERCEPTUAL = 0
+INTENT_RELATIVE_COLORIMETRIC = 1
+INTENT_SATURATION = 2
+INTENT_ABSOLUTE_COLORIMETRIC = 3
+
+DIRECTION_INPUT = 0
+DIRECTION_OUTPUT = 1
+DIRECTION_PROOF = 2
+
+#
+# flags
+
+FLAGS = {
+ "MATRIXINPUT": 1,
+ "MATRIXOUTPUT": 2,
+ "MATRIXONLY": (1 | 2),
+ "NOWHITEONWHITEFIXUP": 4, # Don't hot fix scum dot
+ # Don't create prelinearization tables on precalculated transforms
+ # (internal use):
+ "NOPRELINEARIZATION": 16,
+ "GUESSDEVICECLASS": 32, # Guess device class (for transform2devicelink)
+ "NOTCACHE": 64, # Inhibit 1-pixel cache
+ "NOTPRECALC": 256,
+ "NULLTRANSFORM": 512, # Don't transform anyway
+ "HIGHRESPRECALC": 1024, # Use more memory to give better accuracy
+ "LOWRESPRECALC": 2048, # Use less memory to minimize resources
+ "WHITEBLACKCOMPENSATION": 8192,
+ "BLACKPOINTCOMPENSATION": 8192,
+ "GAMUTCHECK": 4096, # Out of Gamut alarm
+ "SOFTPROOFING": 16384, # Do softproofing
+ "PRESERVEBLACK": 32768, # Black preservation
+ "NODEFAULTRESOURCEDEF": 16777216, # CRD special
+ "GRIDPOINTS": lambda n: ((n) & 0xFF) << 16, # Gridpoints
+}
+
+_MAX_FLAG = 0
+for flag in FLAGS.values():
+ if isinstance(flag, int):
+ _MAX_FLAG = _MAX_FLAG | flag
+
+
+# --------------------------------------------------------------------.
+# Experimental PIL-level API
+# --------------------------------------------------------------------.
+
+##
+# Profile.
+
+
+class ImageCmsProfile(object):
+ def __init__(self, profile):
+ """
+ :param profile: Either a string representing a filename,
+ a file like object containing a profile or a
+ low-level profile object
+
+ """
+
+ if isStringType(profile):
+ self._set(core.profile_open(profile), profile)
+ elif hasattr(profile, "read"):
+ self._set(core.profile_frombytes(profile.read()))
+ elif isinstance(profile, _imagingcms.CmsProfile):
+ self._set(profile)
+ else:
+ raise TypeError("Invalid type for Profile")
+
+ def _set(self, profile, filename=None):
+ self.profile = profile
+ self.filename = filename
+ if profile:
+ self.product_name = None # profile.product_name
+ self.product_info = None # profile.product_info
+ else:
+ self.product_name = None
+ self.product_info = None
+
+ def tobytes(self):
+ """
+ Returns the profile in a format suitable for embedding in
+ saved images.
+
+ :returns: a bytes object containing the ICC profile.
+ """
+
+ return core.profile_tobytes(self.profile)
+
+
+class ImageCmsTransform(Image.ImagePointHandler):
+
+ """
+ Transform. This can be used with the procedural API, or with the standard
+ Image.point() method.
+
+ Will return the output profile in the output.info['icc_profile'].
+ """
+
+ def __init__(
+ self,
+ input,
+ output,
+ input_mode,
+ output_mode,
+ intent=INTENT_PERCEPTUAL,
+ proof=None,
+ proof_intent=INTENT_ABSOLUTE_COLORIMETRIC,
+ flags=0,
+ ):
+ if proof is None:
+ self.transform = core.buildTransform(
+ input.profile, output.profile, input_mode, output_mode, intent, flags
+ )
+ else:
+ self.transform = core.buildProofTransform(
+ input.profile,
+ output.profile,
+ proof.profile,
+ input_mode,
+ output_mode,
+ intent,
+ proof_intent,
+ flags,
+ )
+ # Note: inputMode and outputMode are for pyCMS compatibility only
+ self.input_mode = self.inputMode = input_mode
+ self.output_mode = self.outputMode = output_mode
+
+ self.output_profile = output
+
+ def point(self, im):
+ return self.apply(im)
+
+ def apply(self, im, imOut=None):
+ im.load()
+ if imOut is None:
+ imOut = Image.new(self.output_mode, im.size, None)
+ self.transform.apply(im.im.id, imOut.im.id)
+ imOut.info["icc_profile"] = self.output_profile.tobytes()
+ return imOut
+
+ def apply_in_place(self, im):
+ im.load()
+ if im.mode != self.output_mode:
+ raise ValueError("mode mismatch") # wrong output mode
+ self.transform.apply(im.im.id, im.im.id)
+ im.info["icc_profile"] = self.output_profile.tobytes()
+ return im
+
+
+def get_display_profile(handle=None):
+ """ (experimental) Fetches the profile for the current display device.
+ :returns: None if the profile is not known.
+ """
+
+ if sys.platform == "win32":
+ from PIL import ImageWin
+
+ if isinstance(handle, ImageWin.HDC):
+ profile = core.get_display_profile_win32(handle, 1)
+ else:
+ profile = core.get_display_profile_win32(handle or 0)
+ else:
+ try:
+ get = _imagingcms.get_display_profile
+ except AttributeError:
+ return None
+ else:
+ profile = get()
+ return ImageCmsProfile(profile)
+
+
+# --------------------------------------------------------------------.
+# pyCMS compatible layer
+# --------------------------------------------------------------------.
+
+
+class PyCMSError(Exception):
+
+ """ (pyCMS) Exception class.
+ This is used for all errors in the pyCMS API. """
+
+ pass
+
+
+def profileToProfile(
+ im,
+ inputProfile,
+ outputProfile,
+ renderingIntent=INTENT_PERCEPTUAL,
+ outputMode=None,
+ inPlace=False,
+ flags=0,
+):
+ """
+ (pyCMS) Applies an ICC transformation to a given image, mapping from
+ inputProfile to outputProfile.
+
+ If the input or output profiles specified are not valid filenames, a
+ PyCMSError will be raised. If inPlace is True and outputMode != im.mode,
+ a PyCMSError will be raised. If an error occurs during application of
+ the profiles, a PyCMSError will be raised. If outputMode is not a mode
+ supported by the outputProfile (or by pyCMS), a PyCMSError will be
+ raised.
+
+ This function applies an ICC transformation to im from inputProfile's
+ color space to outputProfile's color space using the specified rendering
+ intent to decide how to handle out-of-gamut colors.
+
+ OutputMode can be used to specify that a color mode conversion is to
+ be done using these profiles, but the specified profiles must be able
+ to handle that mode. I.e., if converting im from RGB to CMYK using
+ profiles, the input profile must handle RGB data, and the output
+ profile must handle CMYK data.
+
+ :param im: An open PIL image object (i.e. Image.new(...) or
+ Image.open(...), etc.)
+ :param inputProfile: String, as a valid filename path to the ICC input
+ profile you wish to use for this image, or a profile object
+ :param outputProfile: String, as a valid filename path to the ICC output
+ profile you wish to use for this image, or a profile object
+ :param renderingIntent: Integer (0-3) specifying the rendering intent you
+ wish to use for the transform
+
+ 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 outputMode: A valid PIL mode for the output image (i.e. "RGB",
+ "CMYK", etc.). Note: if rendering the image "inPlace", outputMode
+ MUST be the same mode as the input, or omitted completely. If
+ omitted, the outputMode will be the same as the mode of the input
+ image (im.mode)
+ :param inPlace: Boolean. If True, the original image is modified in-place,
+ and None is returned. If False (default), a new Image object is
+ returned with the transform applied.
+ :param flags: Integer (0-...) specifying additional flags
+ :returns: Either None or a new PIL image object, depending on value of
+ inPlace
+ :exception PyCMSError:
+ """
+
+ if outputMode is None:
+ outputMode = im.mode
+
+ if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
+ raise PyCMSError("renderingIntent must be an integer between 0 and 3")
+
+ if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
+ raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
+
+ try:
+ if not isinstance(inputProfile, ImageCmsProfile):
+ inputProfile = ImageCmsProfile(inputProfile)
+ if not isinstance(outputProfile, ImageCmsProfile):
+ outputProfile = ImageCmsProfile(outputProfile)
+ transform = ImageCmsTransform(
+ inputProfile,
+ outputProfile,
+ im.mode,
+ outputMode,
+ renderingIntent,
+ flags=flags,
+ )
+ if inPlace:
+ transform.apply_in_place(im)
+ imOut = None
+ else:
+ imOut = transform.apply(im)
+ except (IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+ return imOut
+
+
+def getOpenProfile(profileFilename):
+ """
+ (pyCMS) Opens an ICC profile file.
+
+ The PyCMSProfile object can be passed back into pyCMS for use in creating
+ transforms and such (as in ImageCms.buildTransformFromOpenProfiles()).
+
+ If profileFilename is not a valid filename for an ICC profile, a PyCMSError
+ will be raised.
+
+ :param profileFilename: String, as a valid filename path to the ICC profile
+ you wish to open, or a file-like object.
+ :returns: A CmsProfile class object.
+ :exception PyCMSError:
+ """
+
+ try:
+ return ImageCmsProfile(profileFilename)
+ except (IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def buildTransform(
+ inputProfile,
+ outputProfile,
+ inMode,
+ outMode,
+ renderingIntent=INTENT_PERCEPTUAL,
+ flags=0,
+):
+ """
+ (pyCMS) Builds an ICC transform mapping from the inputProfile to the
+ outputProfile. Use applyTransform to apply the transform to a given
+ image.
+
+ If the input or output profiles specified are not valid filenames, a
+ PyCMSError will be raised. If an error occurs during creation of the
+ transform, a PyCMSError will be raised.
+
+ If inMode or outMode are not a mode supported by the outputProfile (or
+ by pyCMS), a PyCMSError will be raised.
+
+ This function builds and returns an ICC transform from the inputProfile
+ to the outputProfile using the renderingIntent to determine what to do
+ with out-of-gamut colors. It will ONLY work for converting images that
+ are in inMode to images that are in outMode color format (PIL mode,
+ i.e. "RGB", "RGBA", "CMYK", etc.).
+
+ Building the transform is a fair part of the overhead in
+ ImageCms.profileToProfile(), so if you're planning on converting multiple
+ images using the same input/output settings, this can save you time.
+ Once you have a transform object, it can be used with
+ ImageCms.applyProfile() to convert images without the need to re-compute
+ the lookup table for the transform.
+
+ The reason pyCMS returns a class object rather than a handle directly
+ to the transform is that it needs to keep track of the PIL input/output
+ modes that the transform is meant for. These attributes are stored in
+ the "inMode" and "outMode" attributes of the object (which can be
+ manually overridden if you really want to, but I don't know of any
+ time that would be of use, or would even work).
+
+ :param inputProfile: String, as a valid filename path to the ICC input
+ profile you wish to use for this transform, or a profile object
+ :param outputProfile: String, as a valid filename path to the ICC output
+ profile you wish to use for this transform, or a profile object
+ :param inMode: String, as a valid PIL mode that the appropriate profile
+ also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
+ :param outMode: String, as a valid PIL mode that the appropriate profile
+ also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
+ :param renderingIntent: Integer (0-3) specifying the rendering intent you
+ wish to use for the transform
+
+ 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 flags: Integer (0-...) specifying additional flags
+ :returns: A CmsTransform class object.
+ :exception PyCMSError:
+ """
+
+ if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
+ raise PyCMSError("renderingIntent must be an integer between 0 and 3")
+
+ if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
+ raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
+
+ try:
+ if not isinstance(inputProfile, ImageCmsProfile):
+ inputProfile = ImageCmsProfile(inputProfile)
+ if not isinstance(outputProfile, ImageCmsProfile):
+ outputProfile = ImageCmsProfile(outputProfile)
+ return ImageCmsTransform(
+ inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags
+ )
+ except (IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def buildProofTransform(
+ inputProfile,
+ outputProfile,
+ proofProfile,
+ inMode,
+ outMode,
+ renderingIntent=INTENT_PERCEPTUAL,
+ proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC,
+ flags=FLAGS["SOFTPROOFING"],
+):
+ """
+ (pyCMS) Builds an ICC transform mapping from the inputProfile to the
+ outputProfile, but tries to simulate the result that would be
+ obtained on the proofProfile device.
+
+ If the input, output, or proof profiles specified are not valid
+ filenames, a PyCMSError will be raised.
+
+ If an error occurs during creation of the transform, a PyCMSError will
+ be raised.
+
+ If inMode or outMode are not a mode supported by the outputProfile
+ (or by pyCMS), a PyCMSError will be raised.
+
+ This function builds and returns an ICC transform from the inputProfile
+ to the outputProfile, but tries to simulate the result that would be
+ obtained on the proofProfile device using renderingIntent and
+ proofRenderingIntent to determine what to do with out-of-gamut
+ colors. This is known as "soft-proofing". It will ONLY work for
+ converting images that are in inMode to images that are in outMode
+ color format (PIL mode, i.e. "RGB", "RGBA", "CMYK", etc.).
+
+ Usage of the resulting transform object is exactly the same as with
+ ImageCms.buildTransform().
+
+ Proof profiling is generally used when using an output device to get a
+ good idea of what the final printed/displayed image would look like on
+ the proofProfile device when it's quicker and easier to use the
+ output device for judging color. Generally, this means that the
+ output device is a monitor, or a dye-sub printer (etc.), and the simulated
+ device is something more expensive, complicated, or time consuming
+ (making it difficult to make a real print for color judgement purposes).
+
+ Soft-proofing basically functions by adjusting the colors on the
+ output device to match the colors of the device being simulated. However,
+ when the simulated device has a much wider gamut than the output
+ device, you may obtain marginal results.
+
+ :param inputProfile: String, as a valid filename path to the ICC input
+ profile you wish to use for this transform, or a profile object
+ :param outputProfile: String, as a valid filename path to the ICC output
+ (monitor, usually) profile you wish to use for this transform, or a
+ profile object
+ :param proofProfile: String, as a valid filename path to the ICC proof
+ profile you wish to use for this transform, or a profile object
+ :param inMode: String, as a valid PIL mode that the appropriate profile
+ also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
+ :param outMode: String, as a valid PIL mode that the appropriate profile
+ also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
+ :param renderingIntent: Integer (0-3) specifying the rendering intent you
+ wish to use for the input->proof (simulated) transform
+
+ 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
+
+ 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 flags: Integer (0-...) specifying additional flags
+ :returns: A CmsTransform class object.
+ :exception PyCMSError:
+ """
+
+ if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
+ raise PyCMSError("renderingIntent must be an integer between 0 and 3")
+
+ if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
+ raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
+
+ try:
+ if not isinstance(inputProfile, ImageCmsProfile):
+ inputProfile = ImageCmsProfile(inputProfile)
+ if not isinstance(outputProfile, ImageCmsProfile):
+ outputProfile = ImageCmsProfile(outputProfile)
+ if not isinstance(proofProfile, ImageCmsProfile):
+ proofProfile = ImageCmsProfile(proofProfile)
+ return ImageCmsTransform(
+ inputProfile,
+ outputProfile,
+ inMode,
+ outMode,
+ renderingIntent,
+ proofProfile,
+ proofRenderingIntent,
+ flags,
+ )
+ except (IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+buildTransformFromOpenProfiles = buildTransform
+buildProofTransformFromOpenProfiles = buildProofTransform
+
+
+def applyTransform(im, transform, inPlace=False):
+ """
+ (pyCMS) Applies a transform to a given image.
+
+ If im.mode != transform.inMode, a PyCMSError is raised.
+
+ If inPlace is True and transform.inMode != transform.outMode, a
+ PyCMSError is raised.
+
+ If im.mode, transform.inMode, or transform.outMode is not supported by
+ pyCMSdll or the profiles you used for the transform, a PyCMSError is
+ raised.
+
+ If an error occurs while the transform is being applied, a PyCMSError
+ is raised.
+
+ This function applies a pre-calculated transform (from
+ ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles())
+ to an image. The transform can be used for multiple images, saving
+ considerable calculation time if doing the same conversion multiple times.
+
+ If you want to modify im in-place instead of receiving a new image as
+ the return value, set inPlace to True. This can only be done if
+ transform.inMode and transform.outMode are the same, because we can't
+ change the mode in-place (the buffer sizes for some modes are
+ different). The default behavior is to return a new Image object of
+ the same dimensions in mode transform.outMode.
+
+ :param im: A PIL Image object, and im.mode must be the same as the inMode
+ supported by the transform.
+ :param transform: A valid CmsTransform class object
+ :param inPlace: Bool. If True, im is modified in place and None is
+ returned, if False, a new Image object with the transform applied is
+ returned (and im is not changed). The default is False.
+ :returns: Either None, or a new PIL Image object, depending on the value of
+ inPlace. The profile will be returned in the image's
+ info['icc_profile'].
+ :exception PyCMSError:
+ """
+
+ try:
+ if inPlace:
+ transform.apply_in_place(im)
+ imOut = None
+ else:
+ imOut = transform.apply(im)
+ except (TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+ return imOut
+
+
+def createProfile(colorSpace, colorTemp=-1):
+ """
+ (pyCMS) Creates a profile.
+
+ If colorSpace not in ["LAB", "XYZ", "sRGB"], a PyCMSError is raised
+
+ If using LAB and colorTemp != a positive integer, a PyCMSError is raised.
+
+ If an error occurs while creating the profile, a PyCMSError is raised.
+
+ Use this function to create common profiles on-the-fly instead of
+ having to supply a profile on disk and knowing the path to it. It
+ returns a normal CmsProfile object that can be passed to
+ ImageCms.buildTransformFromOpenProfiles() to create a transform to apply
+ to images.
+
+ :param colorSpace: String, the color space of the profile you wish to
+ create.
+ Currently only "LAB", "XYZ", and "sRGB" are supported.
+ :param colorTemp: Positive integer for the white point for the profile, in
+ degrees Kelvin (i.e. 5000, 6500, 9600, etc.). The default is for D50
+ illuminant if omitted (5000k). colorTemp is ONLY applied to LAB
+ profiles, and is ignored for XYZ and sRGB.
+ :returns: A CmsProfile class object
+ :exception PyCMSError:
+ """
+
+ if colorSpace not in ["LAB", "XYZ", "sRGB"]:
+ raise PyCMSError(
+ "Color space not supported for on-the-fly profile creation (%s)"
+ % colorSpace
+ )
+
+ if colorSpace == "LAB":
+ try:
+ colorTemp = float(colorTemp)
+ except (TypeError, ValueError):
+ raise PyCMSError(
+ 'Color temperature must be numeric, "%s" not valid' % colorTemp
+ )
+
+ try:
+ return core.createProfile(colorSpace, colorTemp)
+ except (TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def getProfileName(profile):
+ """
+
+ (pyCMS) Gets the internal product name for the given profile.
+
+ If profile isn't a valid CmsProfile object or filename to a profile,
+ a PyCMSError is raised If an error occurs while trying to obtain the
+ name tag, a PyCMSError is raised.
+
+ Use this function to obtain the INTERNAL name of the profile (stored
+ in an ICC tag in the profile itself), usually the one used when the
+ profile was originally created. Sometimes this tag also contains
+ additional information supplied by the creator.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal name of the profile as stored
+ in an ICC tag.
+ :exception PyCMSError:
+ """
+
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ # do it in python, not c.
+ # // name was "%s - %s" (model, manufacturer) || Description ,
+ # // but if the Model and Manufacturer were the same or the model
+ # // was long, Just the model, in 1.x
+ model = profile.profile.model
+ manufacturer = profile.profile.manufacturer
+
+ if not (model or manufacturer):
+ return (profile.profile.profile_description or "") + "\n"
+ if not manufacturer or len(model) > 30:
+ return model + "\n"
+ return "%s - %s\n" % (model, manufacturer)
+
+ except (AttributeError, IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def getProfileInfo(profile):
+ """
+ (pyCMS) Gets the internal product information for the given profile.
+
+ If profile isn't a valid CmsProfile object or filename to a profile,
+ a PyCMSError is raised.
+
+ If an error occurs while trying to obtain the info tag, a PyCMSError
+ is raised
+
+ Use this function to obtain the information stored in the profile's
+ info tag. This often contains details about the profile, and how it
+ was created, as supplied by the creator.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in
+ an ICC tag.
+ :exception PyCMSError:
+ """
+
+ try:
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ # add an extra newline to preserve pyCMS compatibility
+ # Python, not C. the white point bits weren't working well,
+ # so skipping.
+ # info was description \r\n\r\n copyright \r\n\r\n K007 tag \r\n\r\n whitepoint
+ description = profile.profile.profile_description
+ cpright = profile.profile.copyright
+ arr = []
+ for elt in (description, cpright):
+ if elt:
+ arr.append(elt)
+ return "\r\n\r\n".join(arr) + "\r\n\r\n"
+
+ except (AttributeError, IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def getProfileCopyright(profile):
+ """
+ (pyCMS) Gets the copyright for the given profile.
+
+ If profile isn't a valid CmsProfile object or filename to a profile,
+ a PyCMSError is raised.
+
+ If an error occurs while trying to obtain the copyright tag, a PyCMSError
+ is raised
+
+ Use this function to obtain the information stored in the profile's
+ copyright tag.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in
+ an ICC tag.
+ :exception PyCMSError:
+ """
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return (profile.profile.copyright or "") + "\n"
+ except (AttributeError, IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def getProfileManufacturer(profile):
+ """
+ (pyCMS) Gets the manufacturer for the given profile.
+
+ If profile isn't a valid CmsProfile object or filename to a profile,
+ a PyCMSError is raised.
+
+ If an error occurs while trying to obtain the manufacturer tag, a
+ PyCMSError is raised
+
+ Use this function to obtain the information stored in the profile's
+ manufacturer tag.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in
+ an ICC tag.
+ :exception PyCMSError:
+ """
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return (profile.profile.manufacturer or "") + "\n"
+ except (AttributeError, IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def getProfileModel(profile):
+ """
+ (pyCMS) Gets the model for the given profile.
+
+ If profile isn't a valid CmsProfile object or filename to a profile,
+ a PyCMSError is raised.
+
+ If an error occurs while trying to obtain the model tag, a PyCMSError
+ is raised
+
+ Use this function to obtain the information stored in the profile's
+ model tag.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in
+ an ICC tag.
+ :exception PyCMSError:
+ """
+
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return (profile.profile.model or "") + "\n"
+ except (AttributeError, IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def getProfileDescription(profile):
+ """
+ (pyCMS) Gets the description for the given profile.
+
+ If profile isn't a valid CmsProfile object or filename to a profile,
+ a PyCMSError is raised.
+
+ If an error occurs while trying to obtain the description tag, a PyCMSError
+ is raised
+
+ Use this function to obtain the information stored in the profile's
+ description tag.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in an
+ ICC tag.
+ :exception PyCMSError:
+ """
+
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return (profile.profile.profile_description or "") + "\n"
+ except (AttributeError, IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def getDefaultIntent(profile):
+ """
+ (pyCMS) Gets the default intent name for the given profile.
+
+ If profile isn't a valid CmsProfile object or filename to a profile,
+ a PyCMSError is raised.
+
+ If an error occurs while trying to obtain the default intent, a
+ PyCMSError is raised.
+
+ Use this function to determine the default (and usually best optimized)
+ rendering intent for this profile. Most profiles support multiple
+ rendering intents, but are intended mostly for one type of conversion.
+ If you wish to use a different intent than returned, use
+ ImageCms.isIntentSupported() to verify it will work first.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: Integer 0-3 specifying the default rendering intent for this
+ profile.
+
+ 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.
+ :exception PyCMSError:
+ """
+
+ try:
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return profile.profile.rendering_intent
+ except (AttributeError, IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def isIntentSupported(profile, intent, direction):
+ """
+ (pyCMS) Checks if a given intent is supported.
+
+ Use this function to verify that you can use your desired
+ renderingIntent with profile, and that profile can be used for the
+ input/output/proof profile as you desire.
+
+ Some profiles are created specifically for one "direction", can cannot
+ be used for others. Some profiles can only be used for certain
+ rendering intents... so it's best to either verify this before trying
+ to create a transform with them (using this function), or catch the
+ potential PyCMSError that will occur if they don't support the modes
+ you select.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :param intent: Integer (0-3) specifying the rendering intent you wish to
+ use with this profile
+
+ 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
+
+ INPUT = 0 (or use ImageCms.DIRECTION_INPUT)
+ OUTPUT = 1 (or use ImageCms.DIRECTION_OUTPUT)
+ PROOF = 2 (or use ImageCms.DIRECTION_PROOF)
+
+ :returns: 1 if the intent/direction are supported, -1 if they are not.
+ :exception PyCMSError:
+ """
+
+ try:
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ # FIXME: I get different results for the same data w. different
+ # compilers. Bug in LittleCMS or in the binding?
+ if profile.profile.is_intent_supported(intent, direction):
+ return 1
+ else:
+ return -1
+ except (AttributeError, IOError, TypeError, ValueError) as v:
+ raise PyCMSError(v)
+
+
+def versions():
+ """
+ (pyCMS) Fetches versions.
+ """
+
+ return (VERSION, core.littlecms_version, sys.version.split()[0], Image.__version__)
diff --git a/contrib/python/Pillow/py2/PIL/ImageColor.py b/contrib/python/Pillow/py2/PIL/ImageColor.py
new file mode 100644
index 0000000000..692d7d2c3c
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageColor.py
@@ -0,0 +1,298 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# map CSS3-style colour description strings to RGB
+#
+# History:
+# 2002-10-24 fl Added support for CSS-style color strings
+# 2002-12-15 fl Added RGBA support
+# 2004-03-27 fl Fixed remaining int() problems for Python 1.5.2
+# 2004-07-19 fl Fixed gray/grey spelling issues
+# 2009-03-05 fl Fixed rounding error in grayscale calculation
+#
+# Copyright (c) 2002-2004 by Secret Labs AB
+# Copyright (c) 2002-2004 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import re
+
+from . import Image
+
+
+def getrgb(color):
+ """
+ Convert a color string to an RGB tuple. If the string cannot be parsed,
+ this function raises a :py:exc:`ValueError` exception.
+
+ .. versionadded:: 1.1.4
+
+ :param color: A color string
+ :return: ``(red, green, blue[, alpha])``
+ """
+ color = color.lower()
+
+ rgb = colormap.get(color, None)
+ if rgb:
+ if isinstance(rgb, tuple):
+ return rgb
+ colormap[color] = rgb = getrgb(rgb)
+ return rgb
+
+ # check for known string formats
+ if re.match("#[a-f0-9]{3}$", color):
+ return (int(color[1] * 2, 16), int(color[2] * 2, 16), int(color[3] * 2, 16))
+
+ if re.match("#[a-f0-9]{4}$", color):
+ return (
+ int(color[1] * 2, 16),
+ int(color[2] * 2, 16),
+ int(color[3] * 2, 16),
+ int(color[4] * 2, 16),
+ )
+
+ if re.match("#[a-f0-9]{6}$", color):
+ return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
+
+ if re.match("#[a-f0-9]{8}$", color):
+ return (
+ int(color[1:3], 16),
+ int(color[3:5], 16),
+ int(color[5:7], 16),
+ int(color[7:9], 16),
+ )
+
+ m = re.match(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
+ if m:
+ return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
+
+ m = re.match(r"rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
+ if m:
+ return (
+ int((int(m.group(1)) * 255) / 100.0 + 0.5),
+ int((int(m.group(2)) * 255) / 100.0 + 0.5),
+ int((int(m.group(3)) * 255) / 100.0 + 0.5),
+ )
+
+ m = re.match(
+ r"hsl\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color
+ )
+ if m:
+ from colorsys import hls_to_rgb
+
+ rgb = hls_to_rgb(
+ float(m.group(1)) / 360.0,
+ float(m.group(3)) / 100.0,
+ float(m.group(2)) / 100.0,
+ )
+ return (
+ int(rgb[0] * 255 + 0.5),
+ int(rgb[1] * 255 + 0.5),
+ int(rgb[2] * 255 + 0.5),
+ )
+
+ m = re.match(
+ r"hs[bv]\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color
+ )
+ if m:
+ from colorsys import hsv_to_rgb
+
+ rgb = hsv_to_rgb(
+ float(m.group(1)) / 360.0,
+ float(m.group(2)) / 100.0,
+ float(m.group(3)) / 100.0,
+ )
+ return (
+ int(rgb[0] * 255 + 0.5),
+ int(rgb[1] * 255 + 0.5),
+ int(rgb[2] * 255 + 0.5),
+ )
+
+ m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
+ if m:
+ return (int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)))
+ raise ValueError("unknown color specifier: %r" % color)
+
+
+def getcolor(color, mode):
+ """
+ Same as :py:func:`~PIL.ImageColor.getrgb`, but converts the RGB value to a
+ greyscale value if the mode is not color or a palette image. If the string
+ cannot be parsed, this function raises a :py:exc:`ValueError` exception.
+
+ .. versionadded:: 1.1.4
+
+ :param color: A color string
+ :return: ``(graylevel [, alpha]) or (red, green, blue[, alpha])``
+ """
+ # same as getrgb, but converts the result to the given mode
+ color, alpha = getrgb(color), 255
+ if len(color) == 4:
+ color, alpha = color[0:3], color[3]
+
+ if Image.getmodebase(mode) == "L":
+ r, g, b = color
+ color = (r * 299 + g * 587 + b * 114) // 1000
+ if mode[-1] == "A":
+ return (color, alpha)
+ else:
+ if mode[-1] == "A":
+ return color + (alpha,)
+ return color
+
+
+colormap = {
+ # X11 colour table from https://drafts.csswg.org/css-color-4/, with
+ # gray/grey spelling issues fixed. This is a superset of HTML 4.0
+ # colour names used in CSS 1.
+ "aliceblue": "#f0f8ff",
+ "antiquewhite": "#faebd7",
+ "aqua": "#00ffff",
+ "aquamarine": "#7fffd4",
+ "azure": "#f0ffff",
+ "beige": "#f5f5dc",
+ "bisque": "#ffe4c4",
+ "black": "#000000",
+ "blanchedalmond": "#ffebcd",
+ "blue": "#0000ff",
+ "blueviolet": "#8a2be2",
+ "brown": "#a52a2a",
+ "burlywood": "#deb887",
+ "cadetblue": "#5f9ea0",
+ "chartreuse": "#7fff00",
+ "chocolate": "#d2691e",
+ "coral": "#ff7f50",
+ "cornflowerblue": "#6495ed",
+ "cornsilk": "#fff8dc",
+ "crimson": "#dc143c",
+ "cyan": "#00ffff",
+ "darkblue": "#00008b",
+ "darkcyan": "#008b8b",
+ "darkgoldenrod": "#b8860b",
+ "darkgray": "#a9a9a9",
+ "darkgrey": "#a9a9a9",
+ "darkgreen": "#006400",
+ "darkkhaki": "#bdb76b",
+ "darkmagenta": "#8b008b",
+ "darkolivegreen": "#556b2f",
+ "darkorange": "#ff8c00",
+ "darkorchid": "#9932cc",
+ "darkred": "#8b0000",
+ "darksalmon": "#e9967a",
+ "darkseagreen": "#8fbc8f",
+ "darkslateblue": "#483d8b",
+ "darkslategray": "#2f4f4f",
+ "darkslategrey": "#2f4f4f",
+ "darkturquoise": "#00ced1",
+ "darkviolet": "#9400d3",
+ "deeppink": "#ff1493",
+ "deepskyblue": "#00bfff",
+ "dimgray": "#696969",
+ "dimgrey": "#696969",
+ "dodgerblue": "#1e90ff",
+ "firebrick": "#b22222",
+ "floralwhite": "#fffaf0",
+ "forestgreen": "#228b22",
+ "fuchsia": "#ff00ff",
+ "gainsboro": "#dcdcdc",
+ "ghostwhite": "#f8f8ff",
+ "gold": "#ffd700",
+ "goldenrod": "#daa520",
+ "gray": "#808080",
+ "grey": "#808080",
+ "green": "#008000",
+ "greenyellow": "#adff2f",
+ "honeydew": "#f0fff0",
+ "hotpink": "#ff69b4",
+ "indianred": "#cd5c5c",
+ "indigo": "#4b0082",
+ "ivory": "#fffff0",
+ "khaki": "#f0e68c",
+ "lavender": "#e6e6fa",
+ "lavenderblush": "#fff0f5",
+ "lawngreen": "#7cfc00",
+ "lemonchiffon": "#fffacd",
+ "lightblue": "#add8e6",
+ "lightcoral": "#f08080",
+ "lightcyan": "#e0ffff",
+ "lightgoldenrodyellow": "#fafad2",
+ "lightgreen": "#90ee90",
+ "lightgray": "#d3d3d3",
+ "lightgrey": "#d3d3d3",
+ "lightpink": "#ffb6c1",
+ "lightsalmon": "#ffa07a",
+ "lightseagreen": "#20b2aa",
+ "lightskyblue": "#87cefa",
+ "lightslategray": "#778899",
+ "lightslategrey": "#778899",
+ "lightsteelblue": "#b0c4de",
+ "lightyellow": "#ffffe0",
+ "lime": "#00ff00",
+ "limegreen": "#32cd32",
+ "linen": "#faf0e6",
+ "magenta": "#ff00ff",
+ "maroon": "#800000",
+ "mediumaquamarine": "#66cdaa",
+ "mediumblue": "#0000cd",
+ "mediumorchid": "#ba55d3",
+ "mediumpurple": "#9370db",
+ "mediumseagreen": "#3cb371",
+ "mediumslateblue": "#7b68ee",
+ "mediumspringgreen": "#00fa9a",
+ "mediumturquoise": "#48d1cc",
+ "mediumvioletred": "#c71585",
+ "midnightblue": "#191970",
+ "mintcream": "#f5fffa",
+ "mistyrose": "#ffe4e1",
+ "moccasin": "#ffe4b5",
+ "navajowhite": "#ffdead",
+ "navy": "#000080",
+ "oldlace": "#fdf5e6",
+ "olive": "#808000",
+ "olivedrab": "#6b8e23",
+ "orange": "#ffa500",
+ "orangered": "#ff4500",
+ "orchid": "#da70d6",
+ "palegoldenrod": "#eee8aa",
+ "palegreen": "#98fb98",
+ "paleturquoise": "#afeeee",
+ "palevioletred": "#db7093",
+ "papayawhip": "#ffefd5",
+ "peachpuff": "#ffdab9",
+ "peru": "#cd853f",
+ "pink": "#ffc0cb",
+ "plum": "#dda0dd",
+ "powderblue": "#b0e0e6",
+ "purple": "#800080",
+ "rebeccapurple": "#663399",
+ "red": "#ff0000",
+ "rosybrown": "#bc8f8f",
+ "royalblue": "#4169e1",
+ "saddlebrown": "#8b4513",
+ "salmon": "#fa8072",
+ "sandybrown": "#f4a460",
+ "seagreen": "#2e8b57",
+ "seashell": "#fff5ee",
+ "sienna": "#a0522d",
+ "silver": "#c0c0c0",
+ "skyblue": "#87ceeb",
+ "slateblue": "#6a5acd",
+ "slategray": "#708090",
+ "slategrey": "#708090",
+ "snow": "#fffafa",
+ "springgreen": "#00ff7f",
+ "steelblue": "#4682b4",
+ "tan": "#d2b48c",
+ "teal": "#008080",
+ "thistle": "#d8bfd8",
+ "tomato": "#ff6347",
+ "turquoise": "#40e0d0",
+ "violet": "#ee82ee",
+ "wheat": "#f5deb3",
+ "white": "#ffffff",
+ "whitesmoke": "#f5f5f5",
+ "yellow": "#ffff00",
+ "yellowgreen": "#9acd32",
+}
diff --git a/contrib/python/Pillow/py2/PIL/ImageDraw.py b/contrib/python/Pillow/py2/PIL/ImageDraw.py
new file mode 100644
index 0000000000..378f58e5d8
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageDraw.py
@@ -0,0 +1,565 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# drawing interface operations
+#
+# History:
+# 1996-04-13 fl Created (experimental)
+# 1996-08-07 fl Filled polygons, ellipses.
+# 1996-08-13 fl Added text support
+# 1998-06-28 fl Handle I and F images
+# 1998-12-29 fl Added arc; use arc primitive to draw ellipses
+# 1999-01-10 fl Added shape stuff (experimental)
+# 1999-02-06 fl Added bitmap support
+# 1999-02-11 fl Changed all primitives to take options
+# 1999-02-20 fl Fixed backwards compatibility
+# 2000-10-12 fl Copy on write, when necessary
+# 2001-02-18 fl Use default ink for bitmap/text also in fill mode
+# 2002-10-24 fl Added support for CSS-style color strings
+# 2002-12-10 fl Added experimental support for RGBA-on-RGB drawing
+# 2002-12-11 fl Refactored low-level drawing API (work in progress)
+# 2004-08-26 fl Made Draw() a factory function, added getdraw() support
+# 2004-09-04 fl Added width support to line primitive
+# 2004-09-10 fl Added font mode handling
+# 2006-06-19 fl Added font bearing support (getmask2)
+#
+# Copyright (c) 1997-2006 by Secret Labs AB
+# Copyright (c) 1996-2006 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import math
+import numbers
+
+from . import Image, ImageColor
+from ._util import isStringType
+
+
+"""
+A simple 2D drawing interface for PIL images.
+<p>
+Application code should use the <b>Draw</b> factory, instead of
+directly.
+"""
+
+
+class ImageDraw(object):
+ def __init__(self, im, mode=None):
+ """
+ Create a drawing instance.
+
+ :param im: The image to draw in.
+ :param mode: Optional mode to use for color values. For RGB
+ images, this argument can be RGB or RGBA (to blend the
+ drawing into the image). For all other modes, this argument
+ must be the same as the image mode. If omitted, the mode
+ defaults to the mode of the image.
+ """
+ im.load()
+ if im.readonly:
+ im._copy() # make it writeable
+ blend = 0
+ if mode is None:
+ mode = im.mode
+ if mode != im.mode:
+ if mode == "RGBA" and im.mode == "RGB":
+ blend = 1
+ else:
+ raise ValueError("mode mismatch")
+ if mode == "P":
+ self.palette = im.palette
+ else:
+ self.palette = None
+ self.im = im.im
+ self.draw = Image.core.draw(self.im, blend)
+ self.mode = mode
+ if mode in ("I", "F"):
+ self.ink = self.draw.draw_ink(1)
+ else:
+ self.ink = self.draw.draw_ink(-1)
+ if mode in ("1", "P", "I", "F"):
+ # FIXME: fix Fill2 to properly support matte for I+F images
+ self.fontmode = "1"
+ else:
+ self.fontmode = "L" # aliasing is okay for other modes
+ self.fill = 0
+ self.font = None
+
+ def getfont(self):
+ """
+ Get the current default font.
+
+ :returns: An image font."""
+ if not self.font:
+ # FIXME: should add a font repository
+ from . import ImageFont
+
+ self.font = ImageFont.load_default()
+ return self.font
+
+ def _getink(self, ink, fill=None):
+ if ink is None and fill is None:
+ if self.fill:
+ fill = self.ink
+ else:
+ ink = self.ink
+ else:
+ if ink is not None:
+ if isStringType(ink):
+ ink = ImageColor.getcolor(ink, self.mode)
+ if self.palette and not isinstance(ink, numbers.Number):
+ ink = self.palette.getcolor(ink)
+ ink = self.draw.draw_ink(ink)
+ if fill is not None:
+ if isStringType(fill):
+ fill = ImageColor.getcolor(fill, self.mode)
+ if self.palette and not isinstance(fill, numbers.Number):
+ fill = self.palette.getcolor(fill)
+ fill = self.draw.draw_ink(fill)
+ return ink, fill
+
+ def arc(self, xy, start, end, fill=None, width=0):
+ """Draw an arc."""
+ ink, fill = self._getink(fill)
+ if ink is not None:
+ self.draw.draw_arc(xy, start, end, ink, width)
+
+ def bitmap(self, xy, bitmap, fill=None):
+ """Draw a bitmap."""
+ bitmap.load()
+ ink, fill = self._getink(fill)
+ if ink is None:
+ ink = fill
+ if ink is not None:
+ self.draw.draw_bitmap(xy, bitmap.im, ink)
+
+ def chord(self, xy, start, end, fill=None, outline=None, width=0):
+ """Draw a chord."""
+ 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 and ink != fill:
+ self.draw.draw_chord(xy, start, end, ink, 0, width)
+
+ def ellipse(self, xy, fill=None, outline=None, width=0):
+ """Draw an ellipse."""
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_ellipse(xy, fill, 1)
+ if ink is not None and ink != fill:
+ self.draw.draw_ellipse(xy, ink, 0, width)
+
+ def line(self, xy, fill=None, width=0, joint=None):
+ """Draw a line, or a connected sequence of line segments."""
+ ink = self._getink(fill)[0]
+ if ink is not None:
+ self.draw.draw_lines(xy, ink, width)
+ if joint == "curve" and width > 4:
+ for i in range(1, len(xy) - 1):
+ point = xy[i]
+ angles = [
+ math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))
+ % 360
+ for start, end in ((xy[i - 1], point), (point, xy[i + 1]))
+ ]
+ if angles[0] == angles[1]:
+ # This is a straight line, so no joint is required
+ continue
+
+ def coord_at_angle(coord, angle):
+ x, y = coord
+ angle -= 90
+ distance = width / 2 - 1
+ return tuple(
+ [
+ p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))
+ for p, p_d in (
+ (x, distance * math.cos(math.radians(angle))),
+ (y, distance * math.sin(math.radians(angle))),
+ )
+ ]
+ )
+
+ flipped = (
+ angles[1] > angles[0] and angles[1] - 180 > angles[0]
+ ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])
+ coords = [
+ (point[0] - width / 2 + 1, point[1] - width / 2 + 1),
+ (point[0] + width / 2 - 1, point[1] + width / 2 - 1),
+ ]
+ if flipped:
+ start, end = (angles[1] + 90, angles[0] + 90)
+ else:
+ start, end = (angles[0] - 90, angles[1] - 90)
+ self.pieslice(coords, start - 90, end - 90, fill)
+
+ if width > 8:
+ # Cover potential gaps between the line and the joint
+ if flipped:
+ gapCoords = [
+ coord_at_angle(point, angles[0] + 90),
+ point,
+ coord_at_angle(point, angles[1] + 90),
+ ]
+ else:
+ gapCoords = [
+ coord_at_angle(point, angles[0] - 90),
+ point,
+ coord_at_angle(point, angles[1] - 90),
+ ]
+ self.line(gapCoords, fill, width=3)
+
+ def shape(self, shape, fill=None, outline=None):
+ """(Experimental) Draw a shape."""
+ shape.close()
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_outline(shape, fill, 1)
+ 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, width=0):
+ """Draw a pieslice."""
+ 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 and ink != fill:
+ self.draw.draw_pieslice(xy, start, end, ink, 0, width)
+
+ def point(self, xy, fill=None):
+ """Draw one or more individual pixels."""
+ ink, fill = self._getink(fill)
+ if ink is not None:
+ self.draw.draw_points(xy, ink)
+
+ def polygon(self, xy, fill=None, outline=None):
+ """Draw a polygon."""
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_polygon(xy, fill, 1)
+ if ink is not None and ink != fill:
+ self.draw.draw_polygon(xy, ink, 0)
+
+ def rectangle(self, xy, fill=None, outline=None, width=0):
+ """Draw a rectangle."""
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_rectangle(xy, fill, 1)
+ if ink is not None and ink != fill:
+ self.draw.draw_rectangle(xy, ink, 0, width)
+
+ def _multiline_check(self, text):
+ """Draw text."""
+ split_character = "\n" if isinstance(text, str) else b"\n"
+
+ return split_character in text
+
+ def _multiline_split(self, text):
+ split_character = "\n" if isinstance(text, str) else b"\n"
+
+ return text.split(split_character)
+
+ def text(
+ self,
+ xy,
+ text,
+ fill=None,
+ font=None,
+ anchor=None,
+ spacing=4,
+ align="left",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ stroke_fill=None,
+ *args,
+ **kwargs
+ ):
+ if self._multiline_check(text):
+ return self.multiline_text(
+ xy,
+ text,
+ fill,
+ font,
+ anchor,
+ spacing,
+ align,
+ direction,
+ features,
+ language,
+ stroke_width,
+ stroke_fill,
+ )
+
+ if font is None:
+ font = self.getfont()
+
+ def getink(fill):
+ ink, fill = self._getink(fill)
+ if ink is None:
+ return fill
+ return ink
+
+ def draw_text(ink, stroke_width=0, stroke_offset=None):
+ coord = xy
+ try:
+ mask, offset = font.getmask2(
+ text,
+ self.fontmode,
+ direction=direction,
+ features=features,
+ language=language,
+ stroke_width=stroke_width,
+ *args,
+ **kwargs
+ )
+ coord = coord[0] + offset[0], coord[1] + offset[1]
+ except AttributeError:
+ try:
+ mask = font.getmask(
+ text,
+ self.fontmode,
+ direction,
+ features,
+ language,
+ stroke_width,
+ *args,
+ **kwargs
+ )
+ except TypeError:
+ mask = font.getmask(text)
+ if stroke_offset:
+ coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]
+ self.draw.draw_bitmap(coord, mask, ink)
+
+ ink = getink(fill)
+ if ink is not None:
+ stroke_ink = None
+ if stroke_width:
+ stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink
+
+ if stroke_ink is not None:
+ # Draw stroked text
+ draw_text(stroke_ink, stroke_width)
+
+ # Draw normal text
+ draw_text(ink, 0, (stroke_width, stroke_width))
+ else:
+ # Only draw normal text
+ draw_text(ink)
+
+ def multiline_text(
+ self,
+ xy,
+ text,
+ fill=None,
+ font=None,
+ anchor=None,
+ spacing=4,
+ align="left",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ stroke_fill=None,
+ ):
+ widths = []
+ max_width = 0
+ lines = self._multiline_split(text)
+ line_spacing = (
+ self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
+ )
+ for line in lines:
+ line_width, line_height = self.textsize(
+ line,
+ font,
+ direction=direction,
+ features=features,
+ language=language,
+ stroke_width=stroke_width,
+ )
+ widths.append(line_width)
+ max_width = max(max_width, line_width)
+ left, top = xy
+ for idx, line in enumerate(lines):
+ if align == "left":
+ pass # left = x
+ elif align == "center":
+ left += (max_width - widths[idx]) / 2.0
+ elif align == "right":
+ left += max_width - widths[idx]
+ else:
+ raise ValueError('align must be "left", "center" or "right"')
+ self.text(
+ (left, top),
+ line,
+ fill,
+ font,
+ anchor,
+ direction=direction,
+ features=features,
+ language=language,
+ stroke_width=stroke_width,
+ stroke_fill=stroke_fill,
+ )
+ top += line_spacing
+ left = xy[0]
+
+ def textsize(
+ self,
+ text,
+ font=None,
+ spacing=4,
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ ):
+ """Get the size of a given string, in pixels."""
+ if self._multiline_check(text):
+ return self.multiline_textsize(
+ text, font, spacing, direction, features, language, stroke_width
+ )
+
+ if font is None:
+ font = self.getfont()
+ return font.getsize(text, direction, features, language, stroke_width)
+
+ def multiline_textsize(
+ self,
+ text,
+ font=None,
+ spacing=4,
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ ):
+ max_width = 0
+ lines = self._multiline_split(text)
+ line_spacing = (
+ self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
+ )
+ for line in lines:
+ line_width, line_height = self.textsize(
+ line, font, spacing, direction, features, language, stroke_width
+ )
+ max_width = max(max_width, line_width)
+ return max_width, len(lines) * line_spacing
+
+
+def Draw(im, mode=None):
+ """
+ A simple 2D drawing interface for PIL images.
+
+ :param im: The image to draw in.
+ :param mode: Optional mode to use for color values. For RGB
+ images, this argument can be RGB or RGBA (to blend the
+ drawing into the image). For all other modes, this argument
+ must be the same as the image mode. If omitted, the mode
+ defaults to the mode of the image.
+ """
+ try:
+ return im.getdraw(mode)
+ except AttributeError:
+ return ImageDraw(im, mode)
+
+
+# experimental access to the outline API
+try:
+ Outline = Image.core.outline
+except AttributeError:
+ Outline = None
+
+
+def getdraw(im=None, hints=None):
+ """
+ (Experimental) A more advanced 2D drawing interface for PIL images,
+ based on the WCK interface.
+
+ :param im: The image to draw in.
+ :param hints: An optional list of hints.
+ :returns: A (drawing context, drawing resource factory) tuple.
+ """
+ # FIXME: this needs more work!
+ # FIXME: come up with a better 'hints' scheme.
+ handler = None
+ if not hints or "nicest" in hints:
+ try:
+ from . import _imagingagg as handler
+ except ImportError:
+ pass
+ if handler is None:
+ from . import ImageDraw2 as handler
+ if im:
+ im = handler.Draw(im)
+ return im, handler
+
+
+def floodfill(image, xy, value, border=None, thresh=0):
+ """
+ (experimental) Fills a bounded region with a given color.
+
+ :param image: Target image.
+ :param xy: Seed position (a 2-item coordinate tuple). See
+ :ref:`coordinate-system`.
+ :param value: Fill color.
+ :param border: Optional border value. If given, the region consists of
+ pixels with a color different from the border color. If not given,
+ the region consists of pixels having the same color as the seed
+ pixel.
+ :param thresh: Optional threshold value which specifies a maximum
+ tolerable difference of a pixel value from the 'background' in
+ order for it to be replaced. Useful for filling regions of
+ non-homogeneous, but similar, colors.
+ """
+ # based on an implementation by Eric S. Raymond
+ # amended by yo1995 @20180806
+ pixel = image.load()
+ x, y = xy
+ try:
+ background = pixel[x, y]
+ if _color_diff(value, background) <= thresh:
+ return # seed point already has fill color
+ pixel[x, y] = value
+ except (ValueError, IndexError):
+ return # seed point outside image
+ edge = {(x, y)}
+ # use a set to keep record of current and previous edge pixels
+ # to reduce memory consumption
+ full_edge = set()
+ while edge:
+ new_edge = set()
+ for (x, y) in edge: # 4 adjacent method
+ for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
+ # If already processed, or if a coordinate is negative, skip
+ if (s, t) in full_edge or s < 0 or t < 0:
+ continue
+ try:
+ p = pixel[s, t]
+ except (ValueError, IndexError):
+ pass
+ else:
+ full_edge.add((s, t))
+ if border is None:
+ fill = _color_diff(p, background) <= thresh
+ else:
+ fill = p != value and p != border
+ if fill:
+ pixel[s, t] = value
+ new_edge.add((s, t))
+ full_edge = edge # discard pixels processed
+ edge = new_edge
+
+
+def _color_diff(color1, color2):
+ """
+ Uses 1-norm distance to calculate difference between two values.
+ """
+ if isinstance(color2, tuple):
+ return sum([abs(color1[i] - color2[i]) for i in range(0, len(color2))])
+ else:
+ return abs(color1 - color2)
diff --git a/contrib/python/Pillow/py2/PIL/ImageDraw2.py b/contrib/python/Pillow/py2/PIL/ImageDraw2.py
new file mode 100644
index 0000000000..324d869f03
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageDraw2.py
@@ -0,0 +1,107 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# WCK-style drawing interface operations
+#
+# History:
+# 2003-12-07 fl created
+# 2005-05-15 fl updated; added to PIL as ImageDraw2
+# 2005-05-15 fl added text support
+# 2005-05-20 fl added arc/chord/pieslice support
+#
+# Copyright (c) 2003-2005 by Secret Labs AB
+# Copyright (c) 2003-2005 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
+
+
+class Pen(object):
+ def __init__(self, color, width=1, opacity=255):
+ self.color = ImageColor.getrgb(color)
+ self.width = width
+
+
+class Brush(object):
+ def __init__(self, color, opacity=255):
+ self.color = ImageColor.getrgb(color)
+
+
+class Font(object):
+ def __init__(self, color, file, size=12):
+ # FIXME: add support for bitmap fonts
+ self.color = ImageColor.getrgb(color)
+ self.font = ImageFont.truetype(file, size)
+
+
+class Draw(object):
+ def __init__(self, image, size=None, color=None):
+ if not hasattr(image, "im"):
+ image = Image.new(image, size, color)
+ self.draw = ImageDraw.Draw(image)
+ self.image = image
+ self.transform = None
+
+ def flush(self):
+ return self.image
+
+ def render(self, op, xy, pen, brush=None):
+ # handle color arguments
+ outline = fill = None
+ width = 1
+ if isinstance(pen, Pen):
+ outline = pen.color
+ width = pen.width
+ elif isinstance(brush, Pen):
+ outline = brush.color
+ width = brush.width
+ if isinstance(brush, Brush):
+ fill = brush.color
+ elif isinstance(pen, Brush):
+ fill = pen.color
+ # handle transformation
+ if self.transform:
+ xy = ImagePath.Path(xy)
+ xy.transform(self.transform)
+ # render the item
+ if op == "line":
+ self.draw.line(xy, fill=outline, width=width)
+ else:
+ getattr(self.draw, op)(xy, fill=fill, outline=outline)
+
+ def settransform(self, offset):
+ (xoffset, yoffset) = offset
+ self.transform = (1, 0, xoffset, 0, 1, yoffset)
+
+ def arc(self, xy, start, end, *options):
+ self.render("arc", xy, start, end, *options)
+
+ def chord(self, xy, start, end, *options):
+ self.render("chord", xy, start, end, *options)
+
+ def ellipse(self, xy, *options):
+ self.render("ellipse", xy, *options)
+
+ def line(self, xy, *options):
+ self.render("line", xy, *options)
+
+ def pieslice(self, xy, start, end, *options):
+ self.render("pieslice", xy, start, end, *options)
+
+ def polygon(self, xy, *options):
+ self.render("polygon", xy, *options)
+
+ def rectangle(self, xy, *options):
+ self.render("rectangle", xy, *options)
+
+ def text(self, xy, text, font):
+ if self.transform:
+ xy = ImagePath.Path(xy)
+ xy.transform(self.transform)
+ self.draw.text(xy, text, font=font.font, fill=font.color)
+
+ def textsize(self, text, font):
+ return self.draw.textsize(text, font=font.font)
diff --git a/contrib/python/Pillow/py2/PIL/ImageEnhance.py b/contrib/python/Pillow/py2/PIL/ImageEnhance.py
new file mode 100644
index 0000000000..534eb4f16a
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageEnhance.py
@@ -0,0 +1,103 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# image enhancement classes
+#
+# For a background, see "Image Processing By Interpolation and
+# Extrapolation", Paul Haeberli and Douglas Voorhies. Available
+# at http://www.graficaobscura.com/interp/index.html
+#
+# History:
+# 1996-03-23 fl Created
+# 2009-06-16 fl Fixed mean calculation
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFilter, ImageStat
+
+
+class _Enhance(object):
+ def enhance(self, factor):
+ """
+ Returns an enhanced image.
+
+ :param factor: A floating point value controlling the enhancement.
+ Factor 1.0 always returns a copy of the original image,
+ lower factors mean less color (brightness, contrast,
+ etc), and higher values more. There are no restrictions
+ on this value.
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+ return Image.blend(self.degenerate, self.image, factor)
+
+
+class Color(_Enhance):
+ """Adjust image color balance.
+
+ This class can be used to adjust the colour balance of an image, in
+ a manner similar to the controls on a colour TV set. An enhancement
+ factor of 0.0 gives a black and white image. A factor of 1.0 gives
+ the original image.
+ """
+
+ def __init__(self, image):
+ self.image = image
+ self.intermediate_mode = "L"
+ if "A" in image.getbands():
+ self.intermediate_mode = "LA"
+
+ self.degenerate = image.convert(self.intermediate_mode).convert(image.mode)
+
+
+class Contrast(_Enhance):
+ """Adjust image contrast.
+
+ This class can be used to control the contrast of an image, similar
+ to the contrast control on a TV set. An enhancement factor of 0.0
+ gives a solid grey image. A factor of 1.0 gives the original image.
+ """
+
+ def __init__(self, image):
+ self.image = image
+ mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5)
+ self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
+
+ if "A" in image.getbands():
+ self.degenerate.putalpha(image.getchannel("A"))
+
+
+class Brightness(_Enhance):
+ """Adjust image brightness.
+
+ This class can be used to control the brightness of an image. An
+ enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the
+ original image.
+ """
+
+ def __init__(self, image):
+ self.image = image
+ self.degenerate = Image.new(image.mode, image.size, 0)
+
+ if "A" in image.getbands():
+ self.degenerate.putalpha(image.getchannel("A"))
+
+
+class Sharpness(_Enhance):
+ """Adjust image sharpness.
+
+ This class can be used to adjust the sharpness of an image. An
+ enhancement factor of 0.0 gives a blurred image, a factor of 1.0 gives the
+ original image, and a factor of 2.0 gives a sharpened image.
+ """
+
+ def __init__(self, image):
+ self.image = image
+ self.degenerate = image.filter(ImageFilter.SMOOTH)
+
+ if "A" in image.getbands():
+ self.degenerate.putalpha(image.getchannel("A"))
diff --git a/contrib/python/Pillow/py2/PIL/ImageFile.py b/contrib/python/Pillow/py2/PIL/ImageFile.py
new file mode 100644
index 0000000000..836e6318c5
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageFile.py
@@ -0,0 +1,685 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# base class for image file handlers
+#
+# history:
+# 1995-09-09 fl Created
+# 1996-03-11 fl Fixed load mechanism.
+# 1996-04-15 fl Added pcx/xbm decoders.
+# 1996-04-30 fl Added encoders.
+# 1996-12-14 fl Added load helpers
+# 1997-01-11 fl Use encode_to_file where possible
+# 1997-08-27 fl Flush output in _save
+# 1998-03-05 fl Use memory mapping for some modes
+# 1999-02-04 fl Use memory mapping also for "I;16" and "I;16B"
+# 1999-05-31 fl Added image parser
+# 2000-10-12 fl Set readonly flag on memory-mapped images
+# 2002-03-20 fl Use better messages for common decoder errors
+# 2003-04-21 fl Fall back on mmap/map_buffer if map is not available
+# 2003-10-30 fl Added StubImageFile class
+# 2004-02-25 fl Made incremental parser more robust
+#
+# Copyright (c) 1997-2004 by Secret Labs AB
+# Copyright (c) 1995-2004 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+import struct
+import sys
+
+from . import Image
+from ._util import isPath
+
+MAXBLOCK = 65536
+
+SAFEBLOCK = 1024 * 1024
+
+LOAD_TRUNCATED_IMAGES = False
+
+ERRORS = {
+ -1: "image buffer overrun error",
+ -2: "decoding error",
+ -3: "unknown error",
+ -8: "bad configuration",
+ -9: "out of memory error",
+}
+
+
+def raise_ioerror(error):
+ try:
+ message = Image.core.getcodecstatus(error)
+ except AttributeError:
+ message = ERRORS.get(error)
+ if not message:
+ message = "decoder error %d" % error
+ raise IOError(message + " when reading image file")
+
+
+#
+# --------------------------------------------------------------------
+# Helpers
+
+
+def _tilesort(t):
+ # sort on offset
+ return t[2]
+
+
+#
+# --------------------------------------------------------------------
+# ImageFile base class
+
+
+class ImageFile(Image.Image):
+ "Base class for image file format handlers."
+
+ def __init__(self, fp=None, filename=None):
+ Image.Image.__init__(self)
+
+ self._min_frame = 0
+
+ self.custom_mimetype = None
+
+ self.tile = None
+ self.readonly = 1 # until we know better
+
+ self.decoderconfig = ()
+ self.decodermaxblock = MAXBLOCK
+
+ if isPath(fp):
+ # filename
+ self.fp = open(fp, "rb")
+ self.filename = fp
+ self._exclusive_fp = True
+ else:
+ # stream
+ self.fp = fp
+ self.filename = filename
+ # can be overridden
+ self._exclusive_fp = None
+
+ try:
+ self._open()
+ except (
+ IndexError, # end of data
+ TypeError, # end of data (ord)
+ KeyError, # unsupported mode
+ EOFError, # got header but not the first frame
+ struct.error,
+ ) as v:
+ # close the file only if we have opened it this constructor
+ if self._exclusive_fp:
+ self.fp.close()
+ raise SyntaxError(v)
+
+ if not self.mode or self.size[0] <= 0:
+ raise SyntaxError("not identified by this driver")
+
+ def draft(self, mode, size):
+ """Set draft mode"""
+
+ pass
+
+ def get_format_mimetype(self):
+ if self.custom_mimetype:
+ return self.custom_mimetype
+ if self.format is not None:
+ return Image.MIME.get(self.format.upper())
+
+ def verify(self):
+ """Check file integrity"""
+
+ # raise exception if something's wrong. must be called
+ # directly after open, and closes file when finished.
+ if self._exclusive_fp:
+ self.fp.close()
+ self.fp = None
+
+ def load(self):
+ """Load image data based on tile list"""
+
+ pixel = Image.Image.load(self)
+
+ if self.tile is None:
+ raise IOError("cannot load this image")
+ if not self.tile:
+ return pixel
+
+ self.map = None
+ use_mmap = self.filename and len(self.tile) == 1
+ # As of pypy 2.1.0, memory mapping was failing here.
+ use_mmap = use_mmap and not hasattr(sys, "pypy_version_info")
+
+ readonly = 0
+
+ # look for read/seek overrides
+ try:
+ read = self.load_read
+ # don't use mmap if there are custom read/seek functions
+ use_mmap = False
+ except AttributeError:
+ read = self.fp.read
+
+ try:
+ seek = self.load_seek
+ use_mmap = False
+ except AttributeError:
+ seek = self.fp.seek
+
+ 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
+ ):
+ try:
+ if hasattr(Image.core, "map"):
+ # use built-in mapper WIN32 only
+ self.map = Image.core.map(self.filename)
+ self.map.seek(offset)
+ self.im = self.map.readimage(
+ self.mode, self.size, args[1], args[2]
+ )
+ else:
+ # 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.im = Image.core.map_buffer(
+ self.map, self.size, decoder_name, extents, offset, args
+ )
+ readonly = 1
+ # After trashing self.im,
+ # we might need to reload the palette data.
+ if self.palette:
+ self.palette.dirty = 1
+ except (AttributeError, EnvironmentError, ImportError):
+ self.map = None
+
+ self.load_prepare()
+ err_code = -3 # initialize to unknown error
+ if not self.map:
+ # sort tiles in file order
+ self.tile.sort(key=_tilesort)
+
+ try:
+ # FIXME: This is a hack to handle TIFF's JpegTables tag.
+ prefix = self.tile_prefix
+ except AttributeError:
+ prefix = b""
+
+ for decoder_name, extents, offset, args in self.tile:
+ decoder = Image._getdecoder(
+ self.mode, decoder_name, args, self.decoderconfig
+ )
+ try:
+ seek(offset)
+ decoder.setimage(self.im, extents)
+ if decoder.pulls_fd:
+ decoder.setfd(self.fp)
+ status, err_code = decoder.decode(b"")
+ else:
+ b = prefix
+ while True:
+ try:
+ s = read(self.decodermaxblock)
+ except (IndexError, struct.error):
+ # truncated png/gif
+ if LOAD_TRUNCATED_IMAGES:
+ break
+ else:
+ raise IOError("image file is truncated")
+
+ if not s: # truncated jpeg
+ if LOAD_TRUNCATED_IMAGES:
+ break
+ else:
+ raise IOError(
+ "image file is truncated "
+ "(%d bytes not processed)" % len(b)
+ )
+
+ b = b + s
+ n, err_code = decoder.decode(b)
+ if n < 0:
+ break
+ b = b[n:]
+ finally:
+ # Need to cleanup here to prevent leaks
+ decoder.cleanup()
+
+ self.tile = []
+ self.readonly = readonly
+
+ self.load_end()
+
+ if self._exclusive_fp and self._close_exclusive_fp_after_loading:
+ self.fp.close()
+ self.fp = None
+
+ if not self.map and not LOAD_TRUNCATED_IMAGES and err_code < 0:
+ # still raised if decoder fails to return anything
+ raise_ioerror(err_code)
+
+ return Image.Image.load(self)
+
+ def load_prepare(self):
+ # create image memory if necessary
+ if not self.im or self.im.mode != self.mode or self.im.size != self.size:
+ self.im = Image.core.new(self.mode, self.size)
+ # create palette (optional)
+ if self.mode == "P":
+ Image.Image.load(self)
+
+ def load_end(self):
+ # may be overridden
+ pass
+
+ # may be defined for contained formats
+ # def load_seek(self, pos):
+ # pass
+
+ # may be defined for blocked formats (e.g. PNG)
+ # def load_read(self, bytes):
+ # pass
+
+ def _seek_check(self, frame):
+ if (
+ frame < self._min_frame
+ # Only check upper limit on frames if additional seek operations
+ # are not required to do so
+ or (
+ not (hasattr(self, "_n_frames") and self._n_frames is None)
+ and frame >= self.n_frames + self._min_frame
+ )
+ ):
+ raise EOFError("attempt to seek outside sequence")
+
+ return self.tell() != frame
+
+
+class StubImageFile(ImageFile):
+ """
+ Base class for stub image loaders.
+
+ A stub loader is an image loader that can identify files of a
+ certain format, but relies on external code to load the file.
+ """
+
+ def _open(self):
+ raise NotImplementedError("StubImageFile subclass must implement _open")
+
+ def load(self):
+ loader = self._load()
+ if loader is None:
+ raise IOError("cannot find loader for this %s file" % self.format)
+ image = loader.load(self)
+ assert image is not None
+ # become the other object (!)
+ self.__class__ = image.__class__
+ self.__dict__ = image.__dict__
+
+ def _load(self):
+ """(Hook) Find actual image loader."""
+ raise NotImplementedError("StubImageFile subclass must implement _load")
+
+
+class Parser(object):
+ """
+ Incremental image parser. This class implements the standard
+ feed/close consumer interface.
+ """
+
+ incremental = None
+ image = None
+ data = None
+ decoder = None
+ offset = 0
+ finished = 0
+
+ def reset(self):
+ """
+ (Consumer) Reset the parser. Note that you can only call this
+ method immediately after you've created a parser; parser
+ instances cannot be reused.
+ """
+ assert self.data is None, "cannot reuse parsers"
+
+ def feed(self, data):
+ """
+ (Consumer) Feed data to the parser.
+
+ :param data: A string buffer.
+ :exception IOError: If the parser failed to parse the image file.
+ """
+ # collect data
+
+ if self.finished:
+ return
+
+ if self.data is None:
+ self.data = data
+ else:
+ self.data = self.data + data
+
+ # parse what we have
+ if self.decoder:
+
+ if self.offset > 0:
+ # skip header
+ skip = min(len(self.data), self.offset)
+ self.data = self.data[skip:]
+ self.offset = self.offset - skip
+ if self.offset > 0 or not self.data:
+ return
+
+ n, e = self.decoder.decode(self.data)
+
+ if n < 0:
+ # end of stream
+ self.data = None
+ self.finished = 1
+ if e < 0:
+ # decoding error
+ self.image = None
+ raise_ioerror(e)
+ else:
+ # end of image
+ return
+ self.data = self.data[n:]
+
+ elif self.image:
+
+ # if we end up here with no decoder, this file cannot
+ # be incrementally parsed. wait until we've gotten all
+ # available data
+ pass
+
+ else:
+
+ # attempt to open this file
+ try:
+ with io.BytesIO(self.data) as fp:
+ im = Image.open(fp)
+ except IOError:
+ # traceback.print_exc()
+ pass # not enough data
+ else:
+ flag = hasattr(im, "load_seek") or hasattr(im, "load_read")
+ if flag or len(im.tile) != 1:
+ # custom load code, or multiple tiles
+ self.decode = None
+ else:
+ # initialize decoder
+ im.load_prepare()
+ d, e, o, a = im.tile[0]
+ im.tile = []
+ self.decoder = Image._getdecoder(im.mode, d, a, im.decoderconfig)
+ self.decoder.setimage(im.im, e)
+
+ # calculate decoder offset
+ self.offset = o
+ if self.offset <= len(self.data):
+ self.data = self.data[self.offset :]
+ self.offset = 0
+
+ self.image = im
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ def close(self):
+ """
+ (Consumer) Close the stream.
+
+ :returns: An image object.
+ :exception IOError: If the parser failed to parse the image file either
+ because it cannot be identified or cannot be
+ decoded.
+ """
+ # finish decoding
+ if self.decoder:
+ # get rid of what's left in the buffers
+ self.feed(b"")
+ self.data = self.decoder = None
+ if not self.finished:
+ raise IOError("image was incomplete")
+ if not self.image:
+ raise IOError("cannot parse this image")
+ if self.data:
+ # incremental parsing not possible; reopen the file
+ # not that we have all data
+ with io.BytesIO(self.data) as fp:
+ try:
+ self.image = Image.open(fp)
+ finally:
+ self.image.load()
+ return self.image
+
+
+# --------------------------------------------------------------------
+
+
+def _save(im, fp, tile, bufsize=0):
+ """Helper to save image based on tile list
+
+ :param im: Image object.
+ :param fp: File object.
+ :param tile: Tile list.
+ :param bufsize: Optional buffer size
+ """
+
+ im.load()
+ if not hasattr(im, "encoderconfig"):
+ im.encoderconfig = ()
+ tile.sort(key=_tilesort)
+ # FIXME: make MAXBLOCK a configuration parameter
+ # It would be great if we could have the encoder specify what it needs
+ # But, it would need at least the image size in most cases. RawEncode is
+ # a tricky case.
+ bufsize = max(MAXBLOCK, bufsize, im.size[0] * 4) # see RawEncode.c
+ if fp == sys.stdout:
+ fp.flush()
+ return
+ try:
+ fh = fp.fileno()
+ fp.flush()
+ except (AttributeError, io.UnsupportedOperation):
+ # compress to Python file-compatible object
+ for e, b, o, a in tile:
+ e = Image._getencoder(im.mode, e, a, im.encoderconfig)
+ if o > 0:
+ fp.seek(o)
+ e.setimage(im.im, b)
+ if e.pushes_fd:
+ e.setfd(fp)
+ l, s = e.encode_to_pyfd()
+ else:
+ while True:
+ l, s, d = e.encode(bufsize)
+ fp.write(d)
+ if s:
+ break
+ if s < 0:
+ raise IOError("encoder error %d when writing image file" % s)
+ e.cleanup()
+ else:
+ # slight speedup: compress to real file object
+ for e, b, o, a in tile:
+ e = Image._getencoder(im.mode, e, a, im.encoderconfig)
+ if o > 0:
+ fp.seek(o)
+ e.setimage(im.im, b)
+ if e.pushes_fd:
+ e.setfd(fp)
+ l, s = e.encode_to_pyfd()
+ else:
+ s = e.encode_to_file(fh, bufsize)
+ if s < 0:
+ raise IOError("encoder error %d when writing image file" % s)
+ e.cleanup()
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+
+def _safe_read(fp, size):
+ """
+ Reads large blocks in a safe way. Unlike fp.read(n), this function
+ doesn't trust the user. If the requested size is larger than
+ SAFEBLOCK, the file is read block by block.
+
+ :param fp: File handle. Must implement a <b>read</b> method.
+ :param size: Number of bytes to read.
+ :returns: A string containing up to <i>size</i> bytes of data.
+ """
+ if size <= 0:
+ return b""
+ if size <= SAFEBLOCK:
+ return fp.read(size)
+ data = []
+ while size > 0:
+ block = fp.read(min(size, SAFEBLOCK))
+ if not block:
+ break
+ data.append(block)
+ size -= len(block)
+ return b"".join(data)
+
+
+class PyCodecState(object):
+ def __init__(self):
+ self.xsize = 0
+ self.ysize = 0
+ self.xoff = 0
+ self.yoff = 0
+
+ def extents(self):
+ return (self.xoff, self.yoff, self.xoff + self.xsize, self.yoff + self.ysize)
+
+
+class PyDecoder(object):
+ """
+ Python implementation of a format decoder. Override this class and
+ add the decoding logic in the `decode` method.
+
+ See :ref:`Writing Your Own File Decoder in Python<file-decoders-py>`
+ """
+
+ _pulls_fd = False
+
+ def __init__(self, mode, *args):
+ self.im = None
+ self.state = PyCodecState()
+ self.fd = None
+ self.mode = mode
+ self.init(args)
+
+ def init(self, args):
+ """
+ Override to perform decoder specific initialization
+
+ :param args: Array of args items from the tile entry
+ :returns: None
+ """
+ self.args = args
+
+ @property
+ def pulls_fd(self):
+ return self._pulls_fd
+
+ def decode(self, buffer):
+ """
+ Override to perform the decoding process.
+
+ :param buffer: A bytes object with the data to be decoded.
+ :returns: A tuple of (bytes consumed, errcode).
+ If finished with decoding return <0 for the bytes consumed.
+ Err codes are from `ERRORS`
+ """
+ raise NotImplementedError()
+
+ def cleanup(self):
+ """
+ Override to perform decoder specific cleanup
+
+ :returns: None
+ """
+ pass
+
+ def setfd(self, fd):
+ """
+ Called from ImageFile to set the python file-like object
+
+ :param fd: A python file-like object
+ :returns: None
+ """
+ self.fd = fd
+
+ def setimage(self, im, extents=None):
+ """
+ Called from ImageFile to set the core output image for the decoder
+
+ :param im: A core image object
+ :param extents: a 4 tuple of (x0, y0, x1, y1) defining the rectangle
+ for this tile
+ :returns: None
+ """
+
+ # following c code
+ self.im = im
+
+ if extents:
+ (x0, y0, x1, y1) = extents
+ else:
+ (x0, y0, x1, y1) = (0, 0, 0, 0)
+
+ if x0 == 0 and x1 == 0:
+ self.state.xsize, self.state.ysize = self.im.size
+ else:
+ self.state.xoff = x0
+ self.state.yoff = y0
+ self.state.xsize = x1 - x0
+ self.state.ysize = y1 - y0
+
+ if self.state.xsize <= 0 or self.state.ysize <= 0:
+ raise ValueError("Size cannot be negative")
+
+ if (
+ self.state.xsize + self.state.xoff > self.im.size[0]
+ or self.state.ysize + self.state.yoff > self.im.size[1]
+ ):
+ raise ValueError("Tile cannot extend outside image")
+
+ def set_as_raw(self, data, rawmode=None):
+ """
+ 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
+ :returns: None
+ """
+
+ if not rawmode:
+ rawmode = self.mode
+ d = Image._getdecoder(self.mode, "raw", (rawmode))
+ d.setimage(self.im, self.state.extents())
+ s = d.decode(data)
+
+ if s[0] >= 0:
+ raise ValueError("not enough image data")
+ if s[1] != 0:
+ raise ValueError("cannot decode image data")
diff --git a/contrib/python/Pillow/py2/PIL/ImageFilter.py b/contrib/python/Pillow/py2/PIL/ImageFilter.py
new file mode 100644
index 0000000000..fa4162b611
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageFilter.py
@@ -0,0 +1,538 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# standard filters
+#
+# History:
+# 1995-11-27 fl Created
+# 2002-06-08 fl Added rank and mode filters
+# 2003-09-15 fl Fixed rank calculation in rank filter; added expand call
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-2002 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import division
+
+import functools
+
+try:
+ import numpy
+except ImportError: # pragma: no cover
+ numpy = None
+
+
+class Filter(object):
+ pass
+
+
+class MultibandFilter(Filter):
+ pass
+
+
+class BuiltinFilter(MultibandFilter):
+ def filter(self, image):
+ if image.mode == "P":
+ raise ValueError("cannot filter palette images")
+ return image.filter(*self.filterargs)
+
+
+class Kernel(BuiltinFilter):
+ """
+ Create a convolution kernel. The current version only
+ supports 3x3 and 5x5 integer and floating point kernels.
+
+ In the current version, kernels can only be applied to
+ "L" and "RGB" images.
+
+ :param size: Kernel size, given as (width, height). In the current
+ version, this must be (3,3) or (5,5).
+ :param kernel: A sequence containing kernel weights.
+ :param scale: Scale factor. If given, the result for each pixel is
+ divided by this value. the default is the sum of the
+ kernel weights.
+ :param offset: Offset. If given, this value is added to the result,
+ after it has been divided by the scale factor.
+ """
+
+ name = "Kernel"
+
+ def __init__(self, size, kernel, scale=None, offset=0):
+ if scale is None:
+ # default scale is sum of kernel
+ scale = functools.reduce(lambda a, b: a + b, kernel)
+ if size[0] * size[1] != len(kernel):
+ raise ValueError("not enough coefficients in kernel")
+ self.filterargs = size, scale, offset, kernel
+
+
+class RankFilter(Filter):
+ """
+ Create a rank filter. The rank filter sorts all pixels in
+ a window of the given size, and returns the **rank**'th value.
+
+ :param size: The kernel size, in pixels.
+ :param rank: What pixel value to pick. Use 0 for a min filter,
+ ``size * size / 2`` for a median filter, ``size * size - 1``
+ for a max filter, etc.
+ """
+
+ name = "Rank"
+
+ def __init__(self, size, rank):
+ self.size = size
+ self.rank = rank
+
+ def filter(self, image):
+ if image.mode == "P":
+ raise ValueError("cannot filter palette images")
+ image = image.expand(self.size // 2, self.size // 2)
+ return image.rankfilter(self.size, self.rank)
+
+
+class MedianFilter(RankFilter):
+ """
+ Create a median filter. Picks the median pixel value in a window with the
+ given size.
+
+ :param size: The kernel size, in pixels.
+ """
+
+ name = "Median"
+
+ def __init__(self, size=3):
+ self.size = size
+ self.rank = size * size // 2
+
+
+class MinFilter(RankFilter):
+ """
+ Create a min filter. Picks the lowest pixel value in a window with the
+ given size.
+
+ :param size: The kernel size, in pixels.
+ """
+
+ name = "Min"
+
+ def __init__(self, size=3):
+ self.size = size
+ self.rank = 0
+
+
+class MaxFilter(RankFilter):
+ """
+ Create a max filter. Picks the largest pixel value in a window with the
+ given size.
+
+ :param size: The kernel size, in pixels.
+ """
+
+ name = "Max"
+
+ def __init__(self, size=3):
+ self.size = size
+ self.rank = size * size - 1
+
+
+class ModeFilter(Filter):
+ """
+ Create a mode filter. Picks the most frequent pixel value in a box with the
+ given size. Pixel values that occur only once or twice are ignored; if no
+ pixel value occurs more than twice, the original pixel value is preserved.
+
+ :param size: The kernel size, in pixels.
+ """
+
+ name = "Mode"
+
+ def __init__(self, size=3):
+ self.size = size
+
+ def filter(self, image):
+ return image.modefilter(self.size)
+
+
+class GaussianBlur(MultibandFilter):
+ """Gaussian blur filter.
+
+ :param radius: Blur radius.
+ """
+
+ name = "GaussianBlur"
+
+ def __init__(self, radius=2):
+ self.radius = radius
+
+ def filter(self, image):
+ return image.gaussian_blur(self.radius)
+
+
+class BoxBlur(MultibandFilter):
+ """Blurs the image by setting each pixel to the average value of the pixels
+ in a square box extending radius pixels in each direction.
+ Supports float radius of arbitrary size. Uses an optimized implementation
+ which runs in linear time relative to the size of the image
+ for any radius value.
+
+ :param radius: Size of the box in one direction. Radius 0 does not blur,
+ returns an identical image. Radius 1 takes 1 pixel
+ in each direction, i.e. 9 pixels in total.
+ """
+
+ name = "BoxBlur"
+
+ def __init__(self, radius):
+ self.radius = radius
+
+ def filter(self, image):
+ return image.box_blur(self.radius)
+
+
+class UnsharpMask(MultibandFilter):
+ """Unsharp mask filter.
+
+ See Wikipedia's entry on `digital unsharp masking`_ for an explanation of
+ the parameters.
+
+ :param radius: Blur Radius
+ :param percent: Unsharp strength, in percent
+ :param threshold: Threshold controls the minimum brightness change that
+ will be sharpened
+
+ .. _digital unsharp masking: https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking
+
+ """ # noqa: E501
+
+ name = "UnsharpMask"
+
+ def __init__(self, radius=2, percent=150, threshold=3):
+ self.radius = radius
+ self.percent = percent
+ self.threshold = threshold
+
+ def filter(self, image):
+ return image.unsharp_mask(self.radius, self.percent, self.threshold)
+
+
+class BLUR(BuiltinFilter):
+ name = "Blur"
+ # fmt: off
+ filterargs = (5, 5), 16, 0, (
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ )
+ # fmt: on
+
+
+class CONTOUR(BuiltinFilter):
+ name = "Contour"
+ # fmt: off
+ filterargs = (3, 3), 1, 255, (
+ -1, -1, -1,
+ -1, 8, -1,
+ -1, -1, -1,
+ )
+ # fmt: on
+
+
+class DETAIL(BuiltinFilter):
+ name = "Detail"
+ # fmt: off
+ filterargs = (3, 3), 6, 0, (
+ 0, -1, 0,
+ -1, 10, -1,
+ 0, -1, 0,
+ )
+ # fmt: on
+
+
+class EDGE_ENHANCE(BuiltinFilter):
+ name = "Edge-enhance"
+ # fmt: off
+ filterargs = (3, 3), 2, 0, (
+ -1, -1, -1,
+ -1, 10, -1,
+ -1, -1, -1,
+ )
+ # fmt: on
+
+
+class EDGE_ENHANCE_MORE(BuiltinFilter):
+ name = "Edge-enhance More"
+ # fmt: off
+ filterargs = (3, 3), 1, 0, (
+ -1, -1, -1,
+ -1, 9, -1,
+ -1, -1, -1,
+ )
+ # fmt: on
+
+
+class EMBOSS(BuiltinFilter):
+ name = "Emboss"
+ # fmt: off
+ filterargs = (3, 3), 1, 128, (
+ -1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 0,
+ )
+ # fmt: on
+
+
+class FIND_EDGES(BuiltinFilter):
+ name = "Find Edges"
+ # fmt: off
+ filterargs = (3, 3), 1, 0, (
+ -1, -1, -1,
+ -1, 8, -1,
+ -1, -1, -1,
+ )
+ # fmt: on
+
+
+class SHARPEN(BuiltinFilter):
+ name = "Sharpen"
+ # fmt: off
+ filterargs = (3, 3), 16, 0, (
+ -2, -2, -2,
+ -2, 32, -2,
+ -2, -2, -2,
+ )
+ # fmt: on
+
+
+class SMOOTH(BuiltinFilter):
+ name = "Smooth"
+ # fmt: off
+ filterargs = (3, 3), 13, 0, (
+ 1, 1, 1,
+ 1, 5, 1,
+ 1, 1, 1,
+ )
+ # fmt: on
+
+
+class SMOOTH_MORE(BuiltinFilter):
+ name = "Smooth More"
+ # fmt: off
+ filterargs = (5, 5), 100, 0, (
+ 1, 1, 1, 1, 1,
+ 1, 5, 5, 5, 1,
+ 1, 5, 44, 5, 1,
+ 1, 5, 5, 5, 1,
+ 1, 1, 1, 1, 1,
+ )
+ # fmt: on
+
+
+class Color3DLUT(MultibandFilter):
+ """Three-dimensional color lookup table.
+
+ Transforms 3-channel pixels using the values of the channels as coordinates
+ in the 3D lookup table and interpolating the nearest elements.
+
+ This method allows you to apply almost any color transformation
+ in constant time by using pre-calculated decimated tables.
+
+ .. versionadded:: 5.2.0
+
+ :param size: Size of the table. One int or tuple of (int, int, int).
+ Minimal size in any dimension is 2, maximum is 65.
+ :param table: Flat lookup table. A list of ``channels * size**3``
+ float elements or a list of ``size**3`` channels-sized
+ tuples with floats. Channels are changed first,
+ then first dimension, then second, then third.
+ Value 0.0 corresponds lowest value of output, 1.0 highest.
+ :param channels: Number of channels in the table. Could be 3 or 4.
+ Default is 3.
+ :param target_mode: A mode for the result image. Should have not less
+ than ``channels`` channels. Default is ``None``,
+ which means that mode wouldn't be changed.
+ """
+
+ name = "Color 3D LUT"
+
+ def __init__(self, size, table, channels=3, target_mode=None, **kwargs):
+ if channels not in (3, 4):
+ raise ValueError("Only 3 or 4 output channels are supported")
+ self.size = size = self._check_size(size)
+ self.channels = channels
+ self.mode = target_mode
+
+ # Hidden flag `_copy_table=False` could be used to avoid extra copying
+ # of the table if the table is specially made for the constructor.
+ copy_table = kwargs.get("_copy_table", True)
+ items = size[0] * size[1] * size[2]
+ wrong_size = False
+
+ if numpy and isinstance(table, numpy.ndarray):
+ if copy_table:
+ table = table.copy()
+
+ if table.shape in [
+ (items * channels,),
+ (items, channels),
+ (size[2], size[1], size[0], channels),
+ ]:
+ table = table.reshape(items * channels)
+ else:
+ wrong_size = True
+
+ else:
+ if copy_table:
+ table = list(table)
+
+ # Convert to a flat list
+ if table and isinstance(table[0], (list, tuple)):
+ table, raw_table = [], table
+ for pixel in raw_table:
+ if len(pixel) != channels:
+ raise ValueError(
+ "The elements of the table should "
+ "have a length of {}.".format(channels)
+ )
+ table.extend(pixel)
+
+ if wrong_size or len(table) != items * channels:
+ raise ValueError(
+ "The table should have either channels * size**3 float items "
+ "or size**3 items of channels-sized tuples with floats. "
+ "Table should be: {}x{}x{}x{}. Actual length: {}".format(
+ channels, size[0], size[1], size[2], len(table)
+ )
+ )
+ self.table = table
+
+ @staticmethod
+ def _check_size(size):
+ try:
+ _, _, _ = size
+ except ValueError:
+ raise ValueError(
+ "Size should be either an integer or a tuple of three integers."
+ )
+ except TypeError:
+ size = (size, size, size)
+ size = [int(x) for x in size]
+ for size1D in size:
+ if not 2 <= size1D <= 65:
+ raise ValueError("Size should be in [2, 65] range.")
+ return size
+
+ @classmethod
+ def generate(cls, size, callback, channels=3, target_mode=None):
+ """Generates new LUT using provided callback.
+
+ :param size: Size of the table. Passed to the constructor.
+ :param callback: Function with three parameters which correspond
+ three color channels. Will be called ``size**3``
+ times with values from 0.0 to 1.0 and should return
+ a tuple with ``channels`` elements.
+ :param channels: The number of channels which should return callback.
+ :param target_mode: Passed to the constructor of the resulting
+ lookup table.
+ """
+ size1D, size2D, size3D = cls._check_size(size)
+ if channels not in (3, 4):
+ raise ValueError("Only 3 or 4 output channels are supported")
+
+ table = [0] * (size1D * size2D * size3D * channels)
+ idx_out = 0
+ for b in range(size3D):
+ for g in range(size2D):
+ for r in range(size1D):
+ table[idx_out : idx_out + channels] = callback(
+ r / (size1D - 1), g / (size2D - 1), b / (size3D - 1)
+ )
+ idx_out += channels
+
+ return cls(
+ (size1D, size2D, size3D),
+ table,
+ channels=channels,
+ target_mode=target_mode,
+ _copy_table=False,
+ )
+
+ def transform(self, callback, with_normals=False, channels=None, target_mode=None):
+ """Transforms the table values using provided callback and returns
+ a new LUT with altered values.
+
+ :param callback: A function which takes old lookup table values
+ and returns a new set of values. The number
+ of arguments which function should take is
+ ``self.channels`` or ``3 + self.channels``
+ if ``with_normals`` flag is set.
+ Should return a tuple of ``self.channels`` or
+ ``channels`` elements if it is set.
+ :param with_normals: If true, ``callback`` will be called with
+ coordinates in the color cube as the first
+ three arguments. Otherwise, ``callback``
+ will be called only with actual color values.
+ :param channels: The number of channels in the resulting lookup table.
+ :param target_mode: Passed to the constructor of the resulting
+ lookup table.
+ """
+ if channels not in (None, 3, 4):
+ raise ValueError("Only 3 or 4 output channels are supported")
+ ch_in = self.channels
+ ch_out = channels or ch_in
+ size1D, size2D, size3D = self.size
+
+ table = [0] * (size1D * size2D * size3D * ch_out)
+ idx_in = 0
+ idx_out = 0
+ for b in range(size3D):
+ for g in range(size2D):
+ for r in range(size1D):
+ values = self.table[idx_in : idx_in + ch_in]
+ if with_normals:
+ values = callback(
+ r / (size1D - 1),
+ g / (size2D - 1),
+ b / (size3D - 1),
+ *values
+ )
+ else:
+ values = callback(*values)
+ table[idx_out : idx_out + ch_out] = values
+ idx_in += ch_in
+ idx_out += ch_out
+
+ return type(self)(
+ self.size,
+ table,
+ channels=ch_out,
+ target_mode=target_mode or self.mode,
+ _copy_table=False,
+ )
+
+ def __repr__(self):
+ r = [
+ "{} from {}".format(self.__class__.__name__, self.table.__class__.__name__),
+ "size={:d}x{:d}x{:d}".format(*self.size),
+ "channels={:d}".format(self.channels),
+ ]
+ if self.mode:
+ r.append("target_mode={}".format(self.mode))
+ return "<{}>".format(" ".join(r))
+
+ def filter(self, image):
+ from . import Image
+
+ return image.color_lut_3d(
+ self.mode or image.mode,
+ Image.LINEAR,
+ self.channels,
+ self.size[0],
+ self.size[1],
+ self.size[2],
+ self.table,
+ )
diff --git a/contrib/python/Pillow/py2/PIL/ImageFont.py b/contrib/python/Pillow/py2/PIL/ImageFont.py
new file mode 100644
index 0000000000..5cce9af8e4
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageFont.py
@@ -0,0 +1,851 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PIL raster font management
+#
+# History:
+# 1996-08-07 fl created (experimental)
+# 1997-08-25 fl minor adjustments to handle fonts from pilfont 0.3
+# 1999-02-06 fl rewrote most font management stuff in C
+# 1999-03-17 fl take pth files into account in load_path (from Richard Jones)
+# 2001-02-17 fl added freetype support
+# 2001-05-09 fl added TransposedFont wrapper class
+# 2002-03-04 fl make sure we have a "L" or "1" font
+# 2002-12-04 fl skip non-directory entries in the system path
+# 2003-04-29 fl add embedded default font
+# 2003-09-27 fl added support for truetype charmap encodings
+#
+# Todo:
+# Adapt to PILFONT2 format (16-bit fonts, compressed, single file)
+#
+# Copyright (c) 1997-2003 by Secret Labs AB
+# Copyright (c) 1996-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import os
+import sys
+
+from . import Image
+from ._util import isDirectory, isPath, py3
+
+LAYOUT_BASIC = 0
+LAYOUT_RAQM = 1
+
+
+class _imagingft_not_installed(object):
+ # module placeholder
+ def __getattr__(self, id):
+ raise ImportError("The _imagingft C module is not installed")
+
+
+try:
+ from . import _imagingft as core
+except ImportError:
+ core = _imagingft_not_installed()
+
+
+# FIXME: add support for pilfont2 format (see FontFile.py)
+
+# --------------------------------------------------------------------
+# Font metrics format:
+# "PILfont" LF
+# fontdescriptor LF
+# (optional) key=value... LF
+# "DATA" LF
+# binary data: 256*10*2 bytes (dx, dy, dstbox, srcbox)
+#
+# To place a character, cut out srcbox and paste at dstbox,
+# relative to the character position. Then move the character
+# position according to dx, dy.
+# --------------------------------------------------------------------
+
+
+class ImageFont(object):
+ "PIL font wrapper"
+
+ def _load_pilfont(self, filename):
+
+ with open(filename, "rb") as fp:
+ for ext in (".png", ".gif", ".pbm"):
+ try:
+ fullname = os.path.splitext(filename)[0] + ext
+ image = Image.open(fullname)
+ except Exception:
+ pass
+ else:
+ if image and image.mode in ("1", "L"):
+ break
+ else:
+ raise IOError("cannot find glyph data file")
+
+ self.file = fullname
+
+ return self._load_pilfont_data(fp, image)
+
+ def _load_pilfont_data(self, file, image):
+
+ # read PILfont header
+ if file.readline() != b"PILfont\n":
+ raise SyntaxError("Not a PILfont file")
+ file.readline().split(b";")
+ self.info = [] # FIXME: should be a dictionary
+ while True:
+ s = file.readline()
+ if not s or s == b"DATA\n":
+ break
+ self.info.append(s)
+
+ # read PILfont metrics
+ data = file.read(256 * 20)
+
+ # check image
+ if image.mode not in ("1", "L"):
+ raise TypeError("invalid font image mode")
+
+ image.load()
+
+ self.font = Image.core.font(image.im, data)
+
+ def getsize(self, text, *args, **kwargs):
+ """
+ Returns width and height (in pixels) of given text.
+
+ :param text: Text to measure.
+
+ :return: (width, height)
+ """
+ return self.font.getsize(text)
+
+ def getmask(self, text, mode="", *args, **kwargs):
+ """
+ Create a bitmap for the text.
+
+ If the font uses antialiasing, the bitmap should have mode ``L`` and use a
+ maximum value of 255. Otherwise, it should have mode ``1``.
+
+ :param text: Text to render.
+ :param mode: Used by some graphics drivers to indicate what mode the
+ driver prefers; if empty, the renderer may return either
+ mode. Note that the mode is always a string, to simplify
+ C-level implementations.
+
+ .. versionadded:: 1.1.5
+
+ :return: An internal PIL storage memory instance as defined by the
+ :py:mod:`PIL.Image.core` interface module.
+ """
+ return self.font.getmask(text, mode)
+
+
+##
+# Wrapper for FreeType fonts. Application code should use the
+# <b>truetype</b> factory function to create font objects.
+
+
+class FreeTypeFont(object):
+ "FreeType font wrapper (requires _imagingft service)"
+
+ def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None):
+ # FIXME: use service provider instead
+
+ self.path = font
+ self.size = size
+ self.index = index
+ self.encoding = encoding
+
+ if layout_engine not in (LAYOUT_BASIC, LAYOUT_RAQM):
+ layout_engine = LAYOUT_BASIC
+ if core.HAVE_RAQM:
+ layout_engine = LAYOUT_RAQM
+ elif layout_engine == LAYOUT_RAQM and not core.HAVE_RAQM:
+ layout_engine = LAYOUT_BASIC
+
+ self.layout_engine = layout_engine
+
+ def load_from_bytes(f):
+ self.font_bytes = f.read()
+ self.font = core.getfont(
+ "", size, index, encoding, self.font_bytes, layout_engine
+ )
+
+ if isPath(font):
+ if sys.platform == "win32":
+ font_bytes_path = font if isinstance(font, bytes) else font.encode()
+ try:
+ font_bytes_path.decode("ascii")
+ except UnicodeDecodeError:
+ # FreeType cannot load fonts with non-ASCII characters on Windows
+ # So load it into memory first
+ with open(font, "rb") as f:
+ load_from_bytes(f)
+ return
+ self.font = core.getfont(
+ font, size, index, encoding, layout_engine=layout_engine
+ )
+ else:
+ load_from_bytes(font)
+
+ def _multiline_split(self, text):
+ split_character = "\n" if isinstance(text, str) else b"\n"
+ return text.split(split_character)
+
+ def getname(self):
+ """
+ :return: A tuple of the font family (e.g. Helvetica) and the font style
+ (e.g. Bold)
+ """
+ return self.font.family, self.font.style
+
+ def getmetrics(self):
+ """
+ :return: A tuple of the font ascent (the distance from the baseline to
+ the highest outline point) and descent (the distance from the
+ baseline to the lowest outline point, a negative value)
+ """
+ return self.font.ascent, self.font.descent
+
+ def getsize(
+ self, text, direction=None, features=None, language=None, stroke_width=0
+ ):
+ """
+ Returns width and height (in pixels) of given text if rendered in font with
+ provided direction, features, and language.
+
+ :param text: Text to measure.
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ <https://www.w3.org/International/articles/language-tags/>`
+ Requires libraqm.
+
+ .. versionadded:: 6.0.0
+
+ :param stroke_width: The width of the text stroke.
+
+ .. versionadded:: 6.2.0
+
+ :return: (width, height)
+ """
+ size, offset = self.font.getsize(text, direction, features, language)
+ return (
+ size[0] + stroke_width * 2 + offset[0],
+ size[1] + stroke_width * 2 + offset[1],
+ )
+
+ def getsize_multiline(
+ self,
+ text,
+ direction=None,
+ spacing=4,
+ features=None,
+ language=None,
+ stroke_width=0,
+ ):
+ """
+ Returns width and height (in pixels) of given text if rendered in font
+ with provided direction, features, and language, while respecting
+ newline characters.
+
+ :param text: Text to measure.
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ :param spacing: The vertical gap between lines, defaulting to 4 pixels.
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ <https://www.w3.org/International/articles/language-tags/>`
+ Requires libraqm.
+
+ .. versionadded:: 6.0.0
+
+ :param stroke_width: The width of the text stroke.
+
+ .. versionadded:: 6.2.0
+
+ :return: (width, height)
+ """
+ max_width = 0
+ lines = self._multiline_split(text)
+ line_spacing = self.getsize("A", stroke_width=stroke_width)[1] + spacing
+ for line in lines:
+ line_width, line_height = self.getsize(
+ line, direction, features, language, stroke_width
+ )
+ max_width = max(max_width, line_width)
+
+ return max_width, len(lines) * line_spacing - spacing
+
+ def getoffset(self, text):
+ """
+ Returns the offset of given text. This is the gap between the
+ starting coordinate and the first marking. Note that this gap is
+ included in the result of :py:func:`~PIL.ImageFont.FreeTypeFont.getsize`.
+
+ :param text: Text to measure.
+
+ :return: A tuple of the x and y offset
+ """
+ return self.font.getsize(text)[1]
+
+ def getmask(
+ self,
+ text,
+ mode="",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ ):
+ """
+ Create a bitmap for the text.
+
+ If the font uses antialiasing, the bitmap should have mode ``L`` and use a
+ maximum value of 255. Otherwise, it should have mode ``1``.
+
+ :param text: Text to render.
+ :param mode: Used by some graphics drivers to indicate what mode the
+ driver prefers; if empty, the renderer may return either
+ mode. Note that the mode is always a string, to simplify
+ C-level implementations.
+
+ .. versionadded:: 1.1.5
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ <https://www.w3.org/International/articles/language-tags/>`
+ Requires libraqm.
+
+ .. versionadded:: 6.0.0
+
+ :param stroke_width: The width of the text stroke.
+
+ .. versionadded:: 6.2.0
+
+ :return: An internal PIL storage memory instance as defined by the
+ :py:mod:`PIL.Image.core` interface module.
+ """
+ return self.getmask2(
+ text,
+ mode,
+ direction=direction,
+ features=features,
+ language=language,
+ stroke_width=stroke_width,
+ )[0]
+
+ def getmask2(
+ self,
+ text,
+ mode="",
+ fill=Image.core.fill,
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ *args,
+ **kwargs
+ ):
+ """
+ Create a bitmap for the text.
+
+ If the font uses antialiasing, the bitmap should have mode ``L`` and use a
+ maximum value of 255. Otherwise, it should have mode ``1``.
+
+ :param text: Text to render.
+ :param mode: Used by some graphics drivers to indicate what mode the
+ driver prefers; if empty, the renderer may return either
+ mode. Note that the mode is always a string, to simplify
+ C-level implementations.
+
+ .. versionadded:: 1.1.5
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ <https://www.w3.org/International/articles/language-tags/>`
+ Requires libraqm.
+
+ .. versionadded:: 6.0.0
+
+ :param stroke_width: The width of the text stroke.
+
+ .. versionadded:: 6.2.0
+
+ :return: A tuple of an internal PIL storage memory instance as defined by the
+ :py:mod:`PIL.Image.core` interface module, and the text offset, the
+ gap between the starting coordinate and the first marking
+ """
+ size, offset = self.font.getsize(text, direction, features, language)
+ size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
+ im = fill("L", size, 0)
+ self.font.render(
+ text, im.id, mode == "1", direction, features, language, stroke_width
+ )
+ return im, offset
+
+ def font_variant(
+ self, font=None, size=None, index=None, encoding=None, layout_engine=None
+ ):
+ """
+ Create a copy of this FreeTypeFont object,
+ using any specified arguments to override the settings.
+
+ Parameters are identical to the parameters used to initialize this
+ 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=layout_engine or self.layout_engine,
+ )
+
+ def get_variation_names(self):
+ """
+ :returns: A list of the named styles in a variation font.
+ :exception IOError: If the font is not a variation font.
+ """
+ try:
+ names = self.font.getvarnames()
+ except AttributeError:
+ raise NotImplementedError("FreeType 2.9.1 or greater is required")
+ return [name.replace(b"\x00", b"") for name in names]
+
+ def set_variation_by_name(self, name):
+ """
+ :param name: The name of the style.
+ :exception IOError: If the font is not a variation font.
+ """
+ names = self.get_variation_names()
+ if not isinstance(name, bytes):
+ name = name.encode()
+ index = names.index(name)
+
+ if index == getattr(self, "_last_variation_index", None):
+ # When the same name is set twice in a row,
+ # there is an 'unknown freetype error'
+ # https://savannah.nongnu.org/bugs/?56186
+ return
+ self._last_variation_index = index
+
+ self.font.setvarname(index)
+
+ def get_variation_axes(self):
+ """
+ :returns: A list of the axes in a variation font.
+ :exception IOError: If the font is not a variation font.
+ """
+ try:
+ axes = self.font.getvaraxes()
+ except AttributeError:
+ raise NotImplementedError("FreeType 2.9.1 or greater is required")
+ for axis in axes:
+ axis["name"] = axis["name"].replace(b"\x00", b"")
+ return axes
+
+ def set_variation_by_axes(self, axes):
+ """
+ :param axes: A list of values for each axis.
+ :exception IOError: If the font is not a variation font.
+ """
+ try:
+ self.font.setvaraxes(axes)
+ except AttributeError:
+ raise NotImplementedError("FreeType 2.9.1 or greater is required")
+
+
+class TransposedFont(object):
+ "Wrapper for writing rotated or mirrored text"
+
+ def __init__(self, font, orientation=None):
+ """
+ Wrapper that creates a transposed font from any existing font
+ object.
+
+ :param font: A font object.
+ :param orientation: An optional orientation. If given, this should
+ be one of Image.FLIP_LEFT_RIGHT, Image.FLIP_TOP_BOTTOM,
+ Image.ROTATE_90, Image.ROTATE_180, or Image.ROTATE_270.
+ """
+ self.font = font
+ self.orientation = orientation # any 'transpose' argument, or None
+
+ def getsize(self, text, *args, **kwargs):
+ w, h = self.font.getsize(text)
+ if self.orientation in (Image.ROTATE_90, Image.ROTATE_270):
+ return h, w
+ return w, h
+
+ def getmask(self, text, mode="", *args, **kwargs):
+ im = self.font.getmask(text, mode, *args, **kwargs)
+ if self.orientation is not None:
+ return im.transpose(self.orientation)
+ return im
+
+
+def load(filename):
+ """
+ Load a font file. This function loads a font object from the given
+ bitmap font file, and returns the corresponding font object.
+
+ :param filename: Name of font file.
+ :return: A font object.
+ :exception IOError: If the file could not be read.
+ """
+ f = ImageFont()
+ f._load_pilfont(filename)
+ return f
+
+
+def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
+ """
+ Load a TrueType or OpenType font from a file or file-like object,
+ and create a font object.
+ This function loads a font object from the given file or file-like
+ object, and creates a font object for a font of the given size.
+
+ Pillow uses FreeType to open font files. If you are opening many fonts
+ simultaneously on Windows, be aware that Windows limits the number of files
+ that can be open in C at once to 512. If you approach that limit, an
+ ``OSError`` may be thrown, reporting that FreeType "cannot open resource".
+
+ This function requires the _imagingft service.
+
+ :param font: A filename or file-like object containing a TrueType font.
+ If the file is not found in this filename, the loader may also
+ search in other directories, such as the :file:`fonts/`
+ directory on Windows or :file:`/Library/Fonts/`,
+ :file:`/System/Library/Fonts/` and :file:`~/Library/Fonts/` on
+ macOS.
+
+ :param size: The requested size, in points.
+ :param index: Which font face to load (default is first available face).
+ :param encoding: Which font encoding to use (default is Unicode). Possible
+ encodings include (see the FreeType documentation for more
+ information):
+
+ * "unic" (Unicode)
+ * "symb" (Microsoft Symbol)
+ * "ADOB" (Adobe Standard)
+ * "ADBE" (Adobe Expert)
+ * "ADBC" (Adobe Custom)
+ * "armn" (Apple Roman)
+ * "sjis" (Shift JIS)
+ * "gb " (PRC)
+ * "big5"
+ * "wans" (Extended Wansung)
+ * "joha" (Johab)
+ * "lat1" (Latin-1)
+
+ This specifies the character set to use. It does not alter the
+ encoding of any text provided in subsequent operations.
+ :param layout_engine: Which layout engine to use, if available:
+ `ImageFont.LAYOUT_BASIC` or `ImageFont.LAYOUT_RAQM`.
+ :return: A font object.
+ :exception IOError: If the file could not be read.
+ """
+
+ def freetype(font):
+ return FreeTypeFont(font, size, index, encoding, layout_engine)
+
+ try:
+ return freetype(font)
+ except IOError:
+ if not isPath(font):
+ raise
+ ttf_filename = os.path.basename(font)
+
+ dirs = []
+ if sys.platform == "win32":
+ # check the windows font repository
+ # NOTE: must use uppercase WINDIR, to work around bugs in
+ # 1.5.2's os.environ.get()
+ windir = os.environ.get("WINDIR")
+ if windir:
+ dirs.append(os.path.join(windir, "fonts"))
+ elif sys.platform in ("linux", "linux2"):
+ lindirs = os.environ.get("XDG_DATA_DIRS", "")
+ if not lindirs:
+ # According to the freedesktop spec, XDG_DATA_DIRS should
+ # default to /usr/share
+ lindirs = "/usr/share"
+ dirs += [os.path.join(lindir, "fonts") for lindir in lindirs.split(":")]
+ elif sys.platform == "darwin":
+ dirs += [
+ "/Library/Fonts",
+ "/System/Library/Fonts",
+ os.path.expanduser("~/Library/Fonts"),
+ ]
+
+ ext = os.path.splitext(ttf_filename)[1]
+ first_font_with_a_different_extension = None
+ for directory in dirs:
+ for walkroot, walkdir, walkfilenames in os.walk(directory):
+ for walkfilename in walkfilenames:
+ if ext and walkfilename == ttf_filename:
+ return freetype(os.path.join(walkroot, walkfilename))
+ 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 freetype(fontpath)
+ 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 freetype(first_font_with_a_different_extension)
+ raise
+
+
+def load_path(filename):
+ """
+ Load font file. Same as :py:func:`~PIL.ImageFont.load`, but searches for a
+ bitmap font along the Python path.
+
+ :param filename: Name of font file.
+ :return: A font object.
+ :exception IOError: If the file could not be read.
+ """
+ for directory in sys.path:
+ if isDirectory(directory):
+ if not isinstance(filename, str):
+ if py3:
+ filename = filename.decode("utf-8")
+ else:
+ filename = filename.encode("utf-8")
+ try:
+ return load(os.path.join(directory, filename))
+ except IOError:
+ pass
+ raise IOError("cannot find font file")
+
+
+def load_default():
+ """Load a "better than nothing" default font.
+
+ .. versionadded:: 1.1.4
+
+ :return: A font object.
+ """
+ from io import BytesIO
+ import base64
+
+ f = ImageFont()
+ f._load_pilfont_data(
+ # courB08
+ BytesIO(
+ base64.b64decode(
+ b"""
+UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAA//8AAQAAAAAAAAABAAEA
+BgAAAAH/+gADAAAAAQAAAAMABgAGAAAAAf/6AAT//QADAAAABgADAAYAAAAA//kABQABAAYAAAAL
+AAgABgAAAAD/+AAFAAEACwAAABAACQAGAAAAAP/5AAUAAAAQAAAAFQAHAAYAAP////oABQAAABUA
+AAAbAAYABgAAAAH/+QAE//wAGwAAAB4AAwAGAAAAAf/5AAQAAQAeAAAAIQAIAAYAAAAB//kABAAB
+ACEAAAAkAAgABgAAAAD/+QAE//0AJAAAACgABAAGAAAAAP/6AAX//wAoAAAALQAFAAYAAAAB//8A
+BAACAC0AAAAwAAMABgAAAAD//AAF//0AMAAAADUAAQAGAAAAAf//AAMAAAA1AAAANwABAAYAAAAB
+//kABQABADcAAAA7AAgABgAAAAD/+QAFAAAAOwAAAEAABwAGAAAAAP/5AAYAAABAAAAARgAHAAYA
+AAAA//kABQAAAEYAAABLAAcABgAAAAD/+QAFAAAASwAAAFAABwAGAAAAAP/5AAYAAABQAAAAVgAH
+AAYAAAAA//kABQAAAFYAAABbAAcABgAAAAD/+QAFAAAAWwAAAGAABwAGAAAAAP/5AAUAAABgAAAA
+ZQAHAAYAAAAA//kABQAAAGUAAABqAAcABgAAAAD/+QAFAAAAagAAAG8ABwAGAAAAAf/8AAMAAABv
+AAAAcQAEAAYAAAAA//wAAwACAHEAAAB0AAYABgAAAAD/+gAE//8AdAAAAHgABQAGAAAAAP/7AAT/
+/gB4AAAAfAADAAYAAAAB//oABf//AHwAAACAAAUABgAAAAD/+gAFAAAAgAAAAIUABgAGAAAAAP/5
+AAYAAQCFAAAAiwAIAAYAAP////oABgAAAIsAAACSAAYABgAA////+gAFAAAAkgAAAJgABgAGAAAA
+AP/6AAUAAACYAAAAnQAGAAYAAP////oABQAAAJ0AAACjAAYABgAA////+gAFAAAAowAAAKkABgAG
+AAD////6AAUAAACpAAAArwAGAAYAAAAA//oABQAAAK8AAAC0AAYABgAA////+gAGAAAAtAAAALsA
+BgAGAAAAAP/6AAQAAAC7AAAAvwAGAAYAAP////oABQAAAL8AAADFAAYABgAA////+gAGAAAAxQAA
+AMwABgAGAAD////6AAUAAADMAAAA0gAGAAYAAP////oABQAAANIAAADYAAYABgAA////+gAGAAAA
+2AAAAN8ABgAGAAAAAP/6AAUAAADfAAAA5AAGAAYAAP////oABQAAAOQAAADqAAYABgAAAAD/+gAF
+AAEA6gAAAO8ABwAGAAD////6AAYAAADvAAAA9gAGAAYAAAAA//oABQAAAPYAAAD7AAYABgAA////
++gAFAAAA+wAAAQEABgAGAAD////6AAYAAAEBAAABCAAGAAYAAP////oABgAAAQgAAAEPAAYABgAA
+////+gAGAAABDwAAARYABgAGAAAAAP/6AAYAAAEWAAABHAAGAAYAAP////oABgAAARwAAAEjAAYA
+BgAAAAD/+gAFAAABIwAAASgABgAGAAAAAf/5AAQAAQEoAAABKwAIAAYAAAAA//kABAABASsAAAEv
+AAgABgAAAAH/+QAEAAEBLwAAATIACAAGAAAAAP/5AAX//AEyAAABNwADAAYAAAAAAAEABgACATcA
+AAE9AAEABgAAAAH/+QAE//wBPQAAAUAAAwAGAAAAAP/7AAYAAAFAAAABRgAFAAYAAP////kABQAA
+AUYAAAFMAAcABgAAAAD/+wAFAAABTAAAAVEABQAGAAAAAP/5AAYAAAFRAAABVwAHAAYAAAAA//sA
+BQAAAVcAAAFcAAUABgAAAAD/+QAFAAABXAAAAWEABwAGAAAAAP/7AAYAAgFhAAABZwAHAAYAAP//
+//kABQAAAWcAAAFtAAcABgAAAAD/+QAGAAABbQAAAXMABwAGAAAAAP/5AAQAAgFzAAABdwAJAAYA
+AP////kABgAAAXcAAAF+AAcABgAAAAD/+QAGAAABfgAAAYQABwAGAAD////7AAUAAAGEAAABigAF
+AAYAAP////sABQAAAYoAAAGQAAUABgAAAAD/+wAFAAABkAAAAZUABQAGAAD////7AAUAAgGVAAAB
+mwAHAAYAAAAA//sABgACAZsAAAGhAAcABgAAAAD/+wAGAAABoQAAAacABQAGAAAAAP/7AAYAAAGn
+AAABrQAFAAYAAAAA//kABgAAAa0AAAGzAAcABgAA////+wAGAAABswAAAboABQAGAAD////7AAUA
+AAG6AAABwAAFAAYAAP////sABgAAAcAAAAHHAAUABgAAAAD/+wAGAAABxwAAAc0ABQAGAAD////7
+AAYAAgHNAAAB1AAHAAYAAAAA//sABQAAAdQAAAHZAAUABgAAAAH/+QAFAAEB2QAAAd0ACAAGAAAA
+Av/6AAMAAQHdAAAB3gAHAAYAAAAA//kABAABAd4AAAHiAAgABgAAAAD/+wAF//0B4gAAAecAAgAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAB
+//sAAwACAecAAAHpAAcABgAAAAD/+QAFAAEB6QAAAe4ACAAGAAAAAP/5AAYAAAHuAAAB9AAHAAYA
+AAAA//oABf//AfQAAAH5AAUABgAAAAD/+QAGAAAB+QAAAf8ABwAGAAAAAv/5AAMAAgH/AAACAAAJ
+AAYAAAAA//kABQABAgAAAAIFAAgABgAAAAH/+gAE//sCBQAAAggAAQAGAAAAAP/5AAYAAAIIAAAC
+DgAHAAYAAAAB//kABf/+Ag4AAAISAAUABgAA////+wAGAAACEgAAAhkABQAGAAAAAP/7AAX//gIZ
+AAACHgADAAYAAAAA//wABf/9Ah4AAAIjAAEABgAAAAD/+QAHAAACIwAAAioABwAGAAAAAP/6AAT/
++wIqAAACLgABAAYAAAAA//kABP/8Ai4AAAIyAAMABgAAAAD/+gAFAAACMgAAAjcABgAGAAAAAf/5
+AAT//QI3AAACOgAEAAYAAAAB//kABP/9AjoAAAI9AAQABgAAAAL/+QAE//sCPQAAAj8AAgAGAAD/
+///7AAYAAgI/AAACRgAHAAYAAAAA//kABgABAkYAAAJMAAgABgAAAAH//AAD//0CTAAAAk4AAQAG
+AAAAAf//AAQAAgJOAAACUQADAAYAAAAB//kABP/9AlEAAAJUAAQABgAAAAH/+QAF//4CVAAAAlgA
+BQAGAAD////7AAYAAAJYAAACXwAFAAYAAP////kABgAAAl8AAAJmAAcABgAA////+QAGAAACZgAA
+Am0ABwAGAAD////5AAYAAAJtAAACdAAHAAYAAAAA//sABQACAnQAAAJ5AAcABgAA////9wAGAAAC
+eQAAAoAACQAGAAD////3AAYAAAKAAAAChwAJAAYAAP////cABgAAAocAAAKOAAkABgAA////9wAG
+AAACjgAAApUACQAGAAD////4AAYAAAKVAAACnAAIAAYAAP////cABgAAApwAAAKjAAkABgAA////
++gAGAAACowAAAqoABgAGAAAAAP/6AAUAAgKqAAACrwAIAAYAAP////cABQAAAq8AAAK1AAkABgAA
+////9wAFAAACtQAAArsACQAGAAD////3AAUAAAK7AAACwQAJAAYAAP////gABQAAAsEAAALHAAgA
+BgAAAAD/9wAEAAACxwAAAssACQAGAAAAAP/3AAQAAALLAAACzwAJAAYAAAAA//cABAAAAs8AAALT
+AAkABgAAAAD/+AAEAAAC0wAAAtcACAAGAAD////6AAUAAALXAAAC3QAGAAYAAP////cABgAAAt0A
+AALkAAkABgAAAAD/9wAFAAAC5AAAAukACQAGAAAAAP/3AAUAAALpAAAC7gAJAAYAAAAA//cABQAA
+Au4AAALzAAkABgAAAAD/9wAFAAAC8wAAAvgACQAGAAAAAP/4AAUAAAL4AAAC/QAIAAYAAAAA//oA
+Bf//Av0AAAMCAAUABgAA////+gAGAAADAgAAAwkABgAGAAD////3AAYAAAMJAAADEAAJAAYAAP//
+//cABgAAAxAAAAMXAAkABgAA////9wAGAAADFwAAAx4ACQAGAAD////4AAYAAAAAAAoABwASAAYA
+AP////cABgAAAAcACgAOABMABgAA////+gAFAAAADgAKABQAEAAGAAD////6AAYAAAAUAAoAGwAQ
+AAYAAAAA//gABgAAABsACgAhABIABgAAAAD/+AAGAAAAIQAKACcAEgAGAAAAAP/4AAYAAAAnAAoA
+LQASAAYAAAAA//gABgAAAC0ACgAzABIABgAAAAD/+QAGAAAAMwAKADkAEQAGAAAAAP/3AAYAAAA5
+AAoAPwATAAYAAP////sABQAAAD8ACgBFAA8ABgAAAAD/+wAFAAIARQAKAEoAEQAGAAAAAP/4AAUA
+AABKAAoATwASAAYAAAAA//gABQAAAE8ACgBUABIABgAAAAD/+AAFAAAAVAAKAFkAEgAGAAAAAP/5
+AAUAAABZAAoAXgARAAYAAAAA//gABgAAAF4ACgBkABIABgAAAAD/+AAGAAAAZAAKAGoAEgAGAAAA
+AP/4AAYAAABqAAoAcAASAAYAAAAA//kABgAAAHAACgB2ABEABgAAAAD/+AAFAAAAdgAKAHsAEgAG
+AAD////4AAYAAAB7AAoAggASAAYAAAAA//gABQAAAIIACgCHABIABgAAAAD/+AAFAAAAhwAKAIwA
+EgAGAAAAAP/4AAUAAACMAAoAkQASAAYAAAAA//gABQAAAJEACgCWABIABgAAAAD/+QAFAAAAlgAK
+AJsAEQAGAAAAAP/6AAX//wCbAAoAoAAPAAYAAAAA//oABQABAKAACgClABEABgAA////+AAGAAAA
+pQAKAKwAEgAGAAD////4AAYAAACsAAoAswASAAYAAP////gABgAAALMACgC6ABIABgAA////+QAG
+AAAAugAKAMEAEQAGAAD////4AAYAAgDBAAoAyAAUAAYAAP////kABQACAMgACgDOABMABgAA////
++QAGAAIAzgAKANUAEw==
+"""
+ )
+ ),
+ Image.open(
+ BytesIO(
+ base64.b64decode(
+ b"""
+iVBORw0KGgoAAAANSUhEUgAAAx4AAAAUAQAAAAArMtZoAAAEwElEQVR4nABlAJr/AHVE4czCI/4u
+Mc4b7vuds/xzjz5/3/7u/n9vMe7vnfH/9++vPn/xyf5zhxzjt8GHw8+2d83u8x27199/nxuQ6Od9
+M43/5z2I+9n9ZtmDBwMQECDRQw/eQIQohJXxpBCNVE6QCCAAAAD//wBlAJr/AgALyj1t/wINwq0g
+LeNZUworuN1cjTPIzrTX6ofHWeo3v336qPzfEwRmBnHTtf95/fglZK5N0PDgfRTslpGBvz7LFc4F
+IUXBWQGjQ5MGCx34EDFPwXiY4YbYxavpnhHFrk14CDAAAAD//wBlAJr/AgKqRooH2gAgPeggvUAA
+Bu2WfgPoAwzRAABAAAAAAACQgLz/3Uv4Gv+gX7BJgDeeGP6AAAD1NMDzKHD7ANWr3loYbxsAD791
+NAADfcoIDyP44K/jv4Y63/Z+t98Ovt+ub4T48LAAAAD//wBlAJr/AuplMlADJAAAAGuAphWpqhMx
+in0A/fRvAYBABPgBwBUgABBQ/sYAyv9g0bCHgOLoGAAAAAAAREAAwI7nr0ArYpow7aX8//9LaP/9
+SjdavWA8ePHeBIKB//81/83ndznOaXx379wAAAD//wBlAJr/AqDxW+D3AABAAbUh/QMnbQag/gAY
+AYDAAACgtgD/gOqAAAB5IA/8AAAk+n9w0AAA8AAAmFRJuPo27ciC0cD5oeW4E7KA/wD3ECMAn2tt
+y8PgwH8AfAxFzC0JzeAMtratAsC/ffwAAAD//wBlAJr/BGKAyCAA4AAAAvgeYTAwHd1kmQF5chkG
+ABoMIHcL5xVpTfQbUqzlAAAErwAQBgAAEOClA5D9il08AEh/tUzdCBsXkbgACED+woQg8Si9VeqY
+lODCn7lmF6NhnAEYgAAA/NMIAAAAAAD//2JgjLZgVGBg5Pv/Tvpc8hwGBjYGJADjHDrAwPzAjv/H
+/Wf3PzCwtzcwHmBgYGcwbZz8wHaCAQMDOwMDQ8MCBgYOC3W7mp+f0w+wHOYxO3OG+e376hsMZjk3
+AAAAAP//YmCMY2A4wMAIN5e5gQETPD6AZisDAwMDgzSDAAPjByiHcQMDAwMDg1nOze1lByRu5/47
+c4859311AYNZzg0AAAAA//9iYGDBYihOIIMuwIjGL39/fwffA8b//xv/P2BPtzzHwCBjUQAAAAD/
+/yLFBrIBAAAA//9i1HhcwdhizX7u8NZNzyLbvT97bfrMf/QHI8evOwcSqGUJAAAA//9iYBB81iSw
+pEE170Qrg5MIYydHqwdDQRMrAwcVrQAAAAD//2J4x7j9AAMDn8Q/BgYLBoaiAwwMjPdvMDBYM1Tv
+oJodAAAAAP//Yqo/83+dxePWlxl3npsel9lvLfPcqlE9725C+acfVLMEAAAA//9i+s9gwCoaaGMR
+evta/58PTEWzr21hufPjA8N+qlnBwAAAAAD//2JiWLci5v1+HmFXDqcnULE/MxgYGBj+f6CaJQAA
+AAD//2Ji2FrkY3iYpYC5qDeGgeEMAwPDvwQBBoYvcTwOVLMEAAAA//9isDBgkP///0EOg9z35v//
+Gc/eeW7BwPj5+QGZhANUswMAAAD//2JgqGBgYGBgqEMXlvhMPUsAAAAA//8iYDd1AAAAAP//AwDR
+w7IkEbzhVQAAAABJRU5ErkJggg==
+"""
+ )
+ )
+ ),
+ )
+ return f
diff --git a/contrib/python/Pillow/py2/PIL/ImageGrab.py b/contrib/python/Pillow/py2/PIL/ImageGrab.py
new file mode 100644
index 0000000000..9b4413536e
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageGrab.py
@@ -0,0 +1,92 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# screen grabber (macOS and Windows only)
+#
+# History:
+# 2001-04-26 fl created
+# 2001-09-17 fl use builtin driver, if present
+# 2002-11-19 fl added grabclipboard support
+#
+# Copyright (c) 2001-2002 by Secret Labs AB
+# Copyright (c) 2001-2002 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import sys
+
+from . import Image
+
+if sys.platform == "win32":
+ grabber = Image.core.grabscreen
+elif sys.platform == "darwin":
+ import os
+ import tempfile
+ import subprocess
+else:
+ raise ImportError("ImageGrab is macOS and Windows only")
+
+
+def grab(bbox=None, include_layered_windows=False, all_screens=False):
+ if sys.platform == "darwin":
+ fh, filepath = tempfile.mkstemp(".png")
+ os.close(fh)
+ subprocess.call(["screencapture", "-x", filepath])
+ im = Image.open(filepath)
+ im.load()
+ os.unlink(filepath)
+ if bbox:
+ im = im.crop(bbox)
+ else:
+ offset, size, data = grabber(include_layered_windows, all_screens)
+ im = Image.frombytes(
+ "RGB",
+ size,
+ data,
+ # RGB, 32-bit line padding, origin lower left corner
+ "raw",
+ "BGR",
+ (size[0] * 3 + 3) & -4,
+ -1,
+ )
+ if bbox:
+ x0, y0 = offset
+ left, top, right, bottom = bbox
+ im = im.crop((left - x0, top - y0, right - x0, bottom - y0))
+ return im
+
+
+def grabclipboard():
+ if sys.platform == "darwin":
+ fh, filepath = tempfile.mkstemp(".jpg")
+ os.close(fh)
+ commands = [
+ 'set theFile to (open for access POSIX file "'
+ + filepath
+ + '" with write permission)',
+ "try",
+ " write (the clipboard as JPEG picture) to theFile",
+ "end try",
+ "close access theFile",
+ ]
+ script = ["osascript"]
+ for command in commands:
+ script += ["-e", command]
+ subprocess.call(script)
+
+ im = None
+ if os.stat(filepath).st_size != 0:
+ im = Image.open(filepath)
+ im.load()
+ os.unlink(filepath)
+ return im
+ else:
+ data = Image.core.grabclipboard()
+ if isinstance(data, bytes):
+ from . import BmpImagePlugin
+ import io
+
+ return BmpImagePlugin.DibImageFile(io.BytesIO(data))
+ return data
diff --git a/contrib/python/Pillow/py2/PIL/ImageMath.py b/contrib/python/Pillow/py2/PIL/ImageMath.py
new file mode 100644
index 0000000000..392151c10f
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageMath.py
@@ -0,0 +1,271 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# a simple math add-on for the Python Imaging Library
+#
+# History:
+# 1999-02-15 fl Original PIL Plus release
+# 2005-05-05 fl Simplified and cleaned up for PIL 1.1.6
+# 2005-09-12 fl Fixed int() and float() for Python 2.4.1
+#
+# Copyright (c) 1999-2005 by Secret Labs AB
+# Copyright (c) 2005 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, _imagingmath
+from ._util import py3
+
+try:
+ import builtins
+except ImportError:
+ import __builtin__
+
+ builtins = __builtin__
+
+VERBOSE = 0
+
+
+def _isconstant(v):
+ return isinstance(v, (int, float))
+
+
+class _Operand(object):
+ """Wraps an image operand, providing standard operators"""
+
+ def __init__(self, im):
+ self.im = im
+
+ def __fixup(self, im1):
+ # convert image to suitable mode
+ if isinstance(im1, _Operand):
+ # argument was an image.
+ if im1.im.mode in ("1", "L"):
+ return im1.im.convert("I")
+ elif im1.im.mode in ("I", "F"):
+ return im1.im
+ else:
+ raise ValueError("unsupported mode: %s" % im1.im.mode)
+ else:
+ # argument was a constant
+ if _isconstant(im1) and self.im.mode in ("1", "L", "I"):
+ return Image.new("I", self.im.size, im1)
+ else:
+ return Image.new("F", self.im.size, im1)
+
+ def apply(self, op, im1, im2=None, mode=None):
+ im1 = self.__fixup(im1)
+ if im2 is None:
+ # unary operation
+ out = Image.new(mode or im1.mode, im1.size, None)
+ im1.load()
+ try:
+ op = getattr(_imagingmath, op + "_" + im1.mode)
+ except AttributeError:
+ raise TypeError("bad operand type for '%s'" % op)
+ _imagingmath.unop(op, out.im.id, im1.im.id)
+ else:
+ # binary operation
+ im2 = self.__fixup(im2)
+ if im1.mode != im2.mode:
+ # convert both arguments to floating point
+ if im1.mode != "F":
+ im1 = im1.convert("F")
+ if im2.mode != "F":
+ im2 = im2.convert("F")
+ if im1.mode != im2.mode:
+ raise ValueError("mode mismatch")
+ if im1.size != im2.size:
+ # crop both arguments to a common size
+ size = (min(im1.size[0], im2.size[0]), min(im1.size[1], im2.size[1]))
+ if im1.size != size:
+ im1 = im1.crop((0, 0) + size)
+ if im2.size != size:
+ im2 = im2.crop((0, 0) + size)
+ out = Image.new(mode or im1.mode, size, None)
+ else:
+ out = Image.new(mode or im1.mode, im1.size, None)
+ im1.load()
+ im2.load()
+ try:
+ op = getattr(_imagingmath, op + "_" + im1.mode)
+ except AttributeError:
+ raise TypeError("bad operand type for '%s'" % op)
+ _imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id)
+ return _Operand(out)
+
+ # unary operators
+ def __bool__(self):
+ # an image is "true" if it contains at least one non-zero pixel
+ return self.im.getbbox() is not None
+
+ if not py3:
+ # Provide __nonzero__ for pre-Py3k
+ __nonzero__ = __bool__
+ del __bool__
+
+ def __abs__(self):
+ return self.apply("abs", self)
+
+ def __pos__(self):
+ return self
+
+ def __neg__(self):
+ return self.apply("neg", self)
+
+ # binary operators
+ def __add__(self, other):
+ return self.apply("add", self, other)
+
+ def __radd__(self, other):
+ return self.apply("add", other, self)
+
+ def __sub__(self, other):
+ return self.apply("sub", self, other)
+
+ def __rsub__(self, other):
+ return self.apply("sub", other, self)
+
+ def __mul__(self, other):
+ return self.apply("mul", self, other)
+
+ def __rmul__(self, other):
+ return self.apply("mul", other, self)
+
+ def __truediv__(self, other):
+ return self.apply("div", self, other)
+
+ def __rtruediv__(self, other):
+ return self.apply("div", other, self)
+
+ def __mod__(self, other):
+ return self.apply("mod", self, other)
+
+ def __rmod__(self, other):
+ return self.apply("mod", other, self)
+
+ def __pow__(self, other):
+ return self.apply("pow", self, other)
+
+ def __rpow__(self, other):
+ return self.apply("pow", other, self)
+
+ if not py3:
+ # Provide __div__ and __rdiv__ for pre-Py3k
+ __div__ = __truediv__
+ __rdiv__ = __rtruediv__
+ del __truediv__
+ del __rtruediv__
+
+ # bitwise
+ def __invert__(self):
+ return self.apply("invert", self)
+
+ def __and__(self, other):
+ return self.apply("and", self, other)
+
+ def __rand__(self, other):
+ return self.apply("and", other, self)
+
+ def __or__(self, other):
+ return self.apply("or", self, other)
+
+ def __ror__(self, other):
+ return self.apply("or", other, self)
+
+ def __xor__(self, other):
+ return self.apply("xor", self, other)
+
+ def __rxor__(self, other):
+ return self.apply("xor", other, self)
+
+ def __lshift__(self, other):
+ return self.apply("lshift", self, other)
+
+ def __rshift__(self, other):
+ return self.apply("rshift", self, other)
+
+ # logical
+ def __eq__(self, other):
+ return self.apply("eq", self, other)
+
+ def __ne__(self, other):
+ return self.apply("ne", self, other)
+
+ def __lt__(self, other):
+ return self.apply("lt", self, other)
+
+ def __le__(self, other):
+ return self.apply("le", self, other)
+
+ def __gt__(self, other):
+ return self.apply("gt", self, other)
+
+ def __ge__(self, other):
+ return self.apply("ge", self, other)
+
+
+# conversions
+def imagemath_int(self):
+ return _Operand(self.im.convert("I"))
+
+
+def imagemath_float(self):
+ return _Operand(self.im.convert("F"))
+
+
+# logical
+def imagemath_equal(self, other):
+ return self.apply("eq", self, other, mode="I")
+
+
+def imagemath_notequal(self, other):
+ return self.apply("ne", self, other, mode="I")
+
+
+def imagemath_min(self, other):
+ return self.apply("min", self, other)
+
+
+def imagemath_max(self, other):
+ return self.apply("max", self, other)
+
+
+def imagemath_convert(self, mode):
+ return _Operand(self.im.convert(mode))
+
+
+ops = {}
+for k, v in list(globals().items()):
+ if k[:10] == "imagemath_":
+ ops[k[10:]] = v
+
+
+def eval(expression, _dict={}, **kw):
+ """
+ Evaluates an image expression.
+
+ :param expression: A string containing a Python-style expression.
+ :param options: Values to add to the evaluation context. You
+ can either use a dictionary, or one or more keyword
+ arguments.
+ :return: The evaluated expression. This is usually an image object, but can
+ also be an integer, a floating point value, or a pixel tuple,
+ depending on the expression.
+ """
+
+ # build execution namespace
+ args = ops.copy()
+ args.update(_dict)
+ args.update(kw)
+ for k, v in list(args.items()):
+ if hasattr(v, "im"):
+ args[k] = _Operand(v)
+
+ out = builtins.eval(expression, args)
+ try:
+ return out.im
+ except AttributeError:
+ return out
diff --git a/contrib/python/Pillow/py2/PIL/ImageMode.py b/contrib/python/Pillow/py2/PIL/ImageMode.py
new file mode 100644
index 0000000000..596be7b9d7
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageMode.py
@@ -0,0 +1,64 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# standard mode descriptors
+#
+# History:
+# 2006-03-20 fl Added
+#
+# Copyright (c) 2006 by Secret Labs AB.
+# Copyright (c) 2006 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+# mode descriptor cache
+_modes = None
+
+
+class ModeDescriptor(object):
+ """Wrapper for mode strings."""
+
+ def __init__(self, mode, bands, basemode, basetype):
+ self.mode = mode
+ self.bands = bands
+ self.basemode = basemode
+ self.basetype = basetype
+
+ def __str__(self):
+ return self.mode
+
+
+def getmode(mode):
+ """Gets a mode descriptor for the given mode."""
+ global _modes
+ if not _modes:
+ # initialize mode cache
+
+ from . import Image
+
+ modes = {}
+ # core modes
+ 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["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L")
+ modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L")
+ modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L")
+ # mapping modes
+ for i16mode in (
+ "I;16",
+ "I;16S",
+ "I;16L",
+ "I;16LS",
+ "I;16B",
+ "I;16BS",
+ "I;16N",
+ "I;16NS",
+ ):
+ modes[i16mode] = ModeDescriptor(i16mode, ("I",), "L", "L")
+ # set global mode cache atomically
+ _modes = modes
+ return _modes[mode]
diff --git a/contrib/python/Pillow/py2/PIL/ImageMorph.py b/contrib/python/Pillow/py2/PIL/ImageMorph.py
new file mode 100644
index 0000000000..61199234bc
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageMorph.py
@@ -0,0 +1,247 @@
+# A binary morphology add-on for the Python Imaging Library
+#
+# History:
+# 2014-06-04 Initial version.
+#
+# Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com>
+
+from __future__ import print_function
+
+import re
+
+from . import Image, _imagingmorph
+
+LUT_SIZE = 1 << 9
+
+# fmt: off
+ROTATION_MATRIX = [
+ 6, 3, 0,
+ 7, 4, 1,
+ 8, 5, 2,
+]
+MIRROR_MATRIX = [
+ 2, 1, 0,
+ 5, 4, 3,
+ 8, 7, 6,
+]
+# fmt: on
+
+
+class LutBuilder(object):
+ """A class for building a MorphLut from a descriptive language
+
+ The input patterns is a list of a strings sequences like these::
+
+ 4:(...
+ .1.
+ 111)->1
+
+ (whitespaces including linebreaks are ignored). The option 4
+ describes a series of symmetry operations (in this case a
+ 4-rotation), the pattern is described by:
+
+ - . or X - Ignore
+ - 1 - Pixel is on
+ - 0 - Pixel is off
+
+ The result of the operation is described after "->" string.
+
+ The default is to return the current pixel value, which is
+ returned if no other match is found.
+
+ Operations:
+
+ - 4 - 4 way rotation
+ - N - Negate
+ - 1 - Dummy op for no other operation (an op must always be given)
+ - M - Mirroring
+
+ Example::
+
+ lb = LutBuilder(patterns = ["4:(... .1. 111)->1"])
+ lut = lb.build_lut()
+
+ """
+
+ def __init__(self, patterns=None, op_name=None):
+ if patterns is not None:
+ self.patterns = patterns
+ else:
+ self.patterns = []
+ self.lut = None
+ if op_name is not None:
+ known_patterns = {
+ "corner": ["1:(... ... ...)->0", "4:(00. 01. ...)->1"],
+ "dilation4": ["4:(... .0. .1.)->1"],
+ "dilation8": ["4:(... .0. .1.)->1", "4:(... .0. ..1)->1"],
+ "erosion4": ["4:(... .1. .0.)->0"],
+ "erosion8": ["4:(... .1. .0.)->0", "4:(... .1. ..0)->0"],
+ "edge": [
+ "1:(... ... ...)->0",
+ "4:(.0. .1. ...)->1",
+ "4:(01. .1. ...)->1",
+ ],
+ }
+ if op_name not in known_patterns:
+ raise Exception("Unknown pattern " + op_name + "!")
+
+ self.patterns = known_patterns[op_name]
+
+ def add_patterns(self, patterns):
+ self.patterns += patterns
+
+ def build_default_lut(self):
+ symbols = [0, 1]
+ m = 1 << 4 # pos of current pixel
+ self.lut = bytearray(symbols[(i & m) > 0] for i in range(LUT_SIZE))
+
+ def get_lut(self):
+ return self.lut
+
+ def _string_permute(self, pattern, permutation):
+ """string_permute takes a pattern and a permutation and returns the
+ string permuted according to the permutation list.
+ """
+ assert len(permutation) == 9
+ return "".join(pattern[p] for p in permutation)
+
+ def _pattern_permute(self, basic_pattern, options, basic_result):
+ """pattern_permute takes a basic pattern and its result and clones
+ the pattern according to the modifications described in the $options
+ parameter. It returns a list of all cloned patterns."""
+ patterns = [(basic_pattern, basic_result)]
+
+ # rotations
+ if "4" in options:
+ res = patterns[-1][1]
+ for i in range(4):
+ patterns.append(
+ (self._string_permute(patterns[-1][0], ROTATION_MATRIX), res)
+ )
+ # mirror
+ if "M" in options:
+ n = len(patterns)
+ for pattern, res in patterns[0:n]:
+ patterns.append((self._string_permute(pattern, MIRROR_MATRIX), res))
+
+ # negate
+ if "N" in options:
+ n = len(patterns)
+ for pattern, res in patterns[0:n]:
+ # Swap 0 and 1
+ pattern = pattern.replace("0", "Z").replace("1", "0").replace("Z", "1")
+ res = 1 - int(res)
+ patterns.append((pattern, res))
+
+ return patterns
+
+ def build_lut(self):
+ """Compile all patterns into a morphology lut.
+
+ TBD :Build based on (file) morphlut:modify_lut
+ """
+ self.build_default_lut()
+ patterns = []
+
+ # Parse and create symmetries of the patterns strings
+ for p in self.patterns:
+ m = re.search(r"(\w*):?\s*\((.+?)\)\s*->\s*(\d)", p.replace("\n", ""))
+ if not m:
+ raise Exception('Syntax error in pattern "' + p + '"')
+ options = m.group(1)
+ pattern = m.group(2)
+ result = int(m.group(3))
+
+ # Get rid of spaces
+ pattern = pattern.replace(" ", "").replace("\n", "")
+
+ patterns += self._pattern_permute(pattern, options, result)
+
+ # compile the patterns into regular expressions for speed
+ for i, pattern in enumerate(patterns):
+ p = pattern[0].replace(".", "X").replace("X", "[01]")
+ p = re.compile(p)
+ patterns[i] = (p, pattern[1])
+
+ # Step through table and find patterns that match.
+ # Note that all the patterns are searched. The last one
+ # caught overrides
+ for i in range(LUT_SIZE):
+ # Build the bit pattern
+ bitpattern = bin(i)[2:]
+ bitpattern = ("0" * (9 - len(bitpattern)) + bitpattern)[::-1]
+
+ for p, r in patterns:
+ if p.match(bitpattern):
+ self.lut[i] = [0, 1][r]
+
+ return self.lut
+
+
+class MorphOp(object):
+ """A class for binary morphological operators"""
+
+ def __init__(self, lut=None, op_name=None, patterns=None):
+ """Create a binary morphological operator"""
+ self.lut = lut
+ if op_name is not None:
+ self.lut = LutBuilder(op_name=op_name).build_lut()
+ elif patterns is not None:
+ self.lut = LutBuilder(patterns=patterns).build_lut()
+
+ def apply(self, image):
+ """Run a single morphological operation on an image
+
+ Returns a tuple of the number of changed pixels and the
+ morphed image"""
+ if self.lut is None:
+ raise Exception("No operator loaded")
+
+ if image.mode != "L":
+ raise Exception("Image must be binary, meaning it must use mode L")
+ outimage = Image.new(image.mode, image.size, None)
+ count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id)
+ return count, outimage
+
+ def match(self, image):
+ """Get a list of coordinates matching the morphological operation on
+ an image.
+
+ Returns a list of tuples of (x,y) coordinates
+ of all matching pixels. See :ref:`coordinate-system`."""
+ if self.lut is None:
+ raise Exception("No operator loaded")
+
+ if image.mode != "L":
+ raise Exception("Image must be binary, meaning it must use mode L")
+ return _imagingmorph.match(bytes(self.lut), image.im.id)
+
+ def get_on_pixels(self, image):
+ """Get a list of all turned on pixels in a binary image
+
+ Returns a list of tuples of (x,y) coordinates
+ of all matching pixels. See :ref:`coordinate-system`."""
+
+ if image.mode != "L":
+ raise Exception("Image must be binary, meaning it must use mode L")
+ return _imagingmorph.get_on_pixels(image.im.id)
+
+ def load_lut(self, filename):
+ """Load an operator from an mrl file"""
+ with open(filename, "rb") as f:
+ self.lut = bytearray(f.read())
+
+ if len(self.lut) != LUT_SIZE:
+ self.lut = None
+ raise Exception("Wrong size operator file!")
+
+ def save_lut(self, filename):
+ """Save an operator to an mrl file"""
+ if self.lut is None:
+ raise Exception("No operator loaded")
+ with open(filename, "wb") as f:
+ f.write(self.lut)
+
+ def set_lut(self, lut):
+ """Set the lut from an external source"""
+ self.lut = lut
diff --git a/contrib/python/Pillow/py2/PIL/ImageOps.py b/contrib/python/Pillow/py2/PIL/ImageOps.py
new file mode 100644
index 0000000000..5052cb74d4
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageOps.py
@@ -0,0 +1,551 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# standard image operations
+#
+# History:
+# 2001-10-20 fl Created
+# 2001-10-23 fl Added autocontrast operator
+# 2001-12-18 fl Added Kevin's fit operator
+# 2004-03-14 fl Fixed potential division by zero in equalize
+# 2005-05-05 fl Fixed equalize for low number of values
+#
+# Copyright (c) 2001-2004 by Secret Labs AB
+# Copyright (c) 2001-2004 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import functools
+import operator
+
+from . import Image
+from ._util import isStringType
+
+#
+# helpers
+
+
+def _border(border):
+ if isinstance(border, tuple):
+ if len(border) == 2:
+ left, top = right, bottom = border
+ elif len(border) == 4:
+ left, top, right, bottom = border
+ else:
+ left = top = right = bottom = border
+ return left, top, right, bottom
+
+
+def _color(color, mode):
+ if isStringType(color):
+ from . import ImageColor
+
+ color = ImageColor.getcolor(color, mode)
+ return color
+
+
+def _lut(image, lut):
+ if image.mode == "P":
+ # FIXME: apply to lookup table, not image data
+ raise NotImplementedError("mode P support coming soon")
+ elif image.mode in ("L", "RGB"):
+ if image.mode == "RGB" and len(lut) == 256:
+ lut = lut + lut + lut
+ return image.point(lut)
+ else:
+ raise IOError("not supported for this image mode")
+
+
+#
+# actions
+
+
+def autocontrast(image, cutoff=0, ignore=None):
+ """
+ Maximize (normalize) image contrast. This function calculates a
+ histogram of the input image, removes **cutoff** percent of the
+ lightest and darkest pixels from the histogram, and remaps the image
+ so that the darkest pixel becomes black (0), and the lightest
+ becomes white (255).
+
+ :param image: The image to process.
+ :param cutoff: How many percent to cut off from the histogram.
+ :param ignore: The background pixel value (use None for no background).
+ :return: An image.
+ """
+ histogram = image.histogram()
+ lut = []
+ for layer in range(0, len(histogram), 256):
+ h = histogram[layer : layer + 256]
+ if ignore is not None:
+ # get rid of outliers
+ try:
+ h[ignore] = 0
+ except TypeError:
+ # assume sequence
+ for ix in ignore:
+ h[ix] = 0
+ if cutoff:
+ # cut off pixels from both ends of the histogram
+ # get number of pixels
+ n = 0
+ for ix in range(256):
+ n = n + h[ix]
+ # remove cutoff% pixels from the low end
+ cut = n * cutoff // 100
+ for lo in range(256):
+ if cut > h[lo]:
+ cut = cut - h[lo]
+ h[lo] = 0
+ else:
+ h[lo] -= cut
+ cut = 0
+ if cut <= 0:
+ break
+ # remove cutoff% samples from the hi end
+ cut = n * cutoff // 100
+ for hi in range(255, -1, -1):
+ if cut > h[hi]:
+ cut = cut - h[hi]
+ h[hi] = 0
+ else:
+ h[hi] -= cut
+ cut = 0
+ if cut <= 0:
+ break
+ # find lowest/highest samples after preprocessing
+ for lo in range(256):
+ if h[lo]:
+ break
+ for hi in range(255, -1, -1):
+ if h[hi]:
+ break
+ if hi <= lo:
+ # don't bother
+ lut.extend(list(range(256)))
+ else:
+ scale = 255.0 / (hi - lo)
+ offset = -lo * scale
+ for ix in range(256):
+ ix = int(ix * scale + offset)
+ if ix < 0:
+ ix = 0
+ elif ix > 255:
+ ix = 255
+ lut.append(ix)
+ return _lut(image, lut)
+
+
+def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoint=127):
+ """
+ Colorize grayscale image.
+ 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 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.
+ :param white: The color to use for white input pixels.
+ :param mid: The color to use for midtone input pixels.
+ :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"
+ if mid is None:
+ assert 0 <= blackpoint <= whitepoint <= 255
+ else:
+ assert 0 <= blackpoint <= midpoint <= whitepoint <= 255
+
+ # Define colors from arguments
+ black = _color(black, "RGB")
+ white = _color(white, "RGB")
+ if mid is not None:
+ mid = _color(mid, "RGB")
+
+ # Empty lists for the mapping
+ red = []
+ 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:
+
+ range_map = range(0, whitepoint - blackpoint)
+
+ 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))
+
+ # Create the mapping (3-color)
+ else:
+
+ range_map1 = range(0, midpoint - blackpoint)
+ range_map2 = range(0, whitepoint - midpoint)
+
+ 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))
+
+ # 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")
+ return _lut(image, red + green + blue)
+
+
+def pad(image, size, method=Image.NEAREST, color=None, centering=(0.5, 0.5)):
+ """
+ Returns a sized and padded version of the image, expanded to fill the
+ requested aspect ratio and size.
+
+ :param image: The image to size and crop.
+ :param size: The requested output size in pixels, given as a
+ (width, height) tuple.
+ :param method: What resampling method to use. Default is
+ :py:attr:`PIL.Image.NEAREST`.
+ :param color: The background color of the padded image.
+ :param centering: Control the position of the original image within the
+ padded version.
+ (0.5, 0.5) will keep the image centered
+ (0, 0) will keep the image aligned to the top left
+ (1, 1) will keep the image aligned to the bottom
+ right
+ :return: An image.
+ """
+
+ im_ratio = image.width / image.height
+ dest_ratio = float(size[0]) / size[1]
+
+ if im_ratio == dest_ratio:
+ out = image.resize(size, resample=method)
+ else:
+ out = Image.new(image.mode, size, color)
+ if im_ratio > dest_ratio:
+ new_height = int(image.height / image.width * size[0])
+ if new_height != size[1]:
+ image = image.resize((size[0], new_height), resample=method)
+
+ y = int((size[1] - new_height) * max(0, min(centering[1], 1)))
+ out.paste(image, (0, y))
+ else:
+ new_width = int(image.width / image.height * size[1])
+ if new_width != size[0]:
+ image = image.resize((new_width, size[1]), resample=method)
+
+ x = int((size[0] - new_width) * max(0, min(centering[0], 1)))
+ out.paste(image, (x, 0))
+ return out
+
+
+def crop(image, border=0):
+ """
+ Remove border from image. The same amount of pixels are removed
+ from all four sides. This function works on all image modes.
+
+ .. seealso:: :py:meth:`~PIL.Image.Image.crop`
+
+ :param image: The image to crop.
+ :param border: The number of pixels to remove.
+ :return: An image.
+ """
+ left, top, right, bottom = _border(border)
+ return image.crop((left, top, image.size[0] - right, image.size[1] - bottom))
+
+
+def scale(image, factor, resample=Image.NEAREST):
+ """
+ Returns a rescaled image by a specific factor given in parameter.
+ A factor greater than 1 expands the image, between 0 and 1 contracts the
+ image.
+
+ :param image: The image to rescale.
+ :param factor: The expansion factor, as a float.
+ :param resample: An optional resampling filter. Same values possible as
+ in the PIL.Image.resize function.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+ if factor == 1:
+ return image.copy()
+ elif factor <= 0:
+ raise ValueError("the factor must be greater than 0")
+ else:
+ size = (int(round(factor * image.width)), int(round(factor * image.height)))
+ return image.resize(size, resample)
+
+
+def deform(image, deformer, resample=Image.BILINEAR):
+ """
+ Deform the image.
+
+ :param image: The image to deform.
+ :param deformer: A deformer object. Any object that implements a
+ **getmesh** method can be used.
+ :param resample: An optional resampling filter. Same values possible as
+ in the PIL.Image.transform function.
+ :return: An image.
+ """
+ return image.transform(image.size, Image.MESH, deformer.getmesh(image), resample)
+
+
+def equalize(image, mask=None):
+ """
+ Equalize the image histogram. This function applies a non-linear
+ mapping to the input image, in order to create a uniform
+ distribution of grayscale values in the output image.
+
+ :param image: The image to equalize.
+ :param mask: An optional mask. If given, only the pixels selected by
+ the mask are included in the analysis.
+ :return: An image.
+ """
+ if image.mode == "P":
+ image = image.convert("RGB")
+ h = image.histogram(mask)
+ lut = []
+ for b in range(0, len(h), 256):
+ histo = [_f for _f in h[b : b + 256] if _f]
+ if len(histo) <= 1:
+ lut.extend(list(range(256)))
+ else:
+ step = (functools.reduce(operator.add, histo) - histo[-1]) // 255
+ if not step:
+ lut.extend(list(range(256)))
+ else:
+ n = step // 2
+ for i in range(256):
+ lut.append(n // step)
+ n = n + h[i + b]
+ return _lut(image, lut)
+
+
+def expand(image, border=0, fill=0):
+ """
+ Add border to the image
+
+ :param image: The image to expand.
+ :param border: Border width, in pixels.
+ :param fill: Pixel fill value (a color value). Default is 0 (black).
+ :return: An image.
+ """
+ left, top, right, bottom = _border(border)
+ width = left + image.size[0] + right
+ height = top + image.size[1] + bottom
+ out = Image.new(image.mode, (width, height), _color(fill, image.mode))
+ out.paste(image, (left, top))
+ return out
+
+
+def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)):
+ """
+ Returns a sized and cropped version of the image, cropped to the
+ requested aspect ratio and size.
+
+ This function was contributed by Kevin Cazabon.
+
+ :param image: The image to size and crop.
+ :param size: The requested output size in pixels, given as a
+ (width, height) tuple.
+ :param method: What resampling method to use. Default is
+ :py:attr:`PIL.Image.NEAREST`.
+ :param bleed: Remove a border around the outside of the image from all
+ four edges. The value is a decimal percentage (use 0.01 for
+ one percent). The default value is 0 (no border).
+ Cannot be greater than or equal to 0.5.
+ :param centering: Control the cropping position. Use (0.5, 0.5) for
+ center cropping (e.g. if cropping the width, take 50% off
+ of the left side, and therefore 50% off the right side).
+ (0.0, 0.0) will crop from the top left corner (i.e. if
+ cropping the width, take all of the crop off of the right
+ side, and if cropping the height, take all of it off the
+ bottom). (1.0, 0.0) will crop from the bottom left
+ corner, etc. (i.e. if cropping the width, take all of the
+ crop off the left side, and if cropping the height take
+ none from the top, and therefore all off the bottom).
+ :return: An image.
+ """
+
+ # by Kevin Cazabon, Feb 17/2000
+ # kevin@cazabon.com
+ # http://www.cazabon.com
+
+ # ensure centering is mutable
+ centering = list(centering)
+
+ if not 0.0 <= centering[0] <= 1.0:
+ centering[0] = 0.5
+ if not 0.0 <= centering[1] <= 1.0:
+ centering[1] = 0.5
+
+ if not 0.0 <= bleed < 0.5:
+ bleed = 0.0
+
+ # calculate the area to use for resizing and cropping, subtracting
+ # the 'bleed' around the edges
+
+ # number of pixels to trim off on Top and Bottom, Left and Right
+ bleed_pixels = (bleed * image.size[0], bleed * image.size[1])
+
+ live_size = (
+ image.size[0] - bleed_pixels[0] * 2,
+ image.size[1] - bleed_pixels[1] * 2,
+ )
+
+ # calculate the aspect ratio of the live_size
+ live_size_ratio = float(live_size[0]) / live_size[1]
+
+ # calculate the aspect ratio of the output image
+ output_ratio = float(size[0]) / size[1]
+
+ # figure out if the sides or top/bottom will be cropped off
+ if live_size_ratio == output_ratio:
+ # live_size is already the needed ratio
+ crop_width = live_size[0]
+ crop_height = live_size[1]
+ elif live_size_ratio >= output_ratio:
+ # live_size is wider than what's needed, crop the sides
+ crop_width = output_ratio * live_size[1]
+ crop_height = live_size[1]
+ else:
+ # live_size is taller than what's needed, crop the top and bottom
+ crop_width = live_size[0]
+ crop_height = live_size[0] / output_ratio
+
+ # make the crop
+ crop_left = bleed_pixels[0] + (live_size[0] - crop_width) * centering[0]
+ crop_top = bleed_pixels[1] + (live_size[1] - crop_height) * centering[1]
+
+ crop = (crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)
+
+ # resize the image and return it
+ return image.resize(size, method, box=crop)
+
+
+def flip(image):
+ """
+ Flip the image vertically (top to bottom).
+
+ :param image: The image to flip.
+ :return: An image.
+ """
+ return image.transpose(Image.FLIP_TOP_BOTTOM)
+
+
+def grayscale(image):
+ """
+ Convert the image to grayscale.
+
+ :param image: The image to convert.
+ :return: An image.
+ """
+ return image.convert("L")
+
+
+def invert(image):
+ """
+ Invert (negate) the image.
+
+ :param image: The image to invert.
+ :return: An image.
+ """
+ lut = []
+ for i in range(256):
+ lut.append(255 - i)
+ return _lut(image, lut)
+
+
+def mirror(image):
+ """
+ Flip image horizontally (left to right).
+
+ :param image: The image to mirror.
+ :return: An image.
+ """
+ return image.transpose(Image.FLIP_LEFT_RIGHT)
+
+
+def posterize(image, bits):
+ """
+ Reduce the number of bits for each color channel.
+
+ :param image: The image to posterize.
+ :param bits: The number of bits to keep for each channel (1-8).
+ :return: An image.
+ """
+ lut = []
+ mask = ~(2 ** (8 - bits) - 1)
+ for i in range(256):
+ lut.append(i & mask)
+ return _lut(image, lut)
+
+
+def solarize(image, threshold=128):
+ """
+ Invert all pixel values above a threshold.
+
+ :param image: The image to solarize.
+ :param threshold: All pixels above this greyscale level are inverted.
+ :return: An image.
+ """
+ lut = []
+ for i in range(256):
+ if i < threshold:
+ lut.append(i)
+ else:
+ lut.append(255 - i)
+ return _lut(image, lut)
+
+
+def exif_transpose(image):
+ """
+ If an image has an EXIF Orientation tag, return a new image that is
+ transposed accordingly. Otherwise, return a copy of the image.
+
+ :param image: The image to transpose.
+ :return: An image.
+ """
+ exif = image.getexif()
+ orientation = exif.get(0x0112)
+ method = {
+ 2: Image.FLIP_LEFT_RIGHT,
+ 3: Image.ROTATE_180,
+ 4: Image.FLIP_TOP_BOTTOM,
+ 5: Image.TRANSPOSE,
+ 6: Image.ROTATE_270,
+ 7: Image.TRANSVERSE,
+ 8: Image.ROTATE_90,
+ }.get(orientation)
+ if method is not None:
+ transposed_image = image.transpose(method)
+ del exif[0x0112]
+ transposed_image.info["exif"] = exif.tobytes()
+ return transposed_image
+ return image.copy()
diff --git a/contrib/python/Pillow/py2/PIL/ImagePalette.py b/contrib/python/Pillow/py2/PIL/ImagePalette.py
new file mode 100644
index 0000000000..2d4f5cb6b5
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImagePalette.py
@@ -0,0 +1,221 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# image palette object
+#
+# History:
+# 1996-03-11 fl Rewritten.
+# 1997-01-03 fl Up and running.
+# 1997-08-23 fl Added load hack
+# 2001-04-16 fl Fixed randint shadow bug in random()
+#
+# Copyright (c) 1997-2001 by Secret Labs AB
+# Copyright (c) 1996-1997 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import array
+
+from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile
+
+
+class ImagePalette(object):
+ """
+ Color palette for palette mapped images
+
+ :param mode: The mode to use for the Palette. See:
+ :ref:`concept-modes`. Defaults to "RGB"
+ :param palette: An optional palette. If given, it must be a bytearray,
+ an array or a list of ints between 0-255 and of length ``size``
+ times the number of colors in ``mode``. The list must be aligned
+ by channel (All R values must be contiguous in the list before G
+ and B values.) Defaults to 0 through 255 per channel.
+ :param size: An optional palette size. If given, it cannot be equal to
+ or greater than 256. Defaults to 0.
+ """
+
+ def __init__(self, mode="RGB", palette=None, size=0):
+ self.mode = mode
+ self.rawmode = None # if set, palette contains raw data
+ self.palette = palette or bytearray(range(256)) * len(self.mode)
+ self.colors = {}
+ self.dirty = None
+ if (size == 0 and len(self.mode) * 256 != len(self.palette)) or (
+ size != 0 and size != len(self.palette)
+ ):
+ raise ValueError("wrong palette size")
+
+ def copy(self):
+ new = ImagePalette()
+
+ new.mode = self.mode
+ new.rawmode = self.rawmode
+ if self.palette is not None:
+ new.palette = self.palette[:]
+ new.colors = self.colors.copy()
+ new.dirty = self.dirty
+
+ return new
+
+ def getdata(self):
+ """
+ Get palette contents in format suitable for the low-level
+ ``im.putpalette`` primitive.
+
+ .. warning:: This method is experimental.
+ """
+ if self.rawmode:
+ return self.rawmode, self.palette
+ return self.mode + ";L", self.tobytes()
+
+ def tobytes(self):
+ """Convert palette to bytes.
+
+ .. warning:: This method is experimental.
+ """
+ if self.rawmode:
+ raise ValueError("palette contains raw palette data")
+ if isinstance(self.palette, bytes):
+ return self.palette
+ arr = array.array("B", self.palette)
+ if hasattr(arr, "tobytes"):
+ return arr.tobytes()
+ return arr.tostring()
+
+ # Declare tostring as an alias for tobytes
+ tostring = tobytes
+
+ def getcolor(self, color):
+ """Given an rgb tuple, allocate palette entry.
+
+ .. warning:: This method is experimental.
+ """
+ if self.rawmode:
+ raise ValueError("palette contains raw palette data")
+ if isinstance(color, tuple):
+ try:
+ return self.colors[color]
+ except KeyError:
+ # allocate new color slot
+ if isinstance(self.palette, bytes):
+ self.palette = bytearray(self.palette)
+ index = len(self.colors)
+ if index >= 256:
+ raise ValueError("cannot allocate more than 256 colors")
+ self.colors[color] = index
+ self.palette[index] = color[0]
+ self.palette[index + 256] = color[1]
+ self.palette[index + 512] = color[2]
+ self.dirty = 1
+ return index
+ else:
+ raise ValueError("unknown color specifier: %r" % color)
+
+ def save(self, fp):
+ """Save palette to text file.
+
+ .. warning:: This method is experimental.
+ """
+ if self.rawmode:
+ raise ValueError("palette contains raw palette data")
+ if isinstance(fp, str):
+ fp = open(fp, "w")
+ fp.write("# Palette\n")
+ fp.write("# Mode: %s\n" % self.mode)
+ for i in range(256):
+ fp.write("%d" % i)
+ for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
+ try:
+ fp.write(" %d" % self.palette[j])
+ except IndexError:
+ fp.write(" 0")
+ fp.write("\n")
+ fp.close()
+
+
+# --------------------------------------------------------------------
+# Internal
+
+
+def raw(rawmode, data):
+ palette = ImagePalette()
+ palette.rawmode = rawmode
+ palette.palette = data
+ palette.dirty = 1
+ return palette
+
+
+# --------------------------------------------------------------------
+# Factories
+
+
+def make_linear_lut(black, white):
+ lut = []
+ if black == 0:
+ for i in range(256):
+ lut.append(white * i // 255)
+ else:
+ raise NotImplementedError # FIXME
+ return lut
+
+
+def make_gamma_lut(exp):
+ lut = []
+ for i in range(256):
+ lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))
+ return lut
+
+
+def negative(mode="RGB"):
+ palette = list(range(256))
+ palette.reverse()
+ return ImagePalette(mode, palette * len(mode))
+
+
+def random(mode="RGB"):
+ from random import randint
+
+ palette = []
+ for i in range(256 * len(mode)):
+ palette.append(randint(0, 255))
+ return ImagePalette(mode, palette)
+
+
+def sepia(white="#fff0c0"):
+ r, g, b = ImageColor.getrgb(white)
+ r = make_linear_lut(0, r)
+ g = make_linear_lut(0, g)
+ b = make_linear_lut(0, b)
+ return ImagePalette("RGB", r + g + b)
+
+
+def wedge(mode="RGB"):
+ return ImagePalette(mode, list(range(256)) * len(mode))
+
+
+def load(filename):
+
+ # FIXME: supports GIMP gradients only
+
+ with open(filename, "rb") as fp:
+
+ for paletteHandler in [
+ GimpPaletteFile.GimpPaletteFile,
+ GimpGradientFile.GimpGradientFile,
+ PaletteFile.PaletteFile,
+ ]:
+ try:
+ fp.seek(0)
+ lut = paletteHandler(fp).getpalette()
+ if lut:
+ break
+ except (SyntaxError, ValueError):
+ # import traceback
+ # traceback.print_exc()
+ pass
+ else:
+ raise IOError("cannot load palette")
+
+ return lut # data, rawmode
diff --git a/contrib/python/Pillow/py2/PIL/ImagePath.py b/contrib/python/Pillow/py2/PIL/ImagePath.py
new file mode 100644
index 0000000000..3d3538c97b
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImagePath.py
@@ -0,0 +1,19 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# path interface
+#
+# History:
+# 1996-11-04 fl Created
+# 2002-04-14 fl Added documentation stub class
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+
+Path = Image.core.path
diff --git a/contrib/python/Pillow/py2/PIL/ImageSequence.py b/contrib/python/Pillow/py2/PIL/ImageSequence.py
new file mode 100644
index 0000000000..f9be92d483
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageSequence.py
@@ -0,0 +1,78 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# sequence support classes
+#
+# history:
+# 1997-02-20 fl Created
+#
+# Copyright (c) 1997 by Secret Labs AB.
+# Copyright (c) 1997 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+##
+
+
+class Iterator(object):
+ """
+ This class implements an iterator object that can be used to loop
+ over an image sequence.
+
+ You can use the ``[]`` operator to access elements by index. This operator
+ will raise an :py:exc:`IndexError` if you try to access a nonexistent
+ frame.
+
+ :param im: An image object.
+ """
+
+ def __init__(self, im):
+ if not hasattr(im, "seek"):
+ raise AttributeError("im must have seek method")
+ self.im = im
+ self.position = getattr(self.im, "_min_frame", 0)
+
+ def __getitem__(self, ix):
+ try:
+ self.im.seek(ix)
+ return self.im
+ except EOFError:
+ raise IndexError # end of sequence
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ try:
+ self.im.seek(self.position)
+ self.position += 1
+ return self.im
+ except EOFError:
+ raise StopIteration
+
+ def next(self):
+ return self.__next__()
+
+
+def all_frames(im, func=None):
+ """
+ Applies a given function to all frames in an image or a list of images.
+ The frames are returned as a list of separate images.
+
+ :param im: An image, or a list of images.
+ :param func: The function to apply to all of the image frames.
+ :returns: A list of images.
+ """
+ if not isinstance(im, list):
+ im = [im]
+
+ ims = []
+ for imSequence in im:
+ current = imSequence.tell()
+
+ ims += [im_frame.copy() for im_frame in Iterator(imSequence)]
+
+ imSequence.seek(current)
+ return [func(im) for im in ims] if func else ims
diff --git a/contrib/python/Pillow/py2/PIL/ImageShow.py b/contrib/python/Pillow/py2/PIL/ImageShow.py
new file mode 100644
index 0000000000..ca622c5250
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageShow.py
@@ -0,0 +1,224 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# im.show() drivers
+#
+# History:
+# 2008-04-06 fl Created
+#
+# Copyright (c) Secret Labs AB 2008.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import print_function
+
+import os
+import subprocess
+import sys
+import tempfile
+
+from PIL import Image
+
+if sys.version_info.major >= 3:
+ from shlex import quote
+else:
+ from pipes import quote
+
+_viewers = []
+
+
+def register(viewer, order=1):
+ try:
+ if issubclass(viewer, Viewer):
+ viewer = viewer()
+ except TypeError:
+ pass # raised if viewer wasn't a class
+ if order > 0:
+ _viewers.append(viewer)
+ elif order < 0:
+ _viewers.insert(0, viewer)
+
+
+def show(image, title=None, **options):
+ r"""
+ Display a given image.
+
+ :param image: An image object.
+ :param title: Optional title. Not all viewers can display the title.
+ :param \**options: Additional viewer options.
+ :returns: True if a suitable viewer was found, false otherwise.
+ """
+ for viewer in _viewers:
+ if viewer.show(image, title=title, **options):
+ return 1
+ return 0
+
+
+class Viewer(object):
+ """Base class for viewers."""
+
+ # main api
+
+ def show(self, image, **options):
+
+ # save temporary image to disk
+ if not (
+ image.mode in ("1", "RGBA") or (self.format == "PNG" and image.mode == "LA")
+ ):
+ base = Image.getmodebase(image.mode)
+ if image.mode != base:
+ image = image.convert(base)
+
+ return self.show_image(image, **options)
+
+ # hook methods
+
+ format = None
+ options = {}
+
+ def get_format(self, image):
+ """Return format name, or None to save as PGM/PPM"""
+ return self.format
+
+ def get_command(self, file, **options):
+ raise NotImplementedError
+
+ def save_image(self, image):
+ """Save to temporary file, and return filename"""
+ return image._dump(format=self.get_format(image), **self.options)
+
+ def show_image(self, image, **options):
+ """Display given image"""
+ return self.show_file(self.save_image(image), **options)
+
+ def show_file(self, file, **options):
+ """Display given file"""
+ os.system(self.get_command(file, **options))
+ return 1
+
+
+# --------------------------------------------------------------------
+
+
+if sys.platform == "win32":
+
+ class WindowsViewer(Viewer):
+ format = "PNG"
+ options = {"compress_level": 1}
+
+ def get_command(self, file, **options):
+ return (
+ 'start "Pillow" /WAIT "%s" '
+ "&& ping -n 2 127.0.0.1 >NUL "
+ '&& del /f "%s"' % (file, file)
+ )
+
+ register(WindowsViewer)
+
+elif sys.platform == "darwin":
+
+ class MacViewer(Viewer):
+ format = "PNG"
+ options = {"compress_level": 1}
+
+ def get_command(self, file, **options):
+ # on darwin open returns immediately resulting in the temp
+ # file removal while app is opening
+ command = "open -a Preview.app"
+ command = "(%s %s; sleep 20; rm -f %s)&" % (
+ command,
+ quote(file),
+ quote(file),
+ )
+ return command
+
+ def show_file(self, file, **options):
+ """Display given file"""
+ fd, path = tempfile.mkstemp()
+ with os.fdopen(fd, "w") as f:
+ f.write(file)
+ with open(path, "r") as f:
+ subprocess.Popen(
+ ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"],
+ shell=True,
+ stdin=f,
+ )
+ os.remove(path)
+ return 1
+
+ register(MacViewer)
+
+else:
+
+ # unixoids
+
+ def which(executable):
+ path = os.environ.get("PATH")
+ if not path:
+ return None
+ for dirname in path.split(os.pathsep):
+ filename = os.path.join(dirname, executable)
+ if os.path.isfile(filename) and os.access(filename, os.X_OK):
+ return filename
+ return None
+
+ class UnixViewer(Viewer):
+ format = "PNG"
+ options = {"compress_level": 1}
+
+ def get_command(self, file, **options):
+ command = self.get_command_ex(file, **options)[0]
+ return "(%s %s; rm -f %s)&" % (command, quote(file), quote(file))
+
+ def show_file(self, file, **options):
+ """Display given file"""
+ fd, path = tempfile.mkstemp()
+ with os.fdopen(fd, "w") as f:
+ f.write(file)
+ with open(path, "r") as f:
+ command = self.get_command_ex(file, **options)[0]
+ subprocess.Popen(
+ ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f
+ )
+ os.remove(path)
+ return 1
+
+ # implementations
+
+ class DisplayViewer(UnixViewer):
+ def get_command_ex(self, file, **options):
+ command = executable = "display"
+ return command, executable
+
+ if which("display"):
+ register(DisplayViewer)
+
+ class EogViewer(UnixViewer):
+ def get_command_ex(self, file, **options):
+ command = executable = "eog"
+ return command, executable
+
+ if which("eog"):
+ register(EogViewer)
+
+ class XVViewer(UnixViewer):
+ def get_command_ex(self, file, title=None, **options):
+ # note: xv is pretty outdated. most modern systems have
+ # imagemagick's display command instead.
+ command = executable = "xv"
+ if title:
+ command += " -name %s" % quote(title)
+ return command, executable
+
+ if which("xv"):
+ register(XVViewer)
+
+if __name__ == "__main__":
+
+ if len(sys.argv) < 2:
+ print("Syntax: python ImageShow.py imagefile [title]")
+ sys.exit()
+
+ print(show(Image.open(sys.argv[1]), *sys.argv[2:]))
diff --git a/contrib/python/Pillow/py2/PIL/ImageStat.py b/contrib/python/Pillow/py2/PIL/ImageStat.py
new file mode 100644
index 0000000000..9ba16fd851
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageStat.py
@@ -0,0 +1,147 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# global image statistics
+#
+# History:
+# 1996-04-05 fl Created
+# 1997-05-21 fl Added mask; added rms, var, stddev attributes
+# 1997-08-05 fl Added median
+# 1998-07-05 hk Fixed integer overflow error
+#
+# Notes:
+# This class shows how to implement delayed evaluation of attributes.
+# To get a certain value, simply access the corresponding attribute.
+# The __getattr__ dispatcher takes care of the rest.
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996-97.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import functools
+import math
+import operator
+
+
+class Stat(object):
+ def __init__(self, image_or_list, mask=None):
+ try:
+ if mask:
+ self.h = image_or_list.histogram(mask)
+ else:
+ self.h = image_or_list.histogram()
+ except AttributeError:
+ self.h = image_or_list # assume it to be a histogram list
+ if not isinstance(self.h, list):
+ raise TypeError("first argument must be image or list")
+ self.bands = list(range(len(self.h) // 256))
+
+ def __getattr__(self, id):
+ """Calculate missing attribute"""
+ if id[:4] == "_get":
+ raise AttributeError(id)
+ # calculate missing attribute
+ v = getattr(self, "_get" + id)()
+ setattr(self, id, v)
+ return v
+
+ def _getextrema(self):
+ """Get min/max values for each band in the image"""
+
+ def minmax(histogram):
+ n = 255
+ x = 0
+ for i in range(256):
+ if histogram[i]:
+ n = min(n, i)
+ x = max(x, i)
+ return n, x # returns (255, 0) if there's no data in the histogram
+
+ v = []
+ for i in range(0, len(self.h), 256):
+ v.append(minmax(self.h[i:]))
+ return v
+
+ def _getcount(self):
+ """Get total number of pixels in each layer"""
+
+ v = []
+ for i in range(0, len(self.h), 256):
+ v.append(functools.reduce(operator.add, self.h[i : i + 256]))
+ return v
+
+ def _getsum(self):
+ """Get sum of all pixels in each layer"""
+
+ v = []
+ for i in range(0, len(self.h), 256):
+ layerSum = 0.0
+ for j in range(256):
+ layerSum += j * self.h[i + j]
+ v.append(layerSum)
+ return v
+
+ def _getsum2(self):
+ """Get squared sum of all pixels in each layer"""
+
+ v = []
+ for i in range(0, len(self.h), 256):
+ sum2 = 0.0
+ for j in range(256):
+ sum2 += (j ** 2) * float(self.h[i + j])
+ v.append(sum2)
+ return v
+
+ def _getmean(self):
+ """Get average pixel level for each layer"""
+
+ v = []
+ for i in self.bands:
+ v.append(self.sum[i] / self.count[i])
+ return v
+
+ def _getmedian(self):
+ """Get median pixel level for each layer"""
+
+ v = []
+ for i in self.bands:
+ s = 0
+ half = self.count[i] // 2
+ b = i * 256
+ for j in range(256):
+ s = s + self.h[b + j]
+ if s > half:
+ break
+ v.append(j)
+ return v
+
+ def _getrms(self):
+ """Get RMS for each layer"""
+
+ v = []
+ for i in self.bands:
+ v.append(math.sqrt(self.sum2[i] / self.count[i]))
+ return v
+
+ def _getvar(self):
+ """Get variance for each layer"""
+
+ v = []
+ for i in self.bands:
+ n = self.count[i]
+ v.append((self.sum2[i] - (self.sum[i] ** 2.0) / n) / n)
+ return v
+
+ def _getstddev(self):
+ """Get standard deviation for each layer"""
+
+ v = []
+ for i in self.bands:
+ v.append(math.sqrt(self.var[i]))
+ return v
+
+
+Global = Stat # compatibility
diff --git a/contrib/python/Pillow/py2/PIL/ImageTransform.py b/contrib/python/Pillow/py2/PIL/ImageTransform.py
new file mode 100644
index 0000000000..77791ab726
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageTransform.py
@@ -0,0 +1,102 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# transform wrappers
+#
+# History:
+# 2002-04-08 fl Created
+#
+# Copyright (c) 2002 by Secret Labs AB
+# Copyright (c) 2002 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+
+
+class Transform(Image.ImageTransformHandler):
+ def __init__(self, data):
+ self.data = data
+
+ def getdata(self):
+ return self.method, self.data
+
+ def transform(self, size, image, **options):
+ # can be overridden
+ method, data = self.getdata()
+ return image.transform(size, method, data, **options)
+
+
+class AffineTransform(Transform):
+ """
+ Define an affine image transform.
+
+ This function takes a 6-tuple (a, b, c, d, e, f) which contain the first
+ two rows from an affine transform matrix. For each pixel (x, y) in the
+ output image, the new value is taken from a position (a x + b y + c,
+ d x + e y + f) in the input image, rounded to nearest pixel.
+
+ This function can be used to scale, translate, rotate, and shear the
+ original image.
+
+ See :py:meth:`~PIL.Image.Image.transform`
+
+ :param matrix: A 6-tuple (a, b, c, d, e, f) containing the first two rows
+ from an affine transform matrix.
+ """
+
+ method = Image.AFFINE
+
+
+class ExtentTransform(Transform):
+ """
+ Define a transform to extract a subregion from an image.
+
+ Maps a rectangle (defined by two corners) from the image to a rectangle of
+ the given size. The resulting image will contain data sampled from between
+ the corners, such that (x0, y0) in the input image will end up at (0,0) in
+ the output image, and (x1, y1) at size.
+
+ This method can be used to crop, stretch, shrink, or mirror an arbitrary
+ rectangle in the current image. It is slightly slower than crop, but about
+ as fast as a corresponding resize operation.
+
+ See :py:meth:`~PIL.Image.Image.transform`
+
+ :param bbox: A 4-tuple (x0, y0, x1, y1) which specifies two points in the
+ input image's coordinate system. See :ref:`coordinate-system`.
+ """
+
+ method = Image.EXTENT
+
+
+class QuadTransform(Transform):
+ """
+ Define a quad image transform.
+
+ Maps a quadrilateral (a region defined by four corners) from the image to a
+ rectangle of the given size.
+
+ See :py:meth:`~PIL.Image.Image.transform`
+
+ :param xy: An 8-tuple (x0, y0, x1, y1, x2, y2, x3, y3) which contain the
+ upper left, lower left, lower right, and upper right corner of the
+ source quadrilateral.
+ """
+
+ method = Image.QUAD
+
+
+class MeshTransform(Transform):
+ """
+ Define a mesh image transform. A mesh transform consists of one or more
+ individual quad transforms.
+
+ See :py:meth:`~PIL.Image.Image.transform`
+
+ :param data: A list of (bbox, quad) tuples.
+ """
+
+ method = Image.MESH
diff --git a/contrib/python/Pillow/py2/PIL/ImageWin.py b/contrib/python/Pillow/py2/PIL/ImageWin.py
new file mode 100644
index 0000000000..ed2c18ec42
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImageWin.py
@@ -0,0 +1,230 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# a Windows DIB display interface
+#
+# History:
+# 1996-05-20 fl Created
+# 1996-09-20 fl Fixed subregion exposure
+# 1997-09-21 fl Added draw primitive (for tzPrint)
+# 2003-05-21 fl Added experimental Window/ImageWindow classes
+# 2003-09-05 fl Added fromstring/tostring methods
+#
+# Copyright (c) Secret Labs AB 1997-2003.
+# Copyright (c) Fredrik Lundh 1996-2003.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+
+
+class HDC(object):
+ """
+ Wraps an HDC integer. The resulting object can be passed to the
+ :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose`
+ methods.
+ """
+
+ def __init__(self, dc):
+ self.dc = dc
+
+ def __int__(self):
+ return self.dc
+
+
+class HWND(object):
+ """
+ Wraps an HWND integer. The resulting object can be passed to the
+ :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose`
+ methods, instead of a DC.
+ """
+
+ def __init__(self, wnd):
+ self.wnd = wnd
+
+ def __int__(self):
+ return self.wnd
+
+
+class Dib(object):
+ """
+ A Windows bitmap with the given mode and size. The mode can be one of "1",
+ "L", "P", or "RGB".
+
+ If the display requires a palette, this constructor creates a suitable
+ palette and associates it with the image. For an "L" image, 128 greylevels
+ are allocated. For an "RGB" image, a 6x6x6 colour cube is used, together
+ with 20 greylevels.
+
+ To make sure that palettes work properly under Windows, you must call the
+ **palette** method upon certain events from Windows.
+
+ :param image: Either a PIL image, or a mode string. If a mode string is
+ used, a size must also be given. The mode can be one of "1",
+ "L", "P", or "RGB".
+ :param size: If the first argument is a mode string, this
+ defines the size of the image.
+ """
+
+ def __init__(self, image, size=None):
+ if hasattr(image, "mode") and hasattr(image, "size"):
+ mode = image.mode
+ size = image.size
+ else:
+ mode = image
+ image = None
+ if mode not in ["1", "L", "P", "RGB"]:
+ mode = Image.getmodebase(mode)
+ self.image = Image.core.display(mode, size)
+ self.mode = mode
+ self.size = size
+ if image:
+ self.paste(image)
+
+ def expose(self, handle):
+ """
+ Copy the bitmap contents to a device context.
+
+ :param handle: Device context (HDC), cast to a Python integer, or an
+ HDC or HWND instance. In PythonWin, you can use the
+ :py:meth:`CDC.GetHandleAttrib` to get a suitable handle.
+ """
+ if isinstance(handle, HWND):
+ dc = self.image.getdc(handle)
+ try:
+ result = self.image.expose(dc)
+ finally:
+ self.image.releasedc(handle, dc)
+ else:
+ result = self.image.expose(handle)
+ return result
+
+ def draw(self, handle, dst, src=None):
+ """
+ Same as expose, but allows you to specify where to draw the image, and
+ what part of it to draw.
+
+ The destination and source areas are given as 4-tuple rectangles. If
+ the source is omitted, the entire image is copied. If the source and
+ the destination have different sizes, the image is resized as
+ necessary.
+ """
+ if not src:
+ src = (0, 0) + self.size
+ if isinstance(handle, HWND):
+ dc = self.image.getdc(handle)
+ try:
+ result = self.image.draw(dc, dst, src)
+ finally:
+ self.image.releasedc(handle, dc)
+ else:
+ result = self.image.draw(handle, dst, src)
+ return result
+
+ def query_palette(self, handle):
+ """
+ Installs the palette associated with the image in the given device
+ context.
+
+ This method should be called upon **QUERYNEWPALETTE** and
+ **PALETTECHANGED** events from Windows. If this method returns a
+ non-zero value, one or more display palette entries were changed, and
+ the image should be redrawn.
+
+ :param handle: Device context (HDC), cast to a Python integer, or an
+ HDC or HWND instance.
+ :return: A true value if one or more entries were changed (this
+ indicates that the image should be redrawn).
+ """
+ if isinstance(handle, HWND):
+ handle = self.image.getdc(handle)
+ try:
+ result = self.image.query_palette(handle)
+ finally:
+ self.image.releasedc(handle, handle)
+ else:
+ result = self.image.query_palette(handle)
+ return result
+
+ def paste(self, im, box=None):
+ """
+ Paste a PIL image into the bitmap image.
+
+ :param im: A PIL image. The size must match the target region.
+ If the mode does not match, the image is converted to the
+ mode of the bitmap image.
+ :param box: A 4-tuple defining the left, upper, right, and
+ lower pixel coordinate. See :ref:`coordinate-system`. If
+ None is given instead of a tuple, all of the image is
+ assumed.
+ """
+ im.load()
+ if self.mode != im.mode:
+ im = im.convert(self.mode)
+ if box:
+ self.image.paste(im.im, box)
+ else:
+ self.image.paste(im.im)
+
+ def frombytes(self, buffer):
+ """
+ Load display memory contents from byte data.
+
+ :param buffer: A buffer containing display data (usually
+ data returned from <b>tobytes</b>)
+ """
+ return self.image.frombytes(buffer)
+
+ def tobytes(self):
+ """
+ Copy display memory contents to bytes object.
+
+ :return: A bytes object containing display data.
+ """
+ return self.image.tobytes()
+
+
+class Window(object):
+ """Create a Window with the given title size."""
+
+ def __init__(self, title="PIL", width=None, height=None):
+ self.hwnd = Image.core.createwindow(
+ title, self.__dispatcher, width or 0, height or 0
+ )
+
+ def __dispatcher(self, action, *args):
+ return getattr(self, "ui_handle_" + action)(*args)
+
+ def ui_handle_clear(self, dc, x0, y0, x1, y1):
+ pass
+
+ def ui_handle_damage(self, x0, y0, x1, y1):
+ pass
+
+ def ui_handle_destroy(self):
+ pass
+
+ def ui_handle_repair(self, dc, x0, y0, x1, y1):
+ pass
+
+ def ui_handle_resize(self, width, height):
+ pass
+
+ def mainloop(self):
+ Image.core.eventloop()
+
+
+class ImageWindow(Window):
+ """Create an image window which displays the given image."""
+
+ def __init__(self, image, title="PIL"):
+ if not isinstance(image, Dib):
+ image = Dib(image)
+ self.image = image
+ width, height = image.size
+ Window.__init__(self, title, width=width, height=height)
+
+ def ui_handle_repair(self, dc, x0, y0, x1, y1):
+ self.image.draw(dc, (x0, y0, x1, y1))
diff --git a/contrib/python/Pillow/py2/PIL/ImtImagePlugin.py b/contrib/python/Pillow/py2/PIL/ImtImagePlugin.py
new file mode 100644
index 0000000000..a9e991fbe5
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/ImtImagePlugin.py
@@ -0,0 +1,98 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# IM Tools support for PIL
+#
+# history:
+# 1996-05-27 fl Created (read 8-bit images only)
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.2)
+#
+# Copyright (c) Secret Labs AB 1997-2001.
+# Copyright (c) Fredrik Lundh 1996-2001.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import re
+
+from . import Image, ImageFile
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.2"
+
+
+#
+# --------------------------------------------------------------------
+
+field = re.compile(br"([a-z]*) ([^ \r\n]*)")
+
+
+##
+# Image plugin for IM Tools images.
+
+
+class ImtImageFile(ImageFile.ImageFile):
+
+ format = "IMT"
+ format_description = "IM Tools"
+
+ def _open(self):
+
+ # Quick rejection: if there's not a LF among the first
+ # 100 bytes, this is (probably) not a text header.
+
+ if b"\n" not in self.fp.read(100):
+ raise SyntaxError("not an IM file")
+ self.fp.seek(0)
+
+ xsize = ysize = 0
+
+ while True:
+
+ s = self.fp.read(1)
+ if not s:
+ break
+
+ if s == b"\x0C":
+
+ # image data begins
+ self.tile = [
+ ("raw", (0, 0) + self.size, self.fp.tell(), (self.mode, 0, 1))
+ ]
+
+ break
+
+ else:
+
+ # read key/value pair
+ # FIXME: dangerous, may read whole file
+ s = s + self.fp.readline()
+ if len(s) == 1 or len(s) > 100:
+ break
+ if s[0] == ord(b"*"):
+ continue # comment
+
+ m = field.match(s)
+ if not m:
+ break
+ k, v = m.group(1, 2)
+ if k == "width":
+ xsize = int(v)
+ self._size = xsize, ysize
+ elif k == "height":
+ ysize = int(v)
+ self._size = xsize, ysize
+ elif k == "pixel" and v == "n8":
+ self.mode = "L"
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_open(ImtImageFile.format, ImtImageFile)
+
+#
+# no extension registered (".im" is simply too common)
diff --git a/contrib/python/Pillow/py2/PIL/IptcImagePlugin.py b/contrib/python/Pillow/py2/PIL/IptcImagePlugin.py
new file mode 100644
index 0000000000..aedf2e48cc
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/IptcImagePlugin.py
@@ -0,0 +1,233 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# IPTC/NAA file handling
+#
+# history:
+# 1995-10-01 fl Created
+# 1998-03-09 fl Cleaned up and added to PIL
+# 2002-06-18 fl Added getiptcinfo helper
+#
+# Copyright (c) Secret Labs AB 1997-2002.
+# Copyright (c) Fredrik Lundh 1995.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import print_function
+
+import os
+import tempfile
+
+from . import Image, ImageFile
+from ._binary import i8, i16be as i16, i32be as i32, o8
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.3"
+
+COMPRESSION = {1: "raw", 5: "jpeg"}
+
+PAD = o8(0) * 4
+
+
+#
+# Helpers
+
+
+def i(c):
+ return i32((PAD + c)[-4:])
+
+
+def dump(c):
+ for i in c:
+ print("%02x" % i8(i), end=" ")
+ print()
+
+
+##
+# Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields
+# from TIFF and JPEG files, use the <b>getiptcinfo</b> function.
+
+
+class IptcImageFile(ImageFile.ImageFile):
+
+ format = "IPTC"
+ format_description = "IPTC/NAA"
+
+ def getint(self, key):
+ return i(self.info[key])
+
+ def field(self):
+ #
+ # get a IPTC field header
+ s = self.fp.read(5)
+ if not len(s):
+ return None, 0
+
+ tag = i8(s[1]), i8(s[2])
+
+ # syntax
+ if i8(s[0]) != 0x1C or tag[0] < 1 or tag[0] > 9:
+ raise SyntaxError("invalid IPTC/NAA file")
+
+ # field size
+ size = i8(s[3])
+ if size > 132:
+ raise IOError("illegal field length in IPTC/NAA file")
+ elif size == 128:
+ size = 0
+ elif size > 128:
+ size = i(self.fp.read(size - 128))
+ else:
+ size = i16(s[3:])
+
+ return tag, size
+
+ def _open(self):
+
+ # load descriptive fields
+ while True:
+ offset = self.fp.tell()
+ tag, size = self.field()
+ if not tag or tag == (8, 10):
+ break
+ if size:
+ tagdata = self.fp.read(size)
+ else:
+ tagdata = None
+ if tag in self.info:
+ if isinstance(self.info[tag], list):
+ self.info[tag].append(tagdata)
+ else:
+ self.info[tag] = [self.info[tag], tagdata]
+ else:
+ self.info[tag] = tagdata
+
+ # mode
+ layers = i8(self.info[(3, 60)][0])
+ component = i8(self.info[(3, 60)][1])
+ if (3, 65) in self.info:
+ id = i8(self.info[(3, 65)][0]) - 1
+ else:
+ id = 0
+ if layers == 1 and not component:
+ self.mode = "L"
+ elif layers == 3 and component:
+ self.mode = "RGB"[id]
+ elif layers == 4 and component:
+ self.mode = "CMYK"[id]
+
+ # size
+ self._size = self.getint((3, 20)), self.getint((3, 30))
+
+ # compression
+ try:
+ compression = COMPRESSION[self.getint((3, 120))]
+ except KeyError:
+ raise IOError("Unknown IPTC image compression")
+
+ # tile
+ if tag == (8, 10):
+ self.tile = [
+ ("iptc", (compression, offset), (0, 0, self.size[0], self.size[1]))
+ ]
+
+ def load(self):
+
+ if len(self.tile) != 1 or self.tile[0][0] != "iptc":
+ return ImageFile.ImageFile.load(self)
+
+ type, tile, box = self.tile[0]
+
+ encoding, offset = tile
+
+ self.fp.seek(offset)
+
+ # Copy image data to temporary file
+ o_fd, outfile = tempfile.mkstemp(text=False)
+ o = os.fdopen(o_fd)
+ if encoding == "raw":
+ # To simplify access to the extracted file,
+ # prepend a PPM header
+ o.write("P5\n%d %d\n255\n" % self.size)
+ while True:
+ type, size = self.field()
+ if type != (8, 10):
+ break
+ while size > 0:
+ s = self.fp.read(min(size, 8192))
+ if not s:
+ break
+ o.write(s)
+ size -= len(s)
+ o.close()
+
+ try:
+ _im = Image.open(outfile)
+ _im.load()
+ self.im = _im.im
+ finally:
+ try:
+ os.unlink(outfile)
+ except OSError:
+ pass
+
+
+Image.register_open(IptcImageFile.format, IptcImageFile)
+
+Image.register_extension(IptcImageFile.format, ".iim")
+
+
+def getiptcinfo(im):
+ """
+ Get IPTC information from TIFF, JPEG, or IPTC file.
+
+ :param im: An image containing IPTC data.
+ :returns: A dictionary containing IPTC information, or None if
+ no IPTC information block was found.
+ """
+ from . import TiffImagePlugin, JpegImagePlugin
+ import io
+
+ data = None
+
+ if isinstance(im, IptcImageFile):
+ # return info dictionary right away
+ return im.info
+
+ elif isinstance(im, JpegImagePlugin.JpegImageFile):
+ # extract the IPTC/NAA resource
+ photoshop = im.info.get("photoshop")
+ if photoshop:
+ data = photoshop.get(0x0404)
+
+ elif isinstance(im, TiffImagePlugin.TiffImageFile):
+ # get raw data from the IPTC/NAA tag (PhotoShop tags the data
+ # as 4-byte integers, so we cannot use the get method...)
+ try:
+ data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK]
+ except (AttributeError, KeyError):
+ pass
+
+ if data is None:
+ return None # no properties
+
+ # create an IptcImagePlugin object without initializing it
+ class FakeImage(object):
+ pass
+
+ im = FakeImage()
+ im.__class__ = IptcImageFile
+
+ # parse the IPTC information chunk
+ im.info = {}
+ im.fp = io.BytesIO(data)
+
+ try:
+ im._open()
+ except (IndexError, KeyError):
+ pass # expected failure
+
+ return im.info
diff --git a/contrib/python/Pillow/py2/PIL/Jpeg2KImagePlugin.py b/contrib/python/Pillow/py2/PIL/Jpeg2KImagePlugin.py
new file mode 100644
index 0000000000..37f111778c
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/Jpeg2KImagePlugin.py
@@ -0,0 +1,308 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# JPEG2000 file handling
+#
+# History:
+# 2014-03-12 ajh Created
+#
+# Copyright (c) 2014 Coriolis Systems Limited
+# Copyright (c) 2014 Alastair Houghton
+#
+# See the README file for information on usage and redistribution.
+#
+import io
+import os
+import struct
+
+from . import Image, ImageFile
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+
+def _parse_codestream(fp):
+ """Parse the JPEG 2000 codestream to extract the size and component
+ count from the SIZ marker segment, returning a PIL (size, mode) tuple."""
+
+ hdr = fp.read(2)
+ lsiz = struct.unpack(">H", hdr)[0]
+ siz = hdr + fp.read(lsiz - 2)
+ lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, _, _, _, _, csiz = struct.unpack_from(
+ ">HHIIIIIIIIH", siz
+ )
+ ssiz = [None] * csiz
+ xrsiz = [None] * csiz
+ yrsiz = [None] * csiz
+ for i in range(csiz):
+ ssiz[i], xrsiz[i], yrsiz[i] = struct.unpack_from(">BBB", siz, 36 + 3 * i)
+
+ size = (xsiz - xosiz, ysiz - yosiz)
+ if csiz == 1:
+ if (yrsiz[0] & 0x7F) > 8:
+ mode = "I;16"
+ else:
+ mode = "L"
+ elif csiz == 2:
+ mode = "LA"
+ elif csiz == 3:
+ mode = "RGB"
+ elif csiz == 4:
+ mode = "RGBA"
+ else:
+ mode = None
+
+ return (size, mode)
+
+
+def _parse_jp2_header(fp):
+ """Parse the JP2 header box to extract size, component count and
+ color space information, returning a (size, mode, mimetype) tuple."""
+
+ # Find the JP2 header box
+ header = None
+ mimetype = None
+ while True:
+ lbox, tbox = struct.unpack(">I4s", fp.read(8))
+ if lbox == 1:
+ lbox = struct.unpack(">Q", fp.read(8))[0]
+ hlen = 16
+ else:
+ hlen = 8
+
+ if lbox < hlen:
+ raise SyntaxError("Invalid JP2 header length")
+
+ if tbox == b"jp2h":
+ header = fp.read(lbox - hlen)
+ break
+ elif tbox == b"ftyp":
+ if fp.read(4) == b"jpx ":
+ mimetype = "image/jpx"
+ fp.seek(lbox - hlen - 4, os.SEEK_CUR)
+ else:
+ fp.seek(lbox - hlen, os.SEEK_CUR)
+
+ if header is None:
+ raise SyntaxError("could not find JP2 header")
+
+ size = None
+ mode = None
+ bpc = None
+ nc = None
+
+ hio = io.BytesIO(header)
+ while True:
+ lbox, tbox = struct.unpack(">I4s", hio.read(8))
+ if lbox == 1:
+ lbox = struct.unpack(">Q", hio.read(8))[0]
+ hlen = 16
+ else:
+ hlen = 8
+
+ content = hio.read(lbox - hlen)
+
+ if tbox == b"ihdr":
+ height, width, nc, bpc, c, unkc, ipr = struct.unpack(">IIHBBBB", content)
+ size = (width, height)
+ if unkc:
+ if nc == 1 and (bpc & 0x7F) > 8:
+ mode = "I;16"
+ elif nc == 1:
+ mode = "L"
+ elif nc == 2:
+ mode = "LA"
+ elif nc == 3:
+ mode = "RGB"
+ elif nc == 4:
+ mode = "RGBA"
+ break
+ elif tbox == b"colr":
+ meth, prec, approx = struct.unpack_from(">BBB", content)
+ if meth == 1:
+ cs = struct.unpack_from(">I", content, 3)[0]
+ if cs == 16: # sRGB
+ if nc == 1 and (bpc & 0x7F) > 8:
+ mode = "I;16"
+ elif nc == 1:
+ mode = "L"
+ elif nc == 3:
+ mode = "RGB"
+ elif nc == 4:
+ mode = "RGBA"
+ break
+ elif cs == 17: # grayscale
+ if nc == 1 and (bpc & 0x7F) > 8:
+ mode = "I;16"
+ elif nc == 1:
+ mode = "L"
+ elif nc == 2:
+ mode = "LA"
+ break
+ elif cs == 18: # sYCC
+ if nc == 3:
+ mode = "RGB"
+ elif nc == 4:
+ mode = "RGBA"
+ break
+
+ if size is None or mode is None:
+ raise SyntaxError("Malformed jp2 header")
+
+ return (size, mode, mimetype)
+
+
+##
+# Image plugin for JPEG2000 images.
+
+
+class Jpeg2KImageFile(ImageFile.ImageFile):
+ format = "JPEG2000"
+ format_description = "JPEG 2000 (ISO 15444)"
+
+ def _open(self):
+ sig = self.fp.read(4)
+ if sig == b"\xff\x4f\xff\x51":
+ self.codec = "j2k"
+ self._size, self.mode = _parse_codestream(self.fp)
+ else:
+ sig = sig + self.fp.read(8)
+
+ if sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a":
+ self.codec = "jp2"
+ header = _parse_jp2_header(self.fp)
+ self._size, self.mode, self.custom_mimetype = header
+ else:
+ raise SyntaxError("not a JPEG 2000 file")
+
+ if self.size is None or self.mode is None:
+ raise SyntaxError("unable to determine size/mode")
+
+ self.reduce = 0
+ self.layers = 0
+
+ fd = -1
+ length = -1
+
+ try:
+ fd = self.fp.fileno()
+ length = os.fstat(fd).st_size
+ except Exception:
+ fd = -1
+ try:
+ pos = self.fp.tell()
+ self.fp.seek(0, io.SEEK_END)
+ length = self.fp.tell()
+ self.fp.seek(pos)
+ except Exception:
+ length = -1
+
+ self.tile = [
+ (
+ "jpeg2k",
+ (0, 0) + self.size,
+ 0,
+ (self.codec, self.reduce, self.layers, fd, length),
+ )
+ ]
+
+ def load(self):
+ if self.reduce:
+ power = 1 << self.reduce
+ adjust = power >> 1
+ self._size = (
+ int((self.size[0] + adjust) / power),
+ int((self.size[1] + adjust) / power),
+ )
+
+ if self.tile:
+ # Update the reduce and layers settings
+ t = self.tile[0]
+ t3 = (t[3][0], self.reduce, self.layers, t[3][3], t[3][4])
+ self.tile = [(t[0], (0, 0) + self.size, t[2], t3)]
+
+ return ImageFile.ImageFile.load(self)
+
+
+def _accept(prefix):
+ return (
+ prefix[:4] == b"\xff\x4f\xff\x51"
+ or prefix[:12] == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a"
+ )
+
+
+# ------------------------------------------------------------
+# Save support
+
+
+def _save(im, fp, filename):
+ if filename.endswith(".j2k"):
+ kind = "j2k"
+ else:
+ kind = "jp2"
+
+ # Get the keyword arguments
+ info = im.encoderinfo
+
+ offset = info.get("offset", None)
+ tile_offset = info.get("tile_offset", None)
+ tile_size = info.get("tile_size", None)
+ quality_mode = info.get("quality_mode", "rates")
+ quality_layers = info.get("quality_layers", None)
+ if quality_layers is not None and not (
+ isinstance(quality_layers, (list, tuple))
+ and all(
+ [
+ isinstance(quality_layer, (int, float))
+ for quality_layer in quality_layers
+ ]
+ )
+ ):
+ raise ValueError("quality_layers must be a sequence of numbers")
+
+ num_resolutions = info.get("num_resolutions", 0)
+ cblk_size = info.get("codeblock_size", None)
+ precinct_size = info.get("precinct_size", None)
+ irreversible = info.get("irreversible", False)
+ progression = info.get("progression", "LRCP")
+ cinema_mode = info.get("cinema_mode", "no")
+ fd = -1
+
+ if hasattr(fp, "fileno"):
+ try:
+ fd = fp.fileno()
+ except Exception:
+ fd = -1
+
+ im.encoderconfig = (
+ offset,
+ tile_offset,
+ tile_size,
+ quality_mode,
+ quality_layers,
+ num_resolutions,
+ cblk_size,
+ precinct_size,
+ irreversible,
+ progression,
+ cinema_mode,
+ fd,
+ )
+
+ ImageFile._save(im, fp, [("jpeg2k", (0, 0) + im.size, 0, kind)])
+
+
+# ------------------------------------------------------------
+# Registry stuff
+
+
+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_mime(Jpeg2KImageFile.format, "image/jp2")
diff --git a/contrib/python/Pillow/py2/PIL/JpegImagePlugin.py b/contrib/python/Pillow/py2/PIL/JpegImagePlugin.py
new file mode 100644
index 0000000000..020b952192
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/JpegImagePlugin.py
@@ -0,0 +1,817 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# JPEG (JFIF) file handling
+#
+# See "Digital Compression and Coding of Continuous-Tone Still Images,
+# Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1)
+#
+# History:
+# 1995-09-09 fl Created
+# 1995-09-13 fl Added full parser
+# 1996-03-25 fl Added hack to use the IJG command line utilities
+# 1996-05-05 fl Workaround Photoshop 2.5 CMYK polarity bug
+# 1996-05-28 fl Added draft support, JFIF version (0.1)
+# 1996-12-30 fl Added encoder options, added progression property (0.2)
+# 1997-08-27 fl Save mode 1 images as BW (0.3)
+# 1998-07-12 fl Added YCbCr to draft and save methods (0.4)
+# 1998-10-19 fl Don't hang on files using 16-bit DQT's (0.4.1)
+# 2001-04-16 fl Extract DPI settings from JFIF files (0.4.2)
+# 2002-07-01 fl Skip pad bytes before markers; identify Exif files (0.4.3)
+# 2003-04-25 fl Added experimental EXIF decoder (0.5)
+# 2003-06-06 fl Added experimental EXIF GPSinfo decoder
+# 2003-09-13 fl Extract COM markers
+# 2009-09-06 fl Added icc_profile support (from Florian Hoech)
+# 2009-03-06 fl Changed CMYK handling; always use Adobe polarity (0.6)
+# 2009-03-08 fl Added subsampling support (from Justin Huff).
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-1996 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import print_function
+
+import array
+import io
+import struct
+import warnings
+
+from . import Image, ImageFile, TiffImagePlugin
+from ._binary import i8, i16be as i16, i32be as i32, o8
+from ._util import isStringType
+from .JpegPresets import presets
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.6"
+
+
+#
+# Parser
+
+
+def Skip(self, marker):
+ n = i16(self.fp.read(2)) - 2
+ ImageFile._safe_read(self.fp, n)
+
+
+def APP(self, marker):
+ #
+ # Application marker. Store these in the APP dictionary.
+ # Also look for well-known application markers.
+
+ n = i16(self.fp.read(2)) - 2
+ s = ImageFile._safe_read(self.fp, n)
+
+ app = "APP%d" % (marker & 15)
+
+ self.app[app] = s # compatibility
+ self.applist.append((app, s))
+
+ if marker == 0xFFE0 and s[:4] == b"JFIF":
+ # extract JFIF information
+ self.info["jfif"] = version = i16(s, 5) # version
+ self.info["jfif_version"] = divmod(version, 256)
+ # extract JFIF properties
+ try:
+ jfif_unit = i8(s[7])
+ jfif_density = i16(s, 8), i16(s, 10)
+ except Exception:
+ pass
+ else:
+ if jfif_unit == 1:
+ self.info["dpi"] = jfif_density
+ self.info["jfif_unit"] = jfif_unit
+ self.info["jfif_density"] = jfif_density
+ elif marker == 0xFFE1 and s[:5] == b"Exif\0":
+ if "exif" not in self.info:
+ # extract EXIF information (incomplete)
+ self.info["exif"] = s # FIXME: value will change
+ elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
+ # extract FlashPix information (incomplete)
+ self.info["flashpix"] = s # FIXME: value will change
+ elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0":
+ # Since an ICC profile can be larger than the maximum size of
+ # a JPEG marker (64K), we need provisions to split it into
+ # multiple markers. The format defined by the ICC specifies
+ # one or more APP2 markers containing the following data:
+ # Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
+ # Marker sequence number 1, 2, etc (1 byte)
+ # Number of markers Total of APP2's used (1 byte)
+ # Profile data (remainder of APP2 data)
+ # Decoders should use the marker sequence numbers to
+ # reassemble the profile, rather than assuming that the APP2
+ # markers appear in the correct sequence.
+ self.icclist.append(s)
+ elif marker == 0xFFED:
+ if s[:14] == b"Photoshop 3.0\x00":
+ blocks = s[14:]
+ # parse the image resource block
+ offset = 0
+ photoshop = {}
+ while blocks[offset : offset + 4] == b"8BIM":
+ offset += 4
+ # resource code
+ code = i16(blocks, offset)
+ offset += 2
+ # resource name (usually empty)
+ name_len = i8(blocks[offset])
+ # name = blocks[offset+1:offset+1+name_len]
+ offset = 1 + offset + name_len
+ if offset & 1:
+ offset += 1
+ # resource data block
+ size = i32(blocks, offset)
+ offset += 4
+ data = blocks[offset : offset + size]
+ if code == 0x03ED: # ResolutionInfo
+ data = {
+ "XResolution": i32(data[:4]) / 65536,
+ "DisplayedUnitsX": i16(data[4:8]),
+ "YResolution": i32(data[8:12]) / 65536,
+ "DisplayedUnitsY": i16(data[12:]),
+ }
+ photoshop[code] = data
+ offset = offset + size
+ if offset & 1:
+ offset += 1
+ self.info["photoshop"] = photoshop
+ elif marker == 0xFFEE and s[:5] == b"Adobe":
+ self.info["adobe"] = i16(s, 5)
+ # extract Adobe custom properties
+ try:
+ adobe_transform = i8(s[1])
+ except Exception:
+ pass
+ else:
+ self.info["adobe_transform"] = adobe_transform
+ elif marker == 0xFFE2 and s[:4] == b"MPF\0":
+ # extract MPO information
+ self.info["mp"] = s[4:]
+ # offset is current location minus buffer size
+ # plus constant header size
+ self.info["mpoffset"] = self.fp.tell() - n + 4
+
+ # If DPI isn't in JPEG header, fetch from EXIF
+ if "dpi" not in self.info and "exif" in self.info:
+ try:
+ exif = self.getexif()
+ resolution_unit = exif[0x0128]
+ x_resolution = exif[0x011A]
+ try:
+ dpi = float(x_resolution[0]) / x_resolution[1]
+ except TypeError:
+ dpi = x_resolution
+ if resolution_unit == 3: # cm
+ # 1 dpcm = 2.54 dpi
+ dpi *= 2.54
+ self.info["dpi"] = int(dpi + 0.5), int(dpi + 0.5)
+ except (KeyError, SyntaxError, ZeroDivisionError):
+ # SyntaxError for invalid/unreadable EXIF
+ # KeyError for dpi not included
+ # ZeroDivisionError for invalid dpi rational value
+ self.info["dpi"] = 72, 72
+
+
+def COM(self, marker):
+ #
+ # Comment marker. Store these in the APP dictionary.
+ n = i16(self.fp.read(2)) - 2
+ s = ImageFile._safe_read(self.fp, n)
+
+ self.app["COM"] = s # compatibility
+ self.applist.append(("COM", s))
+
+
+def SOF(self, marker):
+ #
+ # Start of frame marker. Defines the size and mode of the
+ # image. JPEG is colour blind, so we use some simple
+ # heuristics to map the number of layers to an appropriate
+ # mode. Note that this could be made a bit brighter, by
+ # looking for JFIF and Adobe APP markers.
+
+ n = i16(self.fp.read(2)) - 2
+ s = ImageFile._safe_read(self.fp, n)
+ self._size = i16(s[3:]), i16(s[1:])
+
+ self.bits = i8(s[0])
+ if self.bits != 8:
+ raise SyntaxError("cannot handle %d-bit layers" % self.bits)
+
+ self.layers = i8(s[5])
+ if self.layers == 1:
+ self.mode = "L"
+ elif self.layers == 3:
+ self.mode = "RGB"
+ elif self.layers == 4:
+ self.mode = "CMYK"
+ else:
+ raise SyntaxError("cannot handle %d-layer images" % self.layers)
+
+ if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]:
+ self.info["progressive"] = self.info["progression"] = 1
+
+ if self.icclist:
+ # fixup icc profile
+ self.icclist.sort() # sort by sequence number
+ if i8(self.icclist[0][13]) == len(self.icclist):
+ profile = []
+ for p in self.icclist:
+ profile.append(p[14:])
+ icc_profile = b"".join(profile)
+ else:
+ icc_profile = None # wrong number of fragments
+ self.info["icc_profile"] = icc_profile
+ self.icclist = None
+
+ for i in range(6, len(s), 3):
+ t = s[i : i + 3]
+ # 4-tuples: id, vsamp, hsamp, qtable
+ self.layer.append((t[0], i8(t[1]) // 16, i8(t[1]) & 15, i8(t[2])))
+
+
+def DQT(self, marker):
+ #
+ # Define quantization table. Support baseline 8-bit tables
+ # only. Note that there might be more than one table in
+ # each marker.
+
+ # FIXME: The quantization tables can be used to estimate the
+ # compression quality.
+
+ n = i16(self.fp.read(2)) - 2
+ s = ImageFile._safe_read(self.fp, n)
+ while len(s):
+ if len(s) < 65:
+ raise SyntaxError("bad quantization table marker")
+ v = i8(s[0])
+ if v // 16 == 0:
+ self.quantization[v & 15] = array.array("B", s[1:65])
+ s = s[65:]
+ else:
+ return # FIXME: add code to read 16-bit tables!
+ # raise SyntaxError, "bad quantization table element size"
+
+
+#
+# JPEG marker table
+
+MARKER = {
+ 0xFFC0: ("SOF0", "Baseline DCT", SOF),
+ 0xFFC1: ("SOF1", "Extended Sequential DCT", SOF),
+ 0xFFC2: ("SOF2", "Progressive DCT", SOF),
+ 0xFFC3: ("SOF3", "Spatial lossless", SOF),
+ 0xFFC4: ("DHT", "Define Huffman table", Skip),
+ 0xFFC5: ("SOF5", "Differential sequential DCT", SOF),
+ 0xFFC6: ("SOF6", "Differential progressive DCT", SOF),
+ 0xFFC7: ("SOF7", "Differential spatial", SOF),
+ 0xFFC8: ("JPG", "Extension", None),
+ 0xFFC9: ("SOF9", "Extended sequential DCT (AC)", SOF),
+ 0xFFCA: ("SOF10", "Progressive DCT (AC)", SOF),
+ 0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", SOF),
+ 0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip),
+ 0xFFCD: ("SOF13", "Differential sequential DCT (AC)", SOF),
+ 0xFFCE: ("SOF14", "Differential progressive DCT (AC)", SOF),
+ 0xFFCF: ("SOF15", "Differential spatial (AC)", SOF),
+ 0xFFD0: ("RST0", "Restart 0", None),
+ 0xFFD1: ("RST1", "Restart 1", None),
+ 0xFFD2: ("RST2", "Restart 2", None),
+ 0xFFD3: ("RST3", "Restart 3", None),
+ 0xFFD4: ("RST4", "Restart 4", None),
+ 0xFFD5: ("RST5", "Restart 5", None),
+ 0xFFD6: ("RST6", "Restart 6", None),
+ 0xFFD7: ("RST7", "Restart 7", None),
+ 0xFFD8: ("SOI", "Start of image", None),
+ 0xFFD9: ("EOI", "End of image", None),
+ 0xFFDA: ("SOS", "Start of scan", Skip),
+ 0xFFDB: ("DQT", "Define quantization table", DQT),
+ 0xFFDC: ("DNL", "Define number of lines", Skip),
+ 0xFFDD: ("DRI", "Define restart interval", Skip),
+ 0xFFDE: ("DHP", "Define hierarchical progression", SOF),
+ 0xFFDF: ("EXP", "Expand reference component", Skip),
+ 0xFFE0: ("APP0", "Application segment 0", APP),
+ 0xFFE1: ("APP1", "Application segment 1", APP),
+ 0xFFE2: ("APP2", "Application segment 2", APP),
+ 0xFFE3: ("APP3", "Application segment 3", APP),
+ 0xFFE4: ("APP4", "Application segment 4", APP),
+ 0xFFE5: ("APP5", "Application segment 5", APP),
+ 0xFFE6: ("APP6", "Application segment 6", APP),
+ 0xFFE7: ("APP7", "Application segment 7", APP),
+ 0xFFE8: ("APP8", "Application segment 8", APP),
+ 0xFFE9: ("APP9", "Application segment 9", APP),
+ 0xFFEA: ("APP10", "Application segment 10", APP),
+ 0xFFEB: ("APP11", "Application segment 11", APP),
+ 0xFFEC: ("APP12", "Application segment 12", APP),
+ 0xFFED: ("APP13", "Application segment 13", APP),
+ 0xFFEE: ("APP14", "Application segment 14", APP),
+ 0xFFEF: ("APP15", "Application segment 15", APP),
+ 0xFFF0: ("JPG0", "Extension 0", None),
+ 0xFFF1: ("JPG1", "Extension 1", None),
+ 0xFFF2: ("JPG2", "Extension 2", None),
+ 0xFFF3: ("JPG3", "Extension 3", None),
+ 0xFFF4: ("JPG4", "Extension 4", None),
+ 0xFFF5: ("JPG5", "Extension 5", None),
+ 0xFFF6: ("JPG6", "Extension 6", None),
+ 0xFFF7: ("JPG7", "Extension 7", None),
+ 0xFFF8: ("JPG8", "Extension 8", None),
+ 0xFFF9: ("JPG9", "Extension 9", None),
+ 0xFFFA: ("JPG10", "Extension 10", None),
+ 0xFFFB: ("JPG11", "Extension 11", None),
+ 0xFFFC: ("JPG12", "Extension 12", None),
+ 0xFFFD: ("JPG13", "Extension 13", None),
+ 0xFFFE: ("COM", "Comment", COM),
+}
+
+
+def _accept(prefix):
+ return prefix[0:1] == b"\377"
+
+
+##
+# Image plugin for JPEG and JFIF images.
+
+
+class JpegImageFile(ImageFile.ImageFile):
+
+ format = "JPEG"
+ format_description = "JPEG (ISO 10918)"
+
+ def _open(self):
+
+ s = self.fp.read(1)
+
+ if i8(s) != 255:
+ raise SyntaxError("not a JPEG file")
+
+ # Create attributes
+ self.bits = self.layers = 0
+
+ # JPEG specifics (internal)
+ self.layer = []
+ self.huffman_dc = {}
+ self.huffman_ac = {}
+ self.quantization = {}
+ self.app = {} # compatibility
+ self.applist = []
+ self.icclist = []
+
+ while True:
+
+ i = i8(s)
+ if i == 0xFF:
+ s = s + self.fp.read(1)
+ i = i16(s)
+ else:
+ # Skip non-0xFF junk
+ s = self.fp.read(1)
+ continue
+
+ if i in MARKER:
+ name, description, handler = MARKER[i]
+ if handler is not None:
+ handler(self, i)
+ if i == 0xFFDA: # start of scan
+ rawmode = self.mode
+ if self.mode == "CMYK":
+ rawmode = "CMYK;I" # assume adobe conventions
+ self.tile = [("jpeg", (0, 0) + self.size, 0, (rawmode, ""))]
+ # self.__offset = self.fp.tell()
+ break
+ s = self.fp.read(1)
+ elif i == 0 or i == 0xFFFF:
+ # padded marker or junk; move on
+ s = b"\xff"
+ elif i == 0xFF00: # Skip extraneous data (escaped 0xFF)
+ s = self.fp.read(1)
+ else:
+ raise SyntaxError("no marker found")
+
+ def load_read(self, read_bytes):
+ """
+ internal: read more image data
+ For premature EOF and LOAD_TRUNCATED_IMAGES adds EOI marker
+ so libjpeg can finish decoding
+ """
+ s = self.fp.read(read_bytes)
+
+ if not s and ImageFile.LOAD_TRUNCATED_IMAGES:
+ # Premature EOF.
+ # Pretend file is finished adding EOI marker
+ return b"\xFF\xD9"
+
+ return s
+
+ def draft(self, mode, size):
+
+ if len(self.tile) != 1:
+ return
+
+ # Protect from second call
+ if self.decoderconfig:
+ return
+
+ d, e, o, a = self.tile[0]
+ scale = 0
+
+ if a[0] == "RGB" and mode in ["L", "YCbCr"]:
+ self.mode = mode
+ a = mode, ""
+
+ if size:
+ scale = min(self.size[0] // size[0], self.size[1] // size[1])
+ for s in [8, 4, 2, 1]:
+ if scale >= s:
+ break
+ e = (
+ e[0],
+ e[1],
+ (e[2] - e[0] + s - 1) // s + e[0],
+ (e[3] - e[1] + s - 1) // s + e[1],
+ )
+ self._size = ((self.size[0] + s - 1) // s, (self.size[1] + s - 1) // s)
+ scale = s
+
+ self.tile = [(d, e, o, a)]
+ self.decoderconfig = (scale, 0)
+
+ return self
+
+ def load_djpeg(self):
+
+ # ALTERNATIVE: handle JPEGs via the IJG command line utilities
+
+ import subprocess
+ import tempfile
+ import os
+
+ f, path = tempfile.mkstemp()
+ os.close(f)
+ if os.path.exists(self.filename):
+ subprocess.check_call(["djpeg", "-outfile", path, self.filename])
+ else:
+ raise ValueError("Invalid Filename")
+
+ try:
+ _im = Image.open(path)
+ _im.load()
+ self.im = _im.im
+ finally:
+ try:
+ os.unlink(path)
+ except OSError:
+ pass
+
+ self.mode = self.im.mode
+ self._size = self.im.size
+
+ self.tile = []
+
+ def _getexif(self):
+ return _getexif(self)
+
+ def _getmp(self):
+ return _getmp(self)
+
+
+def _fixup_dict(src_dict):
+ # Helper function for _getexif()
+ # returns a dict with any single item tuples/lists as individual values
+ exif = Image.Exif()
+ return exif._fixup_dict(src_dict)
+
+
+def _getexif(self):
+ if "exif" not in self.info:
+ return None
+ return dict(self.getexif())
+
+
+def _getmp(self):
+ # Extract MP information. This method was inspired by the "highly
+ # experimental" _getexif version that's been in use for years now,
+ # itself based on the ImageFileDirectory class in the TIFF plug-in.
+
+ # The MP record essentially consists of a TIFF file embedded in a JPEG
+ # application marker.
+ try:
+ data = self.info["mp"]
+ except KeyError:
+ return None
+ file_contents = io.BytesIO(data)
+ head = file_contents.read(8)
+ endianness = ">" if head[:4] == b"\x4d\x4d\x00\x2a" else "<"
+ # process dictionary
+ try:
+ info = TiffImagePlugin.ImageFileDirectory_v2(head)
+ file_contents.seek(info.next)
+ info.load(file_contents)
+ mp = dict(info)
+ except Exception:
+ raise SyntaxError("malformed MP Index (unreadable directory)")
+ # it's an error not to have a number of images
+ try:
+ quant = mp[0xB001]
+ except KeyError:
+ raise SyntaxError("malformed MP Index (no number of images)")
+ # get MP entries
+ mpentries = []
+ try:
+ rawmpentries = mp[0xB002]
+ for entrynum in range(0, quant):
+ unpackedentry = struct.unpack_from(
+ "{}LLLHH".format(endianness), rawmpentries, entrynum * 16
+ )
+ labels = ("Attribute", "Size", "DataOffset", "EntryNo1", "EntryNo2")
+ mpentry = dict(zip(labels, unpackedentry))
+ mpentryattr = {
+ "DependentParentImageFlag": bool(mpentry["Attribute"] & (1 << 31)),
+ "DependentChildImageFlag": bool(mpentry["Attribute"] & (1 << 30)),
+ "RepresentativeImageFlag": bool(mpentry["Attribute"] & (1 << 29)),
+ "Reserved": (mpentry["Attribute"] & (3 << 27)) >> 27,
+ "ImageDataFormat": (mpentry["Attribute"] & (7 << 24)) >> 24,
+ "MPType": mpentry["Attribute"] & 0x00FFFFFF,
+ }
+ if mpentryattr["ImageDataFormat"] == 0:
+ mpentryattr["ImageDataFormat"] = "JPEG"
+ else:
+ raise SyntaxError("unsupported picture format in MPO")
+ mptypemap = {
+ 0x000000: "Undefined",
+ 0x010001: "Large Thumbnail (VGA Equivalent)",
+ 0x010002: "Large Thumbnail (Full HD Equivalent)",
+ 0x020001: "Multi-Frame Image (Panorama)",
+ 0x020002: "Multi-Frame Image: (Disparity)",
+ 0x020003: "Multi-Frame Image: (Multi-Angle)",
+ 0x030000: "Baseline MP Primary Image",
+ }
+ mpentryattr["MPType"] = mptypemap.get(mpentryattr["MPType"], "Unknown")
+ mpentry["Attribute"] = mpentryattr
+ mpentries.append(mpentry)
+ mp[0xB002] = mpentries
+ except KeyError:
+ raise SyntaxError("malformed MP Index (bad MP Entry)")
+ # Next we should try and parse the individual image unique ID list;
+ # we don't because I've never seen this actually used in a real MPO
+ # file and so can't test it.
+ return mp
+
+
+# --------------------------------------------------------------------
+# stuff to save JPEG files
+
+RAWMODE = {
+ "1": "L",
+ "L": "L",
+ "RGB": "RGB",
+ "RGBX": "RGB",
+ "CMYK": "CMYK;I", # assume adobe conventions
+ "YCbCr": "YCbCr",
+}
+
+# fmt: off
+zigzag_index = (
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63,
+)
+
+samplings = {
+ (1, 1, 1, 1, 1, 1): 0,
+ (2, 1, 1, 1, 1, 1): 1,
+ (2, 2, 1, 1, 1, 1): 2,
+}
+# fmt: on
+
+
+def convert_dict_qtables(qtables):
+ qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
+ for idx, table in enumerate(qtables):
+ qtables[idx] = [table[i] for i in zigzag_index]
+ return qtables
+
+
+def get_sampling(im):
+ # There's no subsampling when image have only 1 layer
+ # (grayscale images) or when they are CMYK (4 layers),
+ # so set subsampling to default value.
+ #
+ # NOTE: currently Pillow can't encode JPEG to YCCK format.
+ # If YCCK support is added in the future, subsampling code will have
+ # to be updated (here and in JpegEncode.c) to deal with 4 layers.
+ if not hasattr(im, "layers") or im.layers in (1, 4):
+ return -1
+ sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3]
+ return samplings.get(sampling, -1)
+
+
+def _save(im, fp, filename):
+
+ try:
+ rawmode = RAWMODE[im.mode]
+ except KeyError:
+ raise IOError("cannot write mode %s as JPEG" % im.mode)
+
+ info = im.encoderinfo
+
+ dpi = [int(round(x)) for x in info.get("dpi", (0, 0))]
+
+ quality = info.get("quality", 0)
+ subsampling = info.get("subsampling", -1)
+ qtables = info.get("qtables")
+
+ if quality == "keep":
+ quality = 0
+ subsampling = "keep"
+ qtables = "keep"
+ elif quality in presets:
+ preset = presets[quality]
+ quality = 0
+ subsampling = preset.get("subsampling", -1)
+ qtables = preset.get("quantization")
+ elif not isinstance(quality, int):
+ raise ValueError("Invalid quality setting")
+ else:
+ if subsampling in presets:
+ subsampling = presets[subsampling].get("subsampling", -1)
+ if isStringType(qtables) and qtables in presets:
+ qtables = presets[qtables].get("quantization")
+
+ if subsampling == "4:4:4":
+ subsampling = 0
+ elif subsampling == "4:2:2":
+ subsampling = 1
+ elif subsampling == "4:2:0":
+ subsampling = 2
+ elif subsampling == "4:1:1":
+ # For compatibility. Before Pillow 4.3, 4:1:1 actually meant 4:2:0.
+ # Set 4:2:0 if someone is still using that value.
+ subsampling = 2
+ elif subsampling == "keep":
+ if im.format != "JPEG":
+ raise ValueError("Cannot use 'keep' when original image is not a JPEG")
+ subsampling = get_sampling(im)
+
+ def validate_qtables(qtables):
+ if qtables is None:
+ return qtables
+ if isStringType(qtables):
+ try:
+ lines = [
+ int(num)
+ for line in qtables.splitlines()
+ for num in line.split("#", 1)[0].split()
+ ]
+ except ValueError:
+ raise ValueError("Invalid quantization table")
+ else:
+ qtables = [lines[s : s + 64] for s in range(0, len(lines), 64)]
+ if isinstance(qtables, (tuple, list, dict)):
+ if isinstance(qtables, dict):
+ qtables = convert_dict_qtables(qtables)
+ elif isinstance(qtables, tuple):
+ qtables = list(qtables)
+ if not (0 < len(qtables) < 5):
+ raise ValueError("None or too many quantization tables")
+ for idx, table in enumerate(qtables):
+ try:
+ if len(table) != 64:
+ raise TypeError
+ table = array.array("B", table)
+ except TypeError:
+ raise ValueError("Invalid quantization table")
+ else:
+ qtables[idx] = list(table)
+ return qtables
+
+ if qtables == "keep":
+ if im.format != "JPEG":
+ raise ValueError("Cannot use 'keep' when original image is not a JPEG")
+ qtables = getattr(im, "quantization", None)
+ qtables = validate_qtables(qtables)
+
+ extra = b""
+
+ icc_profile = info.get("icc_profile")
+ if icc_profile:
+ ICC_OVERHEAD_LEN = 14
+ MAX_BYTES_IN_MARKER = 65533
+ MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
+ markers = []
+ while icc_profile:
+ markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
+ icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
+ i = 1
+ for marker in markers:
+ size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
+ extra += (
+ b"\xFF\xE2"
+ + size
+ + b"ICC_PROFILE\0"
+ + o8(i)
+ + o8(len(markers))
+ + marker
+ )
+ i += 1
+
+ # "progressive" is the official name, but older documentation
+ # says "progression"
+ # FIXME: issue a warning if the wrong form is used (post-1.1.7)
+ progressive = info.get("progressive", False) or info.get("progression", False)
+
+ optimize = info.get("optimize", False)
+
+ exif = info.get("exif", b"")
+ if isinstance(exif, Image.Exif):
+ exif = exif.tobytes()
+
+ # get keyword arguments
+ im.encoderconfig = (
+ quality,
+ progressive,
+ info.get("smooth", 0),
+ optimize,
+ info.get("streamtype", 0),
+ dpi[0],
+ dpi[1],
+ subsampling,
+ qtables,
+ extra,
+ exif,
+ )
+
+ # if we optimize, libjpeg needs a buffer big enough to hold the whole image
+ # in a shot. Guessing on the size, at im.size bytes. (raw pixel size is
+ # channels*size, this is a value that's been used in a django patch.
+ # https://github.com/matthewwithanm/django-imagekit/issues/50
+ bufsize = 0
+ if optimize or progressive:
+ # CMYK can be bigger
+ if im.mode == "CMYK":
+ bufsize = 4 * im.size[0] * im.size[1]
+ # keep sets quality to 0, but the actual value may be high.
+ elif quality >= 95 or quality == 0:
+ bufsize = 2 * im.size[0] * im.size[1]
+ else:
+ bufsize = im.size[0] * im.size[1]
+
+ # The EXIF info needs to be written as one block, + APP1, + one spare byte.
+ # Ensure that our buffer is big enough. Same with the icc_profile block.
+ bufsize = max(ImageFile.MAXBLOCK, bufsize, len(exif) + 5, len(extra) + 1)
+
+ ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
+
+
+def _save_cjpeg(im, fp, filename):
+ # ALTERNATIVE: handle JPEGs via the IJG command line utilities.
+ import os
+ import subprocess
+
+ tempfile = im._dump()
+ subprocess.check_call(["cjpeg", "-outfile", filename, tempfile])
+ try:
+ os.unlink(tempfile)
+ except OSError:
+ pass
+
+
+##
+# Factory for making JPEG and MPO instances
+def jpeg_factory(fp=None, filename=None):
+ im = JpegImageFile(fp, filename)
+ try:
+ mpheader = im._getmp()
+ if mpheader[45057] > 1:
+ # It's actually an MPO
+ from .MpoImagePlugin import MpoImageFile
+
+ # Don't reload everything, just convert it.
+ im = MpoImageFile.adopt(im, mpheader)
+ except (TypeError, IndexError):
+ # It is really a JPEG
+ pass
+ except SyntaxError:
+ warnings.warn(
+ "Image appears to be a malformed MPO file, it will be "
+ "interpreted as a base JPEG file"
+ )
+ return im
+
+
+# ---------------------------------------------------------------------
+# Registry stuff
+
+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_mime(JpegImageFile.format, "image/jpeg")
diff --git a/contrib/python/Pillow/py2/PIL/JpegPresets.py b/contrib/python/Pillow/py2/PIL/JpegPresets.py
new file mode 100644
index 0000000000..387844f8e8
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/JpegPresets.py
@@ -0,0 +1,244 @@
+"""
+JPEG quality settings equivalent to the Photoshop settings.
+
+More presets can be added to the presets dict if needed.
+
+Can be use when saving JPEG file.
+
+To apply the preset, specify::
+
+ quality="preset_name"
+
+To apply only the quantization table::
+
+ qtables="preset_name"
+
+To apply only the subsampling setting::
+
+ subsampling="preset_name"
+
+Example::
+
+ im.save("image_name.jpg", quality="web_high")
+
+
+Subsampling
+-----------
+
+Subsampling is the practice of encoding images by implementing less resolution
+for chroma information than for luma information.
+(ref.: https://en.wikipedia.org/wiki/Chroma_subsampling)
+
+Possible subsampling values are 0, 1 and 2 that correspond to 4:4:4, 4:2:2 and
+4:2:0.
+
+You can get the subsampling of a JPEG with the
+`JpegImagePlugin.get_subsampling(im)` function.
+
+
+Quantization tables
+-------------------
+
+They are values use by the DCT (Discrete cosine transform) to remove
+*unnecessary* information from the image (the lossy part of the compression).
+(ref.: https://en.wikipedia.org/wiki/Quantization_matrix#Quantization_matrices,
+https://en.wikipedia.org/wiki/JPEG#Quantization)
+
+You can get the quantization tables of a JPEG with::
+
+ im.quantization
+
+This will return a dict with a number of arrays. You can pass this dict
+directly as the qtables argument when saving a JPEG.
+
+The tables format between im.quantization and quantization in presets differ in
+3 ways:
+
+1. The base container of the preset is a list with sublists instead of dict.
+ dict[0] -> list[0], dict[1] -> list[1], ...
+2. Each table in a preset is a list instead of an array.
+3. The zigzag order is remove in the preset (needed by libjpeg >= 6a).
+
+You can convert the dict format to the preset format with the
+`JpegImagePlugin.convert_dict_qtables(dict_qtables)` function.
+
+Libjpeg ref.:
+https://web.archive.org/web/20120328125543/http://www.jpegcameras.com/libjpeg/libjpeg-3.html
+
+"""
+
+# fmt: off
+presets = { # noqa: E128
+ 'web_low': {'subsampling': 2, # "4:2:0"
+ 'quantization': [
+ [20, 16, 25, 39, 50, 46, 62, 68,
+ 16, 18, 23, 38, 38, 53, 65, 68,
+ 25, 23, 31, 38, 53, 65, 68, 68,
+ 39, 38, 38, 53, 65, 68, 68, 68,
+ 50, 38, 53, 65, 68, 68, 68, 68,
+ 46, 53, 65, 68, 68, 68, 68, 68,
+ 62, 65, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68],
+ [21, 25, 32, 38, 54, 68, 68, 68,
+ 25, 28, 24, 38, 54, 68, 68, 68,
+ 32, 24, 32, 43, 66, 68, 68, 68,
+ 38, 38, 43, 53, 68, 68, 68, 68,
+ 54, 54, 66, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68]
+ ]},
+ 'web_medium': {'subsampling': 2, # "4:2:0"
+ 'quantization': [
+ [16, 11, 11, 16, 23, 27, 31, 30,
+ 11, 12, 12, 15, 20, 23, 23, 30,
+ 11, 12, 13, 16, 23, 26, 35, 47,
+ 16, 15, 16, 23, 26, 37, 47, 64,
+ 23, 20, 23, 26, 39, 51, 64, 64,
+ 27, 23, 26, 37, 51, 64, 64, 64,
+ 31, 23, 35, 47, 64, 64, 64, 64,
+ 30, 30, 47, 64, 64, 64, 64, 64],
+ [17, 15, 17, 21, 20, 26, 38, 48,
+ 15, 19, 18, 17, 20, 26, 35, 43,
+ 17, 18, 20, 22, 26, 30, 46, 53,
+ 21, 17, 22, 28, 30, 39, 53, 64,
+ 20, 20, 26, 30, 39, 48, 64, 64,
+ 26, 26, 30, 39, 48, 63, 64, 64,
+ 38, 35, 46, 53, 64, 64, 64, 64,
+ 48, 43, 53, 64, 64, 64, 64, 64]
+ ]},
+ 'web_high': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [6, 4, 4, 6, 9, 11, 12, 16,
+ 4, 5, 5, 6, 8, 10, 12, 12,
+ 4, 5, 5, 6, 10, 12, 14, 19,
+ 6, 6, 6, 11, 12, 15, 19, 28,
+ 9, 8, 10, 12, 16, 20, 27, 31,
+ 11, 10, 12, 15, 20, 27, 31, 31,
+ 12, 12, 14, 19, 27, 31, 31, 31,
+ 16, 12, 19, 28, 31, 31, 31, 31],
+ [7, 7, 13, 24, 26, 31, 31, 31,
+ 7, 12, 16, 21, 31, 31, 31, 31,
+ 13, 16, 17, 31, 31, 31, 31, 31,
+ 24, 21, 31, 31, 31, 31, 31, 31,
+ 26, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31]
+ ]},
+ 'web_very_high': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [2, 2, 2, 2, 3, 4, 5, 6,
+ 2, 2, 2, 2, 3, 4, 5, 6,
+ 2, 2, 2, 2, 4, 5, 7, 9,
+ 2, 2, 2, 4, 5, 7, 9, 12,
+ 3, 3, 4, 5, 8, 10, 12, 12,
+ 4, 4, 5, 7, 10, 12, 12, 12,
+ 5, 5, 7, 9, 12, 12, 12, 12,
+ 6, 6, 9, 12, 12, 12, 12, 12],
+ [3, 3, 5, 9, 13, 15, 15, 15,
+ 3, 4, 6, 11, 14, 12, 12, 12,
+ 5, 6, 9, 14, 12, 12, 12, 12,
+ 9, 11, 14, 12, 12, 12, 12, 12,
+ 13, 14, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+ 'web_maximum': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 1, 1, 1, 1, 1, 2, 2,
+ 1, 1, 1, 1, 1, 2, 2, 3,
+ 1, 1, 1, 1, 2, 2, 3, 3,
+ 1, 1, 1, 2, 2, 3, 3, 3,
+ 1, 1, 2, 2, 3, 3, 3, 3],
+ [1, 1, 1, 2, 2, 3, 3, 3,
+ 1, 1, 1, 2, 3, 3, 3, 3,
+ 1, 1, 1, 3, 3, 3, 3, 3,
+ 2, 2, 3, 3, 3, 3, 3, 3,
+ 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3]
+ ]},
+ 'low': {'subsampling': 2, # "4:2:0"
+ 'quantization': [
+ [18, 14, 14, 21, 30, 35, 34, 17,
+ 14, 16, 16, 19, 26, 23, 12, 12,
+ 14, 16, 17, 21, 23, 12, 12, 12,
+ 21, 19, 21, 23, 12, 12, 12, 12,
+ 30, 26, 23, 12, 12, 12, 12, 12,
+ 35, 23, 12, 12, 12, 12, 12, 12,
+ 34, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12],
+ [20, 19, 22, 27, 20, 20, 17, 17,
+ 19, 25, 23, 14, 14, 12, 12, 12,
+ 22, 23, 14, 14, 12, 12, 12, 12,
+ 27, 14, 14, 12, 12, 12, 12, 12,
+ 20, 14, 12, 12, 12, 12, 12, 12,
+ 20, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+ 'medium': {'subsampling': 2, # "4:2:0"
+ 'quantization': [
+ [12, 8, 8, 12, 17, 21, 24, 17,
+ 8, 9, 9, 11, 15, 19, 12, 12,
+ 8, 9, 10, 12, 19, 12, 12, 12,
+ 12, 11, 12, 21, 12, 12, 12, 12,
+ 17, 15, 19, 12, 12, 12, 12, 12,
+ 21, 19, 12, 12, 12, 12, 12, 12,
+ 24, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12],
+ [13, 11, 13, 16, 20, 20, 17, 17,
+ 11, 14, 14, 14, 14, 12, 12, 12,
+ 13, 14, 14, 14, 12, 12, 12, 12,
+ 16, 14, 14, 12, 12, 12, 12, 12,
+ 20, 14, 12, 12, 12, 12, 12, 12,
+ 20, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+ 'high': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [6, 4, 4, 6, 9, 11, 12, 16,
+ 4, 5, 5, 6, 8, 10, 12, 12,
+ 4, 5, 5, 6, 10, 12, 12, 12,
+ 6, 6, 6, 11, 12, 12, 12, 12,
+ 9, 8, 10, 12, 12, 12, 12, 12,
+ 11, 10, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12,
+ 16, 12, 12, 12, 12, 12, 12, 12],
+ [7, 7, 13, 24, 20, 20, 17, 17,
+ 7, 12, 16, 14, 14, 12, 12, 12,
+ 13, 16, 14, 14, 12, 12, 12, 12,
+ 24, 14, 14, 12, 12, 12, 12, 12,
+ 20, 14, 12, 12, 12, 12, 12, 12,
+ 20, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+ 'maximum': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [2, 2, 2, 2, 3, 4, 5, 6,
+ 2, 2, 2, 2, 3, 4, 5, 6,
+ 2, 2, 2, 2, 4, 5, 7, 9,
+ 2, 2, 2, 4, 5, 7, 9, 12,
+ 3, 3, 4, 5, 8, 10, 12, 12,
+ 4, 4, 5, 7, 10, 12, 12, 12,
+ 5, 5, 7, 9, 12, 12, 12, 12,
+ 6, 6, 9, 12, 12, 12, 12, 12],
+ [3, 3, 5, 9, 13, 15, 15, 15,
+ 3, 4, 6, 10, 14, 12, 12, 12,
+ 5, 6, 9, 14, 12, 12, 12, 12,
+ 9, 10, 14, 12, 12, 12, 12, 12,
+ 13, 14, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+}
+# fmt: on
diff --git a/contrib/python/Pillow/py2/PIL/McIdasImagePlugin.py b/contrib/python/Pillow/py2/PIL/McIdasImagePlugin.py
new file mode 100644
index 0000000000..bddd33abb7
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/McIdasImagePlugin.py
@@ -0,0 +1,79 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Basic McIdas support for PIL
+#
+# History:
+# 1997-05-05 fl Created (8-bit images only)
+# 2009-03-08 fl Added 16/32-bit support.
+#
+# Thanks to Richard Jones and Craig Swank for specs and samples.
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import struct
+
+from . import Image, ImageFile
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.2"
+
+
+def _accept(s):
+ return s[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04"
+
+
+##
+# Image plugin for McIdas area images.
+
+
+class McIdasImageFile(ImageFile.ImageFile):
+
+ format = "MCIDAS"
+ format_description = "McIdas area file"
+
+ def _open(self):
+
+ # parse area file directory
+ s = self.fp.read(256)
+ if not _accept(s) or len(s) != 256:
+ raise SyntaxError("not an McIdas area file")
+
+ self.area_descriptor_raw = s
+ self.area_descriptor = w = [0] + list(struct.unpack("!64i", s))
+
+ # get mode
+ if w[11] == 1:
+ mode = rawmode = "L"
+ elif w[11] == 2:
+ # FIXME: add memory map support
+ mode = "I"
+ rawmode = "I;16B"
+ elif w[11] == 4:
+ # FIXME: add memory map support
+ mode = "I"
+ rawmode = "I;32B"
+ else:
+ raise SyntaxError("unsupported McIdas format")
+
+ self.mode = mode
+ self._size = w[10], w[9]
+
+ offset = w[34] + w[15]
+ stride = w[15] + w[10] * w[11] * w[14]
+
+ self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride, 1))]
+
+
+# --------------------------------------------------------------------
+# registry
+
+Image.register_open(McIdasImageFile.format, McIdasImageFile, _accept)
+
+# no default extension
diff --git a/contrib/python/Pillow/py2/PIL/MicImagePlugin.py b/contrib/python/Pillow/py2/PIL/MicImagePlugin.py
new file mode 100644
index 0000000000..b48905bda0
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/MicImagePlugin.py
@@ -0,0 +1,118 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Microsoft Image Composer support for PIL
+#
+# Notes:
+# uses TiffImagePlugin.py to read the actual image streams
+#
+# History:
+# 97-01-20 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import olefile
+
+from . import Image, TiffImagePlugin
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+
+#
+# --------------------------------------------------------------------
+
+
+def _accept(prefix):
+ return prefix[:8] == olefile.MAGIC
+
+
+##
+# Image plugin for Microsoft's Image Composer file format.
+
+
+class MicImageFile(TiffImagePlugin.TiffImageFile):
+
+ format = "MIC"
+ format_description = "Microsoft Image Composer"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+
+ # read the OLE directory and see if this is a likely
+ # to be a Microsoft Image Composer file
+
+ try:
+ self.ole = olefile.OleFileIO(self.fp)
+ except IOError:
+ raise SyntaxError("not an MIC file; invalid OLE file")
+
+ # find ACI subfiles with Image members (maybe not the
+ # best way to identify MIC files, but what the... ;-)
+
+ self.images = []
+ for path in self.ole.listdir():
+ if path[1:] and path[0][-4:] == ".ACI" and path[1] == "Image":
+ self.images.append(path)
+
+ # if we didn't find any images, this is probably not
+ # an MIC file.
+ if not self.images:
+ raise SyntaxError("not an MIC file; no image entries")
+
+ self.__fp = self.fp
+ self.frame = None
+
+ if len(self.images) > 1:
+ self.category = Image.CONTAINER
+
+ self.seek(0)
+
+ @property
+ def n_frames(self):
+ return len(self.images)
+
+ @property
+ def is_animated(self):
+ return len(self.images) > 1
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+ try:
+ filename = self.images[frame]
+ except IndexError:
+ raise EOFError("no such frame")
+
+ self.fp = self.ole.openstream(filename)
+
+ TiffImagePlugin.TiffImageFile._open(self)
+
+ self.frame = frame
+
+ def tell(self):
+ return self.frame
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_open(MicImageFile.format, MicImageFile, _accept)
+
+Image.register_extension(MicImageFile.format, ".mic")
diff --git a/contrib/python/Pillow/py2/PIL/MpegImagePlugin.py b/contrib/python/Pillow/py2/PIL/MpegImagePlugin.py
new file mode 100644
index 0000000000..9c662fcc28
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/MpegImagePlugin.py
@@ -0,0 +1,88 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# MPEG file handling
+#
+# History:
+# 95-09-09 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1995.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile
+from ._binary import i8
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+
+#
+# Bitstream parser
+
+
+class BitStream(object):
+ def __init__(self, fp):
+ self.fp = fp
+ self.bits = 0
+ self.bitbuffer = 0
+
+ def next(self):
+ return i8(self.fp.read(1))
+
+ def peek(self, bits):
+ while self.bits < bits:
+ c = self.next()
+ if c < 0:
+ self.bits = 0
+ continue
+ self.bitbuffer = (self.bitbuffer << 8) + c
+ self.bits += 8
+ return self.bitbuffer >> (self.bits - bits) & (1 << bits) - 1
+
+ def skip(self, bits):
+ while self.bits < bits:
+ self.bitbuffer = (self.bitbuffer << 8) + i8(self.fp.read(1))
+ self.bits += 8
+ self.bits = self.bits - bits
+
+ def read(self, bits):
+ v = self.peek(bits)
+ self.bits = self.bits - bits
+ return v
+
+
+##
+# Image plugin for MPEG streams. This plugin can identify a stream,
+# but it cannot read it.
+
+
+class MpegImageFile(ImageFile.ImageFile):
+
+ format = "MPEG"
+ format_description = "MPEG"
+
+ def _open(self):
+
+ s = BitStream(self.fp)
+
+ if s.read(32) != 0x1B3:
+ raise SyntaxError("not an MPEG file")
+
+ self.mode = "RGB"
+ self._size = s.read(12), s.read(12)
+
+
+# --------------------------------------------------------------------
+# Registry stuff
+
+Image.register_open(MpegImageFile.format, MpegImageFile)
+
+Image.register_extensions(MpegImageFile.format, [".mpg", ".mpeg"])
+
+Image.register_mime(MpegImageFile.format, "video/mpeg")
diff --git a/contrib/python/Pillow/py2/PIL/MpoImagePlugin.py b/contrib/python/Pillow/py2/PIL/MpoImagePlugin.py
new file mode 100644
index 0000000000..938f2a5a64
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/MpoImagePlugin.py
@@ -0,0 +1,142 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# MPO file handling
+#
+# See "Multi-Picture Format" (CIPA DC-007-Translation 2009, Standard of the
+# Camera & Imaging Products Association)
+#
+# The multi-picture object combines multiple JPEG images (with a modified EXIF
+# data format) into a single file. While it can theoretically be used much like
+# a GIF animation, it is commonly used to represent 3D photographs and is (as
+# of this writing) the most commonly used format by 3D cameras.
+#
+# History:
+# 2014-03-13 Feneric Created
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFile, JpegImagePlugin
+from ._binary import i16be as i16
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+
+def _accept(prefix):
+ return JpegImagePlugin._accept(prefix)
+
+
+def _save(im, fp, filename):
+ # Note that we can only save the current frame at present
+ return JpegImagePlugin._save(im, fp, filename)
+
+
+##
+# Image plugin for MPO images.
+
+
+class MpoImageFile(JpegImagePlugin.JpegImageFile):
+
+ format = "MPO"
+ format_description = "MPO (CIPA DC-007)"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+ self.fp.seek(0) # prep the fp in order to pass the JPEG test
+ JpegImagePlugin.JpegImageFile._open(self)
+ self._after_jpeg_open()
+
+ def _after_jpeg_open(self, mpheader=None):
+ self.mpinfo = mpheader if mpheader is not None else self._getmp()
+ self.__framecount = self.mpinfo[0xB001]
+ self.__mpoffsets = [
+ mpent["DataOffset"] + self.info["mpoffset"] for mpent in self.mpinfo[0xB002]
+ ]
+ self.__mpoffsets[0] = 0
+ # Note that the following assertion will only be invalid if something
+ # gets broken within JpegImagePlugin.
+ assert self.__framecount == len(self.__mpoffsets)
+ del self.info["mpoffset"] # no longer needed
+ self.__fp = self.fp # FIXME: hack
+ self.__fp.seek(self.__mpoffsets[0]) # get ready to read first frame
+ self.__frame = 0
+ self.offset = 0
+ # for now we can only handle reading and individual frame extraction
+ self.readonly = 1
+
+ def load_seek(self, pos):
+ self.__fp.seek(pos)
+
+ @property
+ def n_frames(self):
+ return self.__framecount
+
+ @property
+ def is_animated(self):
+ return self.__framecount > 1
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+ self.fp = self.__fp
+ self.offset = self.__mpoffsets[frame]
+
+ self.fp.seek(self.offset + 2) # skip SOI marker
+ if i16(self.fp.read(2)) == 0xFFE1: # APP1
+ n = i16(self.fp.read(2)) - 2
+ self.info["exif"] = ImageFile._safe_read(self.fp, n)
+
+ exif = self.getexif()
+ if 40962 in exif and 40963 in exif:
+ self._size = (exif[40962], exif[40963])
+ elif "exif" in self.info:
+ del self.info["exif"]
+
+ self.tile = [("jpeg", (0, 0) + self.size, self.offset, (self.mode, ""))]
+ self.__frame = frame
+
+ def tell(self):
+ return self.__frame
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+ @staticmethod
+ def adopt(jpeg_instance, mpheader=None):
+ """
+ Transform the instance of JpegImageFile into
+ an instance of MpoImageFile.
+ After the call, the JpegImageFile is extended
+ to be an MpoImageFile.
+
+ This is essentially useful when opening a JPEG
+ file that reveals itself as an MPO, to avoid
+ double call to _open.
+ """
+ jpeg_instance.__class__ = MpoImageFile
+ jpeg_instance._after_jpeg_open(mpheader)
+ return jpeg_instance
+
+
+# ---------------------------------------------------------------------
+# Registry stuff
+
+# Note that since MPO shares a factory with JPEG, we do not need to do a
+# separate registration for it here.
+# Image.register_open(MpoImageFile.format,
+# JpegImagePlugin.jpeg_factory, _accept)
+Image.register_save(MpoImageFile.format, _save)
+
+Image.register_extension(MpoImageFile.format, ".mpo")
+
+Image.register_mime(MpoImageFile.format, "image/mpo")
diff --git a/contrib/python/Pillow/py2/PIL/MspImagePlugin.py b/contrib/python/Pillow/py2/PIL/MspImagePlugin.py
new file mode 100644
index 0000000000..7315ab66ed
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/MspImagePlugin.py
@@ -0,0 +1,198 @@
+#
+# The Python Imaging Library.
+#
+# MSP file handling
+#
+# This is the format used by the Paint program in Windows 1 and 2.
+#
+# History:
+# 95-09-05 fl Created
+# 97-01-03 fl Read/write MSP images
+# 17-02-21 es Fixed RLE interpretation
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1995-97.
+# Copyright (c) Eric Soroos 2017.
+#
+# See the README file for information on usage and redistribution.
+#
+# More info on this format: https://archive.org/details/gg243631
+# Page 313:
+# Figure 205. Windows Paint Version 1: "DanM" Format
+# Figure 206. Windows Paint Version 2: "LinS" Format. Used in Windows V2.03
+#
+# See also: http://www.fileformat.info/format/mspaint/egff.htm
+
+import io
+import struct
+
+from . import Image, ImageFile
+from ._binary import i8, i16le as i16, o16le as o16
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+
+#
+# read MSP files
+
+
+def _accept(prefix):
+ return prefix[:4] in [b"DanM", b"LinS"]
+
+
+##
+# Image plugin for Windows MSP images. This plugin supports both
+# uncompressed (Windows 1.0).
+
+
+class MspImageFile(ImageFile.ImageFile):
+
+ format = "MSP"
+ format_description = "Windows Paint"
+
+ def _open(self):
+
+ # Header
+ s = self.fp.read(32)
+ if s[:4] not in [b"DanM", b"LinS"]:
+ raise SyntaxError("not an MSP file")
+
+ # Header checksum
+ checksum = 0
+ for i in range(0, 32, 2):
+ checksum = checksum ^ i16(s[i : i + 2])
+ if checksum != 0:
+ raise SyntaxError("bad MSP checksum")
+
+ self.mode = "1"
+ self._size = i16(s[4:]), i16(s[6:])
+
+ if s[:4] == b"DanM":
+ self.tile = [("raw", (0, 0) + self.size, 32, ("1", 0, 1))]
+ else:
+ self.tile = [("MSP", (0, 0) + self.size, 32, None)]
+
+
+class MspDecoder(ImageFile.PyDecoder):
+ # The algo for the MSP decoder is from
+ # http://www.fileformat.info/format/mspaint/egff.htm
+ # cc-by-attribution -- That page references is taken from the
+ # Encyclopedia of Graphics File Formats and is licensed by
+ # O'Reilly under the Creative Common/Attribution license
+ #
+ # For RLE encoded files, the 32byte header is followed by a scan
+ # line map, encoded as one 16bit word of encoded byte length per
+ # line.
+ #
+ # NOTE: the encoded length of the line can be 0. This was not
+ # handled in the previous version of this encoder, and there's no
+ # mention of how to handle it in the documentation. From the few
+ # examples I've seen, I've assumed that it is a fill of the
+ # background color, in this case, white.
+ #
+ #
+ # Pseudocode of the decoder:
+ # Read a BYTE value as the RunType
+ # If the RunType value is zero
+ # Read next byte as the RunCount
+ # Read the next byte as the RunValue
+ # Write the RunValue byte RunCount times
+ # If the RunType value is non-zero
+ # Use this value as the RunCount
+ # Read and write the next RunCount bytes literally
+ #
+ # e.g.:
+ # 0x00 03 ff 05 00 01 02 03 04
+ # would yield the bytes:
+ # 0xff ff ff 00 01 02 03 04
+ #
+ # which are then interpreted as a bit packed mode '1' image
+
+ _pulls_fd = True
+
+ def decode(self, buffer):
+
+ img = io.BytesIO()
+ blank_line = bytearray((0xFF,) * ((self.state.xsize + 7) // 8))
+ try:
+ self.fd.seek(32)
+ rowmap = struct.unpack_from(
+ "<%dH" % (self.state.ysize), self.fd.read(self.state.ysize * 2)
+ )
+ except struct.error:
+ raise IOError("Truncated MSP file in row map")
+
+ for x, rowlen in enumerate(rowmap):
+ try:
+ if rowlen == 0:
+ img.write(blank_line)
+ continue
+ row = self.fd.read(rowlen)
+ if len(row) != rowlen:
+ raise IOError(
+ "Truncated MSP file, expected %d bytes on row %s", (rowlen, x)
+ )
+ idx = 0
+ while idx < rowlen:
+ runtype = i8(row[idx])
+ idx += 1
+ if runtype == 0:
+ (runcount, runval) = struct.unpack_from("Bc", row, idx)
+ img.write(runval * runcount)
+ idx += 2
+ else:
+ runcount = runtype
+ img.write(row[idx : idx + runcount])
+ idx += runcount
+
+ except struct.error:
+ raise IOError("Corrupted MSP file in row %d" % x)
+
+ self.set_as_raw(img.getvalue(), ("1", 0, 1))
+
+ return 0, 0
+
+
+Image.register_decoder("MSP", MspDecoder)
+
+
+#
+# write MSP files (uncompressed only)
+
+
+def _save(im, fp, filename):
+
+ if im.mode != "1":
+ raise IOError("cannot write mode %s as MSP" % im.mode)
+
+ # create MSP header
+ header = [0] * 16
+
+ header[0], header[1] = i16(b"Da"), i16(b"nM") # version 1
+ header[2], header[3] = im.size
+ header[4], header[5] = 1, 1
+ header[6], header[7] = 1, 1
+ header[8], header[9] = im.size
+
+ checksum = 0
+ for h in header:
+ checksum = checksum ^ h
+ header[12] = checksum # FIXME: is this the right field?
+
+ # header
+ for h in header:
+ fp.write(o16(h))
+
+ # image body
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 32, ("1", 0, 1))])
+
+
+#
+# registry
+
+Image.register_open(MspImageFile.format, MspImageFile, _accept)
+Image.register_save(MspImageFile.format, _save)
+
+Image.register_extension(MspImageFile.format, ".msp")
diff --git a/contrib/python/Pillow/py2/PIL/PSDraw.py b/contrib/python/Pillow/py2/PIL/PSDraw.py
new file mode 100644
index 0000000000..f37701ce97
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PSDraw.py
@@ -0,0 +1,238 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# simple postscript graphics interface
+#
+# History:
+# 1996-04-20 fl Created
+# 1999-01-10 fl Added gsave/grestore to image method
+# 2005-05-04 fl Fixed floating point issue in image (from Eric Etheridge)
+#
+# Copyright (c) 1997-2005 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1996 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import sys
+
+from . import EpsImagePlugin
+from ._util import py3
+
+##
+# Simple Postscript graphics interface.
+
+
+class PSDraw(object):
+ """
+ Sets up printing to the given file. If **fp** is omitted,
+ :py:attr:`sys.stdout` is assumed.
+ """
+
+ def __init__(self, fp=None):
+ if not fp:
+ fp = sys.stdout
+ self.fp = fp
+
+ def _fp_write(self, to_write):
+ if not py3 or self.fp == sys.stdout:
+ self.fp.write(to_write)
+ else:
+ self.fp.write(bytes(to_write, "UTF-8"))
+
+ def begin_document(self, id=None):
+ """Set up printing of a document. (Write Postscript DSC header.)"""
+ # FIXME: incomplete
+ self._fp_write(
+ "%!PS-Adobe-3.0\n"
+ "save\n"
+ "/showpage { } def\n"
+ "%%EndComments\n"
+ "%%BeginDocument\n"
+ )
+ # self._fp_write(ERROR_PS) # debugging!
+ self._fp_write(EDROFF_PS)
+ self._fp_write(VDI_PS)
+ self._fp_write("%%EndProlog\n")
+ self.isofont = {}
+
+ def end_document(self):
+ """Ends printing. (Write Postscript DSC footer.)"""
+ self._fp_write("%%EndDocument\nrestore showpage\n%%End\n")
+ if hasattr(self.fp, "flush"):
+ self.fp.flush()
+
+ def setfont(self, font, size):
+ """
+ Selects which font to use.
+
+ :param font: A Postscript font name
+ :param size: Size in points.
+ """
+ if font not in self.isofont:
+ # reencode font
+ self._fp_write("/PSDraw-%s ISOLatin1Encoding /%s E\n" % (font, font))
+ self.isofont[font] = 1
+ # rough
+ self._fp_write("/F0 %d /PSDraw-%s F\n" % (size, font))
+
+ def line(self, xy0, xy1):
+ """
+ Draws a line between the two points. Coordinates are given in
+ Postscript point coordinates (72 points per inch, (0, 0) is the lower
+ left corner of the page).
+ """
+ xy = xy0 + xy1
+ self._fp_write("%d %d %d %d Vl\n" % xy)
+
+ def rectangle(self, box):
+ """
+ Draws a rectangle.
+
+ :param box: A 4-tuple of integers whose order and function is currently
+ undocumented.
+
+ Hint: the tuple is passed into this format string:
+
+ .. code-block:: python
+
+ %d %d M %d %d 0 Vr\n
+ """
+ self._fp_write("%d %d M %d %d 0 Vr\n" % box)
+
+ def text(self, xy, text):
+ """
+ Draws text at the given position. You must use
+ :py:meth:`~PIL.PSDraw.PSDraw.setfont` before calling this method.
+ """
+ text = "\\(".join(text.split("("))
+ text = "\\)".join(text.split(")"))
+ xy = xy + (text,)
+ self._fp_write("%d %d M (%s) S\n" % xy)
+
+ def image(self, box, im, dpi=None):
+ """Draw a PIL image, centered in the given box."""
+ # default resolution depends on mode
+ if not dpi:
+ if im.mode == "1":
+ dpi = 200 # fax
+ else:
+ dpi = 100 # greyscale
+ # image size (on paper)
+ x = float(im.size[0] * 72) / dpi
+ y = float(im.size[1] * 72) / dpi
+ # max allowed size
+ xmax = float(box[2] - box[0])
+ ymax = float(box[3] - box[1])
+ if x > xmax:
+ y = y * xmax / x
+ x = xmax
+ if y > ymax:
+ x = x * ymax / y
+ y = ymax
+ dx = (xmax - x) / 2 + box[0]
+ dy = (ymax - y) / 2 + box[1]
+ self._fp_write("gsave\n%f %f translate\n" % (dx, dy))
+ if (x, y) != im.size:
+ # EpsImagePlugin._save prints the image at (0,0,xsize,ysize)
+ sx = x / im.size[0]
+ sy = y / im.size[1]
+ self._fp_write("%f %f scale\n" % (sx, sy))
+ EpsImagePlugin._save(im, self.fp, None, 0)
+ self._fp_write("\ngrestore\n")
+
+
+# --------------------------------------------------------------------
+# Postscript driver
+
+#
+# EDROFF.PS -- Postscript driver for Edroff 2
+#
+# History:
+# 94-01-25 fl: created (edroff 2.04)
+#
+# Copyright (c) Fredrik Lundh 1994.
+#
+
+
+EDROFF_PS = """\
+/S { show } bind def
+/P { moveto show } bind def
+/M { moveto } bind def
+/X { 0 rmoveto } bind def
+/Y { 0 exch rmoveto } bind def
+/E { findfont
+ dup maxlength dict begin
+ {
+ 1 index /FID ne { def } { pop pop } ifelse
+ } forall
+ /Encoding exch def
+ dup /FontName exch def
+ currentdict end definefont pop
+} bind def
+/F { findfont exch scalefont dup setfont
+ [ exch /setfont cvx ] cvx bind def
+} bind def
+"""
+
+#
+# VDI.PS -- Postscript driver for VDI meta commands
+#
+# History:
+# 94-01-25 fl: created (edroff 2.04)
+#
+# Copyright (c) Fredrik Lundh 1994.
+#
+
+VDI_PS = """\
+/Vm { moveto } bind def
+/Va { newpath arcn stroke } bind def
+/Vl { moveto lineto stroke } bind def
+/Vc { newpath 0 360 arc closepath } bind def
+/Vr { exch dup 0 rlineto
+ exch dup neg 0 exch rlineto
+ exch neg 0 rlineto
+ 0 exch rlineto
+ 100 div setgray fill 0 setgray } bind def
+/Tm matrix def
+/Ve { Tm currentmatrix pop
+ translate scale newpath 0 0 .5 0 360 arc closepath
+ Tm setmatrix
+} bind def
+/Vf { currentgray exch setgray fill setgray } bind def
+"""
+
+#
+# ERROR.PS -- Error handler
+#
+# History:
+# 89-11-21 fl: created (pslist 1.10)
+#
+
+ERROR_PS = """\
+/landscape false def
+/errorBUF 200 string def
+/errorNL { currentpoint 10 sub exch pop 72 exch moveto } def
+errordict begin /handleerror {
+ initmatrix /Courier findfont 10 scalefont setfont
+ newpath 72 720 moveto $error begin /newerror false def
+ (PostScript Error) show errorNL errorNL
+ (Error: ) show
+ /errorname load errorBUF cvs show errorNL errorNL
+ (Command: ) show
+ /command load dup type /stringtype ne { errorBUF cvs } if show
+ errorNL errorNL
+ (VMstatus: ) show
+ vmstatus errorBUF cvs show ( bytes available, ) show
+ errorBUF cvs show ( bytes used at level ) show
+ errorBUF cvs show errorNL errorNL
+ (Operand stargck: ) show errorNL /ostargck load {
+ dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
+ } forall errorNL
+ (Execution stargck: ) show errorNL /estargck load {
+ dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
+ } forall
+ end showpage
+} def end
+"""
diff --git a/contrib/python/Pillow/py2/PIL/PaletteFile.py b/contrib/python/Pillow/py2/PIL/PaletteFile.py
new file mode 100644
index 0000000000..ab22d5f0c1
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PaletteFile.py
@@ -0,0 +1,55 @@
+#
+# Python Imaging Library
+# $Id$
+#
+# stuff to read simple, teragon-style palette files
+#
+# History:
+# 97-08-23 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from ._binary import o8
+
+##
+# File handler for Teragon-style palette files.
+
+
+class PaletteFile(object):
+
+ rawmode = "RGB"
+
+ def __init__(self, fp):
+
+ self.palette = [(i, i, i) for i in range(256)]
+
+ while True:
+
+ s = fp.readline()
+
+ if not s:
+ break
+ if s[0:1] == b"#":
+ continue
+ if len(s) > 100:
+ raise SyntaxError("bad palette file")
+
+ v = [int(x) for x in s.split()]
+ try:
+ [i, r, g, b] = v
+ except ValueError:
+ [i, r] = v
+ g = b = r
+
+ if 0 <= i <= 255:
+ self.palette[i] = o8(r) + o8(g) + o8(b)
+
+ self.palette = b"".join(self.palette)
+
+ def getpalette(self):
+
+ return self.palette, self.rawmode
diff --git a/contrib/python/Pillow/py2/PIL/PalmImagePlugin.py b/contrib/python/Pillow/py2/PIL/PalmImagePlugin.py
new file mode 100644
index 0000000000..dd068d7941
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PalmImagePlugin.py
@@ -0,0 +1,230 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+
+##
+# Image plugin for Palm pixmap images (output only).
+##
+
+from . import Image, ImageFile
+from ._binary import o8, o16be as o16b
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "1.0"
+
+# fmt: off
+_Palm8BitColormapValues = ( # noqa: E131
+ (255, 255, 255), (255, 204, 255), (255, 153, 255), (255, 102, 255),
+ (255, 51, 255), (255, 0, 255), (255, 255, 204), (255, 204, 204),
+ (255, 153, 204), (255, 102, 204), (255, 51, 204), (255, 0, 204),
+ (255, 255, 153), (255, 204, 153), (255, 153, 153), (255, 102, 153),
+ (255, 51, 153), (255, 0, 153), (204, 255, 255), (204, 204, 255),
+ (204, 153, 255), (204, 102, 255), (204, 51, 255), (204, 0, 255),
+ (204, 255, 204), (204, 204, 204), (204, 153, 204), (204, 102, 204),
+ (204, 51, 204), (204, 0, 204), (204, 255, 153), (204, 204, 153),
+ (204, 153, 153), (204, 102, 153), (204, 51, 153), (204, 0, 153),
+ (153, 255, 255), (153, 204, 255), (153, 153, 255), (153, 102, 255),
+ (153, 51, 255), (153, 0, 255), (153, 255, 204), (153, 204, 204),
+ (153, 153, 204), (153, 102, 204), (153, 51, 204), (153, 0, 204),
+ (153, 255, 153), (153, 204, 153), (153, 153, 153), (153, 102, 153),
+ (153, 51, 153), (153, 0, 153), (102, 255, 255), (102, 204, 255),
+ (102, 153, 255), (102, 102, 255), (102, 51, 255), (102, 0, 255),
+ (102, 255, 204), (102, 204, 204), (102, 153, 204), (102, 102, 204),
+ (102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153),
+ (102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 153),
+ (51, 255, 255), (51, 204, 255), (51, 153, 255), (51, 102, 255),
+ (51, 51, 255), (51, 0, 255), (51, 255, 204), (51, 204, 204),
+ (51, 153, 204), (51, 102, 204), (51, 51, 204), (51, 0, 204),
+ (51, 255, 153), (51, 204, 153), (51, 153, 153), (51, 102, 153),
+ (51, 51, 153), (51, 0, 153), (0, 255, 255), (0, 204, 255),
+ (0, 153, 255), (0, 102, 255), (0, 51, 255), (0, 0, 255),
+ (0, 255, 204), (0, 204, 204), (0, 153, 204), (0, 102, 204),
+ (0, 51, 204), (0, 0, 204), (0, 255, 153), (0, 204, 153),
+ (0, 153, 153), (0, 102, 153), (0, 51, 153), (0, 0, 153),
+ (255, 255, 102), (255, 204, 102), (255, 153, 102), (255, 102, 102),
+ (255, 51, 102), (255, 0, 102), (255, 255, 51), (255, 204, 51),
+ (255, 153, 51), (255, 102, 51), (255, 51, 51), (255, 0, 51),
+ (255, 255, 0), (255, 204, 0), (255, 153, 0), (255, 102, 0),
+ (255, 51, 0), (255, 0, 0), (204, 255, 102), (204, 204, 102),
+ (204, 153, 102), (204, 102, 102), (204, 51, 102), (204, 0, 102),
+ (204, 255, 51), (204, 204, 51), (204, 153, 51), (204, 102, 51),
+ (204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0),
+ (204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0),
+ (153, 255, 102), (153, 204, 102), (153, 153, 102), (153, 102, 102),
+ (153, 51, 102), (153, 0, 102), (153, 255, 51), (153, 204, 51),
+ (153, 153, 51), (153, 102, 51), (153, 51, 51), (153, 0, 51),
+ (153, 255, 0), (153, 204, 0), (153, 153, 0), (153, 102, 0),
+ (153, 51, 0), (153, 0, 0), (102, 255, 102), (102, 204, 102),
+ (102, 153, 102), (102, 102, 102), (102, 51, 102), (102, 0, 102),
+ (102, 255, 51), (102, 204, 51), (102, 153, 51), (102, 102, 51),
+ (102, 51, 51), (102, 0, 51), (102, 255, 0), (102, 204, 0),
+ (102, 153, 0), (102, 102, 0), (102, 51, 0), (102, 0, 0),
+ (51, 255, 102), (51, 204, 102), (51, 153, 102), (51, 102, 102),
+ (51, 51, 102), (51, 0, 102), (51, 255, 51), (51, 204, 51),
+ (51, 153, 51), (51, 102, 51), (51, 51, 51), (51, 0, 51),
+ (51, 255, 0), (51, 204, 0), (51, 153, 0), (51, 102, 0),
+ (51, 51, 0), (51, 0, 0), (0, 255, 102), (0, 204, 102),
+ (0, 153, 102), (0, 102, 102), (0, 51, 102), (0, 0, 102),
+ (0, 255, 51), (0, 204, 51), (0, 153, 51), (0, 102, 51),
+ (0, 51, 51), (0, 0, 51), (0, 255, 0), (0, 204, 0),
+ (0, 153, 0), (0, 102, 0), (0, 51, 0), (17, 17, 17),
+ (34, 34, 34), (68, 68, 68), (85, 85, 85), (119, 119, 119),
+ (136, 136, 136), (170, 170, 170), (187, 187, 187), (221, 221, 221),
+ (238, 238, 238), (192, 192, 192), (128, 0, 0), (128, 0, 128),
+ (0, 128, 0), (0, 128, 128), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0))
+# fmt: on
+
+
+# so build a prototype image to be used for palette resampling
+def build_prototype_image():
+ image = Image.new("L", (1, len(_Palm8BitColormapValues)))
+ image.putdata(list(range(len(_Palm8BitColormapValues))))
+ palettedata = ()
+ for colormapValue in _Palm8BitColormapValues:
+ palettedata += colormapValue
+ palettedata += (0, 0, 0) * (256 - len(_Palm8BitColormapValues))
+ image.putpalette(palettedata)
+ return image
+
+
+Palm8BitColormapImage = build_prototype_image()
+
+# OK, we now have in Palm8BitColormapImage,
+# a "P"-mode image with the right palette
+#
+# --------------------------------------------------------------------
+
+_FLAGS = {"custom-colormap": 0x4000, "is-compressed": 0x8000, "has-transparent": 0x2000}
+
+_COMPRESSION_TYPES = {"none": 0xFF, "rle": 0x01, "scanline": 0x00}
+
+
+#
+# --------------------------------------------------------------------
+
+##
+# (Internal) Image save plugin for the Palm format.
+
+
+def _save(im, fp, filename):
+
+ if im.mode == "P":
+
+ # we assume this is a color Palm image with the standard colormap,
+ # unless the "info" dict has a "custom-colormap" field
+
+ rawmode = "P"
+ bpp = 8
+ version = 1
+
+ elif im.mode == "L":
+ if im.encoderinfo.get("bpp") in (1, 2, 4):
+ # this is 8-bit grayscale, so we shift it to get the high-order bits,
+ # and invert it because
+ # Palm does greyscale from white (0) to black (1)
+ bpp = im.encoderinfo["bpp"]
+ im = im.point(
+ lambda x, shift=8 - bpp, maxval=(1 << bpp) - 1: maxval - (x >> shift)
+ )
+ elif im.info.get("bpp") in (1, 2, 4):
+ # here we assume that even though the inherent mode is 8-bit grayscale,
+ # only the lower bpp bits are significant.
+ # We invert them to match the Palm.
+ bpp = im.info["bpp"]
+ im = im.point(lambda x, maxval=(1 << bpp) - 1: maxval - (x & maxval))
+ else:
+ raise IOError("cannot write mode %s as Palm" % im.mode)
+
+ # we ignore the palette here
+ im.mode = "P"
+ rawmode = "P;" + str(bpp)
+ version = 1
+
+ elif im.mode == "1":
+
+ # monochrome -- write it inverted, as is the Palm standard
+ rawmode = "1;I"
+ bpp = 1
+ version = 0
+
+ else:
+
+ raise IOError("cannot write mode %s as Palm" % im.mode)
+
+ #
+ # make sure image data is available
+ im.load()
+
+ # write header
+
+ cols = im.size[0]
+ rows = im.size[1]
+
+ rowbytes = int((cols + (16 // bpp - 1)) / (16 // bpp)) * 2
+ transparent_index = 0
+ compression_type = _COMPRESSION_TYPES["none"]
+
+ flags = 0
+ if im.mode == "P" and "custom-colormap" in im.info:
+ flags = flags & _FLAGS["custom-colormap"]
+ colormapsize = 4 * 256 + 2
+ colormapmode = im.palette.mode
+ colormap = im.getdata().getpalette()
+ else:
+ colormapsize = 0
+
+ if "offset" in im.info:
+ offset = (rowbytes * rows + 16 + 3 + colormapsize) // 4
+ else:
+ offset = 0
+
+ fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags))
+ fp.write(o8(bpp))
+ fp.write(o8(version))
+ fp.write(o16b(offset))
+ fp.write(o8(transparent_index))
+ fp.write(o8(compression_type))
+ fp.write(o16b(0)) # reserved by Palm
+
+ # now write colormap if necessary
+
+ if colormapsize > 0:
+ fp.write(o16b(256))
+ for i in range(256):
+ fp.write(o8(i))
+ if colormapmode == "RGB":
+ fp.write(
+ o8(colormap[3 * i])
+ + o8(colormap[3 * i + 1])
+ + o8(colormap[3 * i + 2])
+ )
+ elif colormapmode == "RGBA":
+ fp.write(
+ o8(colormap[4 * i])
+ + o8(colormap[4 * i + 1])
+ + o8(colormap[4 * i + 2])
+ )
+
+ # now convert data to raw form
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, rowbytes, 1))])
+
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_save("Palm", _save)
+
+Image.register_extension("Palm", ".palm")
+
+Image.register_mime("Palm", "image/palm")
diff --git a/contrib/python/Pillow/py2/PIL/PcdImagePlugin.py b/contrib/python/Pillow/py2/PIL/PcdImagePlugin.py
new file mode 100644
index 0000000000..6f01845ece
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PcdImagePlugin.py
@@ -0,0 +1,69 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PCD file handling
+#
+# History:
+# 96-05-10 fl Created
+# 96-05-27 fl Added draft mode (128x192, 256x384)
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile
+from ._binary import i8
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+
+##
+# Image plugin for PhotoCD images. This plugin only reads the 768x512
+# image from the file; higher resolutions are encoded in a proprietary
+# encoding.
+
+
+class PcdImageFile(ImageFile.ImageFile):
+
+ format = "PCD"
+ format_description = "Kodak PhotoCD"
+
+ def _open(self):
+
+ # rough
+ self.fp.seek(2048)
+ s = self.fp.read(2048)
+
+ if s[:4] != b"PCD_":
+ raise SyntaxError("not a PCD file")
+
+ orientation = i8(s[1538]) & 3
+ self.tile_post_rotate = None
+ if orientation == 1:
+ self.tile_post_rotate = 90
+ elif orientation == 3:
+ self.tile_post_rotate = -90
+
+ self.mode = "RGB"
+ self._size = 768, 512 # FIXME: not correct for rotated images!
+ self.tile = [("pcd", (0, 0) + self.size, 96 * 2048, None)]
+
+ def load_end(self):
+ if self.tile_post_rotate:
+ # Handle rotated PCDs
+ self.im = self.im.rotate(self.tile_post_rotate)
+ self._size = self.im.size
+
+
+#
+# registry
+
+Image.register_open(PcdImageFile.format, PcdImageFile)
+
+Image.register_extension(PcdImageFile.format, ".pcd")
diff --git a/contrib/python/Pillow/py2/PIL/PcfFontFile.py b/contrib/python/Pillow/py2/PIL/PcfFontFile.py
new file mode 100644
index 0000000000..074124612d
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PcfFontFile.py
@@ -0,0 +1,240 @@
+#
+# THIS IS WORK IN PROGRESS
+#
+# The Python Imaging Library
+# $Id$
+#
+# portable compiled font file parser
+#
+# history:
+# 1997-08-19 fl created
+# 2003-09-13 fl fixed loading of unicode fonts
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1997-2003 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+
+from . import FontFile, Image
+from ._binary import i8, i16be as b16, i16le as l16, i32be as b32, i32le as l32
+
+# --------------------------------------------------------------------
+# declarations
+
+PCF_MAGIC = 0x70636601 # "\x01fcp"
+
+PCF_PROPERTIES = 1 << 0
+PCF_ACCELERATORS = 1 << 1
+PCF_METRICS = 1 << 2
+PCF_BITMAPS = 1 << 3
+PCF_INK_METRICS = 1 << 4
+PCF_BDF_ENCODINGS = 1 << 5
+PCF_SWIDTHS = 1 << 6
+PCF_GLYPH_NAMES = 1 << 7
+PCF_BDF_ACCELERATORS = 1 << 8
+
+BYTES_PER_ROW = [
+ lambda bits: ((bits + 7) >> 3),
+ lambda bits: ((bits + 15) >> 3) & ~1,
+ lambda bits: ((bits + 31) >> 3) & ~3,
+ lambda bits: ((bits + 63) >> 3) & ~7,
+]
+
+
+def sz(s, o):
+ return s[o : s.index(b"\0", o)]
+
+
+##
+# Font file plugin for the X11 PCF format.
+
+
+class PcfFontFile(FontFile.FontFile):
+
+ name = "name"
+
+ def __init__(self, fp):
+
+ magic = l32(fp.read(4))
+ if magic != PCF_MAGIC:
+ raise SyntaxError("not a PCF file")
+
+ FontFile.FontFile.__init__(self)
+
+ count = l32(fp.read(4))
+ self.toc = {}
+ for i in range(count):
+ type = l32(fp.read(4))
+ self.toc[type] = l32(fp.read(4)), l32(fp.read(4)), l32(fp.read(4))
+
+ self.fp = fp
+
+ self.info = self._load_properties()
+
+ metrics = self._load_metrics()
+ bitmaps = self._load_bitmaps(metrics)
+ encoding = self._load_encoding()
+
+ #
+ # create glyph structure
+
+ for ch in range(256):
+ ix = encoding[ch]
+ if ix is not None:
+ x, y, l, r, w, a, d, f = metrics[ix]
+ glyph = (w, 0), (l, d - y, x + l, d), (0, 0, x, y), bitmaps[ix]
+ self.glyph[ch] = glyph
+
+ def _getformat(self, tag):
+
+ format, size, offset = self.toc[tag]
+
+ fp = self.fp
+ fp.seek(offset)
+
+ format = l32(fp.read(4))
+
+ if format & 4:
+ i16, i32 = b16, b32
+ else:
+ i16, i32 = l16, l32
+
+ return fp, format, i16, i32
+
+ def _load_properties(self):
+
+ #
+ # font properties
+
+ properties = {}
+
+ fp, format, i16, i32 = self._getformat(PCF_PROPERTIES)
+
+ nprops = i32(fp.read(4))
+
+ # read property description
+ p = []
+ for i in range(nprops):
+ p.append((i32(fp.read(4)), i8(fp.read(1)), i32(fp.read(4))))
+ if nprops & 3:
+ fp.seek(4 - (nprops & 3), io.SEEK_CUR) # pad
+
+ data = fp.read(i32(fp.read(4)))
+
+ for k, s, v in p:
+ k = sz(data, k)
+ if s:
+ v = sz(data, v)
+ properties[k] = v
+
+ return properties
+
+ def _load_metrics(self):
+
+ #
+ # font metrics
+
+ metrics = []
+
+ fp, format, i16, i32 = self._getformat(PCF_METRICS)
+
+ append = metrics.append
+
+ if (format & 0xFF00) == 0x100:
+
+ # "compressed" metrics
+ for i in range(i16(fp.read(2))):
+ left = i8(fp.read(1)) - 128
+ right = i8(fp.read(1)) - 128
+ width = i8(fp.read(1)) - 128
+ ascent = i8(fp.read(1)) - 128
+ descent = i8(fp.read(1)) - 128
+ xsize = right - left
+ ysize = ascent + descent
+ append((xsize, ysize, left, right, width, ascent, descent, 0))
+
+ else:
+
+ # "jumbo" metrics
+ for i in range(i32(fp.read(4))):
+ left = i16(fp.read(2))
+ right = i16(fp.read(2))
+ width = i16(fp.read(2))
+ ascent = i16(fp.read(2))
+ descent = i16(fp.read(2))
+ attributes = i16(fp.read(2))
+ xsize = right - left
+ ysize = ascent + descent
+ append((xsize, ysize, left, right, width, ascent, descent, attributes))
+
+ return metrics
+
+ def _load_bitmaps(self, metrics):
+
+ #
+ # bitmap data
+
+ bitmaps = []
+
+ fp, format, i16, i32 = self._getformat(PCF_BITMAPS)
+
+ nbitmaps = i32(fp.read(4))
+
+ if nbitmaps != len(metrics):
+ raise IOError("Wrong number of bitmaps")
+
+ offsets = []
+ for i in range(nbitmaps):
+ offsets.append(i32(fp.read(4)))
+
+ bitmapSizes = []
+ for i in range(4):
+ bitmapSizes.append(i32(fp.read(4)))
+
+ # byteorder = format & 4 # non-zero => MSB
+ bitorder = format & 8 # non-zero => MSB
+ padindex = format & 3
+
+ bitmapsize = bitmapSizes[padindex]
+ offsets.append(bitmapsize)
+
+ data = fp.read(bitmapsize)
+
+ pad = BYTES_PER_ROW[padindex]
+ mode = "1;R"
+ if bitorder:
+ mode = "1"
+
+ for i in range(nbitmaps):
+ x, y, l, r, w, a, d, f = metrics[i]
+ b, e = offsets[i], offsets[i + 1]
+ bitmaps.append(Image.frombytes("1", (x, y), data[b:e], "raw", mode, pad(x)))
+
+ return bitmaps
+
+ def _load_encoding(self):
+
+ # map character code to bitmap index
+ encoding = [None] * 256
+
+ fp, format, i16, i32 = self._getformat(PCF_BDF_ENCODINGS)
+
+ firstCol, lastCol = i16(fp.read(2)), i16(fp.read(2))
+ firstRow, lastRow = i16(fp.read(2)), i16(fp.read(2))
+
+ i16(fp.read(2)) # default
+
+ nencoding = (lastCol - firstCol + 1) * (lastRow - firstRow + 1)
+
+ for i in range(nencoding):
+ encodingOffset = i16(fp.read(2))
+ if encodingOffset != 0xFFFF:
+ try:
+ encoding[i + firstCol] = encodingOffset
+ except IndexError:
+ break # only load ISO-8859-1 glyphs
+
+ return encoding
diff --git a/contrib/python/Pillow/py2/PIL/PcxImagePlugin.py b/contrib/python/Pillow/py2/PIL/PcxImagePlugin.py
new file mode 100644
index 0000000000..397af8c106
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PcxImagePlugin.py
@@ -0,0 +1,210 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PCX file handling
+#
+# This format was originally used by ZSoft's popular PaintBrush
+# program for the IBM PC. It is also supported by many MS-DOS and
+# Windows applications, including the Windows PaintBrush program in
+# Windows 3.
+#
+# history:
+# 1995-09-01 fl Created
+# 1996-05-20 fl Fixed RGB support
+# 1997-01-03 fl Fixed 2-bit and 4-bit support
+# 1999-02-03 fl Fixed 8-bit support (broken in 1.0b1)
+# 1999-02-07 fl Added write support
+# 2002-06-09 fl Made 2-bit and 4-bit support a bit more robust
+# 2002-07-30 fl Seek from to current position, not beginning of file
+# 2003-06-03 fl Extract DPI settings (info["dpi"])
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-2003 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+import logging
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8, i16le as i16, o8, o16le as o16
+
+logger = logging.getLogger(__name__)
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.6"
+
+
+def _accept(prefix):
+ return i8(prefix[0]) == 10 and i8(prefix[1]) in [0, 2, 3, 5]
+
+
+##
+# Image plugin for Paintbrush images.
+
+
+class PcxImageFile(ImageFile.ImageFile):
+
+ format = "PCX"
+ format_description = "Paintbrush"
+
+ def _open(self):
+
+ # header
+ s = self.fp.read(128)
+ if not _accept(s):
+ raise SyntaxError("not a PCX file")
+
+ # image
+ bbox = i16(s, 4), i16(s, 6), i16(s, 8) + 1, i16(s, 10) + 1
+ if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
+ raise SyntaxError("bad PCX image size")
+ logger.debug("BBox: %s %s %s %s", *bbox)
+
+ # format
+ version = i8(s[1])
+ bits = i8(s[3])
+ planes = i8(s[65])
+ stride = i16(s, 66)
+ logger.debug(
+ "PCX version %s, bits %s, planes %s, stride %s",
+ version,
+ bits,
+ planes,
+ stride,
+ )
+
+ self.info["dpi"] = i16(s, 12), i16(s, 14)
+
+ if bits == 1 and planes == 1:
+ mode = rawmode = "1"
+
+ elif bits == 1 and planes in (2, 4):
+ mode = "P"
+ rawmode = "P;%dL" % planes
+ self.palette = ImagePalette.raw("RGB", s[16:64])
+
+ elif version == 5 and bits == 8 and planes == 1:
+ mode = rawmode = "L"
+ # FIXME: hey, this doesn't work with the incremental loader !!!
+ self.fp.seek(-769, io.SEEK_END)
+ s = self.fp.read(769)
+ if len(s) == 769 and i8(s[0]) == 12:
+ # check if the palette is linear greyscale
+ for i in range(256):
+ if s[i * 3 + 1 : i * 3 + 4] != o8(i) * 3:
+ mode = rawmode = "P"
+ break
+ if mode == "P":
+ self.palette = ImagePalette.raw("RGB", s[1:])
+ self.fp.seek(128)
+
+ elif version == 5 and bits == 8 and planes == 3:
+ mode = "RGB"
+ rawmode = "RGB;L"
+
+ else:
+ raise IOError("unknown PCX mode")
+
+ self.mode = mode
+ self._size = bbox[2] - bbox[0], bbox[3] - bbox[1]
+
+ bbox = (0, 0) + self.size
+ logger.debug("size: %sx%s", *self.size)
+
+ self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))]
+
+
+# --------------------------------------------------------------------
+# save PCX files
+
+
+SAVE = {
+ # mode: (version, bits, planes, raw mode)
+ "1": (2, 1, 1, "1"),
+ "L": (5, 8, 1, "L"),
+ "P": (5, 8, 1, "P"),
+ "RGB": (5, 8, 3, "RGB;L"),
+}
+
+
+def _save(im, fp, filename):
+
+ try:
+ version, bits, planes, rawmode = SAVE[im.mode]
+ except KeyError:
+ raise ValueError("Cannot save %s images as PCX" % im.mode)
+
+ # bytes per plane
+ stride = (im.size[0] * bits + 7) // 8
+ # stride should be even
+ stride += stride % 2
+ # Stride needs to be kept in sync with the PcxEncode.c version.
+ # Ideally it should be passed in in the state, but the bytes value
+ # gets overwritten.
+
+ logger.debug(
+ "PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d",
+ im.size[0],
+ bits,
+ stride,
+ )
+
+ # under windows, we could determine the current screen size with
+ # "Image.core.display_mode()[1]", but I think that's overkill...
+
+ screen = im.size
+
+ dpi = 100, 100
+
+ # PCX header
+ fp.write(
+ o8(10)
+ + o8(version)
+ + o8(1)
+ + o8(bits)
+ + o16(0)
+ + o16(0)
+ + o16(im.size[0] - 1)
+ + o16(im.size[1] - 1)
+ + o16(dpi[0])
+ + o16(dpi[1])
+ + b"\0" * 24
+ + b"\xFF" * 24
+ + b"\0"
+ + o8(planes)
+ + o16(stride)
+ + o16(1)
+ + o16(screen[0])
+ + o16(screen[1])
+ + b"\0" * 54
+ )
+
+ assert fp.tell() == 128
+
+ ImageFile._save(im, fp, [("pcx", (0, 0) + im.size, 0, (rawmode, bits * planes))])
+
+ if im.mode == "P":
+ # colour palette
+ fp.write(o8(12))
+ fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes
+ elif im.mode == "L":
+ # greyscale palette
+ fp.write(o8(12))
+ for i in range(256):
+ fp.write(o8(i) * 3)
+
+
+# --------------------------------------------------------------------
+# registry
+
+
+Image.register_open(PcxImageFile.format, PcxImageFile, _accept)
+Image.register_save(PcxImageFile.format, _save)
+
+Image.register_extension(PcxImageFile.format, ".pcx")
+
+Image.register_mime(PcxImageFile.format, "image/x-pcx")
diff --git a/contrib/python/Pillow/py2/PIL/PdfImagePlugin.py b/contrib/python/Pillow/py2/PIL/PdfImagePlugin.py
new file mode 100644
index 0000000000..1fd40f5bad
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PdfImagePlugin.py
@@ -0,0 +1,248 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PDF (Acrobat) file handling
+#
+# History:
+# 1996-07-16 fl Created
+# 1997-01-18 fl Fixed header
+# 2004-02-21 fl Fixes for 1/L/CMYK images, etc.
+# 2004-02-24 fl Fixes for 1 and P images.
+#
+# Copyright (c) 1997-2004 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1996-1997 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+##
+# Image plugin for PDF images (output only).
+##
+
+import io
+import os
+import time
+
+from . import Image, ImageFile, ImageSequence, PdfParser
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.5"
+
+
+#
+# --------------------------------------------------------------------
+
+# object ids:
+# 1. catalogue
+# 2. pages
+# 3. image
+# 4. page
+# 5. page contents
+
+
+def _save_all(im, fp, filename):
+ _save(im, fp, filename, save_all=True)
+
+
+##
+# (Internal) Image save plugin for the PDF format.
+
+
+def _save(im, fp, filename, save_all=False):
+ is_appending = im.encoderinfo.get("append", False)
+ if is_appending:
+ existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="r+b")
+ else:
+ existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="w+b")
+
+ resolution = im.encoderinfo.get("resolution", 72.0)
+
+ info = {
+ "title": None
+ if is_appending
+ else os.path.splitext(os.path.basename(filename))[0],
+ "author": None,
+ "subject": None,
+ "keywords": None,
+ "creator": None,
+ "producer": None,
+ "creationDate": None if is_appending else time.gmtime(),
+ "modDate": None if is_appending else time.gmtime(),
+ }
+ for k, default in info.items():
+ v = im.encoderinfo.get(k) if k in im.encoderinfo else default
+ if v:
+ existing_pdf.info[k[0].upper() + k[1:]] = v
+
+ #
+ # make sure image data is available
+ im.load()
+
+ existing_pdf.start_writing()
+ existing_pdf.write_header()
+ existing_pdf.write_comment("created by PIL PDF driver " + __version__)
+
+ #
+ # pages
+ ims = [im]
+ if save_all:
+ append_images = im.encoderinfo.get("append_images", [])
+ for append_im in append_images:
+ append_im.encoderinfo = im.encoderinfo.copy()
+ ims.append(append_im)
+ numberOfPages = 0
+ image_refs = []
+ page_refs = []
+ contents_refs = []
+ for im in ims:
+ im_numberOfPages = 1
+ if save_all:
+ try:
+ im_numberOfPages = im.n_frames
+ except AttributeError:
+ # Image format does not have n_frames.
+ # It is a single frame image
+ pass
+ numberOfPages += im_numberOfPages
+ for i in range(im_numberOfPages):
+ image_refs.append(existing_pdf.next_object_id(0))
+ page_refs.append(existing_pdf.next_object_id(0))
+ contents_refs.append(existing_pdf.next_object_id(0))
+ existing_pdf.pages.append(page_refs[-1])
+
+ #
+ # catalog and list of pages
+ existing_pdf.write_catalog()
+
+ pageNumber = 0
+ 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).
+
+ bits = 8
+ params = None
+
+ if im.mode == "1":
+ filter = "ASCIIHexDecode"
+ colorspace = PdfParser.PdfName("DeviceGray")
+ procset = "ImageB" # grayscale
+ bits = 1
+ elif im.mode == "L":
+ filter = "DCTDecode"
+ # params = "<< /Predictor 15 /Columns %d >>" % (width-2)
+ colorspace = PdfParser.PdfName("DeviceGray")
+ procset = "ImageB" # grayscale
+ elif im.mode == "P":
+ filter = "ASCIIHexDecode"
+ palette = im.im.getpalette("RGB")
+ colorspace = [
+ PdfParser.PdfName("Indexed"),
+ PdfParser.PdfName("DeviceRGB"),
+ 255,
+ PdfParser.PdfBinary(palette),
+ ]
+ procset = "ImageI" # indexed color
+ elif im.mode == "RGB":
+ filter = "DCTDecode"
+ colorspace = PdfParser.PdfName("DeviceRGB")
+ procset = "ImageC" # color images
+ elif im.mode == "CMYK":
+ filter = "DCTDecode"
+ colorspace = PdfParser.PdfName("DeviceCMYK")
+ procset = "ImageC" # color images
+ else:
+ raise ValueError("cannot save mode %s" % im.mode)
+
+ #
+ # image
+
+ op = io.BytesIO()
+
+ if filter == "ASCIIHexDecode":
+ if bits == 1:
+ # FIXME: the hex encoder doesn't support packed 1-bit
+ # images; do things the hard way...
+ data = im.tobytes("raw", "1")
+ im = Image.new("L", im.size)
+ im.putdata(data)
+ ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)])
+ elif filter == "DCTDecode":
+ Image.SAVE["JPEG"](im, op, filename)
+ 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)])
+ else:
+ raise ValueError("unsupported PDF filter (%s)" % filter)
+
+ #
+ # Get image characteristics
+
+ 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,
+ )
+
+ #
+ # 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],
+ )
+
+ #
+ # page contents
+
+ page_contents = PdfParser.make_bytes(
+ "q %d 0 0 %d 0 0 cm /image Do Q\n"
+ % (int(width * 72.0 / resolution), int(height * 72.0 / resolution))
+ )
+
+ existing_pdf.write_obj(contents_refs[pageNumber], stream=page_contents)
+
+ pageNumber += 1
+
+ #
+ # trailer
+ existing_pdf.write_xref_and_trailer()
+ if hasattr(fp, "flush"):
+ fp.flush()
+ existing_pdf.close()
+
+
+#
+# --------------------------------------------------------------------
+
+
+Image.register_save("PDF", _save)
+Image.register_save_all("PDF", _save_all)
+
+Image.register_extension("PDF", ".pdf")
+
+Image.register_mime("PDF", "application/pdf")
diff --git a/contrib/python/Pillow/py2/PIL/PdfParser.py b/contrib/python/Pillow/py2/PIL/PdfParser.py
new file mode 100644
index 0000000000..0ec6bba14d
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PdfParser.py
@@ -0,0 +1,1043 @@
+import calendar
+import codecs
+import collections
+import mmap
+import os
+import re
+import time
+import zlib
+
+from ._util import py3
+
+try:
+ from UserDict import UserDict # Python 2.x
+except ImportError:
+ UserDict = collections.UserDict # Python 3.x
+
+
+if py3: # Python 3.x
+
+ def make_bytes(s):
+ return s.encode("us-ascii")
+
+
+else: # Python 2.x
+
+ def make_bytes(s): # pragma: no cover
+ 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
+def encode_text(s):
+ return codecs.BOM_UTF16_BE + s.encode("utf_16_be")
+
+
+PDFDocEncoding = {
+ 0x16: u"\u0017",
+ 0x18: u"\u02D8",
+ 0x19: u"\u02C7",
+ 0x1A: u"\u02C6",
+ 0x1B: u"\u02D9",
+ 0x1C: u"\u02DD",
+ 0x1D: u"\u02DB",
+ 0x1E: u"\u02DA",
+ 0x1F: u"\u02DC",
+ 0x80: u"\u2022",
+ 0x81: u"\u2020",
+ 0x82: u"\u2021",
+ 0x83: u"\u2026",
+ 0x84: u"\u2014",
+ 0x85: u"\u2013",
+ 0x86: u"\u0192",
+ 0x87: u"\u2044",
+ 0x88: u"\u2039",
+ 0x89: u"\u203A",
+ 0x8A: u"\u2212",
+ 0x8B: u"\u2030",
+ 0x8C: u"\u201E",
+ 0x8D: u"\u201C",
+ 0x8E: u"\u201D",
+ 0x8F: u"\u2018",
+ 0x90: u"\u2019",
+ 0x91: u"\u201A",
+ 0x92: u"\u2122",
+ 0x93: u"\uFB01",
+ 0x94: u"\uFB02",
+ 0x95: u"\u0141",
+ 0x96: u"\u0152",
+ 0x97: u"\u0160",
+ 0x98: u"\u0178",
+ 0x99: u"\u017D",
+ 0x9A: u"\u0131",
+ 0x9B: u"\u0142",
+ 0x9C: u"\u0153",
+ 0x9D: u"\u0161",
+ 0x9E: u"\u017E",
+ 0xA0: u"\u20AC",
+}
+
+
+def decode_text(b):
+ if b[: len(codecs.BOM_UTF16_BE)] == codecs.BOM_UTF16_BE:
+ return b[len(codecs.BOM_UTF16_BE) :].decode("utf_16_be")
+ elif py3: # Python 3.x
+ return "".join(PDFDocEncoding.get(byte, chr(byte)) for byte in b)
+ else: # Python 2.x
+ return u"".join(PDFDocEncoding.get(ord(byte), byte) for byte in b)
+
+
+class PdfFormatError(RuntimeError):
+ """An error that probably indicates a syntactic or semantic error in the
+ PDF file structure"""
+
+ pass
+
+
+def check_format_condition(condition, error_message):
+ if not condition:
+ raise PdfFormatError(error_message)
+
+
+class IndirectReference(
+ collections.namedtuple("IndirectReferenceTuple", ["object_id", "generation"])
+):
+ def __str__(self):
+ return "%s %s R" % self
+
+ def __bytes__(self):
+ 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
+ )
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __hash__(self):
+ return hash((self.object_id, self.generation))
+
+
+class IndirectObjectDef(IndirectReference):
+ def __str__(self):
+ return "%s %s obj" % self
+
+
+class XrefTable:
+ def __init__(self):
+ self.existing_entries = {} # object ID => (offset, generation)
+ self.new_entries = {} # object ID => (offset, generation)
+ self.deleted_entries = {0: 65536} # object ID => generation
+ self.reading_finished = False
+
+ def __setitem__(self, key, value):
+ if self.reading_finished:
+ self.new_entries[key] = value
+ else:
+ self.existing_entries[key] = value
+ if key in self.deleted_entries:
+ del self.deleted_entries[key]
+
+ def __getitem__(self, key):
+ try:
+ return self.new_entries[key]
+ except KeyError:
+ return self.existing_entries[key]
+
+ def __delitem__(self, key):
+ if key in self.new_entries:
+ generation = self.new_entries[key][1] + 1
+ del self.new_entries[key]
+ self.deleted_entries[key] = generation
+ elif key in self.existing_entries:
+ generation = self.existing_entries[key][1] + 1
+ self.deleted_entries[key] = generation
+ 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"
+ )
+
+ 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())
+ )
+
+ def keys(self):
+ 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()))
+ deleted_keys = sorted(set(self.deleted_entries.keys()))
+ startxref = f.tell()
+ f.write(b"xref\n")
+ while keys:
+ # find a contiguous sequence of object IDs
+ prev = None
+ for index, key in enumerate(keys):
+ if prev is None or prev + 1 == key:
+ prev = key
+ else:
+ contiguous_keys = keys[:index]
+ keys = keys[index:]
+ break
+ else:
+ contiguous_keys = keys
+ keys = None
+ 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]))
+ else:
+ this_deleted_object_id = deleted_keys.pop(0)
+ check_format_condition(
+ object_id == this_deleted_object_id,
+ "expected the next deleted object ID to be %s, instead found %s"
+ % (object_id, this_deleted_object_id),
+ )
+ try:
+ 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])
+ )
+ )
+ return startxref
+
+
+class PdfName:
+ def __init__(self, name):
+ if isinstance(name, PdfName):
+ self.name = name.name
+ elif isinstance(name, bytes):
+ self.name = name
+ else:
+ self.name = name.encode("us-ascii")
+
+ def name_as_str(self):
+ return self.name.decode("us-ascii")
+
+ def __eq__(self, other):
+ return (
+ isinstance(other, PdfName) and other.name == self.name
+ ) or other == self.name
+
+ def __hash__(self):
+ return hash(self.name)
+
+ def __repr__(self):
+ return "PdfName(%s)" % repr(self.name)
+
+ @classmethod
+ def from_pdf_stream(cls, data):
+ return cls(PdfParser.interpret_name(data))
+
+ allowed_chars = set(range(33, 127)) - set(ord(c) for c in "#%/()<>[]{}")
+
+ def __bytes__(self):
+ result = bytearray(b"/")
+ for b in self.name:
+ if py3: # Python 3.x
+ if b in self.allowed_chars:
+ result.append(b)
+ else:
+ result.extend(make_bytes("#%02X" % b))
+ else: # Python 2.x
+ if ord(b) in self.allowed_chars:
+ result.append(b)
+ else:
+ result.extend(b"#%02X" % ord(b))
+ return bytes(result)
+
+ __str__ = __bytes__
+
+
+class PdfArray(list):
+ def __bytes__(self):
+ return b"[ " + b" ".join(pdf_repr(x) for x in self) + b" ]"
+
+ __str__ = __bytes__
+
+
+class PdfDict(UserDict):
+ def __setattr__(self, key, value):
+ if key == "data":
+ if hasattr(UserDict, "__setattr__"):
+ UserDict.__setattr__(self, key, value)
+ else:
+ self.__dict__[key] = value
+ else:
+ self[key.encode("us-ascii")] = value
+
+ def __getattr__(self, key):
+ try:
+ value = self[key.encode("us-ascii")]
+ except KeyError:
+ raise AttributeError(key)
+ if isinstance(value, bytes):
+ value = decode_text(value)
+ if key.endswith("Date"):
+ if value.startswith("D:"):
+ value = value[2:]
+
+ relationship = "Z"
+ if len(value) > 17:
+ relationship = value[14]
+ offset = int(value[15:17]) * 60
+ if len(value) > 20:
+ offset += int(value[18:20])
+
+ format = "%Y%m%d%H%M%S"[: len(value) - 2]
+ value = time.strptime(value[: len(format) + 2], format)
+ if relationship in ["+", "-"]:
+ offset *= 60
+ if relationship == "+":
+ offset *= -1
+ value = time.gmtime(calendar.timegm(value) + offset)
+ return value
+
+ def __bytes__(self):
+ out = bytearray(b"<<")
+ for key, value in self.items():
+ if value is None:
+ continue
+ value = pdf_repr(value)
+ out.extend(b"\n")
+ out.extend(bytes(PdfName(key)))
+ out.extend(b" ")
+ out.extend(value)
+ out.extend(b"\n>>")
+ return bytes(out)
+
+ if not py3:
+ __str__ = __bytes__
+
+
+class PdfBinary:
+ def __init__(self, data):
+ self.data = data
+
+ if py3: # Python 3.x
+
+ def __bytes__(self):
+ return make_bytes("<%s>" % "".join("%02X" % b for b in self.data))
+
+ else: # Python 2.x
+
+ def __str__(self):
+ return "<%s>" % "".join("%02X" % ord(b) for b in self.data)
+
+
+class PdfStream:
+ def __init__(self, dictionary, buf):
+ self.dictionary = dictionary
+ self.buf = buf
+
+ def decode(self):
+ try:
+ filter = self.dictionary.Filter
+ except AttributeError:
+ return self.buf
+ if filter == b"FlateDecode":
+ try:
+ expected_length = self.dictionary.DL
+ except AttributeError:
+ 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)
+ )
+
+
+def pdf_repr(x):
+ if x is True:
+ return b"true"
+ elif x is False:
+ return b"false"
+ elif x is None:
+ return b"null"
+ elif isinstance(x, (PdfName, PdfDict, PdfArray, PdfBinary)):
+ return bytes(x)
+ elif isinstance(x, int):
+ return str(x).encode("us-ascii")
+ elif isinstance(x, time.struct_time):
+ return b"(D:" + time.strftime("%Y%m%d%H%M%SZ", x).encode("us-ascii") + b")"
+ elif isinstance(x, dict):
+ 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) # noqa: F821
+ ):
+ return pdf_repr(encode_text(x))
+ elif isinstance(x, bytes):
+ # 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)
+
+
+class PdfParser:
+ """Based on
+ https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
+ Supports PDF up to 1.4
+ """
+
+ def __init__(self, filename=None, f=None, buf=None, start_offset=0, mode="rb"):
+ if 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
+ self.start_offset = start_offset
+ self.should_close_buf = False
+ self.should_close_file = False
+ if filename is not None and f is None:
+ self.f = f = open(filename, mode)
+ self.should_close_file = True
+ if f is not None:
+ self.buf = buf = self.get_buf_from_file(f)
+ self.should_close_buf = True
+ if not filename and hasattr(f, "name"):
+ self.filename = f.name
+ self.cached_objects = {}
+ if buf:
+ self.read_pdf_info()
+ else:
+ self.file_size_total = self.file_size_this = 0
+ self.root = PdfDict()
+ self.root_ref = None
+ self.info = PdfDict()
+ self.info_ref = None
+ self.page_tree_root = {}
+ self.pages = []
+ self.orig_pages = []
+ self.pages_ref = None
+ self.last_xref_section_offset = None
+ self.trailer_dict = {}
+ self.xref_table = XrefTable()
+ self.xref_table.reading_finished = True
+ if f:
+ self.seek_end()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.close()
+ return False # do not suppress exceptions
+
+ def start_writing(self):
+ self.close_buf()
+ self.seek_end()
+
+ def close_buf(self):
+ try:
+ self.buf.close()
+ except AttributeError:
+ pass
+ self.buf = None
+
+ def close(self):
+ if self.should_close_buf:
+ self.close_buf()
+ if self.f is not None and self.should_close_file:
+ self.f.close()
+ self.f = None
+
+ def seek_end(self):
+ self.f.seek(0, os.SEEK_END)
+
+ def write_header(self):
+ self.f.write(b"%PDF-1.4\n")
+
+ def write_comment(self, s):
+ self.f.write(("%% %s\n" % (s,)).encode("utf-8"))
+
+ def write_catalog(self):
+ self.del_root()
+ self.root_ref = self.next_object_id(self.f.tell())
+ self.pages_ref = self.next_object_id(0)
+ self.rewrite_pages()
+ self.write_obj(self.root_ref, Type=PdfName(b"Catalog"), Pages=self.pages_ref)
+ self.write_obj(
+ self.pages_ref,
+ Type=PdfName(b"Pages"),
+ Count=len(self.pages),
+ Kids=self.pages,
+ )
+ return self.root_ref
+
+ def rewrite_pages(self):
+ pages_tree_nodes_to_delete = []
+ for i, page_ref in enumerate(self.orig_pages):
+ page_info = self.cached_objects[page_ref]
+ del self.xref_table[page_ref.object_id]
+ pages_tree_nodes_to_delete.append(page_info[PdfName(b"Parent")])
+ if page_ref not in self.pages:
+ # the page has been deleted
+ continue
+ # make dict keys into strings for passing to write_page
+ stringified_page_info = {}
+ for key, value in page_info.items():
+ # key should be a PdfName
+ stringified_page_info[key.name_as_str()] = value
+ stringified_page_info["Parent"] = self.pages_ref
+ new_page_ref = self.write_page(None, **stringified_page_info)
+ for j, cur_page_ref in enumerate(self.pages):
+ if cur_page_ref == page_ref:
+ # replace the page reference with the new one
+ self.pages[j] = new_page_ref
+ # delete redundant Pages tree nodes from xref table
+ for pages_tree_node_ref in pages_tree_nodes_to_delete:
+ while pages_tree_node_ref:
+ pages_tree_node = self.cached_objects[pages_tree_node_ref]
+ if pages_tree_node_ref.object_id in self.xref_table:
+ del self.xref_table[pages_tree_node_ref.object_id]
+ pages_tree_node_ref = pages_tree_node.get(b"Parent", None)
+ self.orig_pages = []
+
+ def write_xref_and_trailer(self, new_root_ref=None):
+ if new_root_ref:
+ self.del_root()
+ self.root_ref = new_root_ref
+ if self.info:
+ self.info_ref = self.write_obj(None, self.info)
+ start_xref = self.xref_table.write(self.f)
+ num_entries = len(self.xref_table)
+ trailer_dict = {b"Root": self.root_ref, b"Size": num_entries}
+ if self.last_xref_section_offset is not None:
+ trailer_dict[b"Prev"] = self.last_xref_section_offset
+ 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)
+ )
+
+ def write_page(self, ref, *objs, **dict_obj):
+ if isinstance(ref, int):
+ ref = self.pages[ref]
+ if "Type" not in dict_obj:
+ dict_obj["Type"] = PdfName(b"Page")
+ if "Parent" not in dict_obj:
+ dict_obj["Parent"] = self.pages_ref
+ return self.write_obj(ref, *objs, **dict_obj)
+
+ def write_obj(self, ref, *objs, **dict_obj):
+ f = self.f
+ if ref is None:
+ ref = self.next_object_id(f.tell())
+ else:
+ self.xref_table[ref.object_id] = (f.tell(), ref.generation)
+ f.write(bytes(IndirectObjectDef(*ref)))
+ stream = dict_obj.pop("stream", None)
+ if stream is not None:
+ dict_obj["Length"] = len(stream)
+ if dict_obj:
+ f.write(pdf_repr(dict_obj))
+ for obj in objs:
+ f.write(pdf_repr(obj))
+ if stream is not None:
+ f.write(b"stream\n")
+ f.write(stream)
+ f.write(b"\nendstream\n")
+ f.write(b"endobj\n")
+ return ref
+
+ def del_root(self):
+ if self.root_ref is None:
+ return
+ del self.xref_table[self.root_ref.object_id]
+ del self.xref_table[self.root[b"Pages"].object_id]
+
+ @staticmethod
+ def get_buf_from_file(f):
+ if hasattr(f, "getbuffer"):
+ return f.getbuffer()
+ elif hasattr(f, "getvalue"):
+ return f.getvalue()
+ else:
+ try:
+ return mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
+ except ValueError: # cannot mmap an empty file
+ return b""
+
+ def read_pdf_info(self):
+ self.file_size_total = len(self.buf)
+ self.file_size_this = self.file_size_total - self.start_offset
+ self.read_trailer()
+ self.root_ref = self.trailer_dict[b"Root"]
+ self.info_ref = self.trailer_dict.get(b"Info", None)
+ self.root = PdfDict(self.read_indirect(self.root_ref))
+ if self.info_ref is None:
+ self.info = PdfDict()
+ 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(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",
+ )
+ 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
+ self.orig_pages = self.pages[:]
+
+ def next_object_id(self, offset=None):
+ try:
+ # TODO: support reuse of deleted objects
+ reference = IndirectReference(max(self.xref_table.keys()) + 1, 0)
+ except ValueError:
+ reference = IndirectReference(1, 0)
+ if offset is not None:
+ self.xref_table[reference.object_id] = (offset, 0)
+ return reference
+
+ delimiter = br"[][()<>{}/%]"
+ delimiter_or_ws = br"[][()<>{}/%\000\011\012\014\015\040]"
+ whitespace = br"[\000\011\012\014\015\040]"
+ whitespace_or_hex = br"[\000\011\012\014\015\0400-9a-fA-F]"
+ whitespace_optional = whitespace + b"*"
+ 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,
+ )
+
+ def read_trailer(self):
+ search_start_offset = len(self.buf) - 16384
+ if search_start_offset < self.start_offset:
+ search_start_offset = self.start_offset
+ m = self.re_trailer_end.search(self.buf, search_start_offset)
+ check_format_condition(m, "trailer end not found")
+ # make sure we found the LAST trailer
+ last_match = m
+ while m:
+ last_match = m
+ m = self.re_trailer_end.search(self.buf, m.start() + 16)
+ if not m:
+ m = last_match
+ trailer_data = m.group(1)
+ self.last_xref_section_offset = int(m.group(2))
+ self.trailer_dict = self.interpret_trailer(trailer_data)
+ self.xref_table = XrefTable()
+ self.read_xref_table(xref_section_offset=self.last_xref_section_offset)
+ if b"Prev" in self.trailer_dict:
+ 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]
+ )
+ 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",
+ )
+ 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_dict_start = re.compile(whitespace_optional + br"\<\<")
+ re_dict_end = re.compile(whitespace_optional + br"\>\>" + whitespace_optional)
+
+ @classmethod
+ def interpret_trailer(cls, trailer_data):
+ trailer = {}
+ offset = 0
+ while True:
+ 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:]),
+ )
+ 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",
+ )
+ return trailer
+
+ re_hashes_in_name = re.compile(br"([^#]*)(#([0-9a-fA-F]{2}))?")
+
+ @classmethod
+ def interpret_name(cls, raw, as_text=False):
+ 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"))
+ else:
+ name += m.group(1)
+ if as_text:
+ return name.decode("utf-8")
+ 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_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_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_stream_start = re.compile(whitespace_optional + br"stream\r?\n")
+ 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):
+ if max_nesting == 0:
+ return None, None
+ m = cls.re_comment.match(data, offset)
+ if m:
+ 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))),
+ "indirect object definition different than expected",
+ )
+ 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")
+ return object, m.end()
+ 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",
+ )
+ return IndirectReference(int(m.group(1)), int(m.group(2))), m.end()
+ m = cls.re_dict_start.match(data, offset)
+ if m:
+ offset = m.end()
+ result = {}
+ m = cls.re_dict_end.match(data, offset)
+ while not m:
+ 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)
+ result[key] = value
+ if offset is None:
+ return result, None
+ m = cls.re_dict_end.match(data, offset)
+ offset = m.end()
+ m = cls.re_stream_start.match(data, offset)
+ if m:
+ 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)
+ )
+ 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")
+ offset = m.end()
+ result = PdfStream(PdfDict(result), stream_data)
+ else:
+ result = PdfDict(result)
+ return result, offset
+ m = cls.re_array_start.match(data, offset)
+ if m:
+ offset = m.end()
+ result = []
+ m = cls.re_array_end.match(data, offset)
+ while not m:
+ value, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1)
+ result.append(value)
+ if offset is None:
+ return result, None
+ m = cls.re_array_end.match(data, offset)
+ return result, m.end()
+ m = cls.re_null.match(data, offset)
+ if m:
+ return None, m.end()
+ m = cls.re_true.match(data, offset)
+ if m:
+ return True, m.end()
+ m = cls.re_false.match(data, offset)
+ if m:
+ return False, m.end()
+ m = cls.re_name.match(data, offset)
+ if m:
+ return PdfName(cls.interpret_name(m.group(1))), m.end()
+ m = cls.re_int.match(data, offset)
+ if m:
+ return int(m.group(1)), m.end()
+ m = cls.re_real.match(data, offset)
+ if m:
+ # XXX Decimal instead of float???
+ return float(m.group(1)), m.end()
+ m = cls.re_string_hex.match(data, offset)
+ if m:
+ # filter out whitespace
+ hex_string = bytearray(
+ [b for b in m.group(1) if b in b"0123456789abcdefABCDEF"]
+ )
+ if len(hex_string) % 2 == 1:
+ # 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]))
+
+ re_lit_str_token = re.compile(
+ br"(\\[nrtbf()\\])|(\\[0-9]{1,3})|(\\(\r\n|\r|\n))|(\r\n|\r|\n)|(\()|(\))"
+ )
+ escaped_chars = {
+ b"n": b"\n",
+ b"r": b"\r",
+ b"t": b"\t",
+ b"b": b"\b",
+ b"f": b"\f",
+ b"(": b"(",
+ b")": b")",
+ b"\\": b"\\",
+ ord(b"n"): b"\n",
+ ord(b"r"): b"\r",
+ ord(b"t"): b"\t",
+ ord(b"b"): b"\b",
+ ord(b"f"): b"\f",
+ ord(b"("): b"(",
+ ord(b")"): b")",
+ ord(b"\\"): b"\\",
+ }
+
+ @classmethod
+ def get_literal_string(cls, data, offset):
+ nesting_depth = 0
+ result = bytearray()
+ for m in cls.re_lit_str_token.finditer(data, offset):
+ result.extend(data[offset : m.start()])
+ if m.group(1):
+ result.extend(cls.escaped_chars[m.group(1)[1]])
+ elif m.group(2):
+ result.append(int(m.group(2)[1:], 8))
+ elif m.group(3):
+ pass
+ elif m.group(5):
+ result.extend(b"\n")
+ elif m.group(6):
+ result.extend(b"(")
+ nesting_depth += 1
+ elif m.group(7):
+ if nesting_depth == 0:
+ return bytes(result), m.end()
+ result.extend(b")")
+ nesting_depth -= 1
+ 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_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
+ )
+ 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"
+ )
+ break
+ subsection_found = True
+ offset = m.end()
+ first_object = int(m.group(1))
+ num_objects = int(m.group(2))
+ for i in range(first_object, first_object + num_objects):
+ m = self.re_xref_entry.match(self.buf, offset)
+ check_format_condition(m, "xref entry not found")
+ offset = m.end()
+ is_free = m.group(3) == b"f"
+ 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)",
+ )
+ 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"
+ % (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
+ 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"
+ )
+ pages = []
+ for kid in node[b"Kids"]:
+ kid_object = self.read_indirect(kid)
+ if kid_object[b"Type"] == b"Page":
+ pages.append(kid)
+ else:
+ pages.extend(self.linearize_page_tree(node=kid_object))
+ return pages
diff --git a/contrib/python/Pillow/py2/PIL/PixarImagePlugin.py b/contrib/python/Pillow/py2/PIL/PixarImagePlugin.py
new file mode 100644
index 0000000000..dc71ca17a8
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PixarImagePlugin.py
@@ -0,0 +1,75 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PIXAR raster support for PIL
+#
+# history:
+# 97-01-29 fl Created
+#
+# notes:
+# This is incomplete; it is based on a few samples created with
+# Photoshop 2.5 and 3.0, and a summary description provided by
+# Greg Coats <gcoats@labiris.er.usgs.gov>. Hopefully, "L" and
+# "RGBA" support will be added in future versions.
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFile
+from ._binary import i16le as i16
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+
+#
+# helpers
+
+
+def _accept(prefix):
+ return prefix[:4] == b"\200\350\000\000"
+
+
+##
+# Image plugin for PIXAR raster images.
+
+
+class PixarImageFile(ImageFile.ImageFile):
+
+ format = "PIXAR"
+ format_description = "PIXAR raster image"
+
+ def _open(self):
+
+ # assuming a 4-byte magic label
+ s = self.fp.read(4)
+ if s != b"\200\350\000\000":
+ raise SyntaxError("not a PIXAR file")
+
+ # read rest of header
+ s = s + self.fp.read(508)
+
+ self._size = i16(s[418:420]), i16(s[416:418])
+
+ # get channel/depth descriptions
+ mode = i16(s[424:426]), i16(s[426:428])
+
+ if mode == (14, 2):
+ self.mode = "RGB"
+ # FIXME: to be continued...
+
+ # create tile descriptor (assuming "dumped")
+ self.tile = [("raw", (0, 0) + self.size, 1024, (self.mode, 0, 1))]
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_open(PixarImageFile.format, PixarImageFile, _accept)
+
+Image.register_extension(PixarImageFile.format, ".pxr")
diff --git a/contrib/python/Pillow/py2/PIL/PngImagePlugin.py b/contrib/python/Pillow/py2/PIL/PngImagePlugin.py
new file mode 100644
index 0000000000..be237b3eeb
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PngImagePlugin.py
@@ -0,0 +1,958 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PNG support code
+#
+# See "PNG (Portable Network Graphics) Specification, version 1.0;
+# W3C Recommendation", 1996-10-01, Thomas Boutell (ed.).
+#
+# history:
+# 1996-05-06 fl Created (couldn't resist it)
+# 1996-12-14 fl Upgraded, added read and verify support (0.2)
+# 1996-12-15 fl Separate PNG stream parser
+# 1996-12-29 fl Added write support, added getchunks
+# 1996-12-30 fl Eliminated circular references in decoder (0.3)
+# 1998-07-12 fl Read/write 16-bit images as mode I (0.4)
+# 2001-02-08 fl Added transparency support (from Zircon) (0.5)
+# 2001-04-16 fl Don't close data source in "open" method (0.6)
+# 2004-02-24 fl Don't even pretend to support interlaced files (0.7)
+# 2004-08-31 fl Do basic sanity check on chunk identifiers (0.8)
+# 2004-09-20 fl Added PngInfo chunk container
+# 2004-12-18 fl Added DPI read support (based on code by Niki Spahiev)
+# 2008-08-13 fl Added tRNS support for RGB images
+# 2009-03-06 fl Support for preserving ICC profiles (by Florian Hoech)
+# 2009-03-08 fl Added zTXT support (from Lowell Alleman)
+# 2009-03-29 fl Read interlaced PNG files (from Conrado Porto Lopes Gouvua)
+#
+# Copyright (c) 1997-2009 by Secret Labs AB
+# Copyright (c) 1996 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import logging
+import re
+import struct
+import zlib
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8, i16be as i16, i32be as i32, o16be as o16, o32be as o32
+from ._util import py3
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.9"
+
+logger = logging.getLogger(__name__)
+
+is_cid = re.compile(br"\w\w\w\w").match
+
+
+_MAGIC = b"\211PNG\r\n\032\n"
+
+
+_MODES = {
+ # supported bits/color combinations, and corresponding modes/rawmodes
+ # Greyscale
+ (1, 0): ("1", "1"),
+ (2, 0): ("L", "L;2"),
+ (4, 0): ("L", "L;4"),
+ (8, 0): ("L", "L"),
+ (16, 0): ("I", "I;16B"),
+ # Truecolour
+ (8, 2): ("RGB", "RGB"),
+ (16, 2): ("RGB", "RGB;16B"),
+ # Indexed-colour
+ (1, 3): ("P", "P;1"),
+ (2, 3): ("P", "P;2"),
+ (4, 3): ("P", "P;4"),
+ (8, 3): ("P", "P"),
+ # Greyscale with alpha
+ (8, 4): ("LA", "LA"),
+ (16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available
+ # Truecolour with alpha
+ (8, 6): ("RGBA", "RGBA"),
+ (16, 6): ("RGBA", "RGBA;16B"),
+}
+
+
+_simple_palette = re.compile(b"^\xff*\x00\xff*$")
+
+# Maximum decompressed size for a iTXt or zTXt chunk.
+# Eliminates decompression bombs where compressed chunks can expand 1000x
+MAX_TEXT_CHUNK = ImageFile.SAFEBLOCK
+# Set the maximum total text chunk size.
+MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK
+
+
+def _safe_zlib_decompress(s):
+ dobj = zlib.decompressobj()
+ plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
+ if dobj.unconsumed_tail:
+ raise ValueError("Decompressed Data Too Large")
+ return plaintext
+
+
+def _crc32(data, seed=0):
+ return zlib.crc32(data, seed) & 0xFFFFFFFF
+
+
+# --------------------------------------------------------------------
+# Support classes. Suitable for PNG and related formats like MNG etc.
+
+
+class ChunkStream(object):
+ def __init__(self, fp):
+
+ self.fp = fp
+ self.queue = []
+
+ def read(self):
+ """Fetch a new chunk. Returns header information."""
+ cid = None
+
+ if self.queue:
+ cid, pos, length = self.queue.pop()
+ self.fp.seek(pos)
+ else:
+ s = self.fp.read(8)
+ cid = s[4:]
+ pos = self.fp.tell()
+ length = i32(s)
+
+ if not is_cid(cid):
+ if not ImageFile.LOAD_TRUNCATED_IMAGES:
+ raise SyntaxError("broken PNG file (chunk %s)" % repr(cid))
+
+ return cid, pos, length
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ def close(self):
+ self.queue = self.crc = self.fp = None
+
+ def push(self, cid, pos, length):
+
+ self.queue.append((cid, pos, length))
+
+ def call(self, cid, pos, length):
+ """Call the appropriate chunk handler"""
+
+ logger.debug("STREAM %r %s %s", cid, pos, length)
+ return getattr(self, "chunk_" + cid.decode("ascii"))(pos, length)
+
+ def crc(self, cid, data):
+ """Read and verify checksum"""
+
+ # 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)
+ return
+
+ try:
+ crc1 = _crc32(data, _crc32(cid))
+ crc2 = i32(self.fp.read(4))
+ if crc1 != crc2:
+ raise SyntaxError("broken PNG file (bad header checksum in %r)" % cid)
+ except struct.error:
+ raise SyntaxError("broken PNG file (incomplete checksum in %r)" % cid)
+
+ def crc_skip(self, cid, data):
+ """Read checksum. Used if the C module is not present"""
+
+ self.fp.read(4)
+
+ def verify(self, endchunk=b"IEND"):
+
+ # Simple approach; just calculate checksum for all remaining
+ # blocks. Must be called directly after open.
+
+ cids = []
+
+ while True:
+ try:
+ cid, pos, length = self.read()
+ except struct.error:
+ raise IOError("truncated PNG file")
+
+ if cid == endchunk:
+ break
+ self.crc(cid, ImageFile._safe_read(self.fp, length))
+ cids.append(cid)
+
+ return cids
+
+
+class iTXt(str):
+ """
+ Subclass of string to allow iTXt chunks to look like strings while
+ keeping their extra information
+
+ """
+
+ @staticmethod
+ def __new__(cls, text, lang=None, tkey=None):
+ """
+ :param cls: the class to use when creating the instance
+ :param text: value for this key
+ :param lang: language code
+ :param tkey: UTF-8 version of the key name
+ """
+
+ self = str.__new__(cls, text)
+ self.lang = lang
+ self.tkey = tkey
+ return self
+
+
+class PngInfo(object):
+ """
+ PNG chunk container (for use with save(pnginfo=))
+
+ """
+
+ def __init__(self):
+ self.chunks = []
+
+ def add(self, cid, data):
+ """Appends an arbitrary chunk. Use with caution.
+
+ :param cid: a byte string, 4 bytes long.
+ :param data: a byte string of the encoded data
+
+ """
+
+ self.chunks.append((cid, data))
+
+ def add_itxt(self, key, value, lang="", tkey="", zip=False):
+ """Appends an iTXt chunk.
+
+ :param key: latin-1 encodable text key name
+ :param value: value for this key
+ :param lang: language code
+ :param tkey: UTF-8 version of the key name
+ :param zip: compression flag
+
+ """
+
+ if not isinstance(key, bytes):
+ key = key.encode("latin-1", "strict")
+ if not isinstance(value, bytes):
+ value = value.encode("utf-8", "strict")
+ if not isinstance(lang, bytes):
+ lang = lang.encode("utf-8", "strict")
+ if not isinstance(tkey, bytes):
+ tkey = tkey.encode("utf-8", "strict")
+
+ if zip:
+ self.add(
+ b"iTXt",
+ key + b"\0\x01\0" + lang + b"\0" + tkey + b"\0" + zlib.compress(value),
+ )
+ else:
+ self.add(b"iTXt", key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + value)
+
+ def add_text(self, key, value, zip=False):
+ """Appends a text chunk.
+
+ :param key: latin-1 encodable text key name
+ :param value: value for this key, text or an
+ :py:class:`PIL.PngImagePlugin.iTXt` instance
+ :param zip: compression flag
+
+ """
+ if isinstance(value, iTXt):
+ return self.add_itxt(key, value, value.lang, value.tkey, zip=zip)
+
+ # The tEXt chunk stores latin-1 text
+ if not isinstance(value, bytes):
+ try:
+ value = value.encode("latin-1", "strict")
+ except UnicodeError:
+ return self.add_itxt(key, value, zip=zip)
+
+ if not isinstance(key, bytes):
+ key = key.encode("latin-1", "strict")
+
+ if zip:
+ self.add(b"zTXt", key + b"\0\0" + zlib.compress(value))
+ else:
+ self.add(b"tEXt", key + b"\0" + value)
+
+
+# --------------------------------------------------------------------
+# PNG image stream (IHDR/IEND)
+
+
+class PngStream(ChunkStream):
+ def __init__(self, fp):
+
+ ChunkStream.__init__(self, fp)
+
+ # local copies of Image attributes
+ self.im_info = {}
+ self.im_text = {}
+ self.im_size = (0, 0)
+ self.im_mode = None
+ self.im_tile = None
+ self.im_palette = None
+ self.im_custom_mimetype = None
+
+ self.text_memory = 0
+
+ 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
+ )
+
+ def chunk_iCCP(self, pos, length):
+
+ # ICC profile
+ s = ImageFile._safe_read(self.fp, length)
+ # according to PNG spec, the iCCP chunk contains:
+ # Profile name 1-79 bytes (character string)
+ # Null separator 1 byte (null character)
+ # Compression method 1 byte (0)
+ # Compressed profile n bytes (zlib with deflate compression)
+ i = s.find(b"\0")
+ logger.debug("iCCP profile name %r", s[:i])
+ logger.debug("Compression method %s", i8(s[i]))
+ comp_method = i8(s[i])
+ if comp_method != 0:
+ raise SyntaxError(
+ "Unknown compression method %s in iCCP chunk" % comp_method
+ )
+ try:
+ icc_profile = _safe_zlib_decompress(s[i + 2 :])
+ except ValueError:
+ if ImageFile.LOAD_TRUNCATED_IMAGES:
+ icc_profile = None
+ else:
+ raise
+ except zlib.error:
+ icc_profile = None # FIXME
+ self.im_info["icc_profile"] = icc_profile
+ return s
+
+ def chunk_IHDR(self, pos, length):
+
+ # image header
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_size = i32(s), i32(s[4:])
+ try:
+ self.im_mode, self.im_rawmode = _MODES[(i8(s[8]), i8(s[9]))]
+ except Exception:
+ pass
+ if i8(s[12]):
+ self.im_info["interlace"] = 1
+ if i8(s[11]):
+ raise SyntaxError("unknown filter category")
+ return s
+
+ def chunk_IDAT(self, pos, length):
+
+ # image data
+ self.im_tile = [("zip", (0, 0) + self.im_size, pos, self.im_rawmode)]
+ self.im_idat = length
+ raise EOFError
+
+ def chunk_IEND(self, pos, length):
+
+ # end of PNG image
+ raise EOFError
+
+ def chunk_PLTE(self, pos, length):
+
+ # palette
+ s = ImageFile._safe_read(self.fp, length)
+ if self.im_mode == "P":
+ self.im_palette = "RGB", s
+ return s
+
+ def chunk_tRNS(self, pos, length):
+
+ # transparency
+ s = ImageFile._safe_read(self.fp, length)
+ if self.im_mode == "P":
+ if _simple_palette.match(s):
+ # tRNS contains only one full-transparent entry,
+ # other entries are full opaque
+ i = s.find(b"\0")
+ if i >= 0:
+ self.im_info["transparency"] = i
+ else:
+ # otherwise, we have a byte string with one alpha value
+ # for each palette entry
+ self.im_info["transparency"] = s
+ elif self.im_mode in ("1", "L", "I"):
+ self.im_info["transparency"] = i16(s)
+ elif self.im_mode == "RGB":
+ self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:])
+ return s
+
+ def chunk_gAMA(self, pos, length):
+ # gamma setting
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_info["gamma"] = i32(s) / 100000.0
+ return s
+
+ def chunk_cHRM(self, pos, length):
+ # chromaticity, 8 unsigned ints, actual value is scaled by 100,000
+ # WP x,y, Red x,y, Green x,y Blue x,y
+
+ s = ImageFile._safe_read(self.fp, length)
+ raw_vals = struct.unpack(">%dI" % (len(s) // 4), s)
+ self.im_info["chromaticity"] = tuple(elt / 100000.0 for elt in raw_vals)
+ return s
+
+ def chunk_sRGB(self, pos, length):
+ # srgb rendering intent, 1 byte
+ # 0 perceptual
+ # 1 relative colorimetric
+ # 2 saturation
+ # 3 absolute colorimetric
+
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_info["srgb"] = i8(s)
+ return s
+
+ def chunk_pHYs(self, pos, length):
+
+ # pixels per unit
+ s = ImageFile._safe_read(self.fp, length)
+ px, py = i32(s), i32(s[4:])
+ unit = i8(s[8])
+ if unit == 1: # meter
+ dpi = int(px * 0.0254 + 0.5), int(py * 0.0254 + 0.5)
+ self.im_info["dpi"] = dpi
+ elif unit == 0:
+ self.im_info["aspect"] = px, py
+ return s
+
+ def chunk_tEXt(self, pos, length):
+
+ # text
+ s = ImageFile._safe_read(self.fp, length)
+ try:
+ k, v = s.split(b"\0", 1)
+ except ValueError:
+ # fallback for broken tEXt tags
+ k = s
+ v = b""
+ if k:
+ if py3:
+ k = k.decode("latin-1", "strict")
+ v = v.decode("latin-1", "replace")
+
+ self.im_info[k] = self.im_text[k] = v
+ self.check_text_memory(len(v))
+
+ return s
+
+ def chunk_zTXt(self, pos, length):
+
+ # compressed text
+ s = ImageFile._safe_read(self.fp, length)
+ try:
+ k, v = s.split(b"\0", 1)
+ except ValueError:
+ k = s
+ v = b""
+ if v:
+ comp_method = i8(v[0])
+ else:
+ comp_method = 0
+ if comp_method != 0:
+ raise SyntaxError(
+ "Unknown compression method %s in zTXt chunk" % comp_method
+ )
+ try:
+ v = _safe_zlib_decompress(v[1:])
+ except ValueError:
+ if ImageFile.LOAD_TRUNCATED_IMAGES:
+ v = b""
+ else:
+ raise
+ except zlib.error:
+ v = b""
+
+ if k:
+ if py3:
+ k = k.decode("latin-1", "strict")
+ v = v.decode("latin-1", "replace")
+
+ self.im_info[k] = self.im_text[k] = v
+ self.check_text_memory(len(v))
+
+ return s
+
+ def chunk_iTXt(self, pos, length):
+
+ # international text
+ r = s = ImageFile._safe_read(self.fp, length)
+ try:
+ k, r = r.split(b"\0", 1)
+ except ValueError:
+ return s
+ if len(r) < 2:
+ return s
+ cf, cm, r = i8(r[0]), i8(r[1]), r[2:]
+ try:
+ lang, tk, v = r.split(b"\0", 2)
+ except ValueError:
+ return s
+ if cf != 0:
+ if cm == 0:
+ try:
+ v = _safe_zlib_decompress(v)
+ except ValueError:
+ if ImageFile.LOAD_TRUNCATED_IMAGES:
+ return s
+ else:
+ raise
+ except zlib.error:
+ return s
+ else:
+ return s
+ if py3:
+ try:
+ k = k.decode("latin-1", "strict")
+ lang = lang.decode("utf-8", "strict")
+ tk = tk.decode("utf-8", "strict")
+ v = v.decode("utf-8", "strict")
+ except UnicodeError:
+ return s
+
+ self.im_info[k] = self.im_text[k] = iTXt(v, lang, tk)
+ self.check_text_memory(len(v))
+
+ return s
+
+ def chunk_eXIf(self, pos, length):
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_info["exif"] = b"Exif\x00\x00" + s
+ return s
+
+ # APNG chunks
+ def chunk_acTL(self, pos, length):
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_custom_mimetype = "image/apng"
+ return s
+
+
+# --------------------------------------------------------------------
+# PNG reader
+
+
+def _accept(prefix):
+ return prefix[:8] == _MAGIC
+
+
+##
+# Image plugin for PNG images.
+
+
+class PngImageFile(ImageFile.ImageFile):
+
+ format = "PNG"
+ format_description = "Portable network graphics"
+
+ def _open(self):
+
+ if self.fp.read(8) != _MAGIC:
+ raise SyntaxError("not a PNG file")
+
+ #
+ # Parse headers up to the first IDAT chunk
+
+ self.png = PngStream(self.fp)
+
+ while True:
+
+ #
+ # get next chunk
+
+ cid, pos, length = self.png.read()
+
+ try:
+ s = self.png.call(cid, pos, length)
+ except EOFError:
+ break
+ except AttributeError:
+ logger.debug("%r %s %s (unknown)", cid, pos, length)
+ s = ImageFile._safe_read(self.fp, length)
+
+ self.png.crc(cid, s)
+
+ #
+ # Copy relevant attributes from the PngStream. An alternative
+ # would be to let the PngStream class modify these attributes
+ # directly, but that introduces circular references which are
+ # difficult to break if things go wrong in the decoder...
+ # (believe me, I've tried ;-)
+
+ self.mode = self.png.im_mode
+ self._size = self.png.im_size
+ self.info = self.png.im_info
+ self._text = None
+ self.tile = self.png.im_tile
+ self.custom_mimetype = self.png.im_custom_mimetype
+
+ if self.png.im_palette:
+ rawmode, data = self.png.im_palette
+ self.palette = ImagePalette.raw(rawmode, data)
+
+ self.__prepare_idat = length # used by load_prepare()
+
+ @property
+ def text(self):
+ # experimental
+ if self._text is None:
+ # iTxt, tEXt and zTXt chunks may appear at the end of the file
+ # So load the file to ensure that they are read
+ self.load()
+ return self._text
+
+ def verify(self):
+ """Verify PNG file"""
+
+ if self.fp is None:
+ raise RuntimeError("verify must be called directly after open")
+
+ # back up to beginning of IDAT block
+ self.fp.seek(self.tile[0][2] - 8)
+
+ self.png.verify()
+ self.png.close()
+
+ if self._exclusive_fp:
+ self.fp.close()
+ self.fp = None
+
+ def load_prepare(self):
+ """internal: prepare to read PNG file"""
+
+ if self.info.get("interlace"):
+ self.decoderconfig = self.decoderconfig + (1,)
+
+ self.__idat = self.__prepare_idat # used by load_read()
+ ImageFile.ImageFile.load_prepare(self)
+
+ def load_read(self, read_bytes):
+ """internal: read more image data"""
+
+ while self.__idat == 0:
+ # end of chunk, skip forward to next one
+
+ self.fp.read(4) # CRC
+
+ cid, pos, length = self.png.read()
+
+ if cid not in [b"IDAT", b"DDAT"]:
+ self.png.push(cid, pos, length)
+ return b""
+
+ self.__idat = length # empty chunks are allowed
+
+ # read more data from this chunk
+ if read_bytes <= 0:
+ read_bytes = self.__idat
+ else:
+ read_bytes = min(read_bytes, self.__idat)
+
+ self.__idat = self.__idat - read_bytes
+
+ return self.fp.read(read_bytes)
+
+ def load_end(self):
+ """internal: finished reading image data"""
+ while True:
+ self.fp.read(4) # CRC
+
+ try:
+ cid, pos, length = self.png.read()
+ except (struct.error, SyntaxError):
+ break
+
+ if cid == b"IEND":
+ break
+
+ try:
+ self.png.call(cid, pos, length)
+ except UnicodeDecodeError:
+ break
+ except EOFError:
+ ImageFile._safe_read(self.fp, length)
+ except AttributeError:
+ logger.debug("%r %s %s (unknown)", cid, pos, length)
+ ImageFile._safe_read(self.fp, length)
+ self._text = self.png.im_text
+ self.png.close()
+ self.png = None
+
+ def _getexif(self):
+ if "exif" not in self.info:
+ self.load()
+ if "exif" not in self.info:
+ return None
+ return dict(self.getexif())
+
+ def getexif(self):
+ if "exif" not in self.info:
+ self.load()
+ return ImageFile.ImageFile.getexif(self)
+
+
+# --------------------------------------------------------------------
+# PNG writer
+
+_OUTMODES = {
+ # supported PIL modes, and corresponding rawmodes/bits/color combinations
+ "1": ("1", b"\x01\x00"),
+ "L;1": ("L;1", b"\x01\x00"),
+ "L;2": ("L;2", b"\x02\x00"),
+ "L;4": ("L;4", b"\x04\x00"),
+ "L": ("L", b"\x08\x00"),
+ "LA": ("LA", b"\x08\x04"),
+ "I": ("I;16B", b"\x10\x00"),
+ "I;16": ("I;16B", b"\x10\x00"),
+ "P;1": ("P;1", b"\x01\x03"),
+ "P;2": ("P;2", b"\x02\x03"),
+ "P;4": ("P;4", b"\x04\x03"),
+ "P": ("P", b"\x08\x03"),
+ "RGB": ("RGB", b"\x08\x02"),
+ "RGBA": ("RGBA", b"\x08\x06"),
+}
+
+
+def putchunk(fp, cid, *data):
+ """Write a PNG chunk (including CRC field)"""
+
+ data = b"".join(data)
+
+ fp.write(o32(len(data)) + cid)
+ fp.write(data)
+ crc = _crc32(data, _crc32(cid))
+ fp.write(o32(crc))
+
+
+class _idat(object):
+ # wrap output from the encoder in IDAT chunks
+
+ def __init__(self, fp, chunk):
+ self.fp = fp
+ self.chunk = chunk
+
+ def write(self, data):
+ self.chunk(self.fp, b"IDAT", data)
+
+
+def _save(im, fp, filename, chunk=putchunk):
+ # save an image to disk (called by the save method)
+
+ mode = im.mode
+
+ if mode == "P":
+
+ #
+ # attempt to minimize storage requirements for palette images
+ if "bits" in im.encoderinfo:
+ # number of bits specified by user
+ colors = 1 << im.encoderinfo["bits"]
+ else:
+ # check palette contents
+ if im.palette:
+ colors = max(min(len(im.palette.getdata()[1]) // 3, 256), 2)
+ else:
+ colors = 256
+
+ if colors <= 2:
+ bits = 1
+ elif colors <= 4:
+ bits = 2
+ elif colors <= 16:
+ bits = 4
+ else:
+ bits = 8
+ if bits != 8:
+ mode = "%s;%d" % (mode, bits)
+
+ # encoder options
+ im.encoderconfig = (
+ im.encoderinfo.get("optimize", False),
+ im.encoderinfo.get("compress_level", -1),
+ im.encoderinfo.get("compress_type", -1),
+ im.encoderinfo.get("dictionary", b""),
+ )
+
+ # get the corresponding PNG mode
+ try:
+ rawmode, mode = _OUTMODES[mode]
+ except KeyError:
+ raise IOError("cannot write mode %s as PNG" % mode)
+
+ #
+ # write minimal PNG file
+
+ fp.write(_MAGIC)
+
+ chunk(
+ fp,
+ b"IHDR",
+ o32(im.size[0]), # 0: size
+ o32(im.size[1]),
+ mode, # 8: depth/type
+ b"\0", # 10: compression
+ b"\0", # 11: filter category
+ b"\0", # 12: interlace flag
+ )
+
+ chunks = [b"cHRM", b"gAMA", b"sBIT", b"sRGB", b"tIME"]
+
+ icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile"))
+ if icc:
+ # ICC profile
+ # according to PNG spec, the iCCP chunk contains:
+ # Profile name 1-79 bytes (character string)
+ # Null separator 1 byte (null character)
+ # Compression method 1 byte (0)
+ # Compressed profile n bytes (zlib with deflate compression)
+ name = b"ICC Profile"
+ data = name + b"\0\0" + zlib.compress(icc)
+ chunk(fp, b"iCCP", data)
+
+ # You must either have sRGB or iCCP.
+ # Disallow sRGB chunks when an iCCP-chunk has been emitted.
+ chunks.remove(b"sRGB")
+
+ info = im.encoderinfo.get("pnginfo")
+ if info:
+ chunks_multiple_allowed = [b"sPLT", b"iTXt", b"tEXt", b"zTXt"]
+ for cid, data in info.chunks:
+ if cid in chunks:
+ chunks.remove(cid)
+ chunk(fp, cid, data)
+ elif cid in chunks_multiple_allowed:
+ chunk(fp, cid, data)
+
+ if im.mode == "P":
+ palette_byte_number = (2 ** bits) * 3
+ palette_bytes = im.im.getpalette("RGB")[:palette_byte_number]
+ while len(palette_bytes) < palette_byte_number:
+ palette_bytes += b"\0"
+ chunk(fp, b"PLTE", palette_bytes)
+
+ transparency = im.encoderinfo.get("transparency", im.info.get("transparency", None))
+
+ if transparency or transparency == 0:
+ if im.mode == "P":
+ # limit to actual palette size
+ alpha_bytes = 2 ** bits
+ if isinstance(transparency, bytes):
+ chunk(fp, b"tRNS", transparency[:alpha_bytes])
+ else:
+ transparency = max(0, min(255, transparency))
+ alpha = b"\xFF" * transparency + b"\0"
+ chunk(fp, b"tRNS", alpha[:alpha_bytes])
+ elif im.mode in ("1", "L", "I"):
+ transparency = max(0, min(65535, transparency))
+ chunk(fp, b"tRNS", o16(transparency))
+ elif im.mode == "RGB":
+ red, green, blue = transparency
+ chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
+ else:
+ if "transparency" in im.encoderinfo:
+ # don't bother with transparency if it's an RGBA
+ # and it's in the info dict. It's probably just stale.
+ raise IOError("cannot use transparency for this mode")
+ else:
+ if im.mode == "P" and im.im.getpalettemode() == "RGBA":
+ alpha = im.im.getpalette("RGBA", "A")
+ alpha_bytes = 2 ** bits
+ chunk(fp, b"tRNS", alpha[:alpha_bytes])
+
+ dpi = im.encoderinfo.get("dpi")
+ if dpi:
+ chunk(
+ fp,
+ b"pHYs",
+ o32(int(dpi[0] / 0.0254 + 0.5)),
+ o32(int(dpi[1] / 0.0254 + 0.5)),
+ b"\x01",
+ )
+
+ info = im.encoderinfo.get("pnginfo")
+ if info:
+ chunks = [b"bKGD", b"hIST"]
+ for cid, data in info.chunks:
+ if cid in chunks:
+ chunks.remove(cid)
+ chunk(fp, cid, data)
+
+ exif = im.encoderinfo.get("exif", im.info.get("exif"))
+ if exif:
+ if isinstance(exif, Image.Exif):
+ exif = exif.tobytes(8)
+ if exif.startswith(b"Exif\x00\x00"):
+ exif = exif[6:]
+ chunk(fp, b"eXIf", exif)
+
+ ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
+
+ chunk(fp, b"IEND", b"")
+
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+
+# --------------------------------------------------------------------
+# PNG chunk converter
+
+
+def getchunks(im, **params):
+ """Return a list of PNG chunks representing this image."""
+
+ class collector(object):
+ data = []
+
+ def write(self, data):
+ pass
+
+ def append(self, chunk):
+ self.data.append(chunk)
+
+ def append(fp, cid, *data):
+ data = b"".join(data)
+ crc = o32(_crc32(data, _crc32(cid)))
+ fp.append((cid, data, crc))
+
+ fp = collector()
+
+ try:
+ im.encoderinfo = params
+ _save(im, fp, None, append)
+ finally:
+ del im.encoderinfo
+
+ return fp.data
+
+
+# --------------------------------------------------------------------
+# Registry
+
+Image.register_open(PngImageFile.format, PngImageFile, _accept)
+Image.register_save(PngImageFile.format, _save)
+
+Image.register_extensions(PngImageFile.format, [".png", ".apng"])
+
+Image.register_mime(PngImageFile.format, "image/png")
diff --git a/contrib/python/Pillow/py2/PIL/PpmImagePlugin.py b/contrib/python/Pillow/py2/PIL/PpmImagePlugin.py
new file mode 100644
index 0000000000..c3e9eed6da
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PpmImagePlugin.py
@@ -0,0 +1,168 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PPM support for PIL
+#
+# History:
+# 96-03-24 fl Created
+# 98-03-06 fl Write RGBA images (as RGB, that is)
+#
+# Copyright (c) Secret Labs AB 1997-98.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.2"
+
+#
+# --------------------------------------------------------------------
+
+b_whitespace = b"\x20\x09\x0a\x0b\x0c\x0d"
+
+MODES = {
+ # standard
+ b"P4": "1",
+ b"P5": "L",
+ b"P6": "RGB",
+ # extensions
+ b"P0CMYK": "CMYK",
+ # PIL extensions (for test purposes only)
+ b"PyP": "P",
+ b"PyRGBA": "RGBA",
+ b"PyCMYK": "CMYK",
+}
+
+
+def _accept(prefix):
+ return prefix[0:1] == b"P" and prefix[1] in b"0456y"
+
+
+##
+# Image plugin for PBM, PGM, and PPM images.
+
+
+class PpmImageFile(ImageFile.ImageFile):
+
+ format = "PPM"
+ format_description = "Pbmplus image"
+
+ def _token(self, s=b""):
+ while True: # read until next whitespace
+ c = self.fp.read(1)
+ if not c or c in b_whitespace:
+ break
+ if c > b"\x79":
+ raise ValueError("Expected ASCII value, found binary")
+ s = s + c
+ if len(s) > 9:
+ raise ValueError("Expected int, got > 9 digits")
+ return s
+
+ def _open(self):
+
+ # check magic
+ s = self.fp.read(1)
+ if s != b"P":
+ raise SyntaxError("not a PPM file")
+ magic_number = self._token(s)
+ mode = MODES[magic_number]
+
+ self.custom_mimetype = {
+ b"P4": "image/x-portable-bitmap",
+ b"P5": "image/x-portable-graymap",
+ b"P6": "image/x-portable-pixmap",
+ }.get(magic_number)
+
+ if mode == "1":
+ self.mode = "1"
+ rawmode = "1;I"
+ else:
+ self.mode = rawmode = mode
+
+ for ix in range(3):
+ while True:
+ while True:
+ s = self.fp.read(1)
+ if s not in b_whitespace:
+ break
+ if s == b"":
+ raise ValueError("File does not extend beyond magic number")
+ if s != b"#":
+ break
+ s = self.fp.readline()
+ s = int(self._token(s))
+ if ix == 0:
+ xsize = s
+ elif ix == 1:
+ ysize = s
+ if mode == "1":
+ break
+ elif ix == 2:
+ # maxgrey
+ if s > 255:
+ if not mode == "L":
+ raise ValueError("Too many colors for band: %s" % s)
+ if s < 2 ** 16:
+ self.mode = "I"
+ rawmode = "I;16B"
+ else:
+ self.mode = "I"
+ rawmode = "I;32B"
+
+ self._size = xsize, ysize
+ self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(), (rawmode, 0, 1))]
+
+
+#
+# --------------------------------------------------------------------
+
+
+def _save(im, fp, filename):
+ if im.mode == "1":
+ rawmode, head = "1;I", b"P4"
+ elif im.mode == "L":
+ rawmode, head = "L", b"P5"
+ elif im.mode == "I":
+ if im.getextrema()[1] < 2 ** 16:
+ rawmode, head = "I;16B", b"P5"
+ else:
+ rawmode, head = "I;32B", b"P5"
+ elif im.mode == "RGB":
+ rawmode, head = "RGB", b"P6"
+ elif im.mode == "RGBA":
+ rawmode, head = "RGB", b"P6"
+ else:
+ raise IOError("cannot write mode %s as PPM" % im.mode)
+ fp.write(head + ("\n%d %d\n" % im.size).encode("ascii"))
+ if head == b"P6":
+ fp.write(b"255\n")
+ if head == b"P5":
+ if rawmode == "L":
+ fp.write(b"255\n")
+ elif rawmode == "I;16B":
+ fp.write(b"65535\n")
+ elif rawmode == "I;32B":
+ fp.write(b"2147483648\n")
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
+
+ # ALTERNATIVE: save via builtin debug function
+ # im._dump(filename)
+
+
+#
+# --------------------------------------------------------------------
+
+
+Image.register_open(PpmImageFile.format, PpmImageFile, _accept)
+Image.register_save(PpmImageFile.format, _save)
+
+Image.register_extensions(PpmImageFile.format, [".pbm", ".pgm", ".ppm", ".pnm"])
+
+Image.register_mime(PpmImageFile.format, "image/x-portable-anymap")
diff --git a/contrib/python/Pillow/py2/PIL/PsdImagePlugin.py b/contrib/python/Pillow/py2/PIL/PsdImagePlugin.py
new file mode 100644
index 0000000000..f72ad5f443
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PsdImagePlugin.py
@@ -0,0 +1,319 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# Adobe PSD 2.5/3.0 file handling
+#
+# History:
+# 1995-09-01 fl Created
+# 1997-01-03 fl Read most PSD images
+# 1997-01-18 fl Fixed P and CMYK support
+# 2001-10-21 fl Added seek/tell support (for layers)
+#
+# Copyright (c) 1997-2001 by Secret Labs AB.
+# Copyright (c) 1995-2001 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.4"
+
+import io
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8, i16be as i16, i32be as i32
+
+MODES = {
+ # (photoshop mode, bits) -> (pil mode, required channels)
+ (0, 1): ("1", 1),
+ (0, 8): ("L", 1),
+ (1, 8): ("L", 1),
+ (2, 8): ("P", 1),
+ (3, 8): ("RGB", 3),
+ (4, 8): ("CMYK", 4),
+ (7, 8): ("L", 1), # FIXME: multilayer
+ (8, 8): ("L", 1), # duotone
+ (9, 8): ("LAB", 3),
+}
+
+
+# --------------------------------------------------------------------.
+# read PSD images
+
+
+def _accept(prefix):
+ return prefix[:4] == b"8BPS"
+
+
+##
+# Image plugin for Photoshop images.
+
+
+class PsdImageFile(ImageFile.ImageFile):
+
+ format = "PSD"
+ format_description = "Adobe Photoshop"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+
+ read = self.fp.read
+
+ #
+ # header
+
+ s = read(26)
+ if s[:4] != b"8BPS" or i16(s[4:]) != 1:
+ raise SyntaxError("not a PSD file")
+
+ psd_bits = i16(s[22:])
+ psd_channels = i16(s[12:])
+ psd_mode = i16(s[24:])
+
+ mode, channels = MODES[(psd_mode, psd_bits)]
+
+ if channels > psd_channels:
+ raise IOError("not enough channels")
+
+ self.mode = mode
+ self._size = i32(s[18:]), i32(s[14:])
+
+ #
+ # color mode data
+
+ size = i32(read(4))
+ if size:
+ data = read(size)
+ if mode == "P" and size == 768:
+ self.palette = ImagePalette.raw("RGB;L", data)
+
+ #
+ # image resources
+
+ self.resources = []
+
+ size = i32(read(4))
+ if size:
+ # load resources
+ end = self.fp.tell() + size
+ while self.fp.tell() < end:
+ read(4) # signature
+ id = i16(read(2))
+ name = read(i8(read(1)))
+ if not (len(name) & 1):
+ read(1) # padding
+ data = read(i32(read(4)))
+ if len(data) & 1:
+ read(1) # padding
+ self.resources.append((id, name, data))
+ if id == 1039: # ICC profile
+ self.info["icc_profile"] = data
+
+ #
+ # layer and mask information
+
+ self.layers = []
+
+ size = i32(read(4))
+ if size:
+ end = self.fp.tell() + size
+ size = i32(read(4))
+ if size:
+ self.layers = _layerinfo(self.fp)
+ self.fp.seek(end)
+
+ #
+ # image descriptor
+
+ self.tile = _maketile(self.fp, mode, (0, 0) + self.size, channels)
+
+ # keep the file open
+ self.__fp = self.fp
+ self.frame = 1
+ self._min_frame = 1
+
+ @property
+ def n_frames(self):
+ return len(self.layers)
+
+ @property
+ def is_animated(self):
+ return len(self.layers) > 1
+
+ def seek(self, layer):
+ if not self._seek_check(layer):
+ return
+
+ # seek to given layer (1..max)
+ try:
+ name, mode, bbox, tile = self.layers[layer - 1]
+ self.mode = mode
+ self.tile = tile
+ self.frame = layer
+ self.fp = self.__fp
+ return name, bbox
+ except IndexError:
+ raise EOFError("no such layer")
+
+ def tell(self):
+ # return layer number (0=image, 1..max=layers)
+ return self.frame
+
+ def load_prepare(self):
+ # create image memory if necessary
+ if not self.im or self.im.mode != self.mode or self.im.size != self.size:
+ self.im = Image.core.fill(self.mode, self.size, 0)
+ # create palette (optional)
+ if self.mode == "P":
+ Image.Image.load(self)
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+def _layerinfo(file):
+ # read layerinfo block
+ layers = []
+ read = file.read
+ for i in range(abs(i16(read(2)))):
+
+ # bounding box
+ y0 = i32(read(4))
+ x0 = i32(read(4))
+ y1 = i32(read(4))
+ x1 = i32(read(4))
+
+ # image info
+ info = []
+ mode = []
+ types = list(range(i16(read(2))))
+ if len(types) > 4:
+ continue
+
+ for i in types:
+ type = i16(read(2))
+
+ if type == 65535:
+ m = "A"
+ else:
+ m = "RGBA"[type]
+
+ mode.append(m)
+ size = i32(read(4))
+ info.append((m, size))
+
+ # figure out the image mode
+ mode.sort()
+ if mode == ["R"]:
+ mode = "L"
+ elif mode == ["B", "G", "R"]:
+ mode = "RGB"
+ elif mode == ["A", "B", "G", "R"]:
+ mode = "RGBA"
+ else:
+ mode = None # unknown
+
+ # skip over blend flags and extra information
+ read(12) # filler
+ name = ""
+ size = i32(read(4)) # length of the extra data field
+ combined = 0
+ if size:
+ data_end = file.tell() + size
+
+ length = i32(read(4))
+ if length:
+ file.seek(length - 16, io.SEEK_CUR)
+ combined += length + 4
+
+ length = i32(read(4))
+ if length:
+ file.seek(length, io.SEEK_CUR)
+ combined += length + 4
+
+ length = i8(read(1))
+ if length:
+ # Don't know the proper encoding,
+ # Latin-1 should be a good guess
+ name = read(length).decode("latin-1", "replace")
+ combined += length + 1
+
+ file.seek(data_end)
+ layers.append((name, mode, (x0, y0, x1, y1)))
+
+ # get tiles
+ i = 0
+ for name, mode, bbox in layers:
+ tile = []
+ for m in mode:
+ t = _maketile(file, m, bbox, 1)
+ if t:
+ tile.extend(t)
+ layers[i] = name, mode, bbox, tile
+ i += 1
+
+ return layers
+
+
+def _maketile(file, mode, bbox, channels):
+
+ tile = None
+ read = file.read
+
+ compression = i16(read(2))
+
+ xsize = bbox[2] - bbox[0]
+ ysize = bbox[3] - bbox[1]
+
+ offset = file.tell()
+
+ if compression == 0:
+ #
+ # raw compression
+ tile = []
+ for channel in range(channels):
+ layer = mode[channel]
+ if mode == "CMYK":
+ layer += ";I"
+ tile.append(("raw", bbox, offset, layer))
+ offset = offset + xsize * ysize
+
+ elif compression == 1:
+ #
+ # packbits compression
+ i = 0
+ tile = []
+ bytecount = read(channels * ysize * 2)
+ offset = file.tell()
+ for channel in range(channels):
+ layer = mode[channel]
+ if mode == "CMYK":
+ layer += ";I"
+ tile.append(("packbits", bbox, offset, layer))
+ for y in range(ysize):
+ offset = offset + i16(bytecount[i : i + 2])
+ i += 2
+
+ file.seek(offset)
+
+ if offset & 1:
+ read(1) # padding
+
+ return tile
+
+
+# --------------------------------------------------------------------
+# registry
+
+
+Image.register_open(PsdImageFile.format, PsdImageFile, _accept)
+
+Image.register_extension(PsdImageFile.format, ".psd")
diff --git a/contrib/python/Pillow/py2/PIL/PyAccess.py b/contrib/python/Pillow/py2/PIL/PyAccess.py
new file mode 100644
index 0000000000..2ab06f93ff
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/PyAccess.py
@@ -0,0 +1,346 @@
+#
+# The Python Imaging Library
+# Pillow fork
+#
+# Python implementation of the PixelAccess Object
+#
+# Copyright (c) 1997-2009 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1995-2009 by Fredrik Lundh.
+# Copyright (c) 2013 Eric Soroos
+#
+# See the README file for information on usage and redistribution
+#
+
+# Notes:
+#
+# * Implements the pixel access object following Access.
+# * Does not implement the line functions, as they don't appear to be used
+# * Taking only the tuple form, which is used from python.
+# * Fill.c uses the integer form, but it's still going to use the old
+# Access.c implementation.
+#
+
+import logging
+import sys
+
+from cffi import FFI
+
+logger = logging.getLogger(__name__)
+
+
+defs = """
+struct Pixel_RGBA {
+ unsigned char r,g,b,a;
+};
+struct Pixel_I16 {
+ unsigned char l,r;
+};
+"""
+ffi = FFI()
+ffi.cdef(defs)
+
+
+class PyAccess(object):
+ def __init__(self, img, readonly=False):
+ vals = dict(img.im.unsafe_ptrs)
+ self.readonly = readonly
+ self.image8 = ffi.cast("unsigned char **", vals["image8"])
+ self.image32 = ffi.cast("int **", vals["image32"])
+ self.image = ffi.cast("unsigned char **", vals["image"])
+ self.xsize, self.ysize = img.im.size
+
+ # Keep pointer to im object to prevent dereferencing.
+ self._im = img.im
+ if self._im.mode == "P":
+ self._palette = img.palette
+
+ # Debugging is polluting test traces, only useful here
+ # when hacking on PyAccess
+ # logger.debug("%s", vals)
+ self._post_init()
+
+ def _post_init(self):
+ pass
+
+ def __setitem__(self, xy, color):
+ """
+ Modifies the pixel at x,y. The color is given as a single
+ numerical value for single band images, and a tuple for
+ multi-band images
+
+ :param xy: The pixel coordinate, given as (x, y). See
+ :ref:`coordinate-system`.
+ :param color: The pixel value.
+ """
+ if self.readonly:
+ raise ValueError("Attempt to putpixel a read only image")
+ (x, y) = xy
+ if x < 0:
+ x = self.xsize + x
+ if y < 0:
+ y = self.ysize + y
+ (x, y) = self.check_xy((x, y))
+
+ if (
+ self._im.mode == "P"
+ and isinstance(color, (list, tuple))
+ and len(color) in [3, 4]
+ ):
+ # RGB or RGBA value for a P image
+ color = self._palette.getcolor(color)
+
+ return self.set_pixel(x, y, color)
+
+ def __getitem__(self, xy):
+ """
+ Returns the pixel at x,y. The pixel is returned as a single
+ value for single band images or a tuple for multiple band
+ images
+
+ :param xy: The pixel coordinate, given as (x, y). See
+ :ref:`coordinate-system`.
+ :returns: a pixel value for single band images, a tuple of
+ pixel values for multiband images.
+ """
+ (x, y) = xy
+ if x < 0:
+ x = self.xsize + x
+ if y < 0:
+ y = self.ysize + y
+ (x, y) = self.check_xy((x, y))
+ return self.get_pixel(x, y)
+
+ putpixel = __setitem__
+ getpixel = __getitem__
+
+ def check_xy(self, xy):
+ (x, y) = xy
+ if not (0 <= x < self.xsize and 0 <= y < self.ysize):
+ raise ValueError("pixel location out of range")
+ return xy
+
+
+class _PyAccess32_2(PyAccess):
+ """ PA, LA, stored in first and last bytes of a 32 bit word """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return (pixel.r, pixel.a)
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ # tuple
+ pixel.r = min(color[0], 255)
+ pixel.a = min(color[1], 255)
+
+
+class _PyAccess32_3(PyAccess):
+ """ RGB and friends, stored in the first three bytes of a 32 bit word """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return (pixel.r, pixel.g, pixel.b)
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ # tuple
+ pixel.r = min(color[0], 255)
+ pixel.g = min(color[1], 255)
+ pixel.b = min(color[2], 255)
+ pixel.a = 255
+
+
+class _PyAccess32_4(PyAccess):
+ """ RGBA etc, all 4 bytes of a 32 bit word """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return (pixel.r, pixel.g, pixel.b, pixel.a)
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ # tuple
+ pixel.r = min(color[0], 255)
+ pixel.g = min(color[1], 255)
+ pixel.b = min(color[2], 255)
+ pixel.a = min(color[3], 255)
+
+
+class _PyAccess8(PyAccess):
+ """ 1, L, P, 8 bit images stored as uint8 """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = self.image8
+
+ def get_pixel(self, x, y):
+ return self.pixels[y][x]
+
+ def set_pixel(self, x, y, color):
+ try:
+ # integer
+ self.pixels[y][x] = min(color, 255)
+ except TypeError:
+ # tuple
+ self.pixels[y][x] = min(color[0], 255)
+
+
+class _PyAccessI16_N(PyAccess):
+ """ I;16 access, native bitendian without conversion """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("unsigned short **", self.image)
+
+ def get_pixel(self, x, y):
+ return self.pixels[y][x]
+
+ def set_pixel(self, x, y, color):
+ try:
+ # integer
+ self.pixels[y][x] = min(color, 65535)
+ except TypeError:
+ # tuple
+ self.pixels[y][x] = min(color[0], 65535)
+
+
+class _PyAccessI16_L(PyAccess):
+ """ I;16L access, with conversion """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_I16 **", self.image)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return pixel.l + pixel.r * 256
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ try:
+ color = min(color, 65535)
+ except TypeError:
+ color = min(color[0], 65535)
+
+ pixel.l = color & 0xFF # noqa: E741
+ pixel.r = color >> 8
+
+
+class _PyAccessI16_B(PyAccess):
+ """ I;16B access, with conversion """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_I16 **", self.image)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return pixel.l * 256 + pixel.r
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ try:
+ color = min(color, 65535)
+ except Exception:
+ color = min(color[0], 65535)
+
+ pixel.l = color >> 8 # noqa: E741
+ pixel.r = color & 0xFF
+
+
+class _PyAccessI32_N(PyAccess):
+ """ Signed Int32 access, native endian """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = self.image32
+
+ def get_pixel(self, x, y):
+ return self.pixels[y][x]
+
+ def set_pixel(self, x, y, color):
+ self.pixels[y][x] = color
+
+
+class _PyAccessI32_Swap(PyAccess):
+ """ I;32L/B access, with byteswapping conversion """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = self.image32
+
+ def reverse(self, i):
+ orig = ffi.new("int *", i)
+ chars = ffi.cast("unsigned char *", orig)
+ chars[0], chars[1], chars[2], chars[3] = chars[3], chars[2], chars[1], chars[0]
+ return ffi.cast("int *", chars)[0]
+
+ def get_pixel(self, x, y):
+ return self.reverse(self.pixels[y][x])
+
+ def set_pixel(self, x, y, color):
+ self.pixels[y][x] = self.reverse(color)
+
+
+class _PyAccessF(PyAccess):
+ """ 32 bit float access """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("float **", self.image32)
+
+ def get_pixel(self, x, y):
+ return self.pixels[y][x]
+
+ def set_pixel(self, x, y, color):
+ try:
+ # not a tuple
+ self.pixels[y][x] = color
+ except TypeError:
+ # tuple
+ self.pixels[y][x] = color[0]
+
+
+mode_map = {
+ "1": _PyAccess8,
+ "L": _PyAccess8,
+ "P": _PyAccess8,
+ "LA": _PyAccess32_2,
+ "La": _PyAccess32_2,
+ "PA": _PyAccess32_2,
+ "RGB": _PyAccess32_3,
+ "LAB": _PyAccess32_3,
+ "HSV": _PyAccess32_3,
+ "YCbCr": _PyAccess32_3,
+ "RGBA": _PyAccess32_4,
+ "RGBa": _PyAccess32_4,
+ "RGBX": _PyAccess32_4,
+ "CMYK": _PyAccess32_4,
+ "F": _PyAccessF,
+ "I": _PyAccessI32_N,
+}
+
+if sys.byteorder == "little":
+ mode_map["I;16"] = _PyAccessI16_N
+ mode_map["I;16L"] = _PyAccessI16_N
+ mode_map["I;16B"] = _PyAccessI16_B
+
+ mode_map["I;32L"] = _PyAccessI32_N
+ mode_map["I;32B"] = _PyAccessI32_Swap
+else:
+ mode_map["I;16"] = _PyAccessI16_L
+ mode_map["I;16L"] = _PyAccessI16_L
+ mode_map["I;16B"] = _PyAccessI16_N
+
+ mode_map["I;32L"] = _PyAccessI32_Swap
+ mode_map["I;32B"] = _PyAccessI32_N
+
+
+def new(img, readonly=False):
+ access_type = mode_map.get(img.mode, None)
+ if not access_type:
+ logger.debug("PyAccess Not Implemented: %s", img.mode)
+ return None
+ return access_type(img, readonly)
diff --git a/contrib/python/Pillow/py2/PIL/SgiImagePlugin.py b/contrib/python/Pillow/py2/PIL/SgiImagePlugin.py
new file mode 100644
index 0000000000..99408fdc34
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/SgiImagePlugin.py
@@ -0,0 +1,235 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# SGI image file handling
+#
+# See "The SGI Image File Format (Draft version 0.97)", Paul Haeberli.
+# <ftp://ftp.sgi.com/graphics/SGIIMAGESPEC>
+#
+#
+# History:
+# 2017-22-07 mb Add RLE decompression
+# 2016-16-10 mb Add save method without compression
+# 1995-09-10 fl Created
+#
+# Copyright (c) 2016 by Mickael Bonfill.
+# Copyright (c) 2008 by Karsten Hiddemann.
+# Copyright (c) 1997 by Secret Labs AB.
+# Copyright (c) 1995 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import os
+import struct
+
+from . import Image, ImageFile
+from ._binary import i8, i16be as i16, o8
+from ._util import py3
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.3"
+
+
+def _accept(prefix):
+ return len(prefix) >= 2 and i16(prefix) == 474
+
+
+MODES = {
+ (1, 1, 1): "L",
+ (1, 2, 1): "L",
+ (2, 1, 1): "L;16B",
+ (2, 2, 1): "L;16B",
+ (1, 3, 3): "RGB",
+ (2, 3, 3): "RGB;16B",
+ (1, 3, 4): "RGBA",
+ (2, 3, 4): "RGBA;16B",
+}
+
+
+##
+# Image plugin for SGI images.
+class SgiImageFile(ImageFile.ImageFile):
+
+ format = "SGI"
+ format_description = "SGI Image File Format"
+
+ def _open(self):
+
+ # HEAD
+ headlen = 512
+ s = self.fp.read(headlen)
+
+ # magic number : 474
+ if i16(s) != 474:
+ raise ValueError("Not an SGI image file")
+
+ # compression : verbatim or RLE
+ compression = i8(s[2])
+
+ # bpc : 1 or 2 bytes (8bits or 16bits)
+ bpc = i8(s[3])
+
+ # dimension : 1, 2 or 3 (depending on xsize, ysize and zsize)
+ dimension = i16(s[4:])
+
+ # xsize : width
+ xsize = i16(s[6:])
+
+ # ysize : height
+ ysize = i16(s[8:])
+
+ # zsize : channels count
+ zsize = i16(s[10:])
+
+ # layout
+ layout = bpc, dimension, zsize
+
+ # determine mode from bits/zsize
+ rawmode = ""
+ try:
+ rawmode = MODES[layout]
+ except KeyError:
+ pass
+
+ if rawmode == "":
+ raise ValueError("Unsupported SGI image mode")
+
+ self._size = xsize, ysize
+ self.mode = rawmode.split(";")[0]
+ if self.mode == "RGB":
+ self.custom_mimetype = "image/rgb"
+
+ # orientation -1 : scanlines begins at the bottom-left corner
+ orientation = -1
+
+ # decoder info
+ if compression == 0:
+ pagesize = xsize * ysize * bpc
+ if bpc == 2:
+ self.tile = [
+ ("SGI16", (0, 0) + self.size, headlen, (self.mode, 0, orientation))
+ ]
+ else:
+ self.tile = []
+ offset = headlen
+ for layer in self.mode:
+ self.tile.append(
+ ("raw", (0, 0) + self.size, offset, (layer, 0, orientation))
+ )
+ offset += pagesize
+ elif compression == 1:
+ self.tile = [
+ ("sgi_rle", (0, 0) + self.size, headlen, (rawmode, orientation, bpc))
+ ]
+
+
+def _save(im, fp, filename):
+ if im.mode != "RGB" and im.mode != "RGBA" and im.mode != "L":
+ raise ValueError("Unsupported SGI image mode")
+
+ # Get the keyword arguments
+ info = im.encoderinfo
+
+ # Byte-per-pixel precision, 1 = 8bits per pixel
+ bpc = info.get("bpc", 1)
+
+ if bpc not in (1, 2):
+ raise ValueError("Unsupported number of bytes per pixel")
+
+ # Flip the image, since the origin of SGI file is the bottom-left corner
+ orientation = -1
+ # Define the file as SGI File Format
+ magicNumber = 474
+ # Run-Length Encoding Compression - Unsupported at this time
+ rle = 0
+
+ # Number of dimensions (x,y,z)
+ dim = 3
+ # X Dimension = width / Y Dimension = height
+ x, y = im.size
+ if im.mode == "L" and y == 1:
+ dim = 1
+ elif im.mode == "L":
+ dim = 2
+ # Z Dimension: Number of channels
+ z = len(im.mode)
+
+ if dim == 1 or dim == 2:
+ z = 1
+
+ # assert we've got the right number of bands.
+ if len(im.getbands()) != z:
+ raise ValueError(
+ "incorrect number of bands in SGI write: %s vs %s" % (z, len(im.getbands()))
+ )
+
+ # Minimum Byte value
+ pinmin = 0
+ # Maximum Byte value (255 = 8bits per pixel)
+ pinmax = 255
+ # Image name (79 characters max, truncated below in write)
+ imgName = os.path.splitext(os.path.basename(filename))[0]
+ if py3:
+ imgName = imgName.encode("ascii", "ignore")
+ # Standard representation of pixel in the file
+ colormap = 0
+ fp.write(struct.pack(">h", magicNumber))
+ fp.write(o8(rle))
+ fp.write(o8(bpc))
+ fp.write(struct.pack(">H", dim))
+ fp.write(struct.pack(">H", x))
+ fp.write(struct.pack(">H", y))
+ fp.write(struct.pack(">H", z))
+ fp.write(struct.pack(">l", pinmin))
+ fp.write(struct.pack(">l", pinmax))
+ fp.write(struct.pack("4s", b"")) # dummy
+ fp.write(struct.pack("79s", imgName)) # truncates to 79 chars
+ fp.write(struct.pack("s", b"")) # force null byte after imgname
+ fp.write(struct.pack(">l", colormap))
+ fp.write(struct.pack("404s", b"")) # dummy
+
+ rawmode = "L"
+ if bpc == 2:
+ rawmode = "L;16B"
+
+ for channel in im.split():
+ fp.write(channel.tobytes("raw", rawmode, 0, orientation))
+
+ fp.close()
+
+
+class SGI16Decoder(ImageFile.PyDecoder):
+ _pulls_fd = True
+
+ def decode(self, buffer):
+ rawmode, stride, orientation = self.args
+ pagesize = self.state.xsize * self.state.ysize
+ zsize = len(self.mode)
+ self.fd.seek(512)
+
+ for band in range(zsize):
+ channel = Image.new("L", (self.state.xsize, self.state.ysize))
+ channel.frombytes(
+ self.fd.read(2 * pagesize), "raw", "L;16B", stride, orientation
+ )
+ self.im.putband(channel.im, band)
+
+ return -1, 0
+
+
+#
+# registry
+
+
+Image.register_decoder("SGI16", SGI16Decoder)
+Image.register_open(SgiImageFile.format, SgiImageFile, _accept)
+Image.register_save(SgiImageFile.format, _save)
+Image.register_mime(SgiImageFile.format, "image/sgi")
+
+Image.register_extensions(SgiImageFile.format, [".bw", ".rgb", ".rgba", ".sgi"])
+
+# End of file
diff --git a/contrib/python/Pillow/py2/PIL/SpiderImagePlugin.py b/contrib/python/Pillow/py2/PIL/SpiderImagePlugin.py
new file mode 100644
index 0000000000..f1cae4d9f0
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/SpiderImagePlugin.py
@@ -0,0 +1,326 @@
+#
+# The Python Imaging Library.
+#
+# SPIDER image file handling
+#
+# History:
+# 2004-08-02 Created BB
+# 2006-03-02 added save method
+# 2006-03-13 added support for stack images
+#
+# Copyright (c) 2004 by Health Research Inc. (HRI) RENSSELAER, NY 12144.
+# Copyright (c) 2004 by William Baxter.
+# Copyright (c) 2004 by Secret Labs AB.
+# Copyright (c) 2004 by Fredrik Lundh.
+#
+
+##
+# Image plugin for the Spider image format. This format is is used
+# by the SPIDER software, in processing image data from electron
+# microscopy and tomography.
+##
+
+#
+# SpiderImagePlugin.py
+#
+# The Spider image format is used by SPIDER software, in processing
+# image data from electron microscopy and tomography.
+#
+# Spider home page:
+# https://spider.wadsworth.org/spider_doc/spider/docs/spider.html
+#
+# Details about the Spider image format:
+# https://spider.wadsworth.org/spider_doc/spider/docs/image_doc.html
+#
+
+from __future__ import print_function
+
+import os
+import struct
+import sys
+
+from PIL import Image, ImageFile
+
+
+def isInt(f):
+ try:
+ i = int(f)
+ if f - i == 0:
+ return 1
+ else:
+ return 0
+ except (ValueError, OverflowError):
+ return 0
+
+
+iforms = [1, 3, -11, -12, -21, -22]
+
+
+# There is no magic number to identify Spider files, so just check a
+# series of header locations to see if they have reasonable values.
+# Returns no. of bytes in the header, if it is a valid Spider header,
+# otherwise returns 0
+
+
+def isSpiderHeader(t):
+ h = (99,) + t # add 1 value so can use spider header index start=1
+ # header values 1,2,5,12,13,22,23 should be integers
+ for i in [1, 2, 5, 12, 13, 22, 23]:
+ if not isInt(h[i]):
+ return 0
+ # check iform
+ iform = int(h[5])
+ if iform not in iforms:
+ return 0
+ # check other header values
+ labrec = int(h[13]) # no. records in file header
+ labbyt = int(h[22]) # total no. of bytes in header
+ lenbyt = int(h[23]) # record length in bytes
+ if labbyt != (labrec * lenbyt):
+ return 0
+ # looks like a valid header
+ return labbyt
+
+
+def isSpiderImage(filename):
+ with open(filename, "rb") as fp:
+ f = fp.read(92) # read 23 * 4 bytes
+ t = struct.unpack(">23f", f) # try big-endian first
+ hdrlen = isSpiderHeader(t)
+ if hdrlen == 0:
+ t = struct.unpack("<23f", f) # little-endian
+ hdrlen = isSpiderHeader(t)
+ return hdrlen
+
+
+class SpiderImageFile(ImageFile.ImageFile):
+
+ format = "SPIDER"
+ format_description = "Spider 2D image"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+ # check header
+ n = 27 * 4 # read 27 float values
+ f = self.fp.read(n)
+
+ try:
+ self.bigendian = 1
+ t = struct.unpack(">27f", f) # try big-endian first
+ hdrlen = isSpiderHeader(t)
+ if hdrlen == 0:
+ self.bigendian = 0
+ t = struct.unpack("<27f", f) # little-endian
+ hdrlen = isSpiderHeader(t)
+ if hdrlen == 0:
+ raise SyntaxError("not a valid Spider file")
+ except struct.error:
+ raise SyntaxError("not a valid Spider file")
+
+ h = (99,) + t # add 1 value : spider header index starts at 1
+ iform = int(h[5])
+ if iform != 1:
+ raise SyntaxError("not a Spider 2D image")
+
+ self._size = int(h[12]), int(h[2]) # size in pixels (width, height)
+ self.istack = int(h[24])
+ self.imgnumber = int(h[27])
+
+ if self.istack == 0 and self.imgnumber == 0:
+ # stk=0, img=0: a regular 2D image
+ offset = hdrlen
+ self._nimages = 1
+ elif self.istack > 0 and self.imgnumber == 0:
+ # stk>0, img=0: Opening the stack for the first time
+ self.imgbytes = int(h[12]) * int(h[2]) * 4
+ self.hdrlen = hdrlen
+ self._nimages = int(h[26])
+ # Point to the first image in the stack
+ offset = hdrlen * 2
+ self.imgnumber = 1
+ elif self.istack == 0 and self.imgnumber > 0:
+ # stk=0, img>0: an image within the stack
+ offset = hdrlen + self.stkoffset
+ self.istack = 2 # So Image knows it's still a stack
+ else:
+ raise SyntaxError("inconsistent stack header values")
+
+ if self.bigendian:
+ self.rawmode = "F;32BF"
+ else:
+ self.rawmode = "F;32F"
+ self.mode = "F"
+
+ self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))]
+ self.__fp = self.fp # FIXME: hack
+
+ @property
+ def n_frames(self):
+ return self._nimages
+
+ @property
+ def is_animated(self):
+ return self._nimages > 1
+
+ # 1st image index is zero (although SPIDER imgnumber starts at 1)
+ def tell(self):
+ if self.imgnumber < 1:
+ return 0
+ else:
+ return self.imgnumber - 1
+
+ def seek(self, frame):
+ if self.istack == 0:
+ raise EOFError("attempt to seek in a non-stack file")
+ if not self._seek_check(frame):
+ return
+ self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
+ self.fp = self.__fp
+ self.fp.seek(self.stkoffset)
+ self._open()
+
+ # returns a byte image after rescaling to 0..255
+ def convert2byte(self, depth=255):
+ (minimum, maximum) = self.getextrema()
+ m = 1
+ if maximum != minimum:
+ m = depth / (maximum - minimum)
+ b = -m * minimum
+ return self.point(lambda i, m=m, b=b: i * m + b).convert("L")
+
+ # returns a ImageTk.PhotoImage object, after rescaling to 0..255
+ def tkPhotoImage(self):
+ from PIL import ImageTk
+
+ return ImageTk.PhotoImage(self.convert2byte(), palette=256)
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+# --------------------------------------------------------------------
+# Image series
+
+# given a list of filenames, return a list of images
+def loadImageSeries(filelist=None):
+ """create a list of :py:class:`~PIL.Image.Image` objects for use in a montage"""
+ if filelist is None or len(filelist) < 1:
+ return
+
+ imglist = []
+ for img in filelist:
+ if not os.path.exists(img):
+ print("unable to find %s" % img)
+ continue
+ try:
+ im = Image.open(img).convert2byte()
+ except Exception:
+ if not isSpiderImage(img):
+ print(img + " is not a Spider image file")
+ continue
+ im.info["filename"] = img
+ imglist.append(im)
+ return imglist
+
+
+# --------------------------------------------------------------------
+# For saving images in Spider format
+
+
+def makeSpiderHeader(im):
+ nsam, nrow = im.size
+ lenbyt = nsam * 4 # There are labrec records in the header
+ labrec = int(1024 / lenbyt)
+ if 1024 % lenbyt != 0:
+ labrec += 1
+ labbyt = labrec * lenbyt
+ hdr = []
+ nvalues = int(labbyt / 4)
+ for i in range(nvalues):
+ hdr.append(0.0)
+
+ if len(hdr) < 23:
+ return []
+
+ # NB these are Fortran indices
+ hdr[1] = 1.0 # nslice (=1 for an image)
+ hdr[2] = float(nrow) # number of rows per slice
+ hdr[5] = 1.0 # iform for 2D image
+ hdr[12] = float(nsam) # number of pixels per line
+ hdr[13] = float(labrec) # number of records in file header
+ hdr[22] = float(labbyt) # total number of bytes in header
+ hdr[23] = float(lenbyt) # record length in bytes
+
+ # adjust for Fortran indexing
+ hdr = hdr[1:]
+ hdr.append(0.0)
+ # pack binary data into a string
+ hdrstr = []
+ for v in hdr:
+ hdrstr.append(struct.pack("f", v))
+ return hdrstr
+
+
+def _save(im, fp, filename):
+ if im.mode[0] != "F":
+ im = im.convert("F")
+
+ hdr = makeSpiderHeader(im)
+ if len(hdr) < 256:
+ raise IOError("Error creating Spider header")
+
+ # write the SPIDER header
+ fp.writelines(hdr)
+
+ rawmode = "F;32NF" # 32-bit native floating point
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
+
+
+def _save_spider(im, fp, filename):
+ # get the filename extension and register it with Image
+ ext = os.path.splitext(filename)[1]
+ Image.register_extension(SpiderImageFile.format, ext)
+ _save(im, fp, filename)
+
+
+# --------------------------------------------------------------------
+
+
+Image.register_open(SpiderImageFile.format, SpiderImageFile)
+Image.register_save(SpiderImageFile.format, _save_spider)
+
+if __name__ == "__main__":
+
+ if len(sys.argv) < 2:
+ print("Syntax: python SpiderImagePlugin.py [infile] [outfile]")
+ sys.exit()
+
+ filename = sys.argv[1]
+ if not isSpiderImage(filename):
+ print("input image must be in Spider format")
+ sys.exit()
+
+ im = Image.open(filename)
+ print("image: " + str(im))
+ print("format: " + str(im.format))
+ print("size: " + str(im.size))
+ print("mode: " + str(im.mode))
+ print("max, min: ", end=" ")
+ print(im.getextrema())
+
+ if len(sys.argv) > 2:
+ outfile = sys.argv[2]
+
+ # perform some image operation
+ im = im.transpose(Image.FLIP_LEFT_RIGHT)
+ print(
+ "saving a flipped version of %s as %s "
+ % (os.path.basename(filename), outfile)
+ )
+ im.save(outfile, SpiderImageFile.format)
diff --git a/contrib/python/Pillow/py2/PIL/SunImagePlugin.py b/contrib/python/Pillow/py2/PIL/SunImagePlugin.py
new file mode 100644
index 0000000000..74fa5f7bdc
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/SunImagePlugin.py
@@ -0,0 +1,140 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Sun image file handling
+#
+# History:
+# 1995-09-10 fl Created
+# 1996-05-28 fl Fixed 32-bit alignment
+# 1998-12-29 fl Import ImagePalette module
+# 2001-12-18 fl Fixed palette loading (from Jean-Claude Rimbault)
+#
+# Copyright (c) 1997-2001 by Secret Labs AB
+# Copyright (c) 1995-1996 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i32be as i32
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.3"
+
+
+def _accept(prefix):
+ return len(prefix) >= 4 and i32(prefix) == 0x59A66A95
+
+
+##
+# Image plugin for Sun raster files.
+
+
+class SunImageFile(ImageFile.ImageFile):
+
+ format = "SUN"
+ format_description = "Sun Raster File"
+
+ def _open(self):
+
+ # The Sun Raster file header is 32 bytes in length
+ # and has the following format:
+
+ # typedef struct _SunRaster
+ # {
+ # DWORD MagicNumber; /* Magic (identification) number */
+ # DWORD Width; /* Width of image in pixels */
+ # DWORD Height; /* Height of image in pixels */
+ # DWORD Depth; /* Number of bits per pixel */
+ # DWORD Length; /* Size of image data in bytes */
+ # DWORD Type; /* Type of raster file */
+ # DWORD ColorMapType; /* Type of color map */
+ # DWORD ColorMapLength; /* Size of the color map in bytes */
+ # } SUNRASTER;
+
+ # HEAD
+ s = self.fp.read(32)
+ if i32(s) != 0x59A66A95:
+ raise SyntaxError("not an SUN raster file")
+
+ offset = 32
+
+ self._size = i32(s[4:8]), i32(s[8:12])
+
+ depth = i32(s[12:16])
+ # 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])
+
+ if depth == 1:
+ self.mode, rawmode = "1", "1;I"
+ elif depth == 4:
+ self.mode, rawmode = "L", "L;4"
+ elif depth == 8:
+ self.mode = rawmode = "L"
+ elif depth == 24:
+ if file_type == 3:
+ self.mode, rawmode = "RGB", "RGB"
+ else:
+ self.mode, rawmode = "RGB", "BGR"
+ elif depth == 32:
+ if file_type == 3:
+ self.mode, rawmode = "RGB", "RGBX"
+ else:
+ self.mode, rawmode = "RGB", "BGRX"
+ else:
+ raise SyntaxError("Unsupported Mode/Bit Depth")
+
+ if palette_length:
+ if palette_length > 1024:
+ raise SyntaxError("Unsupported Color Palette Length")
+
+ if palette_type != 1:
+ raise SyntaxError("Unsupported Palette Type")
+
+ offset = offset + 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")
+
+ # 16 bit boundaries on stride
+ stride = ((self.size[0] * depth + 15) // 16) * 2
+
+ # file type: Type is the version (or flavor) of the bitmap
+ # file. The following values are typically found in the Type
+ # field:
+ # 0000h Old
+ # 0001h Standard
+ # 0002h Byte-encoded
+ # 0003h RGB format
+ # 0004h TIFF format
+ # 0005h IFF format
+ # FFFFh Experimental
+
+ # Old and standard are the same, except for the length tag.
+ # byte-encoded is run-length-encoded
+ # RGB looks similar to standard, but RGB byte order
+ # TIFF and IFF mean that they were converted from T/IFF
+ # Experimental means that it's something else.
+ # (https://www.fileformat.info/format/sunraster/egff.htm)
+
+ if file_type in (0, 1, 3, 4, 5):
+ self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride))]
+ elif file_type == 2:
+ self.tile = [("sun_rle", (0, 0) + self.size, offset, rawmode)]
+ else:
+ raise SyntaxError("Unsupported Sun Raster file type")
+
+
+#
+# registry
+
+
+Image.register_open(SunImageFile.format, SunImageFile, _accept)
+
+Image.register_extension(SunImageFile.format, ".ras")
diff --git a/contrib/python/Pillow/py2/PIL/TarIO.py b/contrib/python/Pillow/py2/PIL/TarIO.py
new file mode 100644
index 0000000000..e180b802cc
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/TarIO.py
@@ -0,0 +1,73 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# read files from within a tar file
+#
+# History:
+# 95-06-18 fl Created
+# 96-05-28 fl Open files in binary mode
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1995-96.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+import sys
+
+from . import ContainerIO
+
+##
+# A file object that provides read access to a given member of a TAR
+# file.
+
+
+class TarIO(ContainerIO.ContainerIO):
+ def __init__(self, tarfile, file):
+ """
+ Create file object.
+
+ :param tarfile: Name of TAR file.
+ :param file: Name of member file.
+ """
+ self.fh = open(tarfile, "rb")
+
+ while True:
+
+ s = self.fh.read(512)
+ if len(s) != 512:
+ raise IOError("unexpected end of tar file")
+
+ name = s[:100].decode("utf-8")
+ i = name.find("\0")
+ if i == 0:
+ raise IOError("cannot find subfile")
+ if i > 0:
+ name = name[:i]
+
+ size = int(s[124:135], 8)
+
+ if file == name:
+ break
+
+ self.fh.seek((size + 511) & (~511), io.SEEK_CUR)
+
+ # Open region
+ ContainerIO.ContainerIO.__init__(self, self.fh, self.fh.tell(), size)
+
+ # Context manager support
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ if sys.version_info.major >= 3:
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ self.fh.close()
diff --git a/contrib/python/Pillow/py2/PIL/TgaImagePlugin.py b/contrib/python/Pillow/py2/PIL/TgaImagePlugin.py
new file mode 100644
index 0000000000..b1b3513960
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/TgaImagePlugin.py
@@ -0,0 +1,251 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# TGA file handling
+#
+# History:
+# 95-09-01 fl created (reads 24-bit files only)
+# 97-01-04 fl support more TGA versions, including compressed images
+# 98-07-04 fl fixed orientation and alpha layer bugs
+# 98-09-11 fl fixed orientation for runlength decoder
+#
+# Copyright (c) Secret Labs AB 1997-98.
+# Copyright (c) Fredrik Lundh 1995-97.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import warnings
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8, i16le as i16, o8, o16le as o16
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.3"
+
+
+#
+# --------------------------------------------------------------------
+# Read RGA file
+
+
+MODES = {
+ # map imagetype/depth to rawmode
+ (1, 8): "P",
+ (3, 1): "1",
+ (3, 8): "L",
+ (3, 16): "LA",
+ (2, 16): "BGR;5",
+ (2, 24): "BGR",
+ (2, 32): "BGRA",
+}
+
+
+##
+# Image plugin for Targa files.
+
+
+class TgaImageFile(ImageFile.ImageFile):
+
+ format = "TGA"
+ format_description = "Targa"
+
+ def _open(self):
+
+ # process header
+ s = self.fp.read(18)
+
+ id_len = i8(s[0])
+
+ colormaptype = i8(s[1])
+ imagetype = i8(s[2])
+
+ depth = i8(s[16])
+
+ flags = i8(s[17])
+
+ self._size = i16(s[12:]), i16(s[14:])
+
+ # validate header fields
+ if (
+ colormaptype not in (0, 1)
+ or self.size[0] <= 0
+ or self.size[1] <= 0
+ or depth not in (1, 8, 16, 24, 32)
+ ):
+ raise SyntaxError("not a TGA file")
+
+ # image mode
+ if imagetype in (3, 11):
+ self.mode = "L"
+ if depth == 1:
+ self.mode = "1" # ???
+ elif depth == 16:
+ self.mode = "LA"
+ elif imagetype in (1, 9):
+ self.mode = "P"
+ elif imagetype in (2, 10):
+ self.mode = "RGB"
+ if depth == 32:
+ self.mode = "RGBA"
+ else:
+ raise SyntaxError("unknown TGA mode")
+
+ # orientation
+ orientation = flags & 0x30
+ if orientation == 0x20:
+ orientation = 1
+ elif not orientation:
+ orientation = -1
+ else:
+ raise SyntaxError("unknown TGA orientation")
+
+ self.info["orientation"] = orientation
+
+ if imagetype & 8:
+ self.info["compression"] = "tga_rle"
+
+ if id_len:
+ self.info["id_section"] = self.fp.read(id_len)
+
+ if colormaptype:
+ # read palette
+ start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:])
+ if mapdepth == 16:
+ self.palette = ImagePalette.raw(
+ "BGR;16", b"\0" * 2 * start + self.fp.read(2 * size)
+ )
+ elif mapdepth == 24:
+ self.palette = ImagePalette.raw(
+ "BGR", b"\0" * 3 * start + self.fp.read(3 * size)
+ )
+ elif mapdepth == 32:
+ self.palette = ImagePalette.raw(
+ "BGRA", b"\0" * 4 * start + self.fp.read(4 * size)
+ )
+
+ # setup tile descriptor
+ try:
+ rawmode = MODES[(imagetype & 7, depth)]
+ if imagetype & 8:
+ # compressed
+ self.tile = [
+ (
+ "tga_rle",
+ (0, 0) + self.size,
+ self.fp.tell(),
+ (rawmode, orientation, depth),
+ )
+ ]
+ else:
+ self.tile = [
+ (
+ "raw",
+ (0, 0) + self.size,
+ self.fp.tell(),
+ (rawmode, 0, orientation),
+ )
+ ]
+ except KeyError:
+ pass # cannot decode
+
+
+#
+# --------------------------------------------------------------------
+# Write TGA file
+
+
+SAVE = {
+ "1": ("1", 1, 0, 3),
+ "L": ("L", 8, 0, 3),
+ "LA": ("LA", 16, 0, 3),
+ "P": ("P", 8, 1, 1),
+ "RGB": ("BGR", 24, 0, 2),
+ "RGBA": ("BGRA", 32, 0, 2),
+}
+
+
+def _save(im, fp, filename):
+
+ try:
+ rawmode, bits, colormaptype, imagetype = SAVE[im.mode]
+ except KeyError:
+ raise IOError("cannot write mode %s as TGA" % im.mode)
+
+ if "rle" in im.encoderinfo:
+ rle = im.encoderinfo["rle"]
+ else:
+ compression = im.encoderinfo.get("compression", im.info.get("compression"))
+ rle = compression == "tga_rle"
+ if rle:
+ imagetype += 8
+
+ id_section = im.encoderinfo.get("id_section", im.info.get("id_section", ""))
+ id_len = len(id_section)
+ if id_len > 255:
+ id_len = 255
+ id_section = id_section[:255]
+ warnings.warn("id_section has been trimmed to 255 characters")
+
+ if colormaptype:
+ colormapfirst, colormaplength, colormapentry = 0, 256, 24
+ else:
+ colormapfirst, colormaplength, colormapentry = 0, 0, 0
+
+ if im.mode in ("LA", "RGBA"):
+ flags = 8
+ else:
+ flags = 0
+
+ orientation = im.encoderinfo.get("orientation", im.info.get("orientation", -1))
+ if orientation > 0:
+ flags = flags | 0x20
+
+ fp.write(
+ o8(id_len)
+ + o8(colormaptype)
+ + o8(imagetype)
+ + o16(colormapfirst)
+ + o16(colormaplength)
+ + o8(colormapentry)
+ + o16(0)
+ + o16(0)
+ + o16(im.size[0])
+ + o16(im.size[1])
+ + o8(bits)
+ + o8(flags)
+ )
+
+ if id_section:
+ fp.write(id_section)
+
+ if colormaptype:
+ fp.write(im.im.getpalette("RGB", "BGR"))
+
+ if rle:
+ ImageFile._save(
+ im, fp, [("tga_rle", (0, 0) + im.size, 0, (rawmode, orientation))]
+ )
+ else:
+ ImageFile._save(
+ im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))]
+ )
+
+ # write targa version 2 footer
+ fp.write(b"\000" * 8 + b"TRUEVISION-XFILE." + b"\000")
+
+
+#
+# --------------------------------------------------------------------
+# Registry
+
+
+Image.register_open(TgaImageFile.format, TgaImageFile)
+Image.register_save(TgaImageFile.format, _save)
+
+Image.register_extensions(TgaImageFile.format, [".tga", ".icb", ".vda", ".vst"])
+
+Image.register_mime(TgaImageFile.format, "image/x-tga")
diff --git a/contrib/python/Pillow/py2/PIL/TiffImagePlugin.py b/contrib/python/Pillow/py2/PIL/TiffImagePlugin.py
new file mode 100644
index 0000000000..0661c2ffb1
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/TiffImagePlugin.py
@@ -0,0 +1,1947 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# TIFF file handling
+#
+# TIFF is a flexible, if somewhat aged, image file format originally
+# defined by Aldus. Although TIFF supports a wide variety of pixel
+# layouts and compression methods, the name doesn't really stand for
+# "thousands of incompatible file formats," it just feels that way.
+#
+# To read TIFF data from a stream, the stream must be seekable. For
+# progressive decoding, make sure to use TIFF files where the tag
+# directory is placed first in the file.
+#
+# History:
+# 1995-09-01 fl Created
+# 1996-05-04 fl Handle JPEGTABLES tag
+# 1996-05-18 fl Fixed COLORMAP support
+# 1997-01-05 fl Fixed PREDICTOR support
+# 1997-08-27 fl Added support for rational tags (from Perry Stoll)
+# 1998-01-10 fl Fixed seek/tell (from Jan Blom)
+# 1998-07-15 fl Use private names for internal variables
+# 1999-06-13 fl Rewritten for PIL 1.0 (1.0)
+# 2000-10-11 fl Additional fixes for Python 2.0 (1.1)
+# 2001-04-17 fl Fixed rewind support (seek to frame 0) (1.2)
+# 2001-05-12 fl Added write support for more tags (from Greg Couch) (1.3)
+# 2001-12-18 fl Added workaround for broken Matrox library
+# 2002-01-18 fl Don't mess up if photometric tag is missing (D. Alan Stewart)
+# 2003-05-19 fl Check FILLORDER tag
+# 2003-09-26 fl Added RGBa support
+# 2004-02-24 fl Added DPI support; fixed rational write support
+# 2005-02-07 fl Added workaround for broken Corel Draw 10 files
+# 2006-01-09 fl Added support for float/double tags (from Russell Nelson)
+#
+# Copyright (c) 1997-2006 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1995-1997 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import division, print_function
+
+import distutils.version
+import io
+import itertools
+import os
+import struct
+import sys
+import warnings
+from fractions import Fraction
+from numbers import Number, Rational
+
+from . import Image, ImageFile, ImagePalette, TiffTags
+from ._binary import i8, o8
+from ._util import py3
+from .TiffTags import TYPES
+
+try:
+ # Python 3
+ from collections.abc import MutableMapping
+except ImportError:
+ # Python 2.7
+ from collections import MutableMapping
+
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "1.3.5"
+DEBUG = False # Needs to be merged with the new logging approach.
+
+# Set these to true to force use of libtiff for reading or writing.
+READ_LIBTIFF = False
+WRITE_LIBTIFF = False
+IFD_LEGACY_API = True
+
+II = b"II" # little-endian (Intel style)
+MM = b"MM" # big-endian (Motorola style)
+
+#
+# --------------------------------------------------------------------
+# Read TIFF files
+
+# a few tag names, just to make the code below a bit more readable
+IMAGEWIDTH = 256
+IMAGELENGTH = 257
+BITSPERSAMPLE = 258
+COMPRESSION = 259
+PHOTOMETRIC_INTERPRETATION = 262
+FILLORDER = 266
+IMAGEDESCRIPTION = 270
+STRIPOFFSETS = 273
+SAMPLESPERPIXEL = 277
+ROWSPERSTRIP = 278
+STRIPBYTECOUNTS = 279
+X_RESOLUTION = 282
+Y_RESOLUTION = 283
+PLANAR_CONFIGURATION = 284
+RESOLUTION_UNIT = 296
+TRANSFERFUNCTION = 301
+SOFTWARE = 305
+DATE_TIME = 306
+ARTIST = 315
+PREDICTOR = 317
+COLORMAP = 320
+TILEOFFSETS = 324
+EXTRASAMPLES = 338
+SAMPLEFORMAT = 339
+JPEGTABLES = 347
+REFERENCEBLACKWHITE = 532
+COPYRIGHT = 33432
+IPTC_NAA_CHUNK = 33723 # newsphoto properties
+PHOTOSHOP_CHUNK = 34377 # photoshop properties
+ICCPROFILE = 34675
+EXIFIFD = 34665
+XMP = 700
+JPEGQUALITY = 65537 # pseudo-tag by libtiff
+
+# https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/io/TiffDecoder.java
+IMAGEJ_META_DATA_BYTE_COUNTS = 50838
+IMAGEJ_META_DATA = 50839
+
+COMPRESSION_INFO = {
+ # Compression => pil compression name
+ 1: "raw",
+ 2: "tiff_ccitt",
+ 3: "group3",
+ 4: "group4",
+ 5: "tiff_lzw",
+ 6: "tiff_jpeg", # obsolete
+ 7: "jpeg",
+ 8: "tiff_adobe_deflate",
+ 32771: "tiff_raw_16", # 16-bit padding
+ 32773: "packbits",
+ 32809: "tiff_thunderscan",
+ 32946: "tiff_deflate",
+ 34676: "tiff_sgilog",
+ 34677: "tiff_sgilog24",
+ 34925: "lzma",
+ 50000: "zstd",
+ 50001: "webp",
+}
+
+COMPRESSION_INFO_REV = {v: k for k, v in COMPRESSION_INFO.items()}
+
+OPEN_INFO = {
+ # (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
+ # ExtraSamples) => mode, rawmode
+ (II, 0, (1,), 1, (1,), ()): ("1", "1;I"),
+ (MM, 0, (1,), 1, (1,), ()): ("1", "1;I"),
+ (II, 0, (1,), 2, (1,), ()): ("1", "1;IR"),
+ (MM, 0, (1,), 2, (1,), ()): ("1", "1;IR"),
+ (II, 1, (1,), 1, (1,), ()): ("1", "1"),
+ (MM, 1, (1,), 1, (1,), ()): ("1", "1"),
+ (II, 1, (1,), 2, (1,), ()): ("1", "1;R"),
+ (MM, 1, (1,), 2, (1,), ()): ("1", "1;R"),
+ (II, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
+ (MM, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
+ (II, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
+ (MM, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
+ (II, 1, (1,), 1, (2,), ()): ("L", "L;2"),
+ (MM, 1, (1,), 1, (2,), ()): ("L", "L;2"),
+ (II, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
+ (MM, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
+ (II, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
+ (MM, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
+ (II, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
+ (MM, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
+ (II, 1, (1,), 1, (4,), ()): ("L", "L;4"),
+ (MM, 1, (1,), 1, (4,), ()): ("L", "L;4"),
+ (II, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
+ (MM, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
+ (II, 0, (1,), 1, (8,), ()): ("L", "L;I"),
+ (MM, 0, (1,), 1, (8,), ()): ("L", "L;I"),
+ (II, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
+ (MM, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
+ (II, 1, (1,), 1, (8,), ()): ("L", "L"),
+ (MM, 1, (1,), 1, (8,), ()): ("L", "L"),
+ (II, 1, (1,), 2, (8,), ()): ("L", "L;R"),
+ (MM, 1, (1,), 2, (8,), ()): ("L", "L;R"),
+ (II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"),
+ (II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"),
+ (MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"),
+ (II, 1, (2,), 1, (16,), ()): ("I", "I;16S"),
+ (MM, 1, (2,), 1, (16,), ()): ("I", "I;16BS"),
+ (II, 0, (3,), 1, (32,), ()): ("F", "F;32F"),
+ (MM, 0, (3,), 1, (32,), ()): ("F", "F;32BF"),
+ (II, 1, (1,), 1, (32,), ()): ("I", "I;32N"),
+ (II, 1, (2,), 1, (32,), ()): ("I", "I;32S"),
+ (MM, 1, (2,), 1, (32,), ()): ("I", "I;32BS"),
+ (II, 1, (3,), 1, (32,), ()): ("F", "F;32F"),
+ (MM, 1, (3,), 1, (32,), ()): ("F", "F;32BF"),
+ (II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
+ (MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
+ (II, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
+ (MM, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
+ (II, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
+ (MM, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
+ (II, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples
+ (MM, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples
+ (II, 2, (1,), 1, (8, 8, 8, 8), (0,)): ("RGBX", "RGBX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8), (0,)): ("RGBX", "RGBX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGBX", "RGBXX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGBX", "RGBXX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGBX", "RGBXXX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGBX", "RGBXXX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (2, 0, 0)): ("RGBA", "RGBAXX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (2, 0, 0)): ("RGBA", "RGBAXX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
+ (MM, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
+ (II, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16B"),
+ (II, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16B"),
+ (II, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGBX", "RGBX;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGBX", "RGBX;16B"),
+ (II, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16B"),
+ (II, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16B"),
+ (II, 3, (1,), 1, (1,), ()): ("P", "P;1"),
+ (MM, 3, (1,), 1, (1,), ()): ("P", "P;1"),
+ (II, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
+ (MM, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
+ (II, 3, (1,), 1, (2,), ()): ("P", "P;2"),
+ (MM, 3, (1,), 1, (2,), ()): ("P", "P;2"),
+ (II, 3, (1,), 2, (2,), ()): ("P", "P;2R"),
+ (MM, 3, (1,), 2, (2,), ()): ("P", "P;2R"),
+ (II, 3, (1,), 1, (4,), ()): ("P", "P;4"),
+ (MM, 3, (1,), 1, (4,), ()): ("P", "P;4"),
+ (II, 3, (1,), 2, (4,), ()): ("P", "P;4R"),
+ (MM, 3, (1,), 2, (4,), ()): ("P", "P;4R"),
+ (II, 3, (1,), 1, (8,), ()): ("P", "P"),
+ (MM, 3, (1,), 1, (8,), ()): ("P", "P"),
+ (II, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
+ (MM, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
+ (II, 3, (1,), 2, (8,), ()): ("P", "P;R"),
+ (MM, 3, (1,), 2, (8,), ()): ("P", "P;R"),
+ (II, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
+ (MM, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
+ (II, 5, (1,), 1, (8, 8, 8, 8, 8), (0,)): ("CMYK", "CMYKX"),
+ (MM, 5, (1,), 1, (8, 8, 8, 8, 8), (0,)): ("CMYK", "CMYKX"),
+ (II, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"),
+ (MM, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"),
+ (II, 5, (1,), 1, (16, 16, 16, 16), ()): ("CMYK", "CMYK;16L"),
+ # JPEG compressed images handled by LibTiff and auto-converted to RGBX
+ # Minimal Baseline TIFF requires YCbCr images to have 3 SamplesPerPixel
+ (II, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"),
+ (MM, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"),
+ (II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
+ (MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
+}
+
+PREFIXES = [
+ b"MM\x00\x2A", # Valid TIFF header with big-endian byte order
+ b"II\x2A\x00", # Valid TIFF header with little-endian byte order
+ b"MM\x2A\x00", # Invalid TIFF header, assume big-endian
+ b"II\x00\x2A", # Invalid TIFF header, assume little-endian
+]
+
+
+def _accept(prefix):
+ return prefix[:4] in PREFIXES
+
+
+def _limit_rational(val, max_val):
+ inv = abs(val) > 1
+ n_d = IFDRational(1 / val if inv else val).limit_rational(max_val)
+ return n_d[::-1] if inv else n_d
+
+
+def _libtiff_version():
+ return Image.core.libtiff_version.split("\n")[0].split("Version ")[1]
+
+
+##
+# Wrapper for TIFF IFDs.
+
+_load_dispatch = {}
+_write_dispatch = {}
+
+
+class IFDRational(Rational):
+ """ Implements a rational class where 0/0 is a legal value to match
+ the in the wild use of exif rationals.
+
+ e.g., DigitalZoomRatio - 0.00/0.00 indicates that no digital zoom was used
+ """
+
+ """ If the denominator is 0, store this as a float('nan'), otherwise store
+ as a fractions.Fraction(). Delegate as appropriate
+
+ """
+
+ __slots__ = ("_numerator", "_denominator", "_val")
+
+ def __init__(self, value, denominator=1):
+ """
+ :param value: either an integer numerator, a
+ float/rational/other number, or an IFDRational
+ :param denominator: Optional integer denominator
+ """
+ self._denominator = denominator
+ self._numerator = value
+ self._val = float(1)
+
+ if isinstance(value, Fraction):
+ self._numerator = value.numerator
+ self._denominator = value.denominator
+ self._val = value
+
+ if isinstance(value, IFDRational):
+ self._denominator = value.denominator
+ self._numerator = value.numerator
+ self._val = value._val
+ return
+
+ if denominator == 0:
+ self._val = float("nan")
+ return
+
+ elif denominator == 1:
+ self._val = Fraction(value)
+ else:
+ self._val = Fraction(value, denominator)
+
+ @property
+ def numerator(a):
+ return a._numerator
+
+ @property
+ def denominator(a):
+ return a._denominator
+
+ def limit_rational(self, max_denominator):
+ """
+
+ :param max_denominator: Integer, the maximum denominator value
+ :returns: Tuple of (numerator, denominator)
+ """
+
+ if self.denominator == 0:
+ return (self.numerator, self.denominator)
+
+ f = self._val.limit_denominator(max_denominator)
+ return (f.numerator, f.denominator)
+
+ def __repr__(self):
+ return str(float(self._val))
+
+ def __hash__(self):
+ return self._val.__hash__()
+
+ def __eq__(self, other):
+ return self._val == other
+
+ def _delegate(op):
+ def delegate(self, *args):
+ return getattr(self._val, op)(*args)
+
+ return delegate
+
+ """ a = ['add','radd', 'sub', 'rsub','div', 'rdiv', 'mul', 'rmul',
+ 'truediv', 'rtruediv', 'floordiv',
+ 'rfloordiv','mod','rmod', 'pow','rpow', 'pos', 'neg',
+ 'abs', 'trunc', 'lt', 'gt', 'le', 'ge', 'nonzero',
+ 'ceil', 'floor', 'round']
+ print("\n".join("__%s__ = _delegate('__%s__')" % (s,s) for s in a))
+ """
+
+ __add__ = _delegate("__add__")
+ __radd__ = _delegate("__radd__")
+ __sub__ = _delegate("__sub__")
+ __rsub__ = _delegate("__rsub__")
+ __div__ = _delegate("__div__")
+ __rdiv__ = _delegate("__rdiv__")
+ __mul__ = _delegate("__mul__")
+ __rmul__ = _delegate("__rmul__")
+ __truediv__ = _delegate("__truediv__")
+ __rtruediv__ = _delegate("__rtruediv__")
+ __floordiv__ = _delegate("__floordiv__")
+ __rfloordiv__ = _delegate("__rfloordiv__")
+ __mod__ = _delegate("__mod__")
+ __rmod__ = _delegate("__rmod__")
+ __pow__ = _delegate("__pow__")
+ __rpow__ = _delegate("__rpow__")
+ __pos__ = _delegate("__pos__")
+ __neg__ = _delegate("__neg__")
+ __abs__ = _delegate("__abs__")
+ __trunc__ = _delegate("__trunc__")
+ __lt__ = _delegate("__lt__")
+ __gt__ = _delegate("__gt__")
+ __le__ = _delegate("__le__")
+ __ge__ = _delegate("__ge__")
+ __nonzero__ = _delegate("__nonzero__")
+ __ceil__ = _delegate("__ceil__")
+ __floor__ = _delegate("__floor__")
+ __round__ = _delegate("__round__")
+
+
+class ImageFileDirectory_v2(MutableMapping):
+ """This class represents a TIFF tag directory. To speed things up, we
+ don't decode tags unless they're asked for.
+
+ Exposes a dictionary interface of the tags in the directory::
+
+ ifd = ImageFileDirectory_v2()
+ ifd[key] = 'Some Data'
+ ifd.tagtype[key] = TiffTags.ASCII
+ print(ifd[key])
+ 'Some Data'
+
+ Individual values are returned as the strings or numbers, sequences are
+ returned as tuples of the values.
+
+ The tiff metadata type of each item is stored in a dictionary of
+ tag types in
+ `~PIL.TiffImagePlugin.ImageFileDirectory_v2.tagtype`. The types
+ are read from a tiff file, guessed from the type added, or added
+ manually.
+
+ Data Structures:
+
+ * self.tagtype = {}
+
+ * Key: numerical tiff tag number
+ * Value: integer corresponding to the data type from
+ ~PIL.TiffTags.TYPES`
+
+ .. versionadded:: 3.0.0
+ """
+
+ """
+ Documentation:
+
+ 'internal' data structures:
+ * self._tags_v2 = {} Key: numerical tiff tag number
+ Value: decoded data, as tuple for multiple values
+ * self._tagdata = {} Key: numerical tiff tag number
+ Value: undecoded byte string from file
+ * self._tags_v1 = {} Key: numerical tiff tag number
+ Value: decoded data in the v1 format
+
+ Tags will be found in the private attributes self._tagdata, and in
+ self._tags_v2 once decoded.
+
+ Self.legacy_api is a value for internal use, and shouldn't be
+ changed from outside code. In cooperation with the
+ ImageFileDirectory_v1 class, if legacy_api is true, then decoded
+ tags will be populated into both _tags_v1 and _tags_v2. _Tags_v2
+ will be used if this IFD is used in the TIFF save routine. Tags
+ should be read from tags_v1 if legacy_api == true.
+
+ """
+
+ def __init__(self, ifh=b"II\052\0\0\0\0\0", prefix=None):
+ """Initialize an ImageFileDirectory.
+
+ To construct an ImageFileDirectory from a real file, pass the 8-byte
+ magic header to the constructor. To only set the endianness, pass it
+ as the 'prefix' keyword argument.
+
+ :param ifh: One of the accepted magic headers (cf. PREFIXES); also sets
+ endianness.
+ :param prefix: Override the endianness of the file.
+ """
+ if ifh[:4] not in PREFIXES:
+ raise SyntaxError("not a TIFF file (header %r not valid)" % ifh)
+ self._prefix = prefix if prefix is not None else ifh[:2]
+ if self._prefix == MM:
+ self._endian = ">"
+ elif self._prefix == II:
+ self._endian = "<"
+ else:
+ raise SyntaxError("not a TIFF IFD")
+ self.reset()
+ (self.next,) = self._unpack("L", ifh[4:])
+ self._legacy_api = False
+
+ prefix = property(lambda self: self._prefix)
+ offset = property(lambda self: self._offset)
+ legacy_api = property(lambda self: self._legacy_api)
+
+ @legacy_api.setter
+ def legacy_api(self, value):
+ raise Exception("Not allowing setting of legacy api")
+
+ def reset(self):
+ self._tags_v1 = {} # will remain empty if legacy_api is false
+ self._tags_v2 = {} # main tag storage
+ self._tagdata = {}
+ self.tagtype = {} # added 2008-06-05 by Florian Hoech
+ self._next = None
+ self._offset = None
+
+ def __str__(self):
+ return str(dict(self))
+
+ def named(self):
+ """
+ :returns: dict of name|key: value
+
+ Returns the complete tag dictionary, with named tags where possible.
+ """
+ return {TiffTags.lookup(code).name: value for code, value in self.items()}
+
+ def __len__(self):
+ return len(set(self._tagdata) | set(self._tags_v2))
+
+ def __getitem__(self, tag):
+ if tag not in self._tags_v2: # unpack on the fly
+ data = self._tagdata[tag]
+ typ = self.tagtype[tag]
+ size, handler = self._load_dispatch[typ]
+ self[tag] = handler(self, data, self.legacy_api) # check type
+ val = self._tags_v2[tag]
+ if self.legacy_api and not isinstance(val, (tuple, bytes)):
+ val = (val,)
+ return val
+
+ def __contains__(self, tag):
+ return tag in self._tags_v2 or tag in self._tagdata
+
+ if not py3:
+
+ def has_key(self, tag):
+ return tag in self
+
+ def __setitem__(self, tag, value):
+ self._setitem(tag, value, self.legacy_api)
+
+ def _setitem(self, tag, value, legacy_api):
+ basetypes = (Number, bytes, str)
+ if not py3:
+ basetypes += (unicode,) # noqa: F821
+
+ info = TiffTags.lookup(tag)
+ values = [value] if isinstance(value, basetypes) else value
+
+ if tag not in self.tagtype:
+ if info.type:
+ self.tagtype[tag] = info.type
+ else:
+ self.tagtype[tag] = TiffTags.UNDEFINED
+ if all(isinstance(v, IFDRational) for v in values):
+ self.tagtype[tag] = TiffTags.RATIONAL
+ elif all(isinstance(v, int) for v in values):
+ if all(v < 2 ** 16 for v in values):
+ self.tagtype[tag] = TiffTags.SHORT
+ else:
+ self.tagtype[tag] = TiffTags.LONG
+ elif all(isinstance(v, float) for v in values):
+ self.tagtype[tag] = TiffTags.DOUBLE
+ else:
+ if py3:
+ if all(isinstance(v, str) for v in values):
+ self.tagtype[tag] = TiffTags.ASCII
+ else:
+ # Never treat data as binary by default on Python 2.
+ self.tagtype[tag] = TiffTags.ASCII
+
+ if self.tagtype[tag] == TiffTags.UNDEFINED and py3:
+ values = [
+ value.encode("ascii", "replace") if isinstance(value, str) else value
+ ]
+ elif self.tagtype[tag] == TiffTags.RATIONAL:
+ values = [float(v) if isinstance(v, int) else v for v in values]
+
+ values = tuple(info.cvt_enum(value) for value in values)
+
+ dest = self._tags_v1 if legacy_api else self._tags_v2
+
+ # Three branches:
+ # Spec'd length == 1, Actual length 1, store as element
+ # 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
+ ):
+ # Don't mess with the legacy api, since it's frozen.
+ if legacy_api and self.tagtype[tag] in [
+ TiffTags.RATIONAL,
+ TiffTags.SIGNED_RATIONAL,
+ ]: # rationals
+ values = (values,)
+ try:
+ (dest[tag],) = values
+ except ValueError:
+ # We've got a builtin tag with 1 expected entry
+ warnings.warn(
+ "Metadata Warning, tag %s had too many entries: %s, expected 1"
+ % (tag, len(values))
+ )
+ dest[tag] = values[0]
+
+ else:
+ # Spec'd length > 1 or undefined
+ # Unspec'd, and length > 1
+ dest[tag] = values
+
+ def __delitem__(self, tag):
+ self._tags_v2.pop(tag, None)
+ self._tags_v1.pop(tag, None)
+ self._tagdata.pop(tag, None)
+
+ def __iter__(self):
+ return iter(set(self._tagdata) | set(self._tags_v2))
+
+ def _unpack(self, fmt, data):
+ return struct.unpack(self._endian + fmt, data)
+
+ def _pack(self, fmt, *values):
+ return struct.pack(self._endian + fmt, *values)
+
+ def _register_loader(idx, size):
+ def decorator(func):
+ from .TiffTags import TYPES
+
+ if func.__name__.startswith("load_"):
+ TYPES[idx] = func.__name__[5:].replace("_", " ")
+ _load_dispatch[idx] = size, func # noqa: F821
+ return func
+
+ return decorator
+
+ def _register_writer(idx):
+ def decorator(func):
+ _write_dispatch[idx] = func # noqa: F821
+ return func
+
+ return decorator
+
+ def _register_basic(idx_fmt_name):
+ from .TiffTags import TYPES
+
+ idx, fmt, name = idx_fmt_name
+ TYPES[idx] = name
+ size = struct.calcsize("=" + fmt)
+ _load_dispatch[idx] = ( # noqa: F821
+ size,
+ lambda self, data, legacy_api=True: (
+ self._unpack("{}{}".format(len(data) // size, fmt), data)
+ ),
+ )
+ _write_dispatch[idx] = lambda self, *values: ( # noqa: F821
+ b"".join(self._pack(fmt, value) for value in values)
+ )
+
+ list(
+ map(
+ _register_basic,
+ [
+ (TiffTags.SHORT, "H", "short"),
+ (TiffTags.LONG, "L", "long"),
+ (TiffTags.SIGNED_BYTE, "b", "signed byte"),
+ (TiffTags.SIGNED_SHORT, "h", "signed short"),
+ (TiffTags.SIGNED_LONG, "l", "signed long"),
+ (TiffTags.FLOAT, "f", "float"),
+ (TiffTags.DOUBLE, "d", "double"),
+ ],
+ )
+ )
+
+ @_register_loader(1, 1) # Basic type, except for the legacy API.
+ def load_byte(self, data, legacy_api=True):
+ return data
+
+ @_register_writer(1) # Basic type, except for the legacy API.
+ def write_byte(self, data):
+ return data
+
+ @_register_loader(2, 1)
+ def load_string(self, data, legacy_api=True):
+ if data.endswith(b"\0"):
+ data = data[:-1]
+ return data.decode("latin-1", "replace")
+
+ @_register_writer(2)
+ def write_string(self, value):
+ # remerge of https://github.com/python-pillow/Pillow/pull/1416
+ if sys.version_info.major == 2:
+ value = value.decode("ascii", "replace")
+ return b"" + value.encode("ascii", "replace") + b"\0"
+
+ @_register_loader(5, 8)
+ def load_rational(self, data, legacy_api=True):
+ vals = self._unpack("{}L".format(len(data) // 4), data)
+
+ def combine(a, b):
+ return (a, b) if legacy_api else IFDRational(a, b)
+
+ return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
+
+ @_register_writer(5)
+ def write_rational(self, *values):
+ return b"".join(
+ self._pack("2L", *_limit_rational(frac, 2 ** 31)) for frac in values
+ )
+
+ @_register_loader(7, 1)
+ def load_undefined(self, data, legacy_api=True):
+ return data
+
+ @_register_writer(7)
+ def write_undefined(self, value):
+ return value
+
+ @_register_loader(10, 8)
+ def load_signed_rational(self, data, legacy_api=True):
+ vals = self._unpack("{}l".format(len(data) // 4), data)
+
+ def combine(a, b):
+ return (a, b) if legacy_api else IFDRational(a, b)
+
+ return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
+
+ @_register_writer(10)
+ def write_signed_rational(self, *values):
+ return b"".join(
+ self._pack("2L", *_limit_rational(frac, 2 ** 30)) for frac in values
+ )
+
+ def _ensure_read(self, fp, size):
+ ret = fp.read(size)
+ if len(ret) != size:
+ raise IOError(
+ "Corrupt EXIF data. "
+ + "Expecting to read %d bytes but only got %d. " % (size, len(ret))
+ )
+ return ret
+
+ def load(self, fp):
+
+ self.reset()
+ self._offset = fp.tell()
+
+ try:
+ for i in range(self._unpack("H", self._ensure_read(fp, 2))[0]):
+ tag, typ, count, data = self._unpack("HHL4s", self._ensure_read(fp, 12))
+ if DEBUG:
+ tagname = TiffTags.lookup(tag).name
+ typname = TYPES.get(typ, "unknown")
+ print(
+ "tag: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ),
+ end=" ",
+ )
+
+ try:
+ unit_size, handler = self._load_dispatch[typ]
+ except KeyError:
+ if DEBUG:
+ print("- unsupported type", typ)
+ continue # ignore unsupported type
+ size = count * unit_size
+ if size > 4:
+ here = fp.tell()
+ (offset,) = self._unpack("L", data)
+ if DEBUG:
+ print(
+ "Tag Location: %s - Data Location: %s" % (here, offset),
+ end=" ",
+ )
+ fp.seek(offset)
+ data = ImageFile._safe_read(fp, size)
+ fp.seek(here)
+ else:
+ data = data[:size]
+
+ if len(data) != size:
+ warnings.warn(
+ "Possibly corrupt EXIF data. "
+ "Expecting to read %d bytes but only got %d."
+ " Skipping tag %s" % (size, len(data), tag)
+ )
+ continue
+
+ if not data:
+ continue
+
+ self._tagdata[tag] = data
+ self.tagtype[tag] = typ
+
+ if DEBUG:
+ if size > 32:
+ print("- value: <table: %d bytes>" % size)
+ else:
+ print("- value:", self[tag])
+
+ (self.next,) = self._unpack("L", self._ensure_read(fp, 4))
+ except IOError as msg:
+ warnings.warn(str(msg))
+ return
+
+ def tobytes(self, offset=0):
+ # FIXME What about tagdata?
+ result = self._pack("H", len(self._tags_v2))
+
+ entries = []
+ offset = offset + len(result) + len(self._tags_v2) * 12 + 4
+ stripoffsets = None
+
+ # pass 1: convert tags to binary format
+ # always write tags in ascending order
+ for tag, value in sorted(self._tags_v2.items()):
+ if tag == STRIPOFFSETS:
+ stripoffsets = len(entries)
+ typ = self.tagtype.get(tag)
+ if DEBUG:
+ print("Tag %s, Type: %s, Value: %s" % (tag, typ, value))
+ values = value if isinstance(value, tuple) else (value,)
+ data = self._write_dispatch[typ](self, *values)
+ if DEBUG:
+ tagname = TiffTags.lookup(tag).name
+ typname = TYPES.get(typ, "unknown")
+ print(
+ "save: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ),
+ end=" ",
+ )
+ if len(data) >= 16:
+ print("- value: <table: %d bytes>" % len(data))
+ else:
+ print("- value:", values)
+
+ # count is sum of lengths for string and arbitrary data
+ if typ in [TiffTags.BYTE, TiffTags.ASCII, TiffTags.UNDEFINED]:
+ count = len(data)
+ else:
+ count = len(values)
+ # figure out if data fits into the entry
+ if len(data) <= 4:
+ entries.append((tag, typ, count, data.ljust(4, b"\0"), b""))
+ else:
+ entries.append((tag, typ, count, self._pack("L", offset), data))
+ offset += (len(data) + 1) // 2 * 2 # pad to word
+
+ # update strip offset data to point beyond auxiliary data
+ if stripoffsets is not None:
+ tag, typ, count, value, data = entries[stripoffsets]
+ if data:
+ raise NotImplementedError("multistrip support not yet implemented")
+ value = self._pack("L", self._unpack("L", value)[0] + offset)
+ entries[stripoffsets] = tag, typ, count, value, data
+
+ # pass 2: write entries to file
+ for tag, typ, count, value, data in entries:
+ if DEBUG > 1:
+ print(tag, typ, count, repr(value), repr(data))
+ result += self._pack("HHL4s", tag, typ, count, value)
+
+ # -- overwrite here for multi-page --
+ result += b"\0\0\0\0" # end of entries
+
+ # pass 3: write auxiliary data to file
+ for tag, typ, count, value, data in entries:
+ result += data
+ if len(data) & 1:
+ result += b"\0"
+
+ return result
+
+ def save(self, fp):
+
+ if fp.tell() == 0: # skip TIFF header on subsequent pages
+ # tiff header -- PIL always starts the first IFD at offset 8
+ fp.write(self._prefix + self._pack("HL", 42, 8))
+
+ offset = fp.tell()
+ result = self.tobytes(offset)
+ fp.write(result)
+ return offset + len(result)
+
+
+ImageFileDirectory_v2._load_dispatch = _load_dispatch
+ImageFileDirectory_v2._write_dispatch = _write_dispatch
+for idx, name in TYPES.items():
+ name = name.replace(" ", "_")
+ setattr(ImageFileDirectory_v2, "load_" + name, _load_dispatch[idx][1])
+ setattr(ImageFileDirectory_v2, "write_" + name, _write_dispatch[idx])
+del _load_dispatch, _write_dispatch, idx, name
+
+
+# Legacy ImageFileDirectory support.
+class ImageFileDirectory_v1(ImageFileDirectory_v2):
+ """This class represents the **legacy** interface to a TIFF tag directory.
+
+ Exposes a dictionary interface of the tags in the directory::
+
+ ifd = ImageFileDirectory_v1()
+ ifd[key] = 'Some Data'
+ ifd.tagtype[key] = TiffTags.ASCII
+ print(ifd[key])
+ ('Some Data',)
+
+ Also contains a dictionary of tag types as read from the tiff image file,
+ `~PIL.TiffImagePlugin.ImageFileDirectory_v1.tagtype`.
+
+ Values are returned as a tuple.
+
+ .. deprecated:: 3.0.0
+ """
+
+ def __init__(self, *args, **kwargs):
+ ImageFileDirectory_v2.__init__(self, *args, **kwargs)
+ self._legacy_api = True
+
+ tags = property(lambda self: self._tags_v1)
+ tagdata = property(lambda self: self._tagdata)
+
+ @classmethod
+ def from_v2(cls, original):
+ """ Returns an
+ :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
+ instance with the same data as is contained in the original
+ :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
+ instance.
+
+ :returns: :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
+
+ """
+
+ ifd = cls(prefix=original.prefix)
+ ifd._tagdata = original._tagdata
+ ifd.tagtype = original.tagtype
+ ifd.next = original.next # an indicator for multipage tiffs
+ return ifd
+
+ def to_v2(self):
+ """ Returns an
+ :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
+ instance with the same data as is contained in the original
+ :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
+ instance.
+
+ :returns: :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
+
+ """
+
+ ifd = ImageFileDirectory_v2(prefix=self.prefix)
+ ifd._tagdata = dict(self._tagdata)
+ ifd.tagtype = dict(self.tagtype)
+ ifd._tags_v2 = dict(self._tags_v2)
+ return ifd
+
+ def __contains__(self, tag):
+ return tag in self._tags_v1 or tag in self._tagdata
+
+ def __len__(self):
+ return len(set(self._tagdata) | set(self._tags_v1))
+
+ def __iter__(self):
+ return iter(set(self._tagdata) | set(self._tags_v1))
+
+ def __setitem__(self, tag, value):
+ for legacy_api in (False, True):
+ self._setitem(tag, value, legacy_api)
+
+ def __getitem__(self, tag):
+ if tag not in self._tags_v1: # unpack on the fly
+ data = self._tagdata[tag]
+ typ = self.tagtype[tag]
+ size, handler = self._load_dispatch[typ]
+ for legacy in (False, True):
+ self._setitem(tag, handler(self, data, legacy), legacy)
+ val = self._tags_v1[tag]
+ if not isinstance(val, (tuple, bytes)):
+ val = (val,)
+ return val
+
+
+# undone -- switch this pointer when IFD_LEGACY_API == False
+ImageFileDirectory = ImageFileDirectory_v1
+
+
+##
+# Image plugin for TIFF files.
+
+
+class TiffImageFile(ImageFile.ImageFile):
+
+ format = "TIFF"
+ format_description = "Adobe TIFF"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+ """Open the first image in a TIFF file"""
+
+ # Header
+ ifh = self.fp.read(8)
+
+ # image file directory (tag dictionary)
+ self.tag_v2 = ImageFileDirectory_v2(ifh)
+
+ # legacy tag/ifd entries will be filled in later
+ self.tag = self.ifd = None
+
+ # setup frame pointers
+ self.__first = self.__next = self.tag_v2.next
+ self.__frame = -1
+ self.__fp = self.fp
+ self._frame_pos = []
+ self._n_frames = None
+
+ if DEBUG:
+ print("*** TiffImageFile._open ***")
+ print("- __first:", self.__first)
+ print("- ifh: ", ifh)
+
+ # and load the first frame
+ self._seek(0)
+
+ @property
+ def n_frames(self):
+ if self._n_frames is None:
+ current = self.tell()
+ self._seek(len(self._frame_pos))
+ while self._n_frames is None:
+ self._seek(self.tell() + 1)
+ self.seek(current)
+ return self._n_frames
+
+ @property
+ def is_animated(self):
+ return self._is_animated
+
+ def seek(self, frame):
+ """Select a given frame as current image"""
+ if not self._seek_check(frame):
+ return
+ self._seek(frame)
+ # Create a new core image object on second and
+ # subsequent frames in the image. Image may be
+ # different size/mode.
+ Image._decompression_bomb_check(self.size)
+ self.im = Image.core.new(self.mode, self.size)
+
+ def _seek(self, frame):
+ self.fp = self.__fp
+ while len(self._frame_pos) <= frame:
+ if not self.__next:
+ raise EOFError("no more images in TIFF file")
+ if DEBUG:
+ print(
+ "Seeking to frame %s, on frame %s, __next %s, location: %s"
+ % (frame, self.__frame, self.__next, self.fp.tell())
+ )
+ # reset python3 buffered io handle in case fp
+ # was passed to libtiff, invalidating the buffer
+ self.fp.tell()
+ self.fp.seek(self.__next)
+ self._frame_pos.append(self.__next)
+ if DEBUG:
+ print("Loading tags, location: %s" % self.fp.tell())
+ self.tag_v2.load(self.fp)
+ self.__next = self.tag_v2.next
+ if self.__next == 0:
+ self._n_frames = frame + 1
+ if len(self._frame_pos) == 1:
+ self._is_animated = self.__next != 0
+ self.__frame += 1
+ self.fp.seek(self._frame_pos[frame])
+ self.tag_v2.load(self.fp)
+ # fill the legacy tag/ifd entries
+ self.tag = self.ifd = ImageFileDirectory_v1.from_v2(self.tag_v2)
+ self.__frame = frame
+ self._setup()
+
+ def tell(self):
+ """Return the current frame number"""
+ return self.__frame
+
+ @property
+ def size(self):
+ return self._size
+
+ @size.setter
+ def size(self, value):
+ warnings.warn(
+ "Setting the size of a TIFF image directly is deprecated, and will"
+ " be removed in a future version. Use the resize method instead.",
+ DeprecationWarning,
+ )
+ self._size = value
+
+ def load(self):
+ if self.use_load_libtiff:
+ return self._load_libtiff()
+ return super(TiffImageFile, self).load()
+
+ def load_end(self):
+ if self._tile_orientation:
+ method = {
+ 2: Image.FLIP_LEFT_RIGHT,
+ 3: Image.ROTATE_180,
+ 4: Image.FLIP_TOP_BOTTOM,
+ 5: Image.TRANSPOSE,
+ 6: Image.ROTATE_270,
+ 7: Image.TRANSVERSE,
+ 8: Image.ROTATE_90,
+ }.get(self._tile_orientation)
+ if method is not None:
+ self.im = self.im.transpose(method)
+ self._size = self.im.size
+
+ # allow closing if we're on the first frame, there's no next
+ # This is the ImageFile.load path only, libtiff specific below.
+ if not self._is_animated:
+ self._close_exclusive_fp_after_loading = True
+
+ def _load_libtiff(self):
+ """ Overload method triggered when we detect a compressed tiff
+ Calls out to libtiff """
+
+ pixel = Image.Image.load(self)
+
+ if self.tile is None:
+ raise IOError("cannot load this image")
+ if not self.tile:
+ return pixel
+
+ self.load_prepare()
+
+ if not len(self.tile) == 1:
+ raise IOError("Not exactly one tile")
+
+ # (self._compression, (extents tuple),
+ # 0, (rawmode, self._compression, fp))
+ extents = self.tile[0][1]
+ args = list(self.tile[0][3])
+
+ # To be nice on memory footprint, if there's a
+ # file descriptor, use that instead of reading
+ # into a string in python.
+ # libtiff closes the file descriptor, so pass in a dup.
+ try:
+ fp = hasattr(self.fp, "fileno") and os.dup(self.fp.fileno())
+ # flush the file descriptor, prevents error on pypy 2.4+
+ # should also eliminate the need for fp.tell for py3
+ # in _seek
+ if hasattr(self.fp, "flush"):
+ self.fp.flush()
+ except IOError:
+ # io.BytesIO have a fileno, but returns an IOError if
+ # it doesn't use a file descriptor.
+ fp = False
+
+ if fp:
+ args[2] = fp
+
+ decoder = Image._getdecoder(
+ self.mode, "libtiff", tuple(args), self.decoderconfig
+ )
+ try:
+ decoder.setimage(self.im, extents)
+ except ValueError:
+ raise IOError("Couldn't set the image")
+
+ close_self_fp = self._exclusive_fp and not self._is_animated
+ if hasattr(self.fp, "getvalue"):
+ # We've got a stringio like thing passed in. Yay for all in memory.
+ # The decoder needs the entire file in one shot, so there's not
+ # a lot we can do here other than give it the entire file.
+ # unless we could do something like get the address of the
+ # underlying string for stringio.
+ #
+ # Rearranging for supporting byteio items, since they have a fileno
+ # that returns an IOError if there's no underlying fp. Easier to
+ # deal with here by reordering.
+ if DEBUG:
+ print("have getvalue. just sending in a string from getvalue")
+ n, err = decoder.decode(self.fp.getvalue())
+ elif fp:
+ # we've got a actual file on disk, pass in the fp.
+ if DEBUG:
+ print("have fileno, calling fileno version of the decoder.")
+ if not close_self_fp:
+ self.fp.seek(0)
+ # 4 bytes, otherwise the trace might error out
+ n, err = decoder.decode(b"fpfp")
+ else:
+ # we have something else.
+ if DEBUG:
+ print("don't have fileno or getvalue. just reading")
+ self.fp.seek(0)
+ # UNDONE -- so much for that buffer size thing.
+ n, err = decoder.decode(self.fp.read())
+
+ self.tile = []
+ self.readonly = 0
+
+ self.load_end()
+
+ # libtiff closed the fp in a, we need to close self.fp, if possible
+ if close_self_fp:
+ self.fp.close()
+ self.fp = None # might be shared
+
+ if err < 0:
+ raise IOError(err)
+
+ return Image.Image.load(self)
+
+ def _setup(self):
+ """Setup this image object based on current tags"""
+
+ if 0xBC01 in self.tag_v2:
+ raise IOError("Windows Media Photo files not yet supported")
+
+ # extract relevant tags
+ self._compression = COMPRESSION_INFO[self.tag_v2.get(COMPRESSION, 1)]
+ self._planar_configuration = self.tag_v2.get(PLANAR_CONFIGURATION, 1)
+
+ # photometric is a required tag, but not everyone is reading
+ # the specification
+ photo = self.tag_v2.get(PHOTOMETRIC_INTERPRETATION, 0)
+
+ # old style jpeg compression images most certainly are YCbCr
+ if self._compression == "tiff_jpeg":
+ photo = 6
+
+ fillorder = self.tag_v2.get(FILLORDER, 1)
+
+ if DEBUG:
+ print("*** Summary ***")
+ print("- compression:", self._compression)
+ print("- photometric_interpretation:", photo)
+ print("- planar_configuration:", self._planar_configuration)
+ print("- fill_order:", fillorder)
+ print("- YCbCr subsampling:", self.tag.get(530))
+
+ # size
+ xsize = int(self.tag_v2.get(IMAGEWIDTH))
+ ysize = int(self.tag_v2.get(IMAGELENGTH))
+ self._size = xsize, ysize
+
+ if DEBUG:
+ print("- size:", self.size)
+
+ sampleFormat = self.tag_v2.get(SAMPLEFORMAT, (1,))
+ if len(sampleFormat) > 1 and max(sampleFormat) == min(sampleFormat) == 1:
+ # SAMPLEFORMAT is properly per band, so an RGB image will
+ # be (1,1,1). But, we don't support per band pixel types,
+ # and anything more than one band is a uint8. So, just
+ # take the first element. Revisit this if adding support
+ # for more exotic images.
+ sampleFormat = (1,)
+
+ bps_tuple = self.tag_v2.get(BITSPERSAMPLE, (1,))
+ extra_tuple = self.tag_v2.get(EXTRASAMPLES, ())
+ if photo in (2, 6, 8): # RGB, YCbCr, LAB
+ bps_count = 3
+ elif photo == 5: # CMYK
+ bps_count = 4
+ else:
+ bps_count = 1
+ bps_count += len(extra_tuple)
+ # Some files have only one value in bps_tuple,
+ # while should have more. Fix it
+ if bps_count > len(bps_tuple) and len(bps_tuple) == 1:
+ bps_tuple = bps_tuple * bps_count
+
+ # mode: check photometric interpretation and bits per pixel
+ key = (
+ self.tag_v2.prefix,
+ photo,
+ sampleFormat,
+ fillorder,
+ bps_tuple,
+ extra_tuple,
+ )
+ if DEBUG:
+ print("format key:", key)
+ try:
+ self.mode, rawmode = OPEN_INFO[key]
+ except KeyError:
+ if DEBUG:
+ print("- unsupported format")
+ raise SyntaxError("unknown pixel mode")
+
+ if DEBUG:
+ print("- raw mode:", rawmode)
+ print("- pil mode:", self.mode)
+
+ self.info["compression"] = self._compression
+
+ xres = self.tag_v2.get(X_RESOLUTION, 1)
+ yres = self.tag_v2.get(Y_RESOLUTION, 1)
+
+ if xres and yres:
+ resunit = self.tag_v2.get(RESOLUTION_UNIT)
+ if resunit == 2: # dots per inch
+ self.info["dpi"] = int(xres + 0.5), int(yres + 0.5)
+ elif resunit == 3: # dots per centimeter. convert to dpi
+ self.info["dpi"] = int(xres * 2.54 + 0.5), int(yres * 2.54 + 0.5)
+ elif resunit is None: # used to default to 1, but now 2)
+ self.info["dpi"] = int(xres + 0.5), int(yres + 0.5)
+ # For backward compatibility,
+ # we also preserve the old behavior
+ self.info["resolution"] = xres, yres
+ else: # No absolute unit of measurement
+ self.info["resolution"] = xres, yres
+
+ # build tile descriptors
+ x = y = layer = 0
+ self.tile = []
+ self.use_load_libtiff = READ_LIBTIFF or self._compression != "raw"
+ if self.use_load_libtiff:
+ # Decoder expects entire file as one tile.
+ # There's a buffer size limit in load (64k)
+ # so large g4 images will fail if we use that
+ # function.
+ #
+ # Setup the one tile for the whole image, then
+ # use the _load_libtiff function.
+
+ # libtiff handles the fillmode for us, so 1;IR should
+ # actually be 1;I. Including the R double reverses the
+ # bits, so stripes of the image are reversed. See
+ # https://github.com/python-pillow/Pillow/issues/279
+ if fillorder == 2:
+ # Replace fillorder with fillorder=1
+ key = key[:3] + (1,) + key[4:]
+ if DEBUG:
+ print("format key:", key)
+ # this should always work, since all the
+ # fillorder==2 modes have a corresponding
+ # fillorder=1 mode
+ self.mode, rawmode = OPEN_INFO[key]
+ # libtiff always returns the bytes in native order.
+ # we're expecting image byte order. So, if the rawmode
+ # contains I;16, we need to convert from native to image
+ # byte order.
+ if rawmode == "I;16":
+ rawmode = "I;16N"
+ if ";16B" in rawmode:
+ rawmode = rawmode.replace(";16B", ";16N")
+ if ";16L" in rawmode:
+ rawmode = rawmode.replace(";16L", ";16N")
+
+ # Offset in the tile tuple is 0, we go from 0,0 to
+ # w,h, and we only do this once -- eds
+ a = (rawmode, self._compression, False, self.tag_v2.offset)
+ self.tile.append(("libtiff", (0, 0, xsize, ysize), 0, a))
+
+ elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2:
+ # striped image
+ if STRIPOFFSETS in self.tag_v2:
+ offsets = self.tag_v2[STRIPOFFSETS]
+ h = self.tag_v2.get(ROWSPERSTRIP, ysize)
+ w = self.size[0]
+ else:
+ # tiled image
+ offsets = self.tag_v2[TILEOFFSETS]
+ w = self.tag_v2.get(322)
+ h = self.tag_v2.get(323)
+
+ for offset in offsets:
+ if x + w > xsize:
+ stride = w * sum(bps_tuple) / 8 # bytes per line
+ else:
+ stride = 0
+
+ tile_rawmode = rawmode
+ if self._planar_configuration == 2:
+ # each band on it's own layer
+ tile_rawmode = rawmode[layer]
+ # adjust stride width accordingly
+ stride /= bps_count
+
+ a = (tile_rawmode, int(stride), 1)
+ self.tile.append(
+ (
+ self._compression,
+ (x, y, min(x + w, xsize), min(y + h, ysize)),
+ offset,
+ a,
+ )
+ )
+ x = x + w
+ if x >= self.size[0]:
+ x, y = 0, y + h
+ if y >= self.size[1]:
+ x = y = 0
+ layer += 1
+ else:
+ if DEBUG:
+ print("- unsupported data organization")
+ raise SyntaxError("unknown data organization")
+
+ # Fix up info.
+ if ICCPROFILE in self.tag_v2:
+ self.info["icc_profile"] = self.tag_v2[ICCPROFILE]
+
+ # fixup palette descriptor
+
+ if self.mode in ["P", "PA"]:
+ palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]]
+ self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
+
+ self._tile_orientation = self.tag_v2.get(0x0112)
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+#
+# --------------------------------------------------------------------
+# Write TIFF files
+
+# little endian is default except for image modes with
+# explicit big endian byte-order
+
+SAVE_INFO = {
+ # mode => rawmode, byteorder, photometrics,
+ # sampleformat, bitspersample, extra
+ "1": ("1", II, 1, 1, (1,), None),
+ "L": ("L", II, 1, 1, (8,), None),
+ "LA": ("LA", II, 1, 1, (8, 8), 2),
+ "P": ("P", II, 3, 1, (8,), None),
+ "PA": ("PA", II, 3, 1, (8, 8), 2),
+ "I": ("I;32S", II, 1, 2, (32,), None),
+ "I;16": ("I;16", II, 1, 1, (16,), None),
+ "I;16S": ("I;16S", II, 1, 2, (16,), None),
+ "F": ("F;32F", II, 1, 3, (32,), None),
+ "RGB": ("RGB", II, 2, 1, (8, 8, 8), None),
+ "RGBX": ("RGBX", II, 2, 1, (8, 8, 8, 8), 0),
+ "RGBA": ("RGBA", II, 2, 1, (8, 8, 8, 8), 2),
+ "CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None),
+ "YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None),
+ "LAB": ("LAB", II, 8, 1, (8, 8, 8), None),
+ "I;32BS": ("I;32BS", MM, 1, 2, (32,), None),
+ "I;16B": ("I;16B", MM, 1, 1, (16,), None),
+ "I;16BS": ("I;16BS", MM, 1, 2, (16,), None),
+ "F;32BF": ("F;32BF", MM, 1, 3, (32,), None),
+}
+
+
+def _save(im, fp, filename):
+
+ try:
+ rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
+ except KeyError:
+ raise IOError("cannot write mode %s as TIFF" % im.mode)
+
+ ifd = ImageFileDirectory_v2(prefix=prefix)
+
+ compression = im.encoderinfo.get("compression", im.info.get("compression"))
+ if compression is None:
+ compression = "raw"
+
+ libtiff = WRITE_LIBTIFF or compression != "raw"
+
+ # required for color libtiff images
+ ifd[PLANAR_CONFIGURATION] = getattr(im, "_planar_configuration", 1)
+
+ ifd[IMAGEWIDTH] = im.size[0]
+ ifd[IMAGELENGTH] = im.size[1]
+
+ # write any arbitrary tags passed in as an ImageFileDirectory
+ info = im.encoderinfo.get("tiffinfo", {})
+ if DEBUG:
+ print("Tiffinfo Keys: %s" % list(info))
+ if isinstance(info, ImageFileDirectory_v1):
+ info = info.to_v2()
+ for key in info:
+ ifd[key] = info.get(key)
+ try:
+ ifd.tagtype[key] = info.tagtype[key]
+ except Exception:
+ pass # might not be an IFD. Might not have populated type
+
+ # additions written by Greg Couch, gregc@cgl.ucsf.edu
+ # inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
+ if hasattr(im, "tag_v2"):
+ # preserve tags from original TIFF image file
+ for key in (
+ RESOLUTION_UNIT,
+ X_RESOLUTION,
+ Y_RESOLUTION,
+ IPTC_NAA_CHUNK,
+ PHOTOSHOP_CHUNK,
+ XMP,
+ ):
+ if key in im.tag_v2:
+ ifd[key] = im.tag_v2[key]
+ ifd.tagtype[key] = im.tag_v2.tagtype[key]
+
+ # preserve ICC profile (should also work when saving other formats
+ # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
+ if "icc_profile" in im.info:
+ ifd[ICCPROFILE] = im.info["icc_profile"]
+
+ for key, name in [
+ (IMAGEDESCRIPTION, "description"),
+ (X_RESOLUTION, "resolution"),
+ (Y_RESOLUTION, "resolution"),
+ (X_RESOLUTION, "x_resolution"),
+ (Y_RESOLUTION, "y_resolution"),
+ (RESOLUTION_UNIT, "resolution_unit"),
+ (SOFTWARE, "software"),
+ (DATE_TIME, "date_time"),
+ (ARTIST, "artist"),
+ (COPYRIGHT, "copyright"),
+ ]:
+ if name in im.encoderinfo:
+ ifd[key] = im.encoderinfo[name]
+
+ dpi = im.encoderinfo.get("dpi")
+ if dpi:
+ ifd[RESOLUTION_UNIT] = 2
+ ifd[X_RESOLUTION] = int(dpi[0] + 0.5)
+ ifd[Y_RESOLUTION] = int(dpi[1] + 0.5)
+
+ if bits != (1,):
+ ifd[BITSPERSAMPLE] = bits
+ if len(bits) != 1:
+ ifd[SAMPLESPERPIXEL] = len(bits)
+ if extra is not None:
+ ifd[EXTRASAMPLES] = extra
+ if format != 1:
+ ifd[SAMPLEFORMAT] = format
+
+ ifd[PHOTOMETRIC_INTERPRETATION] = photo
+
+ if im.mode in ["P", "PA"]:
+ lut = im.im.getpalette("RGB", "RGB;L")
+ ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)
+ # data orientation
+ stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8)
+ ifd[ROWSPERSTRIP] = im.size[1]
+ ifd[STRIPBYTECOUNTS] = stride * im.size[1]
+ ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
+ # no compression by default:
+ ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)
+
+ if libtiff:
+ if "quality" in im.encoderinfo:
+ quality = im.encoderinfo["quality"]
+ if not isinstance(quality, int) or quality < 0 or quality > 100:
+ raise ValueError("Invalid quality setting")
+ if compression != "jpeg":
+ raise ValueError(
+ "quality setting only supported for 'jpeg' compression"
+ )
+ ifd[JPEGQUALITY] = quality
+
+ if DEBUG:
+ print("Saving using libtiff encoder")
+ print("Items: %s" % sorted(ifd.items()))
+ _fp = 0
+ if hasattr(fp, "fileno"):
+ try:
+ fp.seek(0)
+ _fp = os.dup(fp.fileno())
+ except io.UnsupportedOperation:
+ pass
+
+ # optional types for non core tags
+ types = {}
+ # SAMPLEFORMAT is determined by the image format and should not be copied
+ # from legacy_ifd.
+ # STRIPOFFSETS and STRIPBYTECOUNTS are added by the library
+ # based on the data in the strip.
+ # The other tags expect arrays with a certain length (fixed or depending on
+ # BITSPERSAMPLE, etc), passing arrays with a different length will result in
+ # segfaults. Block these tags until we add extra validation.
+ blocklist = [
+ COLORMAP,
+ REFERENCEBLACKWHITE,
+ SAMPLEFORMAT,
+ STRIPBYTECOUNTS,
+ STRIPOFFSETS,
+ TRANSFERFUNCTION,
+ ]
+
+ atts = {}
+ # bits per sample is a single short in the tiff directory, not a list.
+ atts[BITSPERSAMPLE] = bits[0]
+ # Merge the ones that we have with (optional) more bits from
+ # the original file, e.g x,y resolution so that we can
+ # save(load('')) == original file.
+ legacy_ifd = {}
+ if hasattr(im, "tag"):
+ legacy_ifd = im.tag.to_v2()
+ for tag, value in itertools.chain(
+ ifd.items(), getattr(im, "tag_v2", {}).items(), legacy_ifd.items()
+ ):
+ # Libtiff can only process certain core items without adding
+ # them to the custom dictionary.
+ # Custom items are supported for int, float, unicode, string and byte
+ # values. Other types and tuples require a tagtype.
+ if tag not in TiffTags.LIBTIFF_CORE:
+ if TiffTags.lookup(tag).type == TiffTags.UNDEFINED:
+ continue
+ if distutils.version.StrictVersion(
+ _libtiff_version()
+ ) < distutils.version.StrictVersion("4.0"):
+ continue
+
+ if tag in ifd.tagtype:
+ types[tag] = ifd.tagtype[tag]
+ elif not (
+ isinstance(value, (int, float, str, bytes))
+ or (not py3 and isinstance(value, unicode)) # noqa: F821
+ ):
+ continue
+ if tag not in atts and tag not in blocklist:
+ if isinstance(value, str if py3 else unicode): # noqa: F821
+ atts[tag] = value.encode("ascii", "replace") + b"\0"
+ elif isinstance(value, IFDRational):
+ atts[tag] = float(value)
+ else:
+ atts[tag] = value
+
+ if DEBUG:
+ print("Converted items: %s" % sorted(atts.items()))
+
+ # libtiff always expects the bytes in native order.
+ # we're storing image byte order. So, if the rawmode
+ # contains I;16, we need to convert from native to image
+ # byte order.
+ if im.mode in ("I;16B", "I;16"):
+ rawmode = "I;16N"
+
+ # Pass tags as sorted list so that the tags are set in a fixed order.
+ # This is required by libtiff for some tags. For example, the JPEGQUALITY
+ # pseudo tag requires that the COMPRESS tag was already set.
+ tags = list(atts.items())
+ tags.sort()
+ a = (rawmode, compression, _fp, filename, tags, types)
+ e = Image._getencoder(im.mode, "libtiff", a, im.encoderconfig)
+ e.setimage(im.im, (0, 0) + im.size)
+ while True:
+ # undone, change to self.decodermaxblock:
+ l, s, d = e.encode(16 * 1024)
+ if not _fp:
+ fp.write(d)
+ if s:
+ break
+ if s < 0:
+ raise IOError("encoder error %d when writing image file" % s)
+
+ else:
+ offset = ifd.save(fp)
+
+ ImageFile._save(
+ im, fp, [("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))]
+ )
+
+ # -- helper for multi-page save --
+ if "_debug_multipage" in im.encoderinfo:
+ # just to access o32 and o16 (using correct byte order)
+ im._debug_multipage = ifd
+
+
+class AppendingTiffWriter:
+ fieldSizes = [
+ 0, # None
+ 1, # byte
+ 1, # ascii
+ 2, # short
+ 4, # long
+ 8, # rational
+ 1, # sbyte
+ 1, # undefined
+ 2, # sshort
+ 4, # slong
+ 8, # srational
+ 4, # float
+ 8, # double
+ ]
+
+ # StripOffsets = 273
+ # FreeOffsets = 288
+ # TileOffsets = 324
+ # JPEGQTables = 519
+ # JPEGDCTables = 520
+ # JPEGACTables = 521
+ Tags = {273, 288, 324, 519, 520, 521}
+
+ def __init__(self, fn, new=False):
+ if hasattr(fn, "read"):
+ self.f = fn
+ self.close_fp = False
+ else:
+ self.name = fn
+ self.close_fp = True
+ try:
+ self.f = io.open(fn, "w+b" if new else "r+b")
+ except IOError:
+ self.f = io.open(fn, "w+b")
+ self.beginning = self.f.tell()
+ self.setup()
+
+ def setup(self):
+ # Reset everything.
+ self.f.seek(self.beginning, os.SEEK_SET)
+
+ self.whereToWriteNewIFDOffset = None
+ self.offsetOfNewPage = 0
+
+ self.IIMM = IIMM = self.f.read(4)
+ if not IIMM:
+ # empty file - first page
+ self.isFirst = True
+ return
+
+ self.isFirst = False
+ if IIMM == b"II\x2a\x00":
+ self.setEndian("<")
+ elif IIMM == b"MM\x00\x2a":
+ self.setEndian(">")
+ else:
+ raise RuntimeError("Invalid TIFF file header")
+
+ self.skipIFDs()
+ self.goToEnd()
+
+ def finalize(self):
+ if self.isFirst:
+ return
+
+ # fix offsets
+ self.f.seek(self.offsetOfNewPage)
+
+ IIMM = self.f.read(4)
+ if not IIMM:
+ # raise RuntimeError("nothing written into new page")
+ # Make it easy to finish a frame without committing to a new one.
+ return
+
+ if IIMM != self.IIMM:
+ raise RuntimeError("IIMM of new page doesn't match IIMM of first page")
+
+ IFDoffset = self.readLong()
+ IFDoffset += self.offsetOfNewPage
+ self.f.seek(self.whereToWriteNewIFDOffset)
+ self.writeLong(IFDoffset)
+ self.f.seek(IFDoffset)
+ self.fixIFD()
+
+ def newFrame(self):
+ # Call this to finish a frame.
+ self.finalize()
+ self.setup()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ if self.close_fp:
+ self.close()
+ return False
+
+ def tell(self):
+ return self.f.tell() - self.offsetOfNewPage
+
+ def seek(self, offset, whence=io.SEEK_SET):
+ if whence == os.SEEK_SET:
+ offset += self.offsetOfNewPage
+
+ self.f.seek(offset, whence)
+ return self.tell()
+
+ def goToEnd(self):
+ self.f.seek(0, os.SEEK_END)
+ pos = self.f.tell()
+
+ # pad to 16 byte boundary
+ padBytes = 16 - pos % 16
+ if 0 < padBytes < 16:
+ self.f.write(bytes(bytearray(padBytes)))
+ self.offsetOfNewPage = self.f.tell()
+
+ def setEndian(self, endian):
+ self.endian = endian
+ self.longFmt = self.endian + "L"
+ self.shortFmt = self.endian + "H"
+ self.tagFormat = self.endian + "HHL"
+
+ def skipIFDs(self):
+ while True:
+ IFDoffset = self.readLong()
+ if IFDoffset == 0:
+ self.whereToWriteNewIFDOffset = self.f.tell() - 4
+ break
+
+ self.f.seek(IFDoffset)
+ numTags = self.readShort()
+ self.f.seek(numTags * 12, os.SEEK_CUR)
+
+ def write(self, data):
+ return self.f.write(data)
+
+ def readShort(self):
+ (value,) = struct.unpack(self.shortFmt, self.f.read(2))
+ return value
+
+ def readLong(self):
+ (value,) = struct.unpack(self.longFmt, self.f.read(4))
+ return value
+
+ def rewriteLastShortToLong(self, value):
+ self.f.seek(-2, os.SEEK_CUR)
+ bytesWritten = self.f.write(struct.pack(self.longFmt, value))
+ if bytesWritten is not None and bytesWritten != 4:
+ raise RuntimeError("wrote only %u bytes but wanted 4" % bytesWritten)
+
+ def rewriteLastShort(self, value):
+ self.f.seek(-2, os.SEEK_CUR)
+ bytesWritten = self.f.write(struct.pack(self.shortFmt, value))
+ if bytesWritten is not None and bytesWritten != 2:
+ raise RuntimeError("wrote only %u bytes but wanted 2" % bytesWritten)
+
+ def rewriteLastLong(self, value):
+ self.f.seek(-4, os.SEEK_CUR)
+ bytesWritten = self.f.write(struct.pack(self.longFmt, value))
+ if bytesWritten is not None and bytesWritten != 4:
+ raise RuntimeError("wrote only %u bytes but wanted 4" % bytesWritten)
+
+ def writeShort(self, value):
+ bytesWritten = self.f.write(struct.pack(self.shortFmt, value))
+ if bytesWritten is not None and bytesWritten != 2:
+ raise RuntimeError("wrote only %u bytes but wanted 2" % bytesWritten)
+
+ def writeLong(self, value):
+ bytesWritten = self.f.write(struct.pack(self.longFmt, value))
+ if bytesWritten is not None and bytesWritten != 4:
+ raise RuntimeError("wrote only %u bytes but wanted 4" % bytesWritten)
+
+ def close(self):
+ self.finalize()
+ self.f.close()
+
+ def fixIFD(self):
+ numTags = self.readShort()
+
+ for i in range(numTags):
+ tag, fieldType, count = struct.unpack(self.tagFormat, self.f.read(8))
+
+ fieldSize = self.fieldSizes[fieldType]
+ totalSize = fieldSize * count
+ isLocal = totalSize <= 4
+ if not isLocal:
+ offset = self.readLong()
+ offset += self.offsetOfNewPage
+ self.rewriteLastLong(offset)
+
+ if tag in self.Tags:
+ curPos = self.f.tell()
+
+ if isLocal:
+ self.fixOffsets(
+ count, isShort=(fieldSize == 2), isLong=(fieldSize == 4)
+ )
+ self.f.seek(curPos + 4)
+ else:
+ self.f.seek(offset)
+ self.fixOffsets(
+ count, isShort=(fieldSize == 2), isLong=(fieldSize == 4)
+ )
+ self.f.seek(curPos)
+
+ offset = curPos = None
+
+ elif isLocal:
+ # skip the locally stored value that is not an offset
+ self.f.seek(4, os.SEEK_CUR)
+
+ def fixOffsets(self, count, isShort=False, isLong=False):
+ if not isShort and not isLong:
+ raise RuntimeError("offset is neither short nor long")
+
+ for i in range(count):
+ offset = self.readShort() if isShort else self.readLong()
+ offset += self.offsetOfNewPage
+ if isShort and offset >= 65536:
+ # offset is now too large - we must convert shorts to longs
+ if count != 1:
+ raise RuntimeError("not implemented") # XXX TODO
+
+ # simple case - the offset is just one and therefore it is
+ # local (not referenced with another offset)
+ self.rewriteLastShortToLong(offset)
+ self.f.seek(-10, os.SEEK_CUR)
+ self.writeShort(TiffTags.LONG) # rewrite the type to LONG
+ self.f.seek(8, os.SEEK_CUR)
+ elif isShort:
+ self.rewriteLastShort(offset)
+ else:
+ self.rewriteLastLong(offset)
+
+
+def _save_all(im, fp, filename):
+ encoderinfo = im.encoderinfo.copy()
+ encoderconfig = im.encoderconfig
+ append_images = list(encoderinfo.get("append_images", []))
+ if not hasattr(im, "n_frames") and not append_images:
+ return _save(im, fp, filename)
+
+ cur_idx = im.tell()
+ try:
+ with AppendingTiffWriter(fp) as tf:
+ for ims in [im] + append_images:
+ ims.encoderinfo = encoderinfo
+ ims.encoderconfig = encoderconfig
+ if not hasattr(ims, "n_frames"):
+ nfr = 1
+ else:
+ nfr = ims.n_frames
+
+ for idx in range(nfr):
+ ims.seek(idx)
+ ims.load()
+ _save(ims, tf, filename)
+ tf.newFrame()
+ finally:
+ im.seek(cur_idx)
+
+
+#
+# --------------------------------------------------------------------
+# Register
+
+Image.register_open(TiffImageFile.format, TiffImageFile, _accept)
+Image.register_save(TiffImageFile.format, _save)
+Image.register_save_all(TiffImageFile.format, _save_all)
+
+Image.register_extensions(TiffImageFile.format, [".tif", ".tiff"])
+
+Image.register_mime(TiffImageFile.format, "image/tiff")
diff --git a/contrib/python/Pillow/py2/PIL/TiffTags.py b/contrib/python/Pillow/py2/PIL/TiffTags.py
new file mode 100644
index 0000000000..82719db0ef
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/TiffTags.py
@@ -0,0 +1,499 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# TIFF tags
+#
+# This module provides clear-text names for various well-known
+# TIFF tags. the TIFF codec works just fine without it.
+#
+# Copyright (c) Secret Labs AB 1999.
+#
+# See the README file for information on usage and redistribution.
+#
+
+##
+# This module provides constants and clear-text names for various
+# well-known TIFF tags.
+##
+
+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):
+ return super(TagInfo, cls).__new__(cls, value, name, type, length, enum or {})
+
+ def cvt_enum(self, value):
+ # Using get will call hash(value), which can be expensive
+ # for some types (e.g. Fraction). Since self.enum is rarely
+ # used, it's usually better to test it first.
+ return self.enum.get(value, value) if self.enum else value
+
+
+def lookup(tag):
+ """
+ :param tag: Integer tag number
+ :returns: Taginfo namedtuple, From the TAGS_V2 info if possible,
+ otherwise just populating the value and name from TAGS.
+ If the tag is not recognized, "unknown" is returned for the name
+
+ """
+
+ return TAGS_V2.get(tag, TagInfo(tag, TAGS.get(tag, "unknown")))
+
+
+##
+# Map tag numbers to tag info.
+#
+# id: (Name, Type, Length, enum_values)
+#
+# The length here differs from the length in the tiff spec. For
+# numbers, the tiff spec is for the number of fields returned. We
+# agree here. For string-like types, the tiff spec uses the length of
+# field in bytes. In Pillow, we are using the number of expected
+# fields, in general 1 for string-like types.
+
+
+BYTE = 1
+ASCII = 2
+SHORT = 3
+LONG = 4
+RATIONAL = 5
+SIGNED_BYTE = 6
+UNDEFINED = 7
+SIGNED_SHORT = 8
+SIGNED_LONG = 9
+SIGNED_RATIONAL = 10
+FLOAT = 11
+DOUBLE = 12
+
+TAGS_V2 = {
+ 254: ("NewSubfileType", LONG, 1),
+ 255: ("SubfileType", SHORT, 1),
+ 256: ("ImageWidth", LONG, 1),
+ 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,
+ },
+ ),
+ 262: (
+ "PhotometricInterpretation",
+ SHORT,
+ 1,
+ {
+ "WhiteIsZero": 0,
+ "BlackIsZero": 1,
+ "RGB": 2,
+ "RGB Palette": 3,
+ "Transparency Mask": 4,
+ "CMYK": 5,
+ "YCbCr": 6,
+ "CieLAB": 8,
+ "CFA": 32803, # TIFF/EP, Adobe DNG
+ "LinearRaw": 32892, # Adobe DNG
+ },
+ ),
+ 263: ("Threshholding", SHORT, 1),
+ 264: ("CellWidth", SHORT, 1),
+ 265: ("CellLength", SHORT, 1),
+ 266: ("FillOrder", SHORT, 1),
+ 269: ("DocumentName", ASCII, 1),
+ 270: ("ImageDescription", ASCII, 1),
+ 271: ("Make", ASCII, 1),
+ 272: ("Model", ASCII, 1),
+ 273: ("StripOffsets", LONG, 0),
+ 274: ("Orientation", SHORT, 1),
+ 277: ("SamplesPerPixel", SHORT, 1),
+ 278: ("RowsPerStrip", LONG, 1),
+ 279: ("StripByteCounts", LONG, 0),
+ 280: ("MinSampleValue", LONG, 0),
+ 281: ("MaxSampleValue", SHORT, 0),
+ 282: ("XResolution", RATIONAL, 1),
+ 283: ("YResolution", RATIONAL, 1),
+ 284: ("PlanarConfiguration", SHORT, 1, {"Contiguous": 1, "Separate": 2}),
+ 285: ("PageName", ASCII, 1),
+ 286: ("XPosition", RATIONAL, 1),
+ 287: ("YPosition", RATIONAL, 1),
+ 288: ("FreeOffsets", LONG, 1),
+ 289: ("FreeByteCounts", LONG, 1),
+ 290: ("GrayResponseUnit", SHORT, 1),
+ 291: ("GrayResponseCurve", SHORT, 0),
+ 292: ("T4Options", LONG, 1),
+ 293: ("T6Options", LONG, 1),
+ 296: ("ResolutionUnit", SHORT, 1, {"none": 1, "inch": 2, "cm": 3}),
+ 297: ("PageNumber", SHORT, 2),
+ 301: ("TransferFunction", SHORT, 0),
+ 305: ("Software", ASCII, 1),
+ 306: ("DateTime", ASCII, 1),
+ 315: ("Artist", ASCII, 1),
+ 316: ("HostComputer", ASCII, 1),
+ 317: ("Predictor", SHORT, 1, {"none": 1, "Horizontal Differencing": 2}),
+ 318: ("WhitePoint", RATIONAL, 2),
+ 319: ("PrimaryChromaticities", RATIONAL, 6),
+ 320: ("ColorMap", SHORT, 0),
+ 321: ("HalftoneHints", SHORT, 2),
+ 322: ("TileWidth", LONG, 1),
+ 323: ("TileLength", LONG, 1),
+ 324: ("TileOffsets", LONG, 0),
+ 325: ("TileByteCounts", LONG, 0),
+ 332: ("InkSet", SHORT, 1),
+ 333: ("InkNames", ASCII, 1),
+ 334: ("NumberOfInks", SHORT, 1),
+ 336: ("DotRange", SHORT, 0),
+ 337: ("TargetPrinter", ASCII, 1),
+ 338: ("ExtraSamples", SHORT, 0),
+ 339: ("SampleFormat", SHORT, 0),
+ 340: ("SMinSampleValue", DOUBLE, 0),
+ 341: ("SMaxSampleValue", DOUBLE, 0),
+ 342: ("TransferRange", SHORT, 6),
+ 347: ("JPEGTables", UNDEFINED, 1),
+ # obsolete JPEG tags
+ 512: ("JPEGProc", SHORT, 1),
+ 513: ("JPEGInterchangeFormat", LONG, 1),
+ 514: ("JPEGInterchangeFormatLength", LONG, 1),
+ 515: ("JPEGRestartInterval", SHORT, 1),
+ 517: ("JPEGLosslessPredictors", SHORT, 0),
+ 518: ("JPEGPointTransforms", SHORT, 0),
+ 519: ("JPEGQTables", LONG, 0),
+ 520: ("JPEGDCTables", LONG, 0),
+ 521: ("JPEGACTables", LONG, 0),
+ 529: ("YCbCrCoefficients", RATIONAL, 3),
+ 530: ("YCbCrSubSampling", SHORT, 2),
+ 531: ("YCbCrPositioning", SHORT, 1),
+ 532: ("ReferenceBlackWhite", RATIONAL, 6),
+ 700: ("XMP", BYTE, 0),
+ 33432: ("Copyright", ASCII, 1),
+ 33723: ("IptcNaaInfo", UNDEFINED, 0),
+ 34377: ("PhotoshopInfo", BYTE, 0),
+ # FIXME add more tags here
+ 34665: ("ExifIFD", LONG, 1),
+ 34675: ("ICCProfile", UNDEFINED, 1),
+ 34853: ("GPSInfoIFD", BYTE, 1),
+ # MPInfo
+ 45056: ("MPFVersion", UNDEFINED, 1),
+ 45057: ("NumberOfImages", LONG, 1),
+ 45058: ("MPEntry", UNDEFINED, 1),
+ 45059: ("ImageUIDList", UNDEFINED, 0), # UNDONE, check
+ 45060: ("TotalFrames", LONG, 1),
+ 45313: ("MPIndividualNum", LONG, 1),
+ 45569: ("PanOrientation", LONG, 1),
+ 45570: ("PanOverlap_H", RATIONAL, 1),
+ 45571: ("PanOverlap_V", RATIONAL, 1),
+ 45572: ("BaseViewpointNum", LONG, 1),
+ 45573: ("ConvergenceAngle", SIGNED_RATIONAL, 1),
+ 45574: ("BaselineLength", RATIONAL, 1),
+ 45575: ("VerticalDivergence", SIGNED_RATIONAL, 1),
+ 45576: ("AxisDistance_X", SIGNED_RATIONAL, 1),
+ 45577: ("AxisDistance_Y", SIGNED_RATIONAL, 1),
+ 45578: ("AxisDistance_Z", SIGNED_RATIONAL, 1),
+ 45579: ("YawAngle", SIGNED_RATIONAL, 1),
+ 45580: ("PitchAngle", SIGNED_RATIONAL, 1),
+ 45581: ("RollAngle", SIGNED_RATIONAL, 1),
+ 50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}),
+ 50780: ("BestQualityScale", RATIONAL, 1),
+ 50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one
+ 50839: ("ImageJMetaData", UNDEFINED, 1), # see Issue #2006
+}
+
+# Legacy Tags structure
+# these tags aren't included above, but were in the previous versions
+TAGS = {
+ 347: "JPEGTables",
+ 700: "XMP",
+ # Additional Exif Info
+ 32932: "Wang Annotation",
+ 33434: "ExposureTime",
+ 33437: "FNumber",
+ 33445: "MD FileTag",
+ 33446: "MD ScalePixel",
+ 33447: "MD ColorTable",
+ 33448: "MD LabName",
+ 33449: "MD SampleInfo",
+ 33450: "MD PrepDate",
+ 33451: "MD PrepTime",
+ 33452: "MD FileUnits",
+ 33550: "ModelPixelScaleTag",
+ 33723: "IptcNaaInfo",
+ 33918: "INGR Packet Data Tag",
+ 33919: "INGR Flag Registers",
+ 33920: "IrasB Transformation Matrix",
+ 33922: "ModelTiepointTag",
+ 34264: "ModelTransformationTag",
+ 34377: "PhotoshopInfo",
+ 34735: "GeoKeyDirectoryTag",
+ 34736: "GeoDoubleParamsTag",
+ 34737: "GeoAsciiParamsTag",
+ 34850: "ExposureProgram",
+ 34852: "SpectralSensitivity",
+ 34855: "ISOSpeedRatings",
+ 34856: "OECF",
+ 34864: "SensitivityType",
+ 34865: "StandardOutputSensitivity",
+ 34866: "RecommendedExposureIndex",
+ 34867: "ISOSpeed",
+ 34868: "ISOSpeedLatitudeyyy",
+ 34869: "ISOSpeedLatitudezzz",
+ 34908: "HylaFAX FaxRecvParams",
+ 34909: "HylaFAX FaxSubAddress",
+ 34910: "HylaFAX FaxRecvTime",
+ 36864: "ExifVersion",
+ 36867: "DateTimeOriginal",
+ 36868: "DateTImeDigitized",
+ 37121: "ComponentsConfiguration",
+ 37122: "CompressedBitsPerPixel",
+ 37724: "ImageSourceData",
+ 37377: "ShutterSpeedValue",
+ 37378: "ApertureValue",
+ 37379: "BrightnessValue",
+ 37380: "ExposureBiasValue",
+ 37381: "MaxApertureValue",
+ 37382: "SubjectDistance",
+ 37383: "MeteringMode",
+ 37384: "LightSource",
+ 37385: "Flash",
+ 37386: "FocalLength",
+ 37396: "SubjectArea",
+ 37500: "MakerNote",
+ 37510: "UserComment",
+ 37520: "SubSec",
+ 37521: "SubSecTimeOriginal",
+ 37522: "SubsecTimeDigitized",
+ 40960: "FlashPixVersion",
+ 40961: "ColorSpace",
+ 40962: "PixelXDimension",
+ 40963: "PixelYDimension",
+ 40964: "RelatedSoundFile",
+ 40965: "InteroperabilityIFD",
+ 41483: "FlashEnergy",
+ 41484: "SpatialFrequencyResponse",
+ 41486: "FocalPlaneXResolution",
+ 41487: "FocalPlaneYResolution",
+ 41488: "FocalPlaneResolutionUnit",
+ 41492: "SubjectLocation",
+ 41493: "ExposureIndex",
+ 41495: "SensingMethod",
+ 41728: "FileSource",
+ 41729: "SceneType",
+ 41730: "CFAPattern",
+ 41985: "CustomRendered",
+ 41986: "ExposureMode",
+ 41987: "WhiteBalance",
+ 41988: "DigitalZoomRatio",
+ 41989: "FocalLengthIn35mmFilm",
+ 41990: "SceneCaptureType",
+ 41991: "GainControl",
+ 41992: "Contrast",
+ 41993: "Saturation",
+ 41994: "Sharpness",
+ 41995: "DeviceSettingDescription",
+ 41996: "SubjectDistanceRange",
+ 42016: "ImageUniqueID",
+ 42032: "CameraOwnerName",
+ 42033: "BodySerialNumber",
+ 42034: "LensSpecification",
+ 42035: "LensMake",
+ 42036: "LensModel",
+ 42037: "LensSerialNumber",
+ 42112: "GDAL_METADATA",
+ 42113: "GDAL_NODATA",
+ 42240: "Gamma",
+ 50215: "Oce Scanjob Description",
+ 50216: "Oce Application Selector",
+ 50217: "Oce Identification Number",
+ 50218: "Oce ImageLogic Characteristics",
+ # Adobe DNG
+ 50706: "DNGVersion",
+ 50707: "DNGBackwardVersion",
+ 50708: "UniqueCameraModel",
+ 50709: "LocalizedCameraModel",
+ 50710: "CFAPlaneColor",
+ 50711: "CFALayout",
+ 50712: "LinearizationTable",
+ 50713: "BlackLevelRepeatDim",
+ 50714: "BlackLevel",
+ 50715: "BlackLevelDeltaH",
+ 50716: "BlackLevelDeltaV",
+ 50717: "WhiteLevel",
+ 50718: "DefaultScale",
+ 50719: "DefaultCropOrigin",
+ 50720: "DefaultCropSize",
+ 50721: "ColorMatrix1",
+ 50722: "ColorMatrix2",
+ 50723: "CameraCalibration1",
+ 50724: "CameraCalibration2",
+ 50725: "ReductionMatrix1",
+ 50726: "ReductionMatrix2",
+ 50727: "AnalogBalance",
+ 50728: "AsShotNeutral",
+ 50729: "AsShotWhiteXY",
+ 50730: "BaselineExposure",
+ 50731: "BaselineNoise",
+ 50732: "BaselineSharpness",
+ 50733: "BayerGreenSplit",
+ 50734: "LinearResponseLimit",
+ 50735: "CameraSerialNumber",
+ 50736: "LensInfo",
+ 50737: "ChromaBlurRadius",
+ 50738: "AntiAliasStrength",
+ 50740: "DNGPrivateData",
+ 50778: "CalibrationIlluminant1",
+ 50779: "CalibrationIlluminant2",
+ 50784: "Alias Layer Metadata",
+}
+
+
+def _populate():
+ for k, v in TAGS_V2.items():
+ # Populate legacy structure.
+ TAGS[k] = v[0]
+ if len(v) == 4:
+ for sk, sv in v[3].items():
+ TAGS[(k, sv)] = sk
+
+ TAGS_V2[k] = TagInfo(k, *v)
+
+
+_populate()
+##
+# Map type numbers to type names -- defined in ImageFileDirectory.
+
+TYPES = {}
+
+# was:
+# TYPES = {
+# 1: "byte",
+# 2: "ascii",
+# 3: "short",
+# 4: "long",
+# 5: "rational",
+# 6: "signed byte",
+# 7: "undefined",
+# 8: "signed short",
+# 9: "signed long",
+# 10: "signed rational",
+# 11: "float",
+# 12: "double",
+# }
+
+#
+# These tags are handled by default in libtiff, without
+# adding to the custom dictionary. From tif_dir.c, searching for
+# case TIFFTAG in the _TIFFVSetField function:
+# Line: item.
+# 148: case TIFFTAG_SUBFILETYPE:
+# 151: case TIFFTAG_IMAGEWIDTH:
+# 154: case TIFFTAG_IMAGELENGTH:
+# 157: case TIFFTAG_BITSPERSAMPLE:
+# 181: case TIFFTAG_COMPRESSION:
+# 202: case TIFFTAG_PHOTOMETRIC:
+# 205: case TIFFTAG_THRESHHOLDING:
+# 208: case TIFFTAG_FILLORDER:
+# 214: case TIFFTAG_ORIENTATION:
+# 221: case TIFFTAG_SAMPLESPERPIXEL:
+# 228: case TIFFTAG_ROWSPERSTRIP:
+# 238: case TIFFTAG_MINSAMPLEVALUE:
+# 241: case TIFFTAG_MAXSAMPLEVALUE:
+# 244: case TIFFTAG_SMINSAMPLEVALUE:
+# 247: case TIFFTAG_SMAXSAMPLEVALUE:
+# 250: case TIFFTAG_XRESOLUTION:
+# 256: case TIFFTAG_YRESOLUTION:
+# 262: case TIFFTAG_PLANARCONFIG:
+# 268: case TIFFTAG_XPOSITION:
+# 271: case TIFFTAG_YPOSITION:
+# 274: case TIFFTAG_RESOLUTIONUNIT:
+# 280: case TIFFTAG_PAGENUMBER:
+# 284: case TIFFTAG_HALFTONEHINTS:
+# 288: case TIFFTAG_COLORMAP:
+# 294: case TIFFTAG_EXTRASAMPLES:
+# 298: case TIFFTAG_MATTEING:
+# 305: case TIFFTAG_TILEWIDTH:
+# 316: case TIFFTAG_TILELENGTH:
+# 327: case TIFFTAG_TILEDEPTH:
+# 333: case TIFFTAG_DATATYPE:
+# 344: case TIFFTAG_SAMPLEFORMAT:
+# 361: case TIFFTAG_IMAGEDEPTH:
+# 364: case TIFFTAG_SUBIFD:
+# 376: case TIFFTAG_YCBCRPOSITIONING:
+# 379: case TIFFTAG_YCBCRSUBSAMPLING:
+# 383: case TIFFTAG_TRANSFERFUNCTION:
+# 389: case TIFFTAG_REFERENCEBLACKWHITE:
+# 393: case TIFFTAG_INKNAMES:
+
+# Following pseudo-tags are also handled by default in libtiff:
+# TIFFTAG_JPEGQUALITY 65537
+
+# some of these are not in our TAGS_V2 dict and were included from tiff.h
+
+# This list also exists in encode.c
+LIBTIFF_CORE = {
+ 255,
+ 256,
+ 257,
+ 258,
+ 259,
+ 262,
+ 263,
+ 266,
+ 274,
+ 277,
+ 278,
+ 280,
+ 281,
+ 340,
+ 341,
+ 282,
+ 283,
+ 284,
+ 286,
+ 287,
+ 296,
+ 297,
+ 321,
+ 320,
+ 338,
+ 32995,
+ 322,
+ 323,
+ 32998,
+ 32996,
+ 339,
+ 32997,
+ 330,
+ 531,
+ 530,
+ 301,
+ 532,
+ 333,
+ # as above
+ 269, # this has been in our tests forever, and works
+ 65537,
+}
+
+LIBTIFF_CORE.remove(320) # Array of short, crashes
+LIBTIFF_CORE.remove(301) # Array of short, crashes
+LIBTIFF_CORE.remove(532) # Array of long, crashes
+
+LIBTIFF_CORE.remove(255) # We don't have support for subfiletypes
+LIBTIFF_CORE.remove(322) # We don't have support for writing tiled images with libtiff
+LIBTIFF_CORE.remove(323) # Tiled images
+LIBTIFF_CORE.remove(333) # Ink Names either
+
+# Note to advanced users: There may be combinations of these
+# parameters and values that when added properly, will work and
+# produce valid tiff images that may work in your application.
+# It is safe to add and remove tags from this set from Pillow's point
+# of view so long as you test against libtiff.
diff --git a/contrib/python/Pillow/py2/PIL/WalImageFile.py b/contrib/python/Pillow/py2/PIL/WalImageFile.py
new file mode 100644
index 0000000000..e2e1cd4f57
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/WalImageFile.py
@@ -0,0 +1,129 @@
+# encoding: utf-8
+#
+# The Python Imaging Library.
+# $Id$
+#
+# WAL file handling
+#
+# History:
+# 2003-04-23 fl created
+#
+# Copyright (c) 2003 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+# NOTE: This format cannot be automatically recognized, so the reader
+# is not registered for use with Image.open(). To open a WAL file, use
+# the WalImageFile.open() function instead.
+
+# This reader is based on the specification available from:
+# https://www.flipcode.com/archives/Quake_2_BSP_File_Format.shtml
+# and has been tested with a few sample files found using google.
+
+from . import Image
+from ._binary import i32le as i32
+
+try:
+ import builtins
+except ImportError:
+ import __builtin__
+
+ builtins = __builtin__
+
+
+def open(filename):
+ """
+ Load texture from a Quake2 WAL texture file.
+
+ By default, a Quake2 standard palette is attached to the texture.
+ To override the palette, use the <b>putpalette</b> method.
+
+ :param filename: WAL file name, or an opened file handle.
+ :returns: An image instance.
+ """
+ # FIXME: modify to return a WalImageFile instance instead of
+ # plain Image object ?
+
+ def imopen(fp):
+ # read header fields
+ header = fp.read(32 + 24 + 32 + 12)
+ size = i32(header, 32), i32(header, 36)
+ offset = i32(header, 40)
+
+ # load pixel data
+ fp.seek(offset)
+
+ Image._decompression_bomb_check(size)
+ im = Image.frombytes("P", size, fp.read(size[0] * size[1]))
+ im.putpalette(quake2palette)
+
+ im.format = "WAL"
+ im.format_description = "Quake2 Texture"
+
+ # strings are null-terminated
+ im.info["name"] = header[:32].split(b"\0", 1)[0]
+ next_name = header[56 : 56 + 32].split(b"\0", 1)[0]
+ if next_name:
+ im.info["next_name"] = next_name
+
+ return im
+
+ if hasattr(filename, "read"):
+ return imopen(filename)
+ else:
+ with builtins.open(filename, "rb") as fp:
+ return imopen(fp)
+
+
+quake2palette = (
+ # default palette taken from piffo 0.93 by Hans Häggström
+ b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e"
+ b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f"
+ b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"
+ b"\x24\x1e\x13\x22\x1c\x12\x20\x1b\x12\x1f\x1a\x10\x1d\x19\x10\x1b"
+ b"\x17\x0f\x1a\x16\x0f\x18\x14\x0d\x17\x13\x0d\x16\x12\x0d\x14\x10"
+ b"\x0b\x13\x0f\x0b\x10\x0d\x0a\x0f\x0b\x0a\x0d\x0b\x07\x0b\x0a\x07"
+ b"\x23\x23\x26\x22\x22\x25\x22\x20\x23\x21\x1f\x22\x20\x1e\x20\x1f"
+ b"\x1d\x1e\x1d\x1b\x1c\x1b\x1a\x1a\x1a\x19\x19\x18\x17\x17\x17\x16"
+ b"\x16\x14\x14\x14\x13\x13\x13\x10\x10\x10\x0f\x0f\x0f\x0d\x0d\x0d"
+ b"\x2d\x28\x20\x29\x24\x1c\x27\x22\x1a\x25\x1f\x17\x38\x2e\x1e\x31"
+ b"\x29\x1a\x2c\x25\x17\x26\x20\x14\x3c\x30\x14\x37\x2c\x13\x33\x28"
+ b"\x12\x2d\x24\x10\x28\x1f\x0f\x22\x1a\x0b\x1b\x14\x0a\x13\x0f\x07"
+ b"\x31\x1a\x16\x30\x17\x13\x2e\x16\x10\x2c\x14\x0d\x2a\x12\x0b\x27"
+ b"\x0f\x0a\x25\x0f\x07\x21\x0d\x01\x1e\x0b\x01\x1c\x0b\x01\x1a\x0b"
+ b"\x01\x18\x0a\x01\x16\x0a\x01\x13\x0a\x01\x10\x07\x01\x0d\x07\x01"
+ b"\x29\x23\x1e\x27\x21\x1c\x26\x20\x1b\x25\x1f\x1a\x23\x1d\x19\x21"
+ b"\x1c\x18\x20\x1b\x17\x1e\x19\x16\x1c\x18\x14\x1b\x17\x13\x19\x14"
+ b"\x10\x17\x13\x0f\x14\x10\x0d\x12\x0f\x0b\x0f\x0b\x0a\x0b\x0a\x07"
+ b"\x26\x1a\x0f\x23\x19\x0f\x20\x17\x0f\x1c\x16\x0f\x19\x13\x0d\x14"
+ b"\x10\x0b\x10\x0d\x0a\x0b\x0a\x07\x33\x22\x1f\x35\x29\x26\x37\x2f"
+ b"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34"
+ b"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d"
+ b"\x1e\x25\x0b\x1c\x22\x0a\x1b\x20\x07\x19\x1e\x07\x17\x1b\x07\x14"
+ b"\x18\x01\x12\x16\x01\x0f\x12\x01\x0b\x0d\x01\x07\x0a\x01\x01\x01"
+ b"\x2c\x21\x21\x2a\x1f\x1f\x29\x1d\x1d\x27\x1c\x1c\x26\x1a\x1a\x24"
+ b"\x18\x18\x22\x17\x17\x21\x16\x16\x1e\x13\x13\x1b\x12\x12\x18\x10"
+ b"\x10\x16\x0d\x0d\x12\x0b\x0b\x0d\x0a\x0a\x0a\x07\x07\x01\x01\x01"
+ b"\x2e\x30\x29\x2d\x2e\x27\x2b\x2c\x26\x2a\x2a\x24\x28\x29\x23\x27"
+ b"\x27\x21\x26\x26\x1f\x24\x24\x1d\x22\x22\x1c\x1f\x1f\x1a\x1c\x1c"
+ b"\x18\x19\x19\x16\x17\x17\x13\x13\x13\x10\x0f\x0f\x0d\x0b\x0b\x0a"
+ b"\x30\x1e\x1b\x2d\x1c\x19\x2c\x1a\x17\x2a\x19\x14\x28\x17\x13\x26"
+ b"\x16\x10\x24\x13\x0f\x21\x12\x0d\x1f\x10\x0b\x1c\x0f\x0a\x19\x0d"
+ b"\x0a\x16\x0b\x07\x12\x0a\x07\x0f\x07\x01\x0a\x01\x01\x01\x01\x01"
+ b"\x28\x29\x38\x26\x27\x36\x25\x26\x34\x24\x24\x31\x22\x22\x2f\x20"
+ b"\x21\x2d\x1e\x1f\x2a\x1d\x1d\x27\x1b\x1b\x25\x19\x19\x21\x17\x17"
+ b"\x1e\x14\x14\x1b\x13\x12\x17\x10\x0f\x13\x0d\x0b\x0f\x0a\x07\x07"
+ b"\x2f\x32\x29\x2d\x30\x26\x2b\x2e\x24\x29\x2c\x21\x27\x2a\x1e\x25"
+ b"\x28\x1c\x23\x26\x1a\x21\x25\x18\x1e\x22\x14\x1b\x1f\x10\x19\x1c"
+ b"\x0d\x17\x1a\x0a\x13\x17\x07\x10\x13\x01\x0d\x0f\x01\x0a\x0b\x01"
+ b"\x01\x3f\x01\x13\x3c\x0b\x1b\x39\x10\x20\x35\x14\x23\x31\x17\x23"
+ b"\x2d\x18\x23\x29\x18\x3f\x3f\x3f\x3f\x3f\x39\x3f\x3f\x31\x3f\x3f"
+ b"\x2a\x3f\x3f\x20\x3f\x3f\x14\x3f\x3c\x12\x3f\x39\x0f\x3f\x35\x0b"
+ b"\x3f\x32\x07\x3f\x2d\x01\x3d\x2a\x01\x3b\x26\x01\x39\x21\x01\x37"
+ b"\x1d\x01\x34\x1a\x01\x32\x16\x01\x2f\x12\x01\x2d\x0f\x01\x2a\x0b"
+ b"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01"
+ b"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10"
+ b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b"
+ b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20"
+)
diff --git a/contrib/python/Pillow/py2/PIL/WebPImagePlugin.py b/contrib/python/Pillow/py2/PIL/WebPImagePlugin.py
new file mode 100644
index 0000000000..18eda6d184
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/WebPImagePlugin.py
@@ -0,0 +1,360 @@
+from io import BytesIO
+
+from . import Image, ImageFile
+
+try:
+ from . import _webp
+
+ SUPPORTED = True
+except ImportError:
+ SUPPORTED = False
+
+
+_VALID_WEBP_MODES = {"RGBX": True, "RGBA": True, "RGB": True}
+
+_VALID_WEBP_LEGACY_MODES = {"RGB": True, "RGBA": True}
+
+_VP8_MODES_BY_IDENTIFIER = {
+ b"VP8 ": "RGB",
+ b"VP8X": "RGBA",
+ b"VP8L": "RGBA", # lossless
+}
+
+
+def _accept(prefix):
+ is_riff_file_format = prefix[:4] == b"RIFF"
+ is_webp_file = prefix[8:12] == b"WEBP"
+ is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER
+
+ if is_riff_file_format and is_webp_file and is_valid_vp8_mode:
+ if not SUPPORTED:
+ return (
+ "image file could not be identified because WEBP support not installed"
+ )
+ return True
+
+
+class WebPImageFile(ImageFile.ImageFile):
+
+ format = "WEBP"
+ format_description = "WebP image"
+
+ def _open(self):
+ if not _webp.HAVE_WEBPANIM:
+ # Legacy mode
+ data, width, height, self.mode, icc_profile, exif = _webp.WebPDecode(
+ self.fp.read()
+ )
+ if icc_profile:
+ self.info["icc_profile"] = icc_profile
+ if exif:
+ self.info["exif"] = exif
+ self._size = width, height
+ self.fp = BytesIO(data)
+ self.tile = [("raw", (0, 0) + self.size, 0, self.mode)]
+ self._n_frames = 1
+ return
+
+ # Use the newer AnimDecoder API to parse the (possibly) animated file,
+ # and access muxed chunks like ICC/EXIF/XMP.
+ self._decoder = _webp.WebPAnimDecoder(self.fp.read())
+
+ # Get info from decoder
+ width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info()
+ self._size = width, height
+ self.info["loop"] = loop_count
+ bg_a, bg_r, bg_g, bg_b = (
+ (bgcolor >> 24) & 0xFF,
+ (bgcolor >> 16) & 0xFF,
+ (bgcolor >> 8) & 0xFF,
+ bgcolor & 0xFF,
+ )
+ self.info["background"] = (bg_r, bg_g, bg_b, bg_a)
+ self._n_frames = frame_count
+ self.mode = "RGB" if mode == "RGBX" else mode
+ self.rawmode = mode
+ self.tile = []
+
+ # Attempt to read ICC / EXIF / XMP chunks from file
+ icc_profile = self._decoder.get_chunk("ICCP")
+ exif = self._decoder.get_chunk("EXIF")
+ xmp = self._decoder.get_chunk("XMP ")
+ if icc_profile:
+ self.info["icc_profile"] = icc_profile
+ if exif:
+ self.info["exif"] = exif
+ if xmp:
+ self.info["xmp"] = xmp
+
+ # Initialize seek state
+ self._reset(reset=False)
+ self.seek(0)
+
+ def _getexif(self):
+ if "exif" not in self.info:
+ return None
+ return dict(self.getexif())
+
+ @property
+ def n_frames(self):
+ return self._n_frames
+
+ @property
+ def is_animated(self):
+ return self._n_frames > 1
+
+ def seek(self, frame):
+ if not _webp.HAVE_WEBPANIM:
+ return super(WebPImageFile, self).seek(frame)
+
+ # Perform some simple checks first
+ if frame >= self._n_frames:
+ raise EOFError("attempted to seek beyond end of sequence")
+ if frame < 0:
+ raise EOFError("negative frame index is not valid")
+
+ # Set logical frame to requested position
+ self.__logical_frame = frame
+
+ def _reset(self, reset=True):
+ if reset:
+ self._decoder.reset()
+ self.__physical_frame = 0
+ self.__loaded = -1
+ self.__timestamp = 0
+
+ def _get_next(self):
+ # Get next frame
+ ret = self._decoder.get_next()
+ self.__physical_frame += 1
+
+ # Check if an error occurred
+ if ret is None:
+ self._reset() # Reset just to be safe
+ self.seek(0)
+ raise EOFError("failed to decode next frame in WebP file")
+
+ # Compute duration
+ data, timestamp = ret
+ duration = timestamp - self.__timestamp
+ self.__timestamp = timestamp
+
+ # libwebp gives frame end, adjust to start of frame
+ timestamp -= duration
+ return data, timestamp, duration
+
+ def _seek(self, frame):
+ if self.__physical_frame == frame:
+ return # Nothing to do
+ if frame < self.__physical_frame:
+ self._reset() # Rewind to beginning
+ while self.__physical_frame < frame:
+ self._get_next() # Advance to the requested frame
+
+ def load(self):
+ if _webp.HAVE_WEBPANIM:
+ if self.__loaded != self.__logical_frame:
+ self._seek(self.__logical_frame)
+
+ # We need to load the image data for this frame
+ data, timestamp, duration = self._get_next()
+ self.info["timestamp"] = timestamp
+ self.info["duration"] = duration
+ self.__loaded = self.__logical_frame
+
+ # Set tile
+ if self.fp and self._exclusive_fp:
+ self.fp.close()
+ self.fp = BytesIO(data)
+ self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)]
+
+ return super(WebPImageFile, self).load()
+
+ def tell(self):
+ if not _webp.HAVE_WEBPANIM:
+ return super(WebPImageFile, self).tell()
+
+ return self.__logical_frame
+
+
+def _save_all(im, fp, filename):
+ encoderinfo = im.encoderinfo.copy()
+ append_images = list(encoderinfo.get("append_images", []))
+
+ # If total frame count is 1, then save using the legacy API, which
+ # will preserve non-alpha modes
+ total = 0
+ for ims in [im] + append_images:
+ total += getattr(ims, "n_frames", 1)
+ if total == 1:
+ _save(im, fp, filename)
+ return
+
+ background = (0, 0, 0, 0)
+ if "background" in encoderinfo:
+ background = encoderinfo["background"]
+ elif "background" in im.info:
+ background = im.info["background"]
+ if isinstance(background, int):
+ # GifImagePlugin stores a global color table index in
+ # info["background"]. So it must be converted to an RGBA value
+ palette = im.getpalette()
+ if palette:
+ r, g, b = palette[background * 3 : (background + 1) * 3]
+ background = (r, g, b, 0)
+
+ duration = im.encoderinfo.get("duration", 0)
+ loop = im.encoderinfo.get("loop", 0)
+ minimize_size = im.encoderinfo.get("minimize_size", False)
+ kmin = im.encoderinfo.get("kmin", None)
+ kmax = im.encoderinfo.get("kmax", None)
+ allow_mixed = im.encoderinfo.get("allow_mixed", False)
+ verbose = False
+ lossless = im.encoderinfo.get("lossless", False)
+ quality = im.encoderinfo.get("quality", 80)
+ method = im.encoderinfo.get("method", 0)
+ icc_profile = im.encoderinfo.get("icc_profile", "")
+ exif = im.encoderinfo.get("exif", "")
+ if isinstance(exif, Image.Exif):
+ exif = exif.tobytes()
+ xmp = im.encoderinfo.get("xmp", "")
+ if allow_mixed:
+ lossless = False
+
+ # Sensible keyframe defaults are from gif2webp.c script
+ if kmin is None:
+ kmin = 9 if lossless else 3
+ if kmax is None:
+ kmax = 17 if lossless else 5
+
+ # Validate background color
+ if (
+ not isinstance(background, (list, tuple))
+ or len(background) != 4
+ or not all(v >= 0 and v < 256 for v in background)
+ ):
+ raise IOError(
+ "Background color is not an RGBA tuple clamped to (0-255): %s"
+ % str(background)
+ )
+
+ # Convert to packed uint
+ bg_r, bg_g, bg_b, bg_a = background
+ background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)
+
+ # Setup the WebP animation encoder
+ enc = _webp.WebPAnimEncoder(
+ im.size[0],
+ im.size[1],
+ background,
+ loop,
+ minimize_size,
+ kmin,
+ kmax,
+ allow_mixed,
+ verbose,
+ )
+
+ # Add each frame
+ frame_idx = 0
+ timestamp = 0
+ cur_idx = im.tell()
+ try:
+ for ims in [im] + append_images:
+ # Get # of frames in this image
+ nfr = getattr(ims, "n_frames", 1)
+
+ for idx in range(nfr):
+ ims.seek(idx)
+ ims.load()
+
+ # Make sure image mode is supported
+ frame = ims
+ rawmode = ims.mode
+ if ims.mode not in _VALID_WEBP_MODES:
+ alpha = (
+ "A" in ims.mode
+ or "a" in ims.mode
+ or (ims.mode == "P" and "A" in ims.im.getpalettemode())
+ )
+ rawmode = "RGBA" if alpha else "RGB"
+ frame = ims.convert(rawmode)
+
+ if rawmode == "RGB":
+ # For faster conversion, use RGBX
+ rawmode = "RGBX"
+
+ # Append the frame to the animation encoder
+ enc.add(
+ frame.tobytes("raw", rawmode),
+ timestamp,
+ frame.size[0],
+ frame.size[1],
+ rawmode,
+ lossless,
+ quality,
+ method,
+ )
+
+ # Update timestamp and frame index
+ if isinstance(duration, (list, tuple)):
+ timestamp += duration[frame_idx]
+ else:
+ timestamp += duration
+ frame_idx += 1
+
+ finally:
+ im.seek(cur_idx)
+
+ # Force encoder to flush frames
+ enc.add(None, timestamp, 0, 0, "", lossless, quality, 0)
+
+ # Get the final output from the encoder
+ data = enc.assemble(icc_profile, exif, xmp)
+ if data is None:
+ raise IOError("cannot write file as WebP (encoder returned None)")
+
+ fp.write(data)
+
+
+def _save(im, fp, filename):
+ lossless = im.encoderinfo.get("lossless", False)
+ quality = im.encoderinfo.get("quality", 80)
+ icc_profile = im.encoderinfo.get("icc_profile", "")
+ exif = im.encoderinfo.get("exif", "")
+ if isinstance(exif, Image.Exif):
+ exif = exif.tobytes()
+ xmp = im.encoderinfo.get("xmp", "")
+
+ if im.mode not in _VALID_WEBP_LEGACY_MODES:
+ alpha = (
+ "A" in im.mode
+ or "a" in im.mode
+ or (im.mode == "P" and "A" in im.im.getpalettemode())
+ )
+ im = im.convert("RGBA" if alpha else "RGB")
+
+ data = _webp.WebPEncode(
+ im.tobytes(),
+ im.size[0],
+ im.size[1],
+ lossless,
+ float(quality),
+ im.mode,
+ icc_profile,
+ exif,
+ xmp,
+ )
+ if data is None:
+ raise IOError("cannot write file as WebP (encoder returned None)")
+
+ fp.write(data)
+
+
+Image.register_open(WebPImageFile.format, WebPImageFile, _accept)
+if SUPPORTED:
+ Image.register_save(WebPImageFile.format, _save)
+ if _webp.HAVE_WEBPANIM:
+ Image.register_save_all(WebPImageFile.format, _save_all)
+ Image.register_extension(WebPImageFile.format, ".webp")
+ Image.register_mime(WebPImageFile.format, "image/webp")
diff --git a/contrib/python/Pillow/py2/PIL/WmfImagePlugin.py b/contrib/python/Pillow/py2/PIL/WmfImagePlugin.py
new file mode 100644
index 0000000000..416af6fd74
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/WmfImagePlugin.py
@@ -0,0 +1,173 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# WMF stub codec
+#
+# history:
+# 1996-12-14 fl Created
+# 2004-02-22 fl Turned into a stub driver
+# 2004-02-23 fl Added EMF support
+#
+# Copyright (c) Secret Labs AB 1997-2004. All rights reserved.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+# WMF/EMF reference documentation:
+# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf
+# http://wvware.sourceforge.net/caolan/index.html
+# http://wvware.sourceforge.net/caolan/ora-wmf.html
+
+from __future__ import print_function
+
+from . import Image, ImageFile
+from ._binary import i16le as word, i32le as dword, si16le as short, si32le as _long
+from ._util import py3
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.2"
+
+_handler = None
+
+if py3:
+ long = int
+
+
+def register_handler(handler):
+ """
+ Install application-specific WMF image handler.
+
+ :param handler: Handler object.
+ """
+ global _handler
+ _handler = handler
+
+
+if hasattr(Image.core, "drawwmf"):
+ # install default handler (windows only)
+
+ class WmfHandler(object):
+ def open(self, im):
+ im.mode = "RGB"
+ self.bbox = im.info["wmf_bbox"]
+
+ def load(self, im):
+ im.fp.seek(0) # rewind
+ return Image.frombytes(
+ "RGB",
+ im.size,
+ Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
+ "raw",
+ "BGR",
+ (im.size[0] * 3 + 3) & -4,
+ -1,
+ )
+
+ register_handler(WmfHandler())
+
+#
+# --------------------------------------------------------------------
+# Read WMF file
+
+
+def _accept(prefix):
+ return (
+ prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or prefix[:4] == b"\x01\x00\x00\x00"
+ )
+
+
+##
+# Image plugin for Windows metafiles.
+
+
+class WmfStubImageFile(ImageFile.StubImageFile):
+
+ format = "WMF"
+ format_description = "Windows Metafile"
+
+ def _open(self):
+
+ # check placable header
+ s = self.fp.read(80)
+
+ if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00":
+
+ # placeable windows metafile
+
+ # get units per inch
+ inch = word(s, 14)
+
+ # get bounding box
+ x0 = short(s, 6)
+ y0 = short(s, 8)
+ x1 = short(s, 10)
+ y1 = short(s, 12)
+
+ # normalize size to 72 dots per inch
+ size = (x1 - x0) * 72 // inch, (y1 - y0) * 72 // inch
+
+ self.info["wmf_bbox"] = x0, y0, x1, y1
+
+ self.info["dpi"] = 72
+
+ # sanity check (standard metafile header)
+ if s[22:26] != b"\x01\x00\t\x00":
+ raise SyntaxError("Unsupported WMF file format")
+
+ elif dword(s) == 1 and s[40:44] == b" EMF":
+ # enhanced metafile
+
+ # get bounding box
+ x0 = _long(s, 8)
+ y0 = _long(s, 12)
+ x1 = _long(s, 16)
+ y1 = _long(s, 20)
+
+ # get frame (in 0.01 millimeter units)
+ frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)
+
+ # normalize size to 72 dots per inch
+ size = x1 - x0, y1 - y0
+
+ # calculate dots per inch from bbox and frame
+ xdpi = int(2540.0 * (x1 - y0) / (frame[2] - frame[0]) + 0.5)
+ ydpi = int(2540.0 * (y1 - y0) / (frame[3] - frame[1]) + 0.5)
+
+ self.info["wmf_bbox"] = x0, y0, x1, y1
+
+ if xdpi == ydpi:
+ self.info["dpi"] = xdpi
+ else:
+ self.info["dpi"] = xdpi, ydpi
+
+ else:
+ raise SyntaxError("Unsupported file format")
+
+ self.mode = "RGB"
+ self._size = size
+
+ loader = self._load()
+ if loader:
+ loader.open(self)
+
+ def _load(self):
+ return _handler
+
+
+def _save(im, fp, filename):
+ if _handler is None or not hasattr(_handler, "save"):
+ raise IOError("WMF save handler not installed")
+ _handler.save(im, fp, filename)
+
+
+#
+# --------------------------------------------------------------------
+# Registry stuff
+
+
+Image.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept)
+Image.register_save(WmfStubImageFile.format, _save)
+
+Image.register_extensions(WmfStubImageFile.format, [".wmf", ".emf"])
diff --git a/contrib/python/Pillow/py2/PIL/XVThumbImagePlugin.py b/contrib/python/Pillow/py2/PIL/XVThumbImagePlugin.py
new file mode 100644
index 0000000000..aa3536d85f
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/XVThumbImagePlugin.py
@@ -0,0 +1,82 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# XV Thumbnail file handler by Charles E. "Gene" Cash
+# (gcash@magicnet.net)
+#
+# see xvcolor.c and xvbrowse.c in the sources to John Bradley's XV,
+# available from ftp://ftp.cis.upenn.edu/pub/xv/
+#
+# history:
+# 98-08-15 cec created (b/w only)
+# 98-12-09 cec added color palette
+# 98-12-28 fl added to PIL (with only a few very minor modifications)
+#
+# To do:
+# FIXME: make save work (this requires quantization support)
+#
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8, o8
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.1"
+
+_MAGIC = b"P7 332"
+
+# standard color palette for thumbnails (RGB332)
+PALETTE = b""
+for r in range(8):
+ for g in range(8):
+ for b in range(4):
+ PALETTE = PALETTE + (
+ o8((r * 255) // 7) + o8((g * 255) // 7) + o8((b * 255) // 3)
+ )
+
+
+def _accept(prefix):
+ return prefix[:6] == _MAGIC
+
+
+##
+# Image plugin for XV thumbnail images.
+
+
+class XVThumbImageFile(ImageFile.ImageFile):
+
+ format = "XVThumb"
+ format_description = "XV thumbnail image"
+
+ def _open(self):
+
+ # check magic
+ if not _accept(self.fp.read(6)):
+ raise SyntaxError("not an XV thumbnail file")
+
+ # Skip to beginning of next line
+ self.fp.readline()
+
+ # skip info comments
+ while True:
+ s = self.fp.readline()
+ if not s:
+ raise SyntaxError("Unexpected EOF reading XV thumbnail file")
+ if i8(s[0]) != 35: # ie. when not a comment: '#'
+ break
+
+ # parse header line (already read)
+ s = s.strip().split()
+
+ self.mode = "P"
+ self._size = int(s[0]), int(s[1])
+
+ self.palette = ImagePalette.raw("RGB", PALETTE)
+
+ self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), (self.mode, 0, 1))]
+
+
+# --------------------------------------------------------------------
+
+Image.register_open(XVThumbImageFile.format, XVThumbImageFile, _accept)
diff --git a/contrib/python/Pillow/py2/PIL/XbmImagePlugin.py b/contrib/python/Pillow/py2/PIL/XbmImagePlugin.py
new file mode 100644
index 0000000000..bc825c3f31
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/XbmImagePlugin.py
@@ -0,0 +1,98 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# XBM File handling
+#
+# History:
+# 1995-09-08 fl Created
+# 1996-11-01 fl Added save support
+# 1997-07-07 fl Made header parser more tolerant
+# 1997-07-22 fl Fixed yet another parser bug
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.4)
+# 2001-05-13 fl Added hotspot handling (based on code from Bernhard Herzog)
+# 2004-02-24 fl Allow some whitespace before first #define
+#
+# Copyright (c) 1997-2004 by Secret Labs AB
+# Copyright (c) 1996-1997 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import re
+
+from . import Image, ImageFile
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.6"
+
+# XBM header
+xbm_head = re.compile(
+ br"\s*#define[ \t]+.*_width[ \t]+(?P<width>[0-9]+)[\r\n]+"
+ b"#define[ \t]+.*_height[ \t]+(?P<height>[0-9]+)[\r\n]+"
+ b"(?P<hotspot>"
+ b"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+"
+ b"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+"
+ b")?"
+ b"[\\000-\\377]*_bits\\[\\]"
+)
+
+
+def _accept(prefix):
+ return prefix.lstrip()[:7] == b"#define"
+
+
+##
+# Image plugin for X11 bitmaps.
+
+
+class XbmImageFile(ImageFile.ImageFile):
+
+ format = "XBM"
+ format_description = "X11 Bitmap"
+
+ def _open(self):
+
+ m = xbm_head.match(self.fp.read(512))
+
+ if m:
+
+ xsize = int(m.group("width"))
+ ysize = int(m.group("height"))
+
+ if m.group("hotspot"):
+ self.info["hotspot"] = (int(m.group("xhot")), int(m.group("yhot")))
+
+ self.mode = "1"
+ self._size = xsize, ysize
+
+ self.tile = [("xbm", (0, 0) + self.size, m.end(), None)]
+
+
+def _save(im, fp, filename):
+
+ if im.mode != "1":
+ raise IOError("cannot write mode %s as XBM" % im.mode)
+
+ fp.write(("#define im_width %d\n" % im.size[0]).encode("ascii"))
+ fp.write(("#define im_height %d\n" % im.size[1]).encode("ascii"))
+
+ hotspot = im.encoderinfo.get("hotspot")
+ if hotspot:
+ fp.write(("#define im_x_hot %d\n" % hotspot[0]).encode("ascii"))
+ fp.write(("#define im_y_hot %d\n" % hotspot[1]).encode("ascii"))
+
+ fp.write(b"static char im_bits[] = {\n")
+
+ ImageFile._save(im, fp, [("xbm", (0, 0) + im.size, 0, None)])
+
+ fp.write(b"};\n")
+
+
+Image.register_open(XbmImageFile.format, XbmImageFile, _accept)
+Image.register_save(XbmImageFile.format, _save)
+
+Image.register_extension(XbmImageFile.format, ".xbm")
+
+Image.register_mime(XbmImageFile.format, "image/xbm")
diff --git a/contrib/python/Pillow/py2/PIL/XpmImagePlugin.py b/contrib/python/Pillow/py2/PIL/XpmImagePlugin.py
new file mode 100644
index 0000000000..2751488272
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/XpmImagePlugin.py
@@ -0,0 +1,134 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# XPM File handling
+#
+# History:
+# 1996-12-29 fl Created
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.7)
+#
+# Copyright (c) Secret Labs AB 1997-2001.
+# Copyright (c) Fredrik Lundh 1996-2001.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import re
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8, o8
+
+# __version__ is deprecated and will be removed in a future version. Use
+# PIL.__version__ instead.
+__version__ = "0.2"
+
+# XPM header
+xpm_head = re.compile(b'"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)')
+
+
+def _accept(prefix):
+ return prefix[:9] == b"/* XPM */"
+
+
+##
+# Image plugin for X11 pixel maps.
+
+
+class XpmImageFile(ImageFile.ImageFile):
+
+ format = "XPM"
+ format_description = "X11 Pixel Map"
+
+ def _open(self):
+
+ if not _accept(self.fp.read(9)):
+ raise SyntaxError("not an XPM file")
+
+ # skip forward to next string
+ while True:
+ s = self.fp.readline()
+ if not s:
+ raise SyntaxError("broken XPM file")
+ m = xpm_head.match(s)
+ if m:
+ break
+
+ self._size = int(m.group(1)), int(m.group(2))
+
+ pal = int(m.group(3))
+ bpp = int(m.group(4))
+
+ if pal > 256 or bpp != 1:
+ raise ValueError("cannot read this XPM file")
+
+ #
+ # load palette description
+
+ palette = [b"\0\0\0"] * 256
+
+ for i in range(pal):
+
+ s = self.fp.readline()
+ if s[-2:] == b"\r\n":
+ s = s[:-2]
+ elif s[-1:] in b"\r\n":
+ s = s[:-1]
+
+ c = i8(s[1])
+ s = s[2:-2].split()
+
+ for i in range(0, len(s), 2):
+
+ if s[i] == b"c":
+
+ # process colour key
+ rgb = s[i + 1]
+ if rgb == b"None":
+ self.info["transparency"] = c
+ elif rgb[0:1] == b"#":
+ # FIXME: handle colour names (see ImagePalette.py)
+ rgb = int(rgb[1:], 16)
+ palette[c] = (
+ o8((rgb >> 16) & 255) + o8((rgb >> 8) & 255) + o8(rgb & 255)
+ )
+ else:
+ # unknown colour
+ raise ValueError("cannot read this XPM file")
+ break
+
+ else:
+
+ # missing colour key
+ raise ValueError("cannot read this XPM file")
+
+ self.mode = "P"
+ self.palette = ImagePalette.raw("RGB", b"".join(palette))
+
+ self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))]
+
+ def load_read(self, bytes):
+
+ #
+ # load all image data in one chunk
+
+ xsize, ysize = self.size
+
+ s = [None] * ysize
+
+ for i in range(ysize):
+ s[i] = self.fp.readline()[1 : xsize + 1].ljust(xsize)
+
+ return b"".join(s)
+
+
+#
+# Registry
+
+
+Image.register_open(XpmImageFile.format, XpmImageFile, _accept)
+
+Image.register_extension(XpmImageFile.format, ".xpm")
+
+Image.register_mime(XpmImageFile.format, "image/xpm")
diff --git a/contrib/python/Pillow/py2/PIL/__init__.py b/contrib/python/Pillow/py2/PIL/__init__.py
new file mode 100644
index 0000000000..59eccc9b5a
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/__init__.py
@@ -0,0 +1,73 @@
+"""Pillow (Fork of the Python Imaging Library)
+
+Pillow is the friendly PIL fork by Alex Clark and Contributors.
+ https://github.com/python-pillow/Pillow/
+
+Pillow is forked from PIL 1.1.7.
+
+PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
+Copyright (c) 1999 by Secret Labs AB.
+
+Use PIL.__version__ for this Pillow version.
+PIL.VERSION is the old PIL version and will be removed in the future.
+
+;-)
+"""
+
+from . import _version
+
+# VERSION was removed in Pillow 6.0.0.
+# PILLOW_VERSION is deprecated and will be removed in Pillow 7.0.0.
+# Use __version__ instead.
+PILLOW_VERSION = __version__ = _version.__version__
+
+del _version
+
+
+_plugins = [
+ "BlpImagePlugin",
+ "BmpImagePlugin",
+ "BufrStubImagePlugin",
+ "CurImagePlugin",
+ "DcxImagePlugin",
+ "DdsImagePlugin",
+ "EpsImagePlugin",
+ "FitsStubImagePlugin",
+ "FliImagePlugin",
+ "FpxImagePlugin",
+ "FtexImagePlugin",
+ "GbrImagePlugin",
+ "GifImagePlugin",
+ "GribStubImagePlugin",
+ "Hdf5StubImagePlugin",
+ "IcnsImagePlugin",
+ "IcoImagePlugin",
+ "ImImagePlugin",
+ "ImtImagePlugin",
+ "IptcImagePlugin",
+ "JpegImagePlugin",
+ "Jpeg2KImagePlugin",
+ "McIdasImagePlugin",
+ "MicImagePlugin",
+ "MpegImagePlugin",
+ "MpoImagePlugin",
+ "MspImagePlugin",
+ "PalmImagePlugin",
+ "PcdImagePlugin",
+ "PcxImagePlugin",
+ "PdfImagePlugin",
+ "PixarImagePlugin",
+ "PngImagePlugin",
+ "PpmImagePlugin",
+ "PsdImagePlugin",
+ "SgiImagePlugin",
+ "SpiderImagePlugin",
+ "SunImagePlugin",
+ "TgaImagePlugin",
+ "TiffImagePlugin",
+ "WebPImagePlugin",
+ "WmfImagePlugin",
+ "XbmImagePlugin",
+ "XpmImagePlugin",
+ "XVThumbImagePlugin",
+]
diff --git a/contrib/python/Pillow/py2/PIL/__main__.py b/contrib/python/Pillow/py2/PIL/__main__.py
new file mode 100644
index 0000000000..d249991d05
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/__main__.py
@@ -0,0 +1,9 @@
+from .features import pilinfo
+
+
+def main():
+ pilinfo()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/python/Pillow/py2/PIL/_binary.py b/contrib/python/Pillow/py2/PIL/_binary.py
new file mode 100644
index 0000000000..53b1ca9562
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/_binary.py
@@ -0,0 +1,99 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Binary input/output support routines.
+#
+# Copyright (c) 1997-2003 by Secret Labs AB
+# Copyright (c) 1995-2003 by Fredrik Lundh
+# Copyright (c) 2012 by Brian Crowell
+#
+# See the README file for information on usage and redistribution.
+#
+
+from struct import pack, unpack_from
+
+from ._util import py3
+
+if py3:
+
+ def i8(c):
+ return c if c.__class__ is int else c[0]
+
+ def o8(i):
+ return bytes((i & 255,))
+
+
+else:
+
+ def i8(c):
+ return ord(c)
+
+ def o8(i):
+ return chr(i & 255)
+
+
+# Input, le = little endian, be = big endian
+def i16le(c, o=0):
+ """
+ Converts a 2-bytes (16 bits) string to an unsigned integer.
+
+ :param c: string containing bytes to convert
+ :param o: offset of bytes to convert in string
+ """
+ return unpack_from("<H", c, o)[0]
+
+
+def si16le(c, o=0):
+ """
+ Converts a 2-bytes (16 bits) string to a signed integer.
+
+ :param c: string containing bytes to convert
+ :param o: offset of bytes to convert in string
+ """
+ return unpack_from("<h", c, o)[0]
+
+
+def i32le(c, o=0):
+ """
+ Converts a 4-bytes (32 bits) string to an unsigned integer.
+
+ :param c: string containing bytes to convert
+ :param o: offset of bytes to convert in string
+ """
+ return unpack_from("<I", c, o)[0]
+
+
+def si32le(c, o=0):
+ """
+ Converts a 4-bytes (32 bits) string to a signed integer.
+
+ :param c: string containing bytes to convert
+ :param o: offset of bytes to convert in string
+ """
+ return unpack_from("<i", c, o)[0]
+
+
+def i16be(c, o=0):
+ return unpack_from(">H", c, o)[0]
+
+
+def i32be(c, o=0):
+ return unpack_from(">I", c, o)[0]
+
+
+# Output, le = little endian, be = big endian
+def o16le(i):
+ return pack("<H", i)
+
+
+def o32le(i):
+ return pack("<I", i)
+
+
+def o16be(i):
+ return pack(">H", i)
+
+
+def o32be(i):
+ return pack(">I", i)
diff --git a/contrib/python/Pillow/py2/PIL/_util.py b/contrib/python/Pillow/py2/PIL/_util.py
new file mode 100644
index 0000000000..59964c7efa
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/_util.py
@@ -0,0 +1,43 @@
+import os
+import sys
+
+py3 = sys.version_info.major >= 3
+py36 = sys.version_info[0:2] >= (3, 6)
+
+if py3:
+
+ def isStringType(t):
+ return isinstance(t, str)
+
+ if py36:
+ from pathlib import Path
+
+ def isPath(f):
+ return isinstance(f, (bytes, str, Path))
+
+ else:
+
+ def isPath(f):
+ return isinstance(f, (bytes, str))
+
+
+else:
+
+ def isStringType(t):
+ return isinstance(t, basestring) # noqa: F821
+
+ def isPath(f):
+ return isinstance(f, basestring) # noqa: F821
+
+
+# Checks if an object is a string, and that it points to a directory.
+def isDirectory(f):
+ return isPath(f) and os.path.isdir(f)
+
+
+class deferred_error(object):
+ def __init__(self, ex):
+ self.ex = ex
+
+ def __getattr__(self, elt):
+ raise self.ex
diff --git a/contrib/python/Pillow/py2/PIL/_version.py b/contrib/python/Pillow/py2/PIL/_version.py
new file mode 100644
index 0000000000..df16dce603
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/_version.py
@@ -0,0 +1,2 @@
+# Master version for Pillow
+__version__ = "6.2.2"
diff --git a/contrib/python/Pillow/py2/PIL/features.py b/contrib/python/Pillow/py2/PIL/features.py
new file mode 100644
index 0000000000..9168ed826e
--- /dev/null
+++ b/contrib/python/Pillow/py2/PIL/features.py
@@ -0,0 +1,169 @@
+from __future__ import print_function, unicode_literals
+
+import collections
+import os
+import sys
+
+import PIL
+
+from . import Image
+
+modules = {
+ "pil": "PIL._imaging",
+ "tkinter": "PIL._tkinter_finder",
+ "freetype2": "PIL._imagingft",
+ "littlecms2": "PIL._imagingcms",
+ "webp": "PIL._webp",
+}
+
+
+def check_module(feature):
+ if not (feature in modules):
+ raise ValueError("Unknown module %s" % feature)
+
+ module = modules[feature]
+
+ try:
+ __import__(module)
+ return True
+ except ImportError:
+ return False
+
+
+def get_supported_modules():
+ return [f for f in modules if check_module(f)]
+
+
+codecs = {"jpg": "jpeg", "jpg_2000": "jpeg2k", "zlib": "zip", "libtiff": "libtiff"}
+
+
+def check_codec(feature):
+ if feature not in codecs:
+ raise ValueError("Unknown codec %s" % feature)
+
+ codec = codecs[feature]
+
+ return codec + "_encoder" in dir(Image.core)
+
+
+def get_supported_codecs():
+ return [f for f in codecs if check_codec(f)]
+
+
+features = {
+ "webp_anim": ("PIL._webp", "HAVE_WEBPANIM"),
+ "webp_mux": ("PIL._webp", "HAVE_WEBPMUX"),
+ "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"),
+ "raqm": ("PIL._imagingft", "HAVE_RAQM"),
+ "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO"),
+}
+
+
+def check_feature(feature):
+ if feature not in features:
+ raise ValueError("Unknown feature %s" % feature)
+
+ module, flag = features[feature]
+
+ try:
+ imported_module = __import__(module, fromlist=["PIL"])
+ return getattr(imported_module, flag)
+ except ImportError:
+ return None
+
+
+def get_supported_features():
+ return [f for f in features if check_feature(f)]
+
+
+def check(feature):
+ return (
+ feature in modules
+ and check_module(feature)
+ or feature in codecs
+ and check_codec(feature)
+ or feature in features
+ and check_feature(feature)
+ )
+
+
+def get_supported():
+ ret = get_supported_modules()
+ ret.extend(get_supported_features())
+ ret.extend(get_supported_codecs())
+ return ret
+
+
+def pilinfo(out=None):
+ if out is None:
+ out = sys.stdout
+
+ Image.init()
+
+ print("-" * 68, file=out)
+ print("Pillow {}".format(PIL.__version__), file=out)
+ print("-" * 68, file=out)
+ print(
+ "Python modules loaded from {}".format(os.path.dirname(Image.__file__)),
+ file=out,
+ )
+ print(
+ "Binary modules loaded from {}".format(sys.executable),
+ file=out,
+ )
+ print("-" * 68, file=out)
+
+ v = sys.version.splitlines()
+ print("Python {}".format(v[0].strip()), file=out)
+ for v in v[1:]:
+ print(" {}".format(v.strip()), file=out)
+ print("-" * 68, file=out)
+
+ for name, feature in [
+ ("pil", "PIL CORE"),
+ ("tkinter", "TKINTER"),
+ ("freetype2", "FREETYPE2"),
+ ("littlecms2", "LITTLECMS2"),
+ ("webp", "WEBP"),
+ ("transp_webp", "WEBP Transparency"),
+ ("webp_mux", "WEBPMUX"),
+ ("webp_anim", "WEBP Animation"),
+ ("jpg", "JPEG"),
+ ("jpg_2000", "OPENJPEG (JPEG2000)"),
+ ("zlib", "ZLIB (PNG/ZIP)"),
+ ("libtiff", "LIBTIFF"),
+ ("raqm", "RAQM (Bidirectional Text)"),
+ ]:
+ if check(name):
+ print("---", feature, "support ok", file=out)
+ else:
+ print("***", feature, "support not installed", file=out)
+ print("-" * 68, file=out)
+
+ extensions = collections.defaultdict(list)
+ for ext, i in Image.EXTENSION.items():
+ extensions[i].append(ext)
+
+ for i in sorted(Image.ID):
+ line = "{}".format(i)
+ if i in Image.MIME:
+ line = "{} {}".format(line, Image.MIME[i])
+ print(line, file=out)
+
+ if i in extensions:
+ print("Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out)
+
+ features = []
+ if i in Image.OPEN:
+ features.append("open")
+ if i in Image.SAVE:
+ features.append("save")
+ if i in Image.SAVE_ALL:
+ features.append("save_all")
+ if i in Image.DECODERS:
+ features.append("decode")
+ if i in Image.ENCODERS:
+ features.append("encode")
+
+ print("Features: {}".format(", ".join(features)), file=out)
+ print("-" * 68, file=out)
diff --git a/contrib/python/Pillow/py2/README.rst b/contrib/python/Pillow/py2/README.rst
new file mode 100644
index 0000000000..6b783a95a4
--- /dev/null
+++ b/contrib/python/Pillow/py2/README.rst
@@ -0,0 +1,87 @@
+Pillow
+======
+
+Python Imaging Library (Fork)
+-----------------------------
+
+Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. As of 2019, Pillow development is `supported by Tidelift <https://tidelift.com/subscription/pkg/pypi-pillow>`_.
+
+.. start-badges
+
+.. list-table::
+ :stub-columns: 1
+
+ * - docs
+ - |docs|
+ * - tests
+ - |linux| |macos| |windows| |coverage|
+ * - package
+ - |zenodo| |tidelift| |version| |downloads|
+ * - social
+ - |gitter| |twitter|
+
+.. end-badges
+
+More Information
+----------------
+
+- `Documentation <https://pillow.readthedocs.io/>`_
+
+ - `Installation <https://pillow.readthedocs.io/en/latest/installation.html>`_
+ - `Handbook <https://pillow.readthedocs.io/en/latest/handbook/index.html>`_
+
+- `Contribute <https://github.com/python-pillow/Pillow/blob/master/.github/CONTRIBUTING.md>`_
+
+ - `Issues <https://github.com/python-pillow/Pillow/issues>`_
+ - `Pull requests <https://github.com/python-pillow/Pillow/pulls>`_
+
+- `Changelog <https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst>`_
+
+ - `Pre-fork <https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst#pre-fork>`_
+
+Report a Vulnerability
+----------------------
+
+To report a security vulnerability, please follow the procedure described in the `Tidelift security policy <https://tidelift.com/docs/security>`_.
+
+.. |docs| image:: https://readthedocs.org/projects/pillow/badge/?version=latest
+ :target: https://pillow.readthedocs.io/?badge=latest
+ :alt: Documentation Status
+
+.. |linux| image:: https://img.shields.io/travis/python-pillow/Pillow/master.svg?label=Linux%20build
+ :target: https://travis-ci.org/python-pillow/Pillow
+ :alt: Travis CI build status (Linux)
+
+.. |macos| image:: https://img.shields.io/travis/python-pillow/pillow-wheels/master.svg?label=macOS%20build
+ :target: https://travis-ci.org/python-pillow/pillow-wheels
+ :alt: Travis CI build status (macOS)
+
+.. |windows| image:: https://img.shields.io/appveyor/ci/python-pillow/Pillow/master.svg?label=Windows%20build
+ :target: https://ci.appveyor.com/project/python-pillow/Pillow
+ :alt: AppVeyor CI build status (Windows)
+
+.. |coverage| image:: https://codecov.io/gh/python-pillow/Pillow/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/python-pillow/Pillow
+ :alt: Code coverage
+
+.. |zenodo| image:: https://zenodo.org/badge/17549/python-pillow/Pillow.svg
+ :target: https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow
+
+.. |tidelift| image:: https://tidelift.com/badges/package/pypi/Pillow?style=flat
+ :target: https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=referral&utm_campaign=readme
+
+.. |version| image:: https://img.shields.io/pypi/v/pillow.svg
+ :target: https://pypi.org/project/Pillow/
+ :alt: Latest PyPI version
+
+.. |downloads| image:: https://img.shields.io/pypi/dm/pillow.svg
+ :target: https://pypi.org/project/Pillow/
+ :alt: Number of PyPI downloads
+
+.. |gitter| image:: https://badges.gitter.im/python-pillow/Pillow.svg
+ :target: https://gitter.im/python-pillow/Pillow?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+ :alt: Join the chat at https://gitter.im/python-pillow/Pillow
+
+.. |twitter| image:: https://img.shields.io/badge/tweet-on%20Twitter-00aced.svg
+ :target: https://twitter.com/PythonPillow
+ :alt: Follow on https://twitter.com/PythonPillow
diff --git a/contrib/python/Pillow/py2/RELEASING.md b/contrib/python/Pillow/py2/RELEASING.md
new file mode 100644
index 0000000000..e1f57883c2
--- /dev/null
+++ b/contrib/python/Pillow/py2/RELEASING.md
@@ -0,0 +1,105 @@
+# Release Checklist
+
+## Main Release
+
+Released quarterly on the first day of January, April, July, October.
+
+* [ ] 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 Travis CI.
+* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), update version identifier in `src/PIL/_version.py`
+* [ ] Update `CHANGES.rst`.
+* [ ] Run pre-release check via `make release-test` in a freshly cloned repo.
+* [ ] Create branch and tag for release e.g.:
+ ```bash
+ git branch 5.2.x
+ git tag 5.2.0
+ git push --all
+ git push --tags
+ ```
+* [ ] Create source distributions e.g.:
+ ```bash
+ make sdist
+ ```
+* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/master/RELEASING.md#binary-distributions)
+* [ ] Upload all binaries and source distributions e.g. `twine upload dist/Pillow-5.2.0*`
+* [ ] Create a [new release on GitHub](https://github.com/python-pillow/Pillow/releases/new)
+* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), increment and append `.dev0` to version identifier in `src/PIL/_version.py`
+
+## Point Release
+
+Released as needed for security, installation or critical bug fixes.
+
+* [ ] Make necessary changes in `master` branch.
+* [ ] Update `CHANGES.rst`.
+* [ ] Check out release branch e.g.:
+ ```bash
+ git checkout -t remotes/origin/5.2.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`.
+* [ ] In compliance with [PEP 440](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.:
+ ```bash
+ git tag 5.2.1
+ git push --tags
+ ```
+* [ ] Create source distributions e.g.:
+ ```bash
+ make sdist
+ ```
+* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/master/RELEASING.md#binary-distributions)
+* [ ] Create a [new release on GitHub](https://github.com/python-pillow/Pillow/releases/new)
+
+## Embargoed Release
+
+Released as needed privately to individual vendors for critical security-related bug fixes.
+
+* [ ] Prepare patch for all versions that will get a fix. Test against local installations.
+* [ ] Commit against master, cherry pick to affected release branches.
+* [ ] Run local test matrix on each release & Python version.
+* [ ] Privately send to distros.
+* [ ] Run pre-release check via `make release-test`
+* [ ] Amend any commits with the CVE #
+* [ ] On release date, tag and push to GitHub.
+ ```bash
+ git checkout 2.5.x
+ git tag 2.5.3
+ git push origin 2.5.x
+ git push origin --tags
+ ```
+* [ ] Create source distributions e.g.:
+ ```bash
+ make sdist
+ ```
+* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/master/RELEASING.md#binary-distributions)
+* [ ] Create a [new release on GitHub](https://github.com/python-pillow/Pillow/releases/new)
+
+## Binary Distributions
+
+### Windows
+* [ ] Contact `@cgohlke` for Windows binaries via release ticket e.g. https://github.com/python-pillow/Pillow/issues/1174.
+* [ ] Download and extract tarball from `@cgohlke` and `twine upload *`.
+
+### Mac and Linux
+* [ ] Use the [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels):
+ ```bash
+ git clone https://github.com/python-pillow/pillow-wheels
+ cd pillow-wheels
+ ./update-pillow-tag.sh [[release tag]]
+ ```
+* [ ] Download distributions from the [Pillow Wheel Builder container](http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com/).
+ ```bash
+ wget -m -A 'Pillow-<VERSION>*' \
+ http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com
+ ```
+
+## Publicize Release
+
+* [ ] 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](https://pillow.readthedocs.io/en/stable/) is up-to-date with the release changes
diff --git a/contrib/python/Pillow/py2/_imaging.c b/contrib/python/Pillow/py2/_imaging.c
new file mode 100644
index 0000000000..04520b1a1f
--- /dev/null
+++ b/contrib/python/Pillow/py2/_imaging.c
@@ -0,0 +1,3989 @@
+/*
+ * The Python Imaging Library.
+ *
+ * the imaging library bindings
+ *
+ * history:
+ * 1995-09-24 fl Created
+ * 1996-03-24 fl Ready for first public release (release 0.0)
+ * 1996-03-25 fl Added fromstring (for Jack's "img" library)
+ * 1996-03-28 fl Added channel operations
+ * 1996-03-31 fl Added point operation
+ * 1996-04-08 fl Added new/new_block/new_array factories
+ * 1996-04-13 fl Added decoders
+ * 1996-05-04 fl Added palette hack
+ * 1996-05-12 fl Compile cleanly as C++
+ * 1996-05-19 fl Added matrix conversions, gradient fills
+ * 1996-05-27 fl Added display_mode
+ * 1996-07-22 fl Added getbbox, offset
+ * 1996-07-23 fl Added sequence semantics
+ * 1996-08-13 fl Added logical operators, point mode
+ * 1996-08-16 fl Modified paste interface
+ * 1996-09-06 fl Added putdata methods, use abstract interface
+ * 1996-11-01 fl Added xbm encoder
+ * 1996-11-04 fl Added experimental path stuff, draw_lines, etc
+ * 1996-12-10 fl Added zip decoder, crc32 interface
+ * 1996-12-14 fl Added modulo arithmetics
+ * 1996-12-29 fl Added zip encoder
+ * 1997-01-03 fl Added fli and msp decoders
+ * 1997-01-04 fl Added experimental sun_rle and tga_rle decoders
+ * 1997-01-05 fl Added gif encoder, getpalette hack
+ * 1997-02-23 fl Added histogram mask
+ * 1997-05-12 fl Minor tweaks to match the IFUNC95 interface
+ * 1997-05-21 fl Added noise generator, spread effect
+ * 1997-06-05 fl Added mandelbrot generator
+ * 1997-08-02 fl Modified putpalette to coerce image mode if necessary
+ * 1998-01-11 fl Added INT32 support
+ * 1998-01-22 fl Fixed draw_points to draw the last point too
+ * 1998-06-28 fl Added getpixel, getink, draw_ink
+ * 1998-07-12 fl Added getextrema
+ * 1998-07-17 fl Added point conversion to arbitrary formats
+ * 1998-09-21 fl Added support for resampling filters
+ * 1998-09-22 fl Added support for quad transform
+ * 1998-12-29 fl Added support for arcs, chords, and pieslices
+ * 1999-01-10 fl Added some experimental arrow graphics stuff
+ * 1999-02-06 fl Added draw_bitmap, font acceleration stuff
+ * 2001-04-17 fl Fixed some egcs compiler nits
+ * 2001-09-17 fl Added screen grab primitives (win32)
+ * 2002-03-09 fl Added stretch primitive
+ * 2002-03-10 fl Fixed filter handling in rotate
+ * 2002-06-06 fl Added I, F, and RGB support to putdata
+ * 2002-06-08 fl Added rankfilter
+ * 2002-06-09 fl Added support for user-defined filter kernels
+ * 2002-11-19 fl Added clipboard grab primitives (win32)
+ * 2002-12-11 fl Added draw context
+ * 2003-04-26 fl Tweaks for Python 2.3 beta 1
+ * 2003-05-21 fl Added createwindow primitive (win32)
+ * 2003-09-13 fl Added thread section hooks
+ * 2003-09-15 fl Added expand helper
+ * 2003-09-26 fl Added experimental LA support
+ * 2004-02-21 fl Handle zero-size images in quantize
+ * 2004-06-05 fl Added ptr attribute (used to access Imaging objects)
+ * 2004-06-05 fl Don't crash when fetching pixels from zero-wide images
+ * 2004-09-17 fl Added getcolors
+ * 2004-10-04 fl Added modefilter
+ * 2005-10-02 fl Added access proxy
+ * 2006-06-18 fl Always draw last point in polyline
+ *
+ * Copyright (c) 1997-2006 by Secret Labs AB
+ * Copyright (c) 1995-2006 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h"
+
+#ifdef HAVE_LIBJPEG
+#include "jconfig.h"
+#endif
+
+#ifdef HAVE_LIBZ
+#include "zlib.h"
+#endif
+
+#include "Imaging.h"
+
+#include "py3.h"
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+/* Configuration stuff. Feel free to undef things you don't need. */
+#define WITH_IMAGECHOPS /* ImageChops support */
+#define WITH_IMAGEDRAW /* ImageDraw support */
+#define WITH_MAPPING /* use memory mapping to read some file formats */
+#define WITH_IMAGEPATH /* ImagePath stuff */
+#define WITH_ARROW /* arrow graphics stuff (experimental) */
+#define WITH_EFFECTS /* special effects */
+#define WITH_QUANTIZE /* quantization support */
+#define WITH_RANKFILTER /* rank filter */
+#define WITH_MODEFILTER /* mode filter */
+#define WITH_THREADING /* "friendly" threading support */
+#define WITH_UNSHARPMASK /* Kevin Cazabon's unsharpmask module */
+
+#undef VERBOSE
+
+#define B16(p, i) ((((int)p[(i)]) << 8) + p[(i)+1])
+#define L16(p, i) ((((int)p[(i)+1]) << 8) + p[(i)])
+#define S16(v) ((v) < 32768 ? (v) : ((v) - 65536))
+
+/* -------------------------------------------------------------------- */
+/* OBJECT ADMINISTRATION */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ PyObject_HEAD
+ Imaging image;
+ ImagingAccess access;
+} ImagingObject;
+
+static PyTypeObject Imaging_Type;
+
+#ifdef WITH_IMAGEDRAW
+
+typedef struct
+{
+ /* to write a character, cut out sxy from glyph data, place
+ at current position plus dxy, and advance by (dx, dy) */
+ int dx, dy;
+ int dx0, dy0, dx1, dy1;
+ int sx0, sy0, sx1, sy1;
+} Glyph;
+
+typedef struct {
+ PyObject_HEAD
+ ImagingObject* ref;
+ Imaging bitmap;
+ int ysize;
+ int baseline;
+ Glyph glyphs[256];
+} ImagingFontObject;
+
+static PyTypeObject ImagingFont_Type;
+
+typedef struct {
+ PyObject_HEAD
+ ImagingObject* image;
+ UINT8 ink[4];
+ int blend;
+} ImagingDrawObject;
+
+static PyTypeObject ImagingDraw_Type;
+
+#endif
+
+typedef struct {
+ PyObject_HEAD
+ ImagingObject* image;
+ int readonly;
+} PixelAccessObject;
+
+static PyTypeObject PixelAccess_Type;
+
+PyObject*
+PyImagingNew(Imaging imOut)
+{
+ ImagingObject* imagep;
+
+ if (!imOut)
+ return NULL;
+
+ imagep = PyObject_New(ImagingObject, &Imaging_Type);
+ if (imagep == NULL) {
+ ImagingDelete(imOut);
+ return NULL;
+ }
+
+#ifdef VERBOSE
+ printf("imaging %p allocated\n", imagep);
+#endif
+
+ imagep->image = imOut;
+ imagep->access = ImagingAccessNew(imOut);
+
+ return (PyObject*) imagep;
+}
+
+static void
+_dealloc(ImagingObject* imagep)
+{
+
+#ifdef VERBOSE
+ printf("imaging %p deleted\n", imagep);
+#endif
+
+ if (imagep->access)
+ ImagingAccessDelete(imagep->image, imagep->access);
+ ImagingDelete(imagep->image);
+ PyObject_Del(imagep);
+}
+
+#define PyImaging_Check(op) (Py_TYPE(op) == &Imaging_Type)
+
+Imaging PyImaging_AsImaging(PyObject *op)
+{
+ if (!PyImaging_Check(op)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ return ((ImagingObject *)op)->image;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* THREAD HANDLING */
+/* -------------------------------------------------------------------- */
+
+void ImagingSectionEnter(ImagingSectionCookie* cookie)
+{
+#ifdef WITH_THREADING
+ *cookie = (PyThreadState *) PyEval_SaveThread();
+#endif
+}
+
+void ImagingSectionLeave(ImagingSectionCookie* cookie)
+{
+#ifdef WITH_THREADING
+ PyEval_RestoreThread((PyThreadState*) *cookie);
+#endif
+}
+
+/* -------------------------------------------------------------------- */
+/* BUFFER HANDLING */
+/* -------------------------------------------------------------------- */
+/* Python compatibility API */
+
+int PyImaging_CheckBuffer(PyObject* buffer)
+{
+#if PY_VERSION_HEX >= 0x03000000
+ return PyObject_CheckBuffer(buffer);
+#else
+ return PyObject_CheckBuffer(buffer) || PyObject_CheckReadBuffer(buffer);
+#endif
+}
+
+int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view)
+{
+ /* must call check_buffer first! */
+#if PY_VERSION_HEX >= 0x03000000
+ return PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE);
+#else
+ /* Use new buffer protocol if available
+ (mmap doesn't support this in 2.7, go figure) */
+ if (PyObject_CheckBuffer(buffer)) {
+ int success = PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE);
+ if (!success) { return success; }
+ PyErr_Clear();
+ }
+
+ /* Pretend we support the new protocol; PyBuffer_Release happily ignores
+ calling bf_releasebuffer on objects that don't support it */
+ view->buf = NULL;
+ view->len = 0;
+ view->readonly = 1;
+ view->format = NULL;
+ view->ndim = 0;
+ view->shape = NULL;
+ view->strides = NULL;
+ view->suboffsets = NULL;
+ view->itemsize = 0;
+ view->internal = NULL;
+
+ Py_INCREF(buffer);
+ view->obj = buffer;
+
+ return PyObject_AsReadBuffer(buffer, (void *) &view->buf, &view->len);
+#endif
+}
+
+/* -------------------------------------------------------------------- */
+/* EXCEPTION REROUTING */
+/* -------------------------------------------------------------------- */
+
+/* error messages */
+static const char* must_be_sequence = "argument must be a sequence";
+static const char* must_be_two_coordinates =
+ "coordinate list must contain exactly 2 coordinates";
+static const char* wrong_mode = "unrecognized image mode";
+static const char* wrong_raw_mode = "unrecognized raw mode";
+static const char* outside_image = "image index out of range";
+static const char* outside_palette = "palette index out of range";
+static const char* wrong_palette_size = "invalid palette size";
+static const char* no_palette = "image has no palette";
+static const char* readonly = "image is readonly";
+/* static const char* no_content = "image has no content"; */
+
+void *
+ImagingError_IOError(void)
+{
+ PyErr_SetString(PyExc_IOError, "error when accessing file");
+ return NULL;
+}
+
+void *
+ImagingError_MemoryError(void)
+{
+ return PyErr_NoMemory();
+}
+
+void *
+ImagingError_Mismatch(void)
+{
+ PyErr_SetString(PyExc_ValueError, "images do not match");
+ return NULL;
+}
+
+void *
+ImagingError_ModeError(void)
+{
+ PyErr_SetString(PyExc_ValueError, "image has wrong mode");
+ return NULL;
+}
+
+void *
+ImagingError_ValueError(const char *message)
+{
+ PyErr_SetString(
+ PyExc_ValueError,
+ (message) ? (char*) message : "unrecognized argument value"
+ );
+ return NULL;
+}
+
+void
+ImagingError_Clear(void)
+{
+ PyErr_Clear();
+}
+
+/* -------------------------------------------------------------------- */
+/* HELPERS */
+/* -------------------------------------------------------------------- */
+
+static int
+getbands(const char* mode)
+{
+ Imaging im;
+ int bands;
+
+ /* FIXME: add primitive to libImaging to avoid extra allocation */
+ im = ImagingNew(mode, 0, 0);
+ if (!im)
+ return -1;
+
+ bands = im->bands;
+
+ ImagingDelete(im);
+
+ return bands;
+}
+
+#define TYPE_UINT8 (0x100|sizeof(UINT8))
+#define TYPE_INT32 (0x200|sizeof(INT32))
+#define TYPE_FLOAT16 (0x500|sizeof(FLOAT16))
+#define TYPE_FLOAT32 (0x300|sizeof(FLOAT32))
+#define TYPE_DOUBLE (0x400|sizeof(double))
+
+static void*
+getlist(PyObject* arg, Py_ssize_t* length, const char* wrong_length, int type)
+{
+ /* - allocates and returns a c array of the items in the
+ python sequence arg.
+ - the size of the returned array is in length
+ - all of the arg items must be numeric items of the type
+ specified in type
+ - sequence length is checked against the length parameter IF
+ an error parameter is passed in wrong_length
+ - caller is responsible for freeing the memory
+ */
+
+ Py_ssize_t i, n;
+ int itemp;
+ double dtemp;
+ FLOAT32 ftemp;
+ UINT8* list;
+ PyObject* seq;
+ PyObject* op;
+
+ if ( ! PySequence_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, must_be_sequence);
+ return NULL;
+ }
+
+ n = PySequence_Size(arg);
+ if (length && wrong_length && n != *length) {
+ PyErr_SetString(PyExc_ValueError, wrong_length);
+ return NULL;
+ }
+
+ /* malloc check ok, type & ff is just a sizeof(something)
+ calloc checks for overflow */
+ list = calloc(n, type & 0xff);
+ if ( ! list)
+ return PyErr_NoMemory();
+
+ seq = PySequence_Fast(arg, must_be_sequence);
+ if ( ! seq) {
+ free(list);
+ return NULL;
+ }
+
+ for (i = 0; i < n; i++) {
+ op = PySequence_Fast_GET_ITEM(seq, i);
+ // DRY, branch prediction is going to work _really_ well
+ // on this switch. And 3 fewer loops to copy/paste.
+ switch (type) {
+ case TYPE_UINT8:
+ itemp = PyInt_AsLong(op);
+ list[i] = CLIP8(itemp);
+ break;
+ case TYPE_INT32:
+ itemp = PyInt_AsLong(op);
+ memcpy(list + i * sizeof(INT32), &itemp, sizeof(itemp));
+ break;
+ case TYPE_FLOAT32:
+ ftemp = (FLOAT32)PyFloat_AsDouble(op);
+ memcpy(list + i * sizeof(ftemp), &ftemp, sizeof(ftemp));
+ break;
+ case TYPE_DOUBLE:
+ dtemp = PyFloat_AsDouble(op);
+ memcpy(list + i * sizeof(dtemp), &dtemp, sizeof(dtemp));
+ break;
+ }
+ }
+
+ Py_DECREF(seq);
+
+ if (PyErr_Occurred()) {
+ free(list);
+ return NULL;
+ }
+
+ if (length)
+ *length = n;
+
+ return list;
+}
+
+FLOAT32
+float16tofloat32(const FLOAT16 in) {
+ UINT32 t1;
+ UINT32 t2;
+ UINT32 t3;
+ FLOAT32 out[1] = {0};
+
+ t1 = in & 0x7fff; // Non-sign bits
+ t2 = in & 0x8000; // Sign bit
+ t3 = in & 0x7c00; // Exponent
+
+ t1 <<= 13; // Align mantissa on MSB
+ t2 <<= 16; // Shift sign bit into position
+
+ t1 += 0x38000000; // Adjust bias
+
+ t1 = (t3 == 0 ? 0 : t1); // Denormals-as-zero
+
+ t1 |= t2; // Re-insert sign bit
+
+ memcpy(out, &t1, 4);
+ return out[0];
+}
+
+static inline PyObject*
+getpixel(Imaging im, ImagingAccess access, int x, int y)
+{
+ union {
+ UINT8 b[4];
+ UINT16 h;
+ INT32 i;
+ FLOAT32 f;
+ } pixel;
+
+ if (x < 0) {
+ x = im->xsize + x;
+ }
+ if (y < 0) {
+ y = im->ysize + y;
+ }
+
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
+ PyErr_SetString(PyExc_IndexError, outside_image);
+ return NULL;
+ }
+
+ access->get_pixel(im, x, y, &pixel);
+
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ switch (im->bands) {
+ case 1:
+ return PyInt_FromLong(pixel.b[0]);
+ case 2:
+ return Py_BuildValue("BB", pixel.b[0], pixel.b[1]);
+ case 3:
+ return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]);
+ case 4:
+ return Py_BuildValue("BBBB", pixel.b[0], pixel.b[1], pixel.b[2], pixel.b[3]);
+ }
+ break;
+ case IMAGING_TYPE_INT32:
+ return PyInt_FromLong(pixel.i);
+ case IMAGING_TYPE_FLOAT32:
+ return PyFloat_FromDouble(pixel.f);
+ case IMAGING_TYPE_SPECIAL:
+ if (strncmp(im->mode, "I;16", 4) == 0)
+ return PyInt_FromLong(pixel.h);
+ break;
+ }
+
+ /* unknown type */
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char*
+getink(PyObject* color, Imaging im, char* ink)
+{
+ int g=0, b=0, a=0;
+ double f=0;
+ /* Windows 64 bit longs are 32 bits, and 0xFFFFFFFF (white) is a
+ python long (not int) that raises an overflow error when trying
+ to return it into a 32 bit C long
+ */
+ PY_LONG_LONG r = 0;
+ FLOAT32 ftmp;
+ INT32 itmp;
+
+ /* fill ink buffer (four bytes) with something that can
+ be cast to either UINT8 or INT32 */
+
+ int rIsInt = 0;
+ if (im->type == IMAGING_TYPE_UINT8 ||
+ im->type == IMAGING_TYPE_INT32 ||
+ im->type == IMAGING_TYPE_SPECIAL) {
+#if PY_VERSION_HEX >= 0x03000000
+ if (PyLong_Check(color)) {
+ r = PyLong_AsLongLong(color);
+#else
+ if (PyInt_Check(color) || PyLong_Check(color)) {
+ if (PyInt_Check(color))
+ r = PyInt_AS_LONG(color);
+ else
+ r = PyLong_AsLongLong(color);
+#endif
+ rIsInt = 1;
+ }
+ if (r == -1 && PyErr_Occurred()) {
+ rIsInt = 0;
+ }
+ }
+
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ /* unsigned integer */
+ if (im->bands == 1) {
+ /* unsigned integer, single layer */
+ if (rIsInt != 1) {
+ if (!PyArg_ParseTuple(color, "L", &r)) {
+ return NULL;
+ }
+ }
+ ink[0] = (char) CLIP8(r);
+ ink[1] = ink[2] = ink[3] = 0;
+ } else {
+ a = 255;
+ if (rIsInt) {
+ /* compatibility: ABGR */
+ a = (UINT8) (r >> 24);
+ b = (UINT8) (r >> 16);
+ g = (UINT8) (r >> 8);
+ r = (UINT8) r;
+ } else {
+ if (im->bands == 2) {
+ if (!PyArg_ParseTuple(color, "L|i", &r, &a))
+ return NULL;
+ g = b = r;
+ } else {
+ if (!PyArg_ParseTuple(color, "Lii|i", &r, &g, &b, &a))
+ return NULL;
+ }
+ }
+ ink[0] = (char) CLIP8(r);
+ ink[1] = (char) CLIP8(g);
+ ink[2] = (char) CLIP8(b);
+ ink[3] = (char) CLIP8(a);
+ }
+ return ink;
+ case IMAGING_TYPE_INT32:
+ /* signed integer */
+ if (rIsInt != 1)
+ return NULL;
+ itmp = r;
+ memcpy(ink, &itmp, sizeof(itmp));
+ return ink;
+ case IMAGING_TYPE_FLOAT32:
+ /* floating point */
+ f = PyFloat_AsDouble(color);
+ if (f == -1.0 && PyErr_Occurred())
+ return NULL;
+ ftmp = f;
+ memcpy(ink, &ftmp, sizeof(ftmp));
+ return ink;
+ case IMAGING_TYPE_SPECIAL:
+ if (strncmp(im->mode, "I;16", 4) == 0) {
+ if (rIsInt != 1)
+ return NULL;
+ ink[0] = (UINT8) r;
+ ink[1] = (UINT8) (r >> 8);
+ ink[2] = ink[3] = 0;
+ return ink;
+ }
+ }
+
+ PyErr_SetString(PyExc_ValueError, wrong_mode);
+ return NULL;
+}
+
+/* -------------------------------------------------------------------- */
+/* FACTORIES */
+/* -------------------------------------------------------------------- */
+
+static PyObject*
+_fill(PyObject* self, PyObject* args)
+{
+ char* mode;
+ int xsize, ysize;
+ PyObject* color;
+ char buffer[4];
+ Imaging im;
+
+ xsize = ysize = 256;
+ color = NULL;
+
+ if (!PyArg_ParseTuple(args, "s|(ii)O", &mode, &xsize, &ysize, &color))
+ return NULL;
+
+ im = ImagingNewDirty(mode, xsize, ysize);
+ if (!im)
+ return NULL;
+
+ buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0;
+ if (color) {
+ if (!getink(color, im, buffer)) {
+ ImagingDelete(im);
+ return NULL;
+ }
+ }
+
+
+ (void) ImagingFill(im, buffer);
+
+ return PyImagingNew(im);
+}
+
+static PyObject*
+_new(PyObject* self, PyObject* args)
+{
+ char* mode;
+ int xsize, ysize;
+
+ if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize))
+ return NULL;
+
+ return PyImagingNew(ImagingNew(mode, xsize, ysize));
+}
+
+static PyObject*
+_new_block(PyObject* self, PyObject* args)
+{
+ char* mode;
+ int xsize, ysize;
+
+ if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize))
+ return NULL;
+
+ return PyImagingNew(ImagingNewBlock(mode, xsize, ysize));
+}
+
+static PyObject*
+_linear_gradient(PyObject* self, PyObject* args)
+{
+ char* mode;
+
+ if (!PyArg_ParseTuple(args, "s", &mode))
+ return NULL;
+
+ return PyImagingNew(ImagingFillLinearGradient(mode));
+}
+
+static PyObject*
+_radial_gradient(PyObject* self, PyObject* args)
+{
+ char* mode;
+
+ if (!PyArg_ParseTuple(args, "s", &mode))
+ return NULL;
+
+ return PyImagingNew(ImagingFillRadialGradient(mode));
+}
+
+static PyObject*
+_alpha_composite(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep1;
+ ImagingObject* imagep2;
+
+ if (!PyArg_ParseTuple(args, "O!O!",
+ &Imaging_Type, &imagep1,
+ &Imaging_Type, &imagep2))
+ return NULL;
+
+ return PyImagingNew(ImagingAlphaComposite(imagep1->image, imagep2->image));
+}
+
+static PyObject*
+_blend(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep1;
+ ImagingObject* imagep2;
+ double alpha;
+
+ alpha = 0.5;
+ if (!PyArg_ParseTuple(args, "O!O!|d",
+ &Imaging_Type, &imagep1,
+ &Imaging_Type, &imagep2,
+ &alpha))
+ return NULL;
+
+ return PyImagingNew(ImagingBlend(imagep1->image, imagep2->image,
+ (float) alpha));
+}
+
+/* -------------------------------------------------------------------- */
+/* METHODS */
+/* -------------------------------------------------------------------- */
+
+static INT16*
+_prepare_lut_table(PyObject* table, Py_ssize_t table_size)
+{
+ int i;
+ Py_buffer buffer_info;
+ INT32 data_type = TYPE_FLOAT32;
+ float item = 0;
+ void* table_data = NULL;
+ int free_table_data = 0;
+ INT16* prepared;
+
+ /* NOTE: This value should be the same as in ColorLUT.c */
+ #define PRECISION_BITS (16 - 8 - 2)
+
+ const char* wrong_size = ("The table should have table_channels * "
+ "size1D * size2D * size3D float items.");
+
+ if (PyObject_CheckBuffer(table)) {
+ if ( ! PyObject_GetBuffer(table, &buffer_info,
+ PyBUF_CONTIG_RO | PyBUF_FORMAT)) {
+ if (buffer_info.ndim == 1 && buffer_info.shape[0] == table_size) {
+ if (strlen(buffer_info.format) == 1) {
+ switch (buffer_info.format[0]) {
+ case 'e':
+ data_type = TYPE_FLOAT16;
+ table_data = buffer_info.buf;
+ break;
+ case 'f':
+ data_type = TYPE_FLOAT32;
+ table_data = buffer_info.buf;
+ break;
+ case 'd':
+ data_type = TYPE_DOUBLE;
+ table_data = buffer_info.buf;
+ break;
+ }
+ }
+ }
+ PyBuffer_Release(&buffer_info);
+ }
+ }
+
+ if ( ! table_data) {
+ free_table_data = 1;
+ table_data = getlist(table, &table_size, wrong_size, TYPE_FLOAT32);
+ if ( ! table_data) {
+ return NULL;
+ }
+ }
+
+ /* malloc check ok, max is 2 * 4 * 65**3 = 2197000 */
+ prepared = (INT16*) malloc(sizeof(INT16) * table_size);
+ if ( ! prepared) {
+ if (free_table_data)
+ free(table_data);
+ return (INT16*) PyErr_NoMemory();
+ }
+
+ for (i = 0; i < table_size; i++) {
+ FLOAT16 htmp;
+ double dtmp;
+ switch (data_type) {
+ case TYPE_FLOAT16:
+ memcpy(&htmp, ((char*) table_data) + i * sizeof(htmp), sizeof(htmp));
+ item = float16tofloat32(htmp);
+ break;
+ case TYPE_FLOAT32:
+ memcpy(&item, ((char*) table_data) + i * sizeof(FLOAT32), sizeof(FLOAT32));
+ break;
+ case TYPE_DOUBLE:
+ memcpy(&dtmp, ((char*) table_data) + i * sizeof(dtmp), sizeof(dtmp));
+ item = (FLOAT32) dtmp;
+ break;
+ }
+ /* Max value for INT16 */
+ if (item >= (0x7fff - 0.5) / (255 << PRECISION_BITS)) {
+ prepared[i] = 0x7fff;
+ continue;
+ }
+ /* Min value for INT16 */
+ if (item <= (-0x8000 + 0.5) / (255 << PRECISION_BITS)) {
+ prepared[i] = -0x8000;
+ continue;
+ }
+ if (item < 0) {
+ prepared[i] = item * (255 << PRECISION_BITS) - 0.5;
+ } else {
+ prepared[i] = item * (255 << PRECISION_BITS) + 0.5;
+ }
+ }
+
+ #undef PRECISION_BITS
+ if (free_table_data) {
+ free(table_data);
+ }
+ return prepared;
+}
+
+
+static PyObject*
+_color_lut_3d(ImagingObject* self, PyObject* args)
+{
+ char* mode;
+ int filter;
+ int table_channels;
+ int size1D, size2D, size3D;
+ PyObject* table;
+
+ INT16* prepared_table;
+ Imaging imOut;
+
+ if ( ! PyArg_ParseTuple(args, "siiiiiO:color_lut_3d", &mode, &filter,
+ &table_channels, &size1D, &size2D, &size3D,
+ &table)) {
+ return NULL;
+ }
+
+ /* actually, it is trilinear */
+ if (filter != IMAGING_TRANSFORM_BILINEAR) {
+ PyErr_SetString(PyExc_ValueError,
+ "Only LINEAR filter is supported.");
+ return NULL;
+ }
+
+ if (1 > table_channels || table_channels > 4) {
+ PyErr_SetString(PyExc_ValueError,
+ "table_channels should be from 1 to 4");
+ return NULL;
+ }
+
+ if (2 > size1D || size1D > 65 ||
+ 2 > size2D || size2D > 65 ||
+ 2 > size3D || size3D > 65
+ ) {
+ PyErr_SetString(PyExc_ValueError,
+ "Table size in any dimension should be from 2 to 65");
+ return NULL;
+ }
+
+ prepared_table = _prepare_lut_table(
+ table, table_channels * size1D * size2D * size3D);
+ if ( ! prepared_table) {
+ return NULL;
+ }
+
+ imOut = ImagingNewDirty(mode, self->image->xsize, self->image->ysize);
+ if ( ! imOut) {
+ free(prepared_table);
+ return NULL;
+ }
+
+ if ( ! ImagingColorLUT3D_linear(imOut, self->image,
+ table_channels, size1D, size2D, size3D,
+ prepared_table)) {
+ free(prepared_table);
+ ImagingDelete(imOut);
+ return NULL;
+ }
+
+ free(prepared_table);
+
+ return PyImagingNew(imOut);
+}
+
+static PyObject*
+_convert(ImagingObject* self, PyObject* args)
+{
+ char* mode;
+ int dither = 0;
+ ImagingObject *paletteimage = NULL;
+
+ if (!PyArg_ParseTuple(args, "s|iO", &mode, &dither, &paletteimage))
+ return NULL;
+ if (paletteimage != NULL) {
+ if (!PyImaging_Check(paletteimage)) {
+ PyObject_Print((PyObject *)paletteimage, stderr, 0);
+ PyErr_SetString(PyExc_ValueError, "palette argument must be image with mode 'P'");
+ return NULL;
+ }
+ if (paletteimage->image->palette == NULL) {
+ PyErr_SetString(PyExc_ValueError, "null palette");
+ return NULL;
+ }
+ }
+
+ return PyImagingNew(ImagingConvert(self->image, mode, paletteimage ? paletteimage->image->palette : NULL, dither));
+}
+
+static PyObject*
+_convert2(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep1;
+ ImagingObject* imagep2;
+ if (!PyArg_ParseTuple(args, "O!O!",
+ &Imaging_Type, &imagep1,
+ &Imaging_Type, &imagep2))
+ return NULL;
+
+ if (!ImagingConvert2(imagep1->image, imagep2->image))
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_convert_matrix(ImagingObject* self, PyObject* args)
+{
+ char* mode;
+ float m[12];
+ if (!PyArg_ParseTuple(args, "s(ffff)", &mode, m+0, m+1, m+2, m+3)) {
+ PyErr_Clear();
+ if (!PyArg_ParseTuple(args, "s(ffffffffffff)", &mode,
+ m+0, m+1, m+2, m+3,
+ m+4, m+5, m+6, m+7,
+ m+8, m+9, m+10, m+11)){
+ return NULL;
+ }
+ }
+
+ return PyImagingNew(ImagingConvertMatrix(self->image, mode, m));
+}
+
+static PyObject*
+_convert_transparent(ImagingObject* self, PyObject* args)
+{
+ char* mode;
+ int r,g,b;
+ if (PyArg_ParseTuple(args, "s(iii)", &mode, &r, &g, &b)) {
+ return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, g, b));
+ }
+ PyErr_Clear();
+ if (PyArg_ParseTuple(args, "si", &mode, &r)) {
+ return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, 0, 0));
+ }
+ return NULL;
+}
+
+static PyObject*
+_copy(ImagingObject* self, PyObject* args)
+{
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ return PyImagingNew(ImagingCopy(self->image));
+}
+
+static PyObject*
+_crop(ImagingObject* self, PyObject* args)
+{
+ int x0, y0, x1, y1;
+ if (!PyArg_ParseTuple(args, "(iiii)", &x0, &y0, &x1, &y1))
+ return NULL;
+
+ return PyImagingNew(ImagingCrop(self->image, x0, y0, x1, y1));
+}
+
+static PyObject*
+_expand_image(ImagingObject* self, PyObject* args)
+{
+ int x, y;
+ int mode = 0;
+ if (!PyArg_ParseTuple(args, "ii|i", &x, &y, &mode))
+ return NULL;
+
+ return PyImagingNew(ImagingExpand(self->image, x, y, mode));
+}
+
+static PyObject*
+_filter(ImagingObject* self, PyObject* args)
+{
+ PyObject* imOut;
+ Py_ssize_t kernelsize;
+ FLOAT32* kerneldata;
+
+ int xsize, ysize, i;
+ float divisor, offset;
+ PyObject* kernel = NULL;
+ if (!PyArg_ParseTuple(args, "(ii)ffO", &xsize, &ysize,
+ &divisor, &offset, &kernel))
+ return NULL;
+
+ /* get user-defined kernel */
+ kerneldata = getlist(kernel, &kernelsize, NULL, TYPE_FLOAT32);
+ if (!kerneldata)
+ return NULL;
+ if (kernelsize != (Py_ssize_t) xsize * (Py_ssize_t) ysize) {
+ free(kerneldata);
+ return ImagingError_ValueError("bad kernel size");
+ }
+
+ for (i = 0; i < kernelsize; ++i) {
+ kerneldata[i] /= divisor;
+ }
+
+ imOut = PyImagingNew(
+ ImagingFilter(self->image, xsize, ysize, kerneldata, offset)
+ );
+
+ free(kerneldata);
+
+ return imOut;
+}
+
+#ifdef WITH_UNSHARPMASK
+static PyObject*
+_gaussian_blur(ImagingObject* self, PyObject* args)
+{
+ Imaging imIn;
+ Imaging imOut;
+
+ float radius = 0;
+ int passes = 3;
+ if (!PyArg_ParseTuple(args, "f|i", &radius, &passes))
+ return NULL;
+
+ imIn = self->image;
+ imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
+ if (!imOut)
+ return NULL;
+
+ if (!ImagingGaussianBlur(imOut, imIn, radius, passes)) {
+ ImagingDelete(imOut);
+ return NULL;
+ }
+
+ return PyImagingNew(imOut);
+}
+#endif
+
+static PyObject*
+_getpalette(ImagingObject* self, PyObject* args)
+{
+ PyObject* palette;
+ int palettesize = 256;
+ int bits;
+ ImagingShuffler pack;
+
+ char* mode = "RGB";
+ char* rawmode = "RGB";
+ if (!PyArg_ParseTuple(args, "|ss", &mode, &rawmode))
+ return NULL;
+
+ if (!self->image->palette) {
+ PyErr_SetString(PyExc_ValueError, no_palette);
+ return NULL;
+ }
+
+ pack = ImagingFindPacker(mode, rawmode, &bits);
+ if (!pack) {
+ PyErr_SetString(PyExc_ValueError, wrong_raw_mode);
+ return NULL;
+ }
+
+ palette = PyBytes_FromStringAndSize(NULL, palettesize * bits / 8);
+ if (!palette)
+ return NULL;
+
+ pack((UINT8*) PyBytes_AsString(palette),
+ self->image->palette->palette, palettesize);
+
+ return palette;
+}
+
+static PyObject*
+_getpalettemode(ImagingObject* self, PyObject* args)
+{
+ if (!self->image->palette) {
+ PyErr_SetString(PyExc_ValueError, no_palette);
+ return NULL;
+ }
+
+ return PyUnicode_FromString(self->image->palette->mode);
+}
+
+static inline int
+_getxy(PyObject* xy, int* x, int *y)
+{
+ PyObject* value;
+
+ if (!PyTuple_Check(xy) || PyTuple_GET_SIZE(xy) != 2)
+ goto badarg;
+
+ value = PyTuple_GET_ITEM(xy, 0);
+ if (PyInt_Check(value))
+ *x = PyInt_AS_LONG(value);
+ else if (PyFloat_Check(value))
+ *x = (int) PyFloat_AS_DOUBLE(value);
+ else
+ goto badval;
+
+ value = PyTuple_GET_ITEM(xy, 1);
+ if (PyInt_Check(value))
+ *y = PyInt_AS_LONG(value);
+ else if (PyFloat_Check(value))
+ *y = (int) PyFloat_AS_DOUBLE(value);
+ else
+ goto badval;
+
+ return 0;
+
+ badarg:
+ PyErr_SetString(
+ PyExc_TypeError,
+ "argument must be sequence of length 2"
+ );
+ return -1;
+
+ badval:
+ PyErr_SetString(
+ PyExc_TypeError,
+ "an integer is required"
+ );
+ return -1;
+}
+
+static PyObject*
+_getpixel(ImagingObject* self, PyObject* args)
+{
+ PyObject* xy;
+ int x, y;
+
+ if (PyTuple_GET_SIZE(args) != 1) {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "argument 1 must be sequence of length 2"
+ );
+ return NULL;
+ }
+
+ xy = PyTuple_GET_ITEM(args, 0);
+
+ if (_getxy(xy, &x, &y))
+ return NULL;
+
+ if (self->access == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return getpixel(self->image, self->access, x, y);
+}
+
+union hist_extrema {
+ UINT8 u[2];
+ INT32 i[2];
+ FLOAT32 f[2];
+};
+
+static union hist_extrema*
+parse_histogram_extremap(ImagingObject* self, PyObject* extremap,
+ union hist_extrema* ep)
+{
+ int i0, i1;
+ double f0, f1;
+
+ if (extremap) {
+ switch (self->image->type) {
+ case IMAGING_TYPE_UINT8:
+ if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1))
+ return NULL;
+ ep->u[0] = CLIP8(i0);
+ ep->u[1] = CLIP8(i1);
+ break;
+ case IMAGING_TYPE_INT32:
+ if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1))
+ return NULL;
+ ep->i[0] = i0;
+ ep->i[1] = i1;
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ if (!PyArg_ParseTuple(extremap, "dd", &f0, &f1))
+ return NULL;
+ ep->f[0] = (FLOAT32) f0;
+ ep->f[1] = (FLOAT32) f1;
+ break;
+ default:
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ return ep;
+}
+
+static PyObject*
+_histogram(ImagingObject* self, PyObject* args)
+{
+ ImagingHistogram h;
+ PyObject* list;
+ int i;
+ union hist_extrema extrema;
+ union hist_extrema* ep;
+
+ PyObject* extremap = NULL;
+ ImagingObject* maskp = NULL;
+ if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp))
+ return NULL;
+
+ /* Using a var to avoid allocations. */
+ ep = parse_histogram_extremap(self, extremap, &extrema);
+ h = ImagingGetHistogram(self->image, (maskp) ? maskp->image : NULL, ep);
+
+ if (!h)
+ return NULL;
+
+ /* Build an integer list containing the histogram */
+ list = PyList_New(h->bands * 256);
+ for (i = 0; i < h->bands * 256; i++) {
+ PyObject* item;
+ item = PyInt_FromLong(h->histogram[i]);
+ if (item == NULL) {
+ Py_DECREF(list);
+ list = NULL;
+ break;
+ }
+ PyList_SetItem(list, i, item);
+ }
+
+ /* Destroy the histogram structure */
+ ImagingHistogramDelete(h);
+
+ return list;
+}
+
+static PyObject*
+_entropy(ImagingObject* self, PyObject* args)
+{
+ ImagingHistogram h;
+ int idx, length;
+ long sum;
+ double entropy, fsum, p;
+ union hist_extrema extrema;
+ union hist_extrema* ep;
+
+ PyObject* extremap = NULL;
+ ImagingObject* maskp = NULL;
+ if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp))
+ return NULL;
+
+ /* Using a local var to avoid allocations. */
+ ep = parse_histogram_extremap(self, extremap, &extrema);
+ h = ImagingGetHistogram(self->image, (maskp) ? maskp->image : NULL, ep);
+
+ if (!h)
+ return NULL;
+
+ /* Calculate the histogram entropy */
+ /* First, sum the histogram data */
+ length = h->bands * 256;
+ sum = 0;
+ for (idx = 0; idx < length; idx++) {
+ sum += h->histogram[idx];
+ }
+
+ /* Next, normalize the histogram data, */
+ /* using the histogram sum value */
+ fsum = (double)sum;
+ entropy = 0.0;
+ for (idx = 0; idx < length; idx++) {
+ p = (double)h->histogram[idx] / fsum;
+ if (p != 0.0) {
+ entropy += p * log(p) * M_LOG2E;
+ }
+ }
+
+ /* Destroy the histogram structure */
+ ImagingHistogramDelete(h);
+
+ return PyFloat_FromDouble(-entropy);
+}
+
+#ifdef WITH_MODEFILTER
+static PyObject*
+_modefilter(ImagingObject* self, PyObject* args)
+{
+ int size;
+ if (!PyArg_ParseTuple(args, "i", &size))
+ return NULL;
+
+ return PyImagingNew(ImagingModeFilter(self->image, size));
+}
+#endif
+
+static PyObject*
+_offset(ImagingObject* self, PyObject* args)
+{
+ int xoffset, yoffset;
+ if (!PyArg_ParseTuple(args, "ii", &xoffset, &yoffset))
+ return NULL;
+
+ return PyImagingNew(ImagingOffset(self->image, xoffset, yoffset));
+}
+
+static PyObject*
+_paste(ImagingObject* self, PyObject* args)
+{
+ int status;
+ char ink[4];
+
+ PyObject* source;
+ int x0, y0, x1, y1;
+ ImagingObject* maskp = NULL;
+ if (!PyArg_ParseTuple(args, "O(iiii)|O!",
+ &source,
+ &x0, &y0, &x1, &y1,
+ &Imaging_Type, &maskp))
+ return NULL;
+
+ if (PyImaging_Check(source))
+ status = ImagingPaste(
+ self->image, PyImaging_AsImaging(source),
+ (maskp) ? maskp->image : NULL,
+ x0, y0, x1, y1
+ );
+
+ else {
+ if (!getink(source, self->image, ink))
+ return NULL;
+ status = ImagingFill2(
+ self->image, ink,
+ (maskp) ? maskp->image : NULL,
+ x0, y0, x1, y1
+ );
+ }
+
+ if (status < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_point(ImagingObject* self, PyObject* args)
+{
+ static const char* wrong_number = "wrong number of lut entries";
+
+ Py_ssize_t n;
+ int i, bands;
+ Imaging im;
+
+ PyObject* list;
+ char* mode;
+ if (!PyArg_ParseTuple(args, "Oz", &list, &mode))
+ return NULL;
+
+ if (mode && !strcmp(mode, "F")) {
+ FLOAT32* data;
+
+ /* map from 8-bit data to floating point */
+ n = 256;
+ data = getlist(list, &n, wrong_number, TYPE_FLOAT32);
+ if (!data)
+ return NULL;
+ im = ImagingPoint(self->image, mode, (void*) data);
+ free(data);
+
+ } else if (!strcmp(self->image->mode, "I") && mode && !strcmp(mode, "L")) {
+ UINT8* data;
+
+ /* map from 16-bit subset of 32-bit data to 8-bit */
+ /* FIXME: support arbitrary number of entries (requires API change) */
+ n = 65536;
+ data = getlist(list, &n, wrong_number, TYPE_UINT8);
+ if (!data)
+ return NULL;
+ im = ImagingPoint(self->image, mode, (void*) data);
+ free(data);
+
+ } else {
+ INT32* data;
+ UINT8 lut[1024];
+
+ if (mode) {
+ bands = getbands(mode);
+ if (bands < 0)
+ return NULL;
+ } else
+ bands = self->image->bands;
+
+ /* map to integer data */
+ n = 256 * bands;
+ data = getlist(list, &n, wrong_number, TYPE_INT32);
+ if (!data)
+ return NULL;
+
+ if (mode && !strcmp(mode, "I"))
+ im = ImagingPoint(self->image, mode, (void*) data);
+ else if (mode && bands > 1) {
+ for (i = 0; i < 256; i++) {
+ lut[i*4] = CLIP8(data[i]);
+ lut[i*4+1] = CLIP8(data[i+256]);
+ lut[i*4+2] = CLIP8(data[i+512]);
+ if (n > 768)
+ lut[i*4+3] = CLIP8(data[i+768]);
+ }
+ im = ImagingPoint(self->image, mode, (void*) lut);
+ } else {
+ /* map individual bands */
+ for (i = 0; i < n; i++)
+ lut[i] = CLIP8(data[i]);
+ im = ImagingPoint(self->image, mode, (void*) lut);
+ }
+ free(data);
+ }
+
+ return PyImagingNew(im);
+}
+
+static PyObject*
+_point_transform(ImagingObject* self, PyObject* args)
+{
+ double scale = 1.0;
+ double offset = 0.0;
+ if (!PyArg_ParseTuple(args, "|dd", &scale, &offset))
+ return NULL;
+
+ return PyImagingNew(ImagingPointTransform(self->image, scale, offset));
+}
+
+static PyObject*
+_putdata(ImagingObject* self, PyObject* args)
+{
+ Imaging image;
+ // i & n are # pixels, require py_ssize_t. x can be as large as n. y, just because.
+ Py_ssize_t n, i, x, y;
+
+ PyObject* data;
+ PyObject* seq = NULL;
+ PyObject* op;
+ double scale = 1.0;
+ double offset = 0.0;
+
+ if (!PyArg_ParseTuple(args, "O|dd", &data, &scale, &offset))
+ return NULL;
+
+ if (!PySequence_Check(data)) {
+ PyErr_SetString(PyExc_TypeError, must_be_sequence);
+ return NULL;
+ }
+
+ image = self->image;
+
+ n = PyObject_Length(data);
+ if (n > (Py_ssize_t)image->xsize * (Py_ssize_t)image->ysize) {
+ PyErr_SetString(PyExc_TypeError, "too many data entries");
+ return NULL;
+ }
+
+ if (image->image8) {
+ if (PyBytes_Check(data)) {
+ unsigned char* p;
+ p = (unsigned char*) PyBytes_AS_STRING(data);
+ if (scale == 1.0 && offset == 0.0)
+ /* Plain string data */
+ for (i = y = 0; i < n; i += image->xsize, y++) {
+ x = n - i;
+ if (x > (int) image->xsize)
+ x = image->xsize;
+ memcpy(image->image8[y], p+i, x);
+ }
+ else
+ /* Scaled and clipped string data */
+ for (i = x = y = 0; i < n; i++) {
+ image->image8[y][x] = CLIP8((int) (p[i] * scale + offset));
+ if (++x >= (int) image->xsize)
+ x = 0, y++;
+ }
+ } else {
+ seq = PySequence_Fast(data, must_be_sequence);
+ if (!seq) {
+ PyErr_SetString(PyExc_TypeError, must_be_sequence);
+ return NULL;
+ }
+ if (scale == 1.0 && offset == 0.0) {
+ /* Clipped data */
+ for (i = x = y = 0; i < n; i++) {
+ op = PySequence_Fast_GET_ITEM(seq, i);
+ image->image8[y][x] = (UINT8) CLIP8(PyInt_AsLong(op));
+ if (++x >= (int) image->xsize){
+ x = 0, y++;
+ }
+ }
+
+ } else {
+ /* Scaled and clipped data */
+ for (i = x = y = 0; i < n; i++) {
+ PyObject *op = PySequence_Fast_GET_ITEM(seq, i);
+ image->image8[y][x] = CLIP8(
+ (int) (PyFloat_AsDouble(op) * scale + offset));
+ if (++x >= (int) image->xsize){
+ x = 0, y++;
+ }
+ }
+ }
+ PyErr_Clear(); /* Avoid weird exceptions */
+ }
+ } else {
+ /* 32-bit images */
+ seq = PySequence_Fast(data, must_be_sequence);
+ if (!seq) {
+ PyErr_SetString(PyExc_TypeError, must_be_sequence);
+ return NULL;
+ }
+ switch (image->type) {
+ case IMAGING_TYPE_INT32:
+ for (i = x = y = 0; i < n; i++) {
+ op = PySequence_Fast_GET_ITEM(seq, i);
+ IMAGING_PIXEL_INT32(image, x, y) =
+ (INT32) (PyFloat_AsDouble(op) * scale + offset);
+ if (++x >= (int) image->xsize){
+ x = 0, y++;
+ }
+ }
+ PyErr_Clear(); /* Avoid weird exceptions */
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ for (i = x = y = 0; i < n; i++) {
+ op = PySequence_Fast_GET_ITEM(seq, i);
+ IMAGING_PIXEL_FLOAT32(image, x, y) =
+ (FLOAT32) (PyFloat_AsDouble(op) * scale + offset);
+ if (++x >= (int) image->xsize){
+ x = 0, y++;
+ }
+ }
+ PyErr_Clear(); /* Avoid weird exceptions */
+ break;
+ default:
+ for (i = x = y = 0; i < n; i++) {
+ union {
+ char ink[4];
+ INT32 inkint;
+ } u;
+
+ u.inkint = 0;
+
+ op = PySequence_Fast_GET_ITEM(seq, i);
+ if (!op || !getink(op, image, u.ink)) {
+ Py_DECREF(seq);
+ return NULL;
+ }
+ /* FIXME: what about scale and offset? */
+ image->image32[y][x] = u.inkint;
+ if (++x >= (int) image->xsize){
+ x = 0, y++;
+ }
+ }
+ PyErr_Clear(); /* Avoid weird exceptions */
+ break;
+ }
+ }
+
+ Py_XDECREF(seq);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#ifdef WITH_QUANTIZE
+
+static PyObject*
+_quantize(ImagingObject* self, PyObject* args)
+{
+ int colours = 256;
+ int method = 0;
+ int kmeans = 0;
+ if (!PyArg_ParseTuple(args, "|iii", &colours, &method, &kmeans))
+ return NULL;
+
+ if (!self->image->xsize || !self->image->ysize) {
+ /* no content; return an empty image */
+ return PyImagingNew(
+ ImagingNew("P", self->image->xsize, self->image->ysize)
+ );
+ }
+
+ return PyImagingNew(ImagingQuantize(self->image, colours, method, kmeans));
+}
+#endif
+
+static PyObject*
+_putpalette(ImagingObject* self, PyObject* args)
+{
+ ImagingShuffler unpack;
+ int bits;
+
+ char* rawmode;
+ UINT8* palette;
+ Py_ssize_t palettesize;
+ if (!PyArg_ParseTuple(args, "s"PY_ARG_BYTES_LENGTH, &rawmode, &palette, &palettesize))
+ return NULL;
+
+ if (strcmp(self->image->mode, "L") && strcmp(self->image->mode, "LA") &&
+ strcmp(self->image->mode, "P") && strcmp(self->image->mode, "PA")) {
+ PyErr_SetString(PyExc_ValueError, wrong_mode);
+ return NULL;
+ }
+
+ unpack = ImagingFindUnpacker("RGB", rawmode, &bits);
+ if (!unpack) {
+ PyErr_SetString(PyExc_ValueError, wrong_raw_mode);
+ return NULL;
+ }
+
+ if ( palettesize * 8 / bits > 256) {
+ PyErr_SetString(PyExc_ValueError, wrong_palette_size);
+ return NULL;
+ }
+
+ ImagingPaletteDelete(self->image->palette);
+
+ strcpy(self->image->mode, strlen(self->image->mode) == 2 ? "PA" : "P");
+
+ self->image->palette = ImagingPaletteNew("RGB");
+
+ unpack(self->image->palette->palette, palette, palettesize * 8 / bits);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_putpalettealpha(ImagingObject* self, PyObject* args)
+{
+ int index;
+ int alpha = 0;
+ if (!PyArg_ParseTuple(args, "i|i", &index, &alpha))
+ return NULL;
+
+ if (!self->image->palette) {
+ PyErr_SetString(PyExc_ValueError, no_palette);
+ return NULL;
+ }
+
+ if (index < 0 || index >= 256) {
+ PyErr_SetString(PyExc_ValueError, outside_palette);
+ return NULL;
+ }
+
+ strcpy(self->image->palette->mode, "RGBA");
+ self->image->palette->palette[index*4+3] = (UINT8) alpha;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_putpalettealphas(ImagingObject* self, PyObject* args)
+{
+ int i;
+ UINT8 *values;
+ Py_ssize_t length;
+ if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH, &values, &length))
+ return NULL;
+
+ if (!self->image->palette) {
+ PyErr_SetString(PyExc_ValueError, no_palette);
+ return NULL;
+ }
+
+ if (length > 256) {
+ PyErr_SetString(PyExc_ValueError, outside_palette);
+ return NULL;
+ }
+
+ strcpy(self->image->palette->mode, "RGBA");
+ for (i=0; i<length; i++) {
+ self->image->palette->palette[i*4+3] = (UINT8) values[i];
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_putpixel(ImagingObject* self, PyObject* args)
+{
+ Imaging im;
+ char ink[4];
+
+ int x, y;
+ PyObject* color;
+ if (!PyArg_ParseTuple(args, "(ii)O", &x, &y, &color))
+ return NULL;
+
+ im = self->image;
+
+ if (x < 0) {
+ x = im->xsize + x;
+ }
+ if (y < 0) {
+ y = im->ysize + y;
+ }
+
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
+ PyErr_SetString(PyExc_IndexError, outside_image);
+ return NULL;
+ }
+
+ if (!getink(color, im, ink))
+ return NULL;
+
+ if (self->access)
+ self->access->put_pixel(im, x, y, ink);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#ifdef WITH_RANKFILTER
+static PyObject*
+_rankfilter(ImagingObject* self, PyObject* args)
+{
+ int size, rank;
+ if (!PyArg_ParseTuple(args, "ii", &size, &rank))
+ return NULL;
+
+ return PyImagingNew(ImagingRankFilter(self->image, size, rank));
+}
+#endif
+
+static PyObject*
+_resize(ImagingObject* self, PyObject* args)
+{
+ Imaging imIn;
+ Imaging imOut;
+
+ int xsize, ysize;
+ int filter = IMAGING_TRANSFORM_NEAREST;
+ float box[4] = {0, 0, 0, 0};
+
+ imIn = self->image;
+ box[2] = imIn->xsize;
+ box[3] = imIn->ysize;
+
+ if (!PyArg_ParseTuple(args, "(ii)|i(ffff)", &xsize, &ysize, &filter,
+ &box[0], &box[1], &box[2], &box[3]))
+ return NULL;
+
+ if (xsize < 1 || ysize < 1) {
+ return ImagingError_ValueError("height and width must be > 0");
+ }
+
+ if (box[0] < 0 || box[1] < 0) {
+ return ImagingError_ValueError("box offset can't be negative");
+ }
+
+ if (box[2] > imIn->xsize || box[3] > imIn->ysize) {
+ return ImagingError_ValueError("box can't exceed original image size");
+ }
+
+ if (box[2] - box[0] < 0 || box[3] - box[1] < 0) {
+ return ImagingError_ValueError("box can't be empty");
+ }
+
+ // If box's coordinates are int and box size matches requested size
+ if (box[0] - (int) box[0] == 0 && box[2] - box[0] == xsize
+ && box[1] - (int) box[1] == 0 && box[3] - box[1] == ysize) {
+ imOut = ImagingCrop(imIn, box[0], box[1], box[2], box[3]);
+ }
+ else if (filter == IMAGING_TRANSFORM_NEAREST) {
+ double a[6];
+
+ memset(a, 0, sizeof a);
+ a[0] = (double) (box[2] - box[0]) / xsize;
+ a[4] = (double) (box[3] - box[1]) / ysize;
+ a[2] = box[0];
+ a[5] = box[1];
+
+ imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
+
+ imOut = ImagingTransform(
+ imOut, imIn, IMAGING_TRANSFORM_AFFINE,
+ 0, 0, xsize, ysize,
+ a, filter, 1);
+ }
+ else {
+ imOut = ImagingResample(imIn, xsize, ysize, filter, box);
+ }
+
+ return PyImagingNew(imOut);
+}
+
+
+#define IS_RGB(mode)\
+ (!strcmp(mode, "RGB") || !strcmp(mode, "RGBA") || !strcmp(mode, "RGBX"))
+
+static PyObject*
+im_setmode(ImagingObject* self, PyObject* args)
+{
+ /* attempt to modify the mode of an image in place */
+
+ Imaging im;
+
+ char* mode;
+ Py_ssize_t modelen;
+ if (!PyArg_ParseTuple(args, "s#:setmode", &mode, &modelen))
+ return NULL;
+
+ im = self->image;
+
+ /* move all logic in here to the libImaging primitive */
+
+ if (!strcmp(im->mode, mode)) {
+ ; /* same mode; always succeeds */
+ } else if (IS_RGB(im->mode) && IS_RGB(mode)) {
+ /* color to color */
+ strcpy(im->mode, mode);
+ im->bands = modelen;
+ if (!strcmp(mode, "RGBA"))
+ (void) ImagingFillBand(im, 3, 255);
+ } else {
+ /* trying doing an in-place conversion */
+ if (!ImagingConvertInPlace(im, mode))
+ return NULL;
+ }
+
+ if (self->access)
+ ImagingAccessDelete(im, self->access);
+ self->access = ImagingAccessNew(im);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+_transform2(ImagingObject* self, PyObject* args)
+{
+ static const char* wrong_number = "wrong number of matrix entries";
+
+ Imaging imOut;
+ Py_ssize_t n;
+ double *a;
+
+ ImagingObject* imagep;
+ int x0, y0, x1, y1;
+ int method;
+ PyObject* data;
+ int filter = IMAGING_TRANSFORM_NEAREST;
+ int fill = 1;
+ if (!PyArg_ParseTuple(args, "(iiii)O!iO|ii",
+ &x0, &y0, &x1, &y1,
+ &Imaging_Type, &imagep,
+ &method, &data,
+ &filter, &fill))
+ return NULL;
+
+ switch (method) {
+ case IMAGING_TRANSFORM_AFFINE:
+ n = 6;
+ break;
+ case IMAGING_TRANSFORM_PERSPECTIVE:
+ n = 8;
+ break;
+ case IMAGING_TRANSFORM_QUAD:
+ n = 8;
+ break;
+ default:
+ n = -1; /* force error */
+ }
+
+ a = getlist(data, &n, wrong_number, TYPE_DOUBLE);
+ if (!a)
+ return NULL;
+
+ imOut = ImagingTransform(
+ self->image, imagep->image, method,
+ x0, y0, x1, y1, a, filter, fill);
+
+ free(a);
+
+ if (!imOut)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_transpose(ImagingObject* self, PyObject* args)
+{
+ Imaging imIn;
+ Imaging imOut;
+
+ int op;
+ if (!PyArg_ParseTuple(args, "i", &op))
+ return NULL;
+
+ imIn = self->image;
+
+ switch (op) {
+ case 0: /* flip left right */
+ case 1: /* flip top bottom */
+ case 3: /* rotate 180 */
+ imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
+ break;
+ case 2: /* rotate 90 */
+ case 4: /* rotate 270 */
+ case 5: /* transpose */
+ case 6: /* transverse */
+ imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
+ break;
+ default:
+ PyErr_SetString(PyExc_ValueError, "No such transpose operation");
+ return NULL;
+ }
+
+ if (imOut)
+ switch (op) {
+ case 0:
+ (void) ImagingFlipLeftRight(imOut, imIn);
+ break;
+ case 1:
+ (void) ImagingFlipTopBottom(imOut, imIn);
+ break;
+ case 2:
+ (void) ImagingRotate90(imOut, imIn);
+ break;
+ case 3:
+ (void) ImagingRotate180(imOut, imIn);
+ break;
+ case 4:
+ (void) ImagingRotate270(imOut, imIn);
+ break;
+ case 5:
+ (void) ImagingTranspose(imOut, imIn);
+ break;
+ case 6:
+ (void) ImagingTransverse(imOut, imIn);
+ break;
+ }
+
+ return PyImagingNew(imOut);
+}
+
+#ifdef WITH_UNSHARPMASK
+static PyObject*
+_unsharp_mask(ImagingObject* self, PyObject* args)
+{
+ Imaging imIn;
+ Imaging imOut;
+
+ float radius;
+ int percent, threshold;
+ if (!PyArg_ParseTuple(args, "fii", &radius, &percent, &threshold))
+ return NULL;
+
+ imIn = self->image;
+ imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
+ if (!imOut)
+ return NULL;
+
+ if (!ImagingUnsharpMask(imOut, imIn, radius, percent, threshold))
+ return NULL;
+
+ return PyImagingNew(imOut);
+}
+#endif
+
+static PyObject*
+_box_blur(ImagingObject* self, PyObject* args)
+{
+ Imaging imIn;
+ Imaging imOut;
+
+ float radius;
+ int n = 1;
+ if (!PyArg_ParseTuple(args, "f|i", &radius, &n))
+ return NULL;
+
+ imIn = self->image;
+ imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
+ if (!imOut)
+ return NULL;
+
+ if (!ImagingBoxBlur(imOut, imIn, radius, n)) {
+ ImagingDelete(imOut);
+ return NULL;
+ }
+
+ return PyImagingNew(imOut);
+}
+
+/* -------------------------------------------------------------------- */
+
+static PyObject*
+_isblock(ImagingObject* self, PyObject* args)
+{
+ return PyBool_FromLong(self->image->block != NULL);
+}
+
+static PyObject*
+_getbbox(ImagingObject* self, PyObject* args)
+{
+ int bbox[4];
+ if (!ImagingGetBBox(self->image, bbox)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return Py_BuildValue("iiii", bbox[0], bbox[1], bbox[2], bbox[3]);
+}
+
+static PyObject*
+_getcolors(ImagingObject* self, PyObject* args)
+{
+ ImagingColorItem* items;
+ int i, colors;
+ PyObject* out;
+
+ int maxcolors = 256;
+ if (!PyArg_ParseTuple(args, "i:getcolors", &maxcolors))
+ return NULL;
+
+ items = ImagingGetColors(self->image, maxcolors, &colors);
+ if (!items)
+ return NULL;
+
+ if (colors > maxcolors) {
+ out = Py_None;
+ Py_INCREF(out);
+ } else {
+ out = PyList_New(colors);
+ for (i = 0; i < colors; i++) {
+ ImagingColorItem* v = &items[i];
+ PyObject* item = Py_BuildValue(
+ "iN", v->count, getpixel(self->image, self->access, v->x, v->y)
+ );
+ PyList_SetItem(out, i, item);
+ }
+ }
+
+ free(items);
+
+ return out;
+}
+
+static PyObject*
+_getextrema(ImagingObject* self, PyObject* args)
+{
+ union {
+ UINT8 u[2];
+ INT32 i[2];
+ FLOAT32 f[2];
+ UINT16 s[2];
+ } extrema;
+ int status;
+
+ status = ImagingGetExtrema(self->image, &extrema);
+ if (status < 0)
+ return NULL;
+
+ if (status)
+ switch (self->image->type) {
+ case IMAGING_TYPE_UINT8:
+ return Py_BuildValue("BB", extrema.u[0], extrema.u[1]);
+ case IMAGING_TYPE_INT32:
+ return Py_BuildValue("ii", extrema.i[0], extrema.i[1]);
+ case IMAGING_TYPE_FLOAT32:
+ return Py_BuildValue("dd", extrema.f[0], extrema.f[1]);
+ case IMAGING_TYPE_SPECIAL:
+ if (strcmp(self->image->mode, "I;16") == 0) {
+ return Py_BuildValue("HH", extrema.s[0], extrema.s[1]);
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_getprojection(ImagingObject* self, PyObject* args)
+{
+ unsigned char* xprofile;
+ unsigned char* yprofile;
+ PyObject* result;
+
+ /* malloc check ok */
+ xprofile = malloc(self->image->xsize);
+ yprofile = malloc(self->image->ysize);
+
+ if (xprofile == NULL || yprofile == NULL) {
+ free(xprofile);
+ free(yprofile);
+ return PyErr_NoMemory();
+ }
+
+ ImagingGetProjection(self->image, (unsigned char *)xprofile, (unsigned char *)yprofile);
+
+ result = Py_BuildValue(PY_ARG_BYTES_LENGTH PY_ARG_BYTES_LENGTH,
+ xprofile, (Py_ssize_t)self->image->xsize,
+ yprofile, (Py_ssize_t)self->image->ysize);
+
+ free(xprofile);
+ free(yprofile);
+
+ return result;
+}
+
+/* -------------------------------------------------------------------- */
+
+static PyObject*
+_getband(ImagingObject* self, PyObject* args)
+{
+ int band;
+
+ if (!PyArg_ParseTuple(args, "i", &band))
+ return NULL;
+
+ return PyImagingNew(ImagingGetBand(self->image, band));
+}
+
+static PyObject*
+_fillband(ImagingObject* self, PyObject* args)
+{
+ int band;
+ int color;
+
+ if (!PyArg_ParseTuple(args, "ii", &band, &color))
+ return NULL;
+
+ if (!ImagingFillBand(self->image, band, color))
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_putband(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+ int band;
+ if (!PyArg_ParseTuple(args, "O!i",
+ &Imaging_Type, &imagep,
+ &band))
+ return NULL;
+
+ if (!ImagingPutBand(self->image, imagep->image, band))
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_merge(PyObject* self, PyObject* args)
+{
+ char* mode;
+ ImagingObject *band0 = NULL;
+ ImagingObject *band1 = NULL;
+ ImagingObject *band2 = NULL;
+ ImagingObject *band3 = NULL;
+ Imaging bands[4] = {NULL, NULL, NULL, NULL};
+
+ if (!PyArg_ParseTuple(args, "sO!|O!O!O!", &mode,
+ &Imaging_Type, &band0, &Imaging_Type, &band1,
+ &Imaging_Type, &band2, &Imaging_Type, &band3))
+ return NULL;
+
+ if (band0) bands[0] = band0->image;
+ if (band1) bands[1] = band1->image;
+ if (band2) bands[2] = band2->image;
+ if (band3) bands[3] = band3->image;
+
+ return PyImagingNew(ImagingMerge(mode, bands));
+}
+
+static PyObject*
+_split(ImagingObject* self, PyObject* args)
+{
+ int fails = 0;
+ Py_ssize_t i;
+ PyObject* list;
+ PyObject* imaging_object;
+ Imaging bands[4] = {NULL, NULL, NULL, NULL};
+
+ if ( ! ImagingSplit(self->image, bands))
+ return NULL;
+
+ list = PyTuple_New(self->image->bands);
+ for (i = 0; i < self->image->bands; i++) {
+ imaging_object = PyImagingNew(bands[i]);
+ if ( ! imaging_object)
+ fails += 1;
+ PyTuple_SET_ITEM(list, i, imaging_object);
+ }
+ if (fails) {
+ Py_DECREF(list);
+ list = NULL;
+ }
+ return list;
+}
+
+/* -------------------------------------------------------------------- */
+
+#ifdef WITH_IMAGECHOPS
+
+static PyObject*
+_chop_invert(ImagingObject* self, PyObject* args)
+{
+ return PyImagingNew(ImagingNegative(self->image));
+}
+
+static PyObject*
+_chop_lighter(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopLighter(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_darker(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopDarker(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_difference(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopDifference(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_multiply(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopMultiply(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_screen(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopScreen(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_add(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+ float scale;
+ int offset;
+
+ scale = 1.0;
+ offset = 0;
+
+ if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep,
+ &scale, &offset))
+ return NULL;
+
+ return PyImagingNew(ImagingChopAdd(self->image, imagep->image,
+ scale, offset));
+}
+
+static PyObject*
+_chop_subtract(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+ float scale;
+ int offset;
+
+ scale = 1.0;
+ offset = 0;
+
+ if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep,
+ &scale, &offset))
+ return NULL;
+
+ return PyImagingNew(ImagingChopSubtract(self->image, imagep->image,
+ scale, offset));
+}
+
+static PyObject*
+_chop_and(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopAnd(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_or(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopOr(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_xor(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopXor(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_add_modulo(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopAddModulo(self->image, imagep->image));
+}
+
+static PyObject*
+_chop_subtract_modulo(ImagingObject* self, PyObject* args)
+{
+ ImagingObject* imagep;
+
+ if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep))
+ return NULL;
+
+ return PyImagingNew(ImagingChopSubtractModulo(self->image, imagep->image));
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------- */
+
+#ifdef WITH_IMAGEDRAW
+
+static PyObject*
+_font_new(PyObject* self_, PyObject* args)
+{
+ ImagingFontObject *self;
+ int i, y0, y1;
+ static const char* wrong_length = "descriptor table has wrong size";
+
+ ImagingObject* imagep;
+ unsigned char* glyphdata;
+ Py_ssize_t glyphdata_length;
+ if (!PyArg_ParseTuple(args, "O!"PY_ARG_BYTES_LENGTH,
+ &Imaging_Type, &imagep,
+ &glyphdata, &glyphdata_length))
+ return NULL;
+
+ if (glyphdata_length != 256 * 20) {
+ PyErr_SetString(PyExc_ValueError, wrong_length);
+ return NULL;
+ }
+
+ self = PyObject_New(ImagingFontObject, &ImagingFont_Type);
+ if (self == NULL)
+ return NULL;
+
+ /* glyph bitmap */
+ self->bitmap = imagep->image;
+
+ y0 = y1 = 0;
+
+ /* glyph glyphs */
+ for (i = 0; i < 256; i++) {
+ self->glyphs[i].dx = S16(B16(glyphdata, 0));
+ self->glyphs[i].dy = S16(B16(glyphdata, 2));
+ self->glyphs[i].dx0 = S16(B16(glyphdata, 4));
+ self->glyphs[i].dy0 = S16(B16(glyphdata, 6));
+ self->glyphs[i].dx1 = S16(B16(glyphdata, 8));
+ self->glyphs[i].dy1 = S16(B16(glyphdata, 10));
+ self->glyphs[i].sx0 = S16(B16(glyphdata, 12));
+ self->glyphs[i].sy0 = S16(B16(glyphdata, 14));
+ self->glyphs[i].sx1 = S16(B16(glyphdata, 16));
+ self->glyphs[i].sy1 = S16(B16(glyphdata, 18));
+ if (self->glyphs[i].dy0 < y0)
+ y0 = self->glyphs[i].dy0;
+ if (self->glyphs[i].dy1 > y1)
+ y1 = self->glyphs[i].dy1;
+ glyphdata += 20;
+ }
+
+ self->baseline = -y0;
+ self->ysize = y1 - y0;
+
+ /* keep a reference to the bitmap object */
+ Py_INCREF(imagep);
+ self->ref = imagep;
+
+ return (PyObject*) self;
+}
+
+static void
+_font_dealloc(ImagingFontObject* self)
+{
+ Py_XDECREF(self->ref);
+ PyObject_Del(self);
+}
+
+static inline int
+textwidth(ImagingFontObject* self, const unsigned char* text)
+{
+ int xsize;
+
+ for (xsize = 0; *text; text++)
+ xsize += self->glyphs[*text].dx;
+
+ return xsize;
+}
+
+void _font_text_asBytes(PyObject* encoded_string, unsigned char** text){
+ /* Allocates *text, returns a 'new reference'. Caller is required to free */
+
+ PyObject* bytes = NULL;
+ Py_ssize_t len = 0;
+ char *buffer;
+
+ *text = NULL;
+
+ if (PyUnicode_CheckExact(encoded_string)){
+ bytes = PyUnicode_AsLatin1String(encoded_string);
+ if (!bytes) {
+ return;
+ }
+ PyBytes_AsStringAndSize(bytes, &buffer, &len);
+ } else if (PyBytes_Check(encoded_string)) {
+ PyBytes_AsStringAndSize(encoded_string, &buffer, &len);
+ }
+
+ *text = calloc(len+1,1);
+ if (*text) {
+ memcpy(*text, buffer, len);
+ } else {
+ ImagingError_MemoryError();
+ }
+ if (bytes) {
+ Py_DECREF(bytes);
+ }
+
+ return;
+}
+
+
+static PyObject*
+_font_getmask(ImagingFontObject* self, PyObject* args)
+{
+ Imaging im;
+ Imaging bitmap;
+ int x, b;
+ int i=0;
+ int status;
+ Glyph* glyph;
+
+ PyObject* encoded_string;
+
+ unsigned char* text;
+ char* mode = "";
+
+ if (!PyArg_ParseTuple(args, "O|s:getmask", &encoded_string, &mode)){
+ return NULL;
+ }
+
+ _font_text_asBytes(encoded_string, &text);
+ if (!text) {
+ return NULL;
+ }
+
+ im = ImagingNew(self->bitmap->mode, textwidth(self, text), self->ysize);
+ if (!im) {
+ free(text);
+ ImagingError_MemoryError();
+ return NULL;
+ }
+
+ b = 0;
+ (void) ImagingFill(im, &b);
+
+ b = self->baseline;
+ for (x = 0; text[i]; i++) {
+ glyph = &self->glyphs[text[i]];
+ bitmap = ImagingCrop(
+ self->bitmap,
+ glyph->sx0, glyph->sy0, glyph->sx1, glyph->sy1
+ );
+ if (!bitmap)
+ goto failed;
+ status = ImagingPaste(
+ im, bitmap, NULL,
+ glyph->dx0+x, glyph->dy0+b, glyph->dx1+x, glyph->dy1+b
+ );
+ ImagingDelete(bitmap);
+ if (status < 0)
+ goto failed;
+ x = x + glyph->dx;
+ b = b + glyph->dy;
+ }
+ free(text);
+ return PyImagingNew(im);
+
+ failed:
+ free(text);
+ ImagingDelete(im);
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+_font_getsize(ImagingFontObject* self, PyObject* args)
+{
+ unsigned char* text;
+ PyObject* encoded_string;
+ PyObject* val;
+
+ if (!PyArg_ParseTuple(args, "O:getsize", &encoded_string))
+ return NULL;
+
+ _font_text_asBytes(encoded_string, &text);
+ if (!text) {
+ return NULL;
+ }
+
+ val = Py_BuildValue("ii", textwidth(self, text), self->ysize);
+ free(text);
+ return val;
+}
+
+static struct PyMethodDef _font_methods[] = {
+ {"getmask", (PyCFunction)_font_getmask, 1},
+ {"getsize", (PyCFunction)_font_getsize, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+/* -------------------------------------------------------------------- */
+
+static PyObject*
+_draw_new(PyObject* self_, PyObject* args)
+{
+ ImagingDrawObject *self;
+
+ ImagingObject* imagep;
+ int blend = 0;
+ if (!PyArg_ParseTuple(args, "O!|i", &Imaging_Type, &imagep, &blend))
+ return NULL;
+
+ self = PyObject_New(ImagingDrawObject, &ImagingDraw_Type);
+ if (self == NULL)
+ return NULL;
+
+ /* keep a reference to the image object */
+ Py_INCREF(imagep);
+ self->image = imagep;
+
+ self->ink[0] = self->ink[1] = self->ink[2] = self->ink[3] = 0;
+
+ self->blend = blend;
+
+ return (PyObject*) self;
+}
+
+static void
+_draw_dealloc(ImagingDrawObject* self)
+{
+ Py_XDECREF(self->image);
+ PyObject_Del(self);
+}
+
+extern Py_ssize_t PyPath_Flatten(PyObject* data, double **xy);
+
+static PyObject*
+_draw_ink(ImagingDrawObject* self, PyObject* args)
+{
+ INT32 ink = 0;
+ PyObject* color;
+ if (!PyArg_ParseTuple(args, "O", &color))
+ return NULL;
+
+ if (!getink(color, self->image->image, (char*) &ink))
+ return NULL;
+
+ return PyInt_FromLong((int) ink);
+}
+
+static PyObject*
+_draw_arc(ImagingDrawObject* self, PyObject* args)
+{
+ double* xy;
+ Py_ssize_t n;
+
+ PyObject* data;
+ int ink;
+ int width = 0;
+ float start, end;
+ int op = 0;
+ if (!PyArg_ParseTuple(args, "Offi|ii", &data, &start, &end, &ink, &width))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+ if (n != 2) {
+ PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
+ return NULL;
+ }
+
+ n = ImagingDrawArc(self->image->image,
+ (int) xy[0], (int) xy[1],
+ (int) xy[2], (int) xy[3],
+ start, end, &ink, width, op
+ );
+
+ free(xy);
+
+ if (n < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_draw_bitmap(ImagingDrawObject* self, PyObject* args)
+{
+ double *xy;
+ Py_ssize_t n;
+
+ PyObject *data;
+ ImagingObject* bitmap;
+ int ink;
+ if (!PyArg_ParseTuple(args, "OO!i", &data, &Imaging_Type, &bitmap, &ink))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+ if (n != 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "coordinate list must contain exactly 1 coordinate"
+ );
+ free(xy);
+ return NULL;
+ }
+
+ n = ImagingDrawBitmap(
+ self->image->image, (int) xy[0], (int) xy[1], bitmap->image,
+ &ink, self->blend
+ );
+
+ free(xy);
+
+ if (n < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_draw_chord(ImagingDrawObject* self, PyObject* args)
+{
+ double* xy;
+ Py_ssize_t n;
+
+ PyObject* data;
+ int ink, fill;
+ int width = 0;
+ float start, end;
+ if (!PyArg_ParseTuple(args, "Offii|i",
+ &data, &start, &end, &ink, &fill, &width))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+ if (n != 2) {
+ PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
+ return NULL;
+ }
+
+ n = ImagingDrawChord(self->image->image,
+ (int) xy[0], (int) xy[1],
+ (int) xy[2], (int) xy[3],
+ start, end, &ink, fill, width, self->blend
+ );
+
+ free(xy);
+
+ if (n < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_draw_ellipse(ImagingDrawObject* self, PyObject* args)
+{
+ double* xy;
+ Py_ssize_t n;
+
+ PyObject* data;
+ int ink;
+ int fill = 0;
+ int width = 0;
+ if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+ if (n != 2) {
+ PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
+ return NULL;
+ }
+
+ n = ImagingDrawEllipse(self->image->image,
+ (int) xy[0], (int) xy[1],
+ (int) xy[2], (int) xy[3],
+ &ink, fill, width, self->blend
+ );
+
+ free(xy);
+
+ if (n < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_draw_lines(ImagingDrawObject* self, PyObject* args)
+{
+ double *xy;
+ Py_ssize_t i, n;
+
+ PyObject *data;
+ int ink;
+ int width = 0;
+ if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &width))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+
+ if (width <= 1) {
+ double *p = NULL;
+ for (i = 0; i < n-1; i++) {
+ p = &xy[i+i];
+ if (ImagingDrawLine(
+ self->image->image,
+ (int) p[0], (int) p[1], (int) p[2], (int) p[3],
+ &ink, self->blend) < 0) {
+ free(xy);
+ return NULL;
+ }
+ }
+ if (p) /* draw last point */
+ ImagingDrawPoint(
+ self->image->image,
+ (int) p[2], (int) p[3],
+ &ink, self->blend
+ );
+ } else {
+ for (i = 0; i < n-1; i++) {
+ double *p = &xy[i+i];
+ if (ImagingDrawWideLine(
+ self->image->image,
+ (int) p[0], (int) p[1], (int) p[2], (int) p[3],
+ &ink, width, self->blend) < 0) {
+ free(xy);
+ return NULL;
+ }
+ }
+ }
+
+ free(xy);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_draw_points(ImagingDrawObject* self, PyObject* args)
+{
+ double *xy;
+ Py_ssize_t i, n;
+
+ PyObject *data;
+ int ink;
+ if (!PyArg_ParseTuple(args, "Oi", &data, &ink))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+
+ for (i = 0; i < n; i++) {
+ double *p = &xy[i+i];
+ if (ImagingDrawPoint(self->image->image, (int) p[0], (int) p[1],
+ &ink, self->blend) < 0) {
+ free(xy);
+ return NULL;
+ }
+ }
+
+ free(xy);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#ifdef WITH_ARROW
+
+/* from outline.c */
+extern ImagingOutline PyOutline_AsOutline(PyObject* outline);
+
+static PyObject*
+_draw_outline(ImagingDrawObject* self, PyObject* args)
+{
+ ImagingOutline outline;
+
+ PyObject* outline_;
+ int ink;
+ int fill = 0;
+ if (!PyArg_ParseTuple(args, "Oi|i", &outline_, &ink, &fill))
+ return NULL;
+
+ outline = PyOutline_AsOutline(outline_);
+ if (!outline) {
+ PyErr_SetString(PyExc_TypeError, "expected outline object");
+ return NULL;
+ }
+
+ if (ImagingDrawOutline(self->image->image, outline,
+ &ink, fill, self->blend) < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#endif
+
+static PyObject*
+_draw_pieslice(ImagingDrawObject* self, PyObject* args)
+{
+ double* xy;
+ Py_ssize_t n;
+
+ PyObject* data;
+ int ink, fill;
+ int width = 0;
+ float start, end;
+ if (!PyArg_ParseTuple(args, "Offii|i", &data, &start, &end, &ink, &fill, &width))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+ if (n != 2) {
+ PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
+ return NULL;
+ }
+
+ n = ImagingDrawPieslice(self->image->image,
+ (int) xy[0], (int) xy[1],
+ (int) xy[2], (int) xy[3],
+ start, end, &ink, fill, width, self->blend
+ );
+
+ free(xy);
+
+ if (n < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_draw_polygon(ImagingDrawObject* self, PyObject* args)
+{
+ double *xy;
+ int *ixy;
+ Py_ssize_t n, i;
+
+ PyObject* data;
+ int ink;
+ int fill = 0;
+ if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &fill))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+ if (n < 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "coordinate list must contain at least 2 coordinates"
+ );
+ free(xy);
+ return NULL;
+ }
+
+ /* Copy list of vertices to array */
+ ixy = (int*) calloc(n, 2 * sizeof(int));
+
+ for (i = 0; i < n; i++) {
+ ixy[i+i] = (int) xy[i+i];
+ ixy[i+i+1] = (int) xy[i+i+1];
+ }
+
+ free(xy);
+
+ if (ImagingDrawPolygon(self->image->image, n, ixy,
+ &ink, fill, self->blend) < 0) {
+ free(ixy);
+ return NULL;
+ }
+
+ free(ixy);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_draw_rectangle(ImagingDrawObject* self, PyObject* args)
+{
+ double* xy;
+ Py_ssize_t n;
+
+ PyObject* data;
+ int ink;
+ int fill = 0;
+ int width = 0;
+ if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width))
+ return NULL;
+
+ n = PyPath_Flatten(data, &xy);
+ if (n < 0)
+ return NULL;
+ if (n != 2) {
+ PyErr_SetString(PyExc_TypeError, must_be_two_coordinates);
+ free(xy);
+ return NULL;
+ }
+
+ n = ImagingDrawRectangle(self->image->image,
+ (int) xy[0], (int) xy[1],
+ (int) xy[2], (int) xy[3],
+ &ink, fill, width, self->blend
+ );
+
+ free(xy);
+
+ if (n < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct PyMethodDef _draw_methods[] = {
+#ifdef WITH_IMAGEDRAW
+ /* Graphics (ImageDraw) */
+ {"draw_lines", (PyCFunction)_draw_lines, 1},
+#ifdef WITH_ARROW
+ {"draw_outline", (PyCFunction)_draw_outline, 1},
+#endif
+ {"draw_polygon", (PyCFunction)_draw_polygon, 1},
+ {"draw_rectangle", (PyCFunction)_draw_rectangle, 1},
+ {"draw_points", (PyCFunction)_draw_points, 1},
+ {"draw_arc", (PyCFunction)_draw_arc, 1},
+ {"draw_bitmap", (PyCFunction)_draw_bitmap, 1},
+ {"draw_chord", (PyCFunction)_draw_chord, 1},
+ {"draw_ellipse", (PyCFunction)_draw_ellipse, 1},
+ {"draw_pieslice", (PyCFunction)_draw_pieslice, 1},
+ {"draw_ink", (PyCFunction)_draw_ink, 1},
+#endif
+ {NULL, NULL} /* sentinel */
+};
+
+#endif
+
+
+static PyObject*
+pixel_access_new(ImagingObject* imagep, PyObject* args)
+{
+ PixelAccessObject *self;
+
+ int readonly = 0;
+ if (!PyArg_ParseTuple(args, "|i", &readonly))
+ return NULL;
+
+ self = PyObject_New(PixelAccessObject, &PixelAccess_Type);
+ if (self == NULL)
+ return NULL;
+
+ /* keep a reference to the image object */
+ Py_INCREF(imagep);
+ self->image = imagep;
+
+ self->readonly = readonly;
+
+ return (PyObject*) self;
+}
+
+static void
+pixel_access_dealloc(PixelAccessObject* self)
+{
+ Py_XDECREF(self->image);
+ PyObject_Del(self);
+}
+
+static PyObject *
+pixel_access_getitem(PixelAccessObject *self, PyObject *xy)
+{
+ int x, y;
+ if (_getxy(xy, &x, &y))
+ return NULL;
+
+ return getpixel(self->image->image, self->image->access, x, y);
+}
+
+static int
+pixel_access_setitem(PixelAccessObject *self, PyObject *xy, PyObject *color)
+{
+ Imaging im = self->image->image;
+ char ink[4];
+ int x, y;
+
+ if (self->readonly) {
+ (void) ImagingError_ValueError(readonly);
+ return -1;
+ }
+
+ if (_getxy(xy, &x, &y))
+ return -1;
+
+ if (x < 0) {
+ x = im->xsize + x;
+ }
+ if (y < 0) {
+ y = im->ysize + y;
+ }
+
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
+ PyErr_SetString(PyExc_IndexError, outside_image);
+ return -1;
+ }
+
+ if (!color) /* FIXME: raise exception? */
+ return 0;
+
+ if (!getink(color, im, ink))
+ return -1;
+
+ self->image->access->put_pixel(im, x, y, ink);
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+/* EFFECTS (experimental) */
+/* -------------------------------------------------------------------- */
+
+#ifdef WITH_EFFECTS
+
+static PyObject*
+_effect_mandelbrot(ImagingObject* self, PyObject* args)
+{
+ int xsize = 512;
+ int ysize = 512;
+ double extent[4];
+ int quality = 100;
+
+ extent[0] = -3; extent[1] = -2.5;
+ extent[2] = 2; extent[3] = 2.5;
+
+ if (!PyArg_ParseTuple(args, "|(ii)(dddd)i", &xsize, &ysize,
+ &extent[0], &extent[1], &extent[2], &extent[3],
+ &quality))
+ return NULL;
+
+ return PyImagingNew(ImagingEffectMandelbrot(xsize, ysize, extent, quality));
+}
+
+static PyObject*
+_effect_noise(ImagingObject* self, PyObject* args)
+{
+ int xsize, ysize;
+ float sigma = 128;
+ if (!PyArg_ParseTuple(args, "(ii)|f", &xsize, &ysize, &sigma))
+ return NULL;
+
+ return PyImagingNew(ImagingEffectNoise(xsize, ysize, sigma));
+}
+
+static PyObject*
+_effect_spread(ImagingObject* self, PyObject* args)
+{
+ int dist;
+
+ if (!PyArg_ParseTuple(args, "i", &dist))
+ return NULL;
+
+ return PyImagingNew(ImagingEffectSpread(self->image, dist));
+}
+
+#endif
+
+/* -------------------------------------------------------------------- */
+/* UTILITIES */
+/* -------------------------------------------------------------------- */
+
+
+static PyObject*
+_getcodecstatus(PyObject* self, PyObject* args)
+{
+ int status;
+ char* msg;
+
+ if (!PyArg_ParseTuple(args, "i", &status))
+ return NULL;
+
+ switch (status) {
+ case IMAGING_CODEC_OVERRUN:
+ msg = "buffer overrun"; break;
+ case IMAGING_CODEC_BROKEN:
+ msg = "broken data stream"; break;
+ case IMAGING_CODEC_UNKNOWN:
+ msg = "unrecognized data stream contents"; break;
+ case IMAGING_CODEC_CONFIG:
+ msg = "codec configuration error"; break;
+ case IMAGING_CODEC_MEMORY:
+ msg = "out of memory"; break;
+ default:
+ Py_RETURN_NONE;
+ }
+
+ return PyUnicode_FromString(msg);
+}
+
+/* -------------------------------------------------------------------- */
+/* DEBUGGING HELPERS */
+/* -------------------------------------------------------------------- */
+
+
+static PyObject*
+_save_ppm(ImagingObject* self, PyObject* args)
+{
+ char* filename;
+
+ if (!PyArg_ParseTuple(args, "s", &filename))
+ return NULL;
+
+ if (!ImagingSavePPM(self->image, filename))
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/* methods */
+
+static struct PyMethodDef methods[] = {
+
+ /* Put commonly used methods first */
+ {"getpixel", (PyCFunction)_getpixel, 1},
+ {"putpixel", (PyCFunction)_putpixel, 1},
+
+ {"pixel_access", (PyCFunction)pixel_access_new, 1},
+
+ /* Standard processing methods (Image) */
+ {"color_lut_3d", (PyCFunction)_color_lut_3d, 1},
+ {"convert", (PyCFunction)_convert, 1},
+ {"convert2", (PyCFunction)_convert2, 1},
+ {"convert_matrix", (PyCFunction)_convert_matrix, 1},
+ {"convert_transparent", (PyCFunction)_convert_transparent, 1},
+ {"copy", (PyCFunction)_copy, 1},
+ {"crop", (PyCFunction)_crop, 1},
+ {"expand", (PyCFunction)_expand_image, 1},
+ {"filter", (PyCFunction)_filter, 1},
+ {"histogram", (PyCFunction)_histogram, 1},
+ {"entropy", (PyCFunction)_entropy, 1},
+#ifdef WITH_MODEFILTER
+ {"modefilter", (PyCFunction)_modefilter, 1},
+#endif
+ {"offset", (PyCFunction)_offset, 1},
+ {"paste", (PyCFunction)_paste, 1},
+ {"point", (PyCFunction)_point, 1},
+ {"point_transform", (PyCFunction)_point_transform, 1},
+ {"putdata", (PyCFunction)_putdata, 1},
+#ifdef WITH_QUANTIZE
+ {"quantize", (PyCFunction)_quantize, 1},
+#endif
+#ifdef WITH_RANKFILTER
+ {"rankfilter", (PyCFunction)_rankfilter, 1},
+#endif
+ {"resize", (PyCFunction)_resize, 1},
+ {"transpose", (PyCFunction)_transpose, 1},
+ {"transform2", (PyCFunction)_transform2, 1},
+
+ {"isblock", (PyCFunction)_isblock, 1},
+
+ {"getbbox", (PyCFunction)_getbbox, 1},
+ {"getcolors", (PyCFunction)_getcolors, 1},
+ {"getextrema", (PyCFunction)_getextrema, 1},
+ {"getprojection", (PyCFunction)_getprojection, 1},
+
+ {"getband", (PyCFunction)_getband, 1},
+ {"putband", (PyCFunction)_putband, 1},
+ {"split", (PyCFunction)_split, 1},
+ {"fillband", (PyCFunction)_fillband, 1},
+
+ {"setmode", (PyCFunction)im_setmode, 1},
+
+ {"getpalette", (PyCFunction)_getpalette, 1},
+ {"getpalettemode", (PyCFunction)_getpalettemode, 1},
+ {"putpalette", (PyCFunction)_putpalette, 1},
+ {"putpalettealpha", (PyCFunction)_putpalettealpha, 1},
+ {"putpalettealphas", (PyCFunction)_putpalettealphas, 1},
+
+#ifdef WITH_IMAGECHOPS
+ /* Channel operations (ImageChops) */
+ {"chop_invert", (PyCFunction)_chop_invert, 1},
+ {"chop_lighter", (PyCFunction)_chop_lighter, 1},
+ {"chop_darker", (PyCFunction)_chop_darker, 1},
+ {"chop_difference", (PyCFunction)_chop_difference, 1},
+ {"chop_multiply", (PyCFunction)_chop_multiply, 1},
+ {"chop_screen", (PyCFunction)_chop_screen, 1},
+ {"chop_add", (PyCFunction)_chop_add, 1},
+ {"chop_subtract", (PyCFunction)_chop_subtract, 1},
+ {"chop_add_modulo", (PyCFunction)_chop_add_modulo, 1},
+ {"chop_subtract_modulo", (PyCFunction)_chop_subtract_modulo, 1},
+ {"chop_and", (PyCFunction)_chop_and, 1},
+ {"chop_or", (PyCFunction)_chop_or, 1},
+ {"chop_xor", (PyCFunction)_chop_xor, 1},
+#endif
+
+#ifdef WITH_UNSHARPMASK
+ /* Kevin Cazabon's unsharpmask extension */
+ {"gaussian_blur", (PyCFunction)_gaussian_blur, 1},
+ {"unsharp_mask", (PyCFunction)_unsharp_mask, 1},
+#endif
+
+ {"box_blur", (PyCFunction)_box_blur, 1},
+
+#ifdef WITH_EFFECTS
+ /* Special effects */
+ {"effect_spread", (PyCFunction)_effect_spread, 1},
+#endif
+
+ /* Misc. */
+ {"new_block", (PyCFunction)_new_block, 1},
+
+ {"save_ppm", (PyCFunction)_save_ppm, 1},
+
+ {NULL, NULL} /* sentinel */
+};
+
+
+/* attributes */
+
+static PyObject*
+_getattr_mode(ImagingObject* self, void* closure)
+{
+ return PyUnicode_FromString(self->image->mode);
+}
+
+static PyObject*
+_getattr_size(ImagingObject* self, void* closure)
+{
+ return Py_BuildValue("ii", self->image->xsize, self->image->ysize);
+}
+
+static PyObject*
+_getattr_bands(ImagingObject* self, void* closure)
+{
+ return PyInt_FromLong(self->image->bands);
+}
+
+static PyObject*
+_getattr_id(ImagingObject* self, void* closure)
+{
+ return PyInt_FromSsize_t((Py_ssize_t) self->image);
+}
+
+static PyObject*
+_getattr_ptr(ImagingObject* self, void* closure)
+{
+ return PyCapsule_New(self->image, IMAGING_MAGIC, NULL);
+}
+
+static PyObject*
+_getattr_unsafe_ptrs(ImagingObject* self, void* closure)
+{
+ return Py_BuildValue("(sn)(sn)(sn)",
+ "image8", self->image->image8,
+ "image32", self->image->image32,
+ "image", self->image->image
+ );
+};
+
+
+static struct PyGetSetDef getsetters[] = {
+ { "mode", (getter) _getattr_mode },
+ { "size", (getter) _getattr_size },
+ { "bands", (getter) _getattr_bands },
+ { "id", (getter) _getattr_id },
+ { "ptr", (getter) _getattr_ptr },
+ { "unsafe_ptrs", (getter) _getattr_unsafe_ptrs },
+ { NULL }
+};
+
+/* basic sequence semantics */
+
+static Py_ssize_t
+image_length(ImagingObject *self)
+{
+ Imaging im = self->image;
+
+ return (Py_ssize_t) im->xsize * im->ysize;
+}
+
+static PyObject *
+image_item(ImagingObject *self, Py_ssize_t i)
+{
+ int x, y;
+ Imaging im = self->image;
+
+ if (im->xsize > 0) {
+ x = i % im->xsize;
+ y = i / im->xsize;
+ } else
+ x = y = 0; /* leave it to getpixel to raise an exception */
+
+ return getpixel(im, self->access, x, y);
+}
+
+static PySequenceMethods image_as_sequence = {
+ (lenfunc) image_length, /*sq_length*/
+ (binaryfunc) NULL, /*sq_concat*/
+ (ssizeargfunc) NULL, /*sq_repeat*/
+ (ssizeargfunc) image_item, /*sq_item*/
+ (ssizessizeargfunc) NULL, /*sq_slice*/
+ (ssizeobjargproc) NULL, /*sq_ass_item*/
+ (ssizessizeobjargproc) NULL, /*sq_ass_slice*/
+};
+
+
+/* type description */
+
+static PyTypeObject Imaging_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ImagingCore", /*tp_name*/
+ sizeof(ImagingObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ &image_as_sequence, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ methods, /*tp_methods*/
+ 0, /*tp_members*/
+ getsetters, /*tp_getset*/
+};
+
+#ifdef WITH_IMAGEDRAW
+
+static PyTypeObject ImagingFont_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ImagingFont", /*tp_name*/
+ sizeof(ImagingFontObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)_font_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ _font_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+};
+
+static PyTypeObject ImagingDraw_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ImagingDraw", /*tp_name*/
+ sizeof(ImagingDrawObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)_draw_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ _draw_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+};
+
+#endif
+
+static PyMappingMethods pixel_access_as_mapping = {
+ (lenfunc) NULL, /*mp_length*/
+ (binaryfunc) pixel_access_getitem, /*mp_subscript*/
+ (objobjargproc) pixel_access_setitem, /*mp_ass_subscript*/
+};
+
+/* type description */
+
+static PyTypeObject PixelAccess_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "PixelAccess", sizeof(PixelAccessObject), 0,
+ /* methods */
+ (destructor)pixel_access_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ &pixel_access_as_mapping, /*tp_as_mapping */
+ 0 /*tp_hash*/
+};
+
+/* -------------------------------------------------------------------- */
+
+static PyObject*
+_get_stats(PyObject* self, PyObject* args)
+{
+ PyObject* d;
+ ImagingMemoryArena arena = &ImagingDefaultArena;
+
+ if (!PyArg_ParseTuple(args, ":get_stats"))
+ return NULL;
+
+ d = PyDict_New();
+ if ( ! d)
+ return NULL;
+ PyDict_SetItemString(d, "new_count",
+ PyInt_FromLong(arena->stats_new_count));
+ PyDict_SetItemString(d, "allocated_blocks",
+ PyInt_FromLong(arena->stats_allocated_blocks));
+ PyDict_SetItemString(d, "reused_blocks",
+ PyInt_FromLong(arena->stats_reused_blocks));
+ PyDict_SetItemString(d, "reallocated_blocks",
+ PyInt_FromLong(arena->stats_reallocated_blocks));
+ PyDict_SetItemString(d, "freed_blocks",
+ PyInt_FromLong(arena->stats_freed_blocks));
+ PyDict_SetItemString(d, "blocks_cached",
+ PyInt_FromLong(arena->blocks_cached));
+ return d;
+}
+
+static PyObject*
+_reset_stats(PyObject* self, PyObject* args)
+{
+ ImagingMemoryArena arena = &ImagingDefaultArena;
+
+ if (!PyArg_ParseTuple(args, ":reset_stats"))
+ return NULL;
+
+ arena->stats_new_count = 0;
+ arena->stats_allocated_blocks = 0;
+ arena->stats_reused_blocks = 0;
+ arena->stats_reallocated_blocks = 0;
+ arena->stats_freed_blocks = 0;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_get_alignment(PyObject* self, PyObject* args)
+{
+ if (!PyArg_ParseTuple(args, ":get_alignment"))
+ return NULL;
+
+ return PyInt_FromLong(ImagingDefaultArena.alignment);
+}
+
+static PyObject*
+_get_block_size(PyObject* self, PyObject* args)
+{
+ if (!PyArg_ParseTuple(args, ":get_block_size"))
+ return NULL;
+
+ return PyInt_FromLong(ImagingDefaultArena.block_size);
+}
+
+static PyObject*
+_get_blocks_max(PyObject* self, PyObject* args)
+{
+ if (!PyArg_ParseTuple(args, ":get_blocks_max"))
+ return NULL;
+
+ return PyInt_FromLong(ImagingDefaultArena.blocks_max);
+}
+
+static PyObject*
+_set_alignment(PyObject* self, PyObject* args)
+{
+ int alignment;
+ if (!PyArg_ParseTuple(args, "i:set_alignment", &alignment))
+ return NULL;
+
+ if (alignment < 1 || alignment > 128) {
+ PyErr_SetString(PyExc_ValueError, "alignment should be from 1 to 128");
+ return NULL;
+ }
+ /* Is power of two */
+ if (alignment & (alignment - 1)) {
+ PyErr_SetString(PyExc_ValueError, "alignment should be power of two");
+ return NULL;
+ }
+
+ ImagingDefaultArena.alignment = alignment;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_set_block_size(PyObject* self, PyObject* args)
+{
+ int block_size;
+ if (!PyArg_ParseTuple(args, "i:set_block_size", &block_size))
+ return NULL;
+
+ if (block_size <= 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "block_size should be greater than 0");
+ return NULL;
+ }
+
+ if (block_size & 0xfff) {
+ PyErr_SetString(PyExc_ValueError,
+ "block_size should be multiple of 4096");
+ return NULL;
+ }
+
+ ImagingDefaultArena.block_size = block_size;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_set_blocks_max(PyObject* self, PyObject* args)
+{
+ int blocks_max;
+ if (!PyArg_ParseTuple(args, "i:set_blocks_max", &blocks_max))
+ return NULL;
+
+ if (blocks_max < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "blocks_max should be greater than 0");
+ return NULL;
+ }
+ else if ( blocks_max > SIZE_MAX/sizeof(ImagingDefaultArena.blocks_pool[0])) {
+ PyErr_SetString(PyExc_ValueError,
+ "blocks_max is too large");
+ return NULL;
+ }
+
+
+ if ( ! ImagingMemorySetBlocksMax(&ImagingDefaultArena, blocks_max)) {
+ ImagingError_MemoryError();
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_clear_cache(PyObject* self, PyObject* args)
+{
+ int i = 0;
+
+ if (!PyArg_ParseTuple(args, "|i:clear_cache", &i))
+ return NULL;
+
+ ImagingMemoryClearCache(&ImagingDefaultArena, i);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* -------------------------------------------------------------------- */
+
+/* FIXME: this is something of a mess. Should replace this with
+ pluggable codecs, but not before PIL 1.2 */
+
+/* Decoders (in decode.c) */
+extern PyObject* PyImaging_BcnDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_BitDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_FliDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_GifDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_HexDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_JpegDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_PackbitsDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_PcdDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_PcxDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_RawDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_SgiRleDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_SunRleDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_TgaRleDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_XbmDecoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_ZipDecoderNew(PyObject* self, PyObject* args);
+
+/* Encoders (in encode.c) */
+extern PyObject* PyImaging_EpsEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_GifEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_JpegEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_Jpeg2KEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_PcxEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_TgaRleEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_XbmEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_ZipEncoderNew(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args);
+
+/* Display support etc (in display.c) */
+#ifdef _WIN32
+extern PyObject* PyImaging_CreateWindowWin32(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_DisplayWin32(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_DisplayModeWin32(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_GrabScreenWin32(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_GrabClipboardWin32(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_ListWindowsWin32(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_EventLoopWin32(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_DrawWmf(PyObject* self, PyObject* args);
+#endif
+
+/* Experimental path stuff (in path.c) */
+extern PyObject* PyPath_Create(ImagingObject* self, PyObject* args);
+
+/* Experimental outline stuff (in outline.c) */
+extern PyObject* PyOutline_Create(ImagingObject* self, PyObject* args);
+
+extern PyObject* PyImaging_Mapper(PyObject* self, PyObject* args);
+extern PyObject* PyImaging_MapBuffer(PyObject* self, PyObject* args);
+
+static PyMethodDef functions[] = {
+
+ /* Object factories */
+ {"alpha_composite", (PyCFunction)_alpha_composite, 1},
+ {"blend", (PyCFunction)_blend, 1},
+ {"fill", (PyCFunction)_fill, 1},
+ {"new", (PyCFunction)_new, 1},
+ {"merge", (PyCFunction)_merge, 1},
+
+ /* Functions */
+ {"convert", (PyCFunction)_convert2, 1},
+
+ /* Codecs */
+ {"bcn_decoder", (PyCFunction)PyImaging_BcnDecoderNew, 1},
+ {"bit_decoder", (PyCFunction)PyImaging_BitDecoderNew, 1},
+ {"eps_encoder", (PyCFunction)PyImaging_EpsEncoderNew, 1},
+ {"fli_decoder", (PyCFunction)PyImaging_FliDecoderNew, 1},
+ {"gif_decoder", (PyCFunction)PyImaging_GifDecoderNew, 1},
+ {"gif_encoder", (PyCFunction)PyImaging_GifEncoderNew, 1},
+ {"hex_decoder", (PyCFunction)PyImaging_HexDecoderNew, 1},
+ {"hex_encoder", (PyCFunction)PyImaging_EpsEncoderNew, 1}, /* EPS=HEX! */
+#ifdef HAVE_LIBJPEG
+ {"jpeg_decoder", (PyCFunction)PyImaging_JpegDecoderNew, 1},
+ {"jpeg_encoder", (PyCFunction)PyImaging_JpegEncoderNew, 1},
+#endif
+#ifdef HAVE_OPENJPEG
+ {"jpeg2k_decoder", (PyCFunction)PyImaging_Jpeg2KDecoderNew, 1},
+ {"jpeg2k_encoder", (PyCFunction)PyImaging_Jpeg2KEncoderNew, 1},
+#endif
+#ifdef HAVE_LIBTIFF
+ {"libtiff_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
+ {"libtiff_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
+#endif
+ {"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, 1},
+ {"pcd_decoder", (PyCFunction)PyImaging_PcdDecoderNew, 1},
+ {"pcx_decoder", (PyCFunction)PyImaging_PcxDecoderNew, 1},
+ {"pcx_encoder", (PyCFunction)PyImaging_PcxEncoderNew, 1},
+ {"raw_decoder", (PyCFunction)PyImaging_RawDecoderNew, 1},
+ {"raw_encoder", (PyCFunction)PyImaging_RawEncoderNew, 1},
+ {"sgi_rle_decoder", (PyCFunction)PyImaging_SgiRleDecoderNew, 1},
+ {"sun_rle_decoder", (PyCFunction)PyImaging_SunRleDecoderNew, 1},
+ {"tga_rle_decoder", (PyCFunction)PyImaging_TgaRleDecoderNew, 1},
+ {"tga_rle_encoder", (PyCFunction)PyImaging_TgaRleEncoderNew, 1},
+ {"xbm_decoder", (PyCFunction)PyImaging_XbmDecoderNew, 1},
+ {"xbm_encoder", (PyCFunction)PyImaging_XbmEncoderNew, 1},
+#ifdef HAVE_LIBZ
+ {"zip_decoder", (PyCFunction)PyImaging_ZipDecoderNew, 1},
+ {"zip_encoder", (PyCFunction)PyImaging_ZipEncoderNew, 1},
+#endif
+
+ /* Memory mapping */
+#ifdef WITH_MAPPING
+#ifdef _WIN32
+ {"map", (PyCFunction)PyImaging_Mapper, 1},
+#endif
+ {"map_buffer", (PyCFunction)PyImaging_MapBuffer, 1},
+#endif
+
+ /* Display support */
+#ifdef _WIN32
+ {"display", (PyCFunction)PyImaging_DisplayWin32, 1},
+ {"display_mode", (PyCFunction)PyImaging_DisplayModeWin32, 1},
+ {"grabscreen", (PyCFunction)PyImaging_GrabScreenWin32, 1},
+ {"grabclipboard", (PyCFunction)PyImaging_GrabClipboardWin32, 1},
+ {"createwindow", (PyCFunction)PyImaging_CreateWindowWin32, 1},
+ {"eventloop", (PyCFunction)PyImaging_EventLoopWin32, 1},
+ {"listwindows", (PyCFunction)PyImaging_ListWindowsWin32, 1},
+ {"drawwmf", (PyCFunction)PyImaging_DrawWmf, 1},
+#endif
+
+ /* Utilities */
+ {"getcodecstatus", (PyCFunction)_getcodecstatus, 1},
+
+ /* Special effects (experimental) */
+#ifdef WITH_EFFECTS
+ {"effect_mandelbrot", (PyCFunction)_effect_mandelbrot, 1},
+ {"effect_noise", (PyCFunction)_effect_noise, 1},
+ {"linear_gradient", (PyCFunction)_linear_gradient, 1},
+ {"radial_gradient", (PyCFunction)_radial_gradient, 1},
+ {"wedge", (PyCFunction)_linear_gradient, 1}, /* Compatibility */
+#endif
+
+ /* Drawing support stuff */
+#ifdef WITH_IMAGEDRAW
+ {"font", (PyCFunction)_font_new, 1},
+ {"draw", (PyCFunction)_draw_new, 1},
+#endif
+
+ /* Experimental path stuff */
+#ifdef WITH_IMAGEPATH
+ {"path", (PyCFunction)PyPath_Create, 1},
+#endif
+
+ /* Experimental arrow graphics stuff */
+#ifdef WITH_ARROW
+ {"outline", (PyCFunction)PyOutline_Create, 1},
+#endif
+
+ /* Resource management */
+ {"get_stats", (PyCFunction)_get_stats, 1},
+ {"reset_stats", (PyCFunction)_reset_stats, 1},
+ {"get_alignment", (PyCFunction)_get_alignment, 1},
+ {"get_block_size", (PyCFunction)_get_block_size, 1},
+ {"get_blocks_max", (PyCFunction)_get_blocks_max, 1},
+ {"set_alignment", (PyCFunction)_set_alignment, 1},
+ {"set_block_size", (PyCFunction)_set_block_size, 1},
+ {"set_blocks_max", (PyCFunction)_set_blocks_max, 1},
+ {"clear_cache", (PyCFunction)_clear_cache, 1},
+
+ {NULL, NULL} /* sentinel */
+};
+
+static int
+setup_module(PyObject* m) {
+ PyObject* d = PyModule_GetDict(m);
+ const char* version = (char*)PILLOW_VERSION;
+
+ /* Ready object types */
+ if (PyType_Ready(&Imaging_Type) < 0)
+ return -1;
+
+#ifdef WITH_IMAGEDRAW
+ if (PyType_Ready(&ImagingFont_Type) < 0)
+ return -1;
+
+ if (PyType_Ready(&ImagingDraw_Type) < 0)
+ return -1;
+#endif
+ if (PyType_Ready(&PixelAccess_Type) < 0)
+ return -1;
+
+ ImagingAccessInit();
+
+#ifdef HAVE_LIBJPEG
+ {
+ extern const char* ImagingJpegVersion(void);
+ PyDict_SetItemString(d, "jpeglib_version", PyUnicode_FromString(ImagingJpegVersion()));
+ }
+#endif
+
+#ifdef HAVE_OPENJPEG
+ {
+ extern const char *ImagingJpeg2KVersion(void);
+ PyDict_SetItemString(d, "jp2klib_version", PyUnicode_FromString(ImagingJpeg2KVersion()));
+ }
+#endif
+
+#ifdef LIBJPEG_TURBO_VERSION
+ PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_True);
+#else
+ PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_False);
+#endif
+
+#ifdef HAVE_LIBZ
+ /* zip encoding strategies */
+ PyModule_AddIntConstant(m, "DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY);
+ PyModule_AddIntConstant(m, "FILTERED", Z_FILTERED);
+ PyModule_AddIntConstant(m, "HUFFMAN_ONLY", Z_HUFFMAN_ONLY);
+ PyModule_AddIntConstant(m, "RLE", Z_RLE);
+ PyModule_AddIntConstant(m, "FIXED", Z_FIXED);
+ {
+ extern const char* ImagingZipVersion(void);
+ PyDict_SetItemString(d, "zlib_version", PyUnicode_FromString(ImagingZipVersion()));
+ }
+#endif
+
+#ifdef HAVE_LIBTIFF
+ {
+ extern const char * ImagingTiffVersion(void);
+ PyDict_SetItemString(d, "libtiff_version", PyUnicode_FromString(ImagingTiffVersion()));
+ }
+#endif
+
+ PyDict_SetItemString(d, "PILLOW_VERSION", PyUnicode_FromString(version));
+
+ return 0;
+}
+
+#if PY_VERSION_HEX >= 0x03000000
+PyMODINIT_FUNC
+PyInit__imaging(void) {
+ PyObject* m;
+
+ static PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ "_imaging", /* m_name */
+ NULL, /* m_doc */
+ -1, /* m_size */
+ functions, /* m_methods */
+ };
+
+ m = PyModule_Create(&module_def);
+
+ if (setup_module(m) < 0)
+ return NULL;
+
+ return m;
+}
+#else
+PyMODINIT_FUNC
+init_imaging(void)
+{
+ PyObject* m = Py_InitModule("_imaging", functions);
+ setup_module(m);
+}
+#endif
diff --git a/contrib/python/Pillow/py2/_imagingcms.c b/contrib/python/Pillow/py2/_imagingcms.c
new file mode 100644
index 0000000000..2c9f3aa68f
--- /dev/null
+++ b/contrib/python/Pillow/py2/_imagingcms.c
@@ -0,0 +1,1644 @@
+/*
+ * pyCMS
+ * a Python / PIL interface to the littleCMS ICC Color Management System
+ * Copyright (C) 2002-2003 Kevin Cazabon
+ * kevin@cazabon.com
+ * http://www.cazabon.com
+ * Adapted/reworked for PIL by Fredrik Lundh
+ * Copyright (c) 2009 Fredrik Lundh
+ * Updated to LCMS2
+ * Copyright (c) 2013 Eric Soroos
+ *
+ * pyCMS home page: http://www.cazabon.com/pyCMS
+ * littleCMS home page: http://www.littlecms.com
+ * (littleCMS is Copyright (C) 1998-2001 Marti Maria)
+ *
+ * Originally released under LGPL. Graciously donated to PIL in
+ * March 2009, for distribution under the standard PIL license
+ */
+
+#define COPYRIGHTINFO "\
+pyCMS\n\
+a Python / PIL interface to the littleCMS ICC Color Management System\n\
+Copyright (C) 2002-2003 Kevin Cazabon\n\
+kevin@cazabon.com\n\
+http://www.cazabon.com\n\
+"
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h" // Include before wchar.h so _GNU_SOURCE is set
+#include "wchar.h"
+#include "datetime.h"
+
+#include "lcms2.h"
+#include "Imaging.h"
+#include "py3.h"
+
+#define PYCMSVERSION "1.0.0 pil"
+
+/* version history */
+
+/*
+ 1.0.0 pil Integrating littleCMS2
+ 0.1.0 pil integration & refactoring
+ 0.0.2 alpha: Minor updates, added interfaces to littleCMS features, Jan 6, 2003
+ - fixed some memory holes in how transforms/profiles were created and passed back to Python
+ due to improper destructor setup for PyCObjects
+ - added buildProofTransformFromOpenProfiles() function
+ - eliminated some code redundancy, centralizing several common tasks with internal functions
+
+ 0.0.1 alpha: First public release Dec 26, 2002
+
+*/
+
+/* known to-do list with current version:
+
+ Verify that PILmode->littleCMStype conversion in findLCMStype is correct for all
+ PIL modes (it probably isn't for the more obscure ones)
+
+ Add support for creating custom RGB profiles on the fly
+ Add support for checking presence of a specific tag in a profile
+ Add support for other littleCMS features as required
+
+*/
+
+/*
+ INTENT_PERCEPTUAL 0
+ INTENT_RELATIVE_COLORIMETRIC 1
+ INTENT_SATURATION 2
+ INTENT_ABSOLUTE_COLORIMETRIC 3
+*/
+
+/* -------------------------------------------------------------------- */
+/* wrapper classes */
+
+/* a profile represents the ICC characteristics for a specific device */
+
+typedef struct {
+ PyObject_HEAD
+ cmsHPROFILE profile;
+} CmsProfileObject;
+
+static PyTypeObject CmsProfile_Type;
+
+#define CmsProfile_Check(op) (Py_TYPE(op) == &CmsProfile_Type)
+
+static PyObject*
+cms_profile_new(cmsHPROFILE profile)
+{
+ CmsProfileObject* self;
+
+ self = PyObject_New(CmsProfileObject, &CmsProfile_Type);
+ if (!self)
+ return NULL;
+
+ self->profile = profile;
+
+ return (PyObject*) self;
+}
+
+static PyObject*
+cms_profile_open(PyObject* self, PyObject* args)
+{
+ cmsHPROFILE hProfile;
+
+ char* sProfile;
+ if (!PyArg_ParseTuple(args, "s:profile_open", &sProfile))
+ return NULL;
+
+ hProfile = cmsOpenProfileFromFile(sProfile, "r");
+ if (!hProfile) {
+ PyErr_SetString(PyExc_IOError, "cannot open profile file");
+ return NULL;
+ }
+
+ return cms_profile_new(hProfile);
+}
+
+static PyObject*
+cms_profile_fromstring(PyObject* self, PyObject* args)
+{
+ cmsHPROFILE hProfile;
+
+ char* pProfile;
+ Py_ssize_t nProfile;
+#if PY_VERSION_HEX >= 0x03000000
+ if (!PyArg_ParseTuple(args, "y#:profile_frombytes", &pProfile, &nProfile))
+ return NULL;
+#else
+ if (!PyArg_ParseTuple(args, "s#:profile_fromstring", &pProfile, &nProfile))
+ return NULL;
+#endif
+
+ hProfile = cmsOpenProfileFromMem(pProfile, nProfile);
+ if (!hProfile) {
+ PyErr_SetString(PyExc_IOError, "cannot open profile from string");
+ return NULL;
+ }
+
+ return cms_profile_new(hProfile);
+}
+
+static PyObject*
+cms_profile_tobytes(PyObject* self, PyObject* args)
+{
+ char *pProfile =NULL;
+ cmsUInt32Number nProfile;
+ PyObject* CmsProfile;
+
+ cmsHPROFILE *profile;
+
+ PyObject* ret;
+ if (!PyArg_ParseTuple(args, "O", &CmsProfile)){
+ return NULL;
+ }
+
+ profile = ((CmsProfileObject*)CmsProfile)->profile;
+
+ if (!cmsSaveProfileToMem(profile, pProfile, &nProfile)) {
+ PyErr_SetString(PyExc_IOError, "Could not determine profile size");
+ return NULL;
+ }
+
+ pProfile = (char*)malloc(nProfile);
+ if (!pProfile) {
+ PyErr_SetString(PyExc_IOError, "Out of Memory");
+ return NULL;
+ }
+
+ if (!cmsSaveProfileToMem(profile, pProfile, &nProfile)) {
+ PyErr_SetString(PyExc_IOError, "Could not get profile");
+ free(pProfile);
+ return NULL;
+ }
+
+#if PY_VERSION_HEX >= 0x03000000
+ ret = PyBytes_FromStringAndSize(pProfile, (Py_ssize_t)nProfile);
+#else
+ ret = PyString_FromStringAndSize(pProfile, (Py_ssize_t)nProfile);
+#endif
+
+ free(pProfile);
+ return ret;
+}
+
+static void
+cms_profile_dealloc(CmsProfileObject* self)
+{
+ (void) cmsCloseProfile(self->profile);
+ PyObject_Del(self);
+}
+
+/* a transform represents the mapping between two profiles */
+
+typedef struct {
+ PyObject_HEAD
+ char mode_in[8];
+ char mode_out[8];
+ cmsHTRANSFORM transform;
+} CmsTransformObject;
+
+static PyTypeObject CmsTransform_Type;
+
+#define CmsTransform_Check(op) (Py_TYPE(op) == &CmsTransform_Type)
+
+static PyObject*
+cms_transform_new(cmsHTRANSFORM transform, char* mode_in, char* mode_out)
+{
+ CmsTransformObject* self;
+
+ self = PyObject_New(CmsTransformObject, &CmsTransform_Type);
+ if (!self)
+ return NULL;
+
+ self->transform = transform;
+
+ strcpy(self->mode_in, mode_in);
+ strcpy(self->mode_out, mode_out);
+
+ return (PyObject*) self;
+}
+
+static void
+cms_transform_dealloc(CmsTransformObject* self)
+{
+ cmsDeleteTransform(self->transform);
+ PyObject_Del(self);
+}
+
+/* -------------------------------------------------------------------- */
+/* internal functions */
+
+static const char*
+findICmode(cmsColorSpaceSignature cs)
+{
+ switch (cs) {
+ case cmsSigXYZData: return "XYZ";
+ case cmsSigLabData: return "LAB";
+ case cmsSigLuvData: return "LUV";
+ case cmsSigYCbCrData: return "YCbCr";
+ case cmsSigYxyData: return "YXY";
+ case cmsSigRgbData: return "RGB";
+ case cmsSigGrayData: return "L";
+ case cmsSigHsvData: return "HSV";
+ case cmsSigHlsData: return "HLS";
+ case cmsSigCmykData: return "CMYK";
+ case cmsSigCmyData: return "CMY";
+ default: return ""; /* other TBA */
+ }
+}
+
+static cmsUInt32Number
+findLCMStype(char* PILmode)
+{
+ if (strcmp(PILmode, "RGB") == 0) {
+ return TYPE_RGBA_8;
+ }
+ else if (strcmp(PILmode, "RGBA") == 0) {
+ return TYPE_RGBA_8;
+ }
+ else if (strcmp(PILmode, "RGBX") == 0) {
+ return TYPE_RGBA_8;
+ }
+ else if (strcmp(PILmode, "RGBA;16B") == 0) {
+ return TYPE_RGBA_16;
+ }
+ else if (strcmp(PILmode, "CMYK") == 0) {
+ return TYPE_CMYK_8;
+ }
+ else if (strcmp(PILmode, "L") == 0) {
+ return TYPE_GRAY_8;
+ }
+ else if (strcmp(PILmode, "L;16") == 0) {
+ return TYPE_GRAY_16;
+ }
+ else if (strcmp(PILmode, "L;16B") == 0) {
+ return TYPE_GRAY_16_SE;
+ }
+ else if (strcmp(PILmode, "YCCA") == 0) {
+ return TYPE_YCbCr_8;
+ }
+ else if (strcmp(PILmode, "YCC") == 0) {
+ return TYPE_YCbCr_8;
+ }
+ else if (strcmp(PILmode, "LAB") == 0) {
+ // LabX equivalent like ALab, but not reversed -- no #define in lcms2
+ return (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1));
+ }
+
+ else {
+ /* take a wild guess... but you probably should fail instead. */
+ return TYPE_GRAY_8; /* so there's no buffer overrun... */
+ }
+}
+
+#define Cms_Min(a, b) ((a) < (b) ? (a) : (b))
+
+static int
+pyCMSgetAuxChannelChannel (cmsUInt32Number format, int auxChannelNdx)
+{
+ int numColors = T_CHANNELS(format);
+ int numExtras = T_EXTRA(format);
+
+ if (T_SWAPFIRST(format) && T_DOSWAP(format)) {
+ // reverse order, before anything but last extra is shifted last
+ if (auxChannelNdx == numExtras - 1)
+ return numColors + numExtras - 1;
+ else
+ return numExtras - 2 - auxChannelNdx;
+ }
+ else if (T_SWAPFIRST(format)) {
+ // in order, after color channels, but last extra is shifted to first
+ if (auxChannelNdx == numExtras - 1)
+ return 0;
+ else
+ return numColors + 1 + auxChannelNdx;
+ }
+ else if (T_DOSWAP(format)) {
+ // reverse order, before anything
+ return numExtras - 1 - auxChannelNdx;
+ }
+ else {
+ // in order, after color channels
+ return numColors + auxChannelNdx;
+ }
+}
+
+static void
+pyCMScopyAux (cmsHTRANSFORM hTransform, Imaging imDst, const Imaging imSrc)
+{
+ cmsUInt32Number dstLCMSFormat;
+ cmsUInt32Number srcLCMSFormat;
+ int numSrcExtras;
+ int numDstExtras;
+ int numExtras;
+ int ySize;
+ int xSize;
+ int channelSize;
+ int srcChunkSize;
+ int dstChunkSize;
+ int e;
+
+ // trivially copied
+ if (imDst == imSrc)
+ return;
+
+ dstLCMSFormat = cmsGetTransformOutputFormat(hTransform);
+ srcLCMSFormat = cmsGetTransformInputFormat(hTransform);
+
+ // currently, all Pillow formats are chunky formats, but check it anyway
+ if (T_PLANAR(dstLCMSFormat) || T_PLANAR(srcLCMSFormat))
+ return;
+
+ // copy only if channel format is identical, except OPTIMIZED is ignored as it
+ // does not affect the aux channel
+ if (T_FLOAT(dstLCMSFormat) != T_FLOAT(srcLCMSFormat)
+ || T_FLAVOR(dstLCMSFormat) != T_FLAVOR(srcLCMSFormat)
+ || T_ENDIAN16(dstLCMSFormat) != T_ENDIAN16(srcLCMSFormat)
+ || T_BYTES(dstLCMSFormat) != T_BYTES(srcLCMSFormat))
+ return;
+
+ numSrcExtras = T_EXTRA(srcLCMSFormat);
+ numDstExtras = T_EXTRA(dstLCMSFormat);
+ numExtras = Cms_Min(numSrcExtras, numDstExtras);
+ ySize = Cms_Min(imSrc->ysize, imDst->ysize);
+ xSize = Cms_Min(imSrc->xsize, imDst->xsize);
+ channelSize = T_BYTES(dstLCMSFormat);
+ srcChunkSize = (T_CHANNELS(srcLCMSFormat) + T_EXTRA(srcLCMSFormat)) * channelSize;
+ dstChunkSize = (T_CHANNELS(dstLCMSFormat) + T_EXTRA(dstLCMSFormat)) * channelSize;
+
+ for (e = 0; e < numExtras; ++e) {
+ int y;
+ int dstChannel = pyCMSgetAuxChannelChannel(dstLCMSFormat, e);
+ int srcChannel = pyCMSgetAuxChannelChannel(srcLCMSFormat, e);
+
+ for (y = 0; y < ySize; y++) {
+ int x;
+ char* pDstExtras = imDst->image[y] + dstChannel * channelSize;
+ const char* pSrcExtras = imSrc->image[y] + srcChannel * channelSize;
+
+ for (x = 0; x < xSize; x++)
+ memcpy(pDstExtras + x * dstChunkSize, pSrcExtras + x * srcChunkSize, channelSize);
+ }
+ }
+}
+
+static int
+pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform)
+{
+ int i;
+
+ if (im->xsize > imOut->xsize || im->ysize > imOut->ysize)
+ return -1;
+
+ Py_BEGIN_ALLOW_THREADS
+
+ // transform color channels only
+ for (i = 0; i < im->ysize; i++)
+ cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize);
+
+ // lcms by default does nothing to the auxiliary channels leaving those
+ // unchanged. To do "the right thing" here, i.e. maintain identical results
+ // with and without inPlace, we replicate those channels to the output.
+ //
+ // As of lcms 2.8, a new cmsFLAGS_COPY_ALPHA flag is introduced which would
+ // do the same thing automagically. Unfortunately, lcms2.8 is not yet widely
+ // enough available on all platforms, so we polyfill it here for now.
+ pyCMScopyAux(hTransform, imOut, im);
+
+ Py_END_ALLOW_THREADS
+
+ return 0;
+}
+
+static cmsHTRANSFORM
+_buildTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, char *sInMode, char *sOutMode, int iRenderingIntent, cmsUInt32Number cmsFLAGS)
+{
+ cmsHTRANSFORM hTransform;
+
+ Py_BEGIN_ALLOW_THREADS
+
+ /* create the transform */
+ hTransform = cmsCreateTransform(hInputProfile,
+ findLCMStype(sInMode),
+ hOutputProfile,
+ findLCMStype(sOutMode),
+ iRenderingIntent, cmsFLAGS);
+
+ Py_END_ALLOW_THREADS
+
+ if (!hTransform)
+ PyErr_SetString(PyExc_ValueError, "cannot build transform");
+
+ return hTransform; /* if NULL, an exception is set */
+}
+
+static cmsHTRANSFORM
+_buildProofTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, cmsHPROFILE hProofProfile, char *sInMode, char *sOutMode, int iRenderingIntent, int iProofIntent, cmsUInt32Number cmsFLAGS)
+{
+ cmsHTRANSFORM hTransform;
+
+ Py_BEGIN_ALLOW_THREADS
+
+ /* create the transform */
+ hTransform = cmsCreateProofingTransform(hInputProfile,
+ findLCMStype(sInMode),
+ hOutputProfile,
+ findLCMStype(sOutMode),
+ hProofProfile,
+ iRenderingIntent,
+ iProofIntent,
+ cmsFLAGS);
+
+ Py_END_ALLOW_THREADS
+
+ if (!hTransform)
+ PyErr_SetString(PyExc_ValueError, "cannot build proof transform");
+
+ return hTransform; /* if NULL, an exception is set */
+}
+
+/* -------------------------------------------------------------------- */
+/* Python callable functions */
+
+static PyObject *
+buildTransform(PyObject *self, PyObject *args) {
+ CmsProfileObject *pInputProfile;
+ CmsProfileObject *pOutputProfile;
+ char *sInMode;
+ char *sOutMode;
+ int iRenderingIntent = 0;
+ int cmsFLAGS = 0;
+
+ cmsHTRANSFORM transform = NULL;
+
+ if (!PyArg_ParseTuple(args, "O!O!ss|ii:buildTransform", &CmsProfile_Type, &pInputProfile, &CmsProfile_Type, &pOutputProfile, &sInMode, &sOutMode, &iRenderingIntent, &cmsFLAGS))
+ return NULL;
+
+ transform = _buildTransform(pInputProfile->profile, pOutputProfile->profile, sInMode, sOutMode, iRenderingIntent, cmsFLAGS);
+
+ if (!transform)
+ return NULL;
+
+ return cms_transform_new(transform, sInMode, sOutMode);
+}
+
+static PyObject *
+buildProofTransform(PyObject *self, PyObject *args)
+{
+ CmsProfileObject *pInputProfile;
+ CmsProfileObject *pOutputProfile;
+ CmsProfileObject *pProofProfile;
+ char *sInMode;
+ char *sOutMode;
+ int iRenderingIntent = 0;
+ int iProofIntent = 0;
+ int cmsFLAGS = 0;
+
+ cmsHTRANSFORM transform = NULL;
+
+ if (!PyArg_ParseTuple(args, "O!O!O!ss|iii:buildProofTransform", &CmsProfile_Type, &pInputProfile, &CmsProfile_Type, &pOutputProfile, &CmsProfile_Type, &pProofProfile, &sInMode, &sOutMode, &iRenderingIntent, &iProofIntent, &cmsFLAGS))
+ return NULL;
+
+ transform = _buildProofTransform(pInputProfile->profile, pOutputProfile->profile, pProofProfile->profile, sInMode, sOutMode, iRenderingIntent, iProofIntent, cmsFLAGS);
+
+ if (!transform)
+ return NULL;
+
+ return cms_transform_new(transform, sInMode, sOutMode);
+
+}
+
+static PyObject *
+cms_transform_apply(CmsTransformObject *self, PyObject *args)
+{
+ Py_ssize_t idIn;
+ Py_ssize_t idOut;
+ Imaging im;
+ Imaging imOut;
+
+ int result;
+
+ if (!PyArg_ParseTuple(args, "nn:apply", &idIn, &idOut))
+ return NULL;
+
+ im = (Imaging) idIn;
+ imOut = (Imaging) idOut;
+
+ result = pyCMSdoTransform(im, imOut, self->transform);
+
+ return Py_BuildValue("i", result);
+}
+
+/* -------------------------------------------------------------------- */
+/* Python-Callable On-The-Fly profile creation functions */
+
+static PyObject *
+createProfile(PyObject *self, PyObject *args)
+{
+ char *sColorSpace;
+ cmsHPROFILE hProfile;
+ cmsFloat64Number dColorTemp = 0.0;
+ cmsCIExyY whitePoint;
+ cmsBool result;
+
+ if (!PyArg_ParseTuple(args, "s|d:createProfile", &sColorSpace, &dColorTemp))
+ return NULL;
+
+ if (strcmp(sColorSpace, "LAB") == 0) {
+ if (dColorTemp > 0.0) {
+ result = cmsWhitePointFromTemp(&whitePoint, dColorTemp);
+ if (!result) {
+ PyErr_SetString(PyExc_ValueError, "ERROR: Could not calculate white point from color temperature provided, must be float in degrees Kelvin");
+ return NULL;
+ }
+ hProfile = cmsCreateLab2Profile(&whitePoint);
+ } else {
+ hProfile = cmsCreateLab2Profile(NULL);
+ }
+ }
+ else if (strcmp(sColorSpace, "XYZ") == 0) {
+ hProfile = cmsCreateXYZProfile();
+ }
+ else if (strcmp(sColorSpace, "sRGB") == 0) {
+ hProfile = cmsCreate_sRGBProfile();
+ }
+ else {
+ hProfile = NULL;
+ }
+
+ if (!hProfile) {
+ PyErr_SetString(PyExc_ValueError, "failed to create requested color space");
+ return NULL;
+ }
+
+ return cms_profile_new(hProfile);
+}
+
+/* -------------------------------------------------------------------- */
+/* profile methods */
+
+static PyObject *
+cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args)
+{
+ cmsBool result;
+
+ int intent;
+ int direction;
+ if (!PyArg_ParseTuple(args, "ii:is_intent_supported", &intent, &direction))
+ return NULL;
+
+ result = cmsIsIntentSupported(self->profile, intent, direction);
+
+ /* printf("cmsIsIntentSupported(%p, %d, %d) => %d\n", self->profile, intent, direction, result); */
+
+ return PyInt_FromLong(result != 0);
+}
+
+#ifdef _WIN32
+
+#ifdef _WIN64
+#define F_HANDLE "K"
+#else
+#define F_HANDLE "k"
+#endif
+
+static PyObject *
+cms_get_display_profile_win32(PyObject* self, PyObject* args)
+{
+ char filename[MAX_PATH];
+ cmsUInt32Number filename_size;
+ BOOL ok;
+
+ HANDLE handle = 0;
+ int is_dc = 0;
+ if (!PyArg_ParseTuple(args, "|" F_HANDLE "i:get_display_profile", &handle, &is_dc))
+ return NULL;
+
+ filename_size = sizeof(filename);
+
+ if (is_dc) {
+ ok = GetICMProfile((HDC) handle, &filename_size, filename);
+ } else {
+ HDC dc = GetDC((HWND) handle);
+ ok = GetICMProfile(dc, &filename_size, filename);
+ ReleaseDC((HWND) handle, dc);
+ }
+
+ if (ok)
+ return PyUnicode_FromStringAndSize(filename, filename_size-1);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif
+
+/* -------------------------------------------------------------------- */
+/* Helper functions. */
+
+static PyObject*
+_profile_read_mlu(CmsProfileObject* self, cmsTagSignature info)
+{
+ PyObject *uni;
+ char *lc = "en";
+ char *cc = cmsNoCountry;
+ cmsMLU *mlu;
+ cmsUInt32Number len;
+ wchar_t *buf;
+
+ if (!cmsIsTag(self->profile, info)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ mlu = cmsReadTag(self->profile, info);
+ if (!mlu) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ len = cmsMLUgetWide(mlu, lc, cc, NULL, 0);
+ if (len == 0) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ buf = malloc(len);
+ if (!buf) {
+ PyErr_SetString(PyExc_IOError, "Out of Memory");
+ return NULL;
+ }
+ /* Just in case the next call fails. */
+ buf[0] = '\0';
+
+ cmsMLUgetWide(mlu, lc, cc, buf, len);
+ // buf contains additional junk after \0
+ uni = PyUnicode_FromWideChar(buf, wcslen(buf));
+ free(buf);
+
+ return uni;
+}
+
+
+static PyObject*
+_profile_read_int_as_string(cmsUInt32Number nr)
+{
+ PyObject* ret;
+ char buf[5];
+ buf[0] = (char) ((nr >> 24) & 0xff);
+ buf[1] = (char) ((nr >> 16) & 0xff);
+ buf[2] = (char) ((nr >> 8) & 0xff);
+ buf[3] = (char) (nr & 0xff);
+ buf[4] = 0;
+
+#if PY_VERSION_HEX >= 0x03000000
+ ret = PyUnicode_DecodeASCII(buf, 4, NULL);
+#else
+ ret = PyString_FromStringAndSize(buf, 4);
+#endif
+ return ret;
+}
+
+
+static PyObject*
+_profile_read_signature(CmsProfileObject* self, cmsTagSignature info)
+{
+ unsigned int *sig;
+
+ if (!cmsIsTag(self->profile, info)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ sig = (unsigned int *) cmsReadTag(self->profile, info);
+ if (!sig) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return _profile_read_int_as_string(*sig);
+}
+
+static PyObject*
+_xyz_py(cmsCIEXYZ* XYZ)
+{
+ cmsCIExyY xyY;
+ cmsXYZ2xyY(&xyY, XYZ);
+ return Py_BuildValue("((d,d,d),(d,d,d))", XYZ->X, XYZ->Y, XYZ->Z, xyY.x, xyY.y, xyY.Y);
+}
+
+static PyObject*
+_xyz3_py(cmsCIEXYZ* XYZ)
+{
+ cmsCIExyY xyY[3];
+ cmsXYZ2xyY(&xyY[0], &XYZ[0]);
+ cmsXYZ2xyY(&xyY[1], &XYZ[1]);
+ cmsXYZ2xyY(&xyY[2], &XYZ[2]);
+
+ return Py_BuildValue("(((d,d,d),(d,d,d),(d,d,d)),((d,d,d),(d,d,d),(d,d,d)))",
+ XYZ[0].X, XYZ[0].Y, XYZ[0].Z,
+ XYZ[1].X, XYZ[1].Y, XYZ[1].Z,
+ XYZ[2].X, XYZ[2].Y, XYZ[2].Z,
+ xyY[0].x, xyY[0].y, xyY[0].Y,
+ xyY[1].x, xyY[1].y, xyY[1].Y,
+ xyY[2].x, xyY[2].y, xyY[2].Y);
+}
+
+static PyObject*
+_profile_read_ciexyz(CmsProfileObject* self, cmsTagSignature info, int multi)
+{
+ cmsCIEXYZ* XYZ;
+
+ if (!cmsIsTag(self->profile, info)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ XYZ = (cmsCIEXYZ*) cmsReadTag(self->profile, info);
+ if (!XYZ) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ if (multi)
+ return _xyz3_py(XYZ);
+ else
+ return _xyz_py(XYZ);
+}
+
+static PyObject*
+_profile_read_ciexyy_triple(CmsProfileObject* self, cmsTagSignature info)
+{
+ cmsCIExyYTRIPLE* triple;
+
+ if (!cmsIsTag(self->profile, info)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ triple = (cmsCIExyYTRIPLE*) cmsReadTag(self->profile, info);
+ if (!triple) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ /* Note: lcms does all the heavy lifting and error checking (nr of
+ channels == 3). */
+ return Py_BuildValue("((d,d,d),(d,d,d),(d,d,d)),",
+ triple->Red.x, triple->Red.y, triple->Red.Y,
+ triple->Green.x, triple->Green.y, triple->Green.Y,
+ triple->Blue.x, triple->Blue.y, triple->Blue.Y);
+}
+
+static PyObject*
+_profile_read_named_color_list(CmsProfileObject* self, cmsTagSignature info)
+{
+ cmsNAMEDCOLORLIST* ncl;
+ int i, n;
+ char name[cmsMAX_PATH];
+ PyObject* result;
+
+ if (!cmsIsTag(self->profile, info)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ ncl = (cmsNAMEDCOLORLIST*) cmsReadTag(self->profile, info);
+ if (ncl == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ n = cmsNamedColorCount(ncl);
+ result = PyList_New(n);
+ if (!result) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ for (i = 0; i < n; i++) {
+ PyObject* str;
+ cmsNamedColorInfo(ncl, i, name, NULL, NULL, NULL, NULL);
+ str = PyUnicode_FromString(name);
+ if (str == NULL) {
+ Py_DECREF(result);
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ PyList_SET_ITEM(result, i, str);
+ }
+
+ return result;
+}
+
+static cmsBool _calculate_rgb_primaries(CmsProfileObject* self, cmsCIEXYZTRIPLE* result)
+{
+ double input[3][3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
+ cmsHPROFILE hXYZ;
+ cmsHTRANSFORM hTransform;
+
+ /* https://littlecms2.blogspot.com/2009/07/less-is-more.html */
+
+ // double array of RGB values with max on each identity
+ hXYZ = cmsCreateXYZProfile();
+ if (hXYZ == NULL)
+ return 0;
+
+ // transform from our profile to XYZ using doubles for highest precision
+ hTransform = cmsCreateTransform(self->profile, TYPE_RGB_DBL,
+ hXYZ, TYPE_XYZ_DBL,
+ INTENT_RELATIVE_COLORIMETRIC,
+ cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE);
+ cmsCloseProfile(hXYZ);
+ if (hTransform == NULL)
+ return 0;
+
+ cmsDoTransform(hTransform, (void*) input, result, 3);
+ cmsDeleteTransform(hTransform);
+ return 1;
+}
+
+static cmsBool _check_intent(int clut, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection)
+{
+ if (clut) {
+ return cmsIsCLUT(hProfile, Intent, UsedDirection);
+ }
+ else {
+ return cmsIsIntentSupported(hProfile, Intent, UsedDirection);
+ }
+}
+
+#define INTENTS 200
+
+static PyObject*
+_is_intent_supported(CmsProfileObject* self, int clut)
+{
+ PyObject* result;
+ int n;
+ int i;
+ cmsUInt32Number intent_ids[INTENTS];
+ char *intent_descs[INTENTS];
+
+ result = PyDict_New();
+ if (result == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+
+ n = cmsGetSupportedIntents(INTENTS,
+ intent_ids,
+ intent_descs);
+ for (i = 0; i < n; i++) {
+ int intent = (int) intent_ids[i];
+ PyObject* id;
+ PyObject* entry;
+
+ /* Only valid for ICC Intents (otherwise we read invalid memory in lcms cmsio1.c). */
+ if (!(intent == INTENT_PERCEPTUAL || intent == INTENT_RELATIVE_COLORIMETRIC
+ || intent == INTENT_SATURATION || intent == INTENT_ABSOLUTE_COLORIMETRIC))
+ continue;
+
+ id = PyInt_FromLong((long) intent);
+ entry = Py_BuildValue("(OOO)",
+ _check_intent(clut, self->profile, intent, LCMS_USED_AS_INPUT) ? Py_True : Py_False,
+ _check_intent(clut, self->profile, intent, LCMS_USED_AS_OUTPUT) ? Py_True : Py_False,
+ _check_intent(clut, self->profile, intent, LCMS_USED_AS_PROOF) ? Py_True : Py_False);
+ if (id == NULL || entry == NULL) {
+ Py_XDECREF(id);
+ Py_XDECREF(entry);
+ Py_XDECREF(result);
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ PyDict_SetItem(result, id, entry);
+ }
+ return result;
+}
+
+/* -------------------------------------------------------------------- */
+/* Python interface setup */
+
+static PyMethodDef pyCMSdll_methods[] = {
+
+ {"profile_open", cms_profile_open, 1},
+ {"profile_frombytes", cms_profile_fromstring, 1},
+ {"profile_fromstring", cms_profile_fromstring, 1},
+ {"profile_tobytes", cms_profile_tobytes, 1},
+
+ /* profile and transform functions */
+ {"buildTransform", buildTransform, 1},
+ {"buildProofTransform", buildProofTransform, 1},
+ {"createProfile", createProfile, 1},
+
+ /* platform specific tools */
+#ifdef _WIN32
+ {"get_display_profile_win32", cms_get_display_profile_win32, 1},
+#endif
+
+ {NULL, NULL}
+};
+
+static struct PyMethodDef cms_profile_methods[] = {
+ {"is_intent_supported", (PyCFunction) cms_profile_is_intent_supported, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject*
+_profile_getattr(CmsProfileObject* self, cmsInfoType field)
+{
+ // UNDONE -- check that I'm getting the right fields on these.
+ // return PyUnicode_DecodeFSDefault(cmsTakeProductName(self->profile));
+ //wchar_t buf[256]; -- UNDONE need wchar_t for unicode version.
+ char buf[256];
+ cmsUInt32Number written;
+ written = cmsGetProfileInfoASCII(self->profile,
+ field,
+ "en",
+ "us",
+ buf,
+ 256);
+ if (written) {
+ return PyUnicode_FromString(buf);
+ }
+ // UNDONE suppressing error here by sending back blank string.
+ return PyUnicode_FromString("");
+}
+
+static PyObject*
+cms_profile_getattr_product_desc(CmsProfileObject* self, void* closure)
+{
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "product_desc is deprecated. Use Unicode profile_description instead.", 1);
+ // description was Description != 'Copyright' || or "%s - %s" (manufacturer, model) in 1.x
+ return _profile_getattr(self, cmsInfoDescription);
+}
+
+/* use these four for the individual fields.
+ */
+static PyObject*
+cms_profile_getattr_product_description(CmsProfileObject* self, void* closure)
+{
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "product_description is deprecated. Use Unicode profile_description instead.", 1);
+ return _profile_getattr(self, cmsInfoDescription);
+}
+
+static PyObject*
+cms_profile_getattr_product_model(CmsProfileObject* self, void* closure)
+{
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "product_model is deprecated. Use Unicode model instead.", 1);
+ return _profile_getattr(self, cmsInfoModel);
+}
+
+static PyObject*
+cms_profile_getattr_product_manufacturer(CmsProfileObject* self, void* closure)
+{
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "product_manufacturer is deprecated. Use Unicode manufacturer instead.", 1);
+ return _profile_getattr(self, cmsInfoManufacturer);
+}
+
+static PyObject*
+cms_profile_getattr_product_copyright(CmsProfileObject* self, void* closure)
+{
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "product_copyright is deprecated. Use Unicode copyright instead.", 1);
+ return _profile_getattr(self, cmsInfoCopyright);
+}
+
+static PyObject*
+cms_profile_getattr_rendering_intent(CmsProfileObject* self, void* closure)
+{
+ return PyInt_FromLong(cmsGetHeaderRenderingIntent(self->profile));
+}
+
+static PyObject*
+cms_profile_getattr_pcs(CmsProfileObject* self, void* closure)
+{
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "pcs is deprecated. Use padded connection_space instead.", 1);
+ return PyUnicode_DecodeFSDefault(findICmode(cmsGetPCS(self->profile)));
+}
+
+static PyObject*
+cms_profile_getattr_color_space(CmsProfileObject* self, void* closure)
+{
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "color_space is deprecated. Use padded xcolor_space instead.", 1);
+ return PyUnicode_DecodeFSDefault(findICmode(cmsGetColorSpace(self->profile)));
+}
+
+/* New-style unicode interfaces. */
+static PyObject*
+cms_profile_getattr_copyright(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_mlu(self, cmsSigCopyrightTag);
+}
+
+static PyObject*
+cms_profile_getattr_target(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_mlu(self, cmsSigCharTargetTag);
+}
+
+static PyObject*
+cms_profile_getattr_manufacturer(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_mlu(self, cmsSigDeviceMfgDescTag);
+}
+
+static PyObject*
+cms_profile_getattr_model(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_mlu(self, cmsSigDeviceModelDescTag);
+}
+
+static PyObject*
+cms_profile_getattr_profile_description(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_mlu(self, cmsSigProfileDescriptionTag);
+}
+
+static PyObject*
+cms_profile_getattr_screening_description(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_mlu(self, cmsSigScreeningDescTag);
+}
+
+static PyObject*
+cms_profile_getattr_viewing_condition(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_mlu(self, cmsSigViewingCondDescTag);
+}
+
+static PyObject*
+cms_profile_getattr_creation_date(CmsProfileObject* self, void* closure)
+{
+ cmsBool result;
+ struct tm ct;
+
+ result = cmsGetHeaderCreationDateTime(self->profile, &ct);
+ if (! result) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return PyDateTime_FromDateAndTime(1900 + ct.tm_year, ct.tm_mon, ct.tm_mday,
+ ct.tm_hour, ct.tm_min, ct.tm_sec, 0);
+}
+
+static PyObject*
+cms_profile_getattr_version(CmsProfileObject* self, void* closure)
+{
+ cmsFloat64Number version = cmsGetProfileVersion(self->profile);
+ return PyFloat_FromDouble(version);
+}
+
+static PyObject*
+cms_profile_getattr_icc_version(CmsProfileObject* self, void* closure)
+{
+ return PyInt_FromLong((long) cmsGetEncodedICCversion(self->profile));
+}
+
+static PyObject*
+cms_profile_getattr_attributes(CmsProfileObject* self, void* closure)
+{
+ cmsUInt64Number attr;
+ cmsGetHeaderAttributes(self->profile, &attr);
+ /* This works just as well on Windows (LLP64), 32-bit Linux
+ (ILP32) and 64-bit Linux (LP64) systems. */
+ return PyLong_FromUnsignedLongLong((unsigned long long) attr);
+}
+
+static PyObject*
+cms_profile_getattr_header_flags(CmsProfileObject* self, void* closure)
+{
+ cmsUInt32Number flags = cmsGetHeaderFlags(self->profile);
+ return PyInt_FromLong(flags);
+}
+
+static PyObject*
+cms_profile_getattr_header_manufacturer(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_int_as_string(cmsGetHeaderManufacturer(self->profile));
+}
+
+static PyObject*
+cms_profile_getattr_header_model(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_int_as_string(cmsGetHeaderModel(self->profile));
+}
+
+static PyObject*
+cms_profile_getattr_device_class(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_int_as_string(cmsGetDeviceClass(self->profile));
+}
+
+/* Duplicate of pcs, but uninterpreted. */
+static PyObject*
+cms_profile_getattr_connection_space(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_int_as_string(cmsGetPCS(self->profile));
+}
+
+/* Duplicate of color_space, but uninterpreted. */
+static PyObject*
+cms_profile_getattr_xcolor_space(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_int_as_string(cmsGetColorSpace(self->profile));
+}
+
+static PyObject*
+cms_profile_getattr_profile_id(CmsProfileObject* self, void* closure)
+{
+ cmsUInt8Number id[16];
+ cmsGetHeaderProfileID(self->profile, id);
+ return PyBytes_FromStringAndSize((char *) id, 16);
+}
+
+static PyObject*
+cms_profile_getattr_is_matrix_shaper(CmsProfileObject* self, void* closure)
+{
+ return PyBool_FromLong((long) cmsIsMatrixShaper(self->profile));
+}
+
+static PyObject*
+cms_profile_getattr_technology(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_signature(self, cmsSigTechnologyTag);
+}
+
+static PyObject*
+cms_profile_getattr_colorimetric_intent(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_signature(self, cmsSigColorimetricIntentImageStateTag);
+}
+
+static PyObject*
+cms_profile_getattr_perceptual_rendering_intent_gamut(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_signature(self, cmsSigPerceptualRenderingIntentGamutTag);
+}
+
+static PyObject*
+cms_profile_getattr_saturation_rendering_intent_gamut(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_signature(self, cmsSigSaturationRenderingIntentGamutTag);
+}
+
+static PyObject*
+cms_profile_getattr_red_colorant(CmsProfileObject* self, void* closure)
+{
+ if (!cmsIsMatrixShaper(self->profile)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return _profile_read_ciexyz(self, cmsSigRedColorantTag, 0);
+}
+
+
+static PyObject*
+cms_profile_getattr_green_colorant(CmsProfileObject* self, void* closure)
+{
+ if (!cmsIsMatrixShaper(self->profile)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return _profile_read_ciexyz(self, cmsSigGreenColorantTag, 0);
+}
+
+
+static PyObject*
+cms_profile_getattr_blue_colorant(CmsProfileObject* self, void* closure)
+{
+ if (!cmsIsMatrixShaper(self->profile)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return _profile_read_ciexyz(self, cmsSigBlueColorantTag, 0);
+}
+
+static PyObject*
+cms_profile_getattr_media_white_point_temperature(CmsProfileObject *self, void* closure)
+{
+ cmsCIEXYZ* XYZ;
+ cmsCIExyY xyY;
+ cmsFloat64Number tempK;
+ cmsTagSignature info = cmsSigMediaWhitePointTag;
+ cmsBool result;
+
+ if (!cmsIsTag(self->profile, info)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ XYZ = (cmsCIEXYZ*) cmsReadTag(self->profile, info);
+ if (!XYZ) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ if (XYZ == NULL || XYZ->X == 0) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ cmsXYZ2xyY(&xyY, XYZ);
+ result = cmsTempFromWhitePoint(&tempK, &xyY);
+ if (!result) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return PyFloat_FromDouble(tempK);
+}
+
+static PyObject*
+cms_profile_getattr_media_white_point(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_ciexyz(self, cmsSigMediaWhitePointTag, 0);
+}
+
+
+static PyObject*
+cms_profile_getattr_media_black_point(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_ciexyz(self, cmsSigMediaBlackPointTag, 0);
+}
+
+static PyObject*
+cms_profile_getattr_luminance(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_ciexyz(self, cmsSigLuminanceTag, 0);
+}
+
+static PyObject*
+cms_profile_getattr_chromatic_adaptation(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_ciexyz(self, cmsSigChromaticAdaptationTag, 1);
+}
+
+static PyObject*
+cms_profile_getattr_chromaticity(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_ciexyy_triple(self, cmsSigChromaticityTag);
+}
+
+static PyObject*
+cms_profile_getattr_red_primary(CmsProfileObject* self, void* closure)
+{
+ cmsBool result = 0;
+ cmsCIEXYZTRIPLE primaries;
+
+ if (cmsIsMatrixShaper(self->profile))
+ result = _calculate_rgb_primaries(self, &primaries);
+ if (! result) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return _xyz_py(&primaries.Red);
+}
+
+static PyObject*
+cms_profile_getattr_green_primary(CmsProfileObject* self, void* closure)
+{
+ cmsBool result = 0;
+ cmsCIEXYZTRIPLE primaries;
+
+ if (cmsIsMatrixShaper(self->profile))
+ result = _calculate_rgb_primaries(self, &primaries);
+ if (! result) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return _xyz_py(&primaries.Green);
+}
+
+static PyObject*
+cms_profile_getattr_blue_primary(CmsProfileObject* self, void* closure)
+{
+ cmsBool result = 0;
+ cmsCIEXYZTRIPLE primaries;
+
+ if (cmsIsMatrixShaper(self->profile))
+ result = _calculate_rgb_primaries(self, &primaries);
+ if (! result) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return _xyz_py(&primaries.Blue);
+}
+
+static PyObject*
+cms_profile_getattr_colorant_table(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_named_color_list(self, cmsSigColorantTableTag);
+}
+
+static PyObject*
+cms_profile_getattr_colorant_table_out(CmsProfileObject* self, void* closure)
+{
+ return _profile_read_named_color_list(self, cmsSigColorantTableOutTag);
+}
+
+static PyObject*
+cms_profile_getattr_is_intent_supported (CmsProfileObject* self, void* closure)
+{
+ return _is_intent_supported(self, 0);
+}
+
+static PyObject*
+cms_profile_getattr_is_clut (CmsProfileObject* self, void* closure)
+{
+ return _is_intent_supported(self, 1);
+}
+
+static const char*
+_illu_map(int i)
+{
+ switch(i) {
+ case 0:
+ return "unknown";
+ case 1:
+ return "D50";
+ case 2:
+ return "D65";
+ case 3:
+ return "D93";
+ case 4:
+ return "F2";
+ case 5:
+ return "D55";
+ case 6:
+ return "A";
+ case 7:
+ return "E";
+ case 8:
+ return "F8";
+ default:
+ return NULL;
+ }
+}
+
+static PyObject*
+cms_profile_getattr_icc_measurement_condition (CmsProfileObject* self, void* closure)
+{
+ cmsICCMeasurementConditions* mc;
+ cmsTagSignature info = cmsSigMeasurementTag;
+ const char *geo;
+
+ if (!cmsIsTag(self->profile, info)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ mc = (cmsICCMeasurementConditions*) cmsReadTag(self->profile, info);
+ if (!mc) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if (mc->Geometry == 1)
+ geo = "45/0, 0/45";
+ else if (mc->Geometry == 2)
+ geo = "0d, d/0";
+ else
+ geo = "unknown";
+
+ return Py_BuildValue("{s:i,s:(ddd),s:s,s:d,s:s}",
+ "observer", mc->Observer,
+ "backing", mc->Backing.X, mc->Backing.Y, mc->Backing.Z,
+ "geo", geo,
+ "flare", mc->Flare,
+ "illuminant_type", _illu_map(mc->IlluminantType));
+}
+
+static PyObject*
+cms_profile_getattr_icc_viewing_condition (CmsProfileObject* self, void* closure)
+{
+ cmsICCViewingConditions* vc;
+ cmsTagSignature info = cmsSigViewingConditionsTag;
+
+ if (!cmsIsTag(self->profile, info)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ vc = (cmsICCViewingConditions*) cmsReadTag(self->profile, info);
+ if (!vc) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return Py_BuildValue("{s:(ddd),s:(ddd),s:s}",
+ "illuminant", vc->IlluminantXYZ.X, vc->IlluminantXYZ.Y, vc->IlluminantXYZ.Z,
+ "surround", vc->SurroundXYZ.X, vc->SurroundXYZ.Y, vc->SurroundXYZ.Z,
+ "illuminant_type", _illu_map(vc->IlluminantType));
+}
+
+
+static struct PyGetSetDef cms_profile_getsetters[] = {
+ /* Compatibility interfaces. */
+ { "product_desc", (getter) cms_profile_getattr_product_desc },
+ { "product_description", (getter) cms_profile_getattr_product_description },
+ { "product_manufacturer", (getter) cms_profile_getattr_product_manufacturer },
+ { "product_model", (getter) cms_profile_getattr_product_model },
+ { "product_copyright", (getter) cms_profile_getattr_product_copyright },
+ { "pcs", (getter) cms_profile_getattr_pcs },
+ { "color_space", (getter) cms_profile_getattr_color_space },
+
+ /* New style interfaces. */
+ { "rendering_intent", (getter) cms_profile_getattr_rendering_intent },
+ { "creation_date", (getter) cms_profile_getattr_creation_date },
+ { "copyright", (getter) cms_profile_getattr_copyright },
+ { "target", (getter) cms_profile_getattr_target },
+ { "manufacturer", (getter) cms_profile_getattr_manufacturer },
+ { "model", (getter) cms_profile_getattr_model },
+ { "profile_description", (getter) cms_profile_getattr_profile_description },
+ { "screening_description", (getter) cms_profile_getattr_screening_description },
+ { "viewing_condition", (getter) cms_profile_getattr_viewing_condition },
+ { "version", (getter) cms_profile_getattr_version },
+ { "icc_version", (getter) cms_profile_getattr_icc_version },
+ { "attributes", (getter) cms_profile_getattr_attributes },
+ { "header_flags", (getter) cms_profile_getattr_header_flags },
+ { "header_manufacturer", (getter) cms_profile_getattr_header_manufacturer },
+ { "header_model", (getter) cms_profile_getattr_header_model },
+ { "device_class", (getter) cms_profile_getattr_device_class },
+ { "connection_space", (getter) cms_profile_getattr_connection_space },
+ /* Similar to color_space, but with full 4-letter signature (including trailing whitespace). */
+ { "xcolor_space", (getter) cms_profile_getattr_xcolor_space },
+ { "profile_id", (getter) cms_profile_getattr_profile_id },
+ { "is_matrix_shaper", (getter) cms_profile_getattr_is_matrix_shaper },
+ { "technology", (getter) cms_profile_getattr_technology },
+ { "colorimetric_intent", (getter) cms_profile_getattr_colorimetric_intent },
+ { "perceptual_rendering_intent_gamut", (getter) cms_profile_getattr_perceptual_rendering_intent_gamut },
+ { "saturation_rendering_intent_gamut", (getter) cms_profile_getattr_saturation_rendering_intent_gamut },
+ { "red_colorant", (getter) cms_profile_getattr_red_colorant },
+ { "green_colorant", (getter) cms_profile_getattr_green_colorant },
+ { "blue_colorant", (getter) cms_profile_getattr_blue_colorant },
+ { "red_primary", (getter) cms_profile_getattr_red_primary },
+ { "green_primary", (getter) cms_profile_getattr_green_primary },
+ { "blue_primary", (getter) cms_profile_getattr_blue_primary },
+ { "media_white_point_temperature", (getter) cms_profile_getattr_media_white_point_temperature },
+ { "media_white_point", (getter) cms_profile_getattr_media_white_point },
+ { "media_black_point", (getter) cms_profile_getattr_media_black_point },
+ { "luminance", (getter) cms_profile_getattr_luminance },
+ { "chromatic_adaptation", (getter) cms_profile_getattr_chromatic_adaptation },
+ { "chromaticity", (getter) cms_profile_getattr_chromaticity },
+ { "colorant_table", (getter) cms_profile_getattr_colorant_table },
+ { "colorant_table_out", (getter) cms_profile_getattr_colorant_table_out },
+ { "intent_supported", (getter) cms_profile_getattr_is_intent_supported },
+ { "clut", (getter) cms_profile_getattr_is_clut },
+ { "icc_measurement_condition", (getter) cms_profile_getattr_icc_measurement_condition },
+ { "icc_viewing_condition", (getter) cms_profile_getattr_icc_viewing_condition },
+
+ { NULL }
+};
+
+
+static PyTypeObject CmsProfile_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "PIL._imagingcms.CmsProfile", /*tp_name */
+ sizeof(CmsProfileObject), 0,/*tp_basicsize, tp_itemsize */
+ /* methods */
+ (destructor) cms_profile_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ cms_profile_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ cms_profile_getsetters, /*tp_getset*/
+};
+
+static struct PyMethodDef cms_transform_methods[] = {
+ {"apply", (PyCFunction) cms_transform_apply, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject*
+cms_transform_getattr_inputMode(CmsTransformObject* self, void* closure)
+{
+ return PyUnicode_FromString(self->mode_in);
+}
+
+static PyObject*
+cms_transform_getattr_outputMode(CmsTransformObject* self, void* closure)
+{
+ return PyUnicode_FromString(self->mode_out);
+}
+
+static struct PyGetSetDef cms_transform_getsetters[] = {
+ { "inputMode", (getter) cms_transform_getattr_inputMode },
+ { "outputMode", (getter) cms_transform_getattr_outputMode },
+ { NULL }
+};
+
+static PyTypeObject CmsTransform_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "CmsTransform", sizeof(CmsTransformObject), 0,
+ /* methods */
+ (destructor) cms_transform_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ cms_transform_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ cms_transform_getsetters, /*tp_getset*/
+};
+
+static int
+setup_module(PyObject* m) {
+ PyObject *d;
+ PyObject *v;
+
+ d = PyModule_GetDict(m);
+
+ CmsProfile_Type.tp_new = PyType_GenericNew;
+
+ /* Ready object types */
+ PyType_Ready(&CmsProfile_Type);
+ PyType_Ready(&CmsTransform_Type);
+
+ Py_INCREF(&CmsProfile_Type);
+ PyModule_AddObject(m, "CmsProfile", (PyObject *)&CmsProfile_Type);
+
+ d = PyModule_GetDict(m);
+
+ v = PyUnicode_FromFormat("%d.%d", LCMS_VERSION / 100, LCMS_VERSION % 100);
+ PyDict_SetItemString(d, "littlecms_version", v);
+
+ return 0;
+}
+
+#if PY_VERSION_HEX >= 0x03000000
+PyMODINIT_FUNC
+PyInit__imagingcms(void) {
+ PyObject* m;
+
+ static PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ "_imagingcms", /* m_name */
+ NULL, /* m_doc */
+ -1, /* m_size */
+ pyCMSdll_methods, /* m_methods */
+ };
+
+ m = PyModule_Create(&module_def);
+
+ if (setup_module(m) < 0)
+ return NULL;
+
+ PyDateTime_IMPORT;
+
+ return m;
+}
+#else
+PyMODINIT_FUNC
+init_imagingcms(void)
+{
+ PyObject *m = Py_InitModule("_imagingcms", pyCMSdll_methods);
+ setup_module(m);
+ PyDateTime_IMPORT;
+}
+#endif
diff --git a/contrib/python/Pillow/py2/_imagingft.c b/contrib/python/Pillow/py2/_imagingft.c
new file mode 100644
index 0000000000..7776e43f1b
--- /dev/null
+++ b/contrib/python/Pillow/py2/_imagingft.c
@@ -0,0 +1,1317 @@
+/*
+ * PIL FreeType Driver
+ *
+ * a FreeType 2.X driver for PIL
+ *
+ * history:
+ * 2001-02-17 fl Created (based on old experimental freetype 1.0 code)
+ * 2001-04-18 fl Fixed some egcs compiler nits
+ * 2002-11-08 fl Added unicode support; more font metrics, etc
+ * 2003-05-20 fl Fixed compilation under 1.5.2 and newer non-unicode builds
+ * 2003-09-27 fl Added charmap encoding support
+ * 2004-05-15 fl Fixed compilation for FreeType 2.1.8
+ * 2004-09-10 fl Added support for monochrome bitmaps
+ * 2006-06-18 fl Fixed glyph bearing calculation
+ * 2007-12-23 fl Fixed crash in family/style attribute fetch
+ * 2008-01-02 fl Handle Unicode filenames properly
+ *
+ * Copyright (c) 1998-2007 by Secret Labs AB
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h"
+#include "Imaging.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_STROKER_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_SFNT_NAMES_H
+
+#define KEEP_PY_UNICODE
+#include "py3.h"
+
+#if !defined(_MSC_VER)
+#include <dlfcn.h>
+#endif
+
+#if !defined(FT_LOAD_TARGET_MONO)
+#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
+#endif
+
+/* -------------------------------------------------------------------- */
+/* error table */
+
+#undef FTERRORS_H
+#undef __FTERRORS_H__
+
+#define FT_ERRORDEF( e, v, s ) { e, s },
+#define FT_ERROR_START_LIST {
+#define FT_ERROR_END_LIST { 0, 0 } };
+
+#include <raqm.h>
+
+#define LAYOUT_FALLBACK 0
+#define LAYOUT_RAQM 1
+
+typedef struct
+{
+ int index, x_offset, x_advance, y_offset, y_advance;
+ unsigned int cluster;
+} GlyphInfo;
+
+struct {
+ int code;
+ const char* message;
+} ft_errors[] =
+
+#include FT_ERRORS_H
+
+/* -------------------------------------------------------------------- */
+/* font objects */
+
+static FT_Library library;
+
+typedef struct {
+ PyObject_HEAD
+ FT_Face face;
+ unsigned char *font_bytes;
+ int layout_engine;
+} FontObject;
+
+static PyTypeObject Font_Type;
+
+typedef bool (*t_raqm_version_atleast)(unsigned int major,
+ unsigned int minor,
+ unsigned int micro);
+typedef raqm_t* (*t_raqm_create)(void);
+typedef int (*t_raqm_set_text)(raqm_t *rq,
+ const uint32_t *text,
+ size_t len);
+typedef bool (*t_raqm_set_text_utf8) (raqm_t *rq,
+ const char *text,
+ size_t len);
+typedef bool (*t_raqm_set_par_direction) (raqm_t *rq,
+ raqm_direction_t dir);
+typedef bool (*t_raqm_set_language) (raqm_t *rq,
+ const char *lang,
+ size_t start,
+ size_t len);
+typedef bool (*t_raqm_add_font_feature) (raqm_t *rq,
+ const char *feature,
+ int len);
+typedef bool (*t_raqm_set_freetype_face) (raqm_t *rq,
+ FT_Face face);
+typedef bool (*t_raqm_layout) (raqm_t *rq);
+typedef raqm_glyph_t* (*t_raqm_get_glyphs) (raqm_t *rq,
+ size_t *length);
+typedef raqm_glyph_t_01* (*t_raqm_get_glyphs_01) (raqm_t *rq,
+ size_t *length);
+typedef void (*t_raqm_destroy) (raqm_t *rq);
+
+typedef struct {
+ void* raqm;
+ int version;
+ t_raqm_version_atleast version_atleast;
+ t_raqm_create create;
+ t_raqm_set_text set_text;
+ t_raqm_set_text_utf8 set_text_utf8;
+ t_raqm_set_par_direction set_par_direction;
+ t_raqm_set_language set_language;
+ t_raqm_add_font_feature add_font_feature;
+ t_raqm_set_freetype_face set_freetype_face;
+ t_raqm_layout layout;
+ t_raqm_get_glyphs get_glyphs;
+ t_raqm_get_glyphs_01 get_glyphs_01;
+ t_raqm_destroy destroy;
+} p_raqm_func;
+
+static p_raqm_func p_raqm;
+
+
+/* round a 26.6 pixel coordinate to the nearest larger integer */
+#define PIXEL(x) ((((x)+63) & -64)>>6)
+
+static PyObject*
+geterror(int code)
+{
+ int i;
+
+ for (i = 0; ft_errors[i].message; i++)
+ if (ft_errors[i].code == code) {
+ PyErr_SetString(PyExc_IOError, ft_errors[i].message);
+ return NULL;
+ }
+
+ PyErr_SetString(PyExc_IOError, "unknown freetype error");
+ return NULL;
+}
+
+static int
+setraqm(void)
+{
+ /* set the static function pointers for dynamic raqm linking */
+ p_raqm.raqm = NULL;
+
+ /* Microsoft needs a totally different system */
+#if !defined(_MSC_VER)
+ p_raqm.raqm = dlopen("libraqm.so.0", RTLD_LAZY);
+ if (!p_raqm.raqm) {
+ p_raqm.raqm = dlopen("libraqm.dylib", RTLD_LAZY);
+ }
+#else
+ p_raqm.raqm = LoadLibrary("libraqm");
+#endif
+
+ if (!p_raqm.raqm) {
+ return 1;
+ }
+
+#if !defined(_MSC_VER)
+ p_raqm.version_atleast = (t_raqm_version_atleast)dlsym(p_raqm.raqm, "raqm_version_atleast");
+ p_raqm.create = (t_raqm_create)dlsym(p_raqm.raqm, "raqm_create");
+ p_raqm.set_text = (t_raqm_set_text)dlsym(p_raqm.raqm, "raqm_set_text");
+ p_raqm.set_text_utf8 = (t_raqm_set_text_utf8)dlsym(p_raqm.raqm, "raqm_set_text_utf8");
+ p_raqm.set_par_direction = (t_raqm_set_par_direction)dlsym(p_raqm.raqm, "raqm_set_par_direction");
+ p_raqm.set_language = (t_raqm_set_language)dlsym(p_raqm.raqm, "raqm_set_language");
+ p_raqm.add_font_feature = (t_raqm_add_font_feature)dlsym(p_raqm.raqm, "raqm_add_font_feature");
+ p_raqm.set_freetype_face = (t_raqm_set_freetype_face)dlsym(p_raqm.raqm, "raqm_set_freetype_face");
+ p_raqm.layout = (t_raqm_layout)dlsym(p_raqm.raqm, "raqm_layout");
+ p_raqm.destroy = (t_raqm_destroy)dlsym(p_raqm.raqm, "raqm_destroy");
+ if(dlsym(p_raqm.raqm, "raqm_index_to_position")) {
+ p_raqm.get_glyphs = (t_raqm_get_glyphs)dlsym(p_raqm.raqm, "raqm_get_glyphs");
+ p_raqm.version = 2;
+ } else {
+ p_raqm.version = 1;
+ p_raqm.get_glyphs_01 = (t_raqm_get_glyphs_01)dlsym(p_raqm.raqm, "raqm_get_glyphs");
+ }
+ if (dlerror() ||
+ !(p_raqm.create &&
+ p_raqm.set_text &&
+ p_raqm.set_text_utf8 &&
+ p_raqm.set_par_direction &&
+ p_raqm.set_language &&
+ p_raqm.add_font_feature &&
+ p_raqm.set_freetype_face &&
+ p_raqm.layout &&
+ (p_raqm.get_glyphs || p_raqm.get_glyphs_01) &&
+ p_raqm.destroy)) {
+ dlclose(p_raqm.raqm);
+ p_raqm.raqm = NULL;
+ return 2;
+ }
+#else
+ p_raqm.version_atleast = (t_raqm_version_atleast)GetProcAddress(p_raqm.raqm, "raqm_version_atleast");
+ p_raqm.create = (t_raqm_create)GetProcAddress(p_raqm.raqm, "raqm_create");
+ p_raqm.set_text = (t_raqm_set_text)GetProcAddress(p_raqm.raqm, "raqm_set_text");
+ p_raqm.set_text_utf8 = (t_raqm_set_text_utf8)GetProcAddress(p_raqm.raqm, "raqm_set_text_utf8");
+ p_raqm.set_par_direction = (t_raqm_set_par_direction)GetProcAddress(p_raqm.raqm, "raqm_set_par_direction");
+ p_raqm.set_language = (t_raqm_set_language)GetProcAddress(p_raqm.raqm, "raqm_set_language");
+ p_raqm.add_font_feature = (t_raqm_add_font_feature)GetProcAddress(p_raqm.raqm, "raqm_add_font_feature");
+ p_raqm.set_freetype_face = (t_raqm_set_freetype_face)GetProcAddress(p_raqm.raqm, "raqm_set_freetype_face");
+ p_raqm.layout = (t_raqm_layout)GetProcAddress(p_raqm.raqm, "raqm_layout");
+ p_raqm.destroy = (t_raqm_destroy)GetProcAddress(p_raqm.raqm, "raqm_destroy");
+ if(GetProcAddress(p_raqm.raqm, "raqm_index_to_position")) {
+ p_raqm.get_glyphs = (t_raqm_get_glyphs)GetProcAddress(p_raqm.raqm, "raqm_get_glyphs");
+ p_raqm.version = 2;
+ } else {
+ p_raqm.version = 1;
+ p_raqm.get_glyphs_01 = (t_raqm_get_glyphs_01)GetProcAddress(p_raqm.raqm, "raqm_get_glyphs");
+ }
+ if (!(p_raqm.create &&
+ p_raqm.set_text &&
+ p_raqm.set_text_utf8 &&
+ p_raqm.set_par_direction &&
+ p_raqm.set_language &&
+ p_raqm.add_font_feature &&
+ p_raqm.set_freetype_face &&
+ p_raqm.layout &&
+ (p_raqm.get_glyphs || p_raqm.get_glyphs_01) &&
+ p_raqm.destroy)) {
+ FreeLibrary(p_raqm.raqm);
+ p_raqm.raqm = NULL;
+ return 2;
+ }
+#endif
+
+ return 0;
+}
+
+static PyObject*
+getfont(PyObject* self_, PyObject* args, PyObject* kw)
+{
+ /* create a font object from a file name and a size (in pixels) */
+
+ FontObject* self;
+ int error = 0;
+
+ char* filename = NULL;
+ Py_ssize_t size;
+ Py_ssize_t index = 0;
+ Py_ssize_t layout_engine = 0;
+ unsigned char* encoding;
+ unsigned char* font_bytes;
+ Py_ssize_t font_bytes_size = 0;
+ static char* kwlist[] = {
+ "filename", "size", "index", "encoding", "font_bytes",
+ "layout_engine", NULL
+ };
+
+ if (!library) {
+ PyErr_SetString(
+ PyExc_IOError,
+ "failed to initialize FreeType library"
+ );
+ return NULL;
+ }
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "etn|ns"PY_ARG_BYTES_LENGTH"n",
+ kwlist,
+ Py_FileSystemDefaultEncoding, &filename,
+ &size, &index, &encoding, &font_bytes,
+ &font_bytes_size, &layout_engine)) {
+ return NULL;
+ }
+
+ self = PyObject_New(FontObject, &Font_Type);
+ if (!self) {
+ if (filename)
+ PyMem_Free(filename);
+ return NULL;
+ }
+
+ self->face = NULL;
+ self->layout_engine = layout_engine;
+
+ if (filename && font_bytes_size <= 0) {
+ self->font_bytes = NULL;
+ error = FT_New_Face(library, filename, index, &self->face);
+ } else {
+ /* need to have allocated storage for font_bytes for the life of the object.*/
+ /* Don't free this before FT_Done_Face */
+ self->font_bytes = PyMem_Malloc(font_bytes_size);
+ if (!self->font_bytes) {
+ error = 65; // Out of Memory in Freetype.
+ }
+ if (!error) {
+ memcpy(self->font_bytes, font_bytes, (size_t)font_bytes_size);
+ error = FT_New_Memory_Face(library, (FT_Byte*)self->font_bytes,
+ font_bytes_size, index, &self->face);
+ }
+ }
+
+ if (!error)
+ error = FT_Set_Pixel_Sizes(self->face, 0, size);
+
+ if (!error && encoding && strlen((char*) encoding) == 4) {
+ FT_Encoding encoding_tag = FT_MAKE_TAG(
+ encoding[0], encoding[1], encoding[2], encoding[3]
+ );
+ error = FT_Select_Charmap(self->face, encoding_tag);
+ }
+ if (filename)
+ PyMem_Free(filename);
+
+ if (error) {
+ if (self->font_bytes) {
+ PyMem_Free(self->font_bytes);
+ self->font_bytes = NULL;
+ }
+ Py_DECREF(self);
+ return geterror(error);
+ }
+
+ return (PyObject*) self;
+}
+
+static int
+font_getchar(PyObject* string, int index, FT_ULong* char_out)
+{
+#if (PY_VERSION_HEX < 0x03030000) || (defined(PYPY_VERSION_NUM))
+ if (PyUnicode_Check(string)) {
+ Py_UNICODE* p = PyUnicode_AS_UNICODE(string);
+ int size = PyUnicode_GET_SIZE(string);
+ if (index >= size)
+ return 0;
+ *char_out = p[index];
+ return 1;
+ }
+#if PY_VERSION_HEX < 0x03000000
+ if (PyString_Check(string)) {
+ unsigned char* p = (unsigned char*) PyString_AS_STRING(string);
+ int size = PyString_GET_SIZE(string);
+ if (index >= size)
+ return 0;
+ *char_out = (unsigned char) p[index];
+ return 1;
+ }
+#endif
+#else
+ if (PyUnicode_Check(string)) {
+ if (index >= PyUnicode_GET_LENGTH(string))
+ return 0;
+ *char_out = PyUnicode_READ_CHAR(string, index);
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+static size_t
+text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *features,
+ const char* lang, GlyphInfo **glyph_info, int mask)
+{
+ size_t i = 0, count = 0, start = 0;
+ raqm_t *rq;
+ raqm_glyph_t *glyphs = NULL;
+ raqm_glyph_t_01 *glyphs_01 = NULL;
+ raqm_direction_t direction;
+
+ rq = (*p_raqm.create)();
+ if (rq == NULL) {
+ PyErr_SetString(PyExc_ValueError, "raqm_create() failed.");
+ goto failed;
+ }
+
+#if (PY_VERSION_HEX < 0x03030000) || (defined(PYPY_VERSION_NUM))
+ if (PyUnicode_Check(string)) {
+ Py_UNICODE *text = PyUnicode_AS_UNICODE(string);
+ Py_ssize_t size = PyUnicode_GET_SIZE(string);
+ if (! size) {
+ /* return 0 and clean up, no glyphs==no size,
+ and raqm fails with empty strings */
+ goto failed;
+ }
+ if (!(*p_raqm.set_text)(rq, (const uint32_t *)(text), size)) {
+ PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed");
+ goto failed;
+ }
+ if (lang) {
+ if (!(*p_raqm.set_language)(rq, lang, start, size)) {
+ PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed");
+ goto failed;
+ }
+ }
+ }
+#if PY_VERSION_HEX < 0x03000000
+ else if (PyString_Check(string)) {
+ char *text = PyString_AS_STRING(string);
+ int size = PyString_GET_SIZE(string);
+ if (! size) {
+ goto failed;
+ }
+ if (!(*p_raqm.set_text_utf8)(rq, text, size)) {
+ PyErr_SetString(PyExc_ValueError, "raqm_set_text_utf8() failed");
+ goto failed;
+ }
+ if (lang) {
+ if (!(*p_raqm.set_language)(rq, lang, start, size)) {
+ PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed");
+ goto failed;
+ }
+ }
+ }
+#endif
+#else
+ if (PyUnicode_Check(string)) {
+ Py_UCS4 *text = PyUnicode_AsUCS4Copy(string);
+ Py_ssize_t size = PyUnicode_GET_LENGTH(string);
+ if (!text || !size) {
+ /* return 0 and clean up, no glyphs==no size,
+ and raqm fails with empty strings */
+ goto failed;
+ }
+ int set_text = (*p_raqm.set_text)(rq, (const uint32_t *)(text), size);
+ PyMem_Free(text);
+ if (!set_text) {
+ PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed");
+ goto failed;
+ }
+ if (lang) {
+ if (!(*p_raqm.set_language)(rq, lang, start, size)) {
+ PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed");
+ goto failed;
+ }
+ }
+ }
+#endif
+ else {
+ PyErr_SetString(PyExc_TypeError, "expected string");
+ goto failed;
+ }
+
+ direction = RAQM_DIRECTION_DEFAULT;
+ if (dir) {
+ if (strcmp(dir, "rtl") == 0)
+ direction = RAQM_DIRECTION_RTL;
+ else if (strcmp(dir, "ltr") == 0)
+ direction = RAQM_DIRECTION_LTR;
+ else if (strcmp(dir, "ttb") == 0) {
+ direction = RAQM_DIRECTION_TTB;
+ if (p_raqm.version_atleast == NULL || !(*p_raqm.version_atleast)(0, 7, 0)) {
+ PyErr_SetString(PyExc_ValueError, "libraqm 0.7 or greater required for 'ttb' direction");
+ goto failed;
+ }
+ } else {
+ PyErr_SetString(PyExc_ValueError, "direction must be either 'rtl', 'ltr' or 'ttb'");
+ goto failed;
+ }
+ }
+
+ if (!(*p_raqm.set_par_direction)(rq, direction)) {
+ PyErr_SetString(PyExc_ValueError, "raqm_set_par_direction() failed");
+ goto failed;
+ }
+
+ if (features != Py_None) {
+ int j, len;
+ PyObject *seq = PySequence_Fast(features, "expected a sequence");
+ if (!seq) {
+ goto failed;
+ }
+
+ len = PySequence_Size(seq);
+ for (j = 0; j < len; j++) {
+ PyObject *item = PySequence_Fast_GET_ITEM(seq, j);
+ char *feature = NULL;
+ Py_ssize_t size = 0;
+ PyObject *bytes;
+
+#if PY_VERSION_HEX >= 0x03000000
+ if (!PyUnicode_Check(item)) {
+#else
+ if (!PyUnicode_Check(item) && !PyString_Check(item)) {
+#endif
+ PyErr_SetString(PyExc_TypeError, "expected a string");
+ goto failed;
+ }
+
+ if (PyUnicode_Check(item)) {
+ bytes = PyUnicode_AsUTF8String(item);
+ if (bytes == NULL)
+ goto failed;
+ feature = PyBytes_AS_STRING(bytes);
+ size = PyBytes_GET_SIZE(bytes);
+ }
+#if PY_VERSION_HEX < 0x03000000
+ else {
+ feature = PyString_AsString(item);
+ size = PyString_GET_SIZE(item);
+ }
+#endif
+ if (!(*p_raqm.add_font_feature)(rq, feature, size)) {
+ PyErr_SetString(PyExc_ValueError, "raqm_add_font_feature() failed");
+ goto failed;
+ }
+ }
+ }
+
+ if (!(*p_raqm.set_freetype_face)(rq, self->face)) {
+ PyErr_SetString(PyExc_RuntimeError, "raqm_set_freetype_face() failed.");
+ goto failed;
+ }
+
+ if (!(*p_raqm.layout)(rq)) {
+ PyErr_SetString(PyExc_RuntimeError, "raqm_layout() failed.");
+ goto failed;
+ }
+
+ if (p_raqm.version == 1) {
+ glyphs_01 = (*p_raqm.get_glyphs_01)(rq, &count);
+ if (glyphs_01 == NULL) {
+ PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed.");
+ count = 0;
+ goto failed;
+ }
+ } else { /* version == 2 */
+ glyphs = (*p_raqm.get_glyphs)(rq, &count);
+ if (glyphs == NULL) {
+ PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed.");
+ count = 0;
+ goto failed;
+ }
+ }
+
+ (*glyph_info) = PyMem_New(GlyphInfo, count);
+ if ((*glyph_info) == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "PyMem_New() failed");
+ count = 0;
+ goto failed;
+ }
+
+ if (p_raqm.version == 1) {
+ for (i = 0; i < count; i++) {
+ (*glyph_info)[i].index = glyphs_01[i].index;
+ (*glyph_info)[i].x_offset = glyphs_01[i].x_offset;
+ (*glyph_info)[i].x_advance = glyphs_01[i].x_advance;
+ (*glyph_info)[i].y_offset = glyphs_01[i].y_offset;
+ (*glyph_info)[i].y_advance = glyphs_01[i].y_advance;
+ (*glyph_info)[i].cluster = glyphs_01[i].cluster;
+ }
+ } else {
+ for (i = 0; i < count; i++) {
+ (*glyph_info)[i].index = glyphs[i].index;
+ (*glyph_info)[i].x_offset = glyphs[i].x_offset;
+ (*glyph_info)[i].x_advance = glyphs[i].x_advance;
+ (*glyph_info)[i].y_offset = glyphs[i].y_offset;
+ (*glyph_info)[i].y_advance = glyphs[i].y_advance;
+ (*glyph_info)[i].cluster = glyphs[i].cluster;
+ }
+ }
+
+failed:
+ (*p_raqm.destroy)(rq);
+ return count;
+}
+
+static size_t
+text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObject *features,
+ const char* lang, GlyphInfo **glyph_info, int mask)
+{
+ int error, load_flags;
+ FT_ULong ch;
+ Py_ssize_t count;
+ FT_GlyphSlot glyph;
+ FT_Bool kerning = FT_HAS_KERNING(self->face);
+ FT_UInt last_index = 0;
+ int i;
+
+ if (features != Py_None || dir != NULL || lang != NULL) {
+ PyErr_SetString(PyExc_KeyError, "setting text direction, language or font features is not supported without libraqm");
+ }
+#if PY_VERSION_HEX >= 0x03000000
+ if (!PyUnicode_Check(string)) {
+#else
+ if (!PyUnicode_Check(string) && !PyString_Check(string)) {
+#endif
+ PyErr_SetString(PyExc_TypeError, "expected string");
+ return 0;
+ }
+
+ count = 0;
+ while (font_getchar(string, count, &ch)) {
+ count++;
+ }
+ if (count == 0) {
+ return 0;
+ }
+
+ (*glyph_info) = PyMem_New(GlyphInfo, count);
+ if ((*glyph_info) == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "PyMem_New() failed");
+ return 0;
+ }
+
+ load_flags = FT_LOAD_RENDER|FT_LOAD_NO_BITMAP;
+ if (mask) {
+ load_flags |= FT_LOAD_TARGET_MONO;
+ }
+ for (i = 0; font_getchar(string, i, &ch); i++) {
+ (*glyph_info)[i].index = FT_Get_Char_Index(self->face, ch);
+ error = FT_Load_Glyph(self->face, (*glyph_info)[i].index, load_flags);
+ if (error) {
+ geterror(error);
+ return 0;
+ }
+ glyph = self->face->glyph;
+ (*glyph_info)[i].x_offset=0;
+ (*glyph_info)[i].y_offset=0;
+ if (kerning && last_index && (*glyph_info)[i].index) {
+ FT_Vector delta;
+ if (FT_Get_Kerning(self->face, last_index, (*glyph_info)[i].index,
+ ft_kerning_default,&delta) == 0)
+ (*glyph_info)[i-1].x_advance += PIXEL(delta.x);
+ (*glyph_info)[i-1].y_advance += PIXEL(delta.y);
+ }
+
+ (*glyph_info)[i].x_advance = glyph->metrics.horiAdvance;
+ (*glyph_info)[i].y_advance = glyph->metrics.vertAdvance;
+ last_index = (*glyph_info)[i].index;
+ (*glyph_info)[i].cluster = ch;
+ }
+ return count;
+}
+
+static size_t
+text_layout(PyObject* string, FontObject* self, const char* dir, PyObject *features,
+ const char* lang, GlyphInfo **glyph_info, int mask)
+{
+ size_t count;
+
+ if (p_raqm.raqm && self->layout_engine == LAYOUT_RAQM) {
+ count = text_layout_raqm(string, self, dir, features, lang, glyph_info, mask);
+ } else {
+ count = text_layout_fallback(string, self, dir, features, lang, glyph_info, mask);
+ }
+ return count;
+}
+
+static PyObject*
+font_getsize(FontObject* self, PyObject* args)
+{
+ int x_position, x_max, x_min, y_max, y_min;
+ FT_Face face;
+ int xoffset, yoffset;
+ int horizontal_dir;
+ const char *dir = NULL;
+ const char *lang = NULL;
+ size_t i, count;
+ GlyphInfo *glyph_info = NULL;
+ PyObject *features = Py_None;
+
+ /* calculate size and bearing for a given string */
+
+ PyObject* string;
+ if (!PyArg_ParseTuple(args, "O|zOz:getsize", &string, &dir, &features, &lang))
+ return NULL;
+
+ count = text_layout(string, self, dir, features, lang, &glyph_info, 0);
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+
+ face = NULL;
+ xoffset = yoffset = 0;
+ x_position = x_max = x_min = y_max = y_min = 0;
+
+ horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
+ for (i = 0; i < count; i++) {
+ int index, error, offset, x_advanced;
+ FT_BBox bbox;
+ FT_Glyph glyph;
+ face = self->face;
+ index = glyph_info[i].index;
+ /* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960
+ * Yifu Yu<root@jackyyf.com>, 2014-10-15
+ */
+ error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP);
+ if (error)
+ return geterror(error);
+
+ if (i == 0) {
+ if (horizontal_dir) {
+ if (face->glyph->metrics.horiBearingX < 0) {
+ xoffset = face->glyph->metrics.horiBearingX;
+ x_position -= xoffset;
+ }
+ } else {
+ if (face->glyph->metrics.vertBearingY < 0) {
+ yoffset = face->glyph->metrics.vertBearingY;
+ y_max -= yoffset;
+ }
+ }
+ }
+
+ FT_Get_Glyph(face->glyph, &glyph);
+ FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_SUBPIXELS, &bbox);
+ if (horizontal_dir) {
+ x_position += glyph_info[i].x_advance;
+
+ x_advanced = x_position;
+ offset = glyph_info[i].x_advance -
+ face->glyph->metrics.width -
+ face->glyph->metrics.horiBearingX;
+ if (offset < 0)
+ x_advanced -= offset;
+ if (x_advanced > x_max)
+ x_max = x_advanced;
+
+ bbox.yMax += glyph_info[i].y_offset;
+ bbox.yMin += glyph_info[i].y_offset;
+ if (bbox.yMax > y_max)
+ y_max = bbox.yMax;
+ if (bbox.yMin < y_min)
+ y_min = bbox.yMin;
+
+ // find max distance of baseline from top
+ if (face->glyph->metrics.horiBearingY > yoffset)
+ yoffset = face->glyph->metrics.horiBearingY;
+ } else {
+ y_max -= glyph_info[i].y_advance;
+
+ if (i == count - 1) {
+ // trim end gap from final glyph
+ int offset;
+ offset = -glyph_info[i].y_advance -
+ face->glyph->metrics.height -
+ face->glyph->metrics.vertBearingY;
+ if (offset < 0)
+ y_max -= offset;
+ }
+
+ if (bbox.xMax > x_max)
+ x_max = bbox.xMax;
+ if (i == 0 || bbox.xMin < x_min)
+ x_min = bbox.xMin;
+ }
+
+ FT_Done_Glyph(glyph);
+ }
+
+ if (glyph_info) {
+ PyMem_Free(glyph_info);
+ glyph_info = NULL;
+ }
+
+ if (face) {
+ if (horizontal_dir) {
+ // left bearing
+ if (xoffset < 0)
+ x_max -= xoffset;
+ else
+ xoffset = 0;
+
+ /* difference between the font ascender and the distance of
+ * the baseline from the top */
+ yoffset = PIXEL(self->face->size->metrics.ascender - yoffset);
+ } else {
+ // top bearing
+ if (yoffset < 0)
+ y_max -= yoffset;
+ else
+ yoffset = 0;
+ }
+ }
+
+ return Py_BuildValue(
+ "(ii)(ii)",
+ PIXEL(x_max - x_min), PIXEL(y_max - y_min),
+ PIXEL(xoffset), yoffset
+ );
+}
+
+static PyObject*
+font_render(FontObject* self, PyObject* args)
+{
+ int x;
+ unsigned int y;
+ Imaging im;
+ int index, error, ascender, horizontal_dir;
+ int load_flags;
+ unsigned char *source;
+ FT_Glyph glyph;
+ FT_GlyphSlot glyph_slot;
+ FT_Bitmap bitmap;
+ FT_BitmapGlyph bitmap_glyph;
+ int stroke_width = 0;
+ FT_Stroker stroker = NULL;
+ FT_Int left;
+ /* render string into given buffer (the buffer *must* have
+ the right size, or this will crash) */
+ PyObject* string;
+ Py_ssize_t id;
+ int mask = 0;
+ int temp;
+ int xx, x0, x1;
+ int yy;
+ unsigned int bitmap_y;
+ const char *dir = NULL;
+ const char *lang = NULL;
+ size_t i, count;
+ GlyphInfo *glyph_info;
+ PyObject *features = NULL;
+
+ if (!PyArg_ParseTuple(args, "On|izOzi:render", &string, &id, &mask, &dir, &features, &lang,
+ &stroke_width)) {
+ return NULL;
+ }
+
+ glyph_info = NULL;
+ count = text_layout(string, self, dir, features, lang, &glyph_info, mask);
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ if (count == 0) {
+ Py_RETURN_NONE;
+ }
+
+ if (stroke_width) {
+ error = FT_Stroker_New(library, &stroker);
+ if (error) {
+ return geterror(error);
+ }
+
+ FT_Stroker_Set(stroker, (FT_Fixed)stroke_width*64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
+ }
+
+ im = (Imaging) id;
+ /* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
+ load_flags = FT_LOAD_NO_BITMAP;
+ if (stroker == NULL) {
+ load_flags |= FT_LOAD_RENDER;
+ }
+ if (mask) {
+ load_flags |= FT_LOAD_TARGET_MONO;
+ }
+
+ ascender = 0;
+ for (i = 0; i < count; i++) {
+ index = glyph_info[i].index;
+ error = FT_Load_Glyph(self->face, index, load_flags);
+ if (error) {
+ return geterror(error);
+ }
+
+ glyph_slot = self->face->glyph;
+ bitmap = glyph_slot->bitmap;
+
+ temp = bitmap.rows - glyph_slot->bitmap_top;
+ temp -= PIXEL(glyph_info[i].y_offset);
+ if (temp > ascender)
+ ascender = temp;
+ }
+
+ x = y = 0;
+ horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
+ for (i = 0; i < count; i++) {
+ index = glyph_info[i].index;
+ error = FT_Load_Glyph(self->face, index, load_flags);
+ if (error) {
+ return geterror(error);
+ }
+
+ glyph_slot = self->face->glyph;
+ if (stroker != NULL) {
+ error = FT_Get_Glyph(glyph_slot, &glyph);
+ if (!error) {
+ error = FT_Glyph_Stroke(&glyph, stroker, 1);
+ }
+ if (!error) {
+ FT_Vector origin = {0, 0};
+ error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, &origin, 1);
+ }
+ if (error) {
+ return geterror(error);
+ }
+
+ bitmap_glyph = (FT_BitmapGlyph)glyph;
+
+ bitmap = bitmap_glyph->bitmap;
+ left = bitmap_glyph->left;
+
+ FT_Done_Glyph(glyph);
+ } else {
+ bitmap = glyph_slot->bitmap;
+ left = glyph_slot->bitmap_left;
+ }
+
+ if (horizontal_dir) {
+ if (i == 0 && glyph_slot->metrics.horiBearingX < 0) {
+ x = -glyph_slot->metrics.horiBearingX;
+ }
+ xx = PIXEL(x) + left;
+ xx += PIXEL(glyph_info[i].x_offset) + stroke_width;
+ } else {
+ if (glyph_slot->metrics.vertBearingX < 0) {
+ x = -glyph_slot->metrics.vertBearingX;
+ }
+ xx = im->xsize / 2 - bitmap.width / 2;
+ }
+
+ x0 = 0;
+ x1 = bitmap.width;
+ if (xx < 0)
+ x0 = -xx;
+ if (xx + x1 > im->xsize)
+ x1 = im->xsize - xx;
+
+ source = (unsigned char*) bitmap.buffer;
+ for (bitmap_y = 0; bitmap_y < bitmap.rows; bitmap_y++) {
+ if (horizontal_dir) {
+ yy = bitmap_y + im->ysize - (PIXEL(glyph_slot->metrics.horiBearingY) + ascender);
+ yy -= PIXEL(glyph_info[i].y_offset) + stroke_width * 2;
+ } else {
+ yy = bitmap_y + PIXEL(y + glyph_slot->metrics.vertBearingY) + ascender;
+ yy += PIXEL(glyph_info[i].y_offset);
+ }
+ if (yy >= 0 && yy < im->ysize) {
+ // blend this glyph into the buffer
+ unsigned char *target = im->image8[yy] + xx;
+ if (mask) {
+ // use monochrome mask (on palette images, etc)
+ int j, k, m = 128;
+ for (j = k = 0; j < x1; j++) {
+ if (j >= x0 && (source[k] & m))
+ target[j] = 255;
+ if (!(m >>= 1)) {
+ m = 128;
+ k++;
+ }
+ }
+ } else {
+ // use antialiased rendering
+ int k;
+ for (k = x0; k < x1; k++) {
+ if (target[k] < source[k])
+ target[k] = source[k];
+ }
+ }
+ }
+ source += bitmap.pitch;
+ }
+ x += glyph_info[i].x_advance;
+ y -= glyph_info[i].y_advance;
+ }
+
+ FT_Stroker_Done(stroker);
+ PyMem_Del(glyph_info);
+ Py_RETURN_NONE;
+}
+
+#if FREETYPE_MAJOR > 2 ||\
+ (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) ||\
+ (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 9 && FREETYPE_PATCH == 1)
+ static PyObject*
+ font_getvarnames(FontObject* self, PyObject* args)
+ {
+ int error;
+ FT_UInt i, j, num_namedstyles, name_count;
+ FT_MM_Var *master;
+ FT_SfntName name;
+ PyObject *list_names, *list_name;
+
+ error = FT_Get_MM_Var(self->face, &master);
+ if (error)
+ return geterror(error);
+
+ num_namedstyles = master->num_namedstyles;
+ list_names = PyList_New(num_namedstyles);
+
+ name_count = FT_Get_Sfnt_Name_Count(self->face);
+ for (i = 0; i < name_count; i++) {
+ error = FT_Get_Sfnt_Name(self->face, i, &name);
+ if (error)
+ return geterror(error);
+
+ for (j = 0; j < num_namedstyles; j++) {
+ if (PyList_GetItem(list_names, j) != NULL)
+ continue;
+
+ if (master->namedstyle[j].strid == name.name_id) {
+ list_name = Py_BuildValue(PY_ARG_BYTES_LENGTH,
+ name.string, name.string_len);
+ PyList_SetItem(list_names, j, list_name);
+ break;
+ }
+ }
+ }
+
+ FT_Done_MM_Var(library, master);
+
+ return list_names;
+ }
+
+ static PyObject*
+ font_getvaraxes(FontObject* self, PyObject* args)
+ {
+ int error;
+ FT_UInt i, j, num_axis, name_count;
+ FT_MM_Var* master;
+ FT_Var_Axis axis;
+ FT_SfntName name;
+ PyObject *list_axes, *list_axis, *axis_name;
+ error = FT_Get_MM_Var(self->face, &master);
+ if (error)
+ return geterror(error);
+
+ num_axis = master->num_axis;
+ name_count = FT_Get_Sfnt_Name_Count(self->face);
+
+ list_axes = PyList_New(num_axis);
+ for (i = 0; i < num_axis; i++) {
+ axis = master->axis[i];
+
+ list_axis = PyDict_New();
+ PyDict_SetItemString(list_axis, "minimum",
+ PyInt_FromLong(axis.minimum / 65536));
+ PyDict_SetItemString(list_axis, "default",
+ PyInt_FromLong(axis.def / 65536));
+ PyDict_SetItemString(list_axis, "maximum",
+ PyInt_FromLong(axis.maximum / 65536));
+
+ for (j = 0; j < name_count; j++) {
+ error = FT_Get_Sfnt_Name(self->face, j, &name);
+ if (error)
+ return geterror(error);
+
+ if (name.name_id == axis.strid) {
+ axis_name = Py_BuildValue(PY_ARG_BYTES_LENGTH,
+ name.string, name.string_len);
+ PyDict_SetItemString(list_axis, "name", axis_name);
+ break;
+ }
+ }
+
+ PyList_SetItem(list_axes, i, list_axis);
+ }
+
+ FT_Done_MM_Var(library, master);
+
+ return list_axes;
+ }
+
+ static PyObject*
+ font_setvarname(FontObject* self, PyObject* args)
+ {
+ int error;
+
+ int instance_index;
+ if (!PyArg_ParseTuple(args, "i", &instance_index))
+ return NULL;
+
+ error = FT_Set_Named_Instance(self->face, instance_index);
+ if (error)
+ return geterror(error);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ static PyObject*
+ font_setvaraxes(FontObject* self, PyObject* args)
+ {
+ int error;
+
+ PyObject *axes, *item;
+ Py_ssize_t i, num_coords;
+ FT_Fixed *coords;
+ FT_Fixed coord;
+ if (!PyArg_ParseTuple(args, "O", &axes))
+ return NULL;
+
+ if (!PyList_Check(axes)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a list");
+ return NULL;
+ }
+
+ num_coords = PyObject_Length(axes);
+ coords = malloc(2 * sizeof(coords));
+ if (coords == NULL) {
+ return PyErr_NoMemory();
+ }
+ for (i = 0; i < num_coords; i++) {
+ item = PyList_GET_ITEM(axes, i);
+ if (PyFloat_Check(item))
+ coord = PyFloat_AS_DOUBLE(item);
+ else if (PyInt_Check(item))
+ coord = (float) PyInt_AS_LONG(item);
+ else if (PyNumber_Check(item))
+ coord = PyFloat_AsDouble(item);
+ else {
+ free(coords);
+ PyErr_SetString(PyExc_TypeError, "list must contain numbers");
+ return NULL;
+ }
+ coords[i] = coord * 65536;
+ }
+
+ error = FT_Set_Var_Design_Coordinates(self->face, num_coords, coords);
+ free(coords);
+ if (error)
+ return geterror(error);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+#endif
+
+static void
+font_dealloc(FontObject* self)
+{
+ if (self->face) {
+ FT_Done_Face(self->face);
+ }
+ if (self->font_bytes) {
+ PyMem_Free(self->font_bytes);
+ }
+ PyObject_Del(self);
+}
+
+static PyMethodDef font_methods[] = {
+ {"render", (PyCFunction) font_render, METH_VARARGS},
+ {"getsize", (PyCFunction) font_getsize, METH_VARARGS},
+#if FREETYPE_MAJOR > 2 ||\
+ (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) ||\
+ (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 9 && FREETYPE_PATCH == 1)
+ {"getvarnames", (PyCFunction) font_getvarnames, METH_VARARGS },
+ {"getvaraxes", (PyCFunction) font_getvaraxes, METH_VARARGS },
+ {"setvarname", (PyCFunction) font_setvarname, METH_VARARGS},
+ {"setvaraxes", (PyCFunction) font_setvaraxes, METH_VARARGS},
+#endif
+ {NULL, NULL}
+};
+
+static PyObject*
+font_getattr_family(FontObject* self, void* closure)
+{
+#if PY_VERSION_HEX >= 0x03000000
+ if (self->face->family_name)
+ return PyUnicode_FromString(self->face->family_name);
+#else
+ if (self->face->family_name)
+ return PyString_FromString(self->face->family_name);
+#endif
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+font_getattr_style(FontObject* self, void* closure)
+{
+#if PY_VERSION_HEX >= 0x03000000
+ if (self->face->style_name)
+ return PyUnicode_FromString(self->face->style_name);
+#else
+ if (self->face->style_name)
+ return PyString_FromString(self->face->style_name);
+#endif
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+font_getattr_ascent(FontObject* self, void* closure)
+{
+ return PyInt_FromLong(PIXEL(self->face->size->metrics.ascender));
+}
+
+static PyObject*
+font_getattr_descent(FontObject* self, void* closure)
+{
+ return PyInt_FromLong(-PIXEL(self->face->size->metrics.descender));
+}
+
+static PyObject*
+font_getattr_height(FontObject* self, void* closure)
+{
+ return PyInt_FromLong(PIXEL(self->face->size->metrics.height));
+}
+
+static PyObject*
+font_getattr_x_ppem(FontObject* self, void* closure)
+{
+ return PyInt_FromLong(self->face->size->metrics.x_ppem);
+}
+
+static PyObject*
+font_getattr_y_ppem(FontObject* self, void* closure)
+{
+ return PyInt_FromLong(self->face->size->metrics.y_ppem);
+}
+
+
+static PyObject*
+font_getattr_glyphs(FontObject* self, void* closure)
+{
+ return PyInt_FromLong(self->face->num_glyphs);
+}
+
+static struct PyGetSetDef font_getsetters[] = {
+ { "family", (getter) font_getattr_family },
+ { "style", (getter) font_getattr_style },
+ { "ascent", (getter) font_getattr_ascent },
+ { "descent", (getter) font_getattr_descent },
+ { "height", (getter) font_getattr_height },
+ { "x_ppem", (getter) font_getattr_x_ppem },
+ { "y_ppem", (getter) font_getattr_y_ppem },
+ { "glyphs", (getter) font_getattr_glyphs },
+ { NULL }
+};
+
+static PyTypeObject Font_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Font", sizeof(FontObject), 0,
+ /* methods */
+ (destructor)font_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ font_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ font_getsetters, /*tp_getset*/
+};
+
+static PyMethodDef _functions[] = {
+ {"getfont", (PyCFunction) getfont, METH_VARARGS|METH_KEYWORDS},
+ {NULL, NULL}
+};
+
+static int
+setup_module(PyObject* m) {
+ PyObject* d;
+ PyObject* v;
+ int major, minor, patch;
+
+ d = PyModule_GetDict(m);
+
+ /* Ready object type */
+ PyType_Ready(&Font_Type);
+
+ if (FT_Init_FreeType(&library))
+ return 0; /* leave it uninitialized */
+
+ FT_Library_Version(library, &major, &minor, &patch);
+
+#if PY_VERSION_HEX >= 0x03000000
+ v = PyUnicode_FromFormat("%d.%d.%d", major, minor, patch);
+#else
+ v = PyString_FromFormat("%d.%d.%d", major, minor, patch);
+#endif
+ PyDict_SetItemString(d, "freetype2_version", v);
+
+
+ setraqm();
+ v = PyBool_FromLong(!!p_raqm.raqm);
+ PyDict_SetItemString(d, "HAVE_RAQM", v);
+
+ return 0;
+}
+
+#if PY_VERSION_HEX >= 0x03000000
+PyMODINIT_FUNC
+PyInit__imagingft(void) {
+ PyObject* m;
+
+ static PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ "_imagingft", /* m_name */
+ NULL, /* m_doc */
+ -1, /* m_size */
+ _functions, /* m_methods */
+ };
+
+ m = PyModule_Create(&module_def);
+
+ if (setup_module(m) < 0)
+ return NULL;
+
+ return m;
+}
+#else
+PyMODINIT_FUNC
+init_imagingft(void)
+{
+ PyObject* m = Py_InitModule("_imagingft", _functions);
+ setup_module(m);
+}
+#endif
+
diff --git a/contrib/python/Pillow/py2/_imagingmath.c b/contrib/python/Pillow/py2/_imagingmath.c
new file mode 100644
index 0000000000..ea9f103c68
--- /dev/null
+++ b/contrib/python/Pillow/py2/_imagingmath.c
@@ -0,0 +1,304 @@
+/*
+ * The Python Imaging Library
+ *
+ * a simple math add-on for the Python Imaging Library
+ *
+ * history:
+ * 1999-02-15 fl Created
+ * 2005-05-05 fl Simplified and cleaned up for PIL 1.1.6
+ *
+ * Copyright (c) 1999-2005 by Secret Labs AB
+ * Copyright (c) 2005 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Python.h"
+
+#include "Imaging.h"
+#include "py3.h"
+
+#include "math.h"
+#include "float.h"
+
+#define MAX_INT32 2147483647.0
+#define MIN_INT32 -2147483648.0
+
+#define UNOP(name, op, type)\
+void name(Imaging out, Imaging im1)\
+{\
+ int x, y;\
+ for (y = 0; y < out->ysize; y++) {\
+ type* p0 = (type*) out->image[y];\
+ type* p1 = (type*) im1->image[y];\
+ for (x = 0; x < out->xsize; x++) {\
+ *p0 = op(type, *p1);\
+ p0++; p1++;\
+ }\
+ }\
+}
+
+#define BINOP(name, op, type)\
+void name(Imaging out, Imaging im1, Imaging im2)\
+{\
+ int x, y;\
+ for (y = 0; y < out->ysize; y++) {\
+ type* p0 = (type*) out->image[y];\
+ type* p1 = (type*) im1->image[y];\
+ type* p2 = (type*) im2->image[y];\
+ for (x = 0; x < out->xsize; x++) {\
+ *p0 = op(type, *p1, *p2);\
+ p0++; p1++; p2++;\
+ }\
+ }\
+}
+
+#define NEG(type, v1) -(v1)
+#define INVERT(type, v1) ~(v1)
+
+#define ADD(type, v1, v2) (v1)+(v2)
+#define SUB(type, v1, v2) (v1)-(v2)
+#define MUL(type, v1, v2) (v1)*(v2)
+
+#define MIN(type, v1, v2) ((v1)<(v2))?(v1):(v2)
+#define MAX(type, v1, v2) ((v1)>(v2))?(v1):(v2)
+
+#define AND(type, v1, v2) (v1)&(v2)
+#define OR(type, v1, v2) (v1)|(v2)
+#define XOR(type, v1, v2) (v1)^(v2)
+#define LSHIFT(type, v1, v2) (v1)<<(v2)
+#define RSHIFT(type, v1, v2) (v1)>>(v2)
+
+#define ABS_I(type, v1) abs((v1))
+#define ABS_F(type, v1) fabs((v1))
+
+/* --------------------------------------------------------------------
+ * some day, we should add FPE protection mechanisms. see pyfpe.h for
+ * details.
+ *
+ * PyFPE_START_PROTECT("Error in foobar", return 0)
+ * PyFPE_END_PROTECT(result)
+ */
+
+#define DIV_I(type, v1, v2) ((v2)!=0)?(v1)/(v2):0
+#define DIV_F(type, v1, v2) ((v2)!=0.0F)?(v1)/(v2):0.0F
+
+#define MOD_I(type, v1, v2) ((v2)!=0)?(v1)%(v2):0
+#define MOD_F(type, v1, v2) ((v2)!=0.0F)?fmod((v1),(v2)):0.0F
+
+static int powi(int x, int y)
+{
+ double v = pow(x, y) + 0.5;
+ if (errno == EDOM)
+ return 0;
+ if (v < MIN_INT32)
+ v = MIN_INT32;
+ else if (v > MAX_INT32)
+ v = MAX_INT32;
+ return (int) v;
+}
+
+#define POW_I(type, v1, v2) powi(v1, v2)
+#define POW_F(type, v1, v2) powf(v1, v2) /* FIXME: EDOM handling */
+
+#define DIFF_I(type, v1, v2) abs((v1)-(v2))
+#define DIFF_F(type, v1, v2) fabs((v1)-(v2))
+
+#define EQ(type, v1, v2) (v1)==(v2)
+#define NE(type, v1, v2) (v1)!=(v2)
+#define LT(type, v1, v2) (v1)<(v2)
+#define LE(type, v1, v2) (v1)<=(v2)
+#define GT(type, v1, v2) (v1)>(v2)
+#define GE(type, v1, v2) (v1)>=(v2)
+
+UNOP(abs_I, ABS_I, INT32)
+UNOP(neg_I, NEG, INT32)
+
+BINOP(add_I, ADD, INT32)
+BINOP(sub_I, SUB, INT32)
+BINOP(mul_I, MUL, INT32)
+BINOP(div_I, DIV_I, INT32)
+BINOP(mod_I, MOD_I, INT32)
+BINOP(pow_I, POW_I, INT32)
+BINOP(diff_I, DIFF_I, INT32)
+
+UNOP(invert_I, INVERT, INT32)
+BINOP(and_I, AND, INT32)
+BINOP(or_I, OR, INT32)
+BINOP(xor_I, XOR, INT32)
+BINOP(lshift_I, LSHIFT, INT32)
+BINOP(rshift_I, RSHIFT, INT32)
+
+BINOP(min_I, MIN, INT32)
+BINOP(max_I, MAX, INT32)
+
+BINOP(eq_I, EQ, INT32)
+BINOP(ne_I, NE, INT32)
+BINOP(lt_I, LT, INT32)
+BINOP(le_I, LE, INT32)
+BINOP(gt_I, GT, INT32)
+BINOP(ge_I, GE, INT32)
+
+UNOP(abs_F, ABS_F, FLOAT32)
+UNOP(neg_F, NEG, FLOAT32)
+
+BINOP(add_F, ADD, FLOAT32)
+BINOP(sub_F, SUB, FLOAT32)
+BINOP(mul_F, MUL, FLOAT32)
+BINOP(div_F, DIV_F, FLOAT32)
+BINOP(mod_F, MOD_F, FLOAT32)
+BINOP(pow_F, POW_F, FLOAT32)
+BINOP(diff_F, DIFF_F, FLOAT32)
+
+BINOP(min_F, MIN, FLOAT32)
+BINOP(max_F, MAX, FLOAT32)
+
+BINOP(eq_F, EQ, FLOAT32)
+BINOP(ne_F, NE, FLOAT32)
+BINOP(lt_F, LT, FLOAT32)
+BINOP(le_F, LE, FLOAT32)
+BINOP(gt_F, GT, FLOAT32)
+BINOP(ge_F, GE, FLOAT32)
+
+static PyObject *
+_unop(PyObject* self, PyObject* args)
+{
+ Imaging out;
+ Imaging im1;
+ void (*unop)(Imaging, Imaging);
+
+ Py_ssize_t op, i0, i1;
+ if (!PyArg_ParseTuple(args, "nnn", &op, &i0, &i1))
+ return NULL;
+
+ out = (Imaging) i0;
+ im1 = (Imaging) i1;
+
+ unop = (void*) op;
+
+ unop(out, im1);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+_binop(PyObject* self, PyObject* args)
+{
+ Imaging out;
+ Imaging im1;
+ Imaging im2;
+ void (*binop)(Imaging, Imaging, Imaging);
+
+ Py_ssize_t op, i0, i1, i2;
+ if (!PyArg_ParseTuple(args, "nnnn", &op, &i0, &i1, &i2))
+ return NULL;
+
+ out = (Imaging) i0;
+ im1 = (Imaging) i1;
+ im2 = (Imaging) i2;
+
+ binop = (void*) op;
+
+ binop(out, im1, im2);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef _functions[] = {
+ {"unop", _unop, 1},
+ {"binop", _binop, 1},
+ {NULL, NULL}
+};
+
+static void
+install(PyObject *d, char* name, void* value)
+{
+ PyObject *v = PyInt_FromSsize_t((Py_ssize_t) value);
+ if (!v || PyDict_SetItemString(d, name, v))
+ PyErr_Clear();
+ Py_XDECREF(v);
+}
+
+static int
+setup_module(PyObject* m) {
+ PyObject* d = PyModule_GetDict(m);
+
+ install(d, "abs_I", abs_I);
+ install(d, "neg_I", neg_I);
+ install(d, "add_I", add_I);
+ install(d, "sub_I", sub_I);
+ install(d, "diff_I", diff_I);
+ install(d, "mul_I", mul_I);
+ install(d, "div_I", div_I);
+ install(d, "mod_I", mod_I);
+ install(d, "min_I", min_I);
+ install(d, "max_I", max_I);
+ install(d, "pow_I", pow_I);
+
+ install(d, "invert_I", invert_I);
+ install(d, "and_I", and_I);
+ install(d, "or_I", or_I);
+ install(d, "xor_I", xor_I);
+ install(d, "lshift_I", lshift_I);
+ install(d, "rshift_I", rshift_I);
+
+ install(d, "eq_I", eq_I);
+ install(d, "ne_I", ne_I);
+ install(d, "lt_I", lt_I);
+ install(d, "le_I", le_I);
+ install(d, "gt_I", gt_I);
+ install(d, "ge_I", ge_I);
+
+ install(d, "abs_F", abs_F);
+ install(d, "neg_F", neg_F);
+ install(d, "add_F", add_F);
+ install(d, "sub_F", sub_F);
+ install(d, "diff_F", diff_F);
+ install(d, "mul_F", mul_F);
+ install(d, "div_F", div_F);
+ install(d, "mod_F", mod_F);
+ install(d, "min_F", min_F);
+ install(d, "max_F", max_F);
+ install(d, "pow_F", pow_F);
+
+ install(d, "eq_F", eq_F);
+ install(d, "ne_F", ne_F);
+ install(d, "lt_F", lt_F);
+ install(d, "le_F", le_F);
+ install(d, "gt_F", gt_F);
+ install(d, "ge_F", ge_F);
+
+ return 0;
+}
+
+#if PY_VERSION_HEX >= 0x03000000
+PyMODINIT_FUNC
+PyInit__imagingmath(void) {
+ PyObject* m;
+
+ static PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ "_imagingmath", /* m_name */
+ NULL, /* m_doc */
+ -1, /* m_size */
+ _functions, /* m_methods */
+ };
+
+ m = PyModule_Create(&module_def);
+
+ if (setup_module(m) < 0)
+ return NULL;
+
+ return m;
+}
+#else
+PyMODINIT_FUNC
+init_imagingmath(void)
+{
+ PyObject* m = Py_InitModule("_imagingmath", _functions);
+ setup_module(m);
+}
+#endif
+
diff --git a/contrib/python/Pillow/py2/_imagingmorph.c b/contrib/python/Pillow/py2/_imagingmorph.c
new file mode 100644
index 0000000000..fc8f246cc8
--- /dev/null
+++ b/contrib/python/Pillow/py2/_imagingmorph.c
@@ -0,0 +1,304 @@
+/*
+ * The Python Imaging Library
+ *
+ * A binary morphology add-on for the Python Imaging Library
+ *
+ * History:
+ * 2014-06-04 Initial version.
+ *
+ * Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com>
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Python.h"
+#include "Imaging.h"
+#include "py3.h"
+
+#define LUT_SIZE (1<<9)
+
+/* Apply a morphologic LUT to a binary image. Outputs a
+ a new binary image.
+
+ Expected parameters:
+
+ 1. a LUT - a 512 byte size lookup table.
+ 2. an input Imaging image id.
+ 3. an output Imaging image id
+
+ Returns number of changed pixels.
+*/
+static PyObject*
+apply(PyObject *self, PyObject* args)
+{
+ const char *lut;
+ PyObject *py_lut;
+ Py_ssize_t lut_len, i0, i1;
+ Imaging imgin, imgout;
+ int width, height;
+ int row_idx, col_idx;
+ UINT8 **inrows, **outrows;
+ int num_changed_pixels = 0;
+
+ if (!PyArg_ParseTuple(args, "Onn", &py_lut, &i0, &i1)) {
+ PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
+ return NULL;
+ }
+
+ if (!PyBytes_Check(py_lut)) {
+ PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object");
+ return NULL;
+ }
+
+ lut_len = PyBytes_Size(py_lut);
+
+ if (lut_len < LUT_SIZE) {
+ PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size");
+ return NULL;
+ }
+
+ lut = PyBytes_AsString(py_lut);
+
+ imgin = (Imaging) i0;
+ imgout = (Imaging) i1;
+ width = imgin->xsize;
+ height = imgin->ysize;
+
+ if (imgin->type != IMAGING_TYPE_UINT8 ||
+ imgin->bands != 1) {
+ PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
+ return NULL;
+ }
+ if (imgout->type != IMAGING_TYPE_UINT8 ||
+ imgout->bands != 1) {
+ PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
+ return NULL;
+ }
+
+ inrows = imgin->image8;
+ outrows = imgout->image8;
+
+ for (row_idx=0; row_idx < height; row_idx++) {
+ UINT8 *outrow = outrows[row_idx];
+ UINT8 *inrow = inrows[row_idx];
+ UINT8 *prow, *nrow; /* Previous and next row */
+
+ /* zero boundary conditions. TBD support other modes */
+ outrow[0] = outrow[width-1] = 0;
+ if (row_idx==0 || row_idx == height-1) {
+ for(col_idx=0; col_idx<width; col_idx++)
+ outrow[col_idx] = 0;
+ continue;
+ }
+
+ prow = inrows[row_idx-1];
+ nrow = inrows[row_idx+1];
+
+ for (col_idx=1; col_idx<width-1; col_idx++) {
+ int cim = col_idx-1;
+ int cip = col_idx+1;
+ unsigned char b0 = prow[cim] &1;
+ unsigned char b1 = prow[col_idx]&1;
+ unsigned char b2 = prow[cip]&1;
+
+ unsigned char b3 = inrow[cim]&1;
+ unsigned char b4 = inrow[col_idx]&1;
+ unsigned char b5 = inrow[cip]&1;
+
+ unsigned char b6 = nrow[cim]&1;
+ unsigned char b7 = nrow[col_idx]&1;
+ unsigned char b8 = nrow[cip]&1;
+
+ int lut_idx = (b0
+ |(b1 << 1)
+ |(b2 << 2)
+ |(b3 << 3)
+ |(b4 << 4)
+ |(b5 << 5)
+ |(b6 << 6)
+ |(b7 << 7)
+ |(b8 << 8));
+ outrow[col_idx] = 255*(lut[lut_idx]&1);
+ num_changed_pixels += ((b4&1)!=(outrow[col_idx]&1));
+ }
+ }
+ return Py_BuildValue("i",num_changed_pixels);
+}
+
+/* Match a morphologic LUT to a binary image and return a list
+ of the coordinates of all matching pixels.
+
+ Expected parameters:
+
+ 1. a LUT - a 512 byte size lookup table.
+ 2. an input Imaging image id.
+
+ Returns list of matching pixels.
+*/
+static PyObject*
+match(PyObject *self, PyObject* args)
+{
+ const char *lut;
+ PyObject *py_lut;
+ Py_ssize_t lut_len, i0;
+ Imaging imgin;
+ int width, height;
+ int row_idx, col_idx;
+ UINT8 **inrows;
+ PyObject *ret = PyList_New(0);
+
+ if (!PyArg_ParseTuple(args, "On", &py_lut, &i0)) {
+ PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
+ return NULL;
+ }
+
+ if (!PyBytes_Check(py_lut)) {
+ PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object");
+ return NULL;
+ }
+
+ lut_len = PyBytes_Size(py_lut);
+
+ if (lut_len < LUT_SIZE) {
+ PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size");
+ return NULL;
+ }
+
+ lut = PyBytes_AsString(py_lut);
+ imgin = (Imaging) i0;
+
+ if (imgin->type != IMAGING_TYPE_UINT8 ||
+ imgin->bands != 1) {
+ PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
+ return NULL;
+ }
+
+ inrows = imgin->image8;
+ width = imgin->xsize;
+ height = imgin->ysize;
+
+ for (row_idx=1; row_idx < height-1; row_idx++) {
+ UINT8 *inrow = inrows[row_idx];
+ UINT8 *prow, *nrow;
+
+ prow = inrows[row_idx-1];
+ nrow = inrows[row_idx+1];
+
+ for (col_idx=1; col_idx<width-1; col_idx++) {
+ int cim = col_idx-1;
+ int cip = col_idx+1;
+ unsigned char b0 = prow[cim] &1;
+ unsigned char b1 = prow[col_idx]&1;
+ unsigned char b2 = prow[cip]&1;
+
+ unsigned char b3 = inrow[cim]&1;
+ unsigned char b4 = inrow[col_idx]&1;
+ unsigned char b5 = inrow[cip]&1;
+
+ unsigned char b6 = nrow[cim]&1;
+ unsigned char b7 = nrow[col_idx]&1;
+ unsigned char b8 = nrow[cip]&1;
+
+ int lut_idx = (b0
+ |(b1 << 1)
+ |(b2 << 2)
+ |(b3 << 3)
+ |(b4 << 4)
+ |(b5 << 5)
+ |(b6 << 6)
+ |(b7 << 7)
+ |(b8 << 8));
+ if (lut[lut_idx]) {
+ PyObject *coordObj = Py_BuildValue("(nn)",col_idx,row_idx);
+ PyList_Append(ret, coordObj);
+ }
+ }
+ }
+
+ return ret;
+}
+
+/* Return a list of the coordinates of all turned on pixels in an image.
+ May be used to extract features after a sequence of MorphOps were applied.
+ This is faster than match as only 1x1 lookup is made.
+*/
+static PyObject*
+get_on_pixels(PyObject *self, PyObject* args)
+{
+ Py_ssize_t i0;
+ Imaging img;
+ UINT8 **rows;
+ int row_idx, col_idx;
+ int width, height;
+ PyObject *ret = PyList_New(0);
+
+ if (!PyArg_ParseTuple(args, "n", &i0)) {
+ PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
+
+ return NULL;
+ }
+ img = (Imaging) i0;
+ rows = img->image8;
+ width = img->xsize;
+ height = img->ysize;
+
+ for (row_idx=0; row_idx < height; row_idx++) {
+ UINT8 *row = rows[row_idx];
+ for (col_idx=0; col_idx<width; col_idx++) {
+ if (row[col_idx]) {
+ PyObject *coordObj = Py_BuildValue("(nn)",col_idx,row_idx);
+ PyList_Append(ret, coordObj);
+ }
+ }
+ }
+ return ret;
+}
+
+
+static int
+setup_module(PyObject* m)
+{
+ PyObject* d = PyModule_GetDict(m);
+
+ PyDict_SetItemString(d, "__version", PyUnicode_FromString("0.1"));
+
+ return 0;
+}
+
+static PyMethodDef functions[] = {
+ /* Functions */
+ {"apply", (PyCFunction)apply, METH_VARARGS, NULL},
+ {"get_on_pixels", (PyCFunction)get_on_pixels, METH_VARARGS, NULL},
+ {"match", (PyCFunction)match, METH_VARARGS, NULL},
+ {NULL, NULL, 0, NULL}
+};
+
+#if PY_VERSION_HEX >= 0x03000000
+PyMODINIT_FUNC
+PyInit__imagingmorph(void) {
+ PyObject* m;
+
+ static PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ "_imagingmorph", /* m_name */
+ "A module for doing image morphology", /* m_doc */
+ -1, /* m_size */
+ functions, /* m_methods */
+ };
+
+ m = PyModule_Create(&module_def);
+
+ if (setup_module(m) < 0)
+ return NULL;
+
+ return m;
+}
+#else
+PyMODINIT_FUNC
+init_imagingmorph(void)
+{
+ PyObject* m = Py_InitModule("_imagingmorph", functions);
+ setup_module(m);
+}
+#endif
+
diff --git a/contrib/python/Pillow/py2/_webp.c b/contrib/python/Pillow/py2/_webp.c
new file mode 100644
index 0000000000..66b6d3268a
--- /dev/null
+++ b/contrib/python/Pillow/py2/_webp.c
@@ -0,0 +1,877 @@
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include "Imaging.h"
+#include "py3.h"
+#include <webp/encode.h>
+#include <webp/decode.h>
+#include <webp/types.h>
+
+#ifdef HAVE_WEBPMUX
+#include <webp/mux.h>
+#include <webp/demux.h>
+
+/*
+ * Check the versions from mux.h and demux.h, to ensure the WebPAnimEncoder and
+ * WebPAnimDecoder APIs are present (initial support was added in 0.5.0). The
+ * very early versions had some significant differences, so we require later
+ * versions, before enabling animation support.
+ */
+#if WEBP_MUX_ABI_VERSION >= 0x0104 && WEBP_DEMUX_ABI_VERSION >= 0x0105
+#define HAVE_WEBPANIM
+#endif
+
+#endif
+
+/* -------------------------------------------------------------------- */
+/* WebP Muxer Error Handling */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_WEBPMUX
+
+static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = {
+ "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA",
+ "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA"
+};
+
+PyObject* HandleMuxError(WebPMuxError err, char* chunk) {
+ char message[100];
+ int message_len;
+ assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA);
+
+ // Check for a memory error first
+ if (err == WEBP_MUX_MEMORY_ERROR) {
+ return PyErr_NoMemory();
+ }
+
+ // Create the error message
+ if (chunk == NULL) {
+ message_len = sprintf(message, "could not assemble chunks: %s", kErrorMessages[-err]);
+ } else {
+ message_len = sprintf(message, "could not set %.4s chunk: %s", chunk, kErrorMessages[-err]);
+ }
+ if (message_len < 0) {
+ PyErr_SetString(PyExc_RuntimeError, "failed to construct error message");
+ return NULL;
+ }
+
+ // Set the proper error type
+ switch (err) {
+ case WEBP_MUX_NOT_FOUND:
+ case WEBP_MUX_INVALID_ARGUMENT:
+ PyErr_SetString(PyExc_ValueError, message);
+ break;
+
+ case WEBP_MUX_BAD_DATA:
+ case WEBP_MUX_NOT_ENOUGH_DATA:
+ PyErr_SetString(PyExc_IOError, message);
+ break;
+
+ default:
+ PyErr_SetString(PyExc_RuntimeError, message);
+ break;
+ }
+ return NULL;
+}
+
+#endif
+
+/* -------------------------------------------------------------------- */
+/* WebP Animation Support */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_WEBPANIM
+
+// Encoder type
+typedef struct {
+ PyObject_HEAD
+ WebPAnimEncoder* enc;
+ WebPPicture frame;
+} WebPAnimEncoderObject;
+
+static PyTypeObject WebPAnimEncoder_Type;
+
+// Decoder type
+typedef struct {
+ PyObject_HEAD
+ WebPAnimDecoder* dec;
+ WebPAnimInfo info;
+ WebPData data;
+ char* mode;
+} WebPAnimDecoderObject;
+
+static PyTypeObject WebPAnimDecoder_Type;
+
+// Encoder functions
+PyObject* _anim_encoder_new(PyObject* self, PyObject* args)
+{
+ int width, height;
+ uint32_t bgcolor;
+ int loop_count;
+ int minimize_size;
+ int kmin, kmax;
+ int allow_mixed;
+ int verbose;
+ WebPAnimEncoderOptions enc_options;
+ WebPAnimEncoderObject* encp = NULL;
+ WebPAnimEncoder* enc = NULL;
+
+ if (!PyArg_ParseTuple(args, "iiIiiiiii",
+ &width, &height, &bgcolor, &loop_count, &minimize_size,
+ &kmin, &kmax, &allow_mixed, &verbose)) {
+ return NULL;
+ }
+
+ // Setup and configure the encoder's options (these are animation-specific)
+ if (!WebPAnimEncoderOptionsInit(&enc_options)) {
+ PyErr_SetString(PyExc_RuntimeError, "failed to initialize encoder options");
+ return NULL;
+ }
+ enc_options.anim_params.bgcolor = bgcolor;
+ enc_options.anim_params.loop_count = loop_count;
+ enc_options.minimize_size = minimize_size;
+ enc_options.kmin = kmin;
+ enc_options.kmax = kmax;
+ enc_options.allow_mixed = allow_mixed;
+ enc_options.verbose = verbose;
+
+ // Validate canvas dimensions
+ if (width <= 0 || height <= 0) {
+ PyErr_SetString(PyExc_ValueError, "invalid canvas dimensions");
+ return NULL;
+ }
+
+ // Create a new animation encoder and picture frame
+ encp = PyObject_New(WebPAnimEncoderObject, &WebPAnimEncoder_Type);
+ if (encp) {
+ if (WebPPictureInit(&(encp->frame))) {
+ enc = WebPAnimEncoderNew(width, height, &enc_options);
+ if (enc) {
+ encp->enc = enc;
+ return (PyObject*) encp;
+ }
+ WebPPictureFree(&(encp->frame));
+ }
+ PyObject_Del(encp);
+ }
+ PyErr_SetString(PyExc_RuntimeError, "could not create encoder object");
+ return NULL;
+}
+
+PyObject* _anim_encoder_dealloc(PyObject* self)
+{
+ WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self;
+ WebPPictureFree(&(encp->frame));
+ WebPAnimEncoderDelete(encp->enc);
+ Py_RETURN_NONE;
+}
+
+PyObject* _anim_encoder_add(PyObject* self, PyObject* args)
+{
+ uint8_t* rgb;
+ Py_ssize_t size;
+ int timestamp;
+ int width;
+ int height;
+ char* mode;
+ int lossless;
+ float quality_factor;
+ int method;
+ WebPConfig config;
+ WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self;
+ WebPAnimEncoder* enc = encp->enc;
+ WebPPicture* frame = &(encp->frame);
+
+ if (!PyArg_ParseTuple(args, "z#iiisifi",
+ (char**)&rgb, &size, &timestamp, &width, &height, &mode,
+ &lossless, &quality_factor, &method)) {
+ return NULL;
+ }
+
+ // Check for NULL frame, which sets duration of final frame
+ if (!rgb) {
+ WebPAnimEncoderAdd(enc, NULL, timestamp, NULL);
+ Py_RETURN_NONE;
+ }
+
+ // Setup config for this frame
+ if (!WebPConfigInit(&config)) {
+ PyErr_SetString(PyExc_RuntimeError, "failed to initialize config!");
+ return NULL;
+ }
+ config.lossless = lossless;
+ config.quality = quality_factor;
+ config.method = method;
+
+ // Validate the config
+ if (!WebPValidateConfig(&config)) {
+ PyErr_SetString(PyExc_ValueError, "invalid configuration");
+ return NULL;
+ }
+
+ // Populate the frame with raw bytes passed to us
+ frame->width = width;
+ frame->height = height;
+ frame->use_argb = 1; // Don't convert RGB pixels to YUV
+ if (strcmp(mode, "RGBA")==0) {
+ WebPPictureImportRGBA(frame, rgb, 4 * width);
+ } else if (strcmp(mode, "RGBX")==0) {
+ WebPPictureImportRGBX(frame, rgb, 4 * width);
+ } else {
+ WebPPictureImportRGB(frame, rgb, 3 * width);
+ }
+
+ // Add the frame to the encoder
+ if (!WebPAnimEncoderAdd(enc, frame, timestamp, &config)) {
+ PyErr_SetString(PyExc_RuntimeError, WebPAnimEncoderGetError(enc));
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args)
+{
+ uint8_t* icc_bytes;
+ uint8_t* exif_bytes;
+ uint8_t* xmp_bytes;
+ Py_ssize_t icc_size;
+ Py_ssize_t exif_size;
+ Py_ssize_t xmp_size;
+ WebPData webp_data;
+ WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self;
+ WebPAnimEncoder* enc = encp->enc;
+ WebPMux* mux = NULL;
+ PyObject* ret = NULL;
+
+ if (!PyArg_ParseTuple(args, "s#s#s#",
+ &icc_bytes, &icc_size, &exif_bytes, &exif_size, &xmp_bytes, &xmp_size)) {
+ return NULL;
+ }
+
+ // Init the output buffer
+ WebPDataInit(&webp_data);
+
+ // Assemble everything into the output buffer
+ if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
+ PyErr_SetString(PyExc_RuntimeError, WebPAnimEncoderGetError(enc));
+ return NULL;
+ }
+
+ // Re-mux to add metadata as needed
+ if (icc_size > 0 || exif_size > 0 || xmp_size > 0) {
+ WebPMuxError err = WEBP_MUX_OK;
+ int i_icc_size = (int)icc_size;
+ int i_exif_size = (int)exif_size;
+ int i_xmp_size = (int)xmp_size;
+ WebPData icc_profile = { icc_bytes, i_icc_size };
+ WebPData exif = { exif_bytes, i_exif_size };
+ WebPData xmp = { xmp_bytes, i_xmp_size };
+
+ mux = WebPMuxCreate(&webp_data, 1);
+ if (mux == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "could not re-mux to add metadata");
+ return NULL;
+ }
+ WebPDataClear(&webp_data);
+
+ // Add ICCP chunk
+ if (i_icc_size > 0) {
+ err = WebPMuxSetChunk(mux, "ICCP", &icc_profile, 1);
+ if (err != WEBP_MUX_OK) {
+ return HandleMuxError(err, "ICCP");
+ }
+ }
+
+ // Add EXIF chunk
+ if (i_exif_size > 0) {
+ err = WebPMuxSetChunk(mux, "EXIF", &exif, 1);
+ if (err != WEBP_MUX_OK) {
+ return HandleMuxError(err, "EXIF");
+ }
+ }
+
+ // Add XMP chunk
+ if (i_xmp_size > 0) {
+ err = WebPMuxSetChunk(mux, "XMP ", &xmp, 1);
+ if (err != WEBP_MUX_OK) {
+ return HandleMuxError(err, "XMP");
+ }
+ }
+
+ err = WebPMuxAssemble(mux, &webp_data);
+ if (err != WEBP_MUX_OK) {
+ return HandleMuxError(err, NULL);
+ }
+ }
+
+ // Convert to Python bytes
+ ret = PyBytes_FromStringAndSize((char*)webp_data.bytes, webp_data.size);
+ WebPDataClear(&webp_data);
+
+ // If we had to re-mux, we should free it now that we're done with it
+ if (mux != NULL) {
+ WebPMuxDelete(mux);
+ }
+
+ return ret;
+}
+
+// Decoder functions
+PyObject* _anim_decoder_new(PyObject* self, PyObject* args)
+{
+ PyBytesObject *webp_string;
+ const uint8_t *webp;
+ Py_ssize_t size;
+ WebPData webp_src;
+ char* mode;
+ WebPDecoderConfig config;
+ WebPAnimDecoderObject* decp = NULL;
+ WebPAnimDecoder* dec = NULL;
+
+ if (!PyArg_ParseTuple(args, "S", &webp_string)) {
+ return NULL;
+ }
+ PyBytes_AsStringAndSize((PyObject *)webp_string, (char**)&webp, &size);
+ webp_src.bytes = webp;
+ webp_src.size = size;
+
+ // Sniff the mode, since the decoder API doesn't tell us
+ mode = "RGBA";
+ if (WebPGetFeatures(webp, size, &config.input) == VP8_STATUS_OK) {
+ if (!config.input.has_alpha) {
+ mode = "RGBX";
+ }
+ }
+
+ // Create the decoder (default mode is RGBA, if no options passed)
+ decp = PyObject_New(WebPAnimDecoderObject, &WebPAnimDecoder_Type);
+ if (decp) {
+ decp->mode = mode;
+ if (WebPDataCopy(&webp_src, &(decp->data))) {
+ dec = WebPAnimDecoderNew(&(decp->data), NULL);
+ if (dec) {
+ if (WebPAnimDecoderGetInfo(dec, &(decp->info))) {
+ decp->dec = dec;
+ return (PyObject*)decp;
+ }
+ }
+ }
+ PyObject_Del(decp);
+ }
+ PyErr_SetString(PyExc_RuntimeError, "could not create decoder object");
+ return NULL;
+}
+
+PyObject* _anim_decoder_dealloc(PyObject* self)
+{
+ WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self;
+ WebPDataClear(&(decp->data));
+ WebPAnimDecoderDelete(decp->dec);
+ Py_RETURN_NONE;
+}
+
+PyObject* _anim_decoder_get_info(PyObject* self, PyObject* args)
+{
+ WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self;
+ WebPAnimInfo* info = &(decp->info);
+
+ return Py_BuildValue("IIIIIs",
+ info->canvas_width, info->canvas_height,
+ info->loop_count,
+ info->bgcolor,
+ info->frame_count,
+ decp->mode
+ );
+}
+
+PyObject* _anim_decoder_get_chunk(PyObject* self, PyObject* args)
+{
+ char* mode;
+ WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self;
+ const WebPDemuxer* demux;
+ WebPChunkIterator iter;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, "s", &mode)) {
+ return NULL;
+ }
+
+ demux = WebPAnimDecoderGetDemuxer(decp->dec);
+ if (!WebPDemuxGetChunk(demux, mode, 1, &iter)) {
+ Py_RETURN_NONE;
+ }
+
+ ret = PyBytes_FromStringAndSize((const char*)iter.chunk.bytes, iter.chunk.size);
+ WebPDemuxReleaseChunkIterator(&iter);
+
+ return ret;
+}
+
+PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args)
+{
+ uint8_t* buf;
+ int timestamp;
+ PyObject* bytes;
+ PyObject* ret;
+ WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self;
+
+ if (!WebPAnimDecoderGetNext(decp->dec, &buf, &timestamp)) {
+ PyErr_SetString(PyExc_IOError, "failed to read next frame");
+ return NULL;
+ }
+
+ bytes = PyBytes_FromStringAndSize((char *)buf,
+ decp->info.canvas_width * 4 * decp->info.canvas_height);
+
+ ret = Py_BuildValue("Si", bytes, timestamp);
+
+ Py_DECREF(bytes);
+ return ret;
+}
+
+PyObject* _anim_decoder_has_more_frames(PyObject* self, PyObject* args)
+{
+ WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self;
+ return Py_BuildValue("i", WebPAnimDecoderHasMoreFrames(decp->dec));
+}
+
+PyObject* _anim_decoder_reset(PyObject* self, PyObject* args)
+{
+ WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self;
+ WebPAnimDecoderReset(decp->dec);
+ Py_RETURN_NONE;
+}
+
+/* -------------------------------------------------------------------- */
+/* Type Definitions */
+/* -------------------------------------------------------------------- */
+
+// WebPAnimEncoder methods
+static struct PyMethodDef _anim_encoder_methods[] = {
+ {"add", (PyCFunction)_anim_encoder_add, METH_VARARGS, "add"},
+ {"assemble", (PyCFunction)_anim_encoder_assemble, METH_VARARGS, "assemble"},
+ {NULL, NULL} /* sentinel */
+};
+
+// WebPAnimDecoder type definition
+static PyTypeObject WebPAnimEncoder_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "WebPAnimEncoder", /*tp_name */
+ sizeof(WebPAnimEncoderObject), /*tp_size */
+ 0, /*tp_itemsize */
+ /* methods */
+ (destructor)_anim_encoder_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ _anim_encoder_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+};
+
+// WebPAnimDecoder methods
+static struct PyMethodDef _anim_decoder_methods[] = {
+ {"get_info", (PyCFunction)_anim_decoder_get_info, METH_VARARGS, "get_info"},
+ {"get_chunk", (PyCFunction)_anim_decoder_get_chunk, METH_VARARGS, "get_chunk"},
+ {"get_next", (PyCFunction)_anim_decoder_get_next, METH_VARARGS, "get_next"},
+ {"has_more_frames", (PyCFunction)_anim_decoder_has_more_frames, METH_VARARGS, "has_more_frames"},
+ {"reset", (PyCFunction)_anim_decoder_reset, METH_VARARGS, "reset"},
+ {NULL, NULL} /* sentinel */
+};
+
+// WebPAnimDecoder type definition
+static PyTypeObject WebPAnimDecoder_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "WebPAnimDecoder", /*tp_name */
+ sizeof(WebPAnimDecoderObject), /*tp_size */
+ 0, /*tp_itemsize */
+ /* methods */
+ (destructor)_anim_decoder_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ _anim_decoder_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+};
+
+#endif
+
+/* -------------------------------------------------------------------- */
+/* Legacy WebP Support */
+/* -------------------------------------------------------------------- */
+
+PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
+{
+ int width;
+ int height;
+ int lossless;
+ float quality_factor;
+ uint8_t* rgb;
+ uint8_t* icc_bytes;
+ uint8_t* exif_bytes;
+ uint8_t* xmp_bytes;
+ uint8_t* output;
+ char* mode;
+ Py_ssize_t size;
+ Py_ssize_t icc_size;
+ Py_ssize_t exif_size;
+ Py_ssize_t xmp_size;
+ size_t ret_size;
+
+ if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH"iiifss#s#s#",
+ (char**)&rgb, &size, &width, &height, &lossless, &quality_factor, &mode,
+ &icc_bytes, &icc_size, &exif_bytes, &exif_size, &xmp_bytes, &xmp_size)) {
+ return NULL;
+ }
+ if (strcmp(mode, "RGBA")==0){
+ if (size < width * height * 4){
+ Py_RETURN_NONE;
+ }
+ #if WEBP_ENCODER_ABI_VERSION >= 0x0100
+ if (lossless) {
+ ret_size = WebPEncodeLosslessRGBA(rgb, width, height, 4 * width, &output);
+ } else
+ #endif
+ {
+ ret_size = WebPEncodeRGBA(rgb, width, height, 4 * width, quality_factor, &output);
+ }
+ } else if (strcmp(mode, "RGB")==0){
+ if (size < width * height * 3){
+ Py_RETURN_NONE;
+ }
+ #if WEBP_ENCODER_ABI_VERSION >= 0x0100
+ if (lossless) {
+ ret_size = WebPEncodeLosslessRGB(rgb, width, height, 3 * width, &output);
+ } else
+ #endif
+ {
+ ret_size = WebPEncodeRGB(rgb, width, height, 3 * width, quality_factor, &output);
+ }
+ } else {
+ Py_RETURN_NONE;
+ }
+
+#ifndef HAVE_WEBPMUX
+ if (ret_size > 0) {
+ PyObject *ret = PyBytes_FromStringAndSize((char*)output, ret_size);
+ free(output);
+ return ret;
+ }
+#else
+ {
+ /* I want to truncate the *_size items that get passed into WebP
+ data. Pypy2.1.0 had some issues where the Py_ssize_t items had
+ data in the upper byte. (Not sure why, it shouldn't have been there)
+ */
+ int i_icc_size = (int)icc_size;
+ int i_exif_size = (int)exif_size;
+ int i_xmp_size = (int)xmp_size;
+ WebPData output_data = {0};
+ WebPData image = { output, ret_size };
+ WebPData icc_profile = { icc_bytes, i_icc_size };
+ WebPData exif = { exif_bytes, i_exif_size };
+ WebPData xmp = { xmp_bytes, i_xmp_size };
+ WebPMuxError err;
+ int dbg = 0;
+
+ int copy_data = 0; // value 1 indicates given data WILL be copied to the mux
+ // and value 0 indicates data will NOT be copied.
+
+ WebPMux* mux = WebPMuxNew();
+ WebPMuxSetImage(mux, &image, copy_data);
+
+ if (dbg) {
+ /* was getting %ld icc_size == 0, icc_size>0 was true */
+ fprintf(stderr, "icc size %d, %d \n", i_icc_size, i_icc_size > 0);
+ }
+
+ if (i_icc_size > 0) {
+ if (dbg) {
+ fprintf(stderr, "Adding ICC Profile\n");
+ }
+ err = WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
+ if (err != WEBP_MUX_OK) {
+ return HandleMuxError(err, "ICCP");
+ }
+ }
+
+ if (dbg) {
+ fprintf(stderr, "exif size %d \n", i_exif_size);
+ }
+ if (i_exif_size > 0) {
+ if (dbg) {
+ fprintf(stderr, "Adding Exif Data\n");
+ }
+ err = WebPMuxSetChunk(mux, "EXIF", &exif, copy_data);
+ if (err != WEBP_MUX_OK) {
+ return HandleMuxError(err, "EXIF");
+ }
+ }
+
+ if (dbg) {
+ fprintf(stderr, "xmp size %d \n", i_xmp_size);
+ }
+ if (i_xmp_size > 0) {
+ if (dbg){
+ fprintf(stderr, "Adding XMP Data\n");
+ }
+ err = WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data);
+ if (err != WEBP_MUX_OK) {
+ return HandleMuxError(err, "XMP ");
+ }
+ }
+
+ WebPMuxAssemble(mux, &output_data);
+ WebPMuxDelete(mux);
+ free(output);
+
+ ret_size = output_data.size;
+ if (ret_size > 0) {
+ PyObject *ret = PyBytes_FromStringAndSize((char*)output_data.bytes, ret_size);
+ WebPDataClear(&output_data);
+ return ret;
+ }
+ }
+#endif
+ Py_RETURN_NONE;
+}
+
+PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args)
+{
+ PyBytesObject* webp_string;
+ const uint8_t* webp;
+ Py_ssize_t size;
+ PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL, *icc_profile = NULL, *exif = NULL;
+ WebPDecoderConfig config;
+ VP8StatusCode vp8_status_code = VP8_STATUS_OK;
+ char* mode = "RGB";
+
+ if (!PyArg_ParseTuple(args, "S", &webp_string)) {
+ return NULL;
+ }
+
+ if (!WebPInitDecoderConfig(&config)) {
+ Py_RETURN_NONE;
+ }
+
+ PyBytes_AsStringAndSize((PyObject*) webp_string, (char**)&webp, &size);
+
+ vp8_status_code = WebPGetFeatures(webp, size, &config.input);
+ if (vp8_status_code == VP8_STATUS_OK) {
+ // If we don't set it, we don't get alpha.
+ // Initialized to MODE_RGB
+ if (config.input.has_alpha) {
+ config.output.colorspace = MODE_RGBA;
+ mode = "RGBA";
+ }
+
+#ifndef HAVE_WEBPMUX
+ vp8_status_code = WebPDecode(webp, size, &config);
+#else
+ {
+ int copy_data = 0;
+ WebPData data = { webp, size };
+ WebPMuxFrameInfo image;
+ WebPData icc_profile_data = {0};
+ WebPData exif_data = {0};
+
+ WebPMux* mux = WebPMuxCreate(&data, copy_data);
+ if (NULL == mux)
+ goto end;
+
+ if (WEBP_MUX_OK != WebPMuxGetFrame(mux, 1, &image))
+ {
+ WebPMuxDelete(mux);
+ goto end;
+ }
+
+ webp = image.bitstream.bytes;
+ size = image.bitstream.size;
+
+ vp8_status_code = WebPDecode(webp, size, &config);
+
+ if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "ICCP", &icc_profile_data))
+ icc_profile = PyBytes_FromStringAndSize((const char*)icc_profile_data.bytes, icc_profile_data.size);
+
+ if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "EXIF", &exif_data))
+ exif = PyBytes_FromStringAndSize((const char*)exif_data.bytes, exif_data.size);
+
+ WebPDataClear(&image.bitstream);
+ WebPMuxDelete(mux);
+ }
+#endif
+ }
+
+ if (vp8_status_code != VP8_STATUS_OK)
+ goto end;
+
+ if (config.output.colorspace < MODE_YUV) {
+ bytes = PyBytes_FromStringAndSize((char*)config.output.u.RGBA.rgba,
+ config.output.u.RGBA.size);
+ } else {
+ // Skipping YUV for now. Need Test Images.
+ // UNDONE -- unclear if we'll ever get here if we set mode_rgb*
+ bytes = PyBytes_FromStringAndSize((char*)config.output.u.YUVA.y,
+ config.output.u.YUVA.y_size);
+ }
+
+#if PY_VERSION_HEX >= 0x03000000
+ pymode = PyUnicode_FromString(mode);
+#else
+ pymode = PyString_FromString(mode);
+#endif
+ ret = Py_BuildValue("SiiSSS", bytes, config.output.width,
+ config.output.height, pymode,
+ NULL == icc_profile ? Py_None : icc_profile,
+ NULL == exif ? Py_None : exif);
+
+end:
+ WebPFreeDecBuffer(&config.output);
+
+ Py_XDECREF(bytes);
+ Py_XDECREF(pymode);
+ Py_XDECREF(icc_profile);
+ Py_XDECREF(exif);
+
+ if (Py_None == ret)
+ Py_RETURN_NONE;
+
+ return ret;
+}
+
+// Return the decoder's version number, packed in hexadecimal using 8bits for
+// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+PyObject* WebPDecoderVersion_wrapper(PyObject* self, PyObject* args){
+ return Py_BuildValue("i", WebPGetDecoderVersion());
+}
+
+/*
+ * The version of webp that ships with (0.1.3) Ubuntu 12.04 doesn't handle alpha well.
+ * Files that are valid with 0.3 are reported as being invalid.
+ */
+int WebPDecoderBuggyAlpha(void) {
+ return WebPGetDecoderVersion()==0x0103;
+}
+
+PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){
+ return Py_BuildValue("i", WebPDecoderBuggyAlpha());
+}
+
+/* -------------------------------------------------------------------- */
+/* Module Setup */
+/* -------------------------------------------------------------------- */
+
+static PyMethodDef webpMethods[] =
+{
+#ifdef HAVE_WEBPANIM
+ {"WebPAnimDecoder", _anim_decoder_new, METH_VARARGS, "WebPAnimDecoder"},
+ {"WebPAnimEncoder", _anim_encoder_new, METH_VARARGS, "WebPAnimEncoder"},
+#endif
+ {"WebPEncode", WebPEncode_wrapper, METH_VARARGS, "WebPEncode"},
+ {"WebPDecode", WebPDecode_wrapper, METH_VARARGS, "WebPDecode"},
+ {"WebPDecoderVersion", WebPDecoderVersion_wrapper, METH_VARARGS, "WebPVersion"},
+ {"WebPDecoderBuggyAlpha", WebPDecoderBuggyAlpha_wrapper, METH_VARARGS, "WebPDecoderBuggyAlpha"},
+ {NULL, NULL}
+};
+
+void addMuxFlagToModule(PyObject* m) {
+#ifdef HAVE_WEBPMUX
+ PyModule_AddObject(m, "HAVE_WEBPMUX", Py_True);
+#else
+ PyModule_AddObject(m, "HAVE_WEBPMUX", Py_False);
+#endif
+}
+
+void addAnimFlagToModule(PyObject* m) {
+#ifdef HAVE_WEBPANIM
+ PyModule_AddObject(m, "HAVE_WEBPANIM", Py_True);
+#else
+ PyModule_AddObject(m, "HAVE_WEBPANIM", Py_False);
+#endif
+}
+
+void addTransparencyFlagToModule(PyObject* m) {
+ PyModule_AddObject(m, "HAVE_TRANSPARENCY",
+ PyBool_FromLong(!WebPDecoderBuggyAlpha()));
+}
+
+static int setup_module(PyObject* m) {
+ addMuxFlagToModule(m);
+ addAnimFlagToModule(m);
+ addTransparencyFlagToModule(m);
+
+#ifdef HAVE_WEBPANIM
+ /* Ready object types */
+ if (PyType_Ready(&WebPAnimDecoder_Type) < 0 ||
+ PyType_Ready(&WebPAnimEncoder_Type) < 0)
+ return -1;
+#endif
+ return 0;
+}
+
+#if PY_VERSION_HEX >= 0x03000000
+PyMODINIT_FUNC
+PyInit__webp(void) {
+ PyObject* m;
+
+ static PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ "_webp", /* m_name */
+ NULL, /* m_doc */
+ -1, /* m_size */
+ webpMethods, /* m_methods */
+ };
+
+ m = PyModule_Create(&module_def);
+ if (setup_module(m) < 0)
+ return NULL;
+
+ return m;
+}
+#else
+PyMODINIT_FUNC
+init_webp(void)
+{
+ PyObject* m = Py_InitModule("_webp", webpMethods);
+ setup_module(m);
+}
+#endif
diff --git a/contrib/python/Pillow/py2/decode.c b/contrib/python/Pillow/py2/decode.c
new file mode 100644
index 0000000000..79133f48fc
--- /dev/null
+++ b/contrib/python/Pillow/py2/decode.c
@@ -0,0 +1,917 @@
+/*
+ * The Python Imaging Library.
+ *
+ * standard decoder interfaces for the Imaging library
+ *
+ * history:
+ * 1996-03-28 fl Moved from _imagingmodule.c
+ * 1996-04-15 fl Support subregions in setimage
+ * 1996-04-19 fl Allocate decoder buffer (where appropriate)
+ * 1996-05-02 fl Added jpeg decoder
+ * 1996-05-12 fl Compile cleanly as C++
+ * 1996-05-16 fl Added hex decoder
+ * 1996-05-26 fl Added jpeg configuration parameters
+ * 1996-12-14 fl Added zip decoder
+ * 1996-12-30 fl Plugged potential memory leak for tiled images
+ * 1997-01-03 fl Added fli and msp decoders
+ * 1997-01-04 fl Added sun_rle and tga_rle decoders
+ * 1997-05-31 fl Added bitfield decoder
+ * 1998-09-11 fl Added orientation and pixelsize fields to tga_rle decoder
+ * 1998-12-29 fl Added mode/rawmode argument to decoders
+ * 1998-12-30 fl Added mode argument to *all* decoders
+ * 2002-06-09 fl Added stride argument to pcx decoder
+ *
+ * Copyright (c) 1997-2002 by Secret Labs AB.
+ * Copyright (c) 1995-2002 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+/* FIXME: make these pluggable! */
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h"
+
+#include "Imaging.h"
+#include "py3.h"
+
+#include "Gif.h"
+#include "Raw.h"
+#include "Bit.h"
+#include "Sgi.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Common */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ PyObject_HEAD
+ int (*decode)(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+ int (*cleanup)(ImagingCodecState state);
+ struct ImagingCodecStateInstance state;
+ Imaging im;
+ PyObject* lock;
+ int pulls_fd;
+} ImagingDecoderObject;
+
+static PyTypeObject ImagingDecoderType;
+
+static ImagingDecoderObject*
+PyImaging_DecoderNew(int contextsize)
+{
+ ImagingDecoderObject *decoder;
+ void *context;
+
+ if(PyType_Ready(&ImagingDecoderType) < 0)
+ return NULL;
+
+ decoder = PyObject_New(ImagingDecoderObject, &ImagingDecoderType);
+ if (decoder == NULL)
+ return NULL;
+
+ /* Clear the decoder state */
+ memset(&decoder->state, 0, sizeof(decoder->state));
+
+ /* Allocate decoder context */
+ if (contextsize > 0) {
+ context = (void*) calloc(1, contextsize);
+ if (!context) {
+ Py_DECREF(decoder);
+ (void) PyErr_NoMemory();
+ return NULL;
+ }
+ } else
+ context = 0;
+
+ /* Initialize decoder context */
+ decoder->state.context = context;
+
+ /* Target image */
+ decoder->lock = NULL;
+ decoder->im = NULL;
+
+ /* Initialize the cleanup function pointer */
+ decoder->cleanup = NULL;
+
+ /* set if the decoder needs to pull data from the fd, instead of
+ having it pushed */
+ decoder->pulls_fd = 0;
+
+ return decoder;
+}
+
+static void
+_dealloc(ImagingDecoderObject* decoder)
+{
+ if (decoder->cleanup)
+ decoder->cleanup(&decoder->state);
+ free(decoder->state.buffer);
+ free(decoder->state.context);
+ Py_XDECREF(decoder->lock);
+ Py_XDECREF(decoder->state.fd);
+ PyObject_Del(decoder);
+}
+
+static PyObject*
+_decode(ImagingDecoderObject* decoder, PyObject* args)
+{
+ UINT8* buffer;
+ Py_ssize_t bufsize;
+ int status;
+ ImagingSectionCookie cookie;
+
+ if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH, &buffer, &bufsize))
+ return NULL;
+
+ if (!decoder->pulls_fd) {
+ ImagingSectionEnter(&cookie);
+ }
+
+ status = decoder->decode(decoder->im, &decoder->state, buffer, bufsize);
+
+ if (!decoder->pulls_fd) {
+ ImagingSectionLeave(&cookie);
+ }
+
+ return Py_BuildValue("ii", status, decoder->state.errcode);
+}
+
+static PyObject*
+_decode_cleanup(ImagingDecoderObject* decoder, PyObject* args)
+{
+ int status = 0;
+
+ if (decoder->cleanup){
+ status = decoder->cleanup(&decoder->state);
+ }
+
+ return Py_BuildValue("i", status);
+}
+
+
+
+extern Imaging PyImaging_AsImaging(PyObject *op);
+
+static PyObject*
+_setimage(ImagingDecoderObject* decoder, PyObject* args)
+{
+ PyObject* op;
+ Imaging im;
+ ImagingCodecState state;
+ int x0, y0, x1, y1;
+
+ x0 = y0 = x1 = y1 = 0;
+
+ /* FIXME: should publish the ImagingType descriptor */
+ if (!PyArg_ParseTuple(args, "O|(iiii)", &op, &x0, &y0, &x1, &y1))
+ return NULL;
+ im = PyImaging_AsImaging(op);
+ if (!im)
+ return NULL;
+
+ decoder->im = im;
+
+ state = &decoder->state;
+
+ /* Setup decoding tile extent */
+ if (x0 == 0 && x1 == 0) {
+ state->xsize = im->xsize;
+ state->ysize = im->ysize;
+ } else {
+ state->xoff = x0;
+ state->yoff = y0;
+ state->xsize = x1 - x0;
+ state->ysize = y1 - y0;
+ }
+
+ if (state->xsize <= 0 ||
+ state->xsize + state->xoff > (int) im->xsize ||
+ state->ysize <= 0 ||
+ state->ysize + state->yoff > (int) im->ysize) {
+ PyErr_SetString(PyExc_ValueError, "tile cannot extend outside image");
+ return NULL;
+ }
+
+ /* Allocate memory buffer (if bits field is set) */
+ if (state->bits > 0) {
+ if (!state->bytes) {
+ if (state->xsize > ((INT_MAX / state->bits)-7)){
+ return PyErr_NoMemory();
+ }
+ state->bytes = (state->bits * state->xsize+7)/8;
+ }
+ /* malloc check ok, overflow checked above */
+ state->buffer = (UINT8*) malloc(state->bytes);
+ if (!state->buffer)
+ return PyErr_NoMemory();
+ }
+
+ /* Keep a reference to the image object, to make sure it doesn't
+ go away before we do */
+ Py_INCREF(op);
+ Py_XDECREF(decoder->lock);
+ decoder->lock = op;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_setfd(ImagingDecoderObject* decoder, PyObject* args)
+{
+ PyObject* fd;
+ ImagingCodecState state;
+
+ if (!PyArg_ParseTuple(args, "O", &fd))
+ return NULL;
+
+ state = &decoder->state;
+
+ Py_XINCREF(fd);
+ state->fd = fd;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject *
+_get_pulls_fd(ImagingDecoderObject *decoder)
+{
+ return PyBool_FromLong(decoder->pulls_fd);
+}
+
+static struct PyMethodDef methods[] = {
+ {"decode", (PyCFunction)_decode, 1},
+ {"cleanup", (PyCFunction)_decode_cleanup, 1},
+ {"setimage", (PyCFunction)_setimage, 1},
+ {"setfd", (PyCFunction)_setfd, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static struct PyGetSetDef getseters[] = {
+ {"pulls_fd", (getter)_get_pulls_fd, NULL,
+ "True if this decoder expects to pull from self.fd itself.",
+ NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject ImagingDecoderType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ImagingDecoder", /*tp_name*/
+ sizeof(ImagingDecoderObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ methods, /*tp_methods*/
+ 0, /*tp_members*/
+ getseters, /*tp_getset*/
+};
+
+/* -------------------------------------------------------------------- */
+
+int
+get_unpacker(ImagingDecoderObject* decoder, const char* mode,
+ const char* rawmode)
+{
+ int bits;
+ ImagingShuffler unpack;
+
+ unpack = ImagingFindUnpacker(mode, rawmode, &bits);
+ if (!unpack) {
+ Py_DECREF(decoder);
+ PyErr_SetString(PyExc_ValueError, "unknown raw mode");
+ return -1;
+ }
+
+ decoder->state.shuffle = unpack;
+ decoder->state.bits = bits;
+
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* BIT (packed fields) */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_BitDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ int bits = 8;
+ int pad = 8;
+ int fill = 0;
+ int sign = 0;
+ int ystep = 1;
+ if (!PyArg_ParseTuple(args, "s|iiiii", &mode, &bits, &pad, &fill,
+ &sign, &ystep))
+ return NULL;
+
+ if (strcmp(mode, "F") != 0) {
+ PyErr_SetString(PyExc_ValueError, "bad image mode");
+ return NULL;
+ }
+
+ decoder = PyImaging_DecoderNew(sizeof(BITSTATE));
+ if (decoder == NULL)
+ return NULL;
+
+ decoder->decode = ImagingBitDecode;
+
+ decoder->state.ystep = ystep;
+
+ ((BITSTATE*)decoder->state.context)->bits = bits;
+ ((BITSTATE*)decoder->state.context)->pad = pad;
+ ((BITSTATE*)decoder->state.context)->fill = fill;
+ ((BITSTATE*)decoder->state.context)->sign = sign;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* BCn: GPU block-compressed texture formats */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_BcnDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* actual;
+ int n = 0;
+ int ystep = 1;
+ if (!PyArg_ParseTuple(args, "s|ii", &mode, &n, &ystep))
+ return NULL;
+
+ switch (n) {
+ case 1: /* BC1: 565 color, 1-bit alpha */
+ case 2: /* BC2: 565 color, 4-bit alpha */
+ case 3: /* BC3: 565 color, 2-endpoint 8-bit interpolated alpha */
+ case 5: /* BC5: 2-channel 8-bit via 2 BC3 alpha blocks */
+ case 7: /* BC7: 4-channel 8-bit via everything */
+ actual = "RGBA"; break;
+ case 4: /* BC4: 1-channel 8-bit via 1 BC3 alpha block */
+ actual = "L"; break;
+ case 6: /* BC6: 3-channel 16-bit float */
+ /* TODO: support 4-channel floating point images */
+ actual = "RGBAF"; break;
+ default:
+ PyErr_SetString(PyExc_ValueError, "block compression type unknown");
+ return NULL;
+ }
+
+ if (strcmp(mode, actual) != 0) {
+ PyErr_SetString(PyExc_ValueError, "bad image mode");
+ return NULL;
+ }
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ decoder->decode = ImagingBcnDecode;
+ decoder->state.state = n;
+ decoder->state.ystep = ystep;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* FLI */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_FliDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ decoder->decode = ImagingFliDecode;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* GIF */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_GifDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ int bits = 8;
+ int interlace = 0;
+ if (!PyArg_ParseTuple(args, "s|ii", &mode, &bits, &interlace))
+ return NULL;
+
+ if (strcmp(mode, "L") != 0 && strcmp(mode, "P") != 0) {
+ PyErr_SetString(PyExc_ValueError, "bad image mode");
+ return NULL;
+ }
+
+ decoder = PyImaging_DecoderNew(sizeof(GIFDECODERSTATE));
+ if (decoder == NULL)
+ return NULL;
+
+ decoder->decode = ImagingGifDecode;
+
+ ((GIFDECODERSTATE*)decoder->state.context)->bits = bits;
+ ((GIFDECODERSTATE*)decoder->state.context)->interlace = interlace;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* HEX */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_HexDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode;
+ if (!PyArg_ParseTuple(args, "ss", &mode, &rawmode))
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->decode = ImagingHexDecode;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* LibTiff */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBTIFF
+
+#include "TiffDecode.h"
+
+#include <string.h>
+
+PyObject*
+PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+ char* mode;
+ char* rawmode;
+ char* compname;
+ int fp;
+ uint32 ifdoffset;
+
+ if (! PyArg_ParseTuple(args, "sssiI", &mode, &rawmode, &compname, &fp, &ifdoffset))
+ return NULL;
+
+ TRACE(("new tiff decoder %s\n", compname));
+
+ decoder = PyImaging_DecoderNew(sizeof(TIFFSTATE));
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ if (! ImagingLibTiffInit(&decoder->state, fp, ifdoffset)) {
+ Py_DECREF(decoder);
+ PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed");
+ return NULL;
+ }
+
+ decoder->decode = ImagingLibTiffDecode;
+
+ return (PyObject*) decoder;
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* PackBits */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_PackbitsDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode;
+ if (!PyArg_ParseTuple(args, "ss", &mode, &rawmode))
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->decode = ImagingPackbitsDecode;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* PCD */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_PcdDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ /* Unpack from PhotoYCC to RGB */
+ if (get_unpacker(decoder, "RGB", "YCC;P") < 0)
+ return NULL;
+
+ decoder->decode = ImagingPcdDecode;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* PCX */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_PcxDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode;
+ int stride;
+ if (!PyArg_ParseTuple(args, "ssi", &mode, &rawmode, &stride))
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->state.bytes = stride;
+
+ decoder->decode = ImagingPcxDecode;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* RAW */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_RawDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode;
+ int stride = 0;
+ int ystep = 1;
+ if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &stride, &ystep))
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(sizeof(RAWSTATE));
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->decode = ImagingRawDecode;
+
+ decoder->state.ystep = ystep;
+
+ ((RAWSTATE*)decoder->state.context)->stride = stride;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* SGI RLE */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_SgiRleDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode;
+ int ystep = 1;
+ int bpc = 1;
+ if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &ystep, &bpc))
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(sizeof(SGISTATE));
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->pulls_fd = 1;
+ decoder->decode = ImagingSgiRleDecode;
+ decoder->state.ystep = ystep;
+
+ ((SGISTATE*)decoder->state.context)->bpc = bpc;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* SUN RLE */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_SunRleDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode;
+ if (!PyArg_ParseTuple(args, "ss", &mode, &rawmode))
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->decode = ImagingSunRleDecode;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* TGA RLE */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_TgaRleDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode;
+ int ystep = 1;
+ int depth = 8;
+ if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &ystep, &depth))
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->decode = ImagingTgaRleDecode;
+
+ decoder->state.ystep = ystep;
+ decoder->state.count = depth / 8;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* XBM */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_XbmDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ decoder = PyImaging_DecoderNew(0);
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, "1", "1;R") < 0)
+ return NULL;
+
+ decoder->decode = ImagingXbmDecode;
+
+ return (PyObject*) decoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* ZIP */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBZ
+
+#include "Zip.h"
+
+PyObject*
+PyImaging_ZipDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode;
+ int interlaced = 0;
+ if (!PyArg_ParseTuple(args, "ss|i", &mode, &rawmode, &interlaced))
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(sizeof(ZIPSTATE));
+ if (decoder == NULL)
+ return NULL;
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->decode = ImagingZipDecode;
+ decoder->cleanup = ImagingZipDecodeCleanup;
+
+ ((ZIPSTATE*)decoder->state.context)->interlaced = interlaced;
+
+ return (PyObject*) decoder;
+}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* JPEG */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBJPEG
+
+/* We better define this decoder last in this file, so the following
+ undef's won't mess things up for the Imaging library proper. */
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_STDDEF_H
+#undef HAVE_STDLIB_H
+#undef UINT8
+#undef UINT16
+#undef UINT32
+#undef INT8
+#undef INT16
+#undef INT32
+
+#include "Jpeg.h"
+
+PyObject*
+PyImaging_JpegDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+
+ char* mode;
+ char* rawmode; /* what we want from the decoder */
+ char* jpegmode; /* what's in the file */
+ int scale = 1;
+ int draft = 0;
+
+ if (!PyArg_ParseTuple(args, "ssz|ii", &mode, &rawmode, &jpegmode,
+ &scale, &draft))
+ return NULL;
+
+ if (!jpegmode)
+ jpegmode = "";
+
+ decoder = PyImaging_DecoderNew(sizeof(JPEGSTATE));
+ if (decoder == NULL)
+ return NULL;
+
+ // libjpeg-turbo supports different output formats.
+ // We are choosing Pillow's native format (3 color bytes + 1 padding)
+ // to avoid extra conversion in Unpack.c.
+ if (ImagingJpegUseJCSExtensions() && strcmp(rawmode, "RGB") == 0) {
+ rawmode = "RGBX";
+ }
+
+ if (get_unpacker(decoder, mode, rawmode) < 0)
+ return NULL;
+
+ decoder->decode = ImagingJpegDecode;
+ decoder->cleanup = ImagingJpegDecodeCleanup;
+
+ strncpy(((JPEGSTATE*)decoder->state.context)->rawmode, rawmode, 8);
+ strncpy(((JPEGSTATE*)decoder->state.context)->jpegmode, jpegmode, 8);
+
+ ((JPEGSTATE*)decoder->state.context)->scale = scale;
+ ((JPEGSTATE*)decoder->state.context)->draft = draft;
+
+ return (PyObject*) decoder;
+}
+#endif
+
+/* -------------------------------------------------------------------- */
+/* JPEG 2000 */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_OPENJPEG
+
+#include "Jpeg2K.h"
+
+PyObject*
+PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
+{
+ ImagingDecoderObject* decoder;
+ JPEG2KDECODESTATE *context;
+
+ char* mode;
+ char* format;
+ OPJ_CODEC_FORMAT codec_format;
+ int reduce = 0;
+ int layers = 0;
+ int fd = -1;
+ PY_LONG_LONG length = -1;
+
+ if (!PyArg_ParseTuple(args, "ss|iiiL", &mode, &format,
+ &reduce, &layers, &fd, &length))
+ return NULL;
+
+ if (strcmp(format, "j2k") == 0)
+ codec_format = OPJ_CODEC_J2K;
+ else if (strcmp(format, "jpt") == 0)
+ codec_format = OPJ_CODEC_JPT;
+ else if (strcmp(format, "jp2") == 0)
+ codec_format = OPJ_CODEC_JP2;
+ else
+ return NULL;
+
+ decoder = PyImaging_DecoderNew(sizeof(JPEG2KDECODESTATE));
+ if (decoder == NULL)
+ return NULL;
+
+ decoder->pulls_fd = 1;
+ decoder->decode = ImagingJpeg2KDecode;
+ decoder->cleanup = ImagingJpeg2KDecodeCleanup;
+
+ context = (JPEG2KDECODESTATE *)decoder->state.context;
+
+ context->fd = fd;
+ context->length = (off_t)length;
+ context->format = codec_format;
+ context->reduce = reduce;
+ context->layers = layers;
+
+ return (PyObject*) decoder;
+}
+#endif /* HAVE_OPENJPEG */
+
diff --git a/contrib/python/Pillow/py2/display.c b/contrib/python/Pillow/py2/display.c
new file mode 100644
index 0000000000..efabf1c86a
--- /dev/null
+++ b/contrib/python/Pillow/py2/display.c
@@ -0,0 +1,828 @@
+/*
+ * The Python Imaging Library.
+ *
+ * display support (and other windows-related stuff)
+ *
+ * History:
+ * 1996-05-13 fl Windows DIB support
+ * 1996-05-21 fl Added palette stuff
+ * 1996-05-28 fl Added display_mode stuff
+ * 1997-09-21 fl Added draw primitive
+ * 2001-09-17 fl Added ImagingGrabScreen (from _grabscreen.c)
+ * 2002-05-12 fl Added ImagingListWindows
+ * 2002-11-19 fl Added clipboard support
+ * 2002-11-25 fl Added GetDC/ReleaseDC helpers
+ * 2003-05-21 fl Added create window support (including window callback)
+ * 2003-09-05 fl Added fromstring/tostring methods
+ * 2009-03-14 fl Added WMF support (from pilwmf)
+ *
+ * Copyright (c) 1997-2003 by Secret Labs AB.
+ * Copyright (c) 1996-1997 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Python.h"
+
+#include "Imaging.h"
+#include "py3.h"
+
+/* -------------------------------------------------------------------- */
+/* Windows DIB support */
+
+#ifdef _WIN32
+
+#include "ImDib.h"
+
+#if SIZEOF_VOID_P == 8
+#define F_HANDLE "K"
+#else
+#define F_HANDLE "k"
+#endif
+
+typedef struct {
+ PyObject_HEAD
+ ImagingDIB dib;
+} ImagingDisplayObject;
+
+static PyTypeObject ImagingDisplayType;
+
+static ImagingDisplayObject*
+_new(const char* mode, int xsize, int ysize)
+{
+ ImagingDisplayObject *display;
+
+ if (PyType_Ready(&ImagingDisplayType) < 0)
+ return NULL;
+
+ display = PyObject_New(ImagingDisplayObject, &ImagingDisplayType);
+ if (display == NULL)
+ return NULL;
+
+ display->dib = ImagingNewDIB(mode, xsize, ysize);
+ if (!display->dib) {
+ Py_DECREF(display);
+ return NULL;
+ }
+
+ return display;
+}
+
+static void
+_delete(ImagingDisplayObject* display)
+{
+ if (display->dib)
+ ImagingDeleteDIB(display->dib);
+ PyObject_Del(display);
+}
+
+static PyObject*
+_expose(ImagingDisplayObject* display, PyObject* args)
+{
+ HDC hdc;
+ if (!PyArg_ParseTuple(args, F_HANDLE, &hdc))
+ return NULL;
+
+ ImagingExposeDIB(display->dib, hdc);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_draw(ImagingDisplayObject* display, PyObject* args)
+{
+ HDC hdc;
+ int dst[4];
+ int src[4];
+ if (!PyArg_ParseTuple(args, F_HANDLE "(iiii)(iiii)", &hdc,
+ dst+0, dst+1, dst+2, dst+3,
+ src+0, src+1, src+2, src+3))
+ return NULL;
+
+ ImagingDrawDIB(display->dib, hdc, dst, src);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+extern Imaging PyImaging_AsImaging(PyObject *op);
+
+static PyObject*
+_paste(ImagingDisplayObject* display, PyObject* args)
+{
+ Imaging im;
+
+ PyObject* op;
+ int xy[4];
+ xy[0] = xy[1] = xy[2] = xy[3] = 0;
+ if (!PyArg_ParseTuple(args, "O|(iiii)", &op, xy+0, xy+1, xy+2, xy+3))
+ return NULL;
+ im = PyImaging_AsImaging(op);
+ if (!im)
+ return NULL;
+
+ if (xy[2] <= xy[0])
+ xy[2] = xy[0] + im->xsize;
+ if (xy[3] <= xy[1])
+ xy[3] = xy[1] + im->ysize;
+
+ ImagingPasteDIB(display->dib, im, xy);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_query_palette(ImagingDisplayObject* display, PyObject* args)
+{
+ HDC hdc;
+ int status;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE, &hdc))
+ return NULL;
+
+ status = ImagingQueryPaletteDIB(display->dib, hdc);
+
+ return Py_BuildValue("i", status);
+}
+
+static PyObject*
+_getdc(ImagingDisplayObject* display, PyObject* args)
+{
+ HWND window;
+ HDC dc;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE, &window))
+ return NULL;
+
+ dc = GetDC(window);
+ if (!dc) {
+ PyErr_SetString(PyExc_IOError, "cannot create dc");
+ return NULL;
+ }
+
+ return Py_BuildValue(F_HANDLE, dc);
+}
+
+static PyObject*
+_releasedc(ImagingDisplayObject* display, PyObject* args)
+{
+ HWND window;
+ HDC dc;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &window, &dc))
+ return NULL;
+
+ ReleaseDC(window, dc);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_frombytes(ImagingDisplayObject* display, PyObject* args)
+{
+ char* ptr;
+ int bytes;
+
+#if PY_VERSION_HEX >= 0x03000000
+ if (!PyArg_ParseTuple(args, "y#:frombytes", &ptr, &bytes))
+ return NULL;
+#else
+ if (!PyArg_ParseTuple(args, "s#:fromstring", &ptr, &bytes))
+ return NULL;
+#endif
+
+ if (display->dib->ysize * display->dib->linesize != bytes) {
+ PyErr_SetString(PyExc_ValueError, "wrong size");
+ return NULL;
+ }
+
+ memcpy(display->dib->bits, ptr, bytes);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_tobytes(ImagingDisplayObject* display, PyObject* args)
+{
+#if PY_VERSION_HEX >= 0x03000000
+ if (!PyArg_ParseTuple(args, ":tobytes"))
+ return NULL;
+#else
+ if (!PyArg_ParseTuple(args, ":tostring"))
+ return NULL;
+#endif
+
+ return PyBytes_FromStringAndSize(
+ display->dib->bits, display->dib->ysize * display->dib->linesize
+ );
+}
+
+static struct PyMethodDef methods[] = {
+ {"draw", (PyCFunction)_draw, 1},
+ {"expose", (PyCFunction)_expose, 1},
+ {"paste", (PyCFunction)_paste, 1},
+ {"query_palette", (PyCFunction)_query_palette, 1},
+ {"getdc", (PyCFunction)_getdc, 1},
+ {"releasedc", (PyCFunction)_releasedc, 1},
+ {"frombytes", (PyCFunction)_frombytes, 1},
+ {"tobytes", (PyCFunction)_tobytes, 1},
+ {"fromstring", (PyCFunction)_frombytes, 1},
+ {"tostring", (PyCFunction)_tobytes, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject*
+_getattr_mode(ImagingDisplayObject* self, void* closure)
+{
+ return Py_BuildValue("s", self->dib->mode);
+}
+
+static PyObject*
+_getattr_size(ImagingDisplayObject* self, void* closure)
+{
+ return Py_BuildValue("ii", self->dib->xsize, self->dib->ysize);
+}
+
+static struct PyGetSetDef getsetters[] = {
+ { "mode", (getter) _getattr_mode },
+ { "size", (getter) _getattr_size },
+ { NULL }
+};
+
+static PyTypeObject ImagingDisplayType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ImagingDisplay", /*tp_name*/
+ sizeof(ImagingDisplayObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)_delete, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ methods, /*tp_methods*/
+ 0, /*tp_members*/
+ getsetters, /*tp_getset*/
+};
+
+PyObject*
+PyImaging_DisplayWin32(PyObject* self, PyObject* args)
+{
+ ImagingDisplayObject* display;
+ char *mode;
+ int xsize, ysize;
+
+ if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize))
+ return NULL;
+
+ display = _new(mode, xsize, ysize);
+ if (display == NULL)
+ return NULL;
+
+ return (PyObject*) display;
+}
+
+PyObject*
+PyImaging_DisplayModeWin32(PyObject* self, PyObject* args)
+{
+ char *mode;
+ int size[2];
+
+ mode = ImagingGetModeDIB(size);
+
+ return Py_BuildValue("s(ii)", mode, size[0], size[1]);
+}
+
+/* -------------------------------------------------------------------- */
+/* Windows screen grabber */
+
+typedef HANDLE(__stdcall* Func_SetThreadDpiAwarenessContext)(HANDLE);
+
+PyObject*
+PyImaging_GrabScreenWin32(PyObject* self, PyObject* args)
+{
+ int x = 0, y = 0, width, height;
+ int includeLayeredWindows = 0, all_screens = 0;
+ HBITMAP bitmap;
+ BITMAPCOREHEADER core;
+ HDC screen, screen_copy;
+ DWORD rop;
+ PyObject* buffer;
+ HANDLE dpiAwareness;
+ HMODULE user32;
+ Func_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContext_function;
+
+ if (!PyArg_ParseTuple(args, "|ii", &includeLayeredWindows, &all_screens))
+ return NULL;
+
+ /* step 1: create a memory DC large enough to hold the
+ entire screen */
+
+ screen = CreateDC("DISPLAY", NULL, NULL, NULL);
+ screen_copy = CreateCompatibleDC(screen);
+
+ // added in Windows 10 (1607)
+ // loaded dynamically to avoid link errors
+ user32 = LoadLibraryA("User32.dll");
+ SetThreadDpiAwarenessContext_function =
+ (Func_SetThreadDpiAwarenessContext)
+ GetProcAddress(user32, "SetThreadDpiAwarenessContext");
+ if (SetThreadDpiAwarenessContext_function != NULL) {
+ // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ((DPI_CONTEXT_HANDLE)-3)
+ dpiAwareness = SetThreadDpiAwarenessContext_function((HANDLE) -3);
+ }
+
+ if (all_screens) {
+ x = GetSystemMetrics(SM_XVIRTUALSCREEN);
+ y = GetSystemMetrics(SM_YVIRTUALSCREEN);
+ width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ } else {
+ width = GetDeviceCaps(screen, HORZRES);
+ height = GetDeviceCaps(screen, VERTRES);
+ }
+
+ if (SetThreadDpiAwarenessContext_function != NULL) {
+ SetThreadDpiAwarenessContext_function(dpiAwareness);
+ }
+
+ FreeLibrary(user32);
+
+ bitmap = CreateCompatibleBitmap(screen, width, height);
+ if (!bitmap)
+ goto error;
+
+ if (!SelectObject(screen_copy, bitmap))
+ goto error;
+
+ /* step 2: copy bits into memory DC bitmap */
+
+ rop = SRCCOPY;
+ if (includeLayeredWindows)
+ rop |= CAPTUREBLT;
+ if (!BitBlt(screen_copy, 0, 0, width, height, screen, x, y, rop))
+ goto error;
+
+ /* step 3: extract bits from bitmap */
+
+ buffer = PyBytes_FromStringAndSize(NULL, height * ((width*3 + 3) & -4));
+ if (!buffer)
+ return NULL;
+
+ core.bcSize = sizeof(core);
+ core.bcWidth = width;
+ core.bcHeight = height;
+ core.bcPlanes = 1;
+ core.bcBitCount = 24;
+ if (!GetDIBits(screen_copy, bitmap, 0, height, PyBytes_AS_STRING(buffer),
+ (BITMAPINFO*) &core, DIB_RGB_COLORS))
+ goto error;
+
+ DeleteObject(bitmap);
+ DeleteDC(screen_copy);
+ DeleteDC(screen);
+
+ return Py_BuildValue("(ii)(ii)N", x, y, width, height, buffer);
+
+error:
+ PyErr_SetString(PyExc_IOError, "screen grab failed");
+
+ DeleteDC(screen_copy);
+ DeleteDC(screen);
+
+ return NULL;
+}
+
+static BOOL CALLBACK list_windows_callback(HWND hwnd, LPARAM lParam)
+{
+ PyObject* window_list = (PyObject*) lParam;
+ PyObject* item;
+ PyObject* title;
+ RECT inner, outer;
+ int title_size;
+ int status;
+
+ /* get window title */
+ title_size = GetWindowTextLength(hwnd);
+ if (title_size > 0) {
+ title = PyUnicode_FromStringAndSize(NULL, title_size);
+ if (title)
+ GetWindowTextW(hwnd, PyUnicode_AS_UNICODE(title), title_size+1);
+ } else
+ title = PyUnicode_FromString("");
+ if (!title)
+ return 0;
+
+ /* get bounding boxes */
+ GetClientRect(hwnd, &inner);
+ GetWindowRect(hwnd, &outer);
+
+ item = Py_BuildValue(
+ F_HANDLE "N(iiii)(iiii)", hwnd, title,
+ inner.left, inner.top, inner.right, inner.bottom,
+ outer.left, outer.top, outer.right, outer.bottom
+ );
+ if (!item)
+ return 0;
+
+ status = PyList_Append(window_list, item);
+
+ Py_DECREF(item);
+
+ if (status < 0)
+ return 0;
+
+ return 1;
+}
+
+PyObject*
+PyImaging_ListWindowsWin32(PyObject* self, PyObject* args)
+{
+ PyObject* window_list;
+
+ window_list = PyList_New(0);
+ if (!window_list)
+ return NULL;
+
+ EnumWindows(list_windows_callback, (LPARAM) window_list);
+
+ if (PyErr_Occurred()) {
+ Py_DECREF(window_list);
+ return NULL;
+ }
+
+ return window_list;
+}
+
+/* -------------------------------------------------------------------- */
+/* Windows clipboard grabber */
+
+PyObject*
+PyImaging_GrabClipboardWin32(PyObject* self, PyObject* args)
+{
+ int clip;
+ HANDLE handle;
+ int size;
+ void* data;
+ PyObject* result;
+
+ clip = OpenClipboard(NULL);
+ /* FIXME: check error status */
+
+ handle = GetClipboardData(CF_DIB);
+ if (!handle) {
+ /* FIXME: add CF_HDROP support to allow cut-and-paste from
+ the explorer */
+ CloseClipboard();
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ size = GlobalSize(handle);
+ data = GlobalLock(handle);
+
+ result = PyBytes_FromStringAndSize(data, size);
+
+ GlobalUnlock(handle);
+
+ CloseClipboard();
+
+ return result;
+}
+
+/* -------------------------------------------------------------------- */
+/* Windows class */
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 522
+#endif
+
+static int mainloop = 0;
+
+static void
+callback_error(const char* handler)
+{
+ PyObject* sys_stderr;
+
+ sys_stderr = PySys_GetObject("stderr");
+
+ if (sys_stderr) {
+ PyFile_WriteString("*** ImageWin: error in ", sys_stderr);
+ PyFile_WriteString((char*) handler, sys_stderr);
+ PyFile_WriteString(":\n", sys_stderr);
+ }
+
+ PyErr_Print();
+ PyErr_Clear();
+}
+
+static LRESULT CALLBACK
+windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PAINTSTRUCT ps;
+ PyObject* callback = NULL;
+ PyObject* result;
+ PyThreadState* threadstate;
+ PyThreadState* current_threadstate;
+ HDC dc;
+ RECT rect;
+ LRESULT status = 0;
+
+ /* set up threadstate for messages that calls back into python */
+ switch (message) {
+ case WM_CREATE:
+ mainloop++;
+ break;
+ case WM_DESTROY:
+ mainloop--;
+ /* fall through... */
+ case WM_PAINT:
+ case WM_SIZE:
+ callback = (PyObject*) GetWindowLongPtr(wnd, 0);
+ if (callback) {
+ threadstate = (PyThreadState*)
+ GetWindowLongPtr(wnd, sizeof(PyObject*));
+ current_threadstate = PyThreadState_Swap(NULL);
+ PyEval_RestoreThread(threadstate);
+ } else
+ return DefWindowProc(wnd, message, wParam, lParam);
+ }
+
+ /* process message */
+ switch (message) {
+
+ case WM_PAINT:
+ /* redraw (part of) window. this generates a WCK-style
+ damage/clear/repair cascade */
+ BeginPaint(wnd, &ps);
+ dc = GetDC(wnd);
+ GetWindowRect(wnd, &rect); /* in screen coordinates */
+
+ result = PyObject_CallFunction(
+ callback, "siiii", "damage",
+ ps.rcPaint.left, ps.rcPaint.top,
+ ps.rcPaint.right, ps.rcPaint.bottom
+ );
+ if (result)
+ Py_DECREF(result);
+ else
+ callback_error("window damage callback");
+
+ result = PyObject_CallFunction(
+ callback, "s" F_HANDLE "iiii", "clear", dc,
+ 0, 0, rect.right-rect.left, rect.bottom-rect.top
+ );
+ if (result)
+ Py_DECREF(result);
+ else
+ callback_error("window clear callback");
+
+ result = PyObject_CallFunction(
+ callback, "s" F_HANDLE "iiii", "repair", dc,
+ 0, 0, rect.right-rect.left, rect.bottom-rect.top
+ );
+ if (result)
+ Py_DECREF(result);
+ else
+ callback_error("window repair callback");
+
+ ReleaseDC(wnd, dc);
+ EndPaint(wnd, &ps);
+ break;
+
+ case WM_SIZE:
+ /* resize window */
+ result = PyObject_CallFunction(
+ callback, "sii", "resize", LOWORD(lParam), HIWORD(lParam)
+ );
+ if (result) {
+ InvalidateRect(wnd, NULL, 1);
+ Py_DECREF(result);
+ } else
+ callback_error("window resize callback");
+ break;
+
+ case WM_DESTROY:
+ /* destroy window */
+ result = PyObject_CallFunction(callback, "s", "destroy");
+ if (result)
+ Py_DECREF(result);
+ else
+ callback_error("window destroy callback");
+ Py_DECREF(callback);
+ break;
+
+ default:
+ status = DefWindowProc(wnd, message, wParam, lParam);
+ }
+
+ if (callback) {
+ /* restore thread state */
+ PyEval_SaveThread();
+ PyThreadState_Swap(threadstate);
+ }
+
+ return status;
+}
+
+PyObject*
+PyImaging_CreateWindowWin32(PyObject* self, PyObject* args)
+{
+ HWND wnd;
+ WNDCLASS windowClass;
+
+ char* title;
+ PyObject* callback;
+ int width = 0, height = 0;
+ if (!PyArg_ParseTuple(args, "sO|ii", &title, &callback, &width, &height))
+ return NULL;
+
+ if (width <= 0)
+ width = CW_USEDEFAULT;
+ if (height <= 0)
+ height = CW_USEDEFAULT;
+
+ /* register toplevel window class */
+ windowClass.style = CS_CLASSDC;
+ windowClass.cbClsExtra = 0;
+ windowClass.cbWndExtra = sizeof(PyObject*) + sizeof(PyThreadState*);
+ windowClass.hInstance = GetModuleHandle(NULL);
+ /* windowClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); */
+ windowClass.hbrBackground = NULL;
+ windowClass.lpszMenuName = NULL;
+ windowClass.lpszClassName = "pilWindow";
+ windowClass.lpfnWndProc = windowCallback;
+ windowClass.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(1));
+ windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); /* CROSS? */
+
+ RegisterClass(&windowClass); /* FIXME: check return status */
+
+ wnd = CreateWindowEx(
+ 0, windowClass.lpszClassName, title,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, width, height,
+ HWND_DESKTOP, NULL, NULL, NULL
+ );
+
+ if (!wnd) {
+ PyErr_SetString(PyExc_IOError, "failed to create window");
+ return NULL;
+ }
+
+ /* register window callback */
+ Py_INCREF(callback);
+ SetWindowLongPtr(wnd, 0, (LONG_PTR) callback);
+ SetWindowLongPtr(wnd, sizeof(callback), (LONG_PTR) PyThreadState_Get());
+
+ Py_BEGIN_ALLOW_THREADS
+ ShowWindow(wnd, SW_SHOWNORMAL);
+ SetForegroundWindow(wnd); /* to make sure it's visible */
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue(F_HANDLE, wnd);
+}
+
+PyObject*
+PyImaging_EventLoopWin32(PyObject* self, PyObject* args)
+{
+ MSG msg;
+
+ Py_BEGIN_ALLOW_THREADS
+ while (mainloop && GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ Py_END_ALLOW_THREADS
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* -------------------------------------------------------------------- */
+/* windows WMF renderer */
+
+#define GET32(p,o) ((DWORD*)(p+o))[0]
+
+PyObject *
+PyImaging_DrawWmf(PyObject* self, PyObject* args)
+{
+ HBITMAP bitmap;
+ HENHMETAFILE meta;
+ BITMAPCOREHEADER core;
+ HDC dc;
+ RECT rect;
+ PyObject* buffer = NULL;
+ char* ptr;
+
+ char* data;
+ int datasize;
+ int width, height;
+ int x0, y0, x1, y1;
+ if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH"(ii)(iiii):_load", &data, &datasize,
+ &width, &height, &x0, &x1, &y0, &y1))
+ return NULL;
+
+ /* step 1: copy metafile contents into METAFILE object */
+
+ if (datasize > 22 && GET32(data, 0) == 0x9ac6cdd7) {
+
+ /* placeable windows metafile (22-byte aldus header) */
+ meta = SetWinMetaFileBits(datasize-22, data+22, NULL, NULL);
+
+ } else if (datasize > 80 && GET32(data, 0) == 1 &&
+ GET32(data, 40) == 0x464d4520) {
+
+ /* enhanced metafile */
+ meta = SetEnhMetaFileBits(datasize, data);
+
+ } else {
+
+ /* unknown meta format */
+ meta = NULL;
+
+ }
+
+ if (!meta) {
+ PyErr_SetString(PyExc_IOError, "cannot load metafile");
+ return NULL;
+ }
+
+ /* step 2: create bitmap */
+
+ core.bcSize = sizeof(core);
+ core.bcWidth = width;
+ core.bcHeight = height;
+ core.bcPlanes = 1;
+ core.bcBitCount = 24;
+
+ dc = CreateCompatibleDC(NULL);
+
+ bitmap = CreateDIBSection(
+ dc, (BITMAPINFO*) &core, DIB_RGB_COLORS, &ptr, NULL, 0
+ );
+
+ if (!bitmap) {
+ PyErr_SetString(PyExc_IOError, "cannot create bitmap");
+ goto error;
+ }
+
+ if (!SelectObject(dc, bitmap)) {
+ PyErr_SetString(PyExc_IOError, "cannot select bitmap");
+ goto error;
+ }
+
+ /* step 3: render metafile into bitmap */
+
+ rect.left = rect.top = 0;
+ rect.right = width;
+ rect.bottom = height;
+
+ /* FIXME: make background transparent? configurable? */
+ FillRect(dc, &rect, GetStockObject(WHITE_BRUSH));
+
+ if (!PlayEnhMetaFile(dc, meta, &rect)) {
+ PyErr_SetString(PyExc_IOError, "cannot render metafile");
+ goto error;
+ }
+
+ /* step 4: extract bits from bitmap */
+
+ GdiFlush();
+
+ buffer = PyBytes_FromStringAndSize(ptr, height * ((width*3 + 3) & -4));
+
+error:
+ DeleteEnhMetaFile(meta);
+
+ if (bitmap)
+ DeleteObject(bitmap);
+
+ DeleteDC(dc);
+
+ return buffer;
+}
+
+#endif /* _WIN32 */
diff --git a/contrib/python/Pillow/py2/encode.c b/contrib/python/Pillow/py2/encode.c
new file mode 100644
index 0000000000..7dc1035c49
--- /dev/null
+++ b/contrib/python/Pillow/py2/encode.c
@@ -0,0 +1,1256 @@
+/*
+ * The Python Imaging Library.
+ *
+ * standard encoder interfaces for the Imaging library
+ *
+ * History:
+ * 1996-04-19 fl Based on decoders.c
+ * 1996-05-12 fl Compile cleanly as C++
+ * 1996-12-30 fl Plugged potential memory leak for tiled images
+ * 1997-01-03 fl Added GIF encoder
+ * 1997-01-05 fl Plugged encoder buffer leaks
+ * 1997-01-11 fl Added encode_to_file method
+ * 1998-03-09 fl Added mode/rawmode argument to encoders
+ * 1998-07-09 fl Added interlace argument to GIF encoder
+ * 1999-02-07 fl Added PCX encoder
+ *
+ * Copyright (c) 1997-2001 by Secret Labs AB
+ * Copyright (c) 1996-1997 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+/* FIXME: make these pluggable! */
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h"
+
+#include "Imaging.h"
+#include "py3.h"
+#include "Gif.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* write */
+#endif
+
+/* -------------------------------------------------------------------- */
+/* Common */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ PyObject_HEAD
+ int (*encode)(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+ int (*cleanup)(ImagingCodecState state);
+ struct ImagingCodecStateInstance state;
+ Imaging im;
+ PyObject* lock;
+ int pushes_fd;
+} ImagingEncoderObject;
+
+static PyTypeObject ImagingEncoderType;
+
+static ImagingEncoderObject*
+PyImaging_EncoderNew(int contextsize)
+{
+ ImagingEncoderObject *encoder;
+ void *context;
+
+ if(PyType_Ready(&ImagingEncoderType) < 0)
+ return NULL;
+
+ encoder = PyObject_New(ImagingEncoderObject, &ImagingEncoderType);
+ if (encoder == NULL)
+ return NULL;
+
+ /* Clear the encoder state */
+ memset(&encoder->state, 0, sizeof(encoder->state));
+
+ /* Allocate encoder context */
+ if (contextsize > 0) {
+ context = (void*) calloc(1, contextsize);
+ if (!context) {
+ Py_DECREF(encoder);
+ (void) PyErr_NoMemory();
+ return NULL;
+ }
+ } else
+ context = 0;
+
+ /* Initialize encoder context */
+ encoder->state.context = context;
+
+ /* Most encoders don't need this */
+ encoder->cleanup = NULL;
+
+ /* Target image */
+ encoder->lock = NULL;
+ encoder->im = NULL;
+ encoder->pushes_fd = 0;
+
+ return encoder;
+}
+
+static void
+_dealloc(ImagingEncoderObject* encoder)
+{
+ if (encoder->cleanup)
+ encoder->cleanup(&encoder->state);
+ free(encoder->state.buffer);
+ free(encoder->state.context);
+ Py_XDECREF(encoder->lock);
+ Py_XDECREF(encoder->state.fd);
+ PyObject_Del(encoder);
+}
+
+static PyObject*
+_encode_cleanup(ImagingEncoderObject* encoder, PyObject* args)
+{
+ int status = 0;
+
+ if (encoder->cleanup){
+ status = encoder->cleanup(&encoder->state);
+ }
+
+ return Py_BuildValue("i", status);
+}
+
+static PyObject*
+_encode(ImagingEncoderObject* encoder, PyObject* args)
+{
+ PyObject* buf;
+ PyObject* result;
+ int status;
+
+ /* Encode to a Python string (allocated by this method) */
+
+ Py_ssize_t bufsize = 16384;
+
+ if (!PyArg_ParseTuple(args, "|n", &bufsize))
+ return NULL;
+
+ buf = PyBytes_FromStringAndSize(NULL, bufsize);
+ if (!buf)
+ return NULL;
+
+ status = encoder->encode(encoder->im, &encoder->state,
+ (UINT8*) PyBytes_AsString(buf), bufsize);
+
+ /* adjust string length to avoid slicing in encoder */
+ if (_PyBytes_Resize(&buf, (status > 0) ? status : 0) < 0)
+ return NULL;
+
+ result = Py_BuildValue("iiO", status, encoder->state.errcode, buf);
+
+ Py_DECREF(buf); /* must release buffer!!! */
+
+ return result;
+}
+
+static PyObject*
+_encode_to_pyfd(ImagingEncoderObject* encoder, PyObject* args)
+{
+
+ PyObject *result;
+ int status;
+
+ if (!encoder->pushes_fd) {
+ // UNDONE, appropriate errcode???
+ result = Py_BuildValue("ii", 0, IMAGING_CODEC_CONFIG);;
+ return result;
+ }
+
+ status = encoder->encode(encoder->im, &encoder->state,
+ (UINT8*) NULL, 0);
+
+ result = Py_BuildValue("ii", status, encoder->state.errcode);
+
+ return result;
+}
+
+static PyObject*
+_encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
+{
+ UINT8* buf;
+ int status;
+ ImagingSectionCookie cookie;
+
+ /* Encode to a file handle */
+
+ Py_ssize_t fh;
+ Py_ssize_t bufsize = 16384;
+
+ if (!PyArg_ParseTuple(args, "n|n", &fh, &bufsize))
+ return NULL;
+
+ /* Allocate an encoder buffer */
+ /* malloc check ok, either constant int, or checked by PyArg_ParseTuple */
+ buf = (UINT8*) malloc(bufsize);
+ if (!buf)
+ return PyErr_NoMemory();
+
+ ImagingSectionEnter(&cookie);
+
+ do {
+
+ /* This replaces the inner loop in the ImageFile _save
+ function. */
+
+ status = encoder->encode(encoder->im, &encoder->state, buf, bufsize);
+
+ if (status > 0)
+ if (write(fh, buf, status) < 0) {
+ ImagingSectionLeave(&cookie);
+ free(buf);
+ return PyErr_SetFromErrno(PyExc_IOError);
+ }
+
+ } while (encoder->state.errcode == 0);
+
+ ImagingSectionLeave(&cookie);
+
+ free(buf);
+
+ return Py_BuildValue("i", encoder->state.errcode);
+}
+
+extern Imaging PyImaging_AsImaging(PyObject *op);
+
+static PyObject*
+_setimage(ImagingEncoderObject* encoder, PyObject* args)
+{
+ PyObject* op;
+ Imaging im;
+ ImagingCodecState state;
+ Py_ssize_t x0, y0, x1, y1;
+
+ /* Define where image data should be stored */
+
+ x0 = y0 = x1 = y1 = 0;
+
+ /* FIXME: should publish the ImagingType descriptor */
+ if (!PyArg_ParseTuple(args, "O|(nnnn)", &op, &x0, &y0, &x1, &y1))
+ return NULL;
+ im = PyImaging_AsImaging(op);
+ if (!im)
+ return NULL;
+
+ encoder->im = im;
+
+ state = &encoder->state;
+
+ if (x0 == 0 && x1 == 0) {
+ state->xsize = im->xsize;
+ state->ysize = im->ysize;
+ } else {
+ state->xoff = x0;
+ state->yoff = y0;
+ state->xsize = x1 - x0;
+ state->ysize = y1 - y0;
+ }
+
+ if (state->xsize <= 0 ||
+ state->xsize + state->xoff > im->xsize ||
+ state->ysize <= 0 ||
+ state->ysize + state->yoff > im->ysize) {
+ PyErr_SetString(PyExc_SystemError, "tile cannot extend outside image");
+ return NULL;
+ }
+
+ /* Allocate memory buffer (if bits field is set) */
+ if (state->bits > 0) {
+ if (state->xsize > ((INT_MAX / state->bits)-7)) {
+ return PyErr_NoMemory();
+ }
+ state->bytes = (state->bits * state->xsize+7)/8;
+ /* malloc check ok, overflow checked above */
+ state->buffer = (UINT8*) malloc(state->bytes);
+ if (!state->buffer)
+ return PyErr_NoMemory();
+ }
+
+ /* Keep a reference to the image object, to make sure it doesn't
+ go away before we do */
+ Py_INCREF(op);
+ Py_XDECREF(encoder->lock);
+ encoder->lock = op;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_setfd(ImagingEncoderObject* encoder, PyObject* args)
+{
+ PyObject* fd;
+ ImagingCodecState state;
+
+ if (!PyArg_ParseTuple(args, "O", &fd))
+ return NULL;
+
+ state = &encoder->state;
+
+ Py_XINCREF(fd);
+ state->fd = fd;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+_get_pushes_fd(ImagingEncoderObject *encoder)
+{
+ return PyBool_FromLong(encoder->pushes_fd);
+}
+
+static struct PyMethodDef methods[] = {
+ {"encode", (PyCFunction)_encode, 1},
+ {"cleanup", (PyCFunction)_encode_cleanup, 1},
+ {"encode_to_file", (PyCFunction)_encode_to_file, 1},
+ {"encode_to_pyfd", (PyCFunction)_encode_to_pyfd, 1},
+ {"setimage", (PyCFunction)_setimage, 1},
+ {"setfd", (PyCFunction)_setfd, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static struct PyGetSetDef getseters[] = {
+ {"pushes_fd", (getter)_get_pushes_fd, NULL,
+ "True if this decoder expects to push directly to self.fd",
+ NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject ImagingEncoderType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ImagingEncoder", /*tp_name*/
+ sizeof(ImagingEncoderObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ methods, /*tp_methods*/
+ 0, /*tp_members*/
+ getseters, /*tp_getset*/
+};
+
+/* -------------------------------------------------------------------- */
+
+int
+get_packer(ImagingEncoderObject* encoder, const char* mode,
+ const char* rawmode)
+{
+ int bits;
+ ImagingShuffler pack;
+
+ pack = ImagingFindPacker(mode, rawmode, &bits);
+ if (!pack) {
+ Py_DECREF(encoder);
+ PyErr_Format(PyExc_ValueError, "No packer found from %s to %s", mode, rawmode);
+ return -1;
+ }
+
+ encoder->state.shuffle = pack;
+ encoder->state.bits = bits;
+
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* EPS */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_EpsEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL)
+ return NULL;
+
+ encoder->encode = ImagingEpsEncode;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* GIF */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_GifEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ Py_ssize_t bits = 8;
+ Py_ssize_t interlace = 0;
+ if (!PyArg_ParseTuple(args, "ss|nn", &mode, &rawmode, &bits, &interlace))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(sizeof(GIFENCODERSTATE));
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ encoder->encode = ImagingGifEncode;
+
+ ((GIFENCODERSTATE*)encoder->state.context)->bits = bits;
+ ((GIFENCODERSTATE*)encoder->state.context)->interlace = interlace;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* PCX */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ Py_ssize_t bits = 8;
+
+ if (!PyArg_ParseTuple(args, "ss|n", &mode, &rawmode, &bits)) {
+ return NULL;
+ }
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL) {
+ return NULL;
+ }
+
+ if (get_packer(encoder, mode, rawmode) < 0) {
+ return NULL;
+ }
+
+ encoder->encode = ImagingPcxEncode;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* RAW */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_RawEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ Py_ssize_t stride = 0;
+ Py_ssize_t ystep = 1;
+
+ if (!PyArg_ParseTuple(args, "ss|nn", &mode, &rawmode, &stride, &ystep))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ encoder->encode = ImagingRawEncode;
+
+ encoder->state.ystep = ystep;
+ encoder->state.count = stride;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* TGA */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_TgaRleEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ Py_ssize_t ystep = 1;
+
+ if (!PyArg_ParseTuple(args, "ss|n", &mode, &rawmode, &ystep))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ encoder->encode = ImagingTgaRleEncode;
+
+ encoder->state.ystep = ystep;
+
+ return (PyObject*) encoder;
+}
+
+
+
+/* -------------------------------------------------------------------- */
+/* XBM */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyImaging_XbmEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ encoder = PyImaging_EncoderNew(0);
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, "1", "1;R") < 0)
+ return NULL;
+
+ encoder->encode = ImagingXbmEncode;
+
+ return (PyObject*) encoder;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* ZIP */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBZ
+
+#include "Zip.h"
+
+PyObject*
+PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char* mode;
+ char* rawmode;
+ Py_ssize_t optimize = 0;
+ Py_ssize_t compress_level = -1;
+ Py_ssize_t compress_type = -1;
+ char* dictionary = NULL;
+ Py_ssize_t dictionary_size = 0;
+ if (!PyArg_ParseTuple(args, "ss|nnn"PY_ARG_BYTES_LENGTH, &mode, &rawmode,
+ &optimize,
+ &compress_level, &compress_type,
+ &dictionary, &dictionary_size))
+ return NULL;
+
+ /* Copy to avoid referencing Python's memory */
+ if (dictionary && dictionary_size > 0) {
+ /* malloc check ok, size comes from PyArg_ParseTuple */
+ char* p = malloc(dictionary_size);
+ if (!p)
+ return PyErr_NoMemory();
+ memcpy(p, dictionary, dictionary_size);
+ dictionary = p;
+ } else
+ dictionary = NULL;
+
+ encoder = PyImaging_EncoderNew(sizeof(ZIPSTATE));
+ if (encoder == NULL) {
+ free(dictionary);
+ return NULL;
+ }
+
+ if (get_packer(encoder, mode, rawmode) < 0) {
+ free(dictionary);
+ return NULL;
+ }
+
+ encoder->encode = ImagingZipEncode;
+ encoder->cleanup = ImagingZipEncodeCleanup;
+
+ if (rawmode[0] == 'P')
+ /* disable filtering */
+ ((ZIPSTATE*)encoder->state.context)->mode = ZIP_PNG_PALETTE;
+
+ ((ZIPSTATE*)encoder->state.context)->optimize = optimize;
+ ((ZIPSTATE*)encoder->state.context)->compress_level = compress_level;
+ ((ZIPSTATE*)encoder->state.context)->compress_type = compress_type;
+ ((ZIPSTATE*)encoder->state.context)->dictionary = dictionary;
+ ((ZIPSTATE*)encoder->state.context)->dictionary_size = dictionary_size;
+
+ return (PyObject*) encoder;
+}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* LibTiff */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBTIFF
+
+#include "TiffDecode.h"
+
+#include <string.h>
+
+PyObject*
+PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char* mode;
+ char* rawmode;
+ char* compname;
+ char* filename;
+ Py_ssize_t fp;
+
+ PyObject *tags, *types;
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ int key_int, status, is_core_tag, is_var_length, num_core_tags, i;
+ TIFFDataType type = TIFF_NOTYPE;
+ // This list also exists in TiffTags.py
+ const int core_tags[] = {
+ 256, 257, 258, 259, 262, 263, 266, 269, 274, 277, 278, 280, 281, 340,
+ 341, 282, 283, 284, 286, 287, 296, 297, 321, 338, 32995, 32998, 32996,
+ 339, 32997, 330, 531, 530, 65537
+ };
+
+ Py_ssize_t tags_size;
+ PyObject *item;
+
+ if (! PyArg_ParseTuple(args, "sssnsOO", &mode, &rawmode, &compname, &fp, &filename, &tags, &types)) {
+ return NULL;
+ }
+
+ if (!PyList_Check(tags)) {
+ PyErr_SetString(PyExc_ValueError, "Invalid tags list");
+ return NULL;
+ } else {
+ tags_size = PyList_Size(tags);
+ TRACE(("tags size: %d\n", (int)tags_size));
+ for (pos=0;pos<tags_size;pos++){
+ item = PyList_GetItem(tags, pos);
+ if (!PyTuple_Check(item) || PyTuple_Size(item) != 2) {
+ PyErr_SetString(PyExc_ValueError, "Invalid tags list");
+ return NULL;
+ }
+ }
+ pos = 0;
+ }
+ if (!PyDict_Check(types)) {
+ PyErr_SetString(PyExc_ValueError, "Invalid types dictionary");
+ return NULL;
+ }
+
+ TRACE(("new tiff encoder %s fp: %d, filename: %s \n", compname, fp, filename));
+
+ encoder = PyImaging_EncoderNew(sizeof(TIFFSTATE));
+ if (encoder == NULL)
+ return NULL;
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ if (! ImagingLibTiffEncodeInit(&encoder->state, filename, fp)) {
+ Py_DECREF(encoder);
+ PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed");
+ return NULL;
+ }
+
+ num_core_tags = sizeof(core_tags) / sizeof(int);
+ for (pos = 0; pos < tags_size; pos++) {
+ item = PyList_GetItem(tags, pos);
+ // We already checked that tags is a 2-tuple list.
+ key = PyTuple_GetItem(item, 0);
+ key_int = (int)PyInt_AsLong(key);
+ value = PyTuple_GetItem(item, 1);
+ status = 0;
+ is_core_tag = 0;
+ is_var_length = 0;
+ type = TIFF_NOTYPE;
+
+ for (i=0; i<num_core_tags; i++) {
+ if (core_tags[i] == key_int) {
+ is_core_tag = 1;
+ break;
+ }
+ }
+
+ if (!is_core_tag) {
+ PyObject *tag_type = PyDict_GetItem(types, key);
+ if (tag_type) {
+ int type_int = PyInt_AsLong(tag_type);
+ if (type_int >= TIFF_BYTE && type_int <= TIFF_DOUBLE) {
+ type = (TIFFDataType)type_int;
+ }
+ }
+ }
+
+
+ if (type == TIFF_NOTYPE) {
+ // Autodetect type. Types should not be changed for backwards
+ // compatibility.
+ if (PyInt_Check(value)) {
+ type = TIFF_LONG;
+ } else if (PyFloat_Check(value)) {
+ type = TIFF_DOUBLE;
+ } else if (PyBytes_Check(value)) {
+ type = TIFF_ASCII;
+ }
+ }
+
+ if (PyBytes_Check(value) &&
+ (type == TIFF_BYTE || type == TIFF_UNDEFINED)) {
+ // For backwards compatibility
+ type = TIFF_ASCII;
+ }
+
+ if (PyTuple_Check(value)) {
+ Py_ssize_t len;
+ len = PyTuple_Size(value);
+
+ is_var_length = 1;
+
+ if (!len) {
+ continue;
+ }
+
+ if (type == TIFF_NOTYPE) {
+ // Autodetect type based on first item. Types should not be
+ // changed for backwards compatibility.
+ if (PyInt_Check(PyTuple_GetItem(value,0))) {
+ type = TIFF_LONG;
+ } else if (PyFloat_Check(PyTuple_GetItem(value,0))) {
+ type = TIFF_FLOAT;
+ }
+ }
+ }
+
+ if (!is_core_tag) {
+ // Register field for non core tags.
+ if (ImagingLibTiffMergeFieldInfo(&encoder->state, type, key_int, is_var_length)) {
+ continue;
+ }
+ }
+
+ if (is_var_length) {
+ Py_ssize_t len,i;
+ TRACE(("Setting from Tuple: %d \n", key_int));
+ len = PyTuple_Size(value);
+
+ if (type == TIFF_BYTE) {
+ UINT8 *av;
+ /* malloc check ok, calloc checks for overflow */
+ av = calloc(len, sizeof(UINT8));
+ if (av) {
+ for (i=0;i<len;i++) {
+ av[i] = (UINT8)PyInt_AsLong(PyTuple_GetItem(value,i));
+ }
+ status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
+ free(av);
+ }
+ } else if (type == TIFF_SHORT) {
+ UINT16 *av;
+ /* malloc check ok, calloc checks for overflow */
+ av = calloc(len, sizeof(UINT16));
+ if (av) {
+ for (i=0;i<len;i++) {
+ av[i] = (UINT16)PyInt_AsLong(PyTuple_GetItem(value,i));
+ }
+ status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
+ free(av);
+ }
+ } else if (type == TIFF_LONG) {
+ UINT32 *av;
+ /* malloc check ok, calloc checks for overflow */
+ av = calloc(len, sizeof(UINT32));
+ if (av) {
+ for (i=0;i<len;i++) {
+ av[i] = (UINT32)PyInt_AsLong(PyTuple_GetItem(value,i));
+ }
+ status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
+ free(av);
+ }
+ } else if (type == TIFF_SBYTE) {
+ INT8 *av;
+ /* malloc check ok, calloc checks for overflow */
+ av = calloc(len, sizeof(INT8));
+ if (av) {
+ for (i=0;i<len;i++) {
+ av[i] = (INT8)PyInt_AsLong(PyTuple_GetItem(value,i));
+ }
+ status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
+ free(av);
+ }
+ } else if (type == TIFF_SSHORT) {
+ INT16 *av;
+ /* malloc check ok, calloc checks for overflow */
+ av = calloc(len, sizeof(INT16));
+ if (av) {
+ for (i=0;i<len;i++) {
+ av[i] = (INT16)PyInt_AsLong(PyTuple_GetItem(value,i));
+ }
+ status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
+ free(av);
+ }
+ } else if (type == TIFF_SLONG) {
+ INT32 *av;
+ /* malloc check ok, calloc checks for overflow */
+ av = calloc(len, sizeof(INT32));
+ if (av) {
+ for (i=0;i<len;i++) {
+ av[i] = (INT32)PyInt_AsLong(PyTuple_GetItem(value,i));
+ }
+ status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
+ free(av);
+ }
+ } else if (type == TIFF_FLOAT) {
+ FLOAT32 *av;
+ /* malloc check ok, calloc checks for overflow */
+ av = calloc(len, sizeof(FLOAT32));
+ if (av) {
+ for (i=0;i<len;i++) {
+ av[i] = (FLOAT32)PyFloat_AsDouble(PyTuple_GetItem(value,i));
+ }
+ status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
+ free(av);
+ }
+ } else if (type == TIFF_DOUBLE) {
+ FLOAT64 *av;
+ /* malloc check ok, calloc checks for overflow */
+ av = calloc(len, sizeof(FLOAT64));
+ if (av) {
+ for (i=0;i<len;i++) {
+ av[i] = PyFloat_AsDouble(PyTuple_GetItem(value,i));
+ }
+ status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
+ free(av);
+ }
+ }
+ } else {
+ if (type == TIFF_SHORT) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (UINT16)PyInt_AsLong(value));
+ } else if (type == TIFF_LONG) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (UINT32)PyInt_AsLong(value));
+ } else if (type == TIFF_SSHORT) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (INT16)PyInt_AsLong(value));
+ } else if (type == TIFF_SLONG) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (INT32)PyInt_AsLong(value));
+ } else if (type == TIFF_FLOAT) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (FLOAT32)PyFloat_AsDouble(value));
+ } else if (type == TIFF_DOUBLE) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (FLOAT64)PyFloat_AsDouble(value));
+ } else if (type == TIFF_BYTE) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (UINT8)PyInt_AsLong(value));
+ } else if (type == TIFF_SBYTE) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (INT8)PyInt_AsLong(value));
+ } else if (type == TIFF_ASCII) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ PyBytes_AsString(value));
+ } else if (type == TIFF_RATIONAL) {
+ status = ImagingLibTiffSetField(&encoder->state,
+ (ttag_t) key_int,
+ (FLOAT64)PyFloat_AsDouble(value));
+ } else {
+ TRACE(("Unhandled type for key %d : %s \n",
+ key_int,
+ PyBytes_AsString(PyObject_Str(value))));
+ }
+ }
+ if (!status) {
+ TRACE(("Error setting Field\n"));
+ Py_DECREF(encoder);
+ PyErr_SetString(PyExc_RuntimeError, "Error setting from dictionary");
+ return NULL;
+ }
+ }
+
+ encoder->encode = ImagingLibTiffEncode;
+
+ return (PyObject*) encoder;
+}
+
+#endif
+
+/* -------------------------------------------------------------------- */
+/* JPEG */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_LIBJPEG
+
+/* We better define this encoder last in this file, so the following
+ undef's won't mess things up for the Imaging library proper. */
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_STDDEF_H
+#undef HAVE_STDLIB_H
+#undef UINT8
+#undef UINT16
+#undef UINT32
+#undef INT8
+#undef INT16
+#undef INT32
+
+#include "Jpeg.h"
+
+static unsigned int* get_qtables_arrays(PyObject* qtables, int* qtablesLen) {
+ PyObject* tables;
+ PyObject* table;
+ PyObject* table_data;
+ int i, j, num_tables;
+ unsigned int *qarrays;
+
+ if ((qtables == NULL) || (qtables == Py_None)) {
+ return NULL;
+ }
+
+ if (!PySequence_Check(qtables)) {
+ PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
+ return NULL;
+ }
+
+ tables = PySequence_Fast(qtables, "expected a sequence");
+ num_tables = PySequence_Size(qtables);
+ if (num_tables < 1 || num_tables > NUM_QUANT_TBLS) {
+ PyErr_SetString(PyExc_ValueError,
+ "Not a valid number of quantization tables. Should be between 1 and 4.");
+ Py_DECREF(tables);
+ return NULL;
+ }
+ /* malloc check ok, num_tables <4, DCTSIZE2 == 64 from jpeglib.h */
+ qarrays = (unsigned int*) malloc(num_tables * DCTSIZE2 * sizeof(unsigned int));
+ if (!qarrays) {
+ Py_DECREF(tables);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (i = 0; i < num_tables; i++) {
+ table = PySequence_Fast_GET_ITEM(tables, i);
+ if (!PySequence_Check(table)) {
+ PyErr_SetString(PyExc_ValueError, "Invalid quantization tables");
+ goto JPEG_QTABLES_ERR;
+ }
+ if (PySequence_Size(table) != DCTSIZE2) {
+ PyErr_SetString(PyExc_ValueError, "Invalid quantization table size");
+ goto JPEG_QTABLES_ERR;
+ }
+ table_data = PySequence_Fast(table, "expected a sequence");
+ for (j = 0; j < DCTSIZE2; j++) {
+ qarrays[i * DCTSIZE2 + j] = PyInt_AS_LONG(PySequence_Fast_GET_ITEM(table_data, j));
+ }
+ Py_DECREF(table_data);
+ }
+
+ *qtablesLen = num_tables;
+
+JPEG_QTABLES_ERR:
+ Py_DECREF(tables); // Run on both error and not error
+ if (PyErr_Occurred()) {
+ free(qarrays);
+ qarrays = NULL;
+ return NULL;
+ }
+
+ return qarrays;
+}
+
+PyObject*
+PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
+{
+ ImagingEncoderObject* encoder;
+
+ char *mode;
+ char *rawmode;
+ Py_ssize_t quality = 0;
+ Py_ssize_t progressive = 0;
+ Py_ssize_t smooth = 0;
+ Py_ssize_t optimize = 0;
+ Py_ssize_t streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */
+ Py_ssize_t xdpi = 0, ydpi = 0;
+ Py_ssize_t subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */
+ PyObject* qtables=NULL;
+ unsigned int *qarrays = NULL;
+ int qtablesLen = 0;
+ char* extra = NULL;
+ Py_ssize_t extra_size;
+ char* rawExif = NULL;
+ Py_ssize_t rawExifLen = 0;
+
+ if (!PyArg_ParseTuple(args, "ss|nnnnnnnnO"PY_ARG_BYTES_LENGTH""PY_ARG_BYTES_LENGTH,
+ &mode, &rawmode, &quality,
+ &progressive, &smooth, &optimize, &streamtype,
+ &xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size,
+ &rawExif, &rawExifLen))
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(sizeof(JPEGENCODERSTATE));
+ if (encoder == NULL)
+ return NULL;
+
+ // libjpeg-turbo supports different output formats.
+ // We are choosing Pillow's native format (3 color bytes + 1 padding)
+ // to avoid extra conversion in Pack.c.
+ if (ImagingJpegUseJCSExtensions() && strcmp(rawmode, "RGB") == 0) {
+ rawmode = "RGBX";
+ }
+
+ if (get_packer(encoder, mode, rawmode) < 0)
+ return NULL;
+
+ // Freed in JpegEncode, Case 5
+ qarrays = get_qtables_arrays(qtables, &qtablesLen);
+
+ if (extra && extra_size > 0) {
+ /* malloc check ok, length is from python parsearg */
+ char* p = malloc(extra_size); // Freed in JpegEncode, Case 5
+ if (!p)
+ return PyErr_NoMemory();
+ memcpy(p, extra, extra_size);
+ extra = p;
+ } else
+ extra = NULL;
+
+ if (rawExif && rawExifLen > 0) {
+ /* malloc check ok, length is from python parsearg */
+ char* pp = malloc(rawExifLen); // Freed in JpegEncode, Case 5
+ if (!pp) {
+ if (extra) free(extra);
+ return PyErr_NoMemory();
+ }
+ memcpy(pp, rawExif, rawExifLen);
+ rawExif = pp;
+ } else
+ rawExif = NULL;
+
+ encoder->encode = ImagingJpegEncode;
+
+ strncpy(((JPEGENCODERSTATE*)encoder->state.context)->rawmode, rawmode, 8);
+
+ ((JPEGENCODERSTATE*)encoder->state.context)->quality = quality;
+ ((JPEGENCODERSTATE*)encoder->state.context)->qtables = qarrays;
+ ((JPEGENCODERSTATE*)encoder->state.context)->qtablesLen = qtablesLen;
+ ((JPEGENCODERSTATE*)encoder->state.context)->subsampling = subsampling;
+ ((JPEGENCODERSTATE*)encoder->state.context)->progressive = progressive;
+ ((JPEGENCODERSTATE*)encoder->state.context)->smooth = smooth;
+ ((JPEGENCODERSTATE*)encoder->state.context)->optimize = optimize;
+ ((JPEGENCODERSTATE*)encoder->state.context)->streamtype = streamtype;
+ ((JPEGENCODERSTATE*)encoder->state.context)->xdpi = xdpi;
+ ((JPEGENCODERSTATE*)encoder->state.context)->ydpi = ydpi;
+ ((JPEGENCODERSTATE*)encoder->state.context)->extra = extra;
+ ((JPEGENCODERSTATE*)encoder->state.context)->extra_size = extra_size;
+ ((JPEGENCODERSTATE*)encoder->state.context)->rawExif = rawExif;
+ ((JPEGENCODERSTATE*)encoder->state.context)->rawExifLen = rawExifLen;
+
+ return (PyObject*) encoder;
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* JPEG 2000 */
+/* -------------------------------------------------------------------- */
+
+#ifdef HAVE_OPENJPEG
+
+#include "Jpeg2K.h"
+
+static void
+j2k_decode_coord_tuple(PyObject *tuple, int *x, int *y)
+{
+ *x = *y = 0;
+
+ if (tuple && PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2) {
+ *x = (int)PyInt_AsLong(PyTuple_GET_ITEM(tuple, 0));
+ *y = (int)PyInt_AsLong(PyTuple_GET_ITEM(tuple, 1));
+
+ if (*x < 0)
+ *x = 0;
+ if (*y < 0)
+ *y = 0;
+ }
+}
+
+PyObject*
+PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
+{
+ ImagingEncoderObject *encoder;
+ JPEG2KENCODESTATE *context;
+
+ char *mode;
+ char *format;
+ OPJ_CODEC_FORMAT codec_format;
+ PyObject *offset = NULL, *tile_offset = NULL, *tile_size = NULL;
+ char *quality_mode = "rates";
+ PyObject *quality_layers = NULL;
+ Py_ssize_t num_resolutions = 0;
+ PyObject *cblk_size = NULL, *precinct_size = NULL;
+ PyObject *irreversible = NULL;
+ char *progression = "LRCP";
+ OPJ_PROG_ORDER prog_order;
+ char *cinema_mode = "no";
+ OPJ_CINEMA_MODE cine_mode;
+ Py_ssize_t fd = -1;
+
+ if (!PyArg_ParseTuple(args, "ss|OOOsOnOOOssn", &mode, &format,
+ &offset, &tile_offset, &tile_size,
+ &quality_mode, &quality_layers, &num_resolutions,
+ &cblk_size, &precinct_size,
+ &irreversible, &progression, &cinema_mode,
+ &fd))
+ return NULL;
+
+ if (strcmp (format, "j2k") == 0)
+ codec_format = OPJ_CODEC_J2K;
+ else if (strcmp (format, "jpt") == 0)
+ codec_format = OPJ_CODEC_JPT;
+ else if (strcmp (format, "jp2") == 0)
+ codec_format = OPJ_CODEC_JP2;
+ else
+ return NULL;
+
+ if (strcmp(progression, "LRCP") == 0)
+ prog_order = OPJ_LRCP;
+ else if (strcmp(progression, "RLCP") == 0)
+ prog_order = OPJ_RLCP;
+ else if (strcmp(progression, "RPCL") == 0)
+ prog_order = OPJ_RPCL;
+ else if (strcmp(progression, "PCRL") == 0)
+ prog_order = OPJ_PCRL;
+ else if (strcmp(progression, "CPRL") == 0)
+ prog_order = OPJ_CPRL;
+ else
+ return NULL;
+
+ if (strcmp(cinema_mode, "no") == 0)
+ cine_mode = OPJ_OFF;
+ else if (strcmp(cinema_mode, "cinema2k-24") == 0)
+ cine_mode = OPJ_CINEMA2K_24;
+ else if (strcmp(cinema_mode, "cinema2k-48") == 0)
+ cine_mode = OPJ_CINEMA2K_48;
+ else if (strcmp(cinema_mode, "cinema4k-24") == 0)
+ cine_mode = OPJ_CINEMA4K_24;
+ else
+ return NULL;
+
+ encoder = PyImaging_EncoderNew(sizeof(JPEG2KENCODESTATE));
+ if (!encoder)
+ return NULL;
+
+ encoder->encode = ImagingJpeg2KEncode;
+ encoder->cleanup = ImagingJpeg2KEncodeCleanup;
+ encoder->pushes_fd = 1;
+
+ context = (JPEG2KENCODESTATE *)encoder->state.context;
+
+ context->fd = fd;
+ context->format = codec_format;
+ context->offset_x = context->offset_y = 0;
+
+
+ j2k_decode_coord_tuple(offset, &context->offset_x, &context->offset_y);
+ j2k_decode_coord_tuple(tile_offset,
+ &context->tile_offset_x,
+ &context->tile_offset_y);
+ j2k_decode_coord_tuple(tile_size,
+ &context->tile_size_x,
+ &context->tile_size_y);
+
+ /* Error on illegal tile offsets */
+ if (context->tile_size_x && context->tile_size_y) {
+ if (context->tile_offset_x <= context->offset_x - context->tile_size_x
+ || context->tile_offset_y <= context->offset_y - context->tile_size_y) {
+ PyErr_SetString(PyExc_ValueError,
+ "JPEG 2000 tile offset too small; top left tile must "
+ "intersect image area");
+ Py_DECREF(encoder);
+ return NULL;
+ }
+
+ if (context->tile_offset_x > context->offset_x
+ || context->tile_offset_y > context->offset_y) {
+ PyErr_SetString(PyExc_ValueError,
+ "JPEG 2000 tile offset too large to cover image area");
+ Py_DECREF(encoder);
+ return NULL;
+ }
+ }
+
+ if (quality_layers && PySequence_Check(quality_layers)) {
+ context->quality_is_in_db = strcmp (quality_mode, "dB") == 0;
+ context->quality_layers = quality_layers;
+ Py_INCREF(quality_layers);
+ }
+
+ context->num_resolutions = num_resolutions;
+
+ j2k_decode_coord_tuple(cblk_size,
+ &context->cblk_width,
+ &context->cblk_height);
+ j2k_decode_coord_tuple(precinct_size,
+ &context->precinct_width,
+ &context->precinct_height);
+
+ context->irreversible = PyObject_IsTrue(irreversible);
+ context->progression = prog_order;
+ context->cinema_mode = cine_mode;
+
+ return (PyObject *)encoder;
+}
+
+#endif
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End:
+ *
+ */
diff --git a/contrib/python/Pillow/py2/libImaging/Access.c b/contrib/python/Pillow/py2/libImaging/Access.c
new file mode 100644
index 0000000000..15ffa11fc7
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Access.c
@@ -0,0 +1,249 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * imaging access objects
+ *
+ * Copyright (c) Fredrik Lundh 2009.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+/* use Tests/make_hash.py to calculate these values */
+#define ACCESS_TABLE_SIZE 27
+#define ACCESS_TABLE_HASH 3078
+
+static struct ImagingAccessInstance access_table[ACCESS_TABLE_SIZE];
+
+static inline UINT32
+hash(const char* mode)
+{
+ UINT32 i = ACCESS_TABLE_HASH;
+ while (*mode)
+ i = ((i<<5) + i) ^ (UINT8) *mode++;
+ return i % ACCESS_TABLE_SIZE;
+}
+
+static ImagingAccess
+add_item(const char* mode)
+{
+ UINT32 i = hash(mode);
+ /* printf("hash %s => %d\n", mode, i); */
+ if (access_table[i].mode && strcmp(access_table[i].mode, mode) != 0) {
+ fprintf(stderr, "AccessInit: hash collision: %d for both %s and %s\n",
+ i, mode, access_table[i].mode);
+ exit(1);
+ }
+ access_table[i].mode = mode;
+ return &access_table[i];
+}
+
+/* fetch pointer to pixel line */
+
+static void*
+line_8(Imaging im, int x, int y)
+{
+ return &im->image8[y][x];
+}
+
+static void*
+line_16(Imaging im, int x, int y)
+{
+ return &im->image8[y][x+x];
+}
+
+static void*
+line_32(Imaging im, int x, int y)
+{
+ return &im->image32[y][x];
+}
+
+/* fetch individual pixel */
+
+static void
+get_pixel(Imaging im, int x, int y, void* color)
+{
+ char* out = color;
+
+ /* generic pixel access*/
+
+ if (im->image8) {
+ out[0] = im->image8[y][x];
+ } else {
+ UINT8* p = (UINT8*) &im->image32[y][x];
+ if (im->type == IMAGING_TYPE_UINT8 && im->bands == 2) {
+ out[0] = p[0];
+ out[1] = p[3];
+ return;
+ }
+ memcpy(out, p, im->pixelsize);
+ }
+}
+
+static void
+get_pixel_8(Imaging im, int x, int y, void* color)
+{
+ char* out = color;
+ out[0] = im->image8[y][x];
+}
+
+static void
+get_pixel_16L(Imaging im, int x, int y, void* color)
+{
+ UINT8* in = (UINT8*) &im->image[y][x+x];
+#ifdef WORDS_BIGENDIAN
+ UINT16 out = in[0] + (in[1]<<8);
+ memcpy(color, &out, sizeof(out));
+#else
+ memcpy(color, in, sizeof(UINT16));
+#endif
+}
+
+static void
+get_pixel_16B(Imaging im, int x, int y, void* color)
+{
+ UINT8* in = (UINT8*) &im->image[y][x+x];
+#ifdef WORDS_BIGENDIAN
+ memcpy(color, in, sizeof(UINT16));
+#else
+ UINT16 out = in[1] + (in[0]<<8);
+ memcpy(color, &out, sizeof(out));
+#endif
+}
+
+static void
+get_pixel_32(Imaging im, int x, int y, void* color)
+{
+ memcpy(color, &im->image32[y][x], sizeof(INT32));
+}
+
+static void
+get_pixel_32L(Imaging im, int x, int y, void* color)
+{
+ UINT8* in = (UINT8*) &im->image[y][x*4];
+#ifdef WORDS_BIGENDIAN
+ INT32 out = in[0] + (in[1]<<8) + (in[2]<<16) + (in[3]<<24);
+ memcpy(color, &out, sizeof(out));
+#else
+ memcpy(color, in, sizeof(INT32));
+#endif
+}
+
+static void
+get_pixel_32B(Imaging im, int x, int y, void* color)
+{
+ UINT8* in = (UINT8*) &im->image[y][x*4];
+#ifdef WORDS_BIGENDIAN
+ memcpy(color, in, sizeof(INT32));
+#else
+ INT32 out = in[3] + (in[2]<<8) + (in[1]<<16) + (in[0]<<24);
+ memcpy(color, &out, sizeof(out));
+#endif
+}
+
+/* store individual pixel */
+
+static void
+put_pixel(Imaging im, int x, int y, const void* color)
+{
+ if (im->image8)
+ im->image8[y][x] = *((UINT8*) color);
+ else
+ memcpy(&im->image32[y][x], color, sizeof(INT32));
+}
+
+static void
+put_pixel_8(Imaging im, int x, int y, const void* color)
+{
+ im->image8[y][x] = *((UINT8*) color);
+}
+
+static void
+put_pixel_16L(Imaging im, int x, int y, const void* color)
+{
+ memcpy(&im->image8[y][x+x], color, 2);
+}
+
+static void
+put_pixel_16B(Imaging im, int x, int y, const void* color)
+{
+ const char* in = color;
+ UINT8* out = (UINT8*) &im->image8[y][x+x];
+ out[0] = in[1];
+ out[1] = in[0];
+}
+
+static void
+put_pixel_32L(Imaging im, int x, int y, const void* color)
+{
+ memcpy(&im->image8[y][x*4], color, 4);
+}
+
+static void
+put_pixel_32B(Imaging im, int x, int y, const void* color)
+{
+ const char* in = color;
+ UINT8* out = (UINT8*) &im->image8[y][x*4];
+ out[0] = in[3];
+ out[1] = in[2];
+ out[2] = in[1];
+ out[3] = in[0];
+}
+
+static void
+put_pixel_32(Imaging im, int x, int y, const void* color)
+{
+ memcpy(&im->image32[y][x], color, sizeof(INT32));
+}
+
+void
+ImagingAccessInit()
+{
+#define ADD(mode_, line_, get_pixel_, put_pixel_) \
+ { ImagingAccess access = add_item(mode_); \
+ access->line = line_; \
+ access->get_pixel = get_pixel_; \
+ access->put_pixel = put_pixel_; \
+ }
+
+ /* populate access table */
+ ADD("1", line_8, get_pixel_8, put_pixel_8);
+ ADD("L", line_8, get_pixel_8, put_pixel_8);
+ ADD("LA", line_32, get_pixel, put_pixel);
+ ADD("La", line_32, get_pixel, put_pixel);
+ ADD("I", line_32, get_pixel_32, put_pixel_32);
+ ADD("I;16", line_16, get_pixel_16L, put_pixel_16L);
+ ADD("I;16L", line_16, get_pixel_16L, put_pixel_16L);
+ ADD("I;16B", line_16, get_pixel_16B, put_pixel_16B);
+ ADD("I;32L", line_32, get_pixel_32L, put_pixel_32L);
+ ADD("I;32B", line_32, get_pixel_32B, put_pixel_32B);
+ ADD("F", line_32, get_pixel_32, put_pixel_32);
+ ADD("P", line_8, get_pixel_8, put_pixel_8);
+ ADD("PA", line_32, get_pixel, put_pixel);
+ ADD("RGB", line_32, get_pixel_32, put_pixel_32);
+ ADD("RGBA", line_32, get_pixel_32, put_pixel_32);
+ ADD("RGBa", line_32, get_pixel_32, put_pixel_32);
+ ADD("RGBX", line_32, get_pixel_32, put_pixel_32);
+ ADD("CMYK", line_32, get_pixel_32, put_pixel_32);
+ ADD("YCbCr", line_32, get_pixel_32, put_pixel_32);
+ ADD("LAB", line_32, get_pixel_32, put_pixel_32);
+ ADD("HSV", line_32, get_pixel_32, put_pixel_32);
+}
+
+ImagingAccess
+ImagingAccessNew(Imaging im)
+{
+ ImagingAccess access = &access_table[hash(im->mode)];
+ if (im->mode[0] != access->mode[0] || strcmp(im->mode, access->mode) != 0)
+ return NULL;
+ return access;
+}
+
+void
+_ImagingAccessDelete(Imaging im, ImagingAccess access)
+{
+
+}
diff --git a/contrib/python/Pillow/py2/libImaging/AlphaComposite.c b/contrib/python/Pillow/py2/libImaging/AlphaComposite.c
new file mode 100644
index 0000000000..a074334aaa
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/AlphaComposite.c
@@ -0,0 +1,87 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * Alpha composite imSrc over imDst.
+ * https://en.wikipedia.org/wiki/Alpha_compositing
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#define PRECISION_BITS 7
+
+typedef struct
+{
+ UINT8 r;
+ UINT8 g;
+ UINT8 b;
+ UINT8 a;
+} rgba8;
+
+
+
+Imaging
+ImagingAlphaComposite(Imaging imDst, Imaging imSrc)
+{
+ Imaging imOut;
+ int x, y;
+
+ /* Check arguments */
+ if (!imDst || !imSrc ||
+ strcmp(imDst->mode, "RGBA") ||
+ imDst->type != IMAGING_TYPE_UINT8 ||
+ imDst->bands != 4)
+ return ImagingError_ModeError();
+
+ if (strcmp(imDst->mode, imSrc->mode) ||
+ imDst->type != imSrc->type ||
+ imDst->bands != imSrc->bands ||
+ imDst->xsize != imSrc->xsize ||
+ imDst->ysize != imSrc->ysize)
+ return ImagingError_Mismatch();
+
+ imOut = ImagingNewDirty(imDst->mode, imDst->xsize, imDst->ysize);
+ if (!imOut)
+ return NULL;
+
+ for (y = 0; y < imDst->ysize; y++) {
+ rgba8* dst = (rgba8*) imDst->image[y];
+ rgba8* src = (rgba8*) imSrc->image[y];
+ rgba8* out = (rgba8*) imOut->image[y];
+
+ for (x = 0; x < imDst->xsize; x ++) {
+ if (src->a == 0) {
+ // Copy 4 bytes at once.
+ *out = *dst;
+ } else {
+ // Integer implementation with increased precision.
+ // Each variable has extra meaningful bits.
+ // Divisions are rounded.
+
+ UINT32 tmpr, tmpg, tmpb;
+ UINT32 blend = dst->a * (255 - src->a);
+ UINT32 outa255 = src->a * 255 + blend;
+ // There we use 7 bits for precision.
+ // We could use more, but we go beyond 32 bits.
+ UINT32 coef1 = src->a * 255 * 255 * (1<<PRECISION_BITS) / outa255;
+ UINT32 coef2 = 255 * (1<<PRECISION_BITS) - coef1;
+
+ tmpr = src->r * coef1 + dst->r * coef2;
+ tmpg = src->g * coef1 + dst->g * coef2;
+ tmpb = src->b * coef1 + dst->b * coef2;
+ out->r = SHIFTFORDIV255(tmpr + (0x80<<PRECISION_BITS)) >> PRECISION_BITS;
+ out->g = SHIFTFORDIV255(tmpg + (0x80<<PRECISION_BITS)) >> PRECISION_BITS;
+ out->b = SHIFTFORDIV255(tmpb + (0x80<<PRECISION_BITS)) >> PRECISION_BITS;
+ out->a = SHIFTFORDIV255(outa255 + 0x80);
+ }
+
+ dst++; src++; out++;
+ }
+
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Bands.c b/contrib/python/Pillow/py2/libImaging/Bands.c
new file mode 100644
index 0000000000..7fff044863
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Bands.c
@@ -0,0 +1,310 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * stuff to extract and paste back individual bands
+ *
+ * history:
+ * 1996-03-20 fl Created
+ * 1997-08-27 fl Fixed putband for single band targets.
+ * 2003-09-26 fl Fixed getband/putband for 2-band images (LA, PA).
+ *
+ * Copyright (c) 1997-2003 by Secret Labs AB.
+ * Copyright (c) 1996-1997 by Fredrik Lundh.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+Imaging
+ImagingGetBand(Imaging imIn, int band)
+{
+ Imaging imOut;
+ int x, y;
+
+ /* Check arguments */
+ if (!imIn || imIn->type != IMAGING_TYPE_UINT8)
+ return (Imaging) ImagingError_ModeError();
+
+ if (band < 0 || band >= imIn->bands)
+ return (Imaging) ImagingError_ValueError("band index out of range");
+
+ /* Shortcuts */
+ if (imIn->bands == 1)
+ return ImagingCopy(imIn);
+
+ /* Special case for LXXA etc */
+ if (imIn->bands == 2 && band == 1)
+ band = 3;
+
+ imOut = ImagingNewDirty("L", imIn->xsize, imIn->ysize);
+ if (!imOut)
+ return NULL;
+
+ /* Extract band from image */
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = (UINT8*) imIn->image[y] + band;
+ UINT8* out = imOut->image8[y];
+ x = 0;
+ for (; x < imIn->xsize - 3; x += 4) {
+ UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
+ memcpy(out + x, &v, sizeof(v));
+ in += 16;
+ }
+ for (; x < imIn->xsize; x++) {
+ out[x] = *in;
+ in += 4;
+ }
+ }
+
+ return imOut;
+}
+
+
+int
+ImagingSplit(Imaging imIn, Imaging bands[4])
+{
+ int i, j, x, y;
+
+ /* Check arguments */
+ if (!imIn || imIn->type != IMAGING_TYPE_UINT8) {
+ (void) ImagingError_ModeError();
+ return 0;
+ }
+
+ /* Shortcuts */
+ if (imIn->bands == 1) {
+ bands[0] = ImagingCopy(imIn);
+ return imIn->bands;
+ }
+
+ for (i = 0; i < imIn->bands; i++) {
+ bands[i] = ImagingNewDirty("L", imIn->xsize, imIn->ysize);
+ if ( ! bands[i]) {
+ for (j = 0; j < i; ++j) {
+ ImagingDelete(bands[j]);
+ }
+ return 0;
+ }
+ }
+
+ /* Extract bands from image */
+ if (imIn->bands == 2) {
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out0 = bands[0]->image8[y];
+ UINT8* out1 = bands[1]->image8[y];
+ x = 0;
+ for (; x < imIn->xsize - 3; x += 4) {
+ UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
+ memcpy(out0 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0+3], in[4+3], in[8+3], in[12+3]);
+ memcpy(out1 + x, &v, sizeof(v));
+ in += 16;
+ }
+ for (; x < imIn->xsize; x++) {
+ out0[x] = in[0];
+ out1[x] = in[3];
+ in += 4;
+ }
+ }
+ } else if (imIn->bands == 3) {
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out0 = bands[0]->image8[y];
+ UINT8* out1 = bands[1]->image8[y];
+ UINT8* out2 = bands[2]->image8[y];
+ x = 0;
+ for (; x < imIn->xsize - 3; x += 4) {
+ UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
+ memcpy(out0 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0+1], in[4+1], in[8+1], in[12+1]);
+ memcpy(out1 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0+2], in[4+2], in[8+2], in[12+2]);
+ memcpy(out2 + x, &v, sizeof(v));
+ in += 16;
+ }
+ for (; x < imIn->xsize; x++) {
+ out0[x] = in[0];
+ out1[x] = in[1];
+ out2[x] = in[2];
+ in += 4;
+ }
+ }
+ } else {
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out0 = bands[0]->image8[y];
+ UINT8* out1 = bands[1]->image8[y];
+ UINT8* out2 = bands[2]->image8[y];
+ UINT8* out3 = bands[3]->image8[y];
+ x = 0;
+ for (; x < imIn->xsize - 3; x += 4) {
+ UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
+ memcpy(out0 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0+1], in[4+1], in[8+1], in[12+1]);
+ memcpy(out1 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0+2], in[4+2], in[8+2], in[12+2]);
+ memcpy(out2 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0+3], in[4+3], in[8+3], in[12+3]);
+ memcpy(out3 + x, &v, sizeof(v));
+ in += 16;
+ }
+ for (; x < imIn->xsize; x++) {
+ out0[x] = in[0];
+ out1[x] = in[1];
+ out2[x] = in[2];
+ out3[x] = in[3];
+ in += 4;
+ }
+ }
+ }
+
+ return imIn->bands;
+}
+
+
+Imaging
+ImagingPutBand(Imaging imOut, Imaging imIn, int band)
+{
+ int x, y;
+
+ /* Check arguments */
+ if (!imIn || imIn->bands != 1 || !imOut)
+ return (Imaging) ImagingError_ModeError();
+
+ if (band < 0 || band >= imOut->bands)
+ return (Imaging) ImagingError_ValueError("band index out of range");
+
+ if (imIn->type != imOut->type ||
+ imIn->xsize != imOut->xsize ||
+ imIn->ysize != imOut->ysize)
+ return (Imaging) ImagingError_Mismatch();
+
+ /* Shortcuts */
+ if (imOut->bands == 1)
+ return ImagingCopy2(imOut, imIn);
+
+ /* Special case for LXXA etc */
+ if (imOut->bands == 2 && band == 1)
+ band = 3;
+
+ /* Insert band into image */
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = imIn->image8[y];
+ UINT8* out = (UINT8*) imOut->image[y] + band;
+ for (x = 0; x < imIn->xsize; x++) {
+ *out = in[x];
+ out += 4;
+ }
+ }
+
+ return imOut;
+}
+
+Imaging
+ImagingFillBand(Imaging imOut, int band, int color)
+{
+ int x, y;
+
+ /* Check arguments */
+ if (!imOut || imOut->type != IMAGING_TYPE_UINT8)
+ return (Imaging) ImagingError_ModeError();
+
+ if (band < 0 || band >= imOut->bands)
+ return (Imaging) ImagingError_ValueError("band index out of range");
+
+ /* Special case for LXXA etc */
+ if (imOut->bands == 2 && band == 1)
+ band = 3;
+
+ color = CLIP8(color);
+
+ /* Insert color into image */
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8* out = (UINT8*) imOut->image[y] + band;
+ for (x = 0; x < imOut->xsize; x++) {
+ *out = (UINT8) color;
+ out += 4;
+ }
+ }
+
+ return imOut;
+}
+
+Imaging
+ImagingMerge(const char* mode, Imaging bands[4])
+{
+ int i, x, y;
+ int bandsCount = 0;
+ Imaging imOut;
+ Imaging firstBand;
+
+ firstBand = bands[0];
+ if ( ! firstBand) {
+ return (Imaging) ImagingError_ValueError("wrong number of bands");
+ }
+
+ for (i = 0; i < 4; ++i) {
+ if ( ! bands[i]) {
+ break;
+ }
+ if (bands[i]->bands != 1) {
+ return (Imaging) ImagingError_ModeError();
+ }
+ if (bands[i]->xsize != firstBand->xsize
+ || bands[i]->ysize != firstBand->ysize) {
+ return (Imaging) ImagingError_Mismatch();
+ }
+ }
+ bandsCount = i;
+
+ imOut = ImagingNewDirty(mode, firstBand->xsize, firstBand->ysize);
+ if ( ! imOut)
+ return NULL;
+
+ if (imOut->bands != bandsCount) {
+ ImagingDelete(imOut);
+ return (Imaging) ImagingError_ValueError("wrong number of bands");
+ }
+
+ if (imOut->bands == 1)
+ return ImagingCopy2(imOut, firstBand);
+
+ if (imOut->bands == 2) {
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8* in0 = bands[0]->image8[y];
+ UINT8* in1 = bands[1]->image8[y];
+ UINT32* out = (UINT32*) imOut->image32[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ out[x] = MAKE_UINT32(in0[x], 0, 0, in1[x]);
+ }
+ }
+ } else if (imOut->bands == 3) {
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8* in0 = bands[0]->image8[y];
+ UINT8* in1 = bands[1]->image8[y];
+ UINT8* in2 = bands[2]->image8[y];
+ UINT32* out = (UINT32*) imOut->image32[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], 0);
+ }
+ }
+ } else if (imOut->bands == 4) {
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8* in0 = bands[0]->image8[y];
+ UINT8* in1 = bands[1]->image8[y];
+ UINT8* in2 = bands[2]->image8[y];
+ UINT8* in3 = bands[3]->image8[y];
+ UINT32* out = (UINT32*) imOut->image32[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], in3[x]);
+ }
+ }
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/BcnDecode.c b/contrib/python/Pillow/py2/libImaging/BcnDecode.c
new file mode 100644
index 0000000000..c2c4f21e7c
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/BcnDecode.c
@@ -0,0 +1,856 @@
+/*
+ * The Python Imaging Library
+ *
+ * decoder for DXTn-compressed data
+ *
+ * Format documentation:
+ * https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt
+ *
+ * The contents of this file are in the public domain (CC0)
+ * Full text of the CC0 license:
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+#include "Imaging.h"
+
+
+typedef struct {
+ UINT8 r, g, b, a;
+} rgba;
+
+typedef struct {
+ UINT8 l;
+} lum;
+
+typedef struct {
+ FLOAT32 r, g, b;
+} rgb32f;
+
+typedef struct {
+ UINT16 c0, c1;
+ UINT32 lut;
+} bc1_color;
+
+typedef struct {
+ UINT8 a0, a1;
+ UINT8 lut[6];
+} bc3_alpha;
+
+#define LOAD16(p) \
+ (p)[0] | ((p)[1] << 8)
+
+#define LOAD32(p) \
+ (p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24)
+
+static void bc1_color_load(bc1_color *dst, const UINT8 *src) {
+ dst->c0 = LOAD16(src);
+ dst->c1 = LOAD16(src + 2);
+ dst->lut = LOAD32(src + 4);
+}
+
+static void bc3_alpha_load(bc3_alpha *dst, const UINT8 *src) {
+ memcpy(dst, src, sizeof(bc3_alpha));
+}
+
+static rgba decode_565(UINT16 x) {
+ rgba c;
+ int r, g, b;
+ r = (x & 0xf800) >> 8;
+ r |= r >> 5;
+ c.r = r;
+ g = (x & 0x7e0) >> 3;
+ g |= g >> 6;
+ c.g = g;
+ b = (x & 0x1f) << 3;
+ b |= b >> 5;
+ c.b = b;
+ c.a = 0xff;
+ return c;
+}
+
+static void decode_bc1_color(rgba *dst, const UINT8 *src) {
+ bc1_color col;
+ rgba p[4];
+ int n, cw;
+ UINT16 r0, g0, b0, r1, g1, b1;
+ bc1_color_load(&col, src);
+
+ p[0] = decode_565(col.c0);
+ r0 = p[0].r;
+ g0 = p[0].g;
+ b0 = p[0].b;
+ p[1] = decode_565(col.c1);
+ r1 = p[1].r;
+ g1 = p[1].g;
+ b1 = p[1].b;
+ if (col.c0 > col.c1) {
+ p[2].r = (2*r0 + 1*r1) / 3;
+ p[2].g = (2*g0 + 1*g1) / 3;
+ p[2].b = (2*b0 + 1*b1) / 3;
+ p[2].a = 0xff;
+ p[3].r = (1*r0 + 2*r1) / 3;
+ p[3].g = (1*g0 + 2*g1) / 3;
+ p[3].b = (1*b0 + 2*b1) / 3;
+ p[3].a = 0xff;
+ } else {
+ p[2].r = (r0 + r1) / 2;
+ p[2].g = (g0 + g1) / 2;
+ p[2].b = (b0 + b1) / 2;
+ p[2].a = 0xff;
+ p[3].r = 0;
+ p[3].g = 0;
+ p[3].b = 0;
+ p[3].a = 0;
+ }
+ for (n = 0; n < 16; n++) {
+ cw = 3 & (col.lut >> (2 * n));
+ dst[n] = p[cw];
+ }
+}
+
+static void decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o) {
+ bc3_alpha b;
+ UINT16 a0, a1;
+ UINT8 a[8];
+ int n, lut, aw;
+ bc3_alpha_load(&b, src);
+
+ a0 = b.a0;
+ a1 = b.a1;
+ a[0] = (UINT8)a0;
+ a[1] = (UINT8)a1;
+ if (a0 > a1) {
+ a[2] = (6*a0 + 1*a1) / 7;
+ a[3] = (5*a0 + 2*a1) / 7;
+ a[4] = (4*a0 + 3*a1) / 7;
+ a[5] = (3*a0 + 4*a1) / 7;
+ a[6] = (2*a0 + 5*a1) / 7;
+ a[7] = (1*a0 + 6*a1) / 7;
+ } else {
+ a[2] = (4*a0 + 1*a1) / 5;
+ a[3] = (3*a0 + 2*a1) / 5;
+ a[4] = (2*a0 + 3*a1) / 5;
+ a[5] = (1*a0 + 4*a1) / 5;
+ a[6] = 0;
+ a[7] = 0xff;
+ }
+ lut = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16);
+ for (n = 0; n < 8; n++) {
+ aw = 7 & (lut >> (3 * n));
+ dst[stride * n + o] = a[aw];
+ }
+ lut = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16);
+ for (n = 0; n < 8; n++) {
+ aw = 7 & (lut >> (3 * n));
+ dst[stride * (8+n) + o] = a[aw];
+ }
+}
+
+static void decode_bc1_block(rgba *col, const UINT8* src) {
+ decode_bc1_color(col, src);
+}
+
+static void decode_bc2_block(rgba *col, const UINT8* src) {
+ int n, bitI, byI, av;
+ decode_bc1_color(col, src + 8);
+ for (n = 0; n < 16; n++) {
+ bitI = n * 4;
+ byI = bitI >> 3;
+ av = 0xf & (src[byI] >> (bitI & 7));
+ av = (av << 4) | av;
+ col[n].a = av;
+ }
+}
+
+static void decode_bc3_block(rgba *col, const UINT8* src) {
+ decode_bc1_color(col, src + 8);
+ decode_bc3_alpha((char *)col, src, sizeof(col[0]), 3);
+}
+
+static void decode_bc4_block(lum *col, const UINT8* src) {
+ decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0);
+}
+
+static void decode_bc5_block(rgba *col, const UINT8* src) {
+ decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0);
+ decode_bc3_alpha((char *)col, src + 8, sizeof(col[0]), 1);
+}
+
+/* BC6 and BC7 are described here:
+ https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt */
+
+static UINT8 get_bit(const UINT8* src, int bit) {
+ int by = bit >> 3;
+ bit &= 7;
+ return (src[by] >> bit) & 1;
+}
+
+static UINT8 get_bits(const UINT8* src, int bit, int count) {
+ UINT8 v;
+ int x;
+ int by = bit >> 3;
+ bit &= 7;
+ if (!count) {
+ return 0;
+ }
+ if (bit + count <= 8) {
+ v = (src[by] >> bit) & ((1 << count) - 1);
+ } else {
+ x = src[by] | (src[by+1] << 8);
+ v = (x >> bit) & ((1 << count) - 1);
+ }
+ return v;
+}
+
+/* BC7 */
+typedef struct {
+ char ns;
+ char pb;
+ char rb;
+ char isb;
+ char cb;
+ char ab;
+ char epb;
+ char spb;
+ char ib;
+ char ib2;
+} bc7_mode_info;
+
+static const bc7_mode_info bc7_modes[] = {
+ {3, 4, 0, 0, 4, 0, 1, 0, 3, 0},
+ {2, 6, 0, 0, 6, 0, 0, 1, 3, 0},
+ {3, 6, 0, 0, 5, 0, 0, 0, 2, 0},
+ {2, 6, 0, 0, 7, 0, 1, 0, 2, 0},
+ {1, 0, 2, 1, 5, 6, 0, 0, 2, 3},
+ {1, 0, 2, 0, 7, 8, 0, 0, 2, 2},
+ {1, 0, 0, 0, 7, 7, 1, 0, 4, 0},
+ {2, 6, 0, 0, 5, 5, 1, 0, 2, 0}
+};
+
+/* Subset indices:
+ Table.P2, 1 bit per index */
+static const UINT16 bc7_si2[] = {
+ 0xcccc, 0x8888, 0xeeee, 0xecc8, 0xc880, 0xfeec, 0xfec8, 0xec80,
+ 0xc800, 0xffec, 0xfe80, 0xe800, 0xffe8, 0xff00, 0xfff0, 0xf000,
+ 0xf710, 0x008e, 0x7100, 0x08ce, 0x008c, 0x7310, 0x3100, 0x8cce,
+ 0x088c, 0x3110, 0x6666, 0x366c, 0x17e8, 0x0ff0, 0x718e, 0x399c,
+ 0xaaaa, 0xf0f0, 0x5a5a, 0x33cc, 0x3c3c, 0x55aa, 0x9696, 0xa55a,
+ 0x73ce, 0x13c8, 0x324c, 0x3bdc, 0x6996, 0xc33c, 0x9966, 0x0660,
+ 0x0272, 0x04e4, 0x4e40, 0x2720, 0xc936, 0x936c, 0x39c6, 0x639c,
+ 0x9336, 0x9cc6, 0x817e, 0xe718, 0xccf0, 0x0fcc, 0x7744, 0xee22};
+
+/* Table.P3, 2 bits per index */
+static const UINT32 bc7_si3[] = {
+ 0xaa685050, 0x6a5a5040, 0x5a5a4200, 0x5450a0a8,
+ 0xa5a50000, 0xa0a05050, 0x5555a0a0, 0x5a5a5050,
+ 0xaa550000, 0xaa555500, 0xaaaa5500, 0x90909090,
+ 0x94949494, 0xa4a4a4a4, 0xa9a59450, 0x2a0a4250,
+ 0xa5945040, 0x0a425054, 0xa5a5a500, 0x55a0a0a0,
+ 0xa8a85454, 0x6a6a4040, 0xa4a45000, 0x1a1a0500,
+ 0x0050a4a4, 0xaaa59090, 0x14696914, 0x69691400,
+ 0xa08585a0, 0xaa821414, 0x50a4a450, 0x6a5a0200,
+ 0xa9a58000, 0x5090a0a8, 0xa8a09050, 0x24242424,
+ 0x00aa5500, 0x24924924, 0x24499224, 0x50a50a50,
+ 0x500aa550, 0xaaaa4444, 0x66660000, 0xa5a0a5a0,
+ 0x50a050a0, 0x69286928, 0x44aaaa44, 0x66666600,
+ 0xaa444444, 0x54a854a8, 0x95809580, 0x96969600,
+ 0xa85454a8, 0x80959580, 0xaa141414, 0x96960000,
+ 0xaaaa1414, 0xa05050a0, 0xa0a5a5a0, 0x96000000,
+ 0x40804080, 0xa9a8a9a8, 0xaaaaaa44, 0x2a4a5254};
+
+/* Anchor indices:
+ Table.A2 */
+static const char bc7_ai0[] = {
+ 15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,
+ 15, 2, 8, 2, 2, 8, 8,15,
+ 2, 8, 2, 2, 8, 8, 2, 2,
+ 15,15, 6, 8, 2, 8,15,15,
+ 2, 8, 2, 2, 2,15,15, 6,
+ 6, 2, 6, 8,15,15, 2, 2,
+ 15,15,15,15,15, 2, 2,15};
+
+/* Table.A3a */
+static const char bc7_ai1[] = {
+ 3, 3,15,15, 8, 3,15,15,
+ 8, 8, 6, 6, 6, 5, 3, 3,
+ 3, 3, 8,15, 3, 3, 6,10,
+ 5, 8, 8, 6, 8, 5,15,15,
+ 8,15, 3, 5, 6,10, 8,15,
+ 15, 3,15, 5,15,15,15,15,
+ 3,15, 5, 5, 5, 8, 5,10,
+ 5,10, 8,13,15,12, 3, 3};
+
+/* Table.A3b */
+static const char bc7_ai2[] = {
+ 15, 8, 8, 3,15,15, 3, 8,
+ 15,15,15,15,15,15,15, 8,
+ 15, 8,15, 3,15, 8,15, 8,
+ 3,15, 6,10,15,15,10, 8,
+ 15, 3,15,10,10, 8, 9,10,
+ 6,15, 8,15, 3, 6, 6, 8,
+ 15, 3,15,15,15,15,15,15,
+ 15,15,15,15, 3,15,15, 8};
+
+/* Interpolation weights */
+static const char bc7_weights2[] = {0, 21, 43, 64};
+static const char bc7_weights3[] = {0, 9, 18, 27, 37, 46, 55, 64};
+static const char bc7_weights4[] = {
+ 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64};
+
+static const char *bc7_get_weights(int n) {
+ if (n == 2) {
+ return bc7_weights2;
+ }
+ if (n == 3) {
+ return bc7_weights3;
+ }
+ return bc7_weights4;
+}
+
+static int bc7_get_subset(int ns, int partition, int n) {
+ if (ns == 2) {
+ return 1 & (bc7_si2[partition] >> n);
+ }
+ if (ns == 3) {
+ return 3 & (bc7_si3[partition] >> (2 * n));
+ }
+ return 0;
+}
+
+static UINT8 expand_quantized(UINT8 v, int bits) {
+ v = v << (8 - bits);
+ return v | (v >> bits);
+}
+
+static void bc7_lerp(rgba *dst, const rgba *e, int s0, int s1) {
+ int t0 = 64 - s0;
+ int t1 = 64 - s1;
+ dst->r = (UINT8)((t0 * e[0].r + s0 * e[1].r + 32) >> 6);
+ dst->g = (UINT8)((t0 * e[0].g + s0 * e[1].g + 32) >> 6);
+ dst->b = (UINT8)((t0 * e[0].b + s0 * e[1].b + 32) >> 6);
+ dst->a = (UINT8)((t1 * e[0].a + s1 * e[1].a + 32) >> 6);
+}
+
+static void decode_bc7_block(rgba *col, const UINT8* src) {
+ rgba endpoints[6];
+ int bit = 0, cibit, aibit;
+ int mode = src[0];
+ int i, j;
+ int numep, cb, ab, ib, ib2, i0, i1, s;
+ UINT8 index_sel, partition, rotation, val;
+ const char *cw, *aw;
+ const bc7_mode_info *info;
+
+ /* mode is the number of unset bits before the first set bit: */
+ if (!mode) {
+ /* degenerate case when no bits set */
+ for (i = 0; i < 16; i++) {
+ col[i].r = col[i].g = col[i].b = 0;
+ col[i].a = 255;
+ }
+ return;
+ }
+ while (!(mode & (1 << bit++))) ;
+ mode = bit - 1;
+ info = &bc7_modes[mode];
+ /* color selection bits: {subset}{endpoint} */
+ cb = info->cb;
+ ab = info->ab;
+ cw = bc7_get_weights(info->ib);
+ aw = bc7_get_weights((ab && info->ib2) ? info->ib2 : info->ib);
+
+#define LOAD(DST, N) \
+ DST = get_bits(src, bit, N); \
+ bit += N;
+ LOAD(partition, info->pb);
+ LOAD(rotation, info->rb);
+ LOAD(index_sel, info->isb);
+ numep = info->ns << 1;
+
+ /* red */
+ for (i = 0; i < numep; i++) {
+ LOAD(val, cb);
+ endpoints[i].r = val;
+ }
+
+ /* green */
+ for (i = 0; i < numep; i++) {
+ LOAD(val, cb);
+ endpoints[i].g = val;
+ }
+
+ /* blue */
+ for (i = 0; i < numep; i++) {
+ LOAD(val, cb);
+ endpoints[i].b = val;
+ }
+
+ /* alpha */
+ for (i = 0; i < numep; i++) {
+ if (ab) {
+ LOAD(val, ab);
+ } else {
+ val = 255;
+ }
+ endpoints[i].a = val;
+ }
+
+ /* p-bits */
+#define ASSIGN_P(x) x = (x << 1) | val
+ if (info->epb) {
+ /* per endpoint */
+ cb++;
+ if (ab) {
+ ab++;
+ }
+ for (i = 0; i < numep; i++) {
+ LOAD(val, 1);
+ ASSIGN_P(endpoints[i].r);
+ ASSIGN_P(endpoints[i].g);
+ ASSIGN_P(endpoints[i].b);
+ if (ab) {
+ ASSIGN_P(endpoints[i].a);
+ }
+ }
+ }
+ if (info->spb) {
+ /* per subset */
+ cb++;
+ if (ab) {
+ ab++;
+ }
+ for (i = 0; i < numep; i+=2) {
+ LOAD(val, 1);
+ for (j = 0; j < 2; j++) {
+ ASSIGN_P(endpoints[i+j].r);
+ ASSIGN_P(endpoints[i+j].g);
+ ASSIGN_P(endpoints[i+j].b);
+ if (ab) {
+ ASSIGN_P(endpoints[i+j].a);
+ }
+ }
+ }
+ }
+#undef ASSIGN_P
+#define EXPAND(x, b) x = expand_quantized(x, b)
+ for (i = 0; i < numep; i++) {
+ EXPAND(endpoints[i].r, cb);
+ EXPAND(endpoints[i].g, cb);
+ EXPAND(endpoints[i].b, cb);
+ if (ab) {
+ EXPAND(endpoints[i].a, ab);
+ }
+ }
+#undef EXPAND
+#undef LOAD
+ cibit = bit;
+ aibit = cibit + 16 * info->ib - info->ns;
+ for (i = 0; i < 16; i++) {
+ s = bc7_get_subset(info->ns, partition, i) << 1;
+ ib = info->ib;
+ if (i == 0) {
+ ib--;
+ } else if (info->ns == 2) {
+ if (i == bc7_ai0[partition]) {
+ ib--;
+ }
+ } else if (info->ns == 3) {
+ if (i == bc7_ai1[partition]) {
+ ib--;
+ } else if (i == bc7_ai2[partition]) {
+ ib--;
+ }
+ }
+ i0 = get_bits(src, cibit, ib);
+ cibit += ib;
+
+ if (ab && info->ib2) {
+ ib2 = info->ib2;
+ if (ib2 && i == 0) {
+ ib2--;
+ }
+ i1 = get_bits(src, aibit, ib2);
+ aibit += ib2;
+ if (index_sel) {
+ bc7_lerp(&col[i], &endpoints[s], aw[i1], cw[i0]);
+ } else {
+ bc7_lerp(&col[i], &endpoints[s], cw[i0], aw[i1]);
+ }
+ } else {
+ bc7_lerp(&col[i], &endpoints[s], cw[i0], cw[i0]);
+ }
+#define ROTATE(x, y) \
+ val = x; \
+ x = y; \
+ y = val
+ if (rotation == 1) {
+ ROTATE(col[i].r, col[i].a);
+ } else if (rotation == 2) {
+ ROTATE(col[i].g, col[i].a);
+ } else if (rotation == 3) {
+ ROTATE(col[i].b, col[i].a);
+ }
+#undef ROTATE
+ }
+}
+
+/* BC6 */
+typedef struct {
+ char ns; /* number of subsets (also called regions) */
+ char tr; /* whether endpoints are delta-compressed */
+ char pb; /* partition bits */
+ char epb; /* endpoint bits */
+ char rb; /* red bits (delta) */
+ char gb; /* green bits (delta) */
+ char bb; /* blue bits (delta) */
+} bc6_mode_info;
+
+static const bc6_mode_info bc6_modes[] = {
+ // 00
+ {2, 1, 5, 10, 5, 5, 5},
+ // 01
+ {2, 1, 5, 7, 6, 6, 6},
+ // 10
+ {2, 1, 5, 11, 5, 4, 4},
+ {2, 1, 5, 11, 4, 5, 4},
+ {2, 1, 5, 11, 4, 4, 5},
+ {2, 1, 5, 9, 5, 5, 5},
+ {2, 1, 5, 8, 6, 5, 5},
+ {2, 1, 5, 8, 5, 6, 5},
+ {2, 1, 5, 8, 5, 5, 6},
+ {2, 0, 5, 6, 6, 6, 6},
+ // 11
+ {1, 0, 0, 10, 10, 10, 10},
+ {1, 1, 0, 11, 9, 9, 9},
+ {1, 1, 0, 12, 8, 8, 8},
+ {1, 1, 0, 16, 4, 4, 4}
+};
+
+/* Table.F, encoded as a sequence of bit indices */
+static const UINT8 bc6_bit_packings[][75] = {
+ {116, 132, 176, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52,
+ 164, 112, 113, 114, 115, 64, 65, 66, 67, 68, 172, 160, 161, 162, 163, 80,
+ 81, 82, 83, 84, 173, 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144,
+ 145, 146, 147, 148, 175},
+ {117, 164, 165, 0, 1, 2, 3, 4, 5, 6, 172, 173, 132, 16, 17, 18, 19, 20, 21,
+ 22, 133, 174, 116, 32, 33, 34, 35, 36, 37, 38, 175, 177, 176, 48, 49, 50,
+ 51, 52, 53, 112, 113, 114, 115, 64, 65, 66, 67, 68, 69, 160, 161, 162, 163,
+ 80, 81, 82, 83, 84, 85, 128, 129, 130, 131, 96, 97, 98, 99, 100, 101, 144,
+ 145, 146, 147, 148, 149},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 10, 112, 113, 114,
+ 115, 64, 65, 66, 67, 26, 172, 160, 161, 162, 163, 80, 81, 82, 83, 42, 173,
+ 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148,
+ 175},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 10, 164, 112, 113, 114,
+ 115, 64, 65, 66, 67, 68, 26, 160, 161, 162, 163, 80, 81, 82, 83, 42, 173,
+ 128, 129, 130, 131, 96, 97, 98, 99, 172, 174, 144, 145, 146, 147, 116,
+ 175},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 10, 132, 112, 113, 114,
+ 115, 64, 65, 66, 67, 26, 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 42,
+ 128, 129, 130, 131, 96, 97, 98, 99, 173, 174, 144, 145, 146, 147, 176,
+ 175},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 132, 16, 17, 18, 19, 20, 21, 22, 23, 24, 116,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 176, 48, 49, 50, 51, 52, 164, 112, 113,
+ 114, 115, 64, 65, 66, 67, 68, 172, 160, 161, 162, 163, 80, 81, 82, 83, 84,
+ 173, 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148,
+ 175},
+ {0, 1, 2, 3, 4, 5, 6, 7, 164, 132, 16, 17, 18, 19, 20, 21, 22, 23, 174, 116,
+ 32, 33, 34, 35, 36, 37, 38, 39, 175, 176, 48, 49, 50, 51, 52, 53, 112, 113,
+ 114, 115, 64, 65, 66, 67, 68, 172, 160, 161, 162, 163, 80, 81, 82, 83, 84,
+ 173, 128, 129, 130, 131, 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148,
+ 149},
+ {0, 1, 2, 3, 4, 5, 6, 7, 172, 132, 16, 17, 18, 19, 20, 21, 22, 23, 117, 116,
+ 32, 33, 34, 35, 36, 37, 38, 39, 165, 176, 48, 49, 50, 51, 52, 164, 112,
+ 113, 114, 115, 64, 65, 66, 67, 68, 69, 160, 161, 162, 163, 80, 81, 82, 83,
+ 84, 173, 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147,
+ 148, 175},
+ {0, 1, 2, 3, 4, 5, 6, 7, 173, 132, 16, 17, 18, 19, 20, 21, 22, 23, 133, 116,
+ 32, 33, 34, 35, 36, 37, 38, 39, 177, 176, 48, 49, 50, 51, 52, 164, 112,
+ 113, 114, 115, 64, 65, 66, 67, 68, 172, 160, 161, 162, 163, 80, 81, 82, 83,
+ 84, 85, 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147,
+ 148, 175},
+ {0, 1, 2, 3, 4, 5, 164, 172, 173, 132, 16, 17, 18, 19, 20, 21, 117, 133,
+ 174, 116, 32, 33, 34, 35, 36, 37, 165, 175, 177, 176, 48, 49, 50, 51, 52,
+ 53, 112, 113, 114, 115, 64, 65, 66, 67, 68, 69, 160, 161, 162, 163, 80, 81,
+ 82, 83, 84, 85, 128, 129, 130, 131, 96, 97, 98, 99, 100, 101, 144, 145,
+ 146, 147, 148, 149},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+ 89},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 10,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 26, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+ 42},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 11, 10,
+ 64, 65, 66, 67, 68, 69, 70, 71, 27, 26, 80, 81, 82, 83, 84, 85, 86, 87, 43,
+ 42},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 15, 14, 13, 12, 11, 10,
+ 64, 65, 66, 67, 31, 30, 29, 28, 27, 26, 80, 81, 82, 83, 47, 46, 45, 44, 43,
+ 42}};
+
+static void bc6_sign_extend(UINT16 *v, int prec) {
+ int x = *v;
+ if (x & (1 << (prec - 1))) {
+ x |= -1 << prec;
+ }
+ *v = (UINT16)x;
+}
+
+static int bc6_unquantize(UINT16 v, int prec, int sign) {
+ int s = 0;
+ int x;
+ if (!sign) {
+ x = v;
+ if (prec >= 15) return x;
+ if (x == 0) return 0;
+ if (x == ((1 << prec) - 1)) {
+ return 0xffff;
+ }
+ return ((x << 15) + 0x4000) >> (prec - 1);
+ } else {
+ x = (INT16)v;
+ if (prec >= 16) return x;
+ if (x < 0) {
+ s = 1;
+ x = -x;
+ }
+
+ if (x != 0) {
+ if (x >= ((1 << (prec - 1)) - 1)) {
+ x = 0x7fff;
+ } else {
+ x = ((x << 15) + 0x4000) >> (prec - 1);
+ }
+ }
+
+ if (s) {
+ return -x;
+ }
+ return x;
+ }
+}
+
+static float half_to_float(UINT16 h) {
+ /* https://gist.github.com/rygorous/2144712 */
+ union {
+ UINT32 u;
+ float f;
+ } o, m;
+ m.u = 0x77800000;
+ o.u = (h & 0x7fff) << 13;
+ o.f *= m.f;
+ m.u = 0x47800000;
+ if (o.f >= m.f) {
+ o.u |= 255 << 23;
+ }
+ o.u |= (h & 0x8000) << 16;
+ return o.f;
+}
+
+static float bc6_finalize(int v, int sign) {
+ if (sign) {
+ if (v < 0) {
+ v = ((-v) * 31) / 32;
+ return half_to_float((UINT16)(0x8000 | v));
+ } else {
+ return half_to_float((UINT16)((v * 31) / 32));
+ }
+ } else {
+ return half_to_float((UINT16)((v * 31) / 64));
+ }
+}
+
+static void bc6_lerp(rgb32f *col, int *e0, int *e1, int s, int sign) {
+ int r, g, b;
+ int t = 64 - s;
+ r = (e0[0] * t + e1[0] * s) >> 6;
+ g = (e0[1] * t + e1[1] * s) >> 6;
+ b = (e0[2] * t + e1[2] * s) >> 6;
+ col->r = bc6_finalize(r, sign);
+ col->g = bc6_finalize(g, sign);
+ col->b = bc6_finalize(b, sign);
+}
+
+static void decode_bc6_block(rgb32f *col, const UINT8* src, int sign) {
+ UINT16 endpoints[12]; /* storage for r0, g0, b0, r1, ... */
+ int ueps[12];
+ int i, i0, ib2, di, dw, mask, numep, s;
+ UINT8 partition;
+ const bc6_mode_info *info;
+ const char *cw;
+ int bit = 5;
+ int epbits = 75;
+ int ib = 3;
+ int mode = src[0] & 0x1f;
+ if ((mode & 3) == 0 || (mode & 3) == 1) {
+ mode &= 3;
+ bit = 2;
+ } else if ((mode & 3) == 2) {
+ mode = 2 + (mode >> 2);
+ epbits = 72;
+ } else {
+ mode = 10 + (mode >> 2);
+ epbits = 60;
+ ib = 4;
+ }
+ if (mode >= 14) {
+ /* invalid block */
+ memset(col, 0, 16 * sizeof(col[0]));
+ return;
+ }
+ info = &bc6_modes[mode];
+ cw = bc7_get_weights(ib);
+ numep = info->ns == 2 ? 12 : 6;
+ for (i = 0; i < 12; i++) {
+ endpoints[i] = 0;
+ }
+ for (i = 0; i < epbits; i++) {
+ di = bc6_bit_packings[mode][i];
+ dw = di >> 4;
+ di &= 15;
+ endpoints[dw] |= (UINT16)get_bit(src, bit + i) << di;
+ }
+ bit += epbits;
+ partition = get_bits(src, bit, info->pb);
+ bit += info->pb;
+ mask = (1 << info->epb) - 1;
+ if (sign) { /* sign-extend e0 if signed */
+ bc6_sign_extend(&endpoints[0], info->epb);
+ bc6_sign_extend(&endpoints[1], info->epb);
+ bc6_sign_extend(&endpoints[2], info->epb);
+ }
+ if (sign || info->tr) { /* sign-extend e1,2,3 if signed or deltas */
+ for (i = 3; i < numep; i += 3) {
+ bc6_sign_extend(&endpoints[i+0], info->rb);
+ bc6_sign_extend(&endpoints[i+1], info->gb);
+ bc6_sign_extend(&endpoints[i+2], info->bb);
+ }
+ }
+ if (info->tr) { /* apply deltas */
+ for (i = 3; i < numep; i++) {
+ endpoints[i] = (endpoints[i] + endpoints[0]) & mask;
+ }
+ if (sign) {
+ for (i = 3; i < numep; i += 3) {
+ bc6_sign_extend(&endpoints[i+0], info->rb);
+ bc6_sign_extend(&endpoints[i+1], info->gb);
+ bc6_sign_extend(&endpoints[i+2], info->bb);
+ }
+ }
+ }
+ for (i = 0; i < numep; i++) {
+ ueps[i] = bc6_unquantize(endpoints[i], info->epb, sign);
+ }
+ for (i = 0; i < 16; i++) {
+ s = bc7_get_subset(info->ns, partition, i) * 6;
+ ib2 = ib;
+ if (i == 0) {
+ ib2--;
+ } else if (info->ns == 2) {
+ if (i == bc7_ai0[partition]) {
+ ib2--;
+ }
+ }
+ i0 = get_bits(src, bit, ib2);
+ bit += ib2;
+
+ bc6_lerp(&col[i], &ueps[s], &ueps[s+3], cw[i0], sign);
+ }
+}
+
+static void put_block(Imaging im, ImagingCodecState state, const char *col, int sz, int C) {
+ int width = state->xsize;
+ int height = state->ysize;
+ int xmax = width + state->xoff;
+ int ymax = height + state->yoff;
+ int j, i, y, x;
+ char *dst;
+ for (j = 0; j < 4; j++) {
+ y = state->y + j;
+ if (C) {
+ if (y >= height) {
+ continue;
+ }
+ if (state->ystep < 0) {
+ y = state->yoff + ymax - y - 1;
+ }
+ dst = im->image[y];
+ for (i = 0; i < 4; i++) {
+ x = state->x + i;
+ if (x >= width) {
+ continue;
+ }
+ memcpy(dst + sz*x, col + sz*(j*4 + i), sz);
+ }
+ } else {
+ if (state->ystep < 0) {
+ y = state->yoff + ymax - y - 1;
+ }
+ x = state->x;
+ dst = im->image[y] + sz*x;
+ memcpy(dst, col + sz*(j*4), 4 * sz);
+ }
+ }
+ state->x += 4;
+ if (state->x >= xmax) {
+ state->y += 4;
+ state->x = state->xoff;
+ }
+}
+
+static int decode_bcn(Imaging im, ImagingCodecState state, const UINT8* src, int bytes, int N, int C) {
+ int ymax = state->ysize + state->yoff;
+ const UINT8 *ptr = src;
+ switch (N) {
+#define DECODE_LOOP(NN, SZ, TY, ...) \
+ case NN: \
+ while (bytes >= SZ) { \
+ TY col[16]; \
+ memset(col, 0, 16 * sizeof(col[0])); \
+ decode_bc##NN##_block(col, ptr); \
+ put_block(im, state, (const char *)col, sizeof(col[0]), C); \
+ ptr += SZ; \
+ bytes -= SZ; \
+ if (state->y >= ymax) return -1; \
+ } \
+ break
+ DECODE_LOOP(1, 8, rgba);
+ DECODE_LOOP(2, 16, rgba);
+ DECODE_LOOP(3, 16, rgba);
+ DECODE_LOOP(4, 8, lum);
+ DECODE_LOOP(5, 16, rgba);
+ case 6:
+ while (bytes >= 16) {
+ rgb32f col[16];
+ decode_bc6_block(col, ptr, (state->state >> 4) & 1);
+ put_block(im, state, (const char *)col, sizeof(col[0]), C);
+ ptr += 16;
+ bytes -= 16;
+ if (state->y >= ymax) return -1; \
+ }
+ break;
+ DECODE_LOOP(7, 16, rgba);
+#undef DECODE_LOOP
+ }
+ return (int)(ptr - src);
+}
+
+int ImagingBcnDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) {
+ int N = state->state & 0xf;
+ int width = state->xsize;
+ int height = state->ysize;
+ if ((width & 3) | (height & 3)) {
+ return decode_bcn(im, state, buf, bytes, N, 1);
+ } else {
+ return decode_bcn(im, state, buf, bytes, N, 0);
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Bit.h b/contrib/python/Pillow/py2/libImaging/Bit.h
new file mode 100644
index 0000000000..56e3a17d2e
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Bit.h
@@ -0,0 +1,30 @@
+/* Bit.h */
+
+typedef struct {
+
+ /* CONFIGURATION */
+
+ /* Number of bits per pixel */
+ int bits;
+
+ /* Line padding (0 or 8) */
+ int pad;
+
+ /* Fill order */
+ /* 0=msb/msb, 1=msbfill/lsbshift, 2=lsbfill/msbshift, 3=lsb/lsb */
+ int fill;
+
+ /* Signed integers (0=unsigned, 1=signed) */
+ int sign;
+
+ /* Lookup table (not implemented) */
+ unsigned long lutsize;
+ FLOAT32* lut;
+
+ /* INTERNAL */
+ unsigned long mask;
+ unsigned long signmask;
+ unsigned long bitbuffer;
+ int bitcount;
+
+} BITSTATE;
diff --git a/contrib/python/Pillow/py2/libImaging/BitDecode.c b/contrib/python/Pillow/py2/libImaging/BitDecode.c
new file mode 100644
index 0000000000..7120b33213
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/BitDecode.c
@@ -0,0 +1,138 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for packed bitfields (converts to floating point)
+ *
+ * history:
+ * 97-05-31 fl created (much more than originally intended)
+ *
+ * Copyright (c) Fredrik Lundh 1997.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#include "Bit.h"
+
+
+int
+ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ BITSTATE* bitstate = state->context;
+ UINT8* ptr;
+
+ if (state->state == 0) {
+
+ /* Initialize context variables */
+
+ /* this decoder only works for float32 image buffers */
+ if (im->type != IMAGING_TYPE_FLOAT32) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ /* sanity check */
+ if (bitstate->bits < 1 || bitstate->bits >= 32) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ bitstate->mask = (1<<bitstate->bits)-1;
+
+ if (bitstate->sign)
+ bitstate->signmask = (1<<(bitstate->bits-1));
+
+ /* check image orientation */
+ if (state->ystep < 0) {
+ state->y = state->ysize-1;
+ state->ystep = -1;
+ } else
+ state->ystep = 1;
+
+ state->state = 1;
+
+ }
+
+ ptr = buf;
+
+ while (bytes > 0) {
+
+ UINT8 byte = *ptr;
+
+ ptr++;
+ bytes--;
+
+ /* get a byte from the input stream and insert in the bit buffer */
+ if (bitstate->fill&1)
+ /* fill MSB first */
+ bitstate->bitbuffer |= (unsigned long) byte << bitstate->bitcount;
+ else
+ /* fill LSB first */
+ bitstate->bitbuffer = (bitstate->bitbuffer << 8) | byte;
+
+ bitstate->bitcount += 8;
+
+ while (bitstate->bitcount >= bitstate->bits) {
+
+ /* get a pixel from the bit buffer */
+ unsigned long data;
+ FLOAT32 pixel;
+
+ if (bitstate->fill&2) {
+ /* store LSB first */
+ data = bitstate->bitbuffer & bitstate->mask;
+ if (bitstate->bitcount > 32)
+ /* bitbuffer overflow; restore it from last input byte */
+ bitstate->bitbuffer = byte >> (8 - (bitstate->bitcount -
+ bitstate->bits));
+ else
+ bitstate->bitbuffer >>= bitstate->bits;
+ } else
+ /* store MSB first */
+ data = (bitstate->bitbuffer >> (bitstate->bitcount -
+ bitstate->bits))
+ & bitstate->mask;
+
+ bitstate->bitcount -= bitstate->bits;
+
+ if (bitstate->lutsize > 0) {
+ /* map through lookup table */
+ if (data <= 0)
+ pixel = bitstate->lut[0];
+ else if (data >= bitstate->lutsize)
+ pixel = bitstate->lut[bitstate->lutsize-1];
+ else
+ pixel = bitstate->lut[data];
+ } else {
+ /* convert */
+ if (data & bitstate->signmask)
+ /* image memory contains signed data */
+ pixel = (FLOAT32) (INT32) (data | ~bitstate->mask);
+ else
+ pixel = (FLOAT32) data;
+ }
+
+ *(FLOAT32*)(&im->image32[state->y][state->x]) = pixel;
+
+ /* step forward */
+ if (++state->x >= state->xsize) {
+ /* new line */
+ state->y += state->ystep;
+ if (state->y < 0 || state->y >= state->ysize) {
+ /* end of file (errcode = 0) */
+ return -1;
+ }
+ state->x = 0;
+ /* reset bit buffer */
+ if (bitstate->pad > 0)
+ bitstate->bitcount = 0;
+ }
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Blend.c b/contrib/python/Pillow/py2/libImaging/Blend.c
new file mode 100644
index 0000000000..19a080d6d5
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Blend.c
@@ -0,0 +1,80 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * interpolate between two existing images
+ *
+ * history:
+ * 96-03-20 fl Created
+ * 96-05-18 fl Simplified blend expression
+ * 96-10-05 fl Fixed expression bug, special case for interpolation
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+Imaging
+ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha)
+{
+ Imaging imOut;
+ int x, y;
+
+ /* Check arguments */
+ if (!imIn1 || !imIn2 || imIn1->type != IMAGING_TYPE_UINT8
+ || imIn1->palette || strcmp(imIn1->mode, "1") == 0
+ || imIn2->palette || strcmp(imIn2->mode, "1") == 0)
+ return ImagingError_ModeError();
+
+ if (imIn1->type != imIn2->type ||
+ imIn1->bands != imIn2->bands ||
+ imIn1->xsize != imIn2->xsize ||
+ imIn1->ysize != imIn2->ysize)
+ return ImagingError_Mismatch();
+
+ /* Shortcuts */
+ if (alpha == 0.0)
+ return ImagingCopy(imIn1);
+ else if (alpha == 1.0)
+ return ImagingCopy(imIn2);
+
+ imOut = ImagingNewDirty(imIn1->mode, imIn1->xsize, imIn1->ysize);
+ if (!imOut)
+ return NULL;
+
+ if (alpha >= 0 && alpha <= 1.0) {
+ /* Interpolate between bands */
+ for (y = 0; y < imIn1->ysize; y++) {
+ UINT8* in1 = (UINT8*) imIn1->image[y];
+ UINT8* in2 = (UINT8*) imIn2->image[y];
+ UINT8* out = (UINT8*) imOut->image[y];
+ for (x = 0; x < imIn1->linesize; x++)
+ out[x] = (UINT8)
+ ((int) in1[x] + alpha * ((int) in2[x] - (int) in1[x]));
+ }
+ } else {
+ /* Extrapolation; must make sure to clip resulting values */
+ for (y = 0; y < imIn1->ysize; y++) {
+ UINT8* in1 = (UINT8*) imIn1->image[y];
+ UINT8* in2 = (UINT8*) imIn2->image[y];
+ UINT8* out = (UINT8*) imOut->image[y];
+ for (x = 0; x < imIn1->linesize; x++) {
+ float temp = (float)
+ ((int) in1[x] + alpha * ((int) in2[x] - (int) in1[x]));
+ if (temp <= 0.0)
+ out[x] = 0;
+ else if (temp >= 255.0)
+ out[x] = 255;
+ else
+ out[x] = (UINT8) temp;
+ }
+ }
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/BoxBlur.c b/contrib/python/Pillow/py2/libImaging/BoxBlur.c
new file mode 100644
index 0000000000..9537c4f98e
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/BoxBlur.c
@@ -0,0 +1,310 @@
+#include "Imaging.h"
+
+
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
+
+typedef UINT8 pixel[4];
+
+void static inline
+ImagingLineBoxBlur32(pixel *lineOut, pixel *lineIn, int lastx, int radius, int edgeA,
+ int edgeB, UINT32 ww, UINT32 fw)
+{
+ int x;
+ UINT32 acc[4];
+ UINT32 bulk[4];
+
+ #define MOVE_ACC(acc, subtract, add) \
+ acc[0] += lineIn[add][0] - lineIn[subtract][0]; \
+ acc[1] += lineIn[add][1] - lineIn[subtract][1]; \
+ acc[2] += lineIn[add][2] - lineIn[subtract][2]; \
+ acc[3] += lineIn[add][3] - lineIn[subtract][3];
+
+ #define ADD_FAR(bulk, acc, left, right) \
+ bulk[0] = (acc[0] * ww) + (lineIn[left][0] + lineIn[right][0]) * fw; \
+ bulk[1] = (acc[1] * ww) + (lineIn[left][1] + lineIn[right][1]) * fw; \
+ bulk[2] = (acc[2] * ww) + (lineIn[left][2] + lineIn[right][2]) * fw; \
+ bulk[3] = (acc[3] * ww) + (lineIn[left][3] + lineIn[right][3]) * fw;
+
+ #define SAVE(x, bulk) \
+ lineOut[x][0] = (UINT8)((bulk[0] + (1 << 23)) >> 24); \
+ lineOut[x][1] = (UINT8)((bulk[1] + (1 << 23)) >> 24); \
+ lineOut[x][2] = (UINT8)((bulk[2] + (1 << 23)) >> 24); \
+ lineOut[x][3] = (UINT8)((bulk[3] + (1 << 23)) >> 24);
+
+ /* Compute acc for -1 pixel (outside of image):
+ From "-radius-1" to "-1" get first pixel,
+ then from "0" to "radius-1". */
+ acc[0] = lineIn[0][0] * (radius + 1);
+ acc[1] = lineIn[0][1] * (radius + 1);
+ acc[2] = lineIn[0][2] * (radius + 1);
+ acc[3] = lineIn[0][3] * (radius + 1);
+ /* As radius can be bigger than xsize, iterate to edgeA -1. */
+ for (x = 0; x < edgeA - 1; x++) {
+ acc[0] += lineIn[x][0];
+ acc[1] += lineIn[x][1];
+ acc[2] += lineIn[x][2];
+ acc[3] += lineIn[x][3];
+ }
+ /* Then multiply remainder to last x. */
+ acc[0] += lineIn[lastx][0] * (radius - edgeA + 1);
+ acc[1] += lineIn[lastx][1] * (radius - edgeA + 1);
+ acc[2] += lineIn[lastx][2] * (radius - edgeA + 1);
+ acc[3] += lineIn[lastx][3] * (radius - edgeA + 1);
+
+ if (edgeA <= edgeB)
+ {
+ /* Subtract pixel from left ("0").
+ Add pixels from radius. */
+ for (x = 0; x < edgeA; x++) {
+ MOVE_ACC(acc, 0, x + radius);
+ ADD_FAR(bulk, acc, 0, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ /* Subtract previous pixel from "-radius".
+ Add pixels from radius. */
+ for (x = edgeA; x < edgeB; x++) {
+ MOVE_ACC(acc, x - radius - 1, x + radius);
+ ADD_FAR(bulk, acc, x - radius - 1, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ /* Subtract previous pixel from "-radius".
+ Add last pixel. */
+ for (x = edgeB; x <= lastx; x++) {
+ MOVE_ACC(acc, x - radius - 1, lastx);
+ ADD_FAR(bulk, acc, x - radius - 1, lastx);
+ SAVE(x, bulk);
+ }
+ }
+ else
+ {
+ for (x = 0; x < edgeB; x++) {
+ MOVE_ACC(acc, 0, x + radius);
+ ADD_FAR(bulk, acc, 0, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ for (x = edgeB; x < edgeA; x++) {
+ MOVE_ACC(acc, 0, lastx);
+ ADD_FAR(bulk, acc, 0, lastx);
+ SAVE(x, bulk);
+ }
+ for (x = edgeA; x <= lastx; x++) {
+ MOVE_ACC(acc, x - radius - 1, lastx);
+ ADD_FAR(bulk, acc, x - radius - 1, lastx);
+ SAVE(x, bulk);
+ }
+ }
+
+ #undef MOVE_ACC
+ #undef ADD_FAR
+ #undef SAVE
+}
+
+
+void static inline
+ImagingLineBoxBlur8(UINT8 *lineOut, UINT8 *lineIn, int lastx, int radius, int edgeA,
+ int edgeB, UINT32 ww, UINT32 fw)
+{
+ int x;
+ UINT32 acc;
+ UINT32 bulk;
+
+ #define MOVE_ACC(acc, subtract, add) \
+ acc += lineIn[add] - lineIn[subtract];
+
+ #define ADD_FAR(bulk, acc, left, right) \
+ bulk = (acc * ww) + (lineIn[left] + lineIn[right]) * fw;
+
+ #define SAVE(x, bulk) \
+ lineOut[x] = (UINT8)((bulk + (1 << 23)) >> 24)
+
+ acc = lineIn[0] * (radius + 1);
+ for (x = 0; x < edgeA - 1; x++) {
+ acc += lineIn[x];
+ }
+ acc += lineIn[lastx] * (radius - edgeA + 1);
+
+ if (edgeA <= edgeB)
+ {
+ for (x = 0; x < edgeA; x++) {
+ MOVE_ACC(acc, 0, x + radius);
+ ADD_FAR(bulk, acc, 0, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ for (x = edgeA; x < edgeB; x++) {
+ MOVE_ACC(acc, x - radius - 1, x + radius);
+ ADD_FAR(bulk, acc, x - radius - 1, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ for (x = edgeB; x <= lastx; x++) {
+ MOVE_ACC(acc, x - radius - 1, lastx);
+ ADD_FAR(bulk, acc, x - radius - 1, lastx);
+ SAVE(x, bulk);
+ }
+ }
+ else
+ {
+ for (x = 0; x < edgeB; x++) {
+ MOVE_ACC(acc, 0, x + radius);
+ ADD_FAR(bulk, acc, 0, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ for (x = edgeB; x < edgeA; x++) {
+ MOVE_ACC(acc, 0, lastx);
+ ADD_FAR(bulk, acc, 0, lastx);
+ SAVE(x, bulk);
+ }
+ for (x = edgeA; x <= lastx; x++) {
+ MOVE_ACC(acc, x - radius - 1, lastx);
+ ADD_FAR(bulk, acc, x - radius - 1, lastx);
+ SAVE(x, bulk);
+ }
+ }
+
+ #undef MOVE_ACC
+ #undef ADD_FAR
+ #undef SAVE
+}
+
+
+
+Imaging
+ImagingHorizontalBoxBlur(Imaging imOut, Imaging imIn, float floatRadius)
+{
+ ImagingSectionCookie cookie;
+
+ int y;
+
+ int radius = (int) floatRadius;
+ UINT32 ww = (UINT32) (1 << 24) / (floatRadius * 2 + 1);
+ UINT32 fw = ((1 << 24) - (radius * 2 + 1) * ww) / 2;
+
+ int edgeA = MIN(radius + 1, imIn->xsize);
+ int edgeB = MAX(imIn->xsize - radius - 1, 0);
+
+ UINT32 *lineOut = calloc(imIn->xsize, sizeof(UINT32));
+ if (lineOut == NULL)
+ return ImagingError_MemoryError();
+
+ // printf(">>> %d %d %d\n", radius, ww, fw);
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8)
+ {
+ for (y = 0; y < imIn->ysize; y++) {
+ ImagingLineBoxBlur8(
+ (imIn == imOut ? (UINT8 *) lineOut : imOut->image8[y]),
+ imIn->image8[y],
+ imIn->xsize - 1,
+ radius, edgeA, edgeB,
+ ww, fw
+ );
+ if (imIn == imOut) {
+ // Commit.
+ memcpy(imOut->image8[y], lineOut, imIn->xsize);
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < imIn->ysize; y++) {
+ ImagingLineBoxBlur32(
+ imIn == imOut ? (pixel *) lineOut : (pixel *) imOut->image32[y],
+ (pixel *) imIn->image32[y],
+ imIn->xsize - 1,
+ radius, edgeA, edgeB,
+ ww, fw
+ );
+ if (imIn == imOut) {
+ // Commit.
+ memcpy(imOut->image32[y], lineOut, imIn->xsize * 4);
+ }
+ }
+ }
+
+ ImagingSectionLeave(&cookie);
+
+ free(lineOut);
+
+ return imOut;
+}
+
+
+Imaging
+ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n)
+{
+ int i;
+ Imaging imTransposed;
+
+ if (n < 1) {
+ return ImagingError_ValueError(
+ "number of passes must be greater than zero"
+ );
+ }
+
+ if (strcmp(imIn->mode, imOut->mode) ||
+ imIn->type != imOut->type ||
+ imIn->bands != imOut->bands ||
+ imIn->xsize != imOut->xsize ||
+ imIn->ysize != imOut->ysize)
+ return ImagingError_Mismatch();
+
+ if (imIn->type != IMAGING_TYPE_UINT8)
+ return ImagingError_ModeError();
+
+ if (!(strcmp(imIn->mode, "RGB") == 0 ||
+ strcmp(imIn->mode, "RGBA") == 0 ||
+ strcmp(imIn->mode, "RGBa") == 0 ||
+ strcmp(imIn->mode, "RGBX") == 0 ||
+ strcmp(imIn->mode, "CMYK") == 0 ||
+ strcmp(imIn->mode, "L") == 0 ||
+ strcmp(imIn->mode, "LA") == 0 ||
+ strcmp(imIn->mode, "La") == 0))
+ return ImagingError_ModeError();
+
+ imTransposed = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
+ if (!imTransposed)
+ return NULL;
+
+ /* Apply blur in one dimension.
+ Use imOut as a destination at first pass,
+ then use imOut as a source too. */
+ ImagingHorizontalBoxBlur(imOut, imIn, radius);
+ for (i = 1; i < n; i ++) {
+ ImagingHorizontalBoxBlur(imOut, imOut, radius);
+ }
+ /* Transpose result for blur in another direction. */
+ ImagingTranspose(imTransposed, imOut);
+
+ /* Reuse imTransposed as a source and destination there. */
+ for (i = 0; i < n; i ++) {
+ ImagingHorizontalBoxBlur(imTransposed, imTransposed, radius);
+ }
+ /* Restore original orientation. */
+ ImagingTranspose(imOut, imTransposed);
+
+ ImagingDelete(imTransposed);
+
+ return imOut;
+}
+
+
+Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius,
+ int passes)
+{
+ float sigma2, L, l, a;
+
+ sigma2 = radius * radius / passes;
+ // from http://www.mia.uni-saarland.de/Publications/gwosdek-ssvm11.pdf
+ // [7] Box length.
+ L = sqrt(12.0 * sigma2 + 1.0);
+ // [11] Integer part of box radius.
+ l = floor((L - 1.0) / 2.0);
+ // [14], [Fig. 2] Fractional part of box radius.
+ a = (2 * l + 1) * (l * (l + 1) - 3 * sigma2);
+ a /= 6 * (sigma2 - (l + 1) * (l + 1));
+
+ return ImagingBoxBlur(imOut, imIn, l + a, passes);
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Chops.c b/contrib/python/Pillow/py2/libImaging/Chops.c
new file mode 100644
index 0000000000..8059b6ffbd
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Chops.c
@@ -0,0 +1,148 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * basic channel operations
+ *
+ * history:
+ * 1996-03-28 fl Created
+ * 1996-08-13 fl Added and/or/xor for "1" images
+ * 1996-12-14 fl Added add_modulo, sub_modulo
+ * 2005-09-10 fl Fixed output values from and/or/xor
+ *
+ * Copyright (c) 1996 by Fredrik Lundh.
+ * Copyright (c) 1997 by Secret Labs AB.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#define CHOP(operation, mode)\
+ int x, y;\
+ Imaging imOut;\
+ imOut = create(imIn1, imIn2, mode);\
+ if (!imOut)\
+ return NULL;\
+ for (y = 0; y < imOut->ysize; y++) {\
+ UINT8* out = (UINT8*) imOut->image[y];\
+ UINT8* in1 = (UINT8*) imIn1->image[y];\
+ UINT8* in2 = (UINT8*) imIn2->image[y];\
+ for (x = 0; x < imOut->linesize; x++) {\
+ int temp = operation;\
+ if (temp <= 0)\
+ out[x] = 0;\
+ else if (temp >= 255)\
+ out[x] = 255;\
+ else\
+ out[x] = temp;\
+ }\
+ }\
+ return imOut;
+
+#define CHOP2(operation, mode)\
+ int x, y;\
+ Imaging imOut;\
+ imOut = create(imIn1, imIn2, mode);\
+ if (!imOut)\
+ return NULL;\
+ for (y = 0; y < imOut->ysize; y++) {\
+ UINT8* out = (UINT8*) imOut->image[y];\
+ UINT8* in1 = (UINT8*) imIn1->image[y];\
+ UINT8* in2 = (UINT8*) imIn2->image[y];\
+ for (x = 0; x < imOut->linesize; x++) {\
+ out[x] = operation;\
+ }\
+ }\
+ return imOut;
+
+static Imaging
+create(Imaging im1, Imaging im2, char* mode)
+{
+ int xsize, ysize;
+
+ if (!im1 || !im2 || im1->type != IMAGING_TYPE_UINT8 ||
+ (mode != NULL && (strcmp(im1->mode, "1") || strcmp(im2->mode, "1"))))
+ return (Imaging) ImagingError_ModeError();
+ if (im1->type != im2->type ||
+ im1->bands != im2->bands)
+ return (Imaging) ImagingError_Mismatch();
+
+ xsize = (im1->xsize < im2->xsize) ? im1->xsize : im2->xsize;
+ ysize = (im1->ysize < im2->ysize) ? im1->ysize : im2->ysize;
+
+ return ImagingNewDirty(im1->mode, xsize, ysize);
+}
+
+Imaging
+ImagingChopLighter(Imaging imIn1, Imaging imIn2)
+{
+ CHOP((in1[x] > in2[x]) ? in1[x] : in2[x], NULL);
+}
+
+Imaging
+ImagingChopDarker(Imaging imIn1, Imaging imIn2)
+{
+ CHOP((in1[x] < in2[x]) ? in1[x] : in2[x], NULL);
+}
+
+Imaging
+ImagingChopDifference(Imaging imIn1, Imaging imIn2)
+{
+ CHOP(abs((int) in1[x] - (int) in2[x]), NULL);
+}
+
+Imaging
+ImagingChopMultiply(Imaging imIn1, Imaging imIn2)
+{
+ CHOP((int) in1[x] * (int) in2[x] / 255, NULL);
+}
+
+Imaging
+ImagingChopScreen(Imaging imIn1, Imaging imIn2)
+{
+ CHOP(255 - ((int) (255 - in1[x]) * (int) (255 - in2[x])) / 255, NULL);
+}
+
+Imaging
+ImagingChopAdd(Imaging imIn1, Imaging imIn2, float scale, int offset)
+{
+ CHOP(((int) in1[x] + (int) in2[x]) / scale + offset, NULL);
+}
+
+Imaging
+ImagingChopSubtract(Imaging imIn1, Imaging imIn2, float scale, int offset)
+{
+ CHOP(((int) in1[x] - (int) in2[x]) / scale + offset, NULL);
+}
+
+Imaging
+ImagingChopAnd(Imaging imIn1, Imaging imIn2)
+{
+ CHOP2((in1[x] && in2[x]) ? 255 : 0, "1");
+}
+
+Imaging
+ImagingChopOr(Imaging imIn1, Imaging imIn2)
+{
+ CHOP2((in1[x] || in2[x]) ? 255 : 0, "1");
+}
+
+Imaging
+ImagingChopXor(Imaging imIn1, Imaging imIn2)
+{
+ CHOP2(((in1[x] != 0) ^ (in2[x] != 0)) ? 255 : 0, "1");
+}
+
+Imaging
+ImagingChopAddModulo(Imaging imIn1, Imaging imIn2)
+{
+ CHOP2(in1[x] + in2[x], NULL);
+}
+
+Imaging
+ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2)
+{
+ CHOP2(in1[x] - in2[x], NULL);
+}
diff --git a/contrib/python/Pillow/py2/libImaging/ColorLUT.c b/contrib/python/Pillow/py2/libImaging/ColorLUT.c
new file mode 100644
index 0000000000..f01d38993d
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/ColorLUT.c
@@ -0,0 +1,168 @@
+#include "Imaging.h"
+#include <math.h>
+
+
+/* 8 bits for result. Table can overflow [0, 1.0] range,
+ so we need extra bits for overflow and negative values.
+ NOTE: This value should be the same as in _imaging/_prepare_lut_table() */
+#define PRECISION_BITS (16 - 8 - 2)
+#define PRECISION_ROUNDING (1<<(PRECISION_BITS-1))
+
+/* 8 — scales are multiplied on byte.
+ 6 — max index in the table
+ (max size is 65, but index 64 is not reachable) */
+#define SCALE_BITS (32 - 8 - 6)
+#define SCALE_MASK ((1<<SCALE_BITS) - 1)
+
+#define SHIFT_BITS (16 - 1)
+
+
+static inline UINT8 clip8(int in)
+{
+ return clip8_lookups[(in + PRECISION_ROUNDING) >> PRECISION_BITS];
+}
+
+static inline void
+interpolate3(INT16 out[3], const INT16 a[3], const INT16 b[3], INT16 shift)
+{
+ out[0] = (a[0] * ((1<<SHIFT_BITS)-shift) + b[0] * shift) >> SHIFT_BITS;
+ out[1] = (a[1] * ((1<<SHIFT_BITS)-shift) + b[1] * shift) >> SHIFT_BITS;
+ out[2] = (a[2] * ((1<<SHIFT_BITS)-shift) + b[2] * shift) >> SHIFT_BITS;
+}
+
+static inline void
+interpolate4(INT16 out[4], const INT16 a[4], const INT16 b[4], INT16 shift)
+{
+ out[0] = (a[0] * ((1<<SHIFT_BITS)-shift) + b[0] * shift) >> SHIFT_BITS;
+ out[1] = (a[1] * ((1<<SHIFT_BITS)-shift) + b[1] * shift) >> SHIFT_BITS;
+ out[2] = (a[2] * ((1<<SHIFT_BITS)-shift) + b[2] * shift) >> SHIFT_BITS;
+ out[3] = (a[3] * ((1<<SHIFT_BITS)-shift) + b[3] * shift) >> SHIFT_BITS;
+}
+
+static inline int
+table_index3D(int index1D, int index2D, int index3D,
+ int size1D, int size1D_2D)
+{
+ return index1D + index2D * size1D + index3D * size1D_2D;
+}
+
+
+/*
+ Transforms colors of imIn using provided 3D lookup table
+ and puts the result in imOut. Returns imOut on success or 0 on error.
+
+ imOut, imIn — images, should be the same size and may be the same image.
+ Should have 3 or 4 channels.
+ table_channels — number of channels in the lookup table, 3 or 4.
+ Should be less or equal than number of channels in imOut image;
+ size1D, size_2D and size3D — dimensions of provided table;
+ table — flat table,
+ array with table_channels × size1D × size2D × size3D elements,
+ where channels are changed first, then 1D, then​ 2D, then 3D.
+ Each element is signed 16-bit int where 0 is lowest output value
+ and 255 << PRECISION_BITS (16320) is highest value.
+*/
+Imaging
+ImagingColorLUT3D_linear(Imaging imOut, Imaging imIn, int table_channels,
+ int size1D, int size2D, int size3D,
+ INT16* table)
+{
+ /* This float to int conversion doesn't have rounding
+ error compensation (+0.5) for two reasons:
+ 1. As we don't hit the highest value,
+ we can use one extra bit for precision.
+ 2. For every pixel, we interpolate 8 elements from the table:
+ current and +1 for every dimension and their combinations.
+ If we hit the upper cells from the table,
+ +1 cells will be outside of the table.
+ With this compensation we never hit the upper cells
+ but this also doesn't introduce any noticeable difference. */
+ UINT32 scale1D = (size1D - 1) / 255.0 * (1<<SCALE_BITS);
+ UINT32 scale2D = (size2D - 1) / 255.0 * (1<<SCALE_BITS);
+ UINT32 scale3D = (size3D - 1) / 255.0 * (1<<SCALE_BITS);
+ int size1D_2D = size1D * size2D;
+ int x, y;
+ ImagingSectionCookie cookie;
+
+ if (table_channels < 3 || table_channels > 4) {
+ PyErr_SetString(PyExc_ValueError, "table_channels could be 3 or 4");
+ return NULL;
+ }
+
+ if (imIn->type != IMAGING_TYPE_UINT8 ||
+ imOut->type != IMAGING_TYPE_UINT8 ||
+ imIn->bands < 3 ||
+ imOut->bands < table_channels
+ ) {
+ return (Imaging) ImagingError_ModeError();
+ }
+
+ /* In case we have one extra band in imOut and don't have in imIn.*/
+ if (imOut->bands > table_channels && imOut->bands > imIn->bands) {
+ return (Imaging) ImagingError_ModeError();
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8* rowIn = (UINT8 *)imIn->image[y];
+ char* rowOut = (char *)imOut->image[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ UINT32 index1D = rowIn[x*4 + 0] * scale1D;
+ UINT32 index2D = rowIn[x*4 + 1] * scale2D;
+ UINT32 index3D = rowIn[x*4 + 2] * scale3D;
+ INT16 shift1D = (SCALE_MASK & index1D) >> (SCALE_BITS - SHIFT_BITS);
+ INT16 shift2D = (SCALE_MASK & index2D) >> (SCALE_BITS - SHIFT_BITS);
+ INT16 shift3D = (SCALE_MASK & index3D) >> (SCALE_BITS - SHIFT_BITS);
+ int idx = table_channels * table_index3D(
+ index1D >> SCALE_BITS, index2D >> SCALE_BITS,
+ index3D >> SCALE_BITS, size1D, size1D_2D);
+ INT16 result[4], left[4], right[4];
+ INT16 leftleft[4], leftright[4], rightleft[4], rightright[4];
+
+ if (table_channels == 3) {
+ UINT32 v;
+ interpolate3(leftleft, &table[idx + 0], &table[idx + 3], shift1D);
+ interpolate3(leftright, &table[idx + size1D*3],
+ &table[idx + size1D*3 + 3], shift1D);
+ interpolate3(left, leftleft, leftright, shift2D);
+
+ interpolate3(rightleft, &table[idx + size1D_2D*3],
+ &table[idx + size1D_2D*3 + 3], shift1D);
+ interpolate3(rightright, &table[idx + size1D_2D*3 + size1D*3],
+ &table[idx + size1D_2D*3 + size1D*3 + 3], shift1D);
+ interpolate3(right, rightleft, rightright, shift2D);
+
+ interpolate3(result, left, right, shift3D);
+
+ v = MAKE_UINT32(
+ clip8(result[0]), clip8(result[1]),
+ clip8(result[2]), rowIn[x*4 + 3]);
+ memcpy(rowOut + x * sizeof(v), &v, sizeof(v));
+ }
+
+ if (table_channels == 4) {
+ UINT32 v;
+ interpolate4(leftleft, &table[idx + 0], &table[idx + 4], shift1D);
+ interpolate4(leftright, &table[idx + size1D*4],
+ &table[idx + size1D*4 + 4], shift1D);
+ interpolate4(left, leftleft, leftright, shift2D);
+
+ interpolate4(rightleft, &table[idx + size1D_2D*4],
+ &table[idx + size1D_2D*4 + 4], shift1D);
+ interpolate4(rightright, &table[idx + size1D_2D*4 + size1D*4],
+ &table[idx + size1D_2D*4 + size1D*4 + 4], shift1D);
+ interpolate4(right, rightleft, rightright, shift2D);
+
+ interpolate4(result, left, right, shift3D);
+
+ v = MAKE_UINT32(
+ clip8(result[0]), clip8(result[1]),
+ clip8(result[2]), clip8(result[3]));
+ memcpy(rowOut + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Convert.c b/contrib/python/Pillow/py2/libImaging/Convert.c
new file mode 100644
index 0000000000..ea402d5880
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Convert.c
@@ -0,0 +1,1737 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * convert images
+ *
+ * history:
+ * 1995-06-15 fl created
+ * 1995-11-28 fl added some "RGBA" and "CMYK" conversions
+ * 1996-04-22 fl added "1" conversions (same as "L")
+ * 1996-05-05 fl added palette conversions (hack)
+ * 1996-07-23 fl fixed "1" conversions to zero/non-zero convention
+ * 1996-11-01 fl fixed "P" to "L" and "RGB" to "1" conversions
+ * 1996-12-29 fl set alpha byte in RGB converters
+ * 1997-05-12 fl added ImagingConvert2
+ * 1997-05-30 fl added floating point support
+ * 1997-08-27 fl added "P" to "1" and "P" to "F" conversions
+ * 1998-01-11 fl added integer support
+ * 1998-07-01 fl added "YCbCr" support
+ * 1998-07-02 fl added "RGBX" conversions (sort of)
+ * 1998-07-04 fl added floyd-steinberg dithering
+ * 1998-07-12 fl changed "YCrCb" to "YCbCr" (!)
+ * 1998-12-29 fl added basic "I;16" and "I;16B" conversions
+ * 1999-02-03 fl added "RGBa", and "BGR" conversions (experimental)
+ * 2003-09-26 fl added "LA" and "PA" conversions (experimental)
+ * 2005-05-05 fl fixed "P" to "1" threshold
+ * 2005-12-08 fl fixed palette memory leak in topalette
+ *
+ * Copyright (c) 1997-2005 by Secret Labs AB.
+ * Copyright (c) 1995-1997 by Fredrik Lundh.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#define MAX(a, b) (a)>(b) ? (a) : (b)
+#define MIN(a, b) (a)<(b) ? (a) : (b)
+
+#define CLIP16(v) ((v) <= -32768 ? -32768 : (v) >= 32767 ? 32767 : (v))
+
+/* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+#define L(rgb)\
+ ((INT32) (rgb)[0]*299 + (INT32) (rgb)[1]*587 + (INT32) (rgb)[2]*114)
+#define L24(rgb)\
+ ((rgb)[0]*19595 + (rgb)[1]*38470 + (rgb)[2]*7471)
+
+/* ------------------- */
+/* 1 (bit) conversions */
+/* ------------------- */
+
+static void
+bit2l(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++)
+ *out++ = (*in++ != 0) ? 255 : 0;
+}
+
+static void
+bit2rgb(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ UINT8 v = (*in++ != 0) ? 255 : 0;
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ *out++ = 255;
+ }
+}
+
+static void
+bit2cmyk(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = (*in++ != 0) ? 0 : 255;
+ }
+}
+
+static void
+bit2ycbcr(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = (*in++ != 0) ? 255 : 0;
+ *out++ = 128;
+ *out++ = 128;
+ *out++ = 255;
+ }
+}
+
+static void
+bit2hsv(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out += 4) {
+ UINT8 v = (*in++ != 0) ? 255 : 0;
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = v;
+ out[3] = 255;
+ }
+}
+
+/* ----------------- */
+/* RGB/L conversions */
+/* ----------------- */
+
+static void
+l2bit(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++)
+ *out++ = (*in++ >= 128) ? 255 : 0;
+}
+
+static void
+lA2la(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ unsigned int alpha, pixel, tmp;
+ for (x = 0; x < xsize; x++, in += 4) {
+ alpha = in[3];
+ pixel = MULDIV255(in[0], alpha, tmp);
+ *out++ = (UINT8) pixel;
+ *out++ = (UINT8) pixel;
+ *out++ = (UINT8) pixel;
+ *out++ = (UINT8) alpha;
+ }
+}
+
+/* RGBa -> RGBA conversion to remove premultiplication
+ Needed for correct transforms/resizing on RGBA images */
+static void
+la2lA(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ unsigned int alpha, pixel;
+ for (x = 0; x < xsize; x++, in+=4) {
+ alpha = in[3];
+ if (alpha == 255 || alpha == 0) {
+ pixel = in[0];
+ } else {
+ pixel = CLIP8((255 * in[0]) / alpha);
+ }
+ *out++ = (UINT8) pixel;
+ *out++ = (UINT8) pixel;
+ *out++ = (UINT8) pixel;
+ *out++ = (UINT8) alpha;
+ }
+}
+
+static void
+l2la(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ UINT8 v = *in++;
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ *out++ = 255;
+ }
+}
+
+static void
+l2rgb(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ UINT8 v = *in++;
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ *out++ = 255;
+ }
+}
+
+static void
+l2hsv(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out += 4) {
+ UINT8 v = *in++;
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = v;
+ out[3] = 255;
+ }
+}
+
+static void
+la2l(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4)
+ *out++ = in[0];
+}
+
+static void
+la2rgb(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ UINT8 v = in[0];
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ *out++ = in[3];
+ }
+}
+
+static void
+la2hsv(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ UINT8 v = in[0];
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = v;
+ out[3] = in[3];
+ }
+}
+
+static void
+rgb2bit(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4)
+ /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+ *out++ = (L(in) >= 128000) ? 255 : 0;
+}
+
+static void
+rgb2l(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4)
+ /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+ *out++ = L24(in) >> 16;
+}
+
+static void
+rgb2la(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+ out[0] = out[1] = out[2] = L24(in) >> 16;
+ out[3] = 255;
+ }
+}
+
+static void
+rgb2i(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out_ += 4) {
+ INT32 v = L24(in) >> 16;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+rgb2f(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out_ += 4) {
+ FLOAT32 v = (float) L(in) / 1000.0F;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+rgb2bgr15(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out_ += 2) {
+ UINT16 v =
+ ((((UINT16)in[0])<<7)&0x7c00) +
+ ((((UINT16)in[1])<<2)&0x03e0) +
+ ((((UINT16)in[2])>>3)&0x001f);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+rgb2bgr16(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out_ += 2) {
+ UINT16 v =
+ ((((UINT16)in[0])<<8)&0xf800) +
+ ((((UINT16)in[1])<<3)&0x07e0) +
+ ((((UINT16)in[2])>>3)&0x001f);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+rgb2bgr24(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = in[2];
+ *out++ = in[1];
+ *out++ = in[0];
+ }
+}
+
+static void
+rgb2hsv_row(UINT8* out, const UINT8* in)
+{ // following colorsys.py
+ float h,s,rc,gc,bc,cr;
+ UINT8 maxc,minc;
+ UINT8 r, g, b;
+ UINT8 uh,us,uv;
+
+ r = in[0];
+ g = in[1];
+ b = in[2];
+ maxc = MAX(r,MAX(g,b));
+ minc = MIN(r,MIN(g,b));
+ uv = maxc;
+ if (minc == maxc){
+ uh = 0;
+ us = 0;
+ } else {
+ cr = (float)(maxc-minc);
+ s = cr/(float)maxc;
+ rc = ((float)(maxc-r))/cr;
+ gc = ((float)(maxc-g))/cr;
+ bc = ((float)(maxc-b))/cr;
+ if (r == maxc) {
+ h = bc-gc;
+ } else if (g == maxc) {
+ h = 2.0 + rc-bc;
+ } else {
+ h = 4.0 + gc-rc;
+ }
+ // incorrect hue happens if h/6 is negative.
+ h = fmod((h/6.0 + 1.0), 1.0);
+
+ uh = (UINT8)CLIP8((int)(h*255.0));
+ us = (UINT8)CLIP8((int)(s*255.0));
+ }
+ out[0] = uh;
+ out[1] = us;
+ out[2] = uv;
+}
+
+static void
+rgb2hsv(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ rgb2hsv_row(out, in);
+ out[3] = in[3];
+ }
+}
+
+
+
+static void
+hsv2rgb(UINT8* out, const UINT8* in, int xsize)
+{ // following colorsys.py
+
+ int p,q,t;
+ UINT8 up,uq,ut;
+ int i, x;
+ float f, fs;
+ UINT8 h,s,v;
+
+ for (x = 0; x < xsize; x++, in += 4) {
+ h = in[0];
+ s = in[1];
+ v = in[2];
+
+ if (s==0){
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ } else {
+ i = floor((float)h * 6.0 / 255.0); // 0 - 6
+ f = (float)h * 6.0 / 255.0 - (float)i; // 0-1 : remainder.
+ fs = ((float)s)/255.0;
+
+ p = round((float)v * (1.0-fs));
+ q = round((float)v * (1.0-fs*f));
+ t = round((float)v * (1.0-fs*(1.0-f)));
+ up = (UINT8)CLIP8(p);
+ uq = (UINT8)CLIP8(q);
+ ut = (UINT8)CLIP8(t);
+
+ switch (i%6) {
+ case 0:
+ *out++ = v;
+ *out++ = ut;
+ *out++ = up;
+ break;
+ case 1:
+ *out++ = uq;
+ *out++ = v;
+ *out++ = up;
+ break;
+ case 2:
+ *out++ = up;
+ *out++ = v;
+ *out++ = ut;
+ break;
+ case 3:
+ *out++ = up;
+ *out++ = uq;
+ *out++ = v;
+ break;
+ case 4:
+ *out++ = ut;
+ *out++ = up;
+ *out++ = v;
+ break;
+ case 5:
+ *out++ = v;
+ *out++ = up;
+ *out++ = uq;
+ break;
+
+ }
+ }
+ *out++ = in[3];
+ }
+}
+
+
+
+/* ---------------- */
+/* RGBA conversions */
+/* ---------------- */
+
+static void
+rgb2rgba(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = 255; in++;
+ }
+}
+
+static void
+rgba2la(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+ out[0] = out[1] = out[2] = L24(in) >> 16;
+ out[3] = in[3];
+ }
+}
+
+static void
+rgba2rgb(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = 255; in++;
+ }
+}
+
+static void
+rgbA2rgba(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ unsigned int alpha, tmp;
+ for (x = 0; x < xsize; x++) {
+ alpha = in[3];
+ *out++ = MULDIV255(*in++, alpha, tmp);
+ *out++ = MULDIV255(*in++, alpha, tmp);
+ *out++ = MULDIV255(*in++, alpha, tmp);
+ *out++ = *in++;
+ }
+}
+
+/* RGBa -> RGBA conversion to remove premultiplication
+ Needed for correct transforms/resizing on RGBA images */
+static void
+rgba2rgbA(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ unsigned int alpha;
+ for (x = 0; x < xsize; x++, in+=4) {
+ alpha = in[3];
+ if (alpha == 255 || alpha == 0) {
+ *out++ = in[0];
+ *out++ = in[1];
+ *out++ = in[2];
+ } else {
+ *out++ = CLIP8((255 * in[0]) / alpha);
+ *out++ = CLIP8((255 * in[1]) / alpha);
+ *out++ = CLIP8((255 * in[2]) / alpha);
+ }
+ *out++ = in[3];
+ }
+}
+
+/*
+ * Conversion of RGB + single transparent color to RGBA,
+ * where any pixel that matches the color will have the
+ * alpha channel set to 0
+ */
+
+static void
+rgbT2rgba(UINT8* out, int xsize, int r, int g, int b)
+{
+#ifdef WORDS_BIGENDIAN
+ UINT32 trns = ((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | 0xff;
+ UINT32 repl = trns & 0xffffff00;
+#else
+ UINT32 trns = (0xff <<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff);
+ UINT32 repl = trns & 0x00ffffff;
+#endif
+
+ int i;
+
+ for (i=0; i < xsize; i++ ,out += sizeof(trns)) {
+ UINT32 v;
+ memcpy(&v, out, sizeof(v));
+ if (v==trns) {
+ memcpy(out, &repl, sizeof(repl));
+ }
+ }
+}
+
+
+/* ---------------- */
+/* CMYK conversions */
+/* ---------------- */
+
+static void
+l2cmyk(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = ~(*in++);
+ }
+}
+
+static void
+la2cmyk(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = ~(in[0]);
+ }
+}
+
+static void
+rgb2cmyk(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ /* Note: no undercolour removal */
+ *out++ = ~(*in++);
+ *out++ = ~(*in++);
+ *out++ = ~(*in++);
+ *out++ = 0; in++;
+ }
+}
+
+static void
+cmyk2rgb(UINT8* out, const UINT8* in, int xsize)
+{
+ int x, nk, tmp;
+ for (x = 0; x < xsize; x++) {
+ nk = 255 - in[3];
+ out[0] = CLIP8(nk - MULDIV255(in[0], nk, tmp));
+ out[1] = CLIP8(nk - MULDIV255(in[1], nk, tmp));
+ out[2] = CLIP8(nk - MULDIV255(in[2], nk, tmp));
+ out[3] = 255;
+ out += 4;
+ in += 4;
+ }
+}
+
+static void
+cmyk2hsv(UINT8* out, const UINT8* in, int xsize)
+{
+ int x, nk, tmp;
+ for (x = 0; x < xsize; x++) {
+ nk = 255 - in[3];
+ out[0] = CLIP8(nk - MULDIV255(in[0], nk, tmp));
+ out[1] = CLIP8(nk - MULDIV255(in[1], nk, tmp));
+ out[2] = CLIP8(nk - MULDIV255(in[2], nk, tmp));
+ rgb2hsv_row(out, out);
+ out[3] = 255;
+ out += 4;
+ in += 4;
+ }
+}
+
+/* ------------- */
+/* I conversions */
+/* ------------- */
+
+static void
+bit2i(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ INT32 v = (*in++ != 0) ? 255 : 0;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+l2i(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ INT32 v = *in++;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+i2l(UINT8* out, const UINT8* in_, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out++, in_ += 4) {
+ INT32 v;
+ memcpy(&v, in_, sizeof(v));
+ if (v <= 0)
+ *out = 0;
+ else if (v >= 255)
+ *out = 255;
+ else
+ *out = (UINT8) v;
+ }
+}
+
+static void
+i2f(UINT8* out_, const UINT8* in_, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) {
+ INT32 i;
+ FLOAT32 f;
+ memcpy(&i, in_, sizeof(i));
+ f = i;
+ memcpy(out_, &f, sizeof(f));
+ }
+}
+
+static void
+i2rgb(UINT8* out, const UINT8* in_, int xsize)
+{
+ int x;
+ INT32* in = (INT32*) in_;
+ for (x = 0; x < xsize; x++, in++, out+=4) {
+ if (*in <= 0)
+ out[0] = out[1] = out[2] = 0;
+ else if (*in >= 255)
+ out[0] = out[1] = out[2] = 255;
+ else
+ out[0] = out[1] = out[2] = (UINT8) *in;
+ out[3] = 255;
+ }
+}
+
+static void
+i2hsv(UINT8* out, const UINT8* in_, int xsize)
+{
+ int x;
+ INT32* in = (INT32*) in_;
+ for (x = 0; x < xsize; x++, in++, out+=4) {
+ out[0] = 0;
+ out[1] = 0;
+ if (*in <= 0) {
+ out[2] = 0;
+ } else if (*in >= 255) {
+ out[2] = 255;
+ } else {
+ out[2] = (UINT8) *in;
+ }
+ out[3] = 255;
+ }
+}
+
+/* ------------- */
+/* F conversions */
+/* ------------- */
+
+static void
+bit2f(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ FLOAT32 f = (*in++ != 0) ? 255.0F : 0.0F;
+ memcpy(out_, &f, sizeof(f));
+ }
+}
+
+static void
+l2f(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ FLOAT32 f = (FLOAT32) *in++;
+ memcpy(out_, &f, sizeof(f));
+ }
+}
+
+static void
+f2l(UINT8* out, const UINT8* in_, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out++, in_ += 4) {
+ FLOAT32 v;
+ memcpy(&v, in_, sizeof(v));
+ if (v <= 0.0)
+ *out = 0;
+ else if (v >= 255.0)
+ *out = 255;
+ else
+ *out = (UINT8) v;
+ }
+}
+
+static void
+f2i(UINT8* out_, const UINT8* in_, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) {
+ FLOAT32 f;
+ INT32 i;
+ memcpy(&f, in_, sizeof(f));
+ i = f;
+ memcpy(out_, &i, sizeof(i));
+ }
+}
+
+/* ----------------- */
+/* YCbCr conversions */
+/* ----------------- */
+
+/* See ConvertYCbCr.c for RGB/YCbCr tables */
+
+static void
+l2ycbcr(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = *in++;
+ *out++ = 128;
+ *out++ = 128;
+ *out++ = 255;
+ }
+}
+
+static void
+la2ycbcr(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = in[0];
+ *out++ = 128;
+ *out++ = 128;
+ *out++ = 255;
+ }
+}
+
+static void
+ycbcr2l(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4)
+ *out++ = in[0];
+}
+
+static void
+ycbcr2la(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ out[0] = out[1] = out[2] = in[0];
+ out[3] = 255;
+ }
+}
+
+/* ------------------------- */
+/* I;16 (16-bit) conversions */
+/* ------------------------- */
+
+static void
+I_I16L(UINT8* out, const UINT8* in_, int xsize)
+{
+ int x, v;
+ for (x = 0; x < xsize; x++, in_ += 4) {
+ INT32 i;
+ memcpy(&i, in_, sizeof(i));
+ v = CLIP16(i);
+ *out++ = (UINT8) v;
+ *out++ = (UINT8) (v >> 8);
+ }
+}
+
+static void
+I_I16B(UINT8* out, const UINT8* in_, int xsize)
+{
+ int x, v;
+ for (x = 0; x < xsize; x++, in_ += 4) {
+ INT32 i;
+ memcpy(&i, in_, sizeof(i));
+ v = CLIP16(i);
+ *out++ = (UINT8) (v >> 8);
+ *out++ = (UINT8) v;
+ }
+}
+
+
+static void
+I16L_I(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
+ INT32 v = in[0] + ((int) in[1] << 8);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+
+static void
+I16B_I(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
+ INT32 v = in[1] + ((int) in[0] << 8);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+I16L_F(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
+ FLOAT32 v = in[0] + ((int) in[1] << 8);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+
+static void
+I16B_F(UINT8* out_, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
+ FLOAT32 v = in[1] + ((int) in[0] << 8);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+L_I16L(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in++) {
+ *out++ = *in;
+ *out++ = 0;
+ }
+}
+
+static void
+L_I16B(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in++) {
+ *out++ = 0;
+ *out++ = *in;
+ }
+}
+
+static void
+I16L_L(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 2)
+ if (in[1] != 0)
+ *out++ = 255;
+ else
+ *out++ = in[0];
+}
+
+static void
+I16B_L(UINT8* out, const UINT8* in, int xsize)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 2)
+ if (in[0] != 0)
+ *out++ = 255;
+ else
+ *out++ = in[1];
+}
+
+static struct {
+ const char* from;
+ const char* to;
+ ImagingShuffler convert;
+} converters[] = {
+
+ { "1", "L", bit2l },
+ { "1", "I", bit2i },
+ { "1", "F", bit2f },
+ { "1", "RGB", bit2rgb },
+ { "1", "RGBA", bit2rgb },
+ { "1", "RGBX", bit2rgb },
+ { "1", "CMYK", bit2cmyk },
+ { "1", "YCbCr", bit2ycbcr },
+ { "1", "HSV", bit2hsv },
+
+ { "L", "1", l2bit },
+ { "L", "LA", l2la },
+ { "L", "I", l2i },
+ { "L", "F", l2f },
+ { "L", "RGB", l2rgb },
+ { "L", "RGBA", l2rgb },
+ { "L", "RGBX", l2rgb },
+ { "L", "CMYK", l2cmyk },
+ { "L", "YCbCr", l2ycbcr },
+ { "L", "HSV", l2hsv },
+
+ { "LA", "L", la2l },
+ { "LA", "La", lA2la },
+ { "LA", "RGB", la2rgb },
+ { "LA", "RGBA", la2rgb },
+ { "LA", "RGBX", la2rgb },
+ { "LA", "CMYK", la2cmyk },
+ { "LA", "YCbCr", la2ycbcr },
+ { "LA", "HSV", la2hsv },
+
+ { "La", "LA", la2lA },
+
+ { "I", "L", i2l },
+ { "I", "F", i2f },
+ { "I", "RGB", i2rgb },
+ { "I", "RGBA", i2rgb },
+ { "I", "RGBX", i2rgb },
+ { "I", "HSV", i2hsv },
+
+ { "F", "L", f2l },
+ { "F", "I", f2i },
+
+ { "RGB", "1", rgb2bit },
+ { "RGB", "L", rgb2l },
+ { "RGB", "LA", rgb2la },
+ { "RGB", "I", rgb2i },
+ { "RGB", "F", rgb2f },
+ { "RGB", "BGR;15", rgb2bgr15 },
+ { "RGB", "BGR;16", rgb2bgr16 },
+ { "RGB", "BGR;24", rgb2bgr24 },
+ { "RGB", "RGBA", rgb2rgba },
+ { "RGB", "RGBX", rgb2rgba },
+ { "RGB", "CMYK", rgb2cmyk },
+ { "RGB", "YCbCr", ImagingConvertRGB2YCbCr },
+ { "RGB", "HSV", rgb2hsv },
+
+ { "RGBA", "1", rgb2bit },
+ { "RGBA", "L", rgb2l },
+ { "RGBA", "LA", rgba2la },
+ { "RGBA", "I", rgb2i },
+ { "RGBA", "F", rgb2f },
+ { "RGBA", "RGB", rgba2rgb },
+ { "RGBA", "RGBa", rgbA2rgba },
+ { "RGBA", "RGBX", rgb2rgba },
+ { "RGBA", "CMYK", rgb2cmyk },
+ { "RGBA", "YCbCr", ImagingConvertRGB2YCbCr },
+ { "RGBA", "HSV", rgb2hsv },
+
+ { "RGBa", "RGBA", rgba2rgbA },
+
+ { "RGBX", "1", rgb2bit },
+ { "RGBX", "L", rgb2l },
+ { "RGBX", "LA", rgb2la },
+ { "RGBX", "I", rgb2i },
+ { "RGBX", "F", rgb2f },
+ { "RGBX", "RGB", rgba2rgb },
+ { "RGBX", "CMYK", rgb2cmyk },
+ { "RGBX", "YCbCr", ImagingConvertRGB2YCbCr },
+ { "RGBX", "HSV", rgb2hsv },
+
+ { "CMYK", "RGB", cmyk2rgb },
+ { "CMYK", "RGBA", cmyk2rgb },
+ { "CMYK", "RGBX", cmyk2rgb },
+ { "CMYK", "HSV", cmyk2hsv },
+
+ { "YCbCr", "L", ycbcr2l },
+ { "YCbCr", "LA", ycbcr2la },
+ { "YCbCr", "RGB", ImagingConvertYCbCr2RGB },
+
+ { "HSV", "RGB", hsv2rgb },
+
+ { "I", "I;16", I_I16L },
+ { "I;16", "I", I16L_I },
+ { "L", "I;16", L_I16L },
+ { "I;16", "L", I16L_L },
+
+ { "I", "I;16L", I_I16L },
+ { "I;16L", "I", I16L_I },
+ { "I", "I;16B", I_I16B },
+ { "I;16B", "I", I16B_I },
+
+ { "L", "I;16L", L_I16L },
+ { "I;16L", "L", I16L_L },
+ { "L", "I;16B", L_I16B },
+ { "I;16B", "L", I16B_L },
+
+ { "I;16", "F", I16L_F },
+ { "I;16L", "F", I16L_F },
+ { "I;16B", "F", I16B_F },
+
+ { NULL }
+};
+
+/* FIXME: translate indexed versions to pointer versions below this line */
+
+/* ------------------- */
+/* Palette conversions */
+/* ------------------- */
+
+static void
+p2bit(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++)
+ *out++ = (L(&palette[in[x]*4]) >= 128000) ? 255 : 0;
+}
+
+static void
+pa2bit(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++, in += 4)
+ *out++ = (L(&palette[in[0]*4]) >= 128000) ? 255 : 0;
+}
+
+static void
+p2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++)
+ *out++ = L(&palette[in[x]*4]) / 1000;
+}
+
+static void
+pa2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++, in += 4)
+ *out++ = L(&palette[in[0]*4]) / 1000;
+}
+
+static void
+p2pa(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in++) {
+ const UINT8* rgba = &palette[in[0]];
+ *out++ = in[0];
+ *out++ = in[0];
+ *out++ = in[0];
+ *out++ = rgba[3];
+ }
+}
+
+static void
+p2la(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++, out+=4) {
+ const UINT8* rgba = &palette[*in++ * 4];
+ out[0] = out[1] = out[2] = L(rgba) / 1000;
+ out[3] = rgba[3];
+ }
+}
+
+static void
+pa2la(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ out[0] = out[1] = out[2] = L(&palette[in[0]*4]) / 1000;
+ out[3] = in[3];
+ }
+}
+
+static void
+p2i(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ INT32 v = L(&palette[in[x]*4]) / 1000;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+pa2i(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ INT32* out = (INT32*) out_;
+ for (x = 0; x < xsize; x++, in += 4)
+ *out++ = L(&palette[in[0]*4]) / 1000;
+}
+
+static void
+p2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ FLOAT32 v = L(&palette[in[x]*4]) / 1000.0F;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+pa2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ FLOAT32* out = (FLOAT32*) out_;
+ for (x = 0; x < xsize; x++, in += 4)
+ *out++ = (float) L(&palette[in[0]*4]) / 1000.0F;
+}
+
+static void
+p2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ const UINT8* rgb = &palette[*in++ * 4];
+ *out++ = rgb[0];
+ *out++ = rgb[1];
+ *out++ = rgb[2];
+ *out++ = 255;
+ }
+}
+
+static void
+pa2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ const UINT8* rgb = &palette[in[0] * 4];
+ *out++ = rgb[0];
+ *out++ = rgb[1];
+ *out++ = rgb[2];
+ *out++ = 255;
+ }
+}
+
+static void
+p2hsv(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++, out += 4) {
+ const UINT8* rgb = &palette[*in++ * 4];
+ rgb2hsv_row(out, rgb);
+ out[3] = 255;
+ }
+}
+
+static void
+pa2hsv(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ const UINT8* rgb = &palette[in[0] * 4];
+ rgb2hsv_row(out, rgb);
+ out[3] = 255;
+ }
+}
+
+static void
+p2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++) {
+ const UINT8* rgba = &palette[*in++ * 4];
+ *out++ = rgba[0];
+ *out++ = rgba[1];
+ *out++ = rgba[2];
+ *out++ = rgba[3];
+ }
+}
+
+static void
+pa2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ const UINT8* rgb = &palette[in[0] * 4];
+ *out++ = rgb[0];
+ *out++ = rgb[1];
+ *out++ = rgb[2];
+ *out++ = in[3];
+ }
+}
+
+static void
+p2cmyk(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ p2rgb(out, in, xsize, palette);
+ rgb2cmyk(out, out, xsize);
+}
+
+static void
+pa2cmyk(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ pa2rgb(out, in, xsize, palette);
+ rgb2cmyk(out, out, xsize);
+}
+
+static void
+p2ycbcr(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ p2rgb(out, in, xsize, palette);
+ ImagingConvertRGB2YCbCr(out, out, xsize);
+}
+
+static void
+pa2ycbcr(UINT8* out, const UINT8* in, int xsize, const UINT8* palette)
+{
+ pa2rgb(out, in, xsize, palette);
+ ImagingConvertRGB2YCbCr(out, out, xsize);
+}
+
+static Imaging
+frompalette(Imaging imOut, Imaging imIn, const char *mode)
+{
+ ImagingSectionCookie cookie;
+ int alpha;
+ int y;
+ void (*convert)(UINT8*, const UINT8*, int, const UINT8*);
+
+ /* Map palette image to L, RGB, RGBA, or CMYK */
+
+ if (!imIn->palette)
+ return (Imaging) ImagingError_ValueError("no palette");
+
+ alpha = !strcmp(imIn->mode, "PA");
+
+ if (strcmp(mode, "1") == 0)
+ convert = alpha ? pa2bit : p2bit;
+ else if (strcmp(mode, "L") == 0)
+ convert = alpha ? pa2l : p2l;
+ else if (strcmp(mode, "LA") == 0)
+ convert = alpha ? pa2la : p2la;
+ else if (strcmp(mode, "PA") == 0)
+ convert = p2pa;
+ else if (strcmp(mode, "I") == 0)
+ convert = alpha ? pa2i : p2i;
+ else if (strcmp(mode, "F") == 0)
+ convert = alpha ? pa2f : p2f;
+ else if (strcmp(mode, "RGB") == 0)
+ convert = alpha ? pa2rgb : p2rgb;
+ else if (strcmp(mode, "RGBA") == 0)
+ convert = alpha ? pa2rgba : p2rgba;
+ else if (strcmp(mode, "RGBX") == 0)
+ convert = alpha ? pa2rgba : p2rgba;
+ else if (strcmp(mode, "CMYK") == 0)
+ convert = alpha ? pa2cmyk : p2cmyk;
+ else if (strcmp(mode, "YCbCr") == 0)
+ convert = alpha ? pa2ycbcr : p2ycbcr;
+ else if (strcmp(mode, "HSV") == 0)
+ convert = alpha ? pa2hsv : p2hsv;
+ else
+ return (Imaging) ImagingError_ValueError("conversion not supported");
+
+ imOut = ImagingNew2Dirty(mode, imOut, imIn);
+ if (!imOut)
+ return NULL;
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++)
+ (*convert)((UINT8*) imOut->image[y], (UINT8*) imIn->image[y],
+ imIn->xsize, imIn->palette->palette);
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+#if defined(_MSC_VER)
+#pragma optimize("", off)
+#endif
+static Imaging
+topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalette, int dither)
+{
+ ImagingSectionCookie cookie;
+ int alpha;
+ int x, y;
+ ImagingPalette palette = inpalette;;
+
+ /* Map L or RGB/RGBX/RGBA to palette image */
+ if (strcmp(imIn->mode, "L") != 0 && strncmp(imIn->mode, "RGB", 3) != 0)
+ return (Imaging) ImagingError_ValueError("conversion not supported");
+
+ alpha = !strcmp(mode, "PA");
+
+ if (palette == NULL) {
+ /* FIXME: make user configurable */
+ if (imIn->bands == 1)
+ palette = ImagingPaletteNew("RGB"); /* Initialised to grey ramp */
+ else
+ palette = ImagingPaletteNewBrowser(); /* Standard colour cube */
+ }
+
+ if (!palette)
+ return (Imaging) ImagingError_ValueError("no palette");
+
+ imOut = ImagingNew2Dirty(mode, imOut, imIn);
+ if (!imOut) {
+ if (palette != inpalette)
+ ImagingPaletteDelete(palette);
+ return NULL;
+ }
+
+ ImagingPaletteDelete(imOut->palette);
+ imOut->palette = ImagingPaletteDuplicate(palette);
+
+ if (imIn->bands == 1) {
+ /* greyscale image */
+
+ /* Greyscale palette: copy data as is */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ if (alpha) {
+ l2la((UINT8*) imOut->image[y], (UINT8*) imIn->image[y], imIn->xsize);
+ } else {
+ memcpy(imOut->image[y], imIn->image[y], imIn->linesize);
+ }
+ }
+ ImagingSectionLeave(&cookie);
+
+ } else {
+ /* colour image */
+
+ /* Create mapping cache */
+ if (ImagingPaletteCachePrepare(palette) < 0) {
+ ImagingDelete(imOut);
+ if (palette != inpalette)
+ ImagingPaletteDelete(palette);
+ return NULL;
+ }
+
+ if (dither) {
+ /* floyd-steinberg dither */
+
+ int* errors;
+ errors = calloc(imIn->xsize + 1, sizeof(int) * 3);
+ if (!errors) {
+ ImagingDelete(imOut);
+ return ImagingError_MemoryError();
+ }
+
+ /* Map each pixel to the nearest palette entry */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ int r, r0, r1, r2;
+ int g, g0, g1, g2;
+ int b, b0, b1, b2;
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out = alpha ? (UINT8*) imOut->image32[y] : imOut->image8[y];
+ int* e = errors;
+
+ r = r0 = r1 = 0;
+ g = g0 = g1 = 0;
+ b = b0 = b1 = b2 = 0;
+
+ for (x = 0; x < imIn->xsize; x++, in += 4) {
+ int d2;
+ INT16* cache;
+
+ r = CLIP8(in[0] + (r + e[3+0])/16);
+ g = CLIP8(in[1] + (g + e[3+1])/16);
+ b = CLIP8(in[2] + (b + e[3+2])/16);
+
+ /* get closest colour */
+ cache = &ImagingPaletteCache(palette, r, g, b);
+ if (cache[0] == 0x100)
+ ImagingPaletteCacheUpdate(palette, r, g, b);
+ if (alpha) {
+ out[x*4] = out[x*4+1] = out[x*4+2] = (UINT8) cache[0];
+ out[x*4+3] = 255;
+ } else {
+ out[x] = (UINT8) cache[0];
+ }
+
+ r -= (int) palette->palette[cache[0]*4];
+ g -= (int) palette->palette[cache[0]*4+1];
+ b -= (int) palette->palette[cache[0]*4+2];
+
+ /* propagate errors (don't ask ;-) */
+ r2 = r; d2 = r + r; r += d2; e[0] = r + r0;
+ r += d2; r0 = r + r1; r1 = r2; r += d2;
+ g2 = g; d2 = g + g; g += d2; e[1] = g + g0;
+ g += d2; g0 = g + g1; g1 = g2; g += d2;
+ b2 = b; d2 = b + b; b += d2; e[2] = b + b0;
+ b += d2; b0 = b + b1; b1 = b2; b += d2;
+
+ e += 3;
+
+ }
+
+ e[0] = b0;
+ e[1] = b1;
+ e[2] = b2;
+
+ }
+ ImagingSectionLeave(&cookie);
+ free(errors);
+
+ } else {
+
+ /* closest colour */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ int r, g, b;
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out = alpha ? (UINT8*) imOut->image32[y] : imOut->image8[y];
+
+ for (x = 0; x < imIn->xsize; x++, in += 4) {
+ INT16* cache;
+
+ r = in[0]; g = in[1]; b = in[2];
+
+ /* get closest colour */
+ cache = &ImagingPaletteCache(palette, r, g, b);
+ if (cache[0] == 0x100)
+ ImagingPaletteCacheUpdate(palette, r, g, b);
+ if (alpha) {
+ out[x*4] = out[x*4+1] = out[x*4+2] = (UINT8) cache[0];
+ out[x*4+3] = 255;
+ } else {
+ out[x] = (UINT8) cache[0];
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+
+ }
+ if (inpalette != palette)
+ ImagingPaletteCacheDelete(palette);
+ }
+
+ if (inpalette != palette)
+ ImagingPaletteDelete(palette);
+
+ return imOut;
+}
+
+static Imaging
+tobilevel(Imaging imOut, Imaging imIn, int dither)
+{
+ ImagingSectionCookie cookie;
+ int x, y;
+ int* errors;
+
+ /* Map L or RGB to dithered 1 image */
+ if (strcmp(imIn->mode, "L") != 0 && strcmp(imIn->mode, "RGB") != 0)
+ return (Imaging) ImagingError_ValueError("conversion not supported");
+
+ imOut = ImagingNew2Dirty("1", imOut, imIn);
+ if (!imOut)
+ return NULL;
+
+ errors = calloc(imIn->xsize + 1, sizeof(int));
+ if (!errors) {
+ ImagingDelete(imOut);
+ return ImagingError_MemoryError();
+ }
+
+ if (imIn->bands == 1) {
+
+ /* map each pixel to black or white, using error diffusion */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ int l, l0, l1, l2, d2;
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out = imOut->image8[y];
+
+ l = l0 = l1 = 0;
+
+ for (x = 0; x < imIn->xsize; x++) {
+
+ /* pick closest colour */
+ l = CLIP8(in[x] + (l + errors[x+1])/16);
+ out[x] = (l > 128) ? 255 : 0;
+
+ /* propagate errors */
+ l -= (int) out[x];
+ l2 = l; d2 = l + l; l += d2; errors[x] = l + l0;
+ l += d2; l0 = l + l1; l1 = l2; l += d2;
+ }
+
+ errors[x] = l0;
+
+ }
+ ImagingSectionLeave(&cookie);
+
+ } else {
+
+ /* map each pixel to black or white, using error diffusion */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ int l, l0, l1, l2, d2;
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out = imOut->image8[y];
+
+ l = l0 = l1 = 0;
+
+ for (x = 0; x < imIn->xsize; x++, in += 4) {
+
+ /* pick closest colour */
+ l = CLIP8(L(in)/1000 + (l + errors[x+1])/16);
+ out[x] = (l > 128) ? 255 : 0;
+
+ /* propagate errors */
+ l -= (int) out[x];
+ l2 = l; d2 = l + l; l += d2; errors[x] = l + l0;
+ l += d2; l0 = l + l1; l1 = l2; l += d2;
+
+ }
+
+ errors[x] = l0;
+
+ }
+ ImagingSectionLeave(&cookie);
+ }
+
+ free(errors);
+
+ return imOut;
+}
+#if defined(_MSC_VER)
+#pragma optimize("", on)
+#endif
+
+static Imaging
+convert(Imaging imOut, Imaging imIn, const char *mode,
+ ImagingPalette palette, int dither)
+{
+ ImagingSectionCookie cookie;
+ ImagingShuffler convert;
+ int y;
+
+ if (!imIn)
+ return (Imaging) ImagingError_ModeError();
+
+ if (!mode) {
+ /* Map palette image to full depth */
+ if (!imIn->palette)
+ return (Imaging) ImagingError_ModeError();
+ mode = imIn->palette->mode;
+ } else
+ /* Same mode? */
+ if (!strcmp(imIn->mode, mode))
+ return ImagingCopy2(imOut, imIn);
+
+
+ /* test for special conversions */
+
+ if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "PA") == 0)
+ return frompalette(imOut, imIn, mode);
+
+ if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0)
+ return topalette(imOut, imIn, mode, palette, dither);
+
+ if (dither && strcmp(mode, "1") == 0)
+ return tobilevel(imOut, imIn, dither);
+
+
+ /* standard conversion machinery */
+
+ convert = NULL;
+
+ for (y = 0; converters[y].from; y++)
+ if (!strcmp(imIn->mode, converters[y].from) &&
+ !strcmp(mode, converters[y].to)) {
+ convert = converters[y].convert;
+ break;
+ }
+
+ if (!convert)
+#ifdef notdef
+ return (Imaging) ImagingError_ValueError("conversion not supported");
+#else
+ {
+ static char buf[256];
+ /* FIXME: may overflow if mode is too large */
+ sprintf(buf, "conversion from %s to %s not supported", imIn->mode, mode);
+ return (Imaging) ImagingError_ValueError(buf);
+ }
+#endif
+
+ imOut = ImagingNew2Dirty(mode, imOut, imIn);
+ if (!imOut)
+ return NULL;
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++)
+ (*convert)((UINT8*) imOut->image[y], (UINT8*) imIn->image[y],
+ imIn->xsize);
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+Imaging
+ImagingConvert(Imaging imIn, const char *mode,
+ ImagingPalette palette, int dither)
+{
+ return convert(NULL, imIn, mode, palette, dither);
+}
+
+Imaging
+ImagingConvert2(Imaging imOut, Imaging imIn)
+{
+ return convert(imOut, imIn, imOut->mode, NULL, 0);
+}
+
+
+Imaging
+ImagingConvertTransparent(Imaging imIn, const char *mode,
+ int r, int g, int b)
+{
+ ImagingSectionCookie cookie;
+ ImagingShuffler convert;
+ Imaging imOut = NULL;
+ int y;
+
+ if (!imIn){
+ return (Imaging) ImagingError_ModeError();
+ }
+
+ if (!((strcmp(imIn->mode, "RGB") == 0 ||
+ strcmp(imIn->mode, "1") == 0 ||
+ strcmp(imIn->mode, "I") == 0 ||
+ strcmp(imIn->mode, "L") == 0)
+ && strcmp(mode, "RGBA") == 0))
+#ifdef notdef
+ {
+ return (Imaging) ImagingError_ValueError("conversion not supported");
+ }
+#else
+ {
+ static char buf[256];
+ /* FIXME: may overflow if mode is too large */
+ sprintf(buf, "conversion from %s to %s not supported in convert_transparent", imIn->mode, mode);
+ return (Imaging) ImagingError_ValueError(buf);
+ }
+#endif
+
+ if (strcmp(imIn->mode, "RGB") == 0) {
+ convert = rgb2rgba;
+ } else {
+ if (strcmp(imIn->mode, "1") == 0) {
+ convert = bit2rgb;
+ } else if (strcmp(imIn->mode, "I") == 0) {
+ convert = i2rgb;
+ } else {
+ convert = l2rgb;
+ }
+ g = b = r;
+ }
+
+ imOut = ImagingNew2Dirty(mode, imOut, imIn);
+ if (!imOut){
+ return NULL;
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ (*convert)((UINT8*) imOut->image[y], (UINT8*) imIn->image[y],
+ imIn->xsize);
+ rgbT2rgba((UINT8*) imOut->image[y], imIn->xsize, r, g, b);
+ }
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+
+}
+
+Imaging
+ImagingConvertInPlace(Imaging imIn, const char* mode)
+{
+ ImagingSectionCookie cookie;
+ ImagingShuffler convert;
+ int y;
+
+ /* limited support for inplace conversion */
+ if (strcmp(imIn->mode, "L") == 0 && strcmp(mode, "1") == 0)
+ convert = l2bit;
+ else if (strcmp(imIn->mode, "1") == 0 && strcmp(mode, "L") == 0)
+ convert = bit2l;
+ else
+ return ImagingError_ModeError();
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++)
+ (*convert)((UINT8*) imIn->image[y], (UINT8*) imIn->image[y],
+ imIn->xsize);
+ ImagingSectionLeave(&cookie);
+
+ return imIn;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/ConvertYCbCr.c b/contrib/python/Pillow/py2/libImaging/ConvertYCbCr.c
new file mode 100644
index 0000000000..6ce549111e
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/ConvertYCbCr.c
@@ -0,0 +1,387 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * code to convert YCbCr data
+ *
+ * history:
+ * 98-07-01 hk Created
+ *
+ * Copyright (c) Secret Labs AB 1998
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+/* JPEG/JFIF YCbCr conversions
+
+ Y = R * 0.29900 + G * 0.58700 + B * 0.11400
+ Cb = R * -0.16874 + G * -0.33126 + B * 0.50000 + 128
+ Cr = R * 0.50000 + G * -0.41869 + B * -0.08131 + 128
+
+ R = Y + + (Cr - 128) * 1.40200
+ G = Y + (Cb - 128) * -0.34414 + (Cr - 128) * -0.71414
+ B = Y + (Cb - 128) * 1.77200
+
+*/
+
+#define SCALE 6 /* bits */
+
+static INT16 Y_R[] = { 0, 19, 38, 57, 77, 96, 115, 134, 153, 172, 191,
+210, 230, 249, 268, 287, 306, 325, 344, 364, 383, 402, 421, 440, 459,
+478, 498, 517, 536, 555, 574, 593, 612, 631, 651, 670, 689, 708, 727,
+746, 765, 785, 804, 823, 842, 861, 880, 899, 919, 938, 957, 976, 995,
+1014, 1033, 1052, 1072, 1091, 1110, 1129, 1148, 1167, 1186, 1206,
+1225, 1244, 1263, 1282, 1301, 1320, 1340, 1359, 1378, 1397, 1416,
+1435, 1454, 1473, 1493, 1512, 1531, 1550, 1569, 1588, 1607, 1627,
+1646, 1665, 1684, 1703, 1722, 1741, 1761, 1780, 1799, 1818, 1837,
+1856, 1875, 1894, 1914, 1933, 1952, 1971, 1990, 2009, 2028, 2048,
+2067, 2086, 2105, 2124, 2143, 2162, 2182, 2201, 2220, 2239, 2258,
+2277, 2296, 2315, 2335, 2354, 2373, 2392, 2411, 2430, 2449, 2469,
+2488, 2507, 2526, 2545, 2564, 2583, 2602, 2622, 2641, 2660, 2679,
+2698, 2717, 2736, 2756, 2775, 2794, 2813, 2832, 2851, 2870, 2890,
+2909, 2928, 2947, 2966, 2985, 3004, 3023, 3043, 3062, 3081, 3100,
+3119, 3138, 3157, 3177, 3196, 3215, 3234, 3253, 3272, 3291, 3311,
+3330, 3349, 3368, 3387, 3406, 3425, 3444, 3464, 3483, 3502, 3521,
+3540, 3559, 3578, 3598, 3617, 3636, 3655, 3674, 3693, 3712, 3732,
+3751, 3770, 3789, 3808, 3827, 3846, 3865, 3885, 3904, 3923, 3942,
+3961, 3980, 3999, 4019, 4038, 4057, 4076, 4095, 4114, 4133, 4153,
+4172, 4191, 4210, 4229, 4248, 4267, 4286, 4306, 4325, 4344, 4363,
+4382, 4401, 4420, 4440, 4459, 4478, 4497, 4516, 4535, 4554, 4574,
+4593, 4612, 4631, 4650, 4669, 4688, 4707, 4727, 4746, 4765, 4784,
+4803, 4822, 4841, 4861, 4880 };
+
+static INT16 Y_G[] = { 0, 38, 75, 113, 150, 188, 225, 263, 301, 338,
+376, 413, 451, 488, 526, 564, 601, 639, 676, 714, 751, 789, 826, 864,
+902, 939, 977, 1014, 1052, 1089, 1127, 1165, 1202, 1240, 1277, 1315,
+1352, 1390, 1428, 1465, 1503, 1540, 1578, 1615, 1653, 1691, 1728,
+1766, 1803, 1841, 1878, 1916, 1954, 1991, 2029, 2066, 2104, 2141,
+2179, 2217, 2254, 2292, 2329, 2367, 2404, 2442, 2479, 2517, 2555,
+2592, 2630, 2667, 2705, 2742, 2780, 2818, 2855, 2893, 2930, 2968,
+3005, 3043, 3081, 3118, 3156, 3193, 3231, 3268, 3306, 3344, 3381,
+3419, 3456, 3494, 3531, 3569, 3607, 3644, 3682, 3719, 3757, 3794,
+3832, 3870, 3907, 3945, 3982, 4020, 4057, 4095, 4132, 4170, 4208,
+4245, 4283, 4320, 4358, 4395, 4433, 4471, 4508, 4546, 4583, 4621,
+4658, 4696, 4734, 4771, 4809, 4846, 4884, 4921, 4959, 4997, 5034,
+5072, 5109, 5147, 5184, 5222, 5260, 5297, 5335, 5372, 5410, 5447,
+5485, 5522, 5560, 5598, 5635, 5673, 5710, 5748, 5785, 5823, 5861,
+5898, 5936, 5973, 6011, 6048, 6086, 6124, 6161, 6199, 6236, 6274,
+6311, 6349, 6387, 6424, 6462, 6499, 6537, 6574, 6612, 6650, 6687,
+6725, 6762, 6800, 6837, 6875, 6913, 6950, 6988, 7025, 7063, 7100,
+7138, 7175, 7213, 7251, 7288, 7326, 7363, 7401, 7438, 7476, 7514,
+7551, 7589, 7626, 7664, 7701, 7739, 7777, 7814, 7852, 7889, 7927,
+7964, 8002, 8040, 8077, 8115, 8152, 8190, 8227, 8265, 8303, 8340,
+8378, 8415, 8453, 8490, 8528, 8566, 8603, 8641, 8678, 8716, 8753,
+8791, 8828, 8866, 8904, 8941, 8979, 9016, 9054, 9091, 9129, 9167,
+9204, 9242, 9279, 9317, 9354, 9392, 9430, 9467, 9505, 9542, 9580 };
+
+static INT16 Y_B[] = { 0, 7, 15, 22, 29, 36, 44, 51, 58, 66, 73, 80,
+88, 95, 102, 109, 117, 124, 131, 139, 146, 153, 161, 168, 175, 182,
+190, 197, 204, 212, 219, 226, 233, 241, 248, 255, 263, 270, 277, 285,
+292, 299, 306, 314, 321, 328, 336, 343, 350, 358, 365, 372, 379, 387,
+394, 401, 409, 416, 423, 430, 438, 445, 452, 460, 467, 474, 482, 489,
+496, 503, 511, 518, 525, 533, 540, 547, 554, 562, 569, 576, 584, 591,
+598, 606, 613, 620, 627, 635, 642, 649, 657, 664, 671, 679, 686, 693,
+700, 708, 715, 722, 730, 737, 744, 751, 759, 766, 773, 781, 788, 795,
+803, 810, 817, 824, 832, 839, 846, 854, 861, 868, 876, 883, 890, 897,
+905, 912, 919, 927, 934, 941, 948, 956, 963, 970, 978, 985, 992, 1000,
+1007, 1014, 1021, 1029, 1036, 1043, 1051, 1058, 1065, 1073, 1080,
+1087, 1094, 1102, 1109, 1116, 1124, 1131, 1138, 1145, 1153, 1160,
+1167, 1175, 1182, 1189, 1197, 1204, 1211, 1218, 1226, 1233, 1240,
+1248, 1255, 1262, 1270, 1277, 1284, 1291, 1299, 1306, 1313, 1321,
+1328, 1335, 1342, 1350, 1357, 1364, 1372, 1379, 1386, 1394, 1401,
+1408, 1415, 1423, 1430, 1437, 1445, 1452, 1459, 1466, 1474, 1481,
+1488, 1496, 1503, 1510, 1518, 1525, 1532, 1539, 1547, 1554, 1561,
+1569, 1576, 1583, 1591, 1598, 1605, 1612, 1620, 1627, 1634, 1642,
+1649, 1656, 1663, 1671, 1678, 1685, 1693, 1700, 1707, 1715, 1722,
+1729, 1736, 1744, 1751, 1758, 1766, 1773, 1780, 1788, 1795, 1802,
+1809, 1817, 1824, 1831, 1839, 1846, 1853, 1860 };
+
+static INT16 Cb_R[] = { 0, -10, -21, -31, -42, -53, -64, -75, -85,
+-96, -107, -118, -129, -139, -150, -161, -172, -183, -193, -204, -215,
+-226, -237, -247, -258, -269, -280, -291, -301, -312, -323, -334,
+-345, -355, -366, -377, -388, -399, -409, -420, -431, -442, -453,
+-463, -474, -485, -496, -507, -517, -528, -539, -550, -561, -571,
+-582, -593, -604, -615, -625, -636, -647, -658, -669, -679, -690,
+-701, -712, -723, -733, -744, -755, -766, -777, -787, -798, -809,
+-820, -831, -841, -852, -863, -874, -885, -895, -906, -917, -928,
+-939, -949, -960, -971, -982, -993, -1003, -1014, -1025, -1036, -1047,
+-1057, -1068, -1079, -1090, -1101, -1111, -1122, -1133, -1144, -1155,
+-1165, -1176, -1187, -1198, -1209, -1219, -1230, -1241, -1252, -1263,
+-1273, -1284, -1295, -1306, -1317, -1327, -1338, -1349, -1360, -1371,
+-1381, -1392, -1403, -1414, -1425, -1435, -1446, -1457, -1468, -1479,
+-1489, -1500, -1511, -1522, -1533, -1543, -1554, -1565, -1576, -1587,
+-1597, -1608, -1619, -1630, -1641, -1651, -1662, -1673, -1684, -1694,
+-1705, -1716, -1727, -1738, -1748, -1759, -1770, -1781, -1792, -1802,
+-1813, -1824, -1835, -1846, -1856, -1867, -1878, -1889, -1900, -1910,
+-1921, -1932, -1943, -1954, -1964, -1975, -1986, -1997, -2008, -2018,
+-2029, -2040, -2051, -2062, -2072, -2083, -2094, -2105, -2116, -2126,
+-2137, -2148, -2159, -2170, -2180, -2191, -2202, -2213, -2224, -2234,
+-2245, -2256, -2267, -2278, -2288, -2299, -2310, -2321, -2332, -2342,
+-2353, -2364, -2375, -2386, -2396, -2407, -2418, -2429, -2440, -2450,
+-2461, -2472, -2483, -2494, -2504, -2515, -2526, -2537, -2548, -2558,
+-2569, -2580, -2591, -2602, -2612, -2623, -2634, -2645, -2656, -2666,
+-2677, -2688, -2699, -2710, -2720, -2731, -2742, -2753 };
+
+static INT16 Cb_G[] = { 0, -20, -41, -63, -84, -105, -126, -147, -169,
+-190, -211, -232, -253, -275, -296, -317, -338, -359, -381, -402,
+-423, -444, -465, -487, -508, -529, -550, -571, -593, -614, -635,
+-656, -677, -699, -720, -741, -762, -783, -805, -826, -847, -868,
+-889, -911, -932, -953, -974, -995, -1017, -1038, -1059, -1080, -1101,
+-1123, -1144, -1165, -1186, -1207, -1229, -1250, -1271, -1292, -1313,
+-1335, -1356, -1377, -1398, -1419, -1441, -1462, -1483, -1504, -1525,
+-1547, -1568, -1589, -1610, -1631, -1653, -1674, -1695, -1716, -1737,
+-1759, -1780, -1801, -1822, -1843, -1865, -1886, -1907, -1928, -1949,
+-1971, -1992, -2013, -2034, -2055, -2077, -2098, -2119, -2140, -2161,
+-2183, -2204, -2225, -2246, -2267, -2289, -2310, -2331, -2352, -2373,
+-2395, -2416, -2437, -2458, -2479, -2501, -2522, -2543, -2564, -2585,
+-2607, -2628, -2649, -2670, -2691, -2713, -2734, -2755, -2776, -2797,
+-2819, -2840, -2861, -2882, -2903, -2925, -2946, -2967, -2988, -3009,
+-3031, -3052, -3073, -3094, -3115, -3137, -3158, -3179, -3200, -3221,
+-3243, -3264, -3285, -3306, -3328, -3349, -3370, -3391, -3412, -3434,
+-3455, -3476, -3497, -3518, -3540, -3561, -3582, -3603, -3624, -3646,
+-3667, -3688, -3709, -3730, -3752, -3773, -3794, -3815, -3836, -3858,
+-3879, -3900, -3921, -3942, -3964, -3985, -4006, -4027, -4048, -4070,
+-4091, -4112, -4133, -4154, -4176, -4197, -4218, -4239, -4260, -4282,
+-4303, -4324, -4345, -4366, -4388, -4409, -4430, -4451, -4472, -4494,
+-4515, -4536, -4557, -4578, -4600, -4621, -4642, -4663, -4684, -4706,
+-4727, -4748, -4769, -4790, -4812, -4833, -4854, -4875, -4896, -4918,
+-4939, -4960, -4981, -5002, -5024, -5045, -5066, -5087, -5108, -5130,
+-5151, -5172, -5193, -5214, -5236, -5257, -5278, -5299, -5320, -5342,
+-5363, -5384, -5405 };
+
+static INT16 Cb_B[] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288,
+320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, 736,
+768, 800, 832, 864, 896, 928, 960, 992, 1024, 1056, 1088, 1120, 1152,
+1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472, 1504,
+1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856,
+1888, 1920, 1952, 1984, 2016, 2048, 2080, 2112, 2144, 2176, 2208,
+2240, 2272, 2304, 2336, 2368, 2400, 2432, 2464, 2496, 2528, 2560,
+2592, 2624, 2656, 2688, 2720, 2752, 2784, 2816, 2848, 2880, 2912,
+2944, 2976, 3008, 3040, 3072, 3104, 3136, 3168, 3200, 3232, 3264,
+3296, 3328, 3360, 3392, 3424, 3456, 3488, 3520, 3552, 3584, 3616,
+3648, 3680, 3712, 3744, 3776, 3808, 3840, 3872, 3904, 3936, 3968,
+4000, 4032, 4064, 4096, 4128, 4160, 4192, 4224, 4256, 4288, 4320,
+4352, 4384, 4416, 4448, 4480, 4512, 4544, 4576, 4608, 4640, 4672,
+4704, 4736, 4768, 4800, 4832, 4864, 4896, 4928, 4960, 4992, 5024,
+5056, 5088, 5120, 5152, 5184, 5216, 5248, 5280, 5312, 5344, 5376,
+5408, 5440, 5472, 5504, 5536, 5568, 5600, 5632, 5664, 5696, 5728,
+5760, 5792, 5824, 5856, 5888, 5920, 5952, 5984, 6016, 6048, 6080,
+6112, 6144, 6176, 6208, 6240, 6272, 6304, 6336, 6368, 6400, 6432,
+6464, 6496, 6528, 6560, 6592, 6624, 6656, 6688, 6720, 6752, 6784,
+6816, 6848, 6880, 6912, 6944, 6976, 7008, 7040, 7072, 7104, 7136,
+7168, 7200, 7232, 7264, 7296, 7328, 7360, 7392, 7424, 7456, 7488,
+7520, 7552, 7584, 7616, 7648, 7680, 7712, 7744, 7776, 7808, 7840,
+7872, 7904, 7936, 7968, 8000, 8032, 8064, 8096, 8128, 8160 };
+
+#define Cr_R Cb_B
+
+static INT16 Cr_G[] = { 0, -26, -53, -79, -106, -133, -160, -187,
+-213, -240, -267, -294, -321, -347, -374, -401, -428, -455, -481,
+-508, -535, -562, -589, -615, -642, -669, -696, -722, -749, -776,
+-803, -830, -856, -883, -910, -937, -964, -990, -1017, -1044, -1071,
+-1098, -1124, -1151, -1178, -1205, -1232, -1258, -1285, -1312, -1339,
+-1366, -1392, -1419, -1446, -1473, -1500, -1526, -1553, -1580, -1607,
+-1634, -1660, -1687, -1714, -1741, -1768, -1794, -1821, -1848, -1875,
+-1902, -1928, -1955, -1982, -2009, -2036, -2062, -2089, -2116, -2143,
+-2169, -2196, -2223, -2250, -2277, -2303, -2330, -2357, -2384, -2411,
+-2437, -2464, -2491, -2518, -2545, -2571, -2598, -2625, -2652, -2679,
+-2705, -2732, -2759, -2786, -2813, -2839, -2866, -2893, -2920, -2947,
+-2973, -3000, -3027, -3054, -3081, -3107, -3134, -3161, -3188, -3215,
+-3241, -3268, -3295, -3322, -3349, -3375, -3402, -3429, -3456, -3483,
+-3509, -3536, -3563, -3590, -3616, -3643, -3670, -3697, -3724, -3750,
+-3777, -3804, -3831, -3858, -3884, -3911, -3938, -3965, -3992, -4018,
+-4045, -4072, -4099, -4126, -4152, -4179, -4206, -4233, -4260, -4286,
+-4313, -4340, -4367, -4394, -4420, -4447, -4474, -4501, -4528, -4554,
+-4581, -4608, -4635, -4662, -4688, -4715, -4742, -4769, -4796, -4822,
+-4849, -4876, -4903, -4929, -4956, -4983, -5010, -5037, -5063, -5090,
+-5117, -5144, -5171, -5197, -5224, -5251, -5278, -5305, -5331, -5358,
+-5385, -5412, -5439, -5465, -5492, -5519, -5546, -5573, -5599, -5626,
+-5653, -5680, -5707, -5733, -5760, -5787, -5814, -5841, -5867, -5894,
+-5921, -5948, -5975, -6001, -6028, -6055, -6082, -6109, -6135, -6162,
+-6189, -6216, -6243, -6269, -6296, -6323, -6350, -6376, -6403, -6430,
+-6457, -6484, -6510, -6537, -6564, -6591, -6618, -6644, -6671, -6698,
+-6725, -6752, -6778, -6805, -6832 };
+
+static INT16 Cr_B[] = { 0, -4, -9, -15, -20, -25, -30, -35, -41, -46,
+-51, -56, -61, -67, -72, -77, -82, -87, -93, -98, -103, -108, -113,
+-119, -124, -129, -134, -140, -145, -150, -155, -160, -166, -171,
+-176, -181, -186, -192, -197, -202, -207, -212, -218, -223, -228,
+-233, -238, -244, -249, -254, -259, -264, -270, -275, -280, -285,
+-290, -296, -301, -306, -311, -316, -322, -327, -332, -337, -342,
+-348, -353, -358, -363, -368, -374, -379, -384, -389, -394, -400,
+-405, -410, -415, -421, -426, -431, -436, -441, -447, -452, -457,
+-462, -467, -473, -478, -483, -488, -493, -499, -504, -509, -514,
+-519, -525, -530, -535, -540, -545, -551, -556, -561, -566, -571,
+-577, -582, -587, -592, -597, -603, -608, -613, -618, -623, -629,
+-634, -639, -644, -649, -655, -660, -665, -670, -675, -681, -686,
+-691, -696, -702, -707, -712, -717, -722, -728, -733, -738, -743,
+-748, -754, -759, -764, -769, -774, -780, -785, -790, -795, -800,
+-806, -811, -816, -821, -826, -832, -837, -842, -847, -852, -858,
+-863, -868, -873, -878, -884, -889, -894, -899, -904, -910, -915,
+-920, -925, -930, -936, -941, -946, -951, -957, -962, -967, -972,
+-977, -983, -988, -993, -998, -1003, -1009, -1014, -1019, -1024,
+-1029, -1035, -1040, -1045, -1050, -1055, -1061, -1066, -1071, -1076,
+-1081, -1087, -1092, -1097, -1102, -1107, -1113, -1118, -1123, -1128,
+-1133, -1139, -1144, -1149, -1154, -1159, -1165, -1170, -1175, -1180,
+-1185, -1191, -1196, -1201, -1206, -1211, -1217, -1222, -1227, -1232,
+-1238, -1243, -1248, -1253, -1258, -1264, -1269, -1274, -1279, -1284,
+-1290, -1295, -1300, -1305, -1310, -1316, -1321, -1326 };
+
+static INT16 R_Cr[] = { -11484, -11394, -11305, -11215, -11125,
+-11036, -10946, -10856, -10766, -10677, -10587, -10497, -10407,
+-10318, -10228, -10138, -10049, -9959, -9869, -9779, -9690, -9600,
+-9510, -9420, -9331, -9241, -9151, -9062, -8972, -8882, -8792, -8703,
+-8613, -8523, -8433, -8344, -8254, -8164, -8075, -7985, -7895, -7805,
+-7716, -7626, -7536, -7446, -7357, -7267, -7177, -7088, -6998, -6908,
+-6818, -6729, -6639, -6549, -6459, -6370, -6280, -6190, -6101, -6011,
+-5921, -5831, -5742, -5652, -5562, -5472, -5383, -5293, -5203, -5113,
+-5024, -4934, -4844, -4755, -4665, -4575, -4485, -4396, -4306, -4216,
+-4126, -4037, -3947, -3857, -3768, -3678, -3588, -3498, -3409, -3319,
+-3229, -3139, -3050, -2960, -2870, -2781, -2691, -2601, -2511, -2422,
+-2332, -2242, -2152, -2063, -1973, -1883, -1794, -1704, -1614, -1524,
+-1435, -1345, -1255, -1165, -1076, -986, -896, -807, -717, -627, -537,
+-448, -358, -268, -178, -89, 0, 90, 179, 269, 359, 449, 538, 628, 718,
+808, 897, 987, 1077, 1166, 1256, 1346, 1436, 1525, 1615, 1705, 1795,
+1884, 1974, 2064, 2153, 2243, 2333, 2423, 2512, 2602, 2692, 2782,
+2871, 2961, 3051, 3140, 3230, 3320, 3410, 3499, 3589, 3679, 3769,
+3858, 3948, 4038, 4127, 4217, 4307, 4397, 4486, 4576, 4666, 4756,
+4845, 4935, 5025, 5114, 5204, 5294, 5384, 5473, 5563, 5653, 5743,
+5832, 5922, 6012, 6102, 6191, 6281, 6371, 6460, 6550, 6640, 6730,
+6819, 6909, 6999, 7089, 7178, 7268, 7358, 7447, 7537, 7627, 7717,
+7806, 7896, 7986, 8076, 8165, 8255, 8345, 8434, 8524, 8614, 8704,
+8793, 8883, 8973, 9063, 9152, 9242, 9332, 9421, 9511, 9601, 9691,
+9780, 9870, 9960, 10050, 10139, 10229, 10319, 10408, 10498, 10588,
+10678, 10767, 10857, 10947, 11037, 11126, 11216, 11306, 11395 };
+
+static INT16 G_Cb[] = { 2819, 2797, 2775, 2753, 2731, 2709, 2687,
+2665, 2643, 2621, 2599, 2577, 2555, 2533, 2511, 2489, 2467, 2445,
+2423, 2401, 2379, 2357, 2335, 2313, 2291, 2269, 2247, 2225, 2202,
+2180, 2158, 2136, 2114, 2092, 2070, 2048, 2026, 2004, 1982, 1960,
+1938, 1916, 1894, 1872, 1850, 1828, 1806, 1784, 1762, 1740, 1718,
+1696, 1674, 1652, 1630, 1608, 1586, 1564, 1542, 1520, 1498, 1476,
+1454, 1432, 1410, 1388, 1366, 1344, 1321, 1299, 1277, 1255, 1233,
+1211, 1189, 1167, 1145, 1123, 1101, 1079, 1057, 1035, 1013, 991, 969,
+947, 925, 903, 881, 859, 837, 815, 793, 771, 749, 727, 705, 683, 661,
+639, 617, 595, 573, 551, 529, 507, 485, 463, 440, 418, 396, 374, 352,
+330, 308, 286, 264, 242, 220, 198, 176, 154, 132, 110, 88, 66, 44, 22,
+0, -21, -43, -65, -87, -109, -131, -153, -175, -197, -219, -241, -263,
+-285, -307, -329, -351, -373, -395, -417, -439, -462, -484, -506,
+-528, -550, -572, -594, -616, -638, -660, -682, -704, -726, -748,
+-770, -792, -814, -836, -858, -880, -902, -924, -946, -968, -990,
+-1012, -1034, -1056, -1078, -1100, -1122, -1144, -1166, -1188, -1210,
+-1232, -1254, -1276, -1298, -1320, -1343, -1365, -1387, -1409, -1431,
+-1453, -1475, -1497, -1519, -1541, -1563, -1585, -1607, -1629, -1651,
+-1673, -1695, -1717, -1739, -1761, -1783, -1805, -1827, -1849, -1871,
+-1893, -1915, -1937, -1959, -1981, -2003, -2025, -2047, -2069, -2091,
+-2113, -2135, -2157, -2179, -2201, -2224, -2246, -2268, -2290, -2312,
+-2334, -2356, -2378, -2400, -2422, -2444, -2466, -2488, -2510, -2532,
+-2554, -2576, -2598, -2620, -2642, -2664, -2686, -2708, -2730, -2752,
+-2774, -2796 };
+
+static INT16 G_Cr[] = { 5850, 5805, 5759, 5713, 5667, 5622, 5576,
+5530, 5485, 5439, 5393, 5347, 5302, 5256, 5210, 5165, 5119, 5073,
+5028, 4982, 4936, 4890, 4845, 4799, 4753, 4708, 4662, 4616, 4570,
+4525, 4479, 4433, 4388, 4342, 4296, 4251, 4205, 4159, 4113, 4068,
+4022, 3976, 3931, 3885, 3839, 3794, 3748, 3702, 3656, 3611, 3565,
+3519, 3474, 3428, 3382, 3336, 3291, 3245, 3199, 3154, 3108, 3062,
+3017, 2971, 2925, 2879, 2834, 2788, 2742, 2697, 2651, 2605, 2559,
+2514, 2468, 2422, 2377, 2331, 2285, 2240, 2194, 2148, 2102, 2057,
+2011, 1965, 1920, 1874, 1828, 1782, 1737, 1691, 1645, 1600, 1554,
+1508, 1463, 1417, 1371, 1325, 1280, 1234, 1188, 1143, 1097, 1051,
+1006, 960, 914, 868, 823, 777, 731, 686, 640, 594, 548, 503, 457, 411,
+366, 320, 274, 229, 183, 137, 91, 46, 0, -45, -90, -136, -182, -228,
+-273, -319, -365, -410, -456, -502, -547, -593, -639, -685, -730,
+-776, -822, -867, -913, -959, -1005, -1050, -1096, -1142, -1187,
+-1233, -1279, -1324, -1370, -1416, -1462, -1507, -1553, -1599, -1644,
+-1690, -1736, -1781, -1827, -1873, -1919, -1964, -2010, -2056, -2101,
+-2147, -2193, -2239, -2284, -2330, -2376, -2421, -2467, -2513, -2558,
+-2604, -2650, -2696, -2741, -2787, -2833, -2878, -2924, -2970, -3016,
+-3061, -3107, -3153, -3198, -3244, -3290, -3335, -3381, -3427, -3473,
+-3518, -3564, -3610, -3655, -3701, -3747, -3793, -3838, -3884, -3930,
+-3975, -4021, -4067, -4112, -4158, -4204, -4250, -4295, -4341, -4387,
+-4432, -4478, -4524, -4569, -4615, -4661, -4707, -4752, -4798, -4844,
+-4889, -4935, -4981, -5027, -5072, -5118, -5164, -5209, -5255, -5301,
+-5346, -5392, -5438, -5484, -5529, -5575, -5621, -5666, -5712, -5758,
+-5804 };
+
+static INT16 B_Cb[] = { -14515, -14402, -14288, -14175, -14062,
+-13948, -13835, -13721, -13608, -13495, -13381, -13268, -13154,
+-13041, -12928, -12814, -12701, -12587, -12474, -12360, -12247,
+-12134, -12020, -11907, -11793, -11680, -11567, -11453, -11340,
+-11226, -11113, -11000, -10886, -10773, -10659, -10546, -10433,
+-10319, -10206, -10092, -9979, -9865, -9752, -9639, -9525, -9412,
+-9298, -9185, -9072, -8958, -8845, -8731, -8618, -8505, -8391, -8278,
+-8164, -8051, -7938, -7824, -7711, -7597, -7484, -7371, -7257, -7144,
+-7030, -6917, -6803, -6690, -6577, -6463, -6350, -6236, -6123, -6010,
+-5896, -5783, -5669, -5556, -5443, -5329, -5216, -5102, -4989, -4876,
+-4762, -4649, -4535, -4422, -4309, -4195, -4082, -3968, -3855, -3741,
+-3628, -3515, -3401, -3288, -3174, -3061, -2948, -2834, -2721, -2607,
+-2494, -2381, -2267, -2154, -2040, -1927, -1814, -1700, -1587, -1473,
+-1360, -1246, -1133, -1020, -906, -793, -679, -566, -453, -339, -226,
+-112, 0, 113, 227, 340, 454, 567, 680, 794, 907, 1021, 1134, 1247,
+1361, 1474, 1588, 1701, 1815, 1928, 2041, 2155, 2268, 2382, 2495,
+2608, 2722, 2835, 2949, 3062, 3175, 3289, 3402, 3516, 3629, 3742,
+3856, 3969, 4083, 4196, 4310, 4423, 4536, 4650, 4763, 4877, 4990,
+5103, 5217, 5330, 5444, 5557, 5670, 5784, 5897, 6011, 6124, 6237,
+6351, 6464, 6578, 6691, 6804, 6918, 7031, 7145, 7258, 7372, 7485,
+7598, 7712, 7825, 7939, 8052, 8165, 8279, 8392, 8506, 8619, 8732,
+8846, 8959, 9073, 9186, 9299, 9413, 9526, 9640, 9753, 9866, 9980,
+10093, 10207, 10320, 10434, 10547, 10660, 10774, 10887, 11001, 11114,
+11227, 11341, 11454, 11568, 11681, 11794, 11908, 12021, 12135, 12248,
+12361, 12475, 12588, 12702, 12815, 12929, 13042, 13155, 13269, 13382,
+13496, 13609, 13722, 13836, 13949, 14063, 14176, 14289, 14403 };
+
+
+void
+ImagingConvertRGB2YCbCr(UINT8* out, const UINT8* in, int pixels)
+{
+ int x;
+ UINT8 a;
+ int r, g, b;
+ int y, cr, cb;
+
+ for (x = 0; x < pixels; x++, in +=4, out += 4) {
+
+ r = in[0];
+ g = in[1];
+ b = in[2];
+ a = in[3];
+
+ y = (Y_R[r] + Y_G[g] + Y_B[b]) >> SCALE;
+ cb = ((Cb_R[r] + Cb_G[g] + Cb_B[b]) >> SCALE) + 128;
+ cr = ((Cr_R[r] + Cr_G[g] + Cr_B[b]) >> SCALE) + 128;
+
+ out[0] = (UINT8) y;
+ out[1] = (UINT8) cb;
+ out[2] = (UINT8) cr;
+ out[3] = a;
+ }
+}
+
+void
+ImagingConvertYCbCr2RGB(UINT8* out, const UINT8* in, int pixels)
+{
+ int x;
+ UINT8 a;
+ int r, g, b;
+ int y, cr, cb;
+
+ for (x = 0; x < pixels; x++, in += 4, out += 4) {
+
+ y = in[0];
+ cb = in[1];
+ cr = in[2];
+ a = in[3];
+
+ r = y + (( R_Cr[cr]) >> SCALE);
+ g = y + ((G_Cb[cb] + G_Cr[cr]) >> SCALE);
+ b = y + ((B_Cb[cb] ) >> SCALE);
+
+ out[0] = (r <= 0) ? 0 : (r >= 255) ? 255 : r;
+ out[1] = (g <= 0) ? 0 : (g >= 255) ? 255 : g;
+ out[2] = (b <= 0) ? 0 : (b >= 255) ? 255 : b;
+ out[3] = a;
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Copy.c b/contrib/python/Pillow/py2/libImaging/Copy.c
new file mode 100644
index 0000000000..1bc9b1a709
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Copy.c
@@ -0,0 +1,58 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * copy image
+ *
+ * history:
+ * 95-11-26 fl Moved from Imaging.c
+ * 97-05-12 fl Added ImagingCopy2
+ * 97-08-28 fl Allow imOut == NULL in ImagingCopy2
+ *
+ * Copyright (c) Fredrik Lundh 1995-97.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+static Imaging
+_copy(Imaging imOut, Imaging imIn)
+{
+ ImagingSectionCookie cookie;
+ int y;
+
+ if (!imIn)
+ return (Imaging) ImagingError_ValueError(NULL);
+
+ imOut = ImagingNew2Dirty(imIn->mode, imOut, imIn);
+ if (!imOut)
+ return NULL;
+
+ ImagingCopyPalette(imOut, imIn);
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->block != NULL && imOut->block != NULL)
+ memcpy(imOut->block, imIn->block, imIn->ysize * imIn->linesize);
+ else
+ for (y = 0; y < imIn->ysize; y++)
+ memcpy(imOut->image[y], imIn->image[y], imIn->linesize);
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+Imaging
+ImagingCopy(Imaging imIn)
+{
+ return _copy(NULL, imIn);
+}
+
+Imaging
+ImagingCopy2(Imaging imOut, Imaging imIn)
+{
+ return _copy(imOut, imIn);
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Crop.c b/contrib/python/Pillow/py2/libImaging/Crop.c
new file mode 100644
index 0000000000..4407c1b1d2
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Crop.c
@@ -0,0 +1,61 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * cut region from image
+ *
+ * history:
+ * 95-11-27 fl Created
+ * 98-07-10 fl Fixed "null result" error
+ * 99-02-05 fl Rewritten to use Paste primitive
+ *
+ * Copyright (c) Secret Labs AB 1997-99.
+ * Copyright (c) Fredrik Lundh 1995.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+Imaging
+ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1)
+{
+ Imaging imOut;
+ int xsize, ysize;
+ int dx0, dy0, dx1, dy1;
+ INT32 zero = 0;
+
+ if (!imIn)
+ return (Imaging) ImagingError_ModeError();
+
+ xsize = sx1 - sx0;
+ if (xsize < 0)
+ xsize = 0;
+ ysize = sy1 - sy0;
+ if (ysize < 0)
+ ysize = 0;
+
+ imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
+ if (!imOut)
+ return NULL;
+
+ ImagingCopyPalette(imOut, imIn);
+
+ if (sx0 < 0 || sy0 < 0 || sx1 > imIn->xsize || sy1 > imIn->ysize)
+ (void) ImagingFill(imOut, &zero);
+
+ dx0 = -sx0;
+ dy0 = -sy0;
+ dx1 = imIn->xsize - sx0;
+ dy1 = imIn->ysize - sy0;
+
+ /* paste the source image on top of the output image!!! */
+ if (ImagingPaste(imOut, imIn, NULL, dx0, dy0, dx1, dy1) < 0) {
+ ImagingDelete(imOut);
+ return NULL;
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Dib.c b/contrib/python/Pillow/py2/libImaging/Dib.c
new file mode 100644
index 0000000000..5042902316
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Dib.c
@@ -0,0 +1,300 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * imaging display object for Windows
+ *
+ * history:
+ * 1996-05-12 fl Created
+ * 1996-05-17 fl Up and running
+ * 1996-05-21 fl Added palette stuff
+ * 1996-05-26 fl Added query palette and mode inquery
+ * 1997-09-21 fl Added draw primitive
+ * 1998-01-20 fl Use StretchDIBits instead of StretchBlt
+ * 1998-12-30 fl Plugged a resource leak in DeleteDIB (from Roger Burnham)
+ *
+ * Copyright (c) Secret Labs AB 1997-2001.
+ * Copyright (c) Fredrik Lundh 1996.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#ifdef _WIN32
+
+#include "ImDib.h"
+
+
+char*
+ImagingGetModeDIB(int size_out[2])
+{
+ /* Get device characteristics */
+
+ HDC dc;
+ char* mode;
+
+ dc = CreateCompatibleDC(NULL);
+
+ mode = "P";
+ if (!(GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE)) {
+ mode = "RGB";
+ if (GetDeviceCaps(dc, BITSPIXEL) == 1)
+ mode = "1";
+ }
+
+ if (size_out) {
+ size_out[0] = GetDeviceCaps(dc, HORZRES);
+ size_out[1] = GetDeviceCaps(dc, VERTRES);
+ }
+
+ DeleteDC(dc);
+
+ return mode;
+}
+
+
+ImagingDIB
+ImagingNewDIB(const char *mode, int xsize, int ysize)
+{
+ /* Create a Windows bitmap */
+
+ ImagingDIB dib;
+ RGBQUAD *palette;
+ int i;
+
+ /* Check mode */
+ if (strcmp(mode, "1") != 0 && strcmp(mode, "L") != 0 &&
+ strcmp(mode, "RGB") != 0)
+ return (ImagingDIB) ImagingError_ModeError();
+
+ /* Create DIB context and info header */
+ /* malloc check ok, small constant allocation */
+ dib = (ImagingDIB) malloc(sizeof(*dib));
+ if (!dib)
+ return (ImagingDIB) ImagingError_MemoryError();
+ /* malloc check ok, small constant allocation */
+ dib->info = (BITMAPINFO*) malloc(sizeof(BITMAPINFOHEADER) +
+ 256 * sizeof(RGBQUAD));
+ if (!dib->info) {
+ free(dib);
+ return (ImagingDIB) ImagingError_MemoryError();
+ }
+
+ memset(dib->info, 0, sizeof(BITMAPINFOHEADER));
+ dib->info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dib->info->bmiHeader.biWidth = xsize;
+ dib->info->bmiHeader.biHeight = ysize;
+ dib->info->bmiHeader.biPlanes = 1;
+ dib->info->bmiHeader.biBitCount = strlen(mode)*8;
+ dib->info->bmiHeader.biCompression = BI_RGB;
+
+ /* Create DIB */
+ dib->dc = CreateCompatibleDC(NULL);
+ if (!dib->dc) {
+ free(dib->info);
+ free(dib);
+ return (ImagingDIB) ImagingError_MemoryError();
+ }
+
+ dib->bitmap = CreateDIBSection(dib->dc, dib->info, DIB_RGB_COLORS,
+ &dib->bits, NULL, 0);
+ if (!dib->bitmap) {
+ free(dib->info);
+ free(dib);
+ return (ImagingDIB) ImagingError_MemoryError();
+ }
+
+ strcpy(dib->mode, mode);
+ dib->xsize = xsize;
+ dib->ysize = ysize;
+
+ dib->pixelsize = strlen(mode);
+ dib->linesize = (xsize * dib->pixelsize + 3) & -4;
+
+ if (dib->pixelsize == 1)
+ dib->pack = dib->unpack = (ImagingShuffler) memcpy;
+ else {
+ dib->pack = ImagingPackBGR;
+ dib->unpack = ImagingPackBGR;
+ }
+
+ /* Bind the DIB to the device context */
+ dib->old_bitmap = SelectObject(dib->dc, dib->bitmap);
+
+ palette = dib->info->bmiColors;
+
+ /* Bind a palette to it as well (only required for 8-bit DIBs) */
+ if (dib->pixelsize == 1) {
+ for (i = 0; i < 256; i++) {
+ palette[i].rgbRed =
+ palette[i].rgbGreen =
+ palette[i].rgbBlue = i;
+ palette[i].rgbReserved = 0;
+ }
+ SetDIBColorTable(dib->dc, 0, 256, palette);
+ }
+
+ /* Create an associated palette (for 8-bit displays only) */
+ if (strcmp(ImagingGetModeDIB(NULL), "P") == 0) {
+
+ char palbuf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)];
+ LPLOGPALETTE pal = (LPLOGPALETTE) palbuf;
+ int i, r, g, b;
+
+ /* Load system palette */
+ pal->palVersion = 0x300;
+ pal->palNumEntries = 256;
+ GetSystemPaletteEntries(dib->dc, 0, 256, pal->palPalEntry);
+
+ if (strcmp(mode, "L") == 0) {
+
+ /* Greyscale DIB. Fill all 236 slots with a greyscale ramp
+ * (this is usually overkill on Windows since VGA only offers
+ * 6 bits greyscale resolution). Ignore the slots already
+ * allocated by Windows */
+
+ i = 10;
+ for (r = 0; r < 236; r++) {
+ pal->palPalEntry[i].peRed =
+ pal->palPalEntry[i].peGreen =
+ pal->palPalEntry[i].peBlue = i;
+ i++;
+ }
+
+ dib->palette = CreatePalette(pal);
+
+ } else if (strcmp(mode, "RGB") == 0) {
+
+#ifdef CUBE216
+
+ /* Colour DIB. Create a 6x6x6 colour cube (216 entries) and
+ * add 20 extra greylevels for best result with greyscale
+ * images. */
+
+ i = 10;
+ for (r = 0; r < 256; r += 51)
+ for (g = 0; g < 256; g += 51)
+ for (b = 0; b < 256; b += 51) {
+ pal->palPalEntry[i].peRed = r;
+ pal->palPalEntry[i].peGreen = g;
+ pal->palPalEntry[i].peBlue = b;
+ i++;
+ }
+ for (r = 1; r < 22-1; r++) {
+ /* Black and white are already provided by the cube. */
+ pal->palPalEntry[i].peRed =
+ pal->palPalEntry[i].peGreen =
+ pal->palPalEntry[i].peBlue = r * 255 / (22-1);
+ i++;
+ }
+
+#else
+
+ /* Colour DIB. Alternate palette. */
+
+ i = 10;
+ for (r = 0; r < 256; r += 37)
+ for (g = 0; g < 256; g += 32)
+ for (b = 0; b < 256; b += 64) {
+ pal->palPalEntry[i].peRed = r;
+ pal->palPalEntry[i].peGreen = g;
+ pal->palPalEntry[i].peBlue = b;
+ i++;
+ }
+
+#endif
+
+ dib->palette = CreatePalette(pal);
+
+ }
+
+ }
+
+ return dib;
+}
+
+void
+ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4])
+{
+ /* Paste image data into a bitmap */
+
+ /* FIXME: check size! */
+
+ int y;
+ for (y = 0; y < im->ysize; y++)
+ dib->pack(dib->bits + dib->linesize*(dib->ysize-(xy[1]+y)-1) +
+ xy[0]*dib->pixelsize, im->image[y], im->xsize);
+
+}
+
+void
+ImagingExposeDIB(ImagingDIB dib, void *dc)
+{
+ /* Copy bitmap to display */
+
+ if (dib->palette != 0)
+ SelectPalette((HDC) dc, dib->palette, FALSE);
+ BitBlt((HDC) dc, 0, 0, dib->xsize, dib->ysize, dib->dc, 0, 0, SRCCOPY);
+}
+
+void
+ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4])
+{
+ /* Copy bitmap to printer/display */
+
+ if (GetDeviceCaps((HDC) dc, RASTERCAPS) & RC_STRETCHDIB) {
+ /* stretchdib (printers) */
+ StretchDIBits((HDC) dc, dst[0], dst[1], dst[2]-dst[0], dst[3]-dst[1],
+ src[0], src[1], src[2]-src[0], src[3]-src[1], dib->bits,
+ dib->info, DIB_RGB_COLORS, SRCCOPY);
+ } else {
+ /* stretchblt (displays) */
+ if (dib->palette != 0)
+ SelectPalette((HDC) dc, dib->palette, FALSE);
+ StretchBlt((HDC) dc, dst[0], dst[1], dst[2]-dst[0], dst[3]-dst[1],
+ dib->dc, src[0], src[1], src[2]-src[0], src[3]-src[1],
+ SRCCOPY);
+ }
+}
+
+int
+ImagingQueryPaletteDIB(ImagingDIB dib, void *dc)
+{
+ /* Install bitmap palette */
+
+ int n;
+
+ if (dib->palette != 0) {
+
+ /* Realize associated palette */
+ HPALETTE now = SelectPalette((HDC) dc, dib->palette, FALSE);
+ n = RealizePalette((HDC) dc);
+
+ /* Restore palette */
+ SelectPalette((HDC) dc, now, FALSE);
+
+ } else
+ n = 0;
+
+ return n; /* number of colours that was changed */
+}
+
+void
+ImagingDeleteDIB(ImagingDIB dib)
+{
+ /* Clean up */
+
+ if (dib->palette)
+ DeleteObject(dib->palette);
+ if (dib->bitmap) {
+ SelectObject(dib->dc, dib->old_bitmap);
+ DeleteObject(dib->bitmap);
+ }
+ if (dib->dc)
+ DeleteDC(dib->dc);
+ free(dib->info);
+}
+
+#endif /* _WIN32 */
diff --git a/contrib/python/Pillow/py2/libImaging/Draw.c b/contrib/python/Pillow/py2/libImaging/Draw.c
new file mode 100644
index 0000000000..dee7c524db
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Draw.c
@@ -0,0 +1,1187 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * a simple drawing package for the Imaging library
+ *
+ * history:
+ * 1996-04-13 fl Created.
+ * 1996-04-30 fl Added transforms and polygon support.
+ * 1996-08-12 fl Added filled polygons.
+ * 1996-11-05 fl Fixed float/int confusion in polygon filler
+ * 1997-07-04 fl Support 32-bit images (C++ would have been nice)
+ * 1998-09-09 fl Eliminated qsort casts; improved rectangle clipping
+ * 1998-09-10 fl Fixed fill rectangle to include lower edge (!)
+ * 1998-12-29 fl Added arc, chord, and pieslice primitives
+ * 1999-01-10 fl Added some level 2 ("arrow") stuff (experimental)
+ * 1999-02-06 fl Added bitmap primitive
+ * 1999-07-26 fl Eliminated a compiler warning
+ * 1999-07-31 fl Pass ink as void* instead of int
+ * 2002-12-10 fl Added experimental RGBA-on-RGB drawing
+ * 2004-09-04 fl Support simple wide lines (no joins)
+ * 2005-05-25 fl Fixed line width calculation
+ *
+ * Copyright (c) 1996-2006 by Fredrik Lundh
+ * Copyright (c) 1997-2006 by Secret Labs AB.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+/* FIXME: support fill/outline attribute for all filled shapes */
+/* FIXME: support zero-winding fill */
+/* FIXME: add drawing context, support affine transforms */
+/* FIXME: support clip window (and mask?) */
+
+#include "Imaging.h"
+
+#include <math.h>
+
+#define CEIL(v) (int) ceil(v)
+#define FLOOR(v) ((v) >= 0.0 ? (int) (v) : (int) floor(v))
+
+#define INK8(ink) (*(UINT8*)ink)
+
+/*
+ * Rounds around zero (up=away from zero, down=torwards zero)
+ * This guarantees that ROUND_UP|DOWN(f) == -ROUND_UP|DOWN(-f)
+ */
+#define ROUND_UP(f) ((int) ((f) >= 0.0 ? floor((f) + 0.5F) : -floor(fabs(f) + 0.5F)))
+#define ROUND_DOWN(f) ((int) ((f) >= 0.0 ? ceil((f) - 0.5F) : -ceil(fabs(f) - 0.5F)))
+
+/* -------------------------------------------------------------------- */
+/* Primitives */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ /* edge descriptor for polygon engine */
+ int d;
+ int x0, y0;
+ int xmin, ymin, xmax, ymax;
+ float dx;
+} Edge;
+
+/* Type used in "polygon*" functions */
+typedef void (*hline_handler)(Imaging, int, int, int, int);
+
+static inline void
+point8(Imaging im, int x, int y, int ink)
+{
+ if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) {
+ if (strncmp(im->mode, "I;16", 4) == 0) {
+ im->image8[y][x*2] = (UINT8) ink;
+ im->image8[y][x*2+1] = (UINT8) ink;
+ } else {
+ im->image8[y][x] = (UINT8) ink;
+ }
+ }
+}
+
+static inline void
+point32(Imaging im, int x, int y, int ink)
+{
+ if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize)
+ im->image32[y][x] = ink;
+}
+
+static inline void
+point32rgba(Imaging im, int x, int y, int ink)
+{
+ unsigned int tmp1;
+
+ if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) {
+ UINT8* out = (UINT8*) im->image[y]+x*4;
+ UINT8* in = (UINT8*) &ink;
+ out[0] = BLEND(in[3], out[0], in[0], tmp1);
+ out[1] = BLEND(in[3], out[1], in[1], tmp1);
+ out[2] = BLEND(in[3], out[2], in[2], tmp1);
+ }
+}
+
+static inline void
+hline8(Imaging im, int x0, int y0, int x1, int ink)
+{
+ int tmp, pixelwidth;
+
+ if (y0 >= 0 && y0 < im->ysize) {
+ if (x0 > x1)
+ tmp = x0, x0 = x1, x1 = tmp;
+ if (x0 < 0)
+ x0 = 0;
+ else if (x0 >= im->xsize)
+ return;
+ if (x1 < 0)
+ return;
+ else if (x1 >= im->xsize)
+ x1 = im->xsize-1;
+ if (x0 <= x1) {
+ pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1;
+ memset(im->image8[y0] + x0 * pixelwidth, (UINT8) ink,
+ (x1 - x0 + 1) * pixelwidth);
+ }
+ }
+}
+
+static inline void
+hline32(Imaging im, int x0, int y0, int x1, int ink)
+{
+ int tmp;
+ INT32* p;
+
+ if (y0 >= 0 && y0 < im->ysize) {
+ if (x0 > x1)
+ tmp = x0, x0 = x1, x1 = tmp;
+ if (x0 < 0)
+ x0 = 0;
+ else if (x0 >= im->xsize)
+ return;
+ if (x1 < 0)
+ return;
+ else if (x1 >= im->xsize)
+ x1 = im->xsize-1;
+ p = im->image32[y0];
+ while (x0 <= x1)
+ p[x0++] = ink;
+ }
+}
+
+static inline void
+hline32rgba(Imaging im, int x0, int y0, int x1, int ink)
+{
+ int tmp;
+ unsigned int tmp1;
+
+ if (y0 >= 0 && y0 < im->ysize) {
+ if (x0 > x1)
+ tmp = x0, x0 = x1, x1 = tmp;
+ if (x0 < 0)
+ x0 = 0;
+ else if (x0 >= im->xsize)
+ return;
+ if (x1 < 0)
+ return;
+ else if (x1 >= im->xsize)
+ x1 = im->xsize-1;
+ if (x0 <= x1) {
+ UINT8* out = (UINT8*) im->image[y0]+x0*4;
+ UINT8* in = (UINT8*) &ink;
+ while (x0 <= x1) {
+ out[0] = BLEND(in[3], out[0], in[0], tmp1);
+ out[1] = BLEND(in[3], out[1], in[1], tmp1);
+ out[2] = BLEND(in[3], out[2], in[2], tmp1);
+ x0++; out += 4;
+ }
+ }
+ }
+}
+
+static inline void
+line8(Imaging im, int x0, int y0, int x1, int y1, int ink)
+{
+ int i, n, e;
+ int dx, dy;
+ int xs, ys;
+
+ /* normalize coordinates */
+ dx = x1-x0;
+ if (dx < 0)
+ dx = -dx, xs = -1;
+ else
+ xs = 1;
+ dy = y1-y0;
+ if (dy < 0)
+ dy = -dy, ys = -1;
+ else
+ ys = 1;
+
+ n = (dx > dy) ? dx : dy;
+
+ if (dx == 0)
+
+ /* vertical */
+ for (i = 0; i < dy; i++) {
+ point8(im, x0, y0, ink);
+ y0 += ys;
+ }
+
+ else if (dy == 0)
+
+ /* horizontal */
+ for (i = 0; i < dx; i++) {
+ point8(im, x0, y0, ink);
+ x0 += xs;
+ }
+
+ else if (dx > dy) {
+
+ /* bresenham, horizontal slope */
+ n = dx;
+ dy += dy;
+ e = dy - dx;
+ dx += dx;
+
+ for (i = 0; i < n; i++) {
+ point8(im, x0, y0, ink);
+ if (e >= 0) {
+ y0 += ys;
+ e -= dx;
+ }
+ e += dy;
+ x0 += xs;
+ }
+
+ } else {
+
+ /* bresenham, vertical slope */
+ n = dy;
+ dx += dx;
+ e = dx - dy;
+ dy += dy;
+
+ for (i = 0; i < n; i++) {
+ point8(im, x0, y0, ink);
+ if (e >= 0) {
+ x0 += xs;
+ e -= dy;
+ }
+ e += dx;
+ y0 += ys;
+ }
+
+ }
+}
+
+static inline void
+line32(Imaging im, int x0, int y0, int x1, int y1, int ink)
+{
+ int i, n, e;
+ int dx, dy;
+ int xs, ys;
+
+ /* normalize coordinates */
+ dx = x1-x0;
+ if (dx < 0)
+ dx = -dx, xs = -1;
+ else
+ xs = 1;
+ dy = y1-y0;
+ if (dy < 0)
+ dy = -dy, ys = -1;
+ else
+ ys = 1;
+
+ n = (dx > dy) ? dx : dy;
+
+ if (dx == 0)
+
+ /* vertical */
+ for (i = 0; i < dy; i++) {
+ point32(im, x0, y0, ink);
+ y0 += ys;
+ }
+
+ else if (dy == 0)
+
+ /* horizontal */
+ for (i = 0; i < dx; i++) {
+ point32(im, x0, y0, ink);
+ x0 += xs;
+ }
+
+ else if (dx > dy) {
+
+ /* bresenham, horizontal slope */
+ n = dx;
+ dy += dy;
+ e = dy - dx;
+ dx += dx;
+
+ for (i = 0; i < n; i++) {
+ point32(im, x0, y0, ink);
+ if (e >= 0) {
+ y0 += ys;
+ e -= dx;
+ }
+ e += dy;
+ x0 += xs;
+ }
+
+ } else {
+
+ /* bresenham, vertical slope */
+ n = dy;
+ dx += dx;
+ e = dx - dy;
+ dy += dy;
+
+ for (i = 0; i < n; i++) {
+ point32(im, x0, y0, ink);
+ if (e >= 0) {
+ x0 += xs;
+ e -= dy;
+ }
+ e += dx;
+ y0 += ys;
+ }
+
+ }
+}
+
+static inline void
+line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink)
+{
+ int i, n, e;
+ int dx, dy;
+ int xs, ys;
+
+ /* normalize coordinates */
+ dx = x1-x0;
+ if (dx < 0)
+ dx = -dx, xs = -1;
+ else
+ xs = 1;
+ dy = y1-y0;
+ if (dy < 0)
+ dy = -dy, ys = -1;
+ else
+ ys = 1;
+
+ n = (dx > dy) ? dx : dy;
+
+ if (dx == 0)
+
+ /* vertical */
+ for (i = 0; i < dy; i++) {
+ point32rgba(im, x0, y0, ink);
+ y0 += ys;
+ }
+
+ else if (dy == 0)
+
+ /* horizontal */
+ for (i = 0; i < dx; i++) {
+ point32rgba(im, x0, y0, ink);
+ x0 += xs;
+ }
+
+ else if (dx > dy) {
+
+ /* bresenham, horizontal slope */
+ n = dx;
+ dy += dy;
+ e = dy - dx;
+ dx += dx;
+
+ for (i = 0; i < n; i++) {
+ point32rgba(im, x0, y0, ink);
+ if (e >= 0) {
+ y0 += ys;
+ e -= dx;
+ }
+ e += dy;
+ x0 += xs;
+ }
+
+ } else {
+
+ /* bresenham, vertical slope */
+ n = dy;
+ dx += dx;
+ e = dx - dy;
+ dy += dy;
+
+ for (i = 0; i < n; i++) {
+ point32rgba(im, x0, y0, ink);
+ if (e >= 0) {
+ x0 += xs;
+ e -= dy;
+ }
+ e += dx;
+ y0 += ys;
+ }
+
+ }
+}
+
+static int
+x_cmp(const void *x0, const void *x1)
+{
+ float diff = *((float*)x0) - *((float*)x1);
+ if (diff < 0)
+ return -1;
+ else if (diff > 0)
+ return 1;
+ else
+ return 0;
+}
+
+
+/*
+ * Filled polygon draw function using scan line algorithm.
+ */
+static inline int
+polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill,
+ hline_handler hline)
+{
+
+ Edge** edge_table;
+ float* xx;
+ int edge_count = 0;
+ int ymin = im->ysize - 1;
+ int ymax = 0;
+ int i;
+
+ if (n <= 0) {
+ return 0;
+ }
+
+ /* Initialize the edge table and find polygon boundaries */
+ /* malloc check ok, using calloc */
+ edge_table = calloc(n, sizeof(Edge*));
+ if (!edge_table) {
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+ /* 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);
+ continue;
+ }
+ if (ymin > e[i].ymin) {
+ ymin = e[i].ymin;
+ }
+ if (ymax < e[i].ymax) {
+ ymax = e[i].ymax;
+ }
+ edge_table[edge_count++] = (e + i);
+ }
+ if (ymin < 0) {
+ ymin = 0;
+ }
+ if (ymax > im->ysize) {
+ ymax = im->ysize;
+ }
+
+ /* Process the edge table with a scan line searching for intersections */
+ /* malloc check ok, using calloc */
+ xx = calloc(edge_count * 2, sizeof(float));
+ if (!xx) {
+ free(edge_table);
+ return -1;
+ }
+ for (; ymin <= ymax; ymin++) {
+ int j = 0;
+ for (i = 0; i < edge_count; i++) {
+ Edge* current = edge_table[i];
+ if (ymin >= current->ymin && ymin <= current->ymax) {
+ xx[j++] = (ymin - current->y0) * current->dx + current->x0;
+ }
+ /* Needed to draw consistent polygons */
+ if (ymin == current->ymax && ymin < ymax) {
+ xx[j] = xx[j - 1];
+ j++;
+ }
+ }
+ qsort(xx, j, sizeof(float), x_cmp);
+ for (i = 1; i < j; i += 2) {
+ (*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink);
+ }
+ }
+
+ free(xx);
+ free(edge_table);
+ return 0;
+}
+
+static inline int
+polygon8(Imaging im, int n, Edge *e, int ink, int eofill)
+{
+ return polygon_generic(im, n, e, ink, eofill, hline8);
+}
+
+static inline int
+polygon32(Imaging im, int n, Edge *e, int ink, int eofill)
+{
+ return polygon_generic(im, n, e, ink, eofill, hline32);
+}
+
+static inline int
+polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill)
+{
+ return polygon_generic(im, n, e, ink, eofill, hline32rgba);
+}
+
+static inline void
+add_edge(Edge *e, int x0, int y0, int x1, int y1)
+{
+ /* printf("edge %d %d %d %d\n", x0, y0, x1, y1); */
+
+ if (x0 <= x1)
+ e->xmin = x0, e->xmax = x1;
+ else
+ e->xmin = x1, e->xmax = x0;
+
+ if (y0 <= y1)
+ e->ymin = y0, e->ymax = y1;
+ else
+ e->ymin = y1, e->ymax = y0;
+
+ if (y0 == y1) {
+ e->d = 0;
+ e->dx = 0.0;
+ } else {
+ e->dx = ((float)(x1-x0)) / (y1-y0);
+ if (y0 == e->ymin)
+ e->d = 1;
+ else
+ e->d = -1;
+ }
+
+ e->x0 = x0;
+ e->y0 = y0;
+}
+
+typedef struct {
+ void (*point)(Imaging im, int x, int y, int ink);
+ void (*hline)(Imaging im, int x0, int y0, int x1, int ink);
+ void (*line)(Imaging im, int x0, int y0, int x1, int y1, int ink);
+ int (*polygon)(Imaging im, int n, Edge *e, int ink, int eofill);
+} DRAW;
+
+DRAW draw8 = { point8, hline8, line8, polygon8 };
+DRAW draw32 = { point32, hline32, line32, polygon32 };
+DRAW draw32rgba = { point32rgba, hline32rgba, line32rgba, polygon32rgba };
+
+/* -------------------------------------------------------------------- */
+/* Interface */
+/* -------------------------------------------------------------------- */
+
+#define DRAWINIT()\
+ if (im->image8) {\
+ draw = &draw8;\
+ ink = INK8(ink_);\
+ } else {\
+ draw = (op) ? &draw32rgba : &draw32; \
+ memcpy(&ink, ink_, sizeof(ink)); \
+ }
+
+int
+ImagingDrawPoint(Imaging im, int x0, int y0, const void* ink_, int op)
+{
+ DRAW* draw;
+ INT32 ink;
+
+ DRAWINIT();
+
+ draw->point(im, x0, y0, ink);
+
+ return 0;
+}
+
+int
+ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void* ink_,
+ int op)
+{
+ DRAW* draw;
+ INT32 ink;
+
+ DRAWINIT();
+
+ draw->line(im, x0, y0, x1, y1, ink);
+
+ return 0;
+}
+
+int
+ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
+ const void* ink_, int width, int op)
+{
+ DRAW* draw;
+ INT32 ink;
+ int dx, dy;
+ double big_hypotenuse, small_hypotenuse, ratio_max, ratio_min;
+ int dxmin, dxmax, dymin, dymax;
+ Edge e[4];
+
+ DRAWINIT();
+
+ dx = x1-x0;
+ dy = y1-y0;
+ if (dx == 0 && dy == 0) {
+ draw->point(im, x0, y0, ink);
+ return 0;
+ }
+
+ big_hypotenuse = sqrt((double) (dx*dx + dy*dy));
+ small_hypotenuse = (width - 1) / 2.0;
+ ratio_max = ROUND_UP(small_hypotenuse) / big_hypotenuse;
+ ratio_min = ROUND_DOWN(small_hypotenuse) / big_hypotenuse;
+
+ dxmin = ROUND_DOWN(ratio_min * dy);
+ dxmax = ROUND_DOWN(ratio_max * dy);
+ dymin = ROUND_DOWN(ratio_min * dx);
+ dymax = ROUND_DOWN(ratio_max * dx);
+ {
+ int vertices[4][2] = {
+ {x0 - dxmin, y0 + dymax},
+ {x1 - dxmin, y1 + dymax},
+ {x1 + dxmax, y1 - dymin},
+ {x0 + dxmax, y0 - dymin}
+ };
+
+ add_edge(e+0, vertices[0][0], vertices[0][1], vertices[1][0], vertices[1][1]);
+ add_edge(e+1, vertices[1][0], vertices[1][1], vertices[2][0], vertices[2][1]);
+ add_edge(e+2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]);
+ add_edge(e+3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]);
+
+ draw->polygon(im, 4, e, ink, 0);
+ }
+ return 0;
+}
+
+int
+ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1,
+ const void* ink_, int fill, int width, int op)
+{
+ int i;
+ int y;
+ int tmp;
+ DRAW* draw;
+ INT32 ink;
+
+ DRAWINIT();
+
+ if (y0 > y1)
+ tmp = y0, y0 = y1, y1 = tmp;
+
+ if (fill) {
+
+ if (y0 < 0)
+ y0 = 0;
+ else if (y0 >= im->ysize)
+ return 0;
+
+ if (y1 < 0)
+ return 0;
+ else if (y1 > im->ysize)
+ y1 = im->ysize;
+
+ for (y = y0; y <= y1; y++)
+ draw->hline(im, x0, y, x1, ink);
+
+ } else {
+ /* outline */
+ if (width == 0) {
+ width = 1;
+ }
+ for (i = 0; i < width; i++) {
+ draw->hline(im, x0, y0+i, x1, ink);
+ draw->hline(im, x0, y1-i, x1, ink);
+ draw->line(im, x1-i, y0, x1-i, y1, ink);
+ draw->line(im, x0+i, y1, x0+i, y0, ink);
+ }
+ }
+
+ return 0;
+}
+
+int
+ImagingDrawPolygon(Imaging im, int count, int* xy, const void* ink_,
+ int fill, int op)
+{
+ int i, n;
+ DRAW* draw;
+ INT32 ink;
+
+ if (count <= 0)
+ return 0;
+
+ DRAWINIT();
+
+ if (fill) {
+
+ /* Build edge list */
+ /* malloc check ok, using calloc */
+ Edge* e = calloc(count, sizeof(Edge));
+ if (!e) {
+ (void) ImagingError_MemoryError();
+ return -1;
+ }
+ for (i = n = 0; i < count-1; i++)
+ add_edge(&e[n++], xy[i+i], xy[i+i+1], xy[i+i+2], xy[i+i+3]);
+ if (xy[i+i] != xy[0] || xy[i+i+1] != xy[1])
+ add_edge(&e[n++], xy[i+i], xy[i+i+1], xy[0], xy[1]);
+ draw->polygon(im, n, e, ink, 0);
+ free(e);
+
+ } else {
+
+ /* Outline */
+ for (i = 0; i < count-1; i++)
+ draw->line(im, xy[i+i], xy[i+i+1], xy[i+i+2], xy[i+i+3], ink);
+ draw->line(im, xy[i+i], xy[i+i+1], xy[0], xy[1], ink);
+
+ }
+
+ return 0;
+}
+
+int
+ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, const void* ink,
+ int op)
+{
+ return ImagingFill2(
+ im, ink, bitmap,
+ x0, y0, x0 + bitmap->xsize, y0 + bitmap->ysize
+ );
+}
+
+/* -------------------------------------------------------------------- */
+/* standard shapes */
+
+#define ARC 0
+#define CHORD 1
+#define PIESLICE 2
+
+static void
+ellipsePoint(int cx, int cy, int w, int h,
+ float i, int *x, int *y)
+{
+ float i_cos, i_sin;
+ float x_f, y_f;
+ double modf_int;
+ i_cos = cos(i*M_PI/180);
+ i_sin = sin(i*M_PI/180);
+ x_f = (i_cos * w/2) + cx;
+ y_f = (i_sin * h/2) + cy;
+ if (modf(x_f, &modf_int) == 0.5) {
+ *x = i_cos > 0 ? FLOOR(x_f) : CEIL(x_f);
+ } else {
+ *x = FLOOR(x_f + 0.5);
+ }
+ if (modf(y_f, &modf_int) == 0.5) {
+ *y = i_sin > 0 ? FLOOR(y_f) : CEIL(y_f);
+ } else {
+ *y = FLOOR(y_f + 0.5);
+ }
+}
+
+static int
+ellipse(Imaging im, int x0, int y0, int x1, int y1,
+ float start, float end, const void* ink_, int fill,
+ int width, int mode, int op)
+{
+ float i;
+ int inner;
+ int n;
+ int maxEdgeCount;
+ int w, h;
+ int x, y;
+ int cx, cy;
+ int lx = 0, ly = 0;
+ int sx = 0, sy = 0;
+ int lx_inner = 0, ly_inner = 0;
+ int sx_inner = 0, sy_inner = 0;
+ DRAW* draw;
+ INT32 ink;
+ Edge* e;
+
+ DRAWINIT();
+
+ while (end < start)
+ end += 360;
+
+ if (end - start > 360) {
+ // no need to go in loops
+ end = start + 361;
+ }
+
+ w = x1 - x0;
+ h = y1 - y0;
+ if (w <= 0 || h <= 0)
+ return 0;
+
+ cx = (x0 + x1) / 2;
+ cy = (y0 + y1) / 2;
+
+ if (!fill && width <= 1) {
+ for (i = start; i < end+1; i++) {
+ if (i > end) {
+ i = end;
+ }
+ ellipsePoint(cx, cy, w, h, i, &x, &y);
+ if (i != start)
+ draw->line(im, lx, ly, x, y, ink);
+ else
+ sx = x, sy = y;
+ lx = x, ly = y;
+ }
+
+ if (i != start) {
+ if (mode == PIESLICE) {
+ if (x != cx || y != cy) {
+ draw->line(im, x, y, cx, cy, ink);
+ draw->line(im, cx, cy, sx, sy, ink);
+ }
+ } else if (mode == CHORD) {
+ if (x != sx || y != sy)
+ draw->line(im, x, y, sx, sy, ink);
+ }
+ }
+ } else {
+ inner = (mode == ARC || !fill) ? 1 : 0;
+
+ // Build edge list
+ // malloc check UNDONE, FLOAT?
+ maxEdgeCount = ceil(end - start);
+ if (inner) {
+ maxEdgeCount *= 2;
+ }
+ maxEdgeCount += 3;
+ e = calloc(maxEdgeCount, sizeof(Edge));
+ if (!e) {
+ ImagingError_MemoryError();
+ return -1;
+ }
+
+ // Outer circle
+ n = 0;
+ for (i = start; i < end+1; i++) {
+ if (i > end) {
+ i = end;
+ }
+ ellipsePoint(cx, cy, w, h, i, &x, &y);
+ if (i == start) {
+ sx = x, sy = y;
+ } else {
+ add_edge(&e[n++], lx, ly, x, y);
+ }
+ lx = x, ly = y;
+ }
+ if (n == 0)
+ return 0;
+
+ if (inner) {
+ // Inner circle
+ x0 += width - 1;
+ y0 += width - 1;
+ x1 -= width - 1;
+ y1 -= width - 1;
+
+ w = x1 - x0;
+ h = y1 - y0;
+ if (w <= 0 || h <= 0) {
+ // ARC with no gap in the middle is a PIESLICE
+ mode = PIESLICE;
+ inner = 0;
+ } else {
+ for (i = start; i < end+1; i++) {
+ if (i > end) {
+ i = end;
+ }
+ ellipsePoint(cx, cy, w, h, i, &x, &y);
+ if (i == start)
+ sx_inner = x, sy_inner = y;
+ else
+ add_edge(&e[n++], lx_inner, ly_inner, x, y);
+ lx_inner = x, ly_inner = y;
+ }
+ }
+ }
+
+ if (end - start < 360) {
+ // Close polygon
+ if (mode == PIESLICE) {
+ if (x != cx || y != cy) {
+ add_edge(&e[n++], sx, sy, cx, cy);
+ add_edge(&e[n++], cx, cy, lx, ly);
+ if (inner) {
+ ImagingDrawWideLine(im, sx, sy, cx, cy, &ink, width, op);
+ ImagingDrawWideLine(im, cx, cy, lx, ly, &ink, width, op);
+ }
+ }
+ } else if (mode == CHORD) {
+ add_edge(&e[n++], sx, sy, lx, ly);
+ if (inner) {
+ add_edge(&e[n++], sx_inner, sy_inner, lx_inner, ly_inner);
+ }
+ } else if (mode == ARC) {
+ add_edge(&e[n++], sx, sy, sx_inner, sy_inner);
+ add_edge(&e[n++], lx, ly, lx_inner, ly_inner);
+ }
+ }
+
+ draw->polygon(im, n, e, ink, 0);
+
+ free(e);
+ }
+
+ return 0;
+}
+
+int
+ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1,
+ float start, float end, const void* ink, int width, int op)
+{
+ return ellipse(im, x0, y0, x1, y1, start, end, ink, 0, width, ARC, op);
+}
+
+int
+ImagingDrawChord(Imaging im, int x0, int y0, int x1, int y1,
+ float start, float end, const void* ink, int fill,
+ int width, int op)
+{
+ return ellipse(im, x0, y0, x1, y1, start, end, ink, fill, width, CHORD, op);
+}
+
+int
+ImagingDrawEllipse(Imaging im, int x0, int y0, int x1, int y1,
+ const void* ink, int fill, int width, int op)
+{
+ return ellipse(im, x0, y0, x1, y1, 0, 360, ink, fill, width, CHORD, op);
+}
+
+int
+ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1,
+ float start, float end, const void* ink, int fill,
+ int width, int op)
+{
+ return ellipse(im, x0, y0, x1, y1, start, end, ink, fill, width, PIESLICE, op);
+}
+
+/* -------------------------------------------------------------------- */
+
+/* experimental level 2 ("arrow") graphics stuff. this implements
+ portions of the arrow api on top of the Edge structure. the
+ semantics are ok, except that "curve" flattens the bezier curves by
+ itself */
+
+struct ImagingOutlineInstance {
+
+ float x0, y0;
+
+ float x, y;
+
+ int count;
+ Edge *edges;
+
+ int size;
+
+};
+
+
+ImagingOutline
+ImagingOutlineNew(void)
+{
+ ImagingOutline outline;
+
+ outline = calloc(1, sizeof(struct ImagingOutlineInstance));
+ if (!outline)
+ return (ImagingOutline) ImagingError_MemoryError();
+
+ outline->edges = NULL;
+ outline->count = outline->size = 0;
+
+ ImagingOutlineMove(outline, 0, 0);
+
+ return outline;
+}
+
+void
+ImagingOutlineDelete(ImagingOutline outline)
+{
+ if (!outline)
+ return;
+
+ if (outline->edges)
+ free(outline->edges);
+
+ free(outline);
+}
+
+
+static Edge*
+allocate(ImagingOutline outline, int extra)
+{
+ Edge* e;
+
+ if (outline->count + extra > outline->size) {
+ /* expand outline buffer */
+ outline->size += extra + 25;
+ if (!outline->edges) {
+ /* malloc check ok, uses calloc for overflow */
+ e = calloc(outline->size, sizeof(Edge));
+ } else {
+ if (outline->size > INT_MAX / sizeof(Edge)) {
+ return NULL;
+ }
+ /* malloc check ok, overflow checked above */
+ e = realloc(outline->edges, outline->size * sizeof(Edge));
+ }
+ if (!e)
+ return NULL;
+ outline->edges = e;
+ }
+
+ e = outline->edges + outline->count;
+
+ outline->count += extra;
+
+ return e;
+}
+
+int
+ImagingOutlineMove(ImagingOutline outline, float x0, float y0)
+{
+ outline->x = outline->x0 = x0;
+ outline->y = outline->y0 = y0;
+
+ return 0;
+}
+
+int
+ImagingOutlineLine(ImagingOutline outline, float x1, float y1)
+{
+ Edge* e;
+
+ e = allocate(outline, 1);
+ if (!e)
+ return -1; /* out of memory */
+
+ add_edge(e, (int) outline->x, (int) outline->y, (int) x1, (int) y1);
+
+ outline->x = x1;
+ outline->y = y1;
+
+ return 0;
+}
+
+int
+ImagingOutlineCurve(ImagingOutline outline, float x1, float y1,
+ float x2, float y2, float x3, float y3)
+{
+ Edge* e;
+ int i;
+ float xo, yo;
+
+#define STEPS 32
+
+ e = allocate(outline, STEPS);
+ if (!e)
+ return -1; /* out of memory */
+
+ xo = outline->x;
+ yo = outline->y;
+
+ /* flatten the bezier segment */
+
+ for (i = 1; i <= STEPS; i++) {
+
+ float t = ((float) i) / STEPS;
+ float t2 = t*t;
+ float t3 = t2*t;
+
+ float u = 1.0F - t;
+ float u2 = u*u;
+ float u3 = u2*u;
+
+ float x = outline->x*u3 + 3*(x1*t*u2 + x2*t2*u) + x3*t3 + 0.5;
+ float y = outline->y*u3 + 3*(y1*t*u2 + y2*t2*u) + y3*t3 + 0.5;
+
+ add_edge(e++, xo, yo, (int) x, (int) y);
+
+ xo = x, yo = y;
+
+ }
+
+ outline->x = xo;
+ outline->y = yo;
+
+ return 0;
+}
+
+int
+ImagingOutlineClose(ImagingOutline outline)
+{
+ if (outline->x == outline->x0 && outline->y == outline->y0)
+ return 0;
+ return ImagingOutlineLine(outline, outline->x0, outline->y0);
+}
+
+int
+ImagingOutlineTransform(ImagingOutline outline, double a[6])
+{
+ Edge *eIn;
+ Edge *eOut;
+ int i, n;
+ int x0, y0, x1, y1;
+ int X0, Y0, X1, Y1;
+
+ double a0 = a[0]; double a1 = a[1]; double a2 = a[2];
+ double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
+
+ eIn = outline->edges;
+ n = outline->count;
+
+ /* FIXME: ugly! */
+ outline->edges = NULL;
+ outline->count = outline->size = 0;
+
+ eOut = allocate(outline, n);
+ if (!eOut) {
+ outline->edges = eIn;
+ outline->count = outline->size = n;
+ ImagingError_MemoryError();
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+
+ x0 = eIn->x0;
+ y0 = eIn->y0;
+
+ /* FIXME: ouch! */
+ if (eIn->x0 == eIn->xmin)
+ x1 = eIn->xmax;
+ else
+ x1 = eIn->xmin;
+ if (eIn->y0 == eIn->ymin)
+ y1 = eIn->ymax;
+ else
+ y1 = eIn->ymin;
+
+ /* full moon tonight! if this doesn't work, you may need to
+ upgrade your compiler (make sure you have the right service
+ pack) */
+
+ X0 = (int) (a0*x0 + a1*y0 + a2);
+ Y0 = (int) (a3*x0 + a4*y0 + a5);
+ X1 = (int) (a0*x1 + a1*y1 + a2);
+ Y1 = (int) (a3*x1 + a4*y1 + a5);
+
+ add_edge(eOut, X0, Y0, X1, Y1);
+
+ eIn++;
+ eOut++;
+
+ }
+
+ free(eIn);
+
+ return 0;
+}
+
+int
+ImagingDrawOutline(Imaging im, ImagingOutline outline, const void* ink_,
+ int fill, int op)
+{
+ DRAW* draw;
+ INT32 ink;
+
+ DRAWINIT();
+
+ draw->polygon(im, outline->count, outline->edges, ink, 0);
+
+ return 0;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Effects.c b/contrib/python/Pillow/py2/libImaging/Effects.c
new file mode 100644
index 0000000000..7b4ff0b438
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Effects.c
@@ -0,0 +1,150 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * various special effects and image generators
+ *
+ * history:
+ * 1997-05-21 fl Just for fun
+ * 1997-06-05 fl Added mandelbrot generator
+ * 2003-05-24 fl Added perlin_turbulence generator (in progress)
+ *
+ * Copyright (c) 1997-2003 by Fredrik Lundh.
+ * Copyright (c) 1997 by Secret Labs AB.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#include <math.h>
+
+Imaging
+ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality)
+{
+ /* Generate a Mandelbrot set covering the given extent */
+
+ Imaging im;
+ int x, y, k;
+ double width, height;
+ double x1, y1, xi2, yi2, cr, ci, radius;
+ double dr, di;
+
+ /* Check arguments */
+ width = extent[2] - extent[0];
+ height = extent[3] - extent[1];
+ if (width < 0.0 || height < 0.0 || quality < 2)
+ return (Imaging) ImagingError_ValueError(NULL);
+
+ im = ImagingNewDirty("L", xsize, ysize);
+ if (!im)
+ return NULL;
+
+ dr = width/(xsize-1);
+ di = height/(ysize-1);
+
+ radius = 100.0;
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* buf = im->image8[y];
+ for (x = 0; x < xsize; x++) {
+ x1 = y1 = xi2 = yi2 = 0.0;
+ cr = x*dr + extent[0];
+ ci = y*di + extent[1];
+ for (k = 1;; k++) {
+ y1 = 2*x1*y1 + ci;
+ x1 = xi2 - yi2 + cr;
+ xi2 = x1*x1;
+ yi2 = y1*y1;
+ if ((xi2 + yi2) > radius) {
+ buf[x] = k*255/quality;
+ break;
+ }
+ if (k > quality) {
+ buf[x] = 0;
+ break;
+ }
+ }
+ }
+ }
+ return im;
+}
+
+Imaging
+ImagingEffectNoise(int xsize, int ysize, float sigma)
+{
+ /* Generate Gaussian noise centered around 128 */
+
+ Imaging imOut;
+ int x, y;
+ int nextok;
+ double this, next;
+
+ imOut = ImagingNewDirty("L", xsize, ysize);
+ if (!imOut)
+ return NULL;
+
+ next = 0.0;
+ nextok = 0;
+
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8* out = imOut->image8[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ if (nextok) {
+ this = next;
+ nextok = 0;
+ } else {
+ /* after numerical recipes */
+ double v1, v2, radius, factor;
+ do {
+ v1 = rand()*(2.0/RAND_MAX) - 1.0;
+ v2 = rand()*(2.0/RAND_MAX) - 1.0;
+ radius= v1*v1 + v2*v2;
+ } while (radius >= 1.0);
+ factor = sqrt(-2.0*log(radius)/radius);
+ this = factor * v1;
+ next = factor * v2;
+ }
+ out[x] = CLIP8(128 + sigma * this);
+ }
+ }
+
+ return imOut;
+}
+
+Imaging
+ImagingEffectSpread(Imaging imIn, int distance)
+{
+ /* Randomly spread pixels in an image */
+
+ Imaging imOut;
+ int x, y;
+
+ imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
+
+ if (!imOut)
+ return NULL;
+
+#define SPREAD(type, image)\
+ for (y = 0; y < imOut->ysize; y++)\
+ for (x = 0; x < imOut->xsize; x++) {\
+ int xx = x + (rand() % distance) - distance/2;\
+ int yy = y + (rand() % distance) - distance/2;\
+ if (xx >= 0 && xx < imIn->xsize && yy >= 0 && yy < imIn->ysize) {\
+ imOut->image[yy][xx] = imIn->image[y][x];\
+ imOut->image[y][x] = imIn->image[yy][xx];\
+ } else\
+ imOut->image[y][x] = imIn->image[y][x];\
+ }
+
+ if (imIn->image8) {
+ SPREAD(UINT8, image8);
+ } else {
+ SPREAD(INT32, image32);
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/EpsEncode.c b/contrib/python/Pillow/py2/libImaging/EpsEncode.c
new file mode 100644
index 0000000000..45fab0a6ed
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/EpsEncode.c
@@ -0,0 +1,80 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * encoder for EPS hex data
+ *
+ * history:
+ * 96-04-19 fl created
+ * 96-06-27 fl don't drop last block of encoded data
+ *
+ * notes:
+ * FIXME: rename to HexEncode.c ??
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+int
+ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
+{
+ enum { HEXBYTE=1, NEWLINE };
+ const char *hex = "0123456789abcdef";
+
+ UINT8* ptr = buf;
+ UINT8* in, i;
+
+ if (!state->state) {
+ state->state = HEXBYTE;
+ state->xsize *= im->pixelsize; /* Hack! */
+ }
+
+ in = (UINT8*) im->image[state->y];
+
+ for (;;) {
+
+ if (state->state == NEWLINE) {
+ if (bytes < 1)
+ break;
+ *ptr++ = '\n';
+ bytes--;
+ state->state = HEXBYTE;
+ }
+
+ if (bytes < 2)
+ break;
+
+ i = in[state->x++];
+ *ptr++ = hex[(i>>4)&15];
+ *ptr++ = hex[i&15];
+ bytes -= 2;
+
+ /* Skip junk bytes */
+ if (im->bands == 3 && (state->x & 3) == 3)
+ state->x++;
+
+ if (++state->count >= 79/2) {
+ state->state = NEWLINE;
+ state->count = 0;
+ }
+
+ if (state->x >= state->xsize) {
+ state->x = 0;
+ if (++state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+ in = (UINT8*) im->image[state->y];
+ }
+
+ }
+
+ return ptr - buf;
+
+}
diff --git a/contrib/python/Pillow/py2/libImaging/File.c b/contrib/python/Pillow/py2/libImaging/File.c
new file mode 100644
index 0000000000..6f014c1f82
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/File.c
@@ -0,0 +1,84 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * built-in image file handling
+ *
+ * history:
+ * 1995-11-26 fl Created, supports PGM/PPM
+ * 1996-08-07 fl Write "1" images as PGM
+ * 1999-02-21 fl Don't write non-standard modes
+ *
+ * Copyright (c) 1997-99 by Secret Labs AB.
+ * Copyright (c) 1995-96 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#include <ctype.h>
+
+
+int
+ImagingSaveRaw(Imaging im, FILE* fp)
+{
+ int x, y, i;
+
+ if (strcmp(im->mode, "1") == 0 || strcmp(im->mode, "L") == 0) {
+
+ /* @PIL227: FIXME: for mode "1", map != 0 to 255 */
+
+ /* PGM "L" */
+ for (y = 0; y < im->ysize; y++)
+ fwrite(im->image[y], 1, im->xsize, fp);
+
+ } else {
+
+ /* PPM "RGB" or other internal format */
+ for (y = 0; y < im->ysize; y++)
+ for (x = i = 0; x < im->xsize; x++, i += im->pixelsize)
+ fwrite(im->image[y]+i, 1, im->bands, fp);
+
+ }
+
+ return 1;
+}
+
+
+int
+ImagingSavePPM(Imaging im, const char* outfile)
+{
+ FILE* fp;
+
+ if (!im) {
+ (void) ImagingError_ValueError(NULL);
+ return 0;
+ }
+
+ fp = fopen(outfile, "wb");
+ if (!fp) {
+ (void) ImagingError_IOError();
+ return 0;
+ }
+
+ if (strcmp(im->mode, "1") == 0 || strcmp(im->mode, "L") == 0) {
+ /* Write "PGM" */
+ fprintf(fp, "P5\n%d %d\n255\n", im->xsize, im->ysize);
+ } else if (strcmp(im->mode, "RGB") == 0) {
+ /* Write "PPM" */
+ fprintf(fp, "P6\n%d %d\n255\n", im->xsize, im->ysize);
+ } else {
+ fclose(fp);
+ (void) ImagingError_ModeError();
+ return 0;
+ }
+
+ ImagingSaveRaw(im, fp);
+
+ fclose(fp);
+
+ return 1;
+}
+
diff --git a/contrib/python/Pillow/py2/libImaging/Fill.c b/contrib/python/Pillow/py2/libImaging/Fill.c
new file mode 100644
index 0000000000..d641a59962
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Fill.c
@@ -0,0 +1,111 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * fill image with constant pixel value
+ *
+ * history:
+ * 95-11-26 fl moved from Imaging.c
+ * 96-05-17 fl added radial fill, renamed wedge to linear
+ * 98-06-23 fl changed ImageFill signature
+ *
+ * Copyright (c) Secret Labs AB 1997-98. All rights reserved.
+ * Copyright (c) Fredrik Lundh 1995-96.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#include "math.h"
+
+Imaging
+ImagingFill(Imaging im, const void* colour)
+{
+ int x, y;
+ ImagingSectionCookie cookie;
+
+ if (im->type == IMAGING_TYPE_SPECIAL) {
+ /* use generic API */
+ ImagingAccess access = ImagingAccessNew(im);
+ if (access) {
+ for (y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->xsize; x++)
+ access->put_pixel(im, x, y, colour);
+ ImagingAccessDelete(im, access);
+ } else {
+ /* wipe the image */
+ for (y = 0; y < im->ysize; y++)
+ memset(im->image[y], 0, im->linesize);
+ }
+ } else {
+ INT32 c = 0L;
+ ImagingSectionEnter(&cookie);
+ memcpy(&c, colour, im->pixelsize);
+ if (im->image32 && c != 0L) {
+ for (y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->xsize; x++)
+ im->image32[y][x] = c;
+ } else {
+ unsigned char cc = (unsigned char) *(UINT8*) colour;
+ for (y = 0; y < im->ysize; y++)
+ memset(im->image[y], cc, im->linesize);
+ }
+ ImagingSectionLeave(&cookie);
+ }
+
+ return im;
+}
+
+Imaging
+ImagingFillLinearGradient(const char *mode)
+{
+ Imaging im;
+ int y;
+
+ if (strlen(mode) != 1) {
+ return (Imaging) ImagingError_ModeError();
+ }
+
+ im = ImagingNewDirty(mode, 256, 256);
+ if (!im) {
+ return NULL;
+ }
+
+ for (y = 0; y < 256; y++) {
+ memset(im->image8[y], (unsigned char) y, 256);
+ }
+
+ return im;
+}
+
+Imaging
+ImagingFillRadialGradient(const char *mode)
+{
+ Imaging im;
+ int x, y;
+ int d;
+
+ if (strlen(mode) != 1) {
+ return (Imaging) ImagingError_ModeError();
+ }
+
+ im = ImagingNewDirty(mode, 256, 256);
+ if (!im) {
+ return NULL;
+ }
+
+ for (y = 0; y < 256; y++) {
+ for (x = 0; x < 256; x++) {
+ d = (int) sqrt((double) ((x-128)*(x-128) + (y-128)*(y-128)) * 2.0);
+ if (d >= 255) {
+ im->image8[y][x] = 255;
+ } else {
+ im->image8[y][x] = d;
+ }
+ }
+ }
+
+ return im;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Filter.c b/contrib/python/Pillow/py2/libImaging/Filter.c
new file mode 100644
index 0000000000..b033abf662
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Filter.c
@@ -0,0 +1,357 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * apply convolution kernel to image
+ *
+ * history:
+ * 1995-11-26 fl Created, supports 3x3 kernels
+ * 1995-11-27 fl Added 5x5 kernels, copy border
+ * 1999-07-26 fl Eliminated a few compiler warnings
+ * 2002-06-09 fl Moved kernel definitions to Python
+ * 2002-06-11 fl Support floating point kernels
+ * 2003-09-15 fl Added ImagingExpand helper
+ *
+ * Copyright (c) Secret Labs AB 1997-2002. All rights reserved.
+ * Copyright (c) Fredrik Lundh 1995.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+/*
+ * FIXME: Support RGB and RGBA/CMYK modes as well
+ * FIXME: Expand image border (current version leaves border as is)
+ * FIXME: Implement image processing gradient filters
+ */
+
+#include "Imaging.h"
+
+
+static inline UINT8 clip8(float in)
+{
+ if (in <= 0.0)
+ return 0;
+ if (in >= 255.0)
+ return 255;
+ return (UINT8) in;
+}
+
+Imaging
+ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
+{
+ Imaging imOut;
+ int x, y;
+ ImagingSectionCookie cookie;
+
+ if (xmargin < 0 && ymargin < 0)
+ return (Imaging) ImagingError_ValueError("bad kernel size");
+
+ imOut = ImagingNewDirty(
+ imIn->mode, imIn->xsize+2*xmargin, imIn->ysize+2*ymargin);
+ if (!imOut)
+ return NULL;
+
+#define EXPAND_LINE(type, image, yin, yout) {\
+ for (x = 0; x < xmargin; x++)\
+ imOut->image[yout][x] = imIn->image[yin][0];\
+ for (x = 0; x < imIn->xsize; x++)\
+ imOut->image[yout][x+xmargin] = imIn->image[yin][x];\
+ for (x = 0; x < xmargin; x++)\
+ imOut->image[yout][xmargin+imIn->xsize+x] =\
+ imIn->image[yin][imIn->xsize-1];\
+ }
+
+#define EXPAND(type, image) {\
+ for (y = 0; y < ymargin; y++)\
+ EXPAND_LINE(type, image, 0, y);\
+ for (y = 0; y < imIn->ysize; y++)\
+ EXPAND_LINE(type, image, y, y+ymargin);\
+ for (y = 0; y < ymargin; y++)\
+ EXPAND_LINE(type, image, imIn->ysize-1, ymargin+imIn->ysize+y);\
+ }
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->image8) {
+ EXPAND(UINT8, image8);
+ } else {
+ EXPAND(INT32, image32);
+ }
+ ImagingSectionLeave(&cookie);
+
+ ImagingCopyPalette(imOut, imIn);
+
+ return imOut;
+}
+
+
+void
+ImagingFilter3x3(Imaging imOut, Imaging im, const float* kernel,
+ float offset)
+{
+#define KERNEL1x3(in0, x, kernel, d) ( \
+ _i2f((UINT8) in0[x-d]) * (kernel)[0] + \
+ _i2f((UINT8) in0[x]) * (kernel)[1] + \
+ _i2f((UINT8) in0[x+d]) * (kernel)[2])
+
+ int x = 0, y = 0;
+
+ memcpy(imOut->image[0], im->image[0], im->linesize);
+ if (im->bands == 1) {
+ // Add one time for rounding
+ offset += 0.5;
+ for (y = 1; y < im->ysize-1; y++) {
+ UINT8* in_1 = (UINT8*) im->image[y-1];
+ UINT8* in0 = (UINT8*) im->image[y];
+ UINT8* in1 = (UINT8*) im->image[y+1];
+ UINT8* out = (UINT8*) imOut->image[y];
+
+ out[0] = in0[0];
+ for (x = 1; x < im->xsize-1; x++) {
+ float ss = offset;
+ ss += KERNEL1x3(in1, x, &kernel[0], 1);
+ ss += KERNEL1x3(in0, x, &kernel[3], 1);
+ ss += KERNEL1x3(in_1, x, &kernel[6], 1);
+ out[x] = clip8(ss);
+ }
+ out[x] = in0[x];
+ }
+ } else {
+ // Add one time for rounding
+ offset += 0.5;
+ for (y = 1; y < im->ysize-1; y++) {
+ UINT8* in_1 = (UINT8*) im->image[y-1];
+ UINT8* in0 = (UINT8*) im->image[y];
+ UINT8* in1 = (UINT8*) im->image[y+1];
+ UINT8* out = (UINT8*) imOut->image[y];
+
+ memcpy(out, in0, sizeof(UINT32));
+ if (im->bands == 2) {
+ for (x = 1; x < im->xsize-1; x++) {
+ float ss0 = offset;
+ float ss3 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4);
+ ss3 += KERNEL1x3(in1, x*4+3, &kernel[0], 4);
+ ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4);
+ ss3 += KERNEL1x3(in0, x*4+3, &kernel[3], 4);
+ ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4);
+ ss3 += KERNEL1x3(in_1, x*4+3, &kernel[6], 4);
+ v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (im->bands == 3) {
+ for (x = 1; x < im->xsize-1; x++) {
+ float ss0 = offset;
+ float ss1 = offset;
+ float ss2 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4);
+ ss1 += KERNEL1x3(in1, x*4+1, &kernel[0], 4);
+ ss2 += KERNEL1x3(in1, x*4+2, &kernel[0], 4);
+ ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4);
+ ss1 += KERNEL1x3(in0, x*4+1, &kernel[3], 4);
+ ss2 += KERNEL1x3(in0, x*4+2, &kernel[3], 4);
+ ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4);
+ ss1 += KERNEL1x3(in_1, x*4+1, &kernel[6], 4);
+ ss2 += KERNEL1x3(in_1, x*4+2, &kernel[6], 4);
+ v = MAKE_UINT32(
+ clip8(ss0), clip8(ss1), clip8(ss2), 0);
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (im->bands == 4) {
+ for (x = 1; x < im->xsize-1; x++) {
+ float ss0 = offset;
+ float ss1 = offset;
+ float ss2 = offset;
+ float ss3 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4);
+ ss1 += KERNEL1x3(in1, x*4+1, &kernel[0], 4);
+ ss2 += KERNEL1x3(in1, x*4+2, &kernel[0], 4);
+ ss3 += KERNEL1x3(in1, x*4+3, &kernel[0], 4);
+ ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4);
+ ss1 += KERNEL1x3(in0, x*4+1, &kernel[3], 4);
+ ss2 += KERNEL1x3(in0, x*4+2, &kernel[3], 4);
+ ss3 += KERNEL1x3(in0, x*4+3, &kernel[3], 4);
+ ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4);
+ ss1 += KERNEL1x3(in_1, x*4+1, &kernel[6], 4);
+ ss2 += KERNEL1x3(in_1, x*4+2, &kernel[6], 4);
+ ss3 += KERNEL1x3(in_1, x*4+3, &kernel[6], 4);
+ v = MAKE_UINT32(
+ clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ memcpy(out + x * sizeof(UINT32), in0 + x * sizeof(UINT32), sizeof(UINT32));
+ }
+ }
+ memcpy(imOut->image[y], im->image[y], im->linesize);
+}
+
+
+void
+ImagingFilter5x5(Imaging imOut, Imaging im, const float* kernel,
+ float offset)
+{
+#define KERNEL1x5(in0, x, kernel, d) ( \
+ _i2f((UINT8) in0[x-d-d]) * (kernel)[0] + \
+ _i2f((UINT8) in0[x-d]) * (kernel)[1] + \
+ _i2f((UINT8) in0[x]) * (kernel)[2] + \
+ _i2f((UINT8) in0[x+d]) * (kernel)[3] + \
+ _i2f((UINT8) in0[x+d+d]) * (kernel)[4])
+
+ int x = 0, y = 0;
+
+ memcpy(imOut->image[0], im->image[0], im->linesize);
+ memcpy(imOut->image[1], im->image[1], im->linesize);
+ if (im->bands == 1) {
+ // Add one time for rounding
+ offset += 0.5;
+ for (y = 2; y < im->ysize-2; y++) {
+ UINT8* in_2 = (UINT8*) im->image[y-2];
+ UINT8* in_1 = (UINT8*) im->image[y-1];
+ UINT8* in0 = (UINT8*) im->image[y];
+ UINT8* in1 = (UINT8*) im->image[y+1];
+ UINT8* in2 = (UINT8*) im->image[y+2];
+ UINT8* out = (UINT8*) imOut->image[y];
+
+ out[0] = in0[0];
+ out[1] = in0[1];
+ for (x = 2; x < im->xsize-2; x++) {
+ float ss = offset;
+ ss += KERNEL1x5(in2, x, &kernel[0], 1);
+ ss += KERNEL1x5(in1, x, &kernel[5], 1);
+ ss += KERNEL1x5(in0, x, &kernel[10], 1);
+ ss += KERNEL1x5(in_1, x, &kernel[15], 1);
+ ss += KERNEL1x5(in_2, x, &kernel[20], 1);
+ out[x] = clip8(ss);
+ }
+ out[x+0] = in0[x+0];
+ out[x+1] = in0[x+1];
+ }
+ } else {
+ // Add one time for rounding
+ offset += 0.5;
+ for (y = 2; y < im->ysize-2; y++) {
+ UINT8* in_2 = (UINT8*) im->image[y-2];
+ UINT8* in_1 = (UINT8*) im->image[y-1];
+ UINT8* in0 = (UINT8*) im->image[y];
+ UINT8* in1 = (UINT8*) im->image[y+1];
+ UINT8* in2 = (UINT8*) im->image[y+2];
+ UINT8* out = (UINT8*) imOut->image[y];
+
+ memcpy(out, in0, sizeof(UINT32) * 2);
+ if (im->bands == 2) {
+ for (x = 2; x < im->xsize-2; x++) {
+ float ss0 = offset;
+ float ss3 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4);
+ ss3 += KERNEL1x5(in2, x*4+3, &kernel[0], 4);
+ ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4);
+ ss3 += KERNEL1x5(in1, x*4+3, &kernel[5], 4);
+ ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4);
+ ss3 += KERNEL1x5(in0, x*4+3, &kernel[10], 4);
+ ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4);
+ ss3 += KERNEL1x5(in_1, x*4+3, &kernel[15], 4);
+ ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4);
+ ss3 += KERNEL1x5(in_2, x*4+3, &kernel[20], 4);
+ v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (im->bands == 3) {
+ for (x = 2; x < im->xsize-2; x++) {
+ float ss0 = offset;
+ float ss1 = offset;
+ float ss2 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4);
+ ss1 += KERNEL1x5(in2, x*4+1, &kernel[0], 4);
+ ss2 += KERNEL1x5(in2, x*4+2, &kernel[0], 4);
+ ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4);
+ ss1 += KERNEL1x5(in1, x*4+1, &kernel[5], 4);
+ ss2 += KERNEL1x5(in1, x*4+2, &kernel[5], 4);
+ ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4);
+ ss1 += KERNEL1x5(in0, x*4+1, &kernel[10], 4);
+ ss2 += KERNEL1x5(in0, x*4+2, &kernel[10], 4);
+ ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4);
+ ss1 += KERNEL1x5(in_1, x*4+1, &kernel[15], 4);
+ ss2 += KERNEL1x5(in_1, x*4+2, &kernel[15], 4);
+ ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4);
+ ss1 += KERNEL1x5(in_2, x*4+1, &kernel[20], 4);
+ ss2 += KERNEL1x5(in_2, x*4+2, &kernel[20], 4);
+ v = MAKE_UINT32(
+ clip8(ss0), clip8(ss1), clip8(ss2), 0);
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (im->bands == 4) {
+ for (x = 2; x < im->xsize-2; x++) {
+ float ss0 = offset;
+ float ss1 = offset;
+ float ss2 = offset;
+ float ss3 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4);
+ ss1 += KERNEL1x5(in2, x*4+1, &kernel[0], 4);
+ ss2 += KERNEL1x5(in2, x*4+2, &kernel[0], 4);
+ ss3 += KERNEL1x5(in2, x*4+3, &kernel[0], 4);
+ ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4);
+ ss1 += KERNEL1x5(in1, x*4+1, &kernel[5], 4);
+ ss2 += KERNEL1x5(in1, x*4+2, &kernel[5], 4);
+ ss3 += KERNEL1x5(in1, x*4+3, &kernel[5], 4);
+ ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4);
+ ss1 += KERNEL1x5(in0, x*4+1, &kernel[10], 4);
+ ss2 += KERNEL1x5(in0, x*4+2, &kernel[10], 4);
+ ss3 += KERNEL1x5(in0, x*4+3, &kernel[10], 4);
+ ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4);
+ ss1 += KERNEL1x5(in_1, x*4+1, &kernel[15], 4);
+ ss2 += KERNEL1x5(in_1, x*4+2, &kernel[15], 4);
+ ss3 += KERNEL1x5(in_1, x*4+3, &kernel[15], 4);
+ ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4);
+ ss1 += KERNEL1x5(in_2, x*4+1, &kernel[20], 4);
+ ss2 += KERNEL1x5(in_2, x*4+2, &kernel[20], 4);
+ ss3 += KERNEL1x5(in_2, x*4+3, &kernel[20], 4);
+ v = MAKE_UINT32(
+ clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ memcpy(out + x * sizeof(UINT32), in0 + x * sizeof(UINT32), sizeof(UINT32) * 2);
+ }
+ }
+ memcpy(imOut->image[y], im->image[y], im->linesize);
+ memcpy(imOut->image[y+1], im->image[y+1], im->linesize);
+}
+
+Imaging
+ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
+ FLOAT32 offset)
+{
+ Imaging imOut;
+ ImagingSectionCookie cookie;
+
+ if ( ! im || im->type != IMAGING_TYPE_UINT8)
+ return (Imaging) ImagingError_ModeError();
+
+ if (im->xsize < xsize || im->ysize < ysize)
+ return ImagingCopy(im);
+
+ if ((xsize != 3 && xsize != 5) || xsize != ysize)
+ return (Imaging) ImagingError_ValueError("bad kernel size");
+
+ imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
+ if (!imOut)
+ return NULL;
+
+ ImagingSectionEnter(&cookie);
+ if (xsize == 3) {
+ /* 3x3 kernel. */
+ ImagingFilter3x3(imOut, im, kernel, offset);
+ } else {
+ /* 5x5 kernel. */
+ ImagingFilter5x5(imOut, im, kernel, offset);
+ }
+ ImagingSectionLeave(&cookie);
+ return imOut;
+}
+
diff --git a/contrib/python/Pillow/py2/libImaging/FliDecode.c b/contrib/python/Pillow/py2/libImaging/FliDecode.c
new file mode 100644
index 0000000000..6f48c07d41
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/FliDecode.c
@@ -0,0 +1,216 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for Autodesk Animator FLI/FLC animations
+ *
+ * history:
+ * 97-01-03 fl Created
+ * 97-01-17 fl Added SS2 support (FLC)
+ *
+ * Copyright (c) Fredrik Lundh 1997.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+#define I16(ptr)\
+ ((ptr)[0] + ((ptr)[1] << 8))
+
+#define I32(ptr)\
+ ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24))
+
+
+int
+ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ UINT8* ptr;
+ int framesize;
+ int c, chunks, advance;
+ int l, lines;
+ int i, j, x = 0, y, ymax;
+
+ /* If not even the chunk size is present, we'd better leave */
+
+ if (bytes < 4)
+ return 0;
+
+ /* We don't decode anything unless we have a full chunk in the
+ input buffer */
+
+ ptr = buf;
+
+ framesize = I32(ptr);
+ if (framesize < I32(ptr))
+ return 0;
+
+ /* Make sure this is a frame chunk. The Python driver takes
+ case of other chunk types. */
+
+ if (bytes < 8) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ if (I16(ptr+4) != 0xF1FA) {
+ state->errcode = IMAGING_CODEC_UNKNOWN;
+ return -1;
+ }
+
+ chunks = I16(ptr+6);
+ ptr += 16;
+ bytes -= 16;
+
+ /* Process subchunks */
+ for (c = 0; c < chunks; c++) {
+ UINT8* data;
+ if (bytes < 10) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ data = ptr + 6;
+ switch (I16(ptr+4)) {
+ case 4: case 11:
+ /* FLI COLOR chunk */
+ break; /* ignored; handled by Python code */
+ case 7:
+ /* FLI SS2 chunk (word delta) */
+ lines = I16(data); data += 2;
+ for (l = y = 0; l < lines && y < state->ysize; l++, y++) {
+ UINT8* buf = (UINT8*) im->image[y];
+ int p, packets;
+ packets = I16(data); data += 2;
+ while (packets & 0x8000) {
+ /* flag word */
+ if (packets & 0x4000) {
+ y += 65536 - packets; /* skip lines */
+ if (y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ buf = (UINT8*) im->image[y];
+ } else {
+ /* store last byte (used if line width is odd) */
+ buf[state->xsize-1] = (UINT8) packets;
+ }
+ packets = I16(data); data += 2;
+ }
+ for (p = x = 0; p < packets; p++) {
+ x += data[0]; /* pixel skip */
+ if (data[1] >= 128) {
+ i = 256-data[1]; /* run */
+ if (x + i + i > state->xsize)
+ break;
+ for (j = 0; j < i; j++) {
+ buf[x++] = data[2];
+ buf[x++] = data[3];
+ }
+ data += 2 + 2;
+ } else {
+ i = 2 * (int) data[1]; /* chunk */
+ if (x + i > state->xsize)
+ break;
+ memcpy(buf + x, data + 2, i);
+ data += 2 + i;
+ x += i;
+ }
+ }
+ if (p < packets)
+ break; /* didn't process all packets */
+ }
+ if (l < lines) {
+ /* didn't process all lines */
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ break;
+ case 12:
+ /* FLI LC chunk (byte delta) */
+ y = I16(data); ymax = y + I16(data+2); data += 4;
+ for (; y < ymax && y < state->ysize; y++) {
+ UINT8* out = (UINT8*) im->image[y];
+ int p, packets = *data++;
+ for (p = x = 0; p < packets; p++, x += i) {
+ x += data[0]; /* skip pixels */
+ if (data[1] & 0x80) {
+ i = 256-data[1]; /* run */
+ if (x + i > state->xsize)
+ break;
+ memset(out + x, data[2], i);
+ data += 3;
+ } else {
+ i = data[1]; /* chunk */
+ if (x + i > state->xsize)
+ break;
+ memcpy(out + x, data + 2, i);
+ data += i + 2;
+ }
+ }
+ if (p < packets)
+ break; /* didn't process all packets */
+ }
+ if (y < ymax) {
+ /* didn't process all lines */
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ break;
+ case 13:
+ /* FLI BLACK chunk */
+ for (y = 0; y < state->ysize; y++)
+ memset(im->image[y], 0, state->xsize);
+ break;
+ case 15:
+ /* FLI BRUN chunk */
+ for (y = 0; y < state->ysize; y++) {
+ UINT8* out = (UINT8*) im->image[y];
+ data += 1; /* ignore packetcount byte */
+ for (x = 0; x < state->xsize; x += i) {
+ if (data[0] & 0x80) {
+ i = 256 - data[0];
+ if (x + i > state->xsize)
+ break; /* safety first */
+ memcpy(out + x, data + 1, i);
+ data += i + 1;
+ } else {
+ i = data[0];
+ if (x + i > state->xsize)
+ break; /* safety first */
+ memset(out + x, data[1], i);
+ data += 2;
+ }
+ }
+ if (x != state->xsize) {
+ /* didn't unpack whole line */
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ }
+ break;
+ case 16:
+ /* COPY chunk */
+ for (y = 0; y < state->ysize; y++) {
+ UINT8* buf = (UINT8*) im->image[y];
+ memcpy(buf, data, state->xsize);
+ data += state->xsize;
+ }
+ break;
+ case 18:
+ /* PSTAMP chunk */
+ break; /* ignored */
+ default:
+ /* unknown chunk */
+ /* printf("unknown FLI/FLC chunk: %d\n", I16(ptr+4)); */
+ state->errcode = IMAGING_CODEC_UNKNOWN;
+ return -1;
+ }
+ advance = I32(ptr);
+ ptr += advance;
+ bytes -= advance;
+ }
+
+ return -1; /* end of frame */
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Geometry.c b/contrib/python/Pillow/py2/libImaging/Geometry.c
new file mode 100644
index 0000000000..fd5e259582
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Geometry.c
@@ -0,0 +1,1069 @@
+#include "Imaging.h"
+
+/* For large images rotation is an inefficient operation in terms of CPU cache.
+ One row in the source image affects each column in destination.
+ Rotating in chunks that fit in the cache can speed up rotation
+ 8x on a modern CPU. A chunk size of 128 requires only 65k and is large enough
+ that the overhead from the extra loops are not apparent. */
+#define ROTATE_CHUNK 512
+#define ROTATE_SMALL_CHUNK 8
+
+#define COORD(v) ((v) < 0.0 ? -1 : ((int)(v)))
+#define FLOOR(v) ((v) < 0.0 ? ((int)floor(v)) : ((int)(v)))
+
+/* -------------------------------------------------------------------- */
+/* Transpose operations */
+
+Imaging
+ImagingFlipLeftRight(Imaging imOut, Imaging imIn)
+{
+ ImagingSectionCookie cookie;
+ int x, y, xr;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+ if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize)
+ return (Imaging) ImagingError_Mismatch();
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define FLIP_LEFT_RIGHT(INT, image) \
+ for (y = 0; y < imIn->ysize; y++) { \
+ INT* in = (INT *)imIn->image[y]; \
+ INT* out = (INT *)imOut->image[y]; \
+ xr = imIn->xsize-1; \
+ for (x = 0; x < imIn->xsize; x++, xr--) \
+ out[xr] = in[x]; \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ FLIP_LEFT_RIGHT(UINT16, image8)
+ } else {
+ FLIP_LEFT_RIGHT(UINT8, image8)
+ }
+ } else {
+ FLIP_LEFT_RIGHT(INT32, image32)
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef FLIP_LEFT_RIGHT
+
+ return imOut;
+}
+
+
+Imaging
+ImagingFlipTopBottom(Imaging imOut, Imaging imIn)
+{
+ ImagingSectionCookie cookie;
+ int y, yr;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+ if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize)
+ return (Imaging) ImagingError_Mismatch();
+
+ ImagingCopyPalette(imOut, imIn);
+
+ ImagingSectionEnter(&cookie);
+
+ yr = imIn->ysize - 1;
+ for (y = 0; y < imIn->ysize; y++, yr--)
+ memcpy(imOut->image[yr], imIn->image[y], imIn->linesize);
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+
+Imaging
+ImagingRotate90(Imaging imOut, Imaging imIn)
+{
+ ImagingSectionCookie cookie;
+ int x, y, xx, yy, xr, xxsize, yysize;
+ int xxx, yyy, xxxsize, yyysize;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+ if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
+ return (Imaging) ImagingError_Mismatch();
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define ROTATE_90(INT, image) \
+ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
+ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
+ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
+ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
+ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
+ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
+ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
+ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
+ for (yyy = yy; yyy < yyysize; yyy++) { \
+ INT* in = (INT *)imIn->image[yyy]; \
+ xr = imIn->xsize - 1 - xx; \
+ for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
+ INT* out = (INT *)imOut->image[xr]; \
+ out[yyy] = in[xxx]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ ROTATE_90(UINT16, image8);
+ } else {
+ ROTATE_90(UINT8, image8);
+ }
+ } else {
+ ROTATE_90(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef ROTATE_90
+
+ return imOut;
+}
+
+
+Imaging
+ImagingTranspose(Imaging imOut, Imaging imIn)
+{
+ ImagingSectionCookie cookie;
+ int x, y, xx, yy, xxsize, yysize;
+ int xxx, yyy, xxxsize, yyysize;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+ if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
+ return (Imaging) ImagingError_Mismatch();
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define TRANSPOSE(INT, image) \
+ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
+ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
+ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
+ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
+ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
+ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
+ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
+ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
+ for (yyy = yy; yyy < yyysize; yyy++) { \
+ INT* in = (INT *)imIn->image[yyy]; \
+ for (xxx = xx; xxx < xxxsize; xxx++) { \
+ INT* out = (INT *)imOut->image[xxx]; \
+ out[yyy] = in[xxx]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ TRANSPOSE(UINT16, image8);
+ } else {
+ TRANSPOSE(UINT8, image8);
+ }
+ } else {
+ TRANSPOSE(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef TRANSPOSE
+
+ return imOut;
+}
+
+
+Imaging
+ImagingTransverse(Imaging imOut, Imaging imIn)
+{
+ ImagingSectionCookie cookie;
+ int x, y, xr, yr, xx, yy, xxsize, yysize;
+ int xxx, yyy, xxxsize, yyysize;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+ if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
+ return (Imaging) ImagingError_Mismatch();
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define TRANSVERSE(INT, image) \
+ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
+ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
+ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
+ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
+ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
+ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
+ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
+ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
+ yr = imIn->ysize - 1 - yy; \
+ for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
+ INT* in = (INT *)imIn->image[yyy]; \
+ xr = imIn->xsize - 1 - xx; \
+ for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
+ INT* out = (INT *)imOut->image[xr]; \
+ out[yr] = in[xxx]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ TRANSVERSE(UINT16, image8);
+ } else {
+ TRANSVERSE(UINT8, image8);
+ }
+ } else {
+ TRANSVERSE(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef TRANSVERSE
+
+ return imOut;
+}
+
+
+Imaging
+ImagingRotate180(Imaging imOut, Imaging imIn)
+{
+ ImagingSectionCookie cookie;
+ int x, y, xr, yr;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+ if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize)
+ return (Imaging) ImagingError_Mismatch();
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define ROTATE_180(INT, image) \
+ for (y = 0; y < imIn->ysize; y++, yr--) { \
+ INT* in = (INT *)imIn->image[y]; \
+ INT* out = (INT *)imOut->image[yr]; \
+ xr = imIn->xsize-1; \
+ for (x = 0; x < imIn->xsize; x++, xr--) \
+ out[xr] = in[x]; \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ yr = imIn->ysize-1;
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ ROTATE_180(UINT16, image8)
+ } else {
+ ROTATE_180(UINT8, image8)
+ }
+ } else {
+ ROTATE_180(INT32, image32)
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef ROTATE_180
+
+ return imOut;
+}
+
+
+Imaging
+ImagingRotate270(Imaging imOut, Imaging imIn)
+{
+ ImagingSectionCookie cookie;
+ int x, y, xx, yy, yr, xxsize, yysize;
+ int xxx, yyy, xxxsize, yyysize;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+ if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
+ return (Imaging) ImagingError_Mismatch();
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define ROTATE_270(INT, image) \
+ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
+ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
+ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
+ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
+ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
+ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
+ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \
+ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \
+ yr = imIn->ysize - 1 - yy; \
+ for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
+ INT* in = (INT *)imIn->image[yyy]; \
+ for (xxx = xx; xxx < xxxsize; xxx++) { \
+ INT* out = (INT *)imOut->image[xxx]; \
+ out[yr] = in[xxx]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ ROTATE_270(UINT16, image8);
+ } else {
+ ROTATE_270(UINT8, image8);
+ }
+ } else {
+ ROTATE_270(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef ROTATE_270
+
+ return imOut;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Transforms */
+
+/* transform primitives (ImagingTransformMap) */
+
+static int
+affine_transform(double* xout, double* yout, int x, int y, void* data)
+{
+ /* full moon tonight. your compiler will generate bogus code
+ for simple expressions, unless you reorganize the code, or
+ install Service Pack 3 */
+
+ double* a = (double*) data;
+ double a0 = a[0]; double a1 = a[1]; double a2 = a[2];
+ double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
+
+ double xin = x + 0.5;
+ double yin = y + 0.5;
+
+ xout[0] = a0*xin + a1*yin + a2;
+ yout[0] = a3*xin + a4*yin + a5;
+
+ return 1;
+}
+
+static int
+perspective_transform(double* xout, double* yout, int x, int y, void* data)
+{
+ double* a = (double*) data;
+ double a0 = a[0]; double a1 = a[1]; double a2 = a[2];
+ double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
+ double a6 = a[6]; double a7 = a[7];
+
+ double xin = x + 0.5;
+ double yin = y + 0.5;
+
+ xout[0] = (a0*xin + a1*yin + a2) / (a6*xin + a7*yin + 1);
+ yout[0] = (a3*xin + a4*yin + a5) / (a6*xin + a7*yin + 1);
+
+ return 1;
+}
+
+static int
+quad_transform(double* xout, double* yout, int x, int y, void* data)
+{
+ /* quad warp: map quadrilateral to rectangle */
+
+ double* a = (double*) data;
+ double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; double a3 = a[3];
+ double a4 = a[4]; double a5 = a[5]; double a6 = a[6]; double a7 = a[7];
+
+ double xin = x + 0.5;
+ double yin = y + 0.5;
+
+ xout[0] = a0 + a1*xin + a2*yin + a3*xin*yin;
+ yout[0] = a4 + a5*xin + a6*yin + a7*xin*yin;
+
+ return 1;
+}
+
+/* transform filters (ImagingTransformFilter) */
+
+static int
+nearest_filter8(void* out, Imaging im, double xin, double yin)
+{
+ int x = COORD(xin);
+ int y = COORD(yin);
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
+ return 0;
+ ((UINT8*)out)[0] = im->image8[y][x];
+ return 1;
+}
+
+static int
+nearest_filter16(void* out, Imaging im, double xin, double yin)
+{
+ int x = COORD(xin);
+ int y = COORD(yin);
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
+ return 0;
+ memcpy(out, im->image8[y] + x * sizeof(INT16), sizeof(INT16));
+ return 1;
+}
+
+static int
+nearest_filter32(void* out, Imaging im, double xin, double yin)
+{
+ int x = COORD(xin);
+ int y = COORD(yin);
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
+ return 0;
+ memcpy(out, &im->image32[y][x], sizeof(INT32));
+ return 1;
+}
+
+#define XCLIP(im, x) ( ((x) < 0) ? 0 : ((x) < im->xsize) ? (x) : im->xsize-1 )
+#define YCLIP(im, y) ( ((y) < 0) ? 0 : ((y) < im->ysize) ? (y) : im->ysize-1 )
+
+#define BILINEAR(v, a, b, d)\
+ (v = (a) + ( (b) - (a) ) * (d))
+
+#define BILINEAR_HEAD(type)\
+ int x, y;\
+ int x0, x1;\
+ double v1, v2;\
+ double dx, dy;\
+ type* in;\
+ if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize)\
+ return 0;\
+ xin -= 0.5;\
+ yin -= 0.5;\
+ x = FLOOR(xin);\
+ y = FLOOR(yin);\
+ dx = xin - x;\
+ dy = yin - y;
+
+#define BILINEAR_BODY(type, image, step, offset) {\
+ in = (type*) ((image)[YCLIP(im, y)] + offset);\
+ x0 = XCLIP(im, x+0)*step;\
+ x1 = XCLIP(im, x+1)*step;\
+ BILINEAR(v1, in[x0], in[x1], dx);\
+ if (y+1 >= 0 && y+1 < im->ysize) {\
+ in = (type*) ((image)[y+1] + offset);\
+ BILINEAR(v2, in[x0], in[x1], dx);\
+ } else\
+ v2 = v1;\
+ BILINEAR(v1, v1, v2, dy);\
+}
+
+static int
+bilinear_filter8(void* out, Imaging im, double xin, double yin)
+{
+ BILINEAR_HEAD(UINT8);
+ BILINEAR_BODY(UINT8, im->image8, 1, 0);
+ ((UINT8*)out)[0] = (UINT8) v1;
+ return 1;
+}
+
+static int
+bilinear_filter32I(void* out, Imaging im, double xin, double yin)
+{
+ INT32 k;
+ BILINEAR_HEAD(INT32);
+ BILINEAR_BODY(INT32, im->image32, 1, 0);
+ k = v1;
+ memcpy(out, &k, sizeof(k));
+ return 1;
+}
+
+static int
+bilinear_filter32F(void* out, Imaging im, double xin, double yin)
+{
+ FLOAT32 k;
+ BILINEAR_HEAD(FLOAT32);
+ BILINEAR_BODY(FLOAT32, im->image32, 1, 0);
+ k = v1;
+ memcpy(out, &k, sizeof(k));
+ return 1;
+}
+
+static int
+bilinear_filter32LA(void* out, Imaging im, double xin, double yin)
+{
+ BILINEAR_HEAD(UINT8);
+ BILINEAR_BODY(UINT8, im->image, 4, 0);
+ ((UINT8*)out)[0] = (UINT8) v1;
+ ((UINT8*)out)[1] = (UINT8) v1;
+ ((UINT8*)out)[2] = (UINT8) v1;
+ BILINEAR_BODY(UINT8, im->image, 4, 3);
+ ((UINT8*)out)[3] = (UINT8) v1;
+ return 1;
+}
+
+static int
+bilinear_filter32RGB(void* out, Imaging im, double xin, double yin)
+{
+ int b;
+ BILINEAR_HEAD(UINT8);
+ for (b = 0; b < im->bands; b++) {
+ BILINEAR_BODY(UINT8, im->image, 4, b);
+ ((UINT8*)out)[b] = (UINT8) v1;
+ }
+ return 1;
+}
+
+#undef BILINEAR
+#undef BILINEAR_HEAD
+#undef BILINEAR_BODY
+
+#define BICUBIC(v, v1, v2, v3, v4, d) {\
+ double p1 = v2;\
+ double p2 = -v1 + v3;\
+ double p3 = 2*(v1 - v2) + v3 - v4;\
+ double p4 = -v1 + v2 - v3 + v4;\
+ v = p1 + (d)*(p2 + (d)*(p3 + (d)*p4));\
+}
+
+#define BICUBIC_HEAD(type)\
+ int x = FLOOR(xin);\
+ int y = FLOOR(yin);\
+ int x0, x1, x2, x3;\
+ double v1, v2, v3, v4;\
+ double dx, dy;\
+ type* in;\
+ if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize)\
+ return 0;\
+ xin -= 0.5;\
+ yin -= 0.5;\
+ x = FLOOR(xin);\
+ y = FLOOR(yin);\
+ dx = xin - x;\
+ dy = yin - y;\
+ x--; y--;
+
+#define BICUBIC_BODY(type, image, step, offset) {\
+ in = (type*) ((image)[YCLIP(im, y)] + offset);\
+ x0 = XCLIP(im, x+0)*step;\
+ x1 = XCLIP(im, x+1)*step;\
+ x2 = XCLIP(im, x+2)*step;\
+ x3 = XCLIP(im, x+3)*step;\
+ BICUBIC(v1, in[x0], in[x1], in[x2], in[x3], dx);\
+ if (y+1 >= 0 && y+1 < im->ysize) {\
+ in = (type*) ((image)[y+1] + offset);\
+ BICUBIC(v2, in[x0], in[x1], in[x2], in[x3], dx);\
+ } else\
+ v2 = v1;\
+ if (y+2 >= 0 && y+2 < im->ysize) {\
+ in = (type*) ((image)[y+2] + offset);\
+ BICUBIC(v3, in[x0], in[x1], in[x2], in[x3], dx);\
+ } else\
+ v3 = v2;\
+ if (y+3 >= 0 && y+3 < im->ysize) {\
+ in = (type*) ((image)[y+3] + offset);\
+ BICUBIC(v4, in[x0], in[x1], in[x2], in[x3], dx);\
+ } else\
+ v4 = v3;\
+ BICUBIC(v1, v1, v2, v3, v4, dy);\
+}
+
+
+static int
+bicubic_filter8(void* out, Imaging im, double xin, double yin)
+{
+ BICUBIC_HEAD(UINT8);
+ BICUBIC_BODY(UINT8, im->image8, 1, 0);
+ if (v1 <= 0.0)
+ ((UINT8*)out)[0] = 0;
+ else if (v1 >= 255.0)
+ ((UINT8*)out)[0] = 255;
+ else
+ ((UINT8*)out)[0] = (UINT8) v1;
+ return 1;
+}
+
+static int
+bicubic_filter32I(void* out, Imaging im, double xin, double yin)
+{
+ INT32 k;
+ BICUBIC_HEAD(INT32);
+ BICUBIC_BODY(INT32, im->image32, 1, 0);
+ k = v1;
+ memcpy(out, &k, sizeof(k));
+ return 1;
+}
+
+static int
+bicubic_filter32F(void* out, Imaging im, double xin, double yin)
+{
+ FLOAT32 k;
+ BICUBIC_HEAD(FLOAT32);
+ BICUBIC_BODY(FLOAT32, im->image32, 1, 0);
+ k = v1;
+ memcpy(out, &k, sizeof(k));
+ return 1;
+}
+
+static int
+bicubic_filter32LA(void* out, Imaging im, double xin, double yin)
+{
+ BICUBIC_HEAD(UINT8);
+ BICUBIC_BODY(UINT8, im->image, 4, 0);
+ if (v1 <= 0.0) {
+ ((UINT8*)out)[0] = 0;
+ ((UINT8*)out)[1] = 0;
+ ((UINT8*)out)[2] = 0;
+ } else if (v1 >= 255.0) {
+ ((UINT8*)out)[0] = 255;
+ ((UINT8*)out)[1] = 255;
+ ((UINT8*)out)[2] = 255;
+ } else {
+ ((UINT8*)out)[0] = (UINT8) v1;
+ ((UINT8*)out)[1] = (UINT8) v1;
+ ((UINT8*)out)[2] = (UINT8) v1;
+ }
+ BICUBIC_BODY(UINT8, im->image, 4, 3);
+ if (v1 <= 0.0)
+ ((UINT8*)out)[3] = 0;
+ else if (v1 >= 255.0)
+ ((UINT8*)out)[3] = 255;
+ else
+ ((UINT8*)out)[3] = (UINT8) v1;
+ return 1;
+}
+
+static int
+bicubic_filter32RGB(void* out, Imaging im, double xin, double yin)
+{
+ int b;
+ BICUBIC_HEAD(UINT8);
+ for (b = 0; b < im->bands; b++) {
+ BICUBIC_BODY(UINT8, im->image, 4, b);
+ if (v1 <= 0.0)
+ ((UINT8*)out)[b] = 0;
+ else if (v1 >= 255.0)
+ ((UINT8*)out)[b] = 255;
+ else
+ ((UINT8*)out)[b] = (UINT8) v1;
+ }
+ return 1;
+}
+
+#undef BICUBIC
+#undef BICUBIC_HEAD
+#undef BICUBIC_BODY
+
+static ImagingTransformFilter
+getfilter(Imaging im, int filterid)
+{
+ switch (filterid) {
+ case IMAGING_TRANSFORM_NEAREST:
+ if (im->image8)
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ return nearest_filter8;
+ case IMAGING_TYPE_SPECIAL:
+ switch (im->pixelsize) {
+ case 1:
+ return nearest_filter8;
+ case 2:
+ return nearest_filter16;
+ case 4:
+ return nearest_filter32;
+ }
+ }
+ else
+ return nearest_filter32;
+ break;
+ case IMAGING_TRANSFORM_BILINEAR:
+ if (im->image8)
+ return bilinear_filter8;
+ else if (im->image32) {
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ if (im->bands == 2)
+ return bilinear_filter32LA;
+ else
+ return bilinear_filter32RGB;
+ case IMAGING_TYPE_INT32:
+ return bilinear_filter32I;
+ case IMAGING_TYPE_FLOAT32:
+ return bilinear_filter32F;
+ }
+ }
+ break;
+ case IMAGING_TRANSFORM_BICUBIC:
+ if (im->image8)
+ return bicubic_filter8;
+ else if (im->image32) {
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ if (im->bands == 2)
+ return bicubic_filter32LA;
+ else
+ return bicubic_filter32RGB;
+ case IMAGING_TYPE_INT32:
+ return bicubic_filter32I;
+ case IMAGING_TYPE_FLOAT32:
+ return bicubic_filter32F;
+ }
+ }
+ break;
+ }
+ /* no such filter */
+ return NULL;
+}
+
+/* transformation engines */
+
+Imaging
+ImagingGenericTransform(
+ Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1,
+ ImagingTransformMap transform, void* transform_data,
+ int filterid, int fill)
+{
+ /* slow generic transformation. use ImagingTransformAffine or
+ ImagingScaleAffine where possible. */
+
+ ImagingSectionCookie cookie;
+ int x, y;
+ char *out;
+ double xx, yy;
+
+ ImagingTransformFilter filter = getfilter(imIn, filterid);
+ if (!filter)
+ return (Imaging) ImagingError_ValueError("bad filter number");
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+
+ ImagingCopyPalette(imOut, imIn);
+
+ ImagingSectionEnter(&cookie);
+
+ if (x0 < 0)
+ x0 = 0;
+ if (y0 < 0)
+ y0 = 0;
+ if (x1 > imOut->xsize)
+ x1 = imOut->xsize;
+ if (y1 > imOut->ysize)
+ y1 = imOut->ysize;
+
+ for (y = y0; y < y1; y++) {
+ out = imOut->image[y] + x0*imOut->pixelsize;
+ for (x = x0; x < x1; x++) {
+ if ( ! transform(&xx, &yy, x-x0, y-y0, transform_data) ||
+ ! filter(out, imIn, xx, yy)) {
+ if (fill)
+ memset(out, 0, imOut->pixelsize);
+ }
+ out += imOut->pixelsize;
+ }
+ }
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+static Imaging
+ImagingScaleAffine(Imaging imOut, Imaging imIn,
+ int x0, int y0, int x1, int y1,
+ double a[6], int fill)
+{
+ /* scale, nearest neighbour resampling */
+
+ ImagingSectionCookie cookie;
+ int x, y;
+ int xin;
+ double xo, yo;
+ int xmin, xmax;
+ int *xintab;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+
+ ImagingCopyPalette(imOut, imIn);
+
+ if (x0 < 0)
+ x0 = 0;
+ if (y0 < 0)
+ y0 = 0;
+ if (x1 > imOut->xsize)
+ x1 = imOut->xsize;
+ if (y1 > imOut->ysize)
+ y1 = imOut->ysize;
+
+ /* malloc check ok, uses calloc for overflow */
+ xintab = (int*) calloc(imOut->xsize, sizeof(int));
+ if (!xintab) {
+ ImagingDelete(imOut);
+ return (Imaging) ImagingError_MemoryError();
+ }
+
+ xo = a[2] + a[0] * 0.5;
+ yo = a[5] + a[4] * 0.5;
+
+ xmin = x1;
+ xmax = x0;
+
+ /* Pretabulate horizontal pixel positions */
+ for (x = x0; x < x1; x++) {
+ xin = COORD(xo);
+ if (xin >= 0 && xin < (int) imIn->xsize) {
+ xmax = x+1;
+ if (x < xmin)
+ xmin = x;
+ xintab[x] = xin;
+ }
+ xo += a[0];
+ }
+
+#define AFFINE_SCALE(pixel, image)\
+ for (y = y0; y < y1; y++) {\
+ int yi = COORD(yo);\
+ pixel *in, *out;\
+ out = imOut->image[y];\
+ if (fill && x1 > x0)\
+ memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
+ if (yi >= 0 && yi < imIn->ysize) {\
+ in = imIn->image[yi];\
+ for (x = xmin; x < xmax; x++)\
+ out[x] = in[xintab[x]];\
+ }\
+ yo += a[4];\
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ AFFINE_SCALE(UINT8, image8);
+ } else {
+ AFFINE_SCALE(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef AFFINE_SCALE
+
+ free(xintab);
+
+ return imOut;
+}
+
+static inline int
+check_fixed(double a[6], int x, int y)
+{
+ return (fabs(x*a[0] + y*a[1] + a[2]) < 32768.0 &&
+ fabs(x*a[3] + y*a[4] + a[5]) < 32768.0);
+}
+
+static inline Imaging
+affine_fixed(Imaging imOut, Imaging imIn,
+ int x0, int y0, int x1, int y1,
+ double a[6], int filterid, int fill)
+{
+ /* affine transform, nearest neighbour resampling, fixed point
+ arithmetics */
+
+ ImagingSectionCookie cookie;
+ int x, y;
+ int xin, yin;
+ int xsize, ysize;
+ int xx, yy;
+ int a0, a1, a2, a3, a4, a5;
+
+ ImagingCopyPalette(imOut, imIn);
+
+ xsize = (int) imIn->xsize;
+ ysize = (int) imIn->ysize;
+
+/* use 16.16 fixed point arithmetics */
+#define FIX(v) FLOOR((v)*65536.0 + 0.5)
+
+ a0 = FIX(a[0]); a1 = FIX(a[1]);
+ a3 = FIX(a[3]); a4 = FIX(a[4]);
+ a2 = FIX(a[2] + a[0] * 0.5 + a[1] * 0.5);
+ a5 = FIX(a[5] + a[3] * 0.5 + a[4] * 0.5);
+
+#undef FIX
+
+#define AFFINE_TRANSFORM_FIXED(pixel, image)\
+ for (y = y0; y < y1; y++) {\
+ pixel *out;\
+ xx = a2;\
+ yy = a5;\
+ out = imOut->image[y];\
+ if (fill && x1 > x0)\
+ memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
+ for (x = x0; x < x1; x++, out++) {\
+ xin = xx >> 16;\
+ if (xin >= 0 && xin < xsize) {\
+ yin = yy >> 16;\
+ if (yin >= 0 && yin < ysize)\
+ *out = imIn->image[yin][xin];\
+ }\
+ xx += a0;\
+ yy += a3;\
+ }\
+ a2 += a1;\
+ a5 += a4;\
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8)
+ AFFINE_TRANSFORM_FIXED(UINT8, image8)
+ else
+ AFFINE_TRANSFORM_FIXED(INT32, image32)
+
+ ImagingSectionLeave(&cookie);
+
+#undef AFFINE_TRANSFORM_FIXED
+
+ return imOut;
+}
+
+Imaging
+ImagingTransformAffine(Imaging imOut, Imaging imIn,
+ int x0, int y0, int x1, int y1,
+ double a[6], int filterid, int fill)
+{
+ /* affine transform, nearest neighbour resampling, floating point
+ arithmetics*/
+
+ ImagingSectionCookie cookie;
+ int x, y;
+ int xin, yin;
+ int xsize, ysize;
+ double xx, yy;
+ double xo, yo;
+
+ if (filterid || imIn->type == IMAGING_TYPE_SPECIAL) {
+ return ImagingGenericTransform(
+ imOut, imIn,
+ x0, y0, x1, y1,
+ affine_transform, a,
+ filterid, fill);
+ }
+
+ if (a[1] == 0 && a[3] == 0) {
+ /* Scaling */
+ return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill);
+ }
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+
+ if (x0 < 0)
+ x0 = 0;
+ if (y0 < 0)
+ y0 = 0;
+ if (x1 > imOut->xsize)
+ x1 = imOut->xsize;
+ if (y1 > imOut->ysize)
+ y1 = imOut->ysize;
+
+ /* translate all four corners to check if they are within the
+ range that can be represented by the fixed point arithmetics */
+
+ if (check_fixed(a, 0, 0) && check_fixed(a, x1-x0, y1-y0) &&
+ check_fixed(a, 0, y1-y0) && check_fixed(a, x1-x0, 0))
+ return affine_fixed(imOut, imIn, x0, y0, x1, y1, a, filterid, fill);
+
+ /* FIXME: cannot really think of any reasonable case when the
+ following code is used. maybe we should fall back on the slow
+ generic transform engine in this case? */
+
+ ImagingCopyPalette(imOut, imIn);
+
+ xsize = (int) imIn->xsize;
+ ysize = (int) imIn->ysize;
+
+ xo = a[2] + a[1] * 0.5 + a[0] * 0.5;
+ yo = a[5] + a[4] * 0.5 + a[3] * 0.5;
+
+#define AFFINE_TRANSFORM(pixel, image)\
+ for (y = y0; y < y1; y++) {\
+ pixel *out;\
+ xx = xo;\
+ yy = yo;\
+ out = imOut->image[y];\
+ if (fill && x1 > x0)\
+ memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
+ for (x = x0; x < x1; x++, out++) {\
+ xin = COORD(xx);\
+ if (xin >= 0 && xin < xsize) {\
+ yin = COORD(yy);\
+ if (yin >= 0 && yin < ysize)\
+ *out = imIn->image[yin][xin];\
+ }\
+ xx += a[0];\
+ yy += a[3];\
+ }\
+ xo += a[1];\
+ yo += a[4];\
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8)
+ AFFINE_TRANSFORM(UINT8, image8)
+ else
+ AFFINE_TRANSFORM(INT32, image32)
+
+ ImagingSectionLeave(&cookie);
+
+#undef AFFINE_TRANSFORM
+
+ return imOut;
+}
+
+Imaging
+ImagingTransform(Imaging imOut, Imaging imIn, int method,
+ int x0, int y0, int x1, int y1,
+ double a[8], int filterid, int fill)
+{
+ ImagingTransformMap transform;
+
+ switch(method) {
+ case IMAGING_TRANSFORM_AFFINE:
+ return ImagingTransformAffine(
+ imOut, imIn, x0, y0, x1, y1, a, filterid, fill);
+ break;
+ case IMAGING_TRANSFORM_PERSPECTIVE:
+ transform = perspective_transform;
+ break;
+ case IMAGING_TRANSFORM_QUAD:
+ transform = quad_transform;
+ break;
+ default:
+ return (Imaging) ImagingError_ValueError("bad transform method");
+ }
+
+ return ImagingGenericTransform(
+ imOut, imIn,
+ x0, y0, x1, y1,
+ transform, a, filterid, fill);
+}
diff --git a/contrib/python/Pillow/py2/libImaging/GetBBox.c b/contrib/python/Pillow/py2/libImaging/GetBBox.c
new file mode 100644
index 0000000000..b63888f874
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/GetBBox.c
@@ -0,0 +1,320 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * helpers to bounding boxes, min/max values, number of colors, etc.
+ *
+ * history:
+ * 1996-07-22 fl Created
+ * 1996-12-30 fl Added projection stuff
+ * 1998-07-12 fl Added extrema stuff
+ * 2004-09-17 fl Added colors stuff
+ *
+ * Copyright (c) 1997-2004 by Secret Labs AB.
+ * Copyright (c) 1996-2004 by Fredrik Lundh.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+int
+ImagingGetBBox(Imaging im, int bbox[4])
+{
+ /* Get the bounding box for any non-zero data in the image.*/
+
+ int x, y;
+ int has_data;
+
+ /* Initialize bounding box to max values */
+ bbox[0] = im->xsize;
+ bbox[1] = -1;
+ bbox[2] = bbox[3] = 0;
+
+#define GETBBOX(image, mask)\
+ for (y = 0; y < im->ysize; y++) {\
+ has_data = 0;\
+ for (x = 0; x < im->xsize; x++)\
+ if (im->image[y][x] & mask) {\
+ has_data = 1;\
+ if (x < bbox[0])\
+ bbox[0] = x;\
+ if (x >= bbox[2])\
+ bbox[2] = x+1;\
+ }\
+ if (has_data) {\
+ if (bbox[1] < 0)\
+ bbox[1] = y;\
+ bbox[3] = y+1;\
+ }\
+ }
+
+ if (im->image8) {
+ GETBBOX(image8, 0xff);
+ } else {
+ INT32 mask = 0xffffffff;
+ if (im->bands == 3)
+ ((UINT8*) &mask)[3] = 0;
+ GETBBOX(image32, mask);
+ }
+
+ /* Check that we got a box */
+ if (bbox[1] < 0)
+ return 0; /* no data */
+
+ return 1; /* ok */
+}
+
+
+int
+ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj)
+{
+ /* Get projection arrays for non-zero data in the image.*/
+
+ int x, y;
+ int has_data;
+
+ /* Initialize projection arrays */
+ memset(xproj, 0, im->xsize);
+ memset(yproj, 0, im->ysize);
+
+#define GETPROJ(image, mask)\
+ for (y = 0; y < im->ysize; y++) {\
+ has_data = 0;\
+ for (x = 0; x < im->xsize; x++)\
+ if (im->image[y][x] & mask) {\
+ has_data = 1;\
+ xproj[x] = 1;\
+ }\
+ if (has_data)\
+ yproj[y] = 1;\
+ }
+
+ if (im->image8) {
+ GETPROJ(image8, 0xff);
+ } else {
+ INT32 mask = 0xffffffff;
+ if (im->bands == 3)
+ ((UINT8*) &mask)[3] = 0;
+ GETPROJ(image32, mask);
+ }
+
+ return 1; /* ok */
+}
+
+
+int
+ImagingGetExtrema(Imaging im, void *extrema)
+{
+ int x, y;
+ INT32 imin, imax;
+ FLOAT32 fmin, fmax;
+
+ if (im->bands != 1) {
+ (void) ImagingError_ModeError();
+ return -1; /* mismatch */
+ }
+
+ if (!im->xsize || !im->ysize)
+ return 0; /* zero size */
+
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ imin = imax = im->image8[0][0];
+ for (y = 0; y < im->ysize; y++) {
+ UINT8* in = im->image8[y];
+ for (x = 0; x < im->xsize; x++) {
+ if (imin > in[x])
+ imin = in[x];
+ else if (imax < in[x])
+ imax = in[x];
+ }
+ }
+ ((UINT8*) extrema)[0] = (UINT8) imin;
+ ((UINT8*) extrema)[1] = (UINT8) imax;
+ break;
+ case IMAGING_TYPE_INT32:
+ imin = imax = im->image32[0][0];
+ for (y = 0; y < im->ysize; y++) {
+ INT32* in = im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ if (imin > in[x])
+ imin = in[x];
+ else if (imax < in[x])
+ imax = in[x];
+ }
+ }
+ memcpy(extrema, &imin, sizeof(imin));
+ memcpy(((char*)extrema) + sizeof(imin), &imax, sizeof(imax));
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ fmin = fmax = ((FLOAT32*) im->image32[0])[0];
+ for (y = 0; y < im->ysize; y++) {
+ FLOAT32* in = (FLOAT32*) im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ if (fmin > in[x])
+ fmin = in[x];
+ else if (fmax < in[x])
+ fmax = in[x];
+ }
+ }
+ memcpy(extrema, &fmin, sizeof(fmin));
+ memcpy(((char*)extrema) + sizeof(fmin), &fmax, sizeof(fmax));
+ break;
+ case IMAGING_TYPE_SPECIAL:
+ if (strcmp(im->mode, "I;16") == 0) {
+ UINT16 v;
+ memcpy(&v, *im->image8, sizeof(v));
+ imin = imax = v;
+ for (y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++) {
+ memcpy(&v, im->image[y] + x * sizeof(v), sizeof(v));
+ if (imin > v)
+ imin = v;
+ else if (imax < v)
+ imax = v;
+ }
+ }
+ v = (UINT16) imin;
+ memcpy(extrema, &v, sizeof(v));
+ v = (UINT16) imax;
+ memcpy(((char*)extrema) + sizeof(v), &v, sizeof(v));
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ (void) ImagingError_ModeError();
+ return -1;
+ }
+ return 1; /* ok */
+}
+
+
+/* static ImagingColorItem* getcolors8(Imaging im, int maxcolors, int* size);*/
+static ImagingColorItem* getcolors32(Imaging im, int maxcolors, int* size);
+
+ImagingColorItem*
+ImagingGetColors(Imaging im, int maxcolors, int* size)
+{
+ /* FIXME: add support for 8-bit images */
+ return getcolors32(im, maxcolors, size);
+}
+
+static ImagingColorItem*
+getcolors32(Imaging im, int maxcolors, int* size)
+{
+ unsigned int h;
+ unsigned int i, incr;
+ int colors;
+ INT32 pixel_mask;
+ int x, y;
+ ImagingColorItem* table;
+ ImagingColorItem* v;
+
+ unsigned int code_size;
+ unsigned int code_poly;
+ unsigned int code_mask;
+
+ /* note: the hash algorithm used here is based on the dictionary
+ code in Python 2.1.3; the exact implementation is borrowed from
+ Python's Unicode property database (written by yours truly) /F */
+
+ static int SIZES[] = {
+ 4,3, 8,3, 16,3, 32,5, 64,3, 128,3, 256,29, 512,17, 1024,9, 2048,5,
+ 4096,83, 8192,27, 16384,43, 32768,3, 65536,45, 131072,9, 262144,39,
+ 524288,39, 1048576,9, 2097152,5, 4194304,3, 8388608,33, 16777216,27,
+ 33554432,9, 67108864,71, 134217728,39, 268435456,9, 536870912,5,
+ 1073741824,83, 0
+ };
+
+ code_size = code_poly = code_mask = 0;
+
+ for (i = 0; SIZES[i]; i += 2) {
+ if (SIZES[i] > maxcolors) {
+ code_size = SIZES[i];
+ code_poly = SIZES[i+1];
+ code_mask = code_size - 1;
+ break;
+ }
+ }
+
+ /* printf("code_size=%d\n", code_size); */
+ /* printf("code_poly=%d\n", code_poly); */
+
+ if (!code_size)
+ return ImagingError_MemoryError(); /* just give up */
+
+ if (!im->image32)
+ return ImagingError_ModeError();
+
+ table = calloc(code_size + 1, sizeof(ImagingColorItem));
+ if (!table)
+ return ImagingError_MemoryError();
+
+ pixel_mask = 0xffffffff;
+ if (im->bands == 3)
+ ((UINT8*) &pixel_mask)[3] = 0;
+
+ colors = 0;
+
+ for (y = 0; y < im->ysize; y++) {
+ INT32* p = im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ INT32 pixel = p[x] & pixel_mask;
+ h = (pixel); /* null hashing */
+ i = (~h) & code_mask;
+ v = &table[i];
+ if (!v->count) {
+ /* add to table */
+ if (colors++ == maxcolors)
+ goto overflow;
+ v->x = x; v->y = y;
+ v->pixel = pixel;
+ v->count = 1;
+ continue;
+ } else if (v->pixel == pixel) {
+ v->count++;
+ continue;
+ }
+ incr = (h ^ (h >> 3)) & code_mask;
+ if (!incr)
+ incr = code_mask;
+ for (;;) {
+ i = (i + incr) & code_mask;
+ v = &table[i];
+ if (!v->count) {
+ /* add to table */
+ if (colors++ == maxcolors)
+ goto overflow;
+ v->x = x; v->y = y;
+ v->pixel = pixel;
+ v->count = 1;
+ break;
+ } else if (v->pixel == pixel) {
+ v->count++;
+ break;
+ }
+ incr = incr << 1;
+ if (incr > code_mask)
+ incr = incr ^ code_poly;
+ }
+ }
+ }
+
+overflow:
+
+ /* pack the table */
+ for (x = y = 0; x < (int) code_size; x++)
+ if (table[x].count) {
+ if (x != y)
+ table[y] = table[x];
+ y++;
+ }
+ table[y].count = 0; /* mark end of table */
+
+ *size = colors;
+
+ return table;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Gif.h b/contrib/python/Pillow/py2/libImaging/Gif.h
new file mode 100644
index 0000000000..2cb95efd28
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Gif.h
@@ -0,0 +1,109 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * Declarations for a fast, suspendable GIF decoder.
+ *
+ * Copyright (c) Fredrik Lundh 1995-96.
+ */
+
+
+/* Max size for a LZW code word. */
+
+#define GIFBITS 12
+
+#define GIFTABLE (1<<GIFBITS)
+#define GIFBUFFER (1<<GIFBITS)
+
+
+typedef struct {
+
+ /* CONFIGURATION */
+
+ /* Initial number of bits. The caller should clear all fields in
+ this structure and set this field before calling the decoder
+ the first time. */
+ int bits;
+
+ /* If set, this is an interlaced image. Process it the following way:
+ * 1st pass: start at top line, lines are 8 pixels high, step 8 pixels
+ * 2nd pass: start at line 4, lines are 4 pixels high, step 8 pixels
+ * 3rd pass: start at line 2, lines are 2 pixels high, step 4 pixels
+ * 4th pass: start at line 1, lines are 1 pixels high, step 2 pixels
+ */
+ int interlace;
+
+ /* PRIVATE CONTEXT (set by decoder) */
+
+ /* Interlace parameters */
+ int step, repeat;
+
+ /* Input bit buffer */
+ INT32 bitbuffer;
+ int bitcount;
+ int blocksize;
+
+ /* Code buffer */
+ int codesize;
+ int codemask;
+
+ /* Constant symbol codes */
+ int clear, end;
+
+ /* Symbol history */
+ int lastcode;
+ unsigned char lastdata;
+
+ /* History buffer */
+ int bufferindex;
+ unsigned char buffer[GIFTABLE];
+
+ /* Symbol table */
+ UINT16 link[GIFTABLE];
+ unsigned char data[GIFTABLE];
+ int next;
+
+} GIFDECODERSTATE;
+
+typedef struct GIFENCODERBLOCK_T
+{
+ struct GIFENCODERBLOCK_T *next;
+ int size;
+ UINT8 data[255];
+} GIFENCODERBLOCK;
+
+typedef struct {
+
+ /* CONFIGURATION */
+
+ /* Initial number of bits. The caller should clear all fields in
+ this structure and set this field before calling the encoder
+ the first time. */
+ int bits;
+
+ /* NOTE: the expanding encoder ignores this field */
+
+ /* If set, write an interlaced image (see above) */
+ int interlace;
+
+ /* PRIVATE CONTEXT (set by encoder) */
+
+ /* Interlace parameters */
+ int step, repeat;
+
+ /* Output bit buffer */
+ INT32 bitbuffer;
+ int bitcount;
+
+ /* Output buffer list (linked list) */
+ GIFENCODERBLOCK* block; /* current block */
+ GIFENCODERBLOCK* flush; /* output queue */
+ GIFENCODERBLOCK* free; /* if not null, use this */
+
+ /* Fields used for run-length encoding */
+ int first; /* true if we haven't read the first pixel */
+ int last; /* last byte value seen */
+ int count; /* how many bytes with that value we've seen */
+ int lastcode;
+
+} GIFENCODERSTATE;
diff --git a/contrib/python/Pillow/py2/libImaging/GifDecode.c b/contrib/python/Pillow/py2/libImaging/GifDecode.c
new file mode 100644
index 0000000000..68429ab26c
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/GifDecode.c
@@ -0,0 +1,297 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * a fast, suspendable GIF decoder
+ *
+ * history:
+ * 95-09-03 fl Created
+ * 95-09-05 fl Fixed sign problem on 16-bit platforms
+ * 95-09-13 fl Added some storage shortcuts
+ * 96-03-28 fl Revised API, integrated with PIL
+ * 96-12-10 fl Added interlace support
+ * 96-12-16 fl Fixed premature termination bug introduced by last fix
+ * 97-01-05 fl Don't mess up on bogus configuration
+ * 97-01-17 fl Don't mess up on very small, interlaced files
+ * 99-02-07 fl Minor speedups
+ *
+ * Copyright (c) Secret Labs AB 1997-99.
+ * Copyright (c) Fredrik Lundh 1995-97.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#include <stdio.h>
+#include <memory.h> /* memcpy() */
+
+#include "Gif.h"
+
+
+#define NEWLINE(state, context) {\
+ state->x = 0;\
+ state->y += context->step;\
+ while (state->y >= state->ysize)\
+ switch (context->interlace) {\
+ case 1:\
+ context->repeat = state->y = 4;\
+ context->interlace = 2;\
+ break;\
+ case 2:\
+ context->step = 4;\
+ context->repeat = state->y = 2;\
+ context->interlace = 3;\
+ break;\
+ case 3:\
+ context->step = 2;\
+ context->repeat = state->y = 1;\
+ context->interlace = 0;\
+ break;\
+ default:\
+ return -1;\
+ }\
+ if (state->y < state->ysize)\
+ out = im->image8[state->y + state->yoff] + state->xoff;\
+}
+
+
+int
+ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes)
+{
+ UINT8* p;
+ UINT8* out;
+ int c, i;
+ int thiscode;
+ GIFDECODERSTATE *context = (GIFDECODERSTATE*) state->context;
+
+ UINT8 *ptr = buffer;
+
+ if (!state->state) {
+
+ /* Initialise state */
+ if (context->bits < 0 || context->bits > 12) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ /* Clear code */
+ context->clear = 1 << context->bits;
+
+ /* End code */
+ context->end = context->clear + 1;
+
+ /* Interlace */
+ if (context->interlace) {
+ context->interlace = 1;
+ context->step = context->repeat = 8;
+ } else
+ context->step = 1;
+
+ state->state = 1;
+ }
+
+ out = im->image8[state->y + state->yoff] + state->xoff + state->x;
+
+ for (;;) {
+
+ if (state->state == 1) {
+
+ /* First free entry in table */
+ context->next = context->clear + 2;
+
+ /* Initial code size */
+ context->codesize = context->bits + 1;
+ context->codemask = (1 << context->codesize) - 1;
+
+ /* Buffer pointer. We fill the buffer from right, which
+ allows us to return all of it in one operation. */
+ context->bufferindex = GIFBUFFER;
+
+ state->state = 2;
+ }
+
+ if (context->bufferindex < GIFBUFFER) {
+
+ /* Return whole buffer in one chunk */
+ i = GIFBUFFER - context->bufferindex;
+ p = &context->buffer[context->bufferindex];
+
+ context->bufferindex = GIFBUFFER;
+
+ } else {
+
+ /* Get current symbol */
+
+ while (context->bitcount < context->codesize) {
+
+ if (context->blocksize > 0) {
+
+ /* Read next byte */
+ c = *ptr++; bytes--;
+
+ context->blocksize--;
+
+ /* New bits are shifted in from from the left. */
+ context->bitbuffer |= (INT32) c << context->bitcount;
+ context->bitcount += 8;
+
+ } else {
+
+ /* New GIF block */
+
+ /* We don't start decoding unless we have a full block */
+ if (bytes < 1)
+ return ptr - buffer;
+ c = *ptr;
+ if (bytes < c+1)
+ return ptr - buffer;
+
+ context->blocksize = c;
+
+ ptr++; bytes--;
+
+ }
+ }
+
+ /* Extract current symbol from bit buffer. */
+ c = (int) context->bitbuffer & context->codemask;
+
+ /* Adjust buffer */
+ context->bitbuffer >>= context->codesize;
+ context->bitcount -= context->codesize;
+
+ /* If c is less than "clear", it's a data byte. Otherwise,
+ it's either clear/end or a code symbol which should be
+ expanded. */
+
+ if (c == context->clear) {
+ if (state->state != 2)
+ state->state = 1;
+ continue;
+ }
+
+ if (c == context->end)
+ break;
+
+ i = 1;
+ p = &context->lastdata;
+
+ if (state->state == 2) {
+
+ /* First valid symbol after clear; use as is */
+ if (c > context->clear) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->lastdata = context->lastcode = c;
+ state->state = 3;
+
+ } else {
+
+ thiscode = c;
+
+ if (c > context->next) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (c == context->next) {
+
+ /* c == next is allowed. not sure why. */
+
+ if (context->bufferindex <= 0) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->buffer[--context->bufferindex] =
+ context->lastdata;
+
+ c = context->lastcode;
+
+ }
+
+ while (c >= context->clear) {
+
+ /* Copy data string to buffer (beginning from right) */
+
+ if (context->bufferindex <= 0 || c >= GIFTABLE) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->buffer[--context->bufferindex] =
+ context->data[c];
+
+ c = context->link[c];
+ }
+
+ context->lastdata = c;
+
+ if (context->next < GIFTABLE) {
+
+ /* We'll only add this symbol if we have room
+ for it (take advise, Netscape!) */
+ context->data[context->next] = c;
+ context->link[context->next] = context->lastcode;
+
+ if (context->next == context->codemask &&
+ context->codesize < GIFBITS) {
+
+ /* Expand code size */
+ context->codesize++;
+ context->codemask = (1 << context->codesize) - 1;
+ }
+
+ context->next++;
+
+ }
+
+ context->lastcode = thiscode;
+
+ }
+ }
+
+ /* Copy the bytes into the image */
+ if (state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ /* To squeeze some extra pixels out of this loop, we test for
+ some common cases and handle them separately. */
+
+ /* FIXME: should we handle the transparency index in here??? */
+
+ if (i == 1) {
+ if (state->x < state->xsize-1) {
+ /* Single pixel, not at the end of the line. */
+ *out++ = p[0];
+ state->x++;
+ continue;
+ }
+ } else if (state->x + i <= state->xsize) {
+ /* This string fits into current line. */
+ memcpy(out, p, i);
+ out += i;
+ state->x += i;
+ if (state->x == state->xsize) {
+ NEWLINE(state, context);
+ }
+ continue;
+ }
+
+ /* No shortcut, copy pixel by pixel */
+ for (c = 0; c < i; c++) {
+ *out++ = p[c];
+ if (++state->x >= state->xsize) {
+ NEWLINE(state, context);
+ }
+ }
+ }
+
+ return ptr - buffer;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/GifEncode.c b/contrib/python/Pillow/py2/libImaging/GifEncode.c
new file mode 100644
index 0000000000..f211814ed0
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/GifEncode.c
@@ -0,0 +1,320 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * encoder for uncompressed GIF data
+ *
+ * history:
+ * 97-01-05 fl created (writes uncompressed data)
+ * 97-08-27 fl fixed off-by-one error in buffer size test
+ * 98-07-09 fl added interlace write support
+ * 99-02-07 fl rewritten, now uses a run-length encoding strategy
+ * 99-02-08 fl improved run-length encoding for long runs
+ *
+ * Copyright (c) Secret Labs AB 1997-99.
+ * Copyright (c) Fredrik Lundh 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include "Gif.h"
+
+/* codes from 0 to 255 are literals */
+#define CLEAR_CODE 256
+#define EOF_CODE 257
+#define FIRST_CODE 258
+#define LAST_CODE 511
+
+enum { INIT, ENCODE, ENCODE_EOF, FLUSH, EXIT };
+
+/* to make things a little less complicated, we use a simple output
+ queue to hold completed blocks. the following inlined function
+ adds a byte to the current block. it allocates a new block if
+ necessary. */
+
+static inline int
+emit(GIFENCODERSTATE *context, int byte)
+{
+ /* write a byte to the output buffer */
+
+ if (!context->block || context->block->size == 255) {
+ GIFENCODERBLOCK* block;
+
+ /* no room in the current block (or no current block);
+ allocate a new one */
+
+ /* add current block to end of flush queue */
+ if (context->block) {
+ block = context->flush;
+ while (block && block->next)
+ block = block->next;
+ if (block)
+ block->next = context->block;
+ else
+ context->flush = context->block;
+ }
+
+ /* get a new block */
+ if (context->free) {
+ block = context->free;
+ context->free = NULL;
+ } else {
+ /* malloc check ok, small constant allocation */
+ block = malloc(sizeof(GIFENCODERBLOCK));
+ if (!block)
+ return 0;
+ }
+
+ block->size = 0;
+ block->next = NULL;
+
+ context->block = block;
+
+ }
+
+ /* write new byte to block */
+ context->block->data[context->block->size++] = byte;
+
+ return 1;
+}
+
+/* write a code word to the current block. this is a macro to make
+ sure it's inlined on all platforms */
+
+#define EMIT(code) {\
+ context->bitbuffer |= ((INT32) (code)) << context->bitcount;\
+ context->bitcount += 9;\
+ while (context->bitcount >= 8) {\
+ if (!emit(context, (UINT8) context->bitbuffer)) {\
+ state->errcode = IMAGING_CODEC_MEMORY;\
+ return 0;\
+ }\
+ context->bitbuffer >>= 8;\
+ context->bitcount -= 8;\
+ }\
+}
+
+/* write a run. we use a combination of literals and combinations of
+ literals. this can give quite decent compression for images with
+ long stretches of identical pixels. but remember: if you want
+ really good compression, use another file format. */
+
+#define EMIT_RUN(label) {\
+label:\
+ while (context->count > 0) {\
+ int run = 2;\
+ EMIT(context->last);\
+ context->count--;\
+ if (state->count++ == LAST_CODE) {\
+ EMIT(CLEAR_CODE);\
+ state->count = FIRST_CODE;\
+ goto label;\
+ }\
+ while (context->count >= run) {\
+ EMIT(state->count - 1);\
+ context->count -= run;\
+ run++;\
+ if (state->count++ == LAST_CODE) {\
+ EMIT(CLEAR_CODE);\
+ state->count = FIRST_CODE;\
+ goto label;\
+ }\
+ }\
+ if (context->count > 1) {\
+ EMIT(state->count - 1 - (run - context->count));\
+ context->count = 0;\
+ if (state->count++ == LAST_CODE) {\
+ EMIT(CLEAR_CODE);\
+ state->count = FIRST_CODE;\
+ }\
+ break;\
+ }\
+ }\
+}
+
+int
+ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
+{
+ UINT8* ptr;
+ int this;
+
+ GIFENCODERBLOCK* block;
+ GIFENCODERSTATE *context = (GIFENCODERSTATE*) state->context;
+
+ if (!state->state) {
+
+ /* place a clear code in the output buffer */
+ context->bitbuffer = CLEAR_CODE;
+ context->bitcount = 9;
+
+ state->count = FIRST_CODE;
+
+ if (context->interlace) {
+ context->interlace = 1;
+ context->step = 8;
+ } else
+ context->step = 1;
+
+ context->last = -1;
+
+ /* sanity check */
+ if (state->xsize <= 0 || state->ysize <= 0)
+ state->state = ENCODE_EOF;
+
+ }
+
+ ptr = buf;
+
+ for (;;)
+
+ switch (state->state) {
+
+ case INIT:
+ case ENCODE:
+
+ /* identify and store a run of pixels */
+
+ if (state->x == 0 || state->x >= state->xsize) {
+
+ if (!context->interlace && state->y >= state->ysize) {
+ state->state = ENCODE_EOF;
+ break;
+ }
+
+ if (context->flush) {
+ state->state = FLUSH;
+ break;
+ }
+
+ /* get another line of data */
+ state->shuffle(
+ state->buffer,
+ (UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->xsize
+ );
+
+ state->x = 0;
+
+ if (state->state == INIT) {
+ /* preload the run-length buffer and get going */
+ context->last = state->buffer[0];
+ context->count = state->x = 1;
+ state->state = ENCODE;
+ }
+
+ /* step forward, according to the interlace settings */
+ state->y += context->step;
+ while (context->interlace && state->y >= state->ysize)
+ switch (context->interlace) {
+ case 1:
+ state->y = 4;
+ context->interlace = 2;
+ break;
+ case 2:
+ context->step = 4;
+ state->y = 2;
+ context->interlace = 3;
+ break;
+ case 3:
+ context->step = 2;
+ state->y = 1;
+ context->interlace = 0;
+ break;
+ default:
+ /* just make sure we don't loop forever */
+ context->interlace = 0;
+ }
+
+ }
+
+ this = state->buffer[state->x++];
+
+ if (this == context->last)
+ context->count++;
+ else {
+ EMIT_RUN(label1);
+ context->last = this;
+ context->count = 1;
+ }
+ break;
+
+
+ case ENCODE_EOF:
+
+ /* write the final run */
+ EMIT_RUN(label2);
+
+ /* write an end of image marker */
+ EMIT(EOF_CODE);
+
+ /* empty the bit buffer */
+ while (context->bitcount > 0) {
+ if (!emit(context, (UINT8) context->bitbuffer)) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return 0;
+ }
+ context->bitbuffer >>= 8;
+ context->bitcount -= 8;
+ }
+
+ /* flush the last block, and exit */
+ if (context->block) {
+ GIFENCODERBLOCK* block;
+ block = context->flush;
+ while (block && block->next)
+ block = block->next;
+ if (block)
+ block->next = context->block;
+ else
+ context->flush = context->block;
+ context->block = NULL;
+ }
+
+ state->state = EXIT;
+
+ /* fall through... */
+
+ case EXIT:
+ case FLUSH:
+
+ while (context->flush) {
+
+ /* get a block from the flush queue */
+ block = context->flush;
+
+ if (block->size > 0) {
+
+ /* make sure it fits into the output buffer */
+ if (bytes < block->size+1)
+ return ptr - buf;
+
+ ptr[0] = block->size;
+ memcpy(ptr+1, block->data, block->size);
+
+ ptr += block->size+1;
+ bytes -= block->size+1;
+
+ }
+
+ context->flush = block->next;
+
+ if (context->free)
+ free(context->free);
+ context->free = block;
+
+ }
+
+ if (state->state == EXIT) {
+ /* this was the last block! */
+ if (context->free)
+ free(context->free);
+ state->errcode = IMAGING_CODEC_END;
+ return ptr - buf;
+ }
+
+ state->state = ENCODE;
+ break;
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/HexDecode.c b/contrib/python/Pillow/py2/libImaging/HexDecode.c
new file mode 100644
index 0000000000..8bd9bf67fa
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/HexDecode.c
@@ -0,0 +1,67 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for hex encoded image data
+ *
+ * history:
+ * 96-05-16 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#define HEX(v) ((v >= '0' && v <= '9') ? v - '0' :\
+ (v >= 'a' && v <= 'f') ? v - 'a' + 10 :\
+ (v >= 'A' && v <= 'F') ? v - 'A' + 10 : -1)
+
+int
+ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ UINT8* ptr;
+ int a, b;
+
+ ptr = buf;
+
+ for (;;) {
+
+ if (bytes < 2)
+ return ptr - buf;
+
+ a = HEX(ptr[0]);
+ b = HEX(ptr[1]);
+
+ if (a < 0 || b < 0) {
+
+ ptr++;
+ bytes--;
+
+ } else {
+
+ ptr += 2;
+ bytes -= 2;
+
+ state->buffer[state->x] = (a<<4) + b;
+
+ if (++state->x >= state->bytes) {
+
+ /* Got a full line, unpack it */
+ state->shuffle((UINT8*) im->image[state->y], state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+
+ }
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Histo.c b/contrib/python/Pillow/py2/libImaging/Histo.c
new file mode 100644
index 0000000000..5c2824ab03
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Histo.c
@@ -0,0 +1,177 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * histogram support
+ *
+ * history:
+ * 1995-06-15 fl Created.
+ * 1996-04-05 fl Fixed histogram for multiband images.
+ * 1997-02-23 fl Added mask support
+ * 1998-07-01 fl Added basic 32-bit float/integer support
+ *
+ * Copyright (c) 1997-2003 by Secret Labs AB.
+ * Copyright (c) 1995-2003 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+/* HISTOGRAM */
+/* --------------------------------------------------------------------
+ * Take a histogram of an image. Returns a histogram object containing
+ * 256 slots per band in the input image.
+ */
+
+void
+ImagingHistogramDelete(ImagingHistogram h)
+{
+ if (h->histogram)
+ free(h->histogram);
+ free(h);
+}
+
+ImagingHistogram
+ImagingHistogramNew(Imaging im)
+{
+ ImagingHistogram h;
+
+ /* Create histogram descriptor */
+ h = calloc(1, sizeof(struct ImagingHistogramInstance));
+ strncpy(h->mode, im->mode, IMAGING_MODE_LENGTH-1);
+ h->mode[IMAGING_MODE_LENGTH-1] = 0;
+
+ h->bands = im->bands;
+ h->histogram = calloc(im->pixelsize, 256 * sizeof(long));
+
+ return h;
+}
+
+ImagingHistogram
+ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax)
+{
+ ImagingSectionCookie cookie;
+ int x, y, i;
+ ImagingHistogram h;
+ INT32 imin, imax;
+ FLOAT32 fmin, fmax, scale;
+
+ if (!im)
+ return ImagingError_ModeError();
+
+ if (imMask) {
+ /* Validate mask */
+ if (im->xsize != imMask->xsize || im->ysize != imMask->ysize)
+ return ImagingError_Mismatch();
+ if (strcmp(imMask->mode, "1") != 0 && strcmp(imMask->mode, "L") != 0)
+ return ImagingError_ValueError("bad transparency mask");
+ }
+
+ h = ImagingHistogramNew(im);
+
+ if (imMask) {
+ /* mask */
+ if (im->image8) {
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->xsize; x++)
+ if (imMask->image8[y][x] != 0)
+ h->histogram[im->image8[y][x]]++;
+ ImagingSectionLeave(&cookie);
+ } else { /* yes, we need the braces. C isn't Python! */
+ if (im->type != IMAGING_TYPE_UINT8) {
+ ImagingHistogramDelete(h);
+ return ImagingError_ModeError();
+ }
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++) {
+ UINT8* in = (UINT8*) im->image32[y];
+ for (x = 0; x < im->xsize; x++)
+ if (imMask->image8[y][x] != 0) {
+ h->histogram[(*in++)]++;
+ h->histogram[(*in++)+256]++;
+ h->histogram[(*in++)+512]++;
+ h->histogram[(*in++)+768]++;
+ } else
+ in += 4;
+ }
+ ImagingSectionLeave(&cookie);
+ }
+ } else {
+ /* mask not given; process pixels in image */
+ if (im->image8) {
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->xsize; x++)
+ h->histogram[im->image8[y][x]]++;
+ ImagingSectionLeave(&cookie);
+ } else {
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++) {
+ UINT8* in = (UINT8*) im->image[y];
+ for (x = 0; x < im->xsize; x++) {
+ h->histogram[(*in++)]++;
+ h->histogram[(*in++)+256]++;
+ h->histogram[(*in++)+512]++;
+ h->histogram[(*in++)+768]++;
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ case IMAGING_TYPE_INT32:
+ if (!minmax) {
+ ImagingHistogramDelete(h);
+ return ImagingError_ValueError("min/max not given");
+ }
+ if (!im->xsize || !im->ysize)
+ break;
+ memcpy(&imin, minmax, sizeof(imin));
+ memcpy(&imax, ((char*)minmax) + sizeof(imin), sizeof(imax));
+ if (imin >= imax)
+ break;
+ ImagingSectionEnter(&cookie);
+ scale = 255.0F / (imax - imin);
+ for (y = 0; y < im->ysize; y++) {
+ INT32* in = im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ i = (int) (((*in++)-imin)*scale);
+ if (i >= 0 && i < 256)
+ h->histogram[i]++;
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ if (!minmax) {
+ ImagingHistogramDelete(h);
+ return ImagingError_ValueError("min/max not given");
+ }
+ if (!im->xsize || !im->ysize)
+ break;
+ memcpy(&fmin, minmax, sizeof(fmin));
+ memcpy(&fmax, ((char*)minmax) + sizeof(fmin), sizeof(fmax));
+ if (fmin >= fmax)
+ break;
+ ImagingSectionEnter(&cookie);
+ scale = 255.0F / (fmax - fmin);
+ for (y = 0; y < im->ysize; y++) {
+ FLOAT32* in = (FLOAT32*) im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ i = (int) (((*in++)-fmin)*scale);
+ if (i >= 0 && i < 256)
+ h->histogram[i]++;
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ }
+ }
+ }
+
+ return h;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/ImDib.h b/contrib/python/Pillow/py2/libImaging/ImDib.h
new file mode 100644
index 0000000000..e5a2cc0f63
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/ImDib.h
@@ -0,0 +1,57 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * Windows DIB specifics
+ *
+ * Copyright (c) Secret Labs AB 1997-98.
+ * Copyright (c) Fredrik Lundh 1996.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#ifdef _WIN32
+
+#include "ImPlatform.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct ImagingDIBInstance {
+ /* Windows interface */
+ HDC dc;
+ HBITMAP bitmap;
+ HGDIOBJ old_bitmap;
+ BITMAPINFO *info;
+ UINT8 *bits;
+ HPALETTE palette;
+ /* Used by cut and paste */
+ char mode[4];
+ int xsize, ysize;
+ int pixelsize;
+ int linesize;
+ ImagingShuffler pack;
+ ImagingShuffler unpack;
+};
+
+typedef struct ImagingDIBInstance* ImagingDIB;
+
+extern char* ImagingGetModeDIB(int size_out[2]);
+
+extern ImagingDIB ImagingNewDIB(const char *mode, int xsize, int ysize);
+
+extern void ImagingDeleteDIB(ImagingDIB im);
+
+extern void ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]);
+extern void ImagingExposeDIB(ImagingDIB dib, void *dc);
+
+extern int ImagingQueryPaletteDIB(ImagingDIB dib, void *dc);
+
+extern void ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/ImPlatform.h b/contrib/python/Pillow/py2/libImaging/ImPlatform.h
new file mode 100644
index 0000000000..b2d4db7859
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/ImPlatform.h
@@ -0,0 +1,86 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * platform declarations for the imaging core library
+ *
+ * Copyright (c) Fredrik Lundh 1995-2003.
+ */
+
+#include "Python.h"
+
+/* Workaround issue #2479 */
+#if PY_VERSION_HEX < 0x03070000 && defined(PySlice_GetIndicesEx) && !defined(PYPY_VERSION)
+#undef PySlice_GetIndicesEx
+#endif
+
+/* Check that we have an ANSI compliant compiler */
+#ifndef HAVE_PROTOTYPES
+#error Sorry, this library requires support for ANSI prototypes.
+#endif
+#ifndef STDC_HEADERS
+#error Sorry, this library requires ANSI header files.
+#endif
+
+#if defined(PIL_NO_INLINE)
+#define inline
+#else
+#if defined(_MSC_VER) && !defined(__GNUC__)
+#define inline __inline
+#endif
+#endif
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+#else
+/* For System that are not Windows, we'll need to define these. */
+
+#if SIZEOF_SHORT == 2
+#define INT16 short
+#elif SIZEOF_INT == 2
+#define INT16 int
+#else
+#define INT16 short /* most things works just fine anyway... */
+#endif
+
+#if SIZEOF_SHORT == 4
+#define INT32 short
+#elif SIZEOF_INT == 4
+#define INT32 int
+#elif SIZEOF_LONG == 4
+#define INT32 long
+#else
+#error Cannot find required 32-bit integer type
+#endif
+
+#if SIZEOF_LONG == 8
+#define INT64 long
+#elif SIZEOF_LONG_LONG == 8
+#define INT64 long
+#endif
+
+#define INT8 signed char
+#define UINT8 unsigned char
+
+#define UINT16 unsigned INT16
+#define UINT32 unsigned INT32
+
+#endif
+
+/* assume IEEE; tweak if necessary (patches are welcome) */
+#define FLOAT16 UINT16
+#define FLOAT32 float
+#define FLOAT64 double
+
+#ifdef _MSC_VER
+typedef signed __int64 int64_t;
+#endif
+
+#ifdef __GNUC__
+ #define GCC_VERSION (__GNUC__ * 10000 \
+ + __GNUC_MINOR__ * 100 \
+ + __GNUC_PATCHLEVEL__)
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/Imaging.h b/contrib/python/Pillow/py2/libImaging/Imaging.h
new file mode 100644
index 0000000000..25c15e758c
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Imaging.h
@@ -0,0 +1,547 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * declarations for the imaging core library
+ *
+ * Copyright (c) 1997-2005 by Secret Labs AB
+ * Copyright (c) 1995-2005 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "ImPlatform.h"
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795
+#endif
+
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * Image data organization:
+ *
+ * mode bytes byte order
+ * -------------------------------
+ * 1 1 1
+ * L 1 L
+ * P 1 P
+ * I 4 I (32-bit integer, native byte order)
+ * F 4 F (32-bit IEEE float, native byte order)
+ * RGB 4 R, G, B, -
+ * RGBA 4 R, G, B, A
+ * CMYK 4 C, M, Y, K
+ * YCbCr 4 Y, Cb, Cr, -
+ * Lab 4 L, a, b, -
+ *
+ * experimental modes (incomplete):
+ * LA 4 L, -, -, A
+ * PA 4 P, -, -, A
+ * I;16 2 I (16-bit integer, native byte order)
+ *
+ * "P" is an 8-bit palette mode, which should be mapped through the
+ * palette member to get an output image. Check palette->mode to
+ * find the corresponding "real" mode.
+ *
+ * For information on how to access Imaging objects from your own C
+ * extensions, see http://www.effbot.org/zone/pil-extending.htm
+ */
+
+/* Handles */
+
+typedef struct ImagingMemoryInstance* Imaging;
+
+typedef struct ImagingAccessInstance* ImagingAccess;
+typedef struct ImagingHistogramInstance* ImagingHistogram;
+typedef struct ImagingOutlineInstance* ImagingOutline;
+typedef struct ImagingPaletteInstance* ImagingPalette;
+
+/* handle magics (used with PyCObject). */
+#define IMAGING_MAGIC "PIL Imaging"
+
+/* pixel types */
+#define IMAGING_TYPE_UINT8 0
+#define IMAGING_TYPE_INT32 1
+#define IMAGING_TYPE_FLOAT32 2
+#define IMAGING_TYPE_SPECIAL 3 /* check mode for details */
+
+#define IMAGING_MODE_LENGTH 6+1 /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */
+
+typedef struct {
+ char *ptr;
+ int size;
+} ImagingMemoryBlock;
+
+struct ImagingMemoryInstance {
+
+ /* Format */
+ char mode[IMAGING_MODE_LENGTH]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */
+ int type; /* Data type (IMAGING_TYPE_*) */
+ int depth; /* Depth (ignored in this version) */
+ int bands; /* Number of bands (1, 2, 3, or 4) */
+ int xsize; /* Image dimension. */
+ int ysize;
+
+ /* Colour palette (for "P" images only) */
+ ImagingPalette palette;
+
+ /* Data pointers */
+ UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */
+ INT32 **image32; /* Set for 32-bit images (pixelsize=4). */
+
+ /* Internals */
+ char **image; /* Actual raster data. */
+ char *block; /* Set if data is allocated in a single block. */
+ ImagingMemoryBlock *blocks; /* Memory blocks for pixel storage */
+
+ int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */
+ int linesize; /* Size of a line, in bytes (xsize * pixelsize) */
+
+ /* Virtual methods */
+ void (*destroy)(Imaging im);
+};
+
+
+#define IMAGING_PIXEL_1(im,x,y) ((im)->image8[(y)][(x)])
+#define IMAGING_PIXEL_L(im,x,y) ((im)->image8[(y)][(x)])
+#define IMAGING_PIXEL_LA(im,x,y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_P(im,x,y) ((im)->image8[(y)][(x)])
+#define IMAGING_PIXEL_PA(im,x,y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_I(im,x,y) ((im)->image32[(y)][(x)])
+#define IMAGING_PIXEL_F(im,x,y) (((FLOAT32*)(im)->image32[y])[x])
+#define IMAGING_PIXEL_RGB(im,x,y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_RGBA(im,x,y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_CMYK(im,x,y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_YCbCr(im,x,y) ((im)->image[(y)][(x)*4])
+
+#define IMAGING_PIXEL_UINT8(im,x,y) ((im)->image8[(y)][(x)])
+#define IMAGING_PIXEL_INT32(im,x,y) ((im)->image32[(y)][(x)])
+#define IMAGING_PIXEL_FLOAT32(im,x,y) (((FLOAT32*)(im)->image32[y])[x])
+
+struct ImagingAccessInstance {
+ const char* mode;
+ void* (*line)(Imaging im, int x, int y);
+ void (*get_pixel)(Imaging im, int x, int y, void* pixel);
+ void (*put_pixel)(Imaging im, int x, int y, const void* pixel);
+};
+
+struct ImagingHistogramInstance {
+
+ /* Format */
+ char mode[IMAGING_MODE_LENGTH]; /* Band names (of corresponding source image) */
+ int bands; /* Number of bands (1, 3, or 4) */
+
+ /* Data */
+ long *histogram; /* Histogram (bands*256 longs) */
+
+};
+
+
+struct ImagingPaletteInstance {
+
+ /* Format */
+ char mode[IMAGING_MODE_LENGTH]; /* Band names */
+
+ /* Data */
+ UINT8 palette[1024];/* Palette data (same format as image data) */
+
+ INT16* cache; /* Palette cache (used for predefined palettes) */
+ int keep_cache; /* This palette will be reused; keep cache */
+
+};
+
+typedef struct ImagingMemoryArena {
+ int alignment; /* Alignment in memory of each line of an image */
+ int block_size; /* Preferred block size, bytes */
+ int blocks_max; /* Maximum number of cached blocks */
+ int blocks_cached; /* Current number of blocks not associated with images */
+ ImagingMemoryBlock *blocks_pool;
+ int stats_new_count; /* Number of new allocated images */
+ int stats_allocated_blocks; /* Number of allocated blocks */
+ int stats_reused_blocks; /* Number of blocks which were retrieved from a pool */
+ int stats_reallocated_blocks; /* Number of blocks which were actually reallocated after retrieving */
+ int stats_freed_blocks; /* Number of freed blocks */
+} *ImagingMemoryArena;
+
+
+/* Objects */
+/* ------- */
+
+extern struct ImagingMemoryArena ImagingDefaultArena;
+extern int ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max);
+extern void ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size);
+
+extern Imaging ImagingNew(const char* mode, int xsize, int ysize);
+extern Imaging ImagingNewDirty(const char* mode, int xsize, int ysize);
+extern Imaging ImagingNew2Dirty(const char* mode, Imaging imOut, Imaging imIn);
+extern void ImagingDelete(Imaging im);
+
+extern Imaging ImagingNewBlock(const char* mode, int xsize, int ysize);
+extern Imaging ImagingNewMap(const char* filename, int readonly,
+ const char* mode, int xsize, int ysize);
+
+extern Imaging ImagingNewPrologue(const char *mode,
+ int xsize, int ysize);
+extern Imaging ImagingNewPrologueSubtype(const char *mode,
+ int xsize, int ysize,
+ int structure_size);
+
+extern void ImagingCopyPalette(Imaging destination, Imaging source);
+
+extern void ImagingHistogramDelete(ImagingHistogram histogram);
+
+extern void ImagingAccessInit(void);
+extern ImagingAccess ImagingAccessNew(Imaging im);
+extern void _ImagingAccessDelete(Imaging im, ImagingAccess access);
+#define ImagingAccessDelete(im, access) /* nop, for now */
+
+extern ImagingPalette ImagingPaletteNew(const char *mode);
+extern ImagingPalette ImagingPaletteNewBrowser(void);
+extern ImagingPalette ImagingPaletteDuplicate(ImagingPalette palette);
+extern void ImagingPaletteDelete(ImagingPalette palette);
+
+extern int ImagingPaletteCachePrepare(ImagingPalette palette);
+extern void ImagingPaletteCacheUpdate(ImagingPalette palette,
+ int r, int g, int b);
+extern void ImagingPaletteCacheDelete(ImagingPalette palette);
+
+#define ImagingPaletteCache(p, r, g, b)\
+ p->cache[(r>>2) + (g>>2)*64 + (b>>2)*64*64]
+
+extern Imaging ImagingQuantize(Imaging im, int colours, int mode, int kmeans);
+
+/* Threading */
+/* --------- */
+
+typedef void* ImagingSectionCookie;
+
+extern void ImagingSectionEnter(ImagingSectionCookie* cookie);
+extern void ImagingSectionLeave(ImagingSectionCookie* cookie);
+
+/* Exceptions */
+/* ---------- */
+
+extern void* ImagingError_IOError(void);
+extern void* ImagingError_MemoryError(void);
+extern void* ImagingError_ModeError(void); /* maps to ValueError by default */
+extern void* ImagingError_Mismatch(void); /* maps to ValueError by default */
+extern void* ImagingError_ValueError(const char* message);
+extern void ImagingError_Clear(void);
+
+/* Transform callbacks */
+/* ------------------- */
+
+/* standard transforms */
+#define IMAGING_TRANSFORM_AFFINE 0
+#define IMAGING_TRANSFORM_PERSPECTIVE 2
+#define IMAGING_TRANSFORM_QUAD 3
+
+
+/* standard filters */
+#define IMAGING_TRANSFORM_NEAREST 0
+#define IMAGING_TRANSFORM_BOX 4
+#define IMAGING_TRANSFORM_BILINEAR 2
+#define IMAGING_TRANSFORM_HAMMING 5
+#define IMAGING_TRANSFORM_BICUBIC 3
+#define IMAGING_TRANSFORM_LANCZOS 1
+
+typedef int (*ImagingTransformMap)(double* X, double* Y,
+ int x, int y, void* data);
+typedef int (*ImagingTransformFilter)(void* out, Imaging im,
+ double x, double y);
+
+/* Image Manipulation Methods */
+/* -------------------------- */
+
+extern Imaging ImagingAlphaComposite(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha);
+extern Imaging ImagingCopy(Imaging im);
+extern Imaging ImagingConvert(Imaging im, const char* mode, ImagingPalette palette, int dither);
+extern Imaging ImagingConvertInPlace(Imaging im, const char* mode);
+extern Imaging ImagingConvertMatrix(Imaging im, const char *mode, float m[]);
+extern Imaging ImagingConvertTransparent(Imaging im, const char *mode, int r, int g, int b);
+extern Imaging ImagingCrop(Imaging im, int x0, int y0, int x1, int y1);
+extern Imaging ImagingExpand(Imaging im, int x, int y, int mode);
+extern Imaging ImagingFill(Imaging im, const void* ink);
+extern int ImagingFill2(
+ Imaging into, const void* ink, Imaging mask,
+ int x0, int y0, int x1, int y1);
+extern Imaging ImagingFillBand(Imaging im, int band, int color);
+extern Imaging ImagingFillLinearGradient(const char* mode);
+extern Imaging ImagingFillRadialGradient(const char* mode);
+extern Imaging ImagingFilter(
+ Imaging im, int xsize, int ysize, const FLOAT32* kernel,
+ FLOAT32 offset);
+extern Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn);
+extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn);
+extern Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius,
+ int passes);
+extern Imaging ImagingGetBand(Imaging im, int band);
+extern Imaging ImagingMerge(const char* mode, Imaging bands[4]);
+extern int ImagingSplit(Imaging im, Imaging bands[4]);
+extern int ImagingGetBBox(Imaging im, int bbox[4]);
+typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem;
+extern ImagingColorItem* ImagingGetColors(Imaging im, int maxcolors,
+ int *colors);
+extern int ImagingGetExtrema(Imaging im, void *extrema);
+extern int ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj);
+extern ImagingHistogram ImagingGetHistogram(
+ Imaging im, Imaging mask, void *extrema);
+extern Imaging ImagingModeFilter(Imaging im, int size);
+extern Imaging ImagingNegative(Imaging im);
+extern Imaging ImagingOffset(Imaging im, int xoffset, int yoffset);
+extern int ImagingPaste(
+ Imaging into, Imaging im, Imaging mask,
+ int x0, int y0, int x1, int y1);
+extern Imaging ImagingPoint(
+ Imaging im, const char* tablemode, const void* table);
+extern Imaging ImagingPointTransform(
+ Imaging imIn, double scale, double offset);
+extern Imaging ImagingPutBand(Imaging im, Imaging imIn, int band);
+extern Imaging ImagingRankFilter(Imaging im, int size, int rank);
+extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn);
+extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn);
+extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn);
+extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn);
+extern Imaging ImagingTransverse(Imaging imOut, Imaging imIn);
+extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]);
+extern Imaging ImagingTransform(
+ Imaging imOut, Imaging imIn, int method, int x0, int y0, int x1, int y1,
+ double *a, int filter, int fill);
+extern Imaging ImagingUnsharpMask(
+ Imaging imOut, Imaging im, float radius, int percent, int threshold);
+extern Imaging ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n);
+extern Imaging ImagingColorLUT3D_linear(Imaging imOut, Imaging imIn,
+ int table_channels, int size1D, int size2D, int size3D, INT16* table);
+
+extern Imaging ImagingCopy2(Imaging imOut, Imaging imIn);
+extern Imaging ImagingConvert2(Imaging imOut, Imaging imIn);
+
+/* Channel operations */
+/* any mode, except "F" */
+extern Imaging ImagingChopLighter(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingChopDarker(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingChopDifference(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingChopMultiply(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingChopScreen(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingChopAdd(
+ Imaging imIn1, Imaging imIn2, float scale, int offset);
+extern Imaging ImagingChopSubtract(
+ Imaging imIn1, Imaging imIn2, float scale, int offset);
+extern Imaging ImagingChopAddModulo(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2);
+
+/* "1" images only */
+extern Imaging ImagingChopAnd(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingChopOr(Imaging imIn1, Imaging imIn2);
+extern Imaging ImagingChopXor(Imaging imIn1, Imaging imIn2);
+
+/* Image measurement */
+extern void ImagingCrack(Imaging im, int x0, int y0);
+
+/* Graphics */
+extern int ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1,
+ float start, float end, const void* ink, int width,
+ int op);
+extern int ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap,
+ const void* ink, int op);
+extern int ImagingDrawChord(Imaging im, int x0, int y0, int x1, int y1,
+ float start, float end, const void* ink, int fill,
+ int width, int op);
+extern int ImagingDrawEllipse(Imaging im, int x0, int y0, int x1, int y1,
+ const void* ink, int fill, int width, int op);
+extern int ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1,
+ const void* ink, int op);
+extern int ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
+ const void* ink, int width, int op);
+extern int ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1,
+ float start, float end, const void* ink, int fill,
+ int width, int op);
+extern int ImagingDrawPoint(Imaging im, int x, int y, const void* ink, int op);
+extern int ImagingDrawPolygon(Imaging im, int points, int *xy,
+ const void* ink, int fill, int op);
+extern int ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1,
+ const void* ink, int fill, int width, int op);
+
+/* Level 2 graphics (WORK IN PROGRESS) */
+extern ImagingOutline ImagingOutlineNew(void);
+extern void ImagingOutlineDelete(ImagingOutline outline);
+
+extern int ImagingDrawOutline(Imaging im, ImagingOutline outline,
+ const void* ink, int fill, int op);
+
+extern int ImagingOutlineMove(ImagingOutline outline, float x, float y);
+extern int ImagingOutlineLine(ImagingOutline outline, float x, float y);
+extern int ImagingOutlineCurve(ImagingOutline outline, float x1, float y1,
+ float x2, float y2, float x3, float y3);
+extern int ImagingOutlineTransform(ImagingOutline outline, double a[6]);
+
+extern int ImagingOutlineClose(ImagingOutline outline);
+
+/* Special effects */
+extern Imaging ImagingEffectSpread(Imaging imIn, int distance);
+extern Imaging ImagingEffectNoise(int xsize, int ysize, float sigma);
+extern Imaging ImagingEffectMandelbrot(int xsize, int ysize,
+ double extent[4], int quality);
+
+/* Obsolete */
+extern int ImagingToString(Imaging im, int orientation, char *buffer);
+extern int ImagingFromString(Imaging im, int orientation, char *buffer);
+
+
+/* File I/O */
+/* -------- */
+
+/* Built-in drivers */
+extern Imaging ImagingOpenPPM(const char* filename);
+extern int ImagingSavePPM(Imaging im, const char* filename);
+
+/* Utility functions */
+extern UINT32 ImagingCRC32(UINT32 crc, UINT8* buffer, int bytes);
+
+/* Codecs */
+typedef struct ImagingCodecStateInstance *ImagingCodecState;
+typedef int (*ImagingCodec)(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+
+extern int ImagingBcnDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingBitDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingEpsEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+extern int ImagingFliDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingGifDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingGifEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+extern int ImagingHexDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+#ifdef HAVE_LIBJPEG
+extern int ImagingJpegDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingJpegDecodeCleanup(ImagingCodecState state);
+extern int ImagingJpegUseJCSExtensions(void);
+
+extern int ImagingJpegEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+#endif
+#ifdef HAVE_OPENJPEG
+extern int ImagingJpeg2KDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingJpeg2KDecodeCleanup(ImagingCodecState state);
+extern int ImagingJpeg2KEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+extern int ImagingJpeg2KEncodeCleanup(ImagingCodecState state);
+#endif
+#ifdef HAVE_LIBTIFF
+extern int ImagingLibTiffDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingLibTiffEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+#endif
+#ifdef HAVE_LIBMPEG
+extern int ImagingMpegDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+#endif
+extern int ImagingMspDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingPackbitsDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingPcdDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingPcxDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingPcxEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+extern int ImagingRawDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingRawEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+extern int ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingSgiRleDecodeCleanup(ImagingCodecState state);
+extern int ImagingSunRleDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingTgaRleDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingTgaRleEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+extern int ImagingXbmDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingXbmEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+#ifdef HAVE_LIBZ
+extern int ImagingZipDecode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, Py_ssize_t bytes);
+extern int ImagingZipDecodeCleanup(ImagingCodecState state);
+extern int ImagingZipEncode(Imaging im, ImagingCodecState state,
+ UINT8* buffer, int bytes);
+extern int ImagingZipEncodeCleanup(ImagingCodecState state);
+#endif
+
+typedef void (*ImagingShuffler)(UINT8* out, const UINT8* in, int pixels);
+
+/* Public shufflers */
+extern void ImagingPackBGR(UINT8* out, const UINT8* in, int pixels);
+extern void ImagingUnpackYCC(UINT8* out, const UINT8* in, int pixels);
+extern void ImagingUnpackYCCA(UINT8* out, const UINT8* in, int pixels);
+
+extern void ImagingConvertRGB2YCbCr(UINT8* out, const UINT8* in, int pixels);
+extern void ImagingConvertYCbCr2RGB(UINT8* out, const UINT8* in, int pixels);
+
+extern ImagingShuffler ImagingFindUnpacker(const char* mode,
+ const char* rawmode, int* bits_out);
+extern ImagingShuffler ImagingFindPacker(const char* mode,
+ const char* rawmode, int* bits_out);
+
+struct ImagingCodecStateInstance {
+ int count;
+ int state;
+ int errcode;
+ int x, y;
+ int ystep;
+ int xsize, ysize, xoff, yoff;
+ ImagingShuffler shuffle;
+ int bits, bytes;
+ UINT8 *buffer;
+ void *context;
+ PyObject *fd;
+};
+
+
+
+/* Codec read/write python fd */
+extern Py_ssize_t _imaging_read_pyFd(PyObject *fd, char* dest, Py_ssize_t bytes);
+extern Py_ssize_t _imaging_write_pyFd(PyObject *fd, char* src, Py_ssize_t bytes);
+extern int _imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence);
+extern Py_ssize_t _imaging_tell_pyFd(PyObject *fd);
+
+
+
+/* Errcodes */
+#define IMAGING_CODEC_END 1
+#define IMAGING_CODEC_OVERRUN -1
+#define IMAGING_CODEC_BROKEN -2
+#define IMAGING_CODEC_UNKNOWN -3
+#define IMAGING_CODEC_CONFIG -8
+#define IMAGING_CODEC_MEMORY -9
+
+
+
+#include "ImagingUtils.h"
+extern UINT8 *clip8_lookups;
+
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/ImagingUtils.h b/contrib/python/Pillow/py2/libImaging/ImagingUtils.h
new file mode 100644
index 0000000000..21c2688d84
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/ImagingUtils.h
@@ -0,0 +1,47 @@
+#ifdef WORDS_BIGENDIAN
+ #define MAKE_UINT32(u0, u1, u2, u3) ((UINT32)(u3) | ((UINT32)(u2)<<8) | ((UINT32)(u1)<<16) | ((UINT32)(u0)<<24))
+ #define MASK_UINT32_CHANNEL_0 0xff000000
+ #define MASK_UINT32_CHANNEL_1 0x00ff0000
+ #define MASK_UINT32_CHANNEL_2 0x0000ff00
+ #define MASK_UINT32_CHANNEL_3 0x000000ff
+#else
+ #define MAKE_UINT32(u0, u1, u2, u3) ((UINT32)(u0) | ((UINT32)(u1)<<8) | ((UINT32)(u2)<<16) | ((UINT32)(u3)<<24))
+ #define MASK_UINT32_CHANNEL_0 0x000000ff
+ #define MASK_UINT32_CHANNEL_1 0x0000ff00
+ #define MASK_UINT32_CHANNEL_2 0x00ff0000
+ #define MASK_UINT32_CHANNEL_3 0xff000000
+#endif
+
+
+#define SHIFTFORDIV255(a)\
+ ((((a) >> 8) + a) >> 8)
+
+/* like (a * b + 127) / 255), but much faster on most platforms */
+#define MULDIV255(a, b, tmp)\
+ (tmp = (a) * (b) + 128, SHIFTFORDIV255(tmp))
+
+#define DIV255(a, tmp)\
+ (tmp = (a) + 128, SHIFTFORDIV255(tmp))
+
+#define BLEND(mask, in1, in2, tmp1)\
+ DIV255(in1 * (255 - mask) + in2 * mask, tmp1)
+
+#define PREBLEND(mask, in1, in2, tmp1)\
+ (MULDIV255(in1, (255 - mask), tmp1) + in2)
+
+
+#define CLIP8(v) ((v) <= 0 ? 0 : (v) < 256 ? (v) : 255)
+
+/* This is to work around a bug in GCC prior 4.9 in 64 bit mode.
+ GCC generates code with partial dependency which is 3 times slower.
+ See: http://stackoverflow.com/a/26588074/253146 */
+#if defined(__x86_64__) && defined(__SSE__) && ! defined(__NO_INLINE__) && \
+ ! defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900)
+static float __attribute__((always_inline)) inline _i2f(int v) {
+ float x;
+ __asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=x"(x) : "r"(v) );
+ return x;
+}
+#else
+static float inline _i2f(int v) { return (float) v; }
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/Jpeg.h b/contrib/python/Pillow/py2/libImaging/Jpeg.h
new file mode 100644
index 0000000000..82e1b449fe
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Jpeg.h
@@ -0,0 +1,116 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * declarations for the IJG JPEG codec interface.
+ *
+ * Copyright (c) 1995-2001 by Secret Labs AB
+ * Copyright (c) 1995-1996 by Fredrik Lundh
+ */
+
+#include "jpeglib.h"
+
+#include <setjmp.h>
+
+
+typedef struct {
+ struct jpeg_error_mgr pub; /* "public" fields */
+ jmp_buf setjmp_buffer; /* for return to caller */
+} JPEGERROR;
+
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+
+typedef struct {
+ struct jpeg_source_mgr pub;
+ int skip;
+} JPEGSOURCE;
+
+typedef struct {
+
+ /* CONFIGURATION */
+
+ /* Jpeg file mode (empty if not known) */
+ char jpegmode[8+1];
+
+ /* Converter output mode (input to the shuffler). If empty,
+ convert conversions are disabled */
+ char rawmode[8+1];
+
+ /* If set, trade quality for speed */
+ int draft;
+
+ /* Scale factor (1, 2, 4, 8) */
+ int scale;
+
+ /* PRIVATE CONTEXT (set by decoder) */
+
+ struct jpeg_decompress_struct cinfo;
+
+ JPEGERROR error;
+
+ JPEGSOURCE source;
+
+} JPEGSTATE;
+
+
+/* -------------------------------------------------------------------- */
+/* Encoder */
+
+typedef struct {
+ struct jpeg_destination_mgr pub;
+ /* might add something some other day */
+} JPEGDESTINATION;
+
+typedef struct {
+
+ /* CONFIGURATION */
+
+ /* Quality (1-100, 0 means default) */
+ int quality;
+
+ /* Progressive mode */
+ int progressive;
+
+ /* Smoothing factor (1-100, 0 means none) */
+ int smooth;
+
+ /* Optimize Huffman tables (slow) */
+ int optimize;
+
+ /* Stream type (0=full, 1=tables only, 2=image only) */
+ int streamtype;
+
+ /* DPI setting (0=square pixels, otherwise DPI) */
+ int xdpi, ydpi;
+
+ /* Chroma Subsampling (-1=default, 0=none, 1=medium, 2=high) */
+ int subsampling;
+
+ /* Converter input mode (input to the shuffler) */
+ char rawmode[8+1];
+
+ /* Custom quantization tables () */
+ unsigned int *qtables;
+
+ /* in factors of DCTSIZE2 */
+ int qtablesLen;
+
+ /* Extra data (to be injected after header) */
+ char* extra; int extra_size;
+
+ /* PRIVATE CONTEXT (set by encoder) */
+
+ struct jpeg_compress_struct cinfo;
+
+ JPEGERROR error;
+
+ JPEGDESTINATION destination;
+
+ int extra_offset;
+
+ int rawExifLen; /* EXIF data length */
+ char* rawExif; /* EXIF buffer pointer */
+
+} JPEGENCODERSTATE;
diff --git a/contrib/python/Pillow/py2/libImaging/Jpeg2K.h b/contrib/python/Pillow/py2/libImaging/Jpeg2K.h
new file mode 100644
index 0000000000..7bb14eb2c0
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Jpeg2K.h
@@ -0,0 +1,102 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * declarations for the OpenJPEG codec interface.
+ *
+ * Copyright (c) 2014 by Coriolis Systems Limited
+ * Copyright (c) 2014 by Alastair Houghton
+ */
+
+#include <openjpeg.h>
+
+/* 1MB for now */
+#define BUFFER_SIZE OPJ_J2K_STREAM_CHUNK_SIZE
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* File descriptor, if available; otherwise, -1 */
+ int fd;
+
+ /* File pointer, when opened */
+ FILE * pfile;
+
+ /* Length of data, if available; otherwise, -1 */
+ off_t length;
+
+ /* Specify the desired format */
+ OPJ_CODEC_FORMAT format;
+
+ /* Set to divide image resolution by 2**reduce. */
+ int reduce;
+
+ /* Set to limit the number of quality layers to decode (0 = all layers) */
+ int layers;
+
+ /* PRIVATE CONTEXT (set by decoder) */
+ const char *error_msg;
+
+} JPEG2KDECODESTATE;
+
+/* -------------------------------------------------------------------- */
+/* Encoder */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* File descriptor, if available; otherwise, -1 */
+ int fd;
+
+ /* File pointer, when opened */
+ FILE * pfile;
+
+ /* Specify the desired format */
+ OPJ_CODEC_FORMAT format;
+
+ /* Image offset */
+ int offset_x, offset_y;
+
+ /* Tile information */
+ int tile_offset_x, tile_offset_y;
+ int tile_size_x, tile_size_y;
+
+ /* Quality layers (a sequence of numbers giving *either* rates or dB) */
+ int quality_is_in_db;
+ PyObject *quality_layers;
+
+ /* Number of resolutions (DWT decompositions + 1 */
+ int num_resolutions;
+
+ /* Code block size */
+ int cblk_width, cblk_height;
+
+ /* Precinct size */
+ int precinct_width, precinct_height;
+
+ /* Compression style */
+ int irreversible;
+
+ /* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */
+ OPJ_PROG_ORDER progression;
+
+ /* Cinema mode */
+ OPJ_CINEMA_MODE cinema_mode;
+
+ /* PRIVATE CONTEXT (set by decoder) */
+ const char *error_msg;
+
+
+} JPEG2KENCODESTATE;
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End:
+ *
+ */
diff --git a/contrib/python/Pillow/py2/libImaging/Jpeg2KDecode.c b/contrib/python/Pillow/py2/libImaging/Jpeg2KDecode.c
new file mode 100644
index 0000000000..f2e437dda2
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Jpeg2KDecode.c
@@ -0,0 +1,828 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for JPEG2000 image data.
+ *
+ * history:
+ * 2014-03-12 ajh Created
+ *
+ * Copyright (c) 2014 Coriolis Systems Limited
+ * Copyright (c) 2014 Alastair Houghton
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_OPENJPEG
+
+#include <stdlib.h>
+#include "Jpeg2K.h"
+
+typedef struct {
+ OPJ_UINT32 tile_index;
+ OPJ_UINT32 data_size;
+ OPJ_INT32 x0, y0, x1, y1;
+ OPJ_UINT32 nb_comps;
+} JPEG2KTILEINFO;
+
+/* -------------------------------------------------------------------- */
+/* Error handler */
+/* -------------------------------------------------------------------- */
+
+static void
+j2k_error(const char *msg, void *client_data)
+{
+ JPEG2KDECODESTATE *state = (JPEG2KDECODESTATE *) client_data;
+ free((void *)state->error_msg);
+ state->error_msg = strdup(msg);
+}
+
+/* -------------------------------------------------------------------- */
+/* Buffer input stream */
+/* -------------------------------------------------------------------- */
+
+static OPJ_SIZE_T
+j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
+{
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+
+ size_t len = _imaging_read_pyFd(state->fd, p_buffer, p_nb_bytes);
+
+ return len ? len : (OPJ_SIZE_T)-1;
+}
+
+static OPJ_OFF_T
+j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
+{
+ off_t pos;
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+
+ _imaging_seek_pyFd(state->fd, p_nb_bytes, SEEK_CUR);
+ pos = _imaging_tell_pyFd(state->fd);
+
+ return pos ? pos : (OPJ_OFF_T)-1;
+}
+
+/* -------------------------------------------------------------------- */
+/* Unpackers */
+/* -------------------------------------------------------------------- */
+
+typedef void (*j2k_unpacker_t)(opj_image_t *in,
+ const JPEG2KTILEINFO *tileInfo,
+ const UINT8 *data,
+ Imaging im);
+
+struct j2k_decode_unpacker {
+ const char *mode;
+ OPJ_COLOR_SPACE color_space;
+ unsigned components;
+ j2k_unpacker_t unpacker;
+};
+
+static inline
+unsigned j2ku_shift(unsigned x, int n)
+{
+ if (n < 0)
+ return x >> -n;
+ else
+ return x << n;
+}
+
+static void
+j2ku_gray_l(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata, Imaging im)
+{
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shift = 8 - in->comps[0].prec;
+ int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
+ int csiz = (in->comps[0].prec + 7) >> 3;
+
+ unsigned x, y;
+
+ if (csiz == 3)
+ csiz = 4;
+
+ if (shift < 0)
+ offset += 1 << (-shift - 1);
+
+ switch (csiz) {
+ case 1:
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data = &tiledata[y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x)
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ break;
+ case 2:
+ for (y = 0; y < h; ++y) {
+ const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x)
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ break;
+ case 4:
+ for (y = 0; y < h; ++y) {
+ const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x)
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ break;
+ }
+}
+
+
+static void
+j2ku_gray_i(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata, Imaging im)
+{
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shift = 16 - in->comps[0].prec;
+ int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
+ int csiz = (in->comps[0].prec + 7) >> 3;
+
+ unsigned x, y;
+
+ if (csiz == 3)
+ csiz = 4;
+
+ if (shift < 0)
+ offset += 1 << (-shift - 1);
+
+ switch (csiz) {
+ case 1:
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data = &tiledata[y * w];
+ UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x)
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ break;
+ case 2:
+ for (y = 0; y < h; ++y) {
+ const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w];
+ UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x)
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ break;
+ case 4:
+ for (y = 0; y < h; ++y) {
+ const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w];
+ UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x)
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ break;
+ }
+}
+
+
+static void
+j2ku_gray_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata, Imaging im)
+{
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shift = 8 - in->comps[0].prec;
+ int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
+ int csiz = (in->comps[0].prec + 7) >> 3;
+
+ unsigned x, y;
+
+ if (shift < 0)
+ offset += 1 << (-shift - 1);
+
+ if (csiz == 3)
+ csiz = 4;
+
+ switch (csiz) {
+ case 1:
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data = &tiledata[y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ UINT8 byte = j2ku_shift(offset + *data++, shift);
+ row[0] = row[1] = row[2] = byte;
+ row[3] = 0xff;
+ row += 4;
+ }
+ }
+ break;
+ case 2:
+ for (y = 0; y < h; ++y) {
+ const UINT16 *data = (UINT16 *)&tiledata[2 * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ UINT8 byte = j2ku_shift(offset + *data++, shift);
+ row[0] = row[1] = row[2] = byte;
+ row[3] = 0xff;
+ row += 4;
+ }
+ }
+ break;
+ case 4:
+ for (y = 0; y < h; ++y) {
+ const UINT32 *data = (UINT32 *)&tiledata[4 * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ UINT8 byte = j2ku_shift(offset + *data++, shift);
+ row[0] = row[1] = row[2] = byte;
+ row[3] = 0xff;
+ row += 4;
+ }
+ }
+ break;
+ }
+}
+
+static void
+j2ku_graya_la(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata, Imaging im)
+{
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shift = 8 - in->comps[0].prec;
+ int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
+ int csiz = (in->comps[0].prec + 7) >> 3;
+ int ashift = 8 - in->comps[1].prec;
+ int aoffset = in->comps[1].sgnd ? 1 << (in->comps[1].prec - 1) : 0;
+ int acsiz = (in->comps[1].prec + 7) >> 3;
+ const UINT8 *atiledata;
+
+ unsigned x, y;
+
+ if (csiz == 3)
+ csiz = 4;
+ if (acsiz == 3)
+ acsiz = 4;
+
+ if (shift < 0)
+ offset += 1 << (-shift - 1);
+ if (ashift < 0)
+ aoffset += 1 << (-ashift - 1);
+
+ atiledata = tiledata + csiz * w * h;
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data = &tiledata[csiz * y * w];
+ const UINT8 *adata = &atiledata[acsiz * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ for (x = 0; x < w; ++x) {
+ UINT32 word = 0, aword = 0, byte;
+
+ switch (csiz) {
+ case 1: word = *data++; break;
+ case 2: word = *(const UINT16 *)data; data += 2; break;
+ case 4: word = *(const UINT32 *)data; data += 4; break;
+ }
+
+ switch (acsiz) {
+ case 1: aword = *adata++; break;
+ case 2: aword = *(const UINT16 *)adata; adata += 2; break;
+ case 4: aword = *(const UINT32 *)adata; adata += 4; break;
+ }
+
+ byte = j2ku_shift(offset + word, shift);
+ row[0] = row[1] = row[2] = byte;
+ row[3] = j2ku_shift(aoffset + aword, ashift);
+ row += 4;
+ }
+ }
+}
+
+static void
+j2ku_srgb_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata, Imaging im)
+{
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shifts[3], offsets[3], csiz[3];
+ const UINT8 *cdata[3];
+ const UINT8 *cptr = tiledata;
+ unsigned n, x, y;
+
+ for (n = 0; n < 3; ++n) {
+ cdata[n] = cptr;
+ shifts[n] = 8 - in->comps[n].prec;
+ offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
+ csiz[n] = (in->comps[n].prec + 7) >> 3;
+
+ if (csiz[n] == 3)
+ csiz[n] = 4;
+
+ if (shifts[n] < 0)
+ offsets[n] += 1 << (-shifts[n] - 1);
+
+ cptr += csiz[n] * w * h;
+ }
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data[3];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ for (n = 0; n < 3; ++n)
+ data[n] = &cdata[n][csiz[n] * y * w];
+
+ for (x = 0; x < w; ++x) {
+ for (n = 0; n < 3; ++n) {
+ UINT32 word = 0;
+
+ switch (csiz[n]) {
+ case 1: word = *data[n]++; break;
+ case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break;
+ case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break;
+ }
+
+ row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
+ }
+ row[3] = 0xff;
+ row += 4;
+ }
+ }
+}
+
+static void
+j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata, Imaging im)
+{
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shifts[3], offsets[3], csiz[3];
+ const UINT8 *cdata[3];
+ const UINT8 *cptr = tiledata;
+ unsigned n, x, y;
+
+ for (n = 0; n < 3; ++n) {
+ cdata[n] = cptr;
+ shifts[n] = 8 - in->comps[n].prec;
+ offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
+ csiz[n] = (in->comps[n].prec + 7) >> 3;
+
+ if (csiz[n] == 3)
+ csiz[n] = 4;
+
+ if (shifts[n] < 0)
+ offsets[n] += 1 << (-shifts[n] - 1);
+
+ cptr += csiz[n] * w * h;
+ }
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data[3];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ UINT8 *row_start = row;
+ for (n = 0; n < 3; ++n)
+ data[n] = &cdata[n][csiz[n] * y * w];
+
+ for (x = 0; x < w; ++x) {
+ for (n = 0; n < 3; ++n) {
+ UINT32 word = 0;
+
+ switch (csiz[n]) {
+ case 1: word = *data[n]++; break;
+ case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break;
+ case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break;
+ }
+
+ row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
+ }
+ row[3] = 0xff;
+ row += 4;
+ }
+
+ ImagingConvertYCbCr2RGB(row_start, row_start, w);
+ }
+}
+
+static void
+j2ku_srgba_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata, Imaging im)
+{
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shifts[4], offsets[4], csiz[4];
+ const UINT8 *cdata[4];
+ const UINT8 *cptr = tiledata;
+ unsigned n, x, y;
+
+ for (n = 0; n < 4; ++n) {
+ cdata[n] = cptr;
+ shifts[n] = 8 - in->comps[n].prec;
+ offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
+ csiz[n] = (in->comps[n].prec + 7) >> 3;
+
+ if (csiz[n] == 3)
+ csiz[n] = 4;
+
+ if (shifts[n] < 0)
+ offsets[n] += 1 << (-shifts[n] - 1);
+
+ cptr += csiz[n] * w * h;
+ }
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data[4];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ for (n = 0; n < 4; ++n)
+ data[n] = &cdata[n][csiz[n] * y * w];
+
+ for (x = 0; x < w; ++x) {
+ for (n = 0; n < 4; ++n) {
+ UINT32 word = 0;
+
+ switch (csiz[n]) {
+ case 1: word = *data[n]++; break;
+ case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break;
+ case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break;
+ }
+
+ row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
+ }
+ row += 4;
+ }
+ }
+}
+
+static void
+j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata, Imaging im)
+{
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shifts[4], offsets[4], csiz[4];
+ const UINT8 *cdata[4];
+ const UINT8 *cptr = tiledata;
+ unsigned n, x, y;
+
+ for (n = 0; n < 4; ++n) {
+ cdata[n] = cptr;
+ shifts[n] = 8 - in->comps[n].prec;
+ offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
+ csiz[n] = (in->comps[n].prec + 7) >> 3;
+
+ if (csiz[n] == 3)
+ csiz[n] = 4;
+
+ if (shifts[n] < 0)
+ offsets[n] += 1 << (-shifts[n] - 1);
+
+ cptr += csiz[n] * w * h;
+ }
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data[4];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ UINT8 *row_start = row;
+ for (n = 0; n < 4; ++n)
+ data[n] = &cdata[n][csiz[n] * y * w];
+
+ for (x = 0; x < w; ++x) {
+ for (n = 0; n < 4; ++n) {
+ UINT32 word = 0;
+
+ switch (csiz[n]) {
+ case 1: word = *data[n]++; break;
+ case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break;
+ case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break;
+ }
+
+ row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
+ }
+ row += 4;
+ }
+
+ ImagingConvertYCbCr2RGB(row_start, row_start, w);
+ }
+}
+
+static const struct j2k_decode_unpacker j2k_unpackers[] = {
+ { "L", OPJ_CLRSPC_GRAY, 1, j2ku_gray_l },
+ { "I;16", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i },
+ { "I;16B", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i },
+ { "LA", OPJ_CLRSPC_GRAY, 2, j2ku_graya_la },
+ { "RGB", OPJ_CLRSPC_GRAY, 1, j2ku_gray_rgb },
+ { "RGB", OPJ_CLRSPC_GRAY, 2, j2ku_gray_rgb },
+ { "RGB", OPJ_CLRSPC_SRGB, 3, j2ku_srgb_rgb },
+ { "RGB", OPJ_CLRSPC_SYCC, 3, j2ku_sycc_rgb },
+ { "RGB", OPJ_CLRSPC_SRGB, 4, j2ku_srgb_rgb },
+ { "RGB", OPJ_CLRSPC_SYCC, 4, j2ku_sycc_rgb },
+ { "RGBA", OPJ_CLRSPC_GRAY, 1, j2ku_gray_rgb },
+ { "RGBA", OPJ_CLRSPC_GRAY, 2, j2ku_graya_la },
+ { "RGBA", OPJ_CLRSPC_SRGB, 3, j2ku_srgb_rgb },
+ { "RGBA", OPJ_CLRSPC_SYCC, 3, j2ku_sycc_rgb },
+ { "RGBA", OPJ_CLRSPC_SRGB, 4, j2ku_srgba_rgba },
+ { "RGBA", OPJ_CLRSPC_SYCC, 4, j2ku_sycca_rgba },
+};
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+/* -------------------------------------------------------------------- */
+
+enum {
+ J2K_STATE_START = 0,
+ J2K_STATE_DECODING = 1,
+ J2K_STATE_DONE = 2,
+ J2K_STATE_FAILED = 3,
+};
+
+static int
+j2k_decode_entry(Imaging im, ImagingCodecState state)
+{
+ JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context;
+ opj_stream_t *stream = NULL;
+ opj_image_t *image = NULL;
+ opj_codec_t *codec = NULL;
+ opj_dparameters_t params;
+ OPJ_COLOR_SPACE color_space;
+ j2k_unpacker_t unpack = NULL;
+ size_t buffer_size = 0;
+ unsigned n;
+
+ stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE);
+
+ if (!stream) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ opj_stream_set_read_function(stream, j2k_read);
+ opj_stream_set_skip_function(stream, j2k_skip);
+
+ /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
+#ifndef OPJ_VERSION_MAJOR
+ opj_stream_set_user_data(stream, state);
+#else
+ opj_stream_set_user_data(stream, state, NULL);
+
+ /* Hack: if we don't know the length, the largest file we can
+ possibly support is 4GB. We can't go larger than this, because
+ OpenJPEG truncates this value for the final box in the file, and
+ the box lengths in OpenJPEG are currently 32 bit. */
+ if (context->length < 0)
+ opj_stream_set_user_data_length(stream, 0xffffffff);
+ else
+ opj_stream_set_user_data_length(stream, context->length);
+#endif
+
+ /* Setup decompression context */
+ context->error_msg = NULL;
+
+ opj_set_default_decoder_parameters(&params);
+ params.cp_reduce = context->reduce;
+ params.cp_layer = context->layers;
+
+ codec = opj_create_decompress(context->format);
+
+ if (!codec) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ opj_set_error_handler(codec, j2k_error, context);
+ opj_setup_decoder(codec, &params);
+
+ if (!opj_read_header(stream, codec, &image)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Check that this image is something we can handle */
+ if (image->numcomps < 1 || image->numcomps > 4
+ || image->color_space == OPJ_CLRSPC_UNKNOWN) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ for (n = 1; n < image->numcomps; ++n) {
+ if (image->comps[n].dx != 1 || image->comps[n].dy != 1) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+ }
+
+ /*
+ Colorspace Number of components PIL mode
+ ------------------------------------------------------
+ sRGB 3 RGB
+ sRGB 4 RGBA
+ gray 1 L or I
+ gray 2 LA
+ YCC 3 YCbCr
+
+
+ If colorspace is unspecified, we assume:
+
+ Number of components Colorspace
+ -----------------------------------------
+ 1 gray
+ 2 gray (+ alpha)
+ 3 sRGB
+ 4 sRGB (+ alpha)
+
+ */
+
+ /* Find the correct unpacker */
+ color_space = image->color_space;
+
+ if (color_space == OPJ_CLRSPC_UNSPECIFIED) {
+ switch (image->numcomps) {
+ case 1: case 2: color_space = OPJ_CLRSPC_GRAY; break;
+ case 3: case 4: color_space = OPJ_CLRSPC_SRGB; break;
+ }
+ }
+
+ for (n = 0; n < sizeof(j2k_unpackers) / sizeof (j2k_unpackers[0]); ++n) {
+ if (color_space == j2k_unpackers[n].color_space
+ && image->numcomps == j2k_unpackers[n].components
+ && strcmp (im->mode, j2k_unpackers[n].mode) == 0) {
+ unpack = j2k_unpackers[n].unpacker;
+ break;
+ }
+ }
+
+ if (!unpack) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Decode the image tile-by-tile; this means we only need use as much
+ memory as is required for one tile's worth of components. */
+ for (;;) {
+ JPEG2KTILEINFO tile_info;
+ OPJ_BOOL should_continue;
+ unsigned correction = (1 << params.cp_reduce) - 1;
+
+ if (!opj_read_tile_header(codec,
+ stream,
+ &tile_info.tile_index,
+ &tile_info.data_size,
+ &tile_info.x0, &tile_info.y0,
+ &tile_info.x1, &tile_info.y1,
+ &tile_info.nb_comps,
+ &should_continue)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ if (!should_continue)
+ break;
+
+ /* Adjust the tile co-ordinates based on the reduction (OpenJPEG
+ doesn't do this for us) */
+ tile_info.x0 = (tile_info.x0 + correction) >> context->reduce;
+ tile_info.y0 = (tile_info.y0 + correction) >> context->reduce;
+ tile_info.x1 = (tile_info.x1 + correction) >> context->reduce;
+ tile_info.y1 = (tile_info.y1 + correction) >> context->reduce;
+
+ if (buffer_size < tile_info.data_size) {
+ /* malloc check ok, tile_info.data_size from openjpeg */
+ UINT8 *new = realloc (state->buffer, tile_info.data_size);
+ if (!new) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+ state->buffer = new;
+ buffer_size = tile_info.data_size;
+ }
+
+ if (!opj_decode_tile_data(codec,
+ tile_info.tile_index,
+ (OPJ_BYTE *)state->buffer,
+ tile_info.data_size,
+ stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Check the tile bounds; if the tile is outside the image area,
+ or if it has a negative width or height (i.e. the coordinates are
+ swapped), bail. */
+ if (tile_info.x0 >= tile_info.x1
+ || tile_info.y0 >= tile_info.y1
+ || tile_info.x0 < image->x0
+ || tile_info.y0 < image->y0
+ || tile_info.x1 - image->x0 > im->xsize
+ || tile_info.y1 - image->y0 > im->ysize) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ unpack(image, &tile_info, state->buffer, im);
+ }
+
+ if (!opj_end_decompress(codec, stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ state->state = J2K_STATE_DONE;
+ state->errcode = IMAGING_CODEC_END;
+
+ if (context->pfile) {
+ if(fclose(context->pfile)){
+ context->pfile = NULL;
+ }
+ }
+
+ quick_exit:
+ if (codec)
+ opj_destroy_codec(codec);
+ if (image)
+ opj_image_destroy(image);
+ if (stream)
+ opj_stream_destroy(stream);
+
+ return -1;
+}
+
+int
+ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+
+ if (bytes){
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ return -1;
+ }
+
+ if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED)
+ return -1;
+
+ if (state->state == J2K_STATE_START) {
+ state->state = J2K_STATE_DECODING;
+
+ return j2k_decode_entry(im, state);
+ }
+
+ if (state->state == J2K_STATE_DECODING) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ return -1;
+ }
+ return -1;
+}
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpeg2KDecodeCleanup(ImagingCodecState state) {
+ JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *)state->context;
+
+ if (context->error_msg) {
+ free ((void *)context->error_msg);
+ }
+
+ context->error_msg = NULL;
+
+ return -1;
+}
+
+const char *
+ImagingJpeg2KVersion(void)
+{
+ return opj_version();
+}
+
+#endif /* HAVE_OPENJPEG */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End:
+ *
+ */
diff --git a/contrib/python/Pillow/py2/libImaging/Jpeg2KEncode.c b/contrib/python/Pillow/py2/libImaging/Jpeg2KEncode.c
new file mode 100644
index 0000000000..aef1a4b949
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Jpeg2KEncode.c
@@ -0,0 +1,630 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for JPEG2000 image data.
+ *
+ * history:
+ * 2014-03-12 ajh Created
+ *
+ * Copyright (c) 2014 Coriolis Systems Limited
+ * Copyright (c) 2014 Alastair Houghton
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_OPENJPEG
+
+#include "Jpeg2K.h"
+
+#define CINEMA_24_CS_LENGTH 1302083
+#define CINEMA_48_CS_LENGTH 651041
+#define COMP_24_CS_MAX_LENGTH 1041666
+#define COMP_48_CS_MAX_LENGTH 520833
+
+/* -------------------------------------------------------------------- */
+/* Error handler */
+/* -------------------------------------------------------------------- */
+
+static void
+j2k_error(const char *msg, void *client_data)
+{
+ JPEG2KENCODESTATE *state = (JPEG2KENCODESTATE *) client_data;
+ free((void *)state->error_msg);
+ state->error_msg = strdup(msg);
+}
+
+static void
+j2k_warn(const char *msg, void *client_data)
+{
+ // Null handler
+}
+
+/* -------------------------------------------------------------------- */
+/* Buffer output stream */
+/* -------------------------------------------------------------------- */
+
+static OPJ_SIZE_T
+j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
+{
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+ int result;
+
+ result = _imaging_write_pyFd(state->fd, p_buffer, p_nb_bytes);
+
+ return result ? result : (OPJ_SIZE_T)-1;
+}
+
+
+static OPJ_OFF_T
+j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
+{
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+ char *buffer;
+ int result;
+
+ /* Explicitly write zeros */
+ buffer = calloc(p_nb_bytes,1);
+ if (!buffer) {
+ return (OPJ_OFF_T)-1;
+ }
+
+ result = _imaging_write_pyFd(state->fd, buffer, p_nb_bytes);
+
+ free(buffer);
+
+ return result ? result : p_nb_bytes;
+}
+
+static OPJ_BOOL
+j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data)
+{
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+ off_t pos = 0;
+
+ _imaging_seek_pyFd(state->fd, p_nb_bytes, SEEK_SET);
+ pos = _imaging_tell_pyFd(state->fd);
+
+ return pos == p_nb_bytes;
+}
+
+/* -------------------------------------------------------------------- */
+/* Encoder */
+/* -------------------------------------------------------------------- */
+
+typedef void (*j2k_pack_tile_t)(Imaging im, UINT8 *buf,
+ unsigned x0, unsigned y0,
+ unsigned w, unsigned h);
+
+static void
+j2k_pack_l(Imaging im, UINT8 *buf,
+ unsigned x0, unsigned y0, unsigned w, unsigned h)
+{
+ UINT8 *ptr = buf;
+ unsigned x,y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + x0);
+ for (x = 0; x < w; ++x)
+ *ptr++ = *data++;
+ }
+}
+
+static void
+j2k_pack_i16(Imaging im, UINT8 *buf,
+ unsigned x0, unsigned y0, unsigned w, unsigned h)
+{
+ UINT8 *ptr = buf;
+ unsigned x,y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + x0);
+ for (x = 0; x < w; ++x) {
+ *ptr++ = *data++;
+ *ptr++ = *data++;
+ }
+ }
+}
+
+
+static void
+j2k_pack_la(Imaging im, UINT8 *buf,
+ unsigned x0, unsigned y0, unsigned w, unsigned h)
+{
+ UINT8 *ptr = buf;
+ UINT8 *ptra = buf + w * h;
+ unsigned x,y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
+ for (x = 0; x < w; ++x) {
+ *ptr++ = data[0];
+ *ptra++ = data[3];
+ data += 4;
+ }
+ }
+}
+
+static void
+j2k_pack_rgb(Imaging im, UINT8 *buf,
+ unsigned x0, unsigned y0, unsigned w, unsigned h)
+{
+ UINT8 *pr = buf;
+ UINT8 *pg = pr + w * h;
+ UINT8 *pb = pg + w * h;
+ unsigned x,y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
+ for (x = 0; x < w; ++x) {
+ *pr++ = data[0];
+ *pg++ = data[1];
+ *pb++ = data[2];
+ data += 4;
+ }
+ }
+}
+
+static void
+j2k_pack_rgba(Imaging im, UINT8 *buf,
+ unsigned x0, unsigned y0, unsigned w, unsigned h)
+{
+ UINT8 *pr = buf;
+ UINT8 *pg = pr + w * h;
+ UINT8 *pb = pg + w * h;
+ UINT8 *pa = pb + w * h;
+ unsigned x,y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
+ for (x = 0; x < w; ++x) {
+ *pr++ = *data++;
+ *pg++ = *data++;
+ *pb++ = *data++;
+ *pa++ = *data++;
+ }
+ }
+}
+
+enum {
+ J2K_STATE_START = 0,
+ J2K_STATE_ENCODING = 1,
+ J2K_STATE_DONE = 2,
+ J2K_STATE_FAILED = 3,
+};
+
+static void
+j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params)
+{
+ float rate;
+ int n;
+
+ /* These settings have been copied from opj_compress in the OpenJPEG
+ sources. */
+
+ params->tile_size_on = OPJ_FALSE;
+ params->cp_tdx = params->cp_tdy = 1;
+ params->tp_flag = 'C';
+ params->tp_on = 1;
+ params->cp_tx0 = params->cp_ty0 = 0;
+ params->image_offset_x0 = params->image_offset_y0 = 0;
+ params->cblockw_init = 32;
+ params->cblockh_init = 32;
+ params->csty |= 0x01;
+ params->prog_order = OPJ_CPRL;
+ params->roi_compno = -1;
+ params->subsampling_dx = params->subsampling_dy = 1;
+ params->irreversible = 1;
+
+ if (params->cp_cinema == OPJ_CINEMA4K_24) {
+ float max_rate = ((float)(components * im->xsize * im->ysize * 8)
+ / (CINEMA_24_CS_LENGTH * 8));
+
+ params->POC[0].tile = 1;
+ params->POC[0].resno0 = 0;
+ params->POC[0].compno0 = 0;
+ params->POC[0].layno1 = 1;
+ params->POC[0].resno1 = params->numresolution - 1;
+ params->POC[0].compno1 = 3;
+ params->POC[0].prg1 = OPJ_CPRL;
+ params->POC[1].tile = 1;
+ params->POC[1].resno0 = 0;
+ params->POC[1].compno0 = 0;
+ params->POC[1].layno1 = 1;
+ params->POC[1].resno1 = params->numresolution - 1;
+ params->POC[1].compno1 = 3;
+ params->POC[1].prg1 = OPJ_CPRL;
+ params->numpocs = 2;
+
+ for (n = 0; n < params->tcp_numlayers; ++n) {
+ rate = 0;
+ if (params->tcp_rates[0] == 0) {
+ params->tcp_rates[n] = max_rate;
+ } else {
+ rate = ((float)(components * im->xsize * im->ysize * 8)
+ / (params->tcp_rates[n] * 8));
+ if (rate > CINEMA_24_CS_LENGTH)
+ params->tcp_rates[n] = max_rate;
+ }
+ }
+
+ params->max_comp_size = COMP_24_CS_MAX_LENGTH;
+ } else {
+ float max_rate = ((float)(components * im->xsize * im->ysize * 8)
+ / (CINEMA_48_CS_LENGTH * 8));
+
+ for (n = 0; n < params->tcp_numlayers; ++n) {
+ rate = 0;
+ if (params->tcp_rates[0] == 0) {
+ params->tcp_rates[n] = max_rate;
+ } else {
+ rate = ((float)(components * im->xsize * im->ysize * 8)
+ / (params->tcp_rates[n] * 8));
+ if (rate > CINEMA_48_CS_LENGTH)
+ params->tcp_rates[n] = max_rate;
+ }
+ }
+
+ params->max_comp_size = COMP_48_CS_MAX_LENGTH;
+ }
+}
+
+static int
+j2k_encode_entry(Imaging im, ImagingCodecState state)
+{
+ JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
+ opj_stream_t *stream = NULL;
+ opj_image_t *image = NULL;
+ opj_codec_t *codec = NULL;
+ opj_cparameters_t params;
+ unsigned components;
+ OPJ_COLOR_SPACE color_space;
+ opj_image_cmptparm_t image_params[4];
+ unsigned xsiz, ysiz;
+ unsigned tile_width, tile_height;
+ unsigned tiles_x, tiles_y;
+ unsigned x, y, tile_ndx;
+ unsigned n;
+ j2k_pack_tile_t pack;
+ int ret = -1;
+
+ unsigned prec = 8;
+ unsigned bpp = 8;
+ unsigned _overflow_scale_factor;
+
+ stream = opj_stream_create(BUFFER_SIZE, OPJ_FALSE);
+
+ if (!stream) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ opj_stream_set_write_function(stream, j2k_write);
+ opj_stream_set_skip_function(stream, j2k_skip);
+ opj_stream_set_seek_function(stream, j2k_seek);
+
+ /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
+#ifndef OPJ_VERSION_MAJOR
+ opj_stream_set_user_data(stream, state);
+#else
+ opj_stream_set_user_data(stream, state, NULL);
+#endif
+
+ /* Setup an opj_image */
+ if (strcmp (im->mode, "L") == 0) {
+ components = 1;
+ color_space = OPJ_CLRSPC_GRAY;
+ pack = j2k_pack_l;
+ } else if (strcmp (im->mode, "I;16") == 0){
+ components = 1;
+ color_space = OPJ_CLRSPC_GRAY;
+ pack = j2k_pack_i16;
+ prec = 16;
+ bpp = 12;
+ } else if (strcmp (im->mode, "I;16B") == 0){
+ components = 1;
+ color_space = OPJ_CLRSPC_GRAY;
+ pack = j2k_pack_i16;
+ prec = 16;
+ bpp = 12;
+ } else if (strcmp (im->mode, "LA") == 0) {
+ components = 2;
+ color_space = OPJ_CLRSPC_GRAY;
+ pack = j2k_pack_la;
+ } else if (strcmp (im->mode, "RGB") == 0) {
+ components = 3;
+ color_space = OPJ_CLRSPC_SRGB;
+ pack = j2k_pack_rgb;
+ } else if (strcmp (im->mode, "YCbCr") == 0) {
+ components = 3;
+ color_space = OPJ_CLRSPC_SYCC;
+ pack = j2k_pack_rgb;
+ } else if (strcmp (im->mode, "RGBA") == 0) {
+ components = 4;
+ color_space = OPJ_CLRSPC_SRGB;
+ pack = j2k_pack_rgba;
+ } else {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ for (n = 0; n < components; ++n) {
+ image_params[n].dx = image_params[n].dy = 1;
+ image_params[n].w = im->xsize;
+ image_params[n].h = im->ysize;
+ image_params[n].x0 = image_params[n].y0 = 0;
+ image_params[n].prec = prec;
+ image_params[n].bpp = bpp;
+ image_params[n].sgnd = 0;
+ }
+
+ image = opj_image_create(components, image_params, color_space);
+ if (!image) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Setup compression context */
+ context->error_msg = NULL;
+
+ opj_set_default_encoder_parameters(&params);
+
+ params.image_offset_x0 = context->offset_x;
+ params.image_offset_y0 = context->offset_y;
+
+ if (context->tile_size_x && context->tile_size_y) {
+ params.tile_size_on = OPJ_TRUE;
+ params.cp_tx0 = context->tile_offset_x;
+ params.cp_ty0 = context->tile_offset_y;
+ params.cp_tdx = context->tile_size_x;
+ params.cp_tdy = context->tile_size_y;
+
+ tile_width = params.cp_tdx;
+ tile_height = params.cp_tdy;
+ } else {
+ params.cp_tx0 = 0;
+ params.cp_ty0 = 0;
+ params.cp_tdx = 1;
+ params.cp_tdy = 1;
+
+ tile_width = im->xsize;
+ tile_height = im->ysize;
+ }
+
+ if (context->quality_layers && PySequence_Check(context->quality_layers)) {
+ Py_ssize_t len = PySequence_Length(context->quality_layers);
+ Py_ssize_t n;
+ float *pq;
+
+ if (len) {
+ if (len > sizeof(params.tcp_rates) / sizeof(params.tcp_rates[0]))
+ len = sizeof(params.tcp_rates)/sizeof(params.tcp_rates[0]);
+
+ params.tcp_numlayers = (int)len;
+
+ if (context->quality_is_in_db) {
+ params.cp_disto_alloc = params.cp_fixed_alloc = 0;
+ params.cp_fixed_quality = 1;
+ pq = params.tcp_distoratio;
+ } else {
+ params.cp_disto_alloc = 1;
+ params.cp_fixed_alloc = params.cp_fixed_quality = 0;
+ pq = params.tcp_rates;
+ }
+
+ for (n = 0; n < len; ++n) {
+ PyObject *obj = PySequence_ITEM(context->quality_layers, n);
+ pq[n] = PyFloat_AsDouble(obj);
+ }
+ }
+ } else {
+ params.tcp_numlayers = 1;
+ params.tcp_rates[0] = 0;
+ params.cp_disto_alloc = 1;
+ }
+
+ if (context->num_resolutions)
+ params.numresolution = context->num_resolutions;
+
+ if (context->cblk_width >= 4 && context->cblk_width <= 1024
+ && context->cblk_height >= 4 && context->cblk_height <= 1024
+ && context->cblk_width * context->cblk_height <= 4096) {
+ params.cblockw_init = context->cblk_width;
+ params.cblockh_init = context->cblk_height;
+ }
+
+ if (context->precinct_width >= 4 && context->precinct_height >= 4
+ && context->precinct_width >= context->cblk_width
+ && context->precinct_height > context->cblk_height) {
+ params.prcw_init[0] = context->precinct_width;
+ params.prch_init[0] = context->precinct_height;
+ params.res_spec = 1;
+ params.csty |= 0x01;
+ }
+
+ params.irreversible = context->irreversible;
+
+ params.prog_order = context->progression;
+
+ params.cp_cinema = context->cinema_mode;
+
+ switch (params.cp_cinema) {
+ case OPJ_OFF:
+ params.cp_rsiz = OPJ_STD_RSIZ;
+ break;
+ case OPJ_CINEMA2K_24:
+ case OPJ_CINEMA2K_48:
+ params.cp_rsiz = OPJ_CINEMA2K;
+ if (params.numresolution > 6)
+ params.numresolution = 6;
+ break;
+ case OPJ_CINEMA4K_24:
+ params.cp_rsiz = OPJ_CINEMA4K;
+ if (params.numresolution > 7)
+ params.numresolution = 7;
+ break;
+ }
+
+ if (context->cinema_mode != OPJ_OFF)
+ j2k_set_cinema_params(im, components, &params);
+
+ /* Set up the reference grid in the image */
+ image->x0 = params.image_offset_x0;
+ image->y0 = params.image_offset_y0;
+ image->x1 = xsiz = im->xsize + params.image_offset_x0;
+ image->y1 = ysiz = im->ysize + params.image_offset_y0;
+
+ /* Create the compressor */
+ codec = opj_create_compress(context->format);
+
+ if (!codec) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ opj_set_error_handler(codec, j2k_error, context);
+ opj_set_info_handler(codec, j2k_warn, context);
+ opj_set_warning_handler(codec, j2k_warn, context);
+ opj_setup_encoder(codec, &params, image);
+
+ /* Start encoding */
+ if (!opj_start_compress(codec, image, stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Write each tile */
+ tiles_x = (im->xsize + (params.image_offset_x0 - params.cp_tx0)
+ + tile_width - 1) / tile_width;
+ tiles_y = (im->ysize + (params.image_offset_y0 - params.cp_ty0)
+ + tile_height - 1) / tile_height;
+
+ /* check for integer overflow for the malloc line, checking any expression
+ that may multiply either tile_width or tile_height */
+ _overflow_scale_factor = components * prec;
+ if (( tile_width > UINT_MAX / _overflow_scale_factor ) ||
+ ( tile_height > UINT_MAX / _overflow_scale_factor ) ||
+ ( tile_width > UINT_MAX / (tile_height * _overflow_scale_factor )) ||
+ ( tile_height > UINT_MAX / (tile_width * _overflow_scale_factor ))) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+ /* malloc check ok, checked for overflow above */
+ state->buffer = malloc (tile_width * tile_height * components * prec / 8);
+ if (!state->buffer) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ tile_ndx = 0;
+ for (y = 0; y < tiles_y; ++y) {
+ int ty0 = params.cp_ty0 + y * tile_height;
+ unsigned ty1 = ty0 + tile_height;
+ unsigned pixy, pixh;
+
+ if (ty0 < params.image_offset_y0)
+ ty0 = params.image_offset_y0;
+ if (ty1 > ysiz)
+ ty1 = ysiz;
+
+ pixy = ty0 - params.image_offset_y0;
+ pixh = ty1 - ty0;
+
+ for (x = 0; x < tiles_x; ++x) {
+ int tx0 = params.cp_tx0 + x * tile_width;
+ unsigned tx1 = tx0 + tile_width;
+ unsigned pixx, pixw;
+ unsigned data_size;
+
+ if (tx0 < params.image_offset_x0)
+ tx0 = params.image_offset_x0;
+ if (tx1 > xsiz)
+ tx1 = xsiz;
+
+ pixx = tx0 - params.image_offset_x0;
+ pixw = tx1 - tx0;
+
+ pack(im, state->buffer, pixx, pixy, pixw, pixh);
+
+ data_size = pixw * pixh * components * prec / 8;
+
+ if (!opj_write_tile(codec, tile_ndx++, state->buffer,
+ data_size, stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+ }
+ }
+
+ if (!opj_end_compress(codec, stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ state->errcode = IMAGING_CODEC_END;
+ state->state = J2K_STATE_DONE;
+ ret = -1;
+
+ quick_exit:
+ if (codec)
+ opj_destroy_codec(codec);
+ if (image)
+ opj_image_destroy(image);
+ if (stream)
+ opj_stream_destroy(stream);
+
+ return ret;
+}
+
+int
+ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes)
+{
+ if (state->state == J2K_STATE_FAILED)
+ return -1;
+
+ if (state->state == J2K_STATE_START) {
+
+ state->state = J2K_STATE_ENCODING;
+
+ return j2k_encode_entry(im, state);
+ }
+
+ return -1;
+}
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpeg2KEncodeCleanup(ImagingCodecState state) {
+ JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
+
+ if (context->quality_layers) {
+ Py_XDECREF(context->quality_layers);
+ context->quality_layers = NULL;
+ }
+
+ if (context->error_msg)
+ free ((void *)context->error_msg);
+
+ context->error_msg = NULL;
+
+
+ return -1;
+}
+
+#endif /* HAVE_OPENJPEG */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End:
+ *
+ */
diff --git a/contrib/python/Pillow/py2/libImaging/JpegDecode.c b/contrib/python/Pillow/py2/libImaging/JpegDecode.c
new file mode 100644
index 0000000000..39d96de531
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/JpegDecode.c
@@ -0,0 +1,315 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for JPEG image data.
+ *
+ * history:
+ * 1996-05-02 fl Created
+ * 1996-05-05 fl Handle small JPEG files correctly
+ * 1996-05-28 fl Added "draft mode" support
+ * 1997-01-25 fl Added colour conversion override
+ * 1998-01-31 fl Adapted to libjpeg 6a
+ * 1998-07-12 fl Extended YCbCr support
+ * 1998-12-29 fl Added new state to handle suspension in multipass modes
+ * 2000-10-12 fl Suppress warnings
+ * 2000-12-04 fl Suppress errors beyond end of image data
+ *
+ * Copyright (c) 1998-2000 Secret Labs AB
+ * Copyright (c) 1996-2000 Fredrik Lundh
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBJPEG
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_STDLIB_H
+#undef HAVE_STDDEF_H
+#undef UINT8
+#undef UINT16
+#undef UINT32
+#undef INT16
+#undef INT32
+
+#include "Jpeg.h"
+
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+// There is no way to compare versions on compile time,
+// so we have to do that in runtime.
+#ifdef LIBJPEG_TURBO_VERSION
+char *libjpeg_turbo_version = TOSTRING(LIBJPEG_TURBO_VERSION);
+#else
+char *libjpeg_turbo_version = NULL;
+#endif
+
+int
+ImagingJpegUseJCSExtensions()
+{
+ int use_jcs_extensions = 0;
+ #ifdef JCS_EXTENSIONS
+ #if defined(LIBJPEG_TURBO_VERSION_NUMBER)
+ #if LIBJPEG_TURBO_VERSION_NUMBER >= 1002010
+ use_jcs_extensions = 1;
+ #endif
+ #else
+ if (libjpeg_turbo_version) {
+ use_jcs_extensions = strcmp(libjpeg_turbo_version, "1.2.1") >= 0;
+ }
+ #endif
+ #endif
+ return use_jcs_extensions;
+}
+
+/* -------------------------------------------------------------------- */
+/* Suspending input handler */
+/* -------------------------------------------------------------------- */
+
+METHODDEF(void)
+stub(j_decompress_ptr cinfo)
+{
+ /* empty */
+}
+
+METHODDEF(boolean)
+fill_input_buffer(j_decompress_ptr cinfo)
+{
+ /* Suspension */
+ return FALSE;
+}
+
+METHODDEF(void)
+skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ JPEGSOURCE* source = (JPEGSOURCE*) cinfo->src;
+
+ if (num_bytes > (long) source->pub.bytes_in_buffer) {
+ /* We need to skip more data than we have in the buffer.
+ This will force the JPEG library to suspend decoding. */
+ source->skip = num_bytes - source->pub.bytes_in_buffer;
+ source->pub.next_input_byte += source->pub.bytes_in_buffer;
+ source->pub.bytes_in_buffer = 0;
+ } else {
+ /* Skip portion of the buffer */
+ source->pub.bytes_in_buffer -= num_bytes;
+ source->pub.next_input_byte += num_bytes;
+ source->skip = 0;
+ }
+}
+
+
+GLOBAL(void)
+jpeg_buffer_src(j_decompress_ptr cinfo, JPEGSOURCE* source)
+{
+ cinfo->src = (void*) source;
+
+ /* Prepare for suspending reader */
+ source->pub.init_source = stub;
+ source->pub.fill_input_buffer = fill_input_buffer;
+ source->pub.skip_input_data = skip_input_data;
+ source->pub.resync_to_restart = jpeg_resync_to_restart;
+ source->pub.term_source = stub;
+ source->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+
+ source->skip = 0;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Error handler */
+/* -------------------------------------------------------------------- */
+
+METHODDEF(void)
+error(j_common_ptr cinfo)
+{
+ JPEGERROR* error;
+ error = (JPEGERROR*) cinfo->err;
+ longjmp(error->setjmp_buffer, 1);
+}
+
+METHODDEF(void)
+output(j_common_ptr cinfo)
+{
+ /* nothing */
+}
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ JPEGSTATE* context = (JPEGSTATE*) state->context;
+ int ok;
+
+ if (setjmp(context->error.setjmp_buffer)) {
+ /* JPEG error handler */
+ jpeg_destroy_decompress(&context->cinfo);
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (!state->state) {
+
+ /* Setup decompression context */
+ context->cinfo.err = jpeg_std_error(&context->error.pub);
+ context->error.pub.error_exit = error;
+ context->error.pub.output_message = output;
+ jpeg_create_decompress(&context->cinfo);
+ jpeg_buffer_src(&context->cinfo, &context->source);
+
+ /* Ready to decode */
+ state->state = 1;
+
+ }
+
+ /* Load the source buffer */
+ context->source.pub.next_input_byte = buf;
+ context->source.pub.bytes_in_buffer = bytes;
+
+ if (context->source.skip > 0) {
+ skip_input_data(&context->cinfo, context->source.skip);
+ if (context->source.skip > 0)
+ return context->source.pub.next_input_byte - buf;
+ }
+
+ switch (state->state) {
+
+ case 1:
+
+ /* Read JPEG header, until we find an image body. */
+ do {
+
+ /* Note that we cannot return unless we have decoded
+ as much data as possible. */
+ ok = jpeg_read_header(&context->cinfo, FALSE);
+
+ } while (ok == JPEG_HEADER_TABLES_ONLY);
+
+ if (ok == JPEG_SUSPENDED)
+ break;
+
+ /* Decoder settings */
+
+ /* jpegmode indicates whats in the file; if not set, we'll
+ trust the decoder */
+ if (strcmp(context->jpegmode, "L") == 0)
+ context->cinfo.jpeg_color_space = JCS_GRAYSCALE;
+ else if (strcmp(context->jpegmode, "RGB") == 0)
+ context->cinfo.jpeg_color_space = JCS_RGB;
+ else if (strcmp(context->jpegmode, "CMYK") == 0)
+ context->cinfo.jpeg_color_space = JCS_CMYK;
+ else if (strcmp(context->jpegmode, "YCbCr") == 0)
+ context->cinfo.jpeg_color_space = JCS_YCbCr;
+ else if (strcmp(context->jpegmode, "YCbCrK") == 0) {
+ context->cinfo.jpeg_color_space = JCS_YCCK;
+ }
+
+ /* rawmode indicates what we want from the decoder. if not
+ set, conversions are disabled */
+ if (strcmp(context->rawmode, "L") == 0)
+ context->cinfo.out_color_space = JCS_GRAYSCALE;
+ else if (strcmp(context->rawmode, "RGB") == 0)
+ context->cinfo.out_color_space = JCS_RGB;
+ #ifdef JCS_EXTENSIONS
+ else if (strcmp(context->rawmode, "RGBX") == 0)
+ context->cinfo.out_color_space = JCS_EXT_RGBX;
+ #endif
+ else if (strcmp(context->rawmode, "CMYK") == 0 ||
+ strcmp(context->rawmode, "CMYK;I") == 0)
+ context->cinfo.out_color_space = JCS_CMYK;
+ else if (strcmp(context->rawmode, "YCbCr") == 0)
+ context->cinfo.out_color_space = JCS_YCbCr;
+ else if (strcmp(context->rawmode, "YCbCrK") == 0)
+ context->cinfo.out_color_space = JCS_YCCK;
+ else {
+ /* Disable decoder conversions */
+ context->cinfo.jpeg_color_space = JCS_UNKNOWN;
+ context->cinfo.out_color_space = JCS_UNKNOWN;
+ }
+
+ if (context->scale > 1) {
+ context->cinfo.scale_num = 1;
+ context->cinfo.scale_denom = context->scale;
+ }
+ if (context->draft) {
+ context->cinfo.do_fancy_upsampling = FALSE;
+ context->cinfo.dct_method = JDCT_FASTEST;
+ }
+
+ state->state++;
+ /* fall through */
+
+ case 2:
+
+ /* Set things up for decompression (this processes the entire
+ file if necessary to return data line by line) */
+ if (!jpeg_start_decompress(&context->cinfo))
+ break;
+
+ state->state++;
+ /* fall through */
+
+ case 3:
+
+ /* Decompress a single line of data */
+ ok = 1;
+ while (state->y < state->ysize) {
+ ok = jpeg_read_scanlines(&context->cinfo, &state->buffer, 1);
+ if (ok != 1)
+ break;
+ state->shuffle((UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->buffer,
+ state->xsize);
+ state->y++;
+ }
+ if (ok != 1)
+ break;
+ state->state++;
+ /* fall through */
+
+ case 4:
+
+ /* Finish decompression */
+ if (!jpeg_finish_decompress(&context->cinfo)) {
+ /* FIXME: add strictness mode test */
+ if (state->y < state->ysize)
+ break;
+ }
+
+ /* Clean up */
+ jpeg_destroy_decompress(&context->cinfo);
+ /* if (jerr.pub.num_warnings) return BROKEN; */
+ return -1;
+
+ }
+
+ /* Return number of bytes consumed */
+ return context->source.pub.next_input_byte - buf;
+
+}
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+
+int ImagingJpegDecodeCleanup(ImagingCodecState state){
+ /* called to free the decompression engine when the decode terminates
+ due to a corrupt or truncated image
+ */
+ JPEGSTATE* context = (JPEGSTATE*) state->context;
+
+ /* Clean up */
+ jpeg_destroy_decompress(&context->cinfo);
+ return -1;
+}
+
+#endif
+
diff --git a/contrib/python/Pillow/py2/libImaging/JpegEncode.c b/contrib/python/Pillow/py2/libImaging/JpegEncode.c
new file mode 100644
index 0000000000..10ad886e04
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/JpegEncode.c
@@ -0,0 +1,340 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * coder for JPEG data
+ *
+ * history:
+ * 1996-05-06 fl created
+ * 1996-07-16 fl don't drop last block of encoded data
+ * 1996-12-30 fl added quality and progressive settings
+ * 1997-01-08 fl added streamtype settings
+ * 1998-01-31 fl adapted to libjpeg 6a
+ * 1998-07-12 fl added YCbCr support
+ * 2001-04-16 fl added DPI write support
+ *
+ * Copyright (c) 1997-2001 by Secret Labs AB
+ * Copyright (c) 1995-1997 by Fredrik Lundh
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBJPEG
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_STDLIB_H
+#undef HAVE_STDDEF_H
+#undef UINT8
+#undef UINT16
+#undef UINT32
+#undef INT16
+#undef INT32
+
+#include "Jpeg.h"
+
+/* -------------------------------------------------------------------- */
+/* Suspending output handler */
+/* -------------------------------------------------------------------- */
+
+METHODDEF(void)
+stub(j_compress_ptr cinfo)
+{
+ /* empty */
+}
+
+METHODDEF(boolean)
+empty_output_buffer (j_compress_ptr cinfo)
+{
+ /* Suspension */
+ return FALSE;
+}
+
+GLOBAL(void)
+jpeg_buffer_dest(j_compress_ptr cinfo, JPEGDESTINATION* destination)
+{
+ cinfo->dest = (void*) destination;
+
+ destination->pub.init_destination = stub;
+ destination->pub.empty_output_buffer = empty_output_buffer;
+ destination->pub.term_destination = stub;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Error handler */
+/* -------------------------------------------------------------------- */
+
+METHODDEF(void)
+error(j_common_ptr cinfo)
+{
+ JPEGERROR* error;
+ error = (JPEGERROR*) cinfo->err;
+ (*cinfo->err->output_message) (cinfo);
+ longjmp(error->setjmp_buffer, 1);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Encoder */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
+{
+ JPEGENCODERSTATE* context = (JPEGENCODERSTATE*) state->context;
+ int ok;
+
+ if (setjmp(context->error.setjmp_buffer)) {
+ /* JPEG error handler */
+ jpeg_destroy_compress(&context->cinfo);
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (!state->state) {
+
+ /* Setup compression context (very similar to the decoder) */
+ context->cinfo.err = jpeg_std_error(&context->error.pub);
+ context->error.pub.error_exit = error;
+ jpeg_create_compress(&context->cinfo);
+ jpeg_buffer_dest(&context->cinfo, &context->destination);
+
+ context->extra_offset = 0;
+
+ /* Ready to encode */
+ state->state = 1;
+
+ }
+
+ /* Load the destination buffer */
+ context->destination.pub.next_output_byte = buf;
+ context->destination.pub.free_in_buffer = bytes;
+
+ switch (state->state) {
+
+ case 1:
+
+ context->cinfo.image_width = state->xsize;
+ context->cinfo.image_height = state->ysize;
+
+ switch (state->bits) {
+ case 8:
+ context->cinfo.input_components = 1;
+ context->cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+ case 24:
+ context->cinfo.input_components = 3;
+ if (strcmp(im->mode, "YCbCr") == 0)
+ context->cinfo.in_color_space = JCS_YCbCr;
+ else
+ context->cinfo.in_color_space = JCS_RGB;
+ break;
+ case 32:
+ context->cinfo.input_components = 4;
+ context->cinfo.in_color_space = JCS_CMYK;
+ #ifdef JCS_EXTENSIONS
+ if (strcmp(context->rawmode, "RGBX") == 0)
+ context->cinfo.in_color_space = JCS_EXT_RGBX;
+ #endif
+ break;
+ default:
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ /* Compressor configuration */
+ jpeg_set_defaults(&context->cinfo);
+
+ /* Use custom quantization tables */
+ if (context->qtables) {
+ int i;
+ int quality = 100;
+ int last_q = 0;
+ if (context->quality > 0) {
+ quality = context->quality;
+ }
+ for (i = 0; i < context->qtablesLen; i++) {
+ // TODO: Should add support for none baseline
+ jpeg_add_quant_table(&context->cinfo, i, &context->qtables[i * DCTSIZE2],
+ quality, TRUE);
+ context->cinfo.comp_info[i].quant_tbl_no = i;
+ last_q = i;
+ }
+ if (context->qtablesLen == 1) {
+ // jpeg_set_defaults created two qtables internally, but we only wanted one.
+ jpeg_add_quant_table(&context->cinfo, 1, &context->qtables[0],
+ quality, TRUE);
+ }
+ for (i = last_q; i < context->cinfo.num_components; i++) {
+ context->cinfo.comp_info[i].quant_tbl_no = last_q;
+ }
+ } else if (context->quality > 0) {
+ jpeg_set_quality(&context->cinfo, context->quality, 1);
+ }
+
+ /* Set subsampling options */
+ switch (context->subsampling)
+ {
+ case 0: /* 1x1 1x1 1x1 (4:4:4) : None */
+ {
+ context->cinfo.comp_info[0].h_samp_factor = 1;
+ context->cinfo.comp_info[0].v_samp_factor = 1;
+ context->cinfo.comp_info[1].h_samp_factor = 1;
+ context->cinfo.comp_info[1].v_samp_factor = 1;
+ context->cinfo.comp_info[2].h_samp_factor = 1;
+ context->cinfo.comp_info[2].v_samp_factor = 1;
+ break;
+ }
+ case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */
+ {
+ context->cinfo.comp_info[0].h_samp_factor = 2;
+ context->cinfo.comp_info[0].v_samp_factor = 1;
+ context->cinfo.comp_info[1].h_samp_factor = 1;
+ context->cinfo.comp_info[1].v_samp_factor = 1;
+ context->cinfo.comp_info[2].h_samp_factor = 1;
+ context->cinfo.comp_info[2].v_samp_factor = 1;
+ break;
+ }
+ case 2: /* 2x2, 1x1, 1x1 (4:2:0) : High */
+ {
+ context->cinfo.comp_info[0].h_samp_factor = 2;
+ context->cinfo.comp_info[0].v_samp_factor = 2;
+ context->cinfo.comp_info[1].h_samp_factor = 1;
+ context->cinfo.comp_info[1].v_samp_factor = 1;
+ context->cinfo.comp_info[2].h_samp_factor = 1;
+ context->cinfo.comp_info[2].v_samp_factor = 1;
+ break;
+ }
+ default:
+ {
+ /* Use the lib's default */
+ break;
+ }
+ }
+ if (context->progressive)
+ jpeg_simple_progression(&context->cinfo);
+ context->cinfo.smoothing_factor = context->smooth;
+ context->cinfo.optimize_coding = (boolean) context->optimize;
+ if (context->xdpi > 0 && context->ydpi > 0) {
+ context->cinfo.density_unit = 1; /* dots per inch */
+ context->cinfo.X_density = context->xdpi;
+ context->cinfo.Y_density = context->ydpi;
+ }
+ switch (context->streamtype) {
+ case 1:
+ /* tables only -- not yet implemented */
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ case 2:
+ /* image only */
+ jpeg_suppress_tables(&context->cinfo, TRUE);
+ jpeg_start_compress(&context->cinfo, FALSE);
+ /* suppress extra section */
+ context->extra_offset = context->extra_size;
+ break;
+ default:
+ /* interchange stream */
+ jpeg_start_compress(&context->cinfo, TRUE);
+ break;
+ }
+ state->state++;
+ /* fall through */
+
+ case 2:
+ // check for exif len + 'APP1' header bytes
+ if (context->rawExifLen + 5 > context->destination.pub.free_in_buffer){
+ break;
+ }
+ //add exif header
+ if (context->rawExifLen > 0){
+ jpeg_write_marker(&context->cinfo, JPEG_APP0+1,
+ (unsigned char*)context->rawExif, context->rawExifLen);
+ }
+
+ state->state++;
+ /* fall through */
+ case 3:
+
+ if (context->extra) {
+ /* copy extra buffer to output buffer */
+ unsigned int n = context->extra_size - context->extra_offset;
+ if (n > context->destination.pub.free_in_buffer)
+ n = context->destination.pub.free_in_buffer;
+ memcpy(context->destination.pub.next_output_byte,
+ context->extra + context->extra_offset, n);
+ context->destination.pub.next_output_byte += n;
+ context->destination.pub.free_in_buffer -= n;
+ context->extra_offset += n;
+ if (context->extra_offset >= context->extra_size)
+ state->state++;
+ else
+ break;
+ } else
+ state->state++;
+
+ case 4:
+ if (1024 > context->destination.pub.free_in_buffer){
+ break;
+ }
+
+ ok = 1;
+ while (state->y < state->ysize) {
+ state->shuffle(state->buffer,
+ (UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->xsize);
+ ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1);
+ if (ok != 1)
+ break;
+ state->y++;
+ }
+
+ if (ok != 1)
+ break;
+ state->state++;
+ /* fall through */
+
+ case 5:
+
+ /* Finish compression */
+ if (context->destination.pub.free_in_buffer < 100)
+ break;
+ jpeg_finish_compress(&context->cinfo);
+
+ /* Clean up */
+ if (context->extra) {
+ free(context->extra);
+ context->extra = NULL;
+ }
+ if (context->rawExif) {
+ free(context->rawExif);
+ context->rawExif = NULL;
+ }
+ if (context->qtables) {
+ free(context->qtables);
+ context->qtables = NULL;
+ }
+
+ jpeg_destroy_compress(&context->cinfo);
+ /* if (jerr.pub.num_warnings) return BROKEN; */
+ state->errcode = IMAGING_CODEC_END;
+ break;
+
+ }
+
+ /* Return number of bytes in output buffer */
+ return context->destination.pub.next_output_byte - buf;
+
+}
+
+const char*
+ImagingJpegVersion(void)
+{
+ static char version[20];
+ sprintf(version, "%d.%d", JPEG_LIB_VERSION / 10, JPEG_LIB_VERSION % 10);
+ return version;
+}
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/Matrix.c b/contrib/python/Pillow/py2/libImaging/Matrix.c
new file mode 100644
index 0000000000..5cc7795a4b
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Matrix.c
@@ -0,0 +1,74 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * colour and luminance matrix transforms
+ *
+ * history:
+ * 1996-05-18 fl: created (brute force implementation)
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+#define CLIPF(v) ((v <= 0.0) ? 0 : (v >= 255.0F) ? 255 : (UINT8) v)
+
+
+Imaging
+ImagingConvertMatrix(Imaging im, const char *mode, float m[])
+{
+ Imaging imOut;
+ int x, y;
+
+ /* Assume there's enough data in the buffer */
+ if (!im)
+ return (Imaging) ImagingError_ModeError();
+
+ if (strcmp(mode, "L") == 0 && im->bands == 3) {
+
+ imOut = ImagingNewDirty("L", im->xsize, im->ysize);
+ if (!imOut)
+ return NULL;
+
+ for (y = 0; y < im->ysize; y++) {
+ UINT8* in = (UINT8*) im->image[y];
+ UINT8* out = (UINT8*) imOut->image[y];
+
+ for (x = 0; x < im->xsize; x++) {
+ float v = m[0]*in[0] + m[1]*in[1] + m[2]*in[2] + m[3] + 0.5;
+ out[x] = CLIPF(v);
+ in += 4;
+ }
+ }
+
+ } else if (strlen(mode) == 3 && im->bands == 3) {
+
+ imOut = ImagingNewDirty(mode, im->xsize, im->ysize);
+ if (!imOut)
+ return NULL;
+
+ for (y = 0; y < im->ysize; y++) {
+ UINT8* in = (UINT8*) im->image[y];
+ UINT8* out = (UINT8*) imOut->image[y];
+
+ for (x = 0; x < im->xsize; x++) {
+ float v0 = m[0]*in[0] + m[1]*in[1] + m[2]*in[2] + m[3] + 0.5;
+ float v1 = m[4]*in[0] + m[5]*in[1] + m[6]*in[2] + m[7] + 0.5;
+ float v2 = m[8]*in[0] + m[9]*in[1] + m[10]*in[2] + m[11] + 0.5;
+ out[0] = CLIPF(v0);
+ out[1] = CLIPF(v1);
+ out[2] = CLIPF(v2);
+ in += 4; out += 4;
+ }
+ }
+ } else
+ return (Imaging) ImagingError_ModeError();
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/ModeFilter.c b/contrib/python/Pillow/py2/libImaging/ModeFilter.c
new file mode 100644
index 0000000000..5237d07328
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/ModeFilter.c
@@ -0,0 +1,78 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * mode filter
+ *
+ * history:
+ * 2002-06-08 fl Created (based on code from IFUNC95)
+ * 2004-10-05 fl Rewritten; use a simpler brute-force algorithm
+ *
+ * Copyright (c) Secret Labs AB 2002-2004. All rights reserved.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+Imaging
+ImagingModeFilter(Imaging im, int size)
+{
+ Imaging imOut;
+ int x, y, i;
+ int xx, yy;
+ int maxcount;
+ UINT8 maxpixel;
+ int histogram[256];
+
+ if (!im || im->bands != 1 || im->type != IMAGING_TYPE_UINT8)
+ return (Imaging) ImagingError_ModeError();
+
+ imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
+ if (!imOut)
+ return NULL;
+
+ size = size / 2;
+
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8* out = &IMAGING_PIXEL_L(imOut, 0, y);
+ for (x = 0; x < imOut->xsize; x++) {
+
+ /* calculate histogram over current area */
+
+ /* FIXME: brute force! to improve, update the histogram
+ incrementally. may also add a "frequent list", like in
+ the old implementation, but I'm not sure that's worth
+ the added complexity... */
+
+ memset(histogram, 0, sizeof(histogram));
+ for (yy = y - size; yy <= y + size; yy++)
+ if (yy >= 0 && yy < imOut->ysize) {
+ UINT8* in = &IMAGING_PIXEL_L(im, 0, yy);
+ for (xx = x - size; xx <= x + size; xx++)
+ if (xx >= 0 && xx < imOut->xsize)
+ histogram[in[xx]]++;
+ }
+
+ /* find most frequent pixel value in this region */
+ maxpixel = 0;
+ maxcount = histogram[maxpixel];
+ for (i = 1; i < 256; i++)
+ if (histogram[i] > maxcount) {
+ maxcount = histogram[i];
+ maxpixel = (UINT8) i;
+ }
+
+ if (maxcount > 2)
+ out[x] = maxpixel;
+ else
+ out[x] = IMAGING_PIXEL_L(im, x, y);
+
+ }
+
+ }
+
+ ImagingCopyPalette(imOut, im);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Negative.c b/contrib/python/Pillow/py2/libImaging/Negative.c
new file mode 100644
index 0000000000..4dedcb2451
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Negative.c
@@ -0,0 +1,42 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * negate image
+ *
+ * to do:
+ * FIXME: Maybe this should be implemented using ImagingPoint()
+ *
+ * history:
+ * 95-11-27 fl: Created
+ *
+ * Copyright (c) Fredrik Lundh 1995.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+Imaging
+ImagingNegative(Imaging im)
+{
+ Imaging imOut;
+ int x, y;
+
+ if (!im)
+ return (Imaging) ImagingError_ModeError();
+
+ imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
+ if (!imOut)
+ return NULL;
+
+ for (y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->linesize; x++)
+ imOut->image[y][x] = ~im->image[y][x];
+
+ return imOut;
+}
+
diff --git a/contrib/python/Pillow/py2/libImaging/Offset.c b/contrib/python/Pillow/py2/libImaging/Offset.c
new file mode 100644
index 0000000000..b3d9425fb6
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Offset.c
@@ -0,0 +1,61 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * offset an image in x and y directions
+ *
+ * history:
+ * 96-07-22 fl: Created
+ * 98-11-01 cgw@pgt.com: Fixed negative-array index bug
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+Imaging
+ImagingOffset(Imaging im, int xoffset, int yoffset)
+{
+ int x, y;
+ Imaging imOut;
+
+ if (!im)
+ return (Imaging) ImagingError_ModeError();
+
+ imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
+ if (!imOut)
+ return NULL;
+
+ ImagingCopyPalette(imOut, im);
+
+ /* make offsets positive to avoid negative coordinates */
+ xoffset %= im->xsize;
+ xoffset = im->xsize - xoffset;
+ if (xoffset < 0)
+ xoffset += im->xsize;
+
+ yoffset %= im->ysize;
+ yoffset = im->ysize - yoffset;
+ if (yoffset < 0)
+ yoffset += im->ysize;
+
+#define OFFSET(image)\
+ for (y = 0; y < im->ysize; y++)\
+ for (x = 0; x < im->xsize; x++) {\
+ int yi = (y + yoffset) % im->ysize;\
+ int xi = (x + xoffset) % im->xsize;\
+ imOut->image[y][x] = im->image[yi][xi];\
+ }
+
+ if (im->image8)
+ OFFSET(image8)
+ else
+ OFFSET(image32)
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Pack.c b/contrib/python/Pillow/py2/libImaging/Pack.c
new file mode 100644
index 0000000000..eaa276af44
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Pack.c
@@ -0,0 +1,681 @@
+ /*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * code to pack raw data
+ *
+ * history:
+ * 1996-04-30 fl Created
+ * 1996-05-12 fl Published a few RGB packers
+ * 1996-11-01 fl More RGB packers (Tk booster stuff)
+ * 1996-12-30 fl Added P;1, P;2 and P;4 packers
+ * 1997-06-02 fl Added F (F;32NF) packer
+ * 1997-08-28 fl Added 1 as L packer
+ * 1998-02-08 fl Added I packer
+ * 1998-03-09 fl Added mode field, RGBA/RGBX as RGB packers
+ * 1998-07-01 fl Added YCbCr support
+ * 1998-07-12 fl Added I 16 packer
+ * 1999-02-03 fl Added BGR packers
+ * 2003-09-26 fl Added LA/PA packers
+ * 2006-06-22 fl Added CMYK;I packer
+ *
+ * Copyright (c) 1997-2006 by Secret Labs AB.
+ * Copyright (c) 1996-1997 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define X 3
+#define A 3
+
+#define C 0
+#define M 1
+#define Y 2
+#define K 3
+
+/* byte swapping macros */
+
+#define C16N\
+ (out[0]=tmp[0], out[1]=tmp[1]);
+#define C16S\
+ (out[1]=tmp[0], out[0]=tmp[1]);
+#define C32N\
+ (out[0]=tmp[0], out[1]=tmp[1], out[2]=tmp[2], out[3]=tmp[3]);
+#define C32S\
+ (out[3]=tmp[0], out[2]=tmp[1], out[1]=tmp[2], out[0]=tmp[3]);
+#define C64N\
+ (out[0]=tmp[0], out[1]=tmp[1], out[2]=tmp[2], out[3]=tmp[3],\
+ out[4]=tmp[4], out[5]=tmp[5], out[6]=tmp[6], out[7]=tmp[7]);
+#define C64S\
+ (out[7]=tmp[0], out[6]=tmp[1], out[5]=tmp[2], out[4]=tmp[3],\
+ out[3]=tmp[4], out[2]=tmp[5], out[1]=tmp[6], out[0]=tmp[7]);
+
+#ifdef WORDS_BIGENDIAN
+#define C16B C16N
+#define C16L C16S
+#define C32B C32N
+#define C32L C32S
+#define C64B C64N
+#define C64L C64S
+#else
+#define C16B C16S
+#define C16L C16N
+#define C32B C32S
+#define C32L C32N
+#define C64B C64S
+#define C64L C64N
+#endif
+
+
+static void
+pack1(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, m, b;
+ /* bilevel (black is 0) */
+ b = 0; m = 128;
+ for (i = 0; i < pixels; i++) {
+ if (in[i] != 0)
+ b |= m;
+ m >>= 1;
+ if (m == 0) {
+ *out++ = b;
+ b = 0; m = 128;
+ }
+ }
+ if (m != 128)
+ *out++ = b;
+}
+
+static void
+pack1I(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, m, b;
+ /* bilevel (black is 1) */
+ b = 0; m = 128;
+ for (i = 0; i < pixels; i++) {
+ if (in[i] == 0)
+ b |= m;
+ m >>= 1;
+ if (m == 0) {
+ *out++ = b;
+ b = 0; m = 128;
+ }
+ }
+ if (m != 128)
+ *out++ = b;
+}
+
+static void
+pack1R(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, m, b;
+ /* bilevel, lsb first (black is 0) */
+ b = 0; m = 1;
+ for (i = 0; i < pixels; i++) {
+ if (in[i] != 0)
+ b |= m;
+ m <<= 1;
+ if (m == 256){
+ *out++ = b;
+ b = 0; m = 1;
+ }
+ }
+ if (m != 1)
+ *out++ = b;
+}
+
+static void
+pack1IR(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, m, b;
+ /* bilevel, lsb first (black is 1) */
+ b = 0; m = 1;
+ for (i = 0; i < pixels; i++) {
+ if (in[i] == 0)
+ b |= m;
+ m <<= 1;
+ if (m == 256){
+ *out++ = b;
+ b = 0; m = 1;
+ }
+ }
+ if (m != 1)
+ *out++ = b;
+}
+
+static void
+pack1L(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* bilevel, stored as bytes */
+ for (i = 0; i < pixels; i++)
+ out[i] = (in[i] != 0) ? 255 : 0;
+}
+
+static void
+packP4(UINT8* out, const UINT8* in, int pixels)
+{
+ while (pixels >= 2) {
+ *out++ = (in[0] << 4) |
+ (in[1] & 15);
+ in += 2; pixels -= 2;
+ }
+
+ if (pixels)
+ out[0] = (in[0] << 4);
+}
+
+static void
+packP2(UINT8* out, const UINT8* in, int pixels)
+{
+ while (pixels >= 4) {
+ *out++ = (in[0] << 6) |
+ ((in[1] & 3) << 4) |
+ ((in[2] & 3) << 2) |
+ (in[3] & 3);
+ in += 4; pixels -= 4;
+ }
+
+ switch (pixels) {
+ case 3:
+ out[0] = (in[0] << 6) |
+ ((in[1] & 3) << 4) |
+ ((in[2] & 3) << 2);
+ break;
+ case 2:
+ out[0] = (in[0] << 6) |
+ ((in[1] & 3) << 4);
+ break;
+ case 1:
+ out[0] = (in[0] << 6);
+ }
+}
+
+static void
+packL16(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* L -> L;16, e.g: \xff77 -> \x00\xff\x00\x77 */
+ for (i = 0; i < pixels; i++) {
+ out[0] = 0;
+ out[1] = in[i];
+ out += 2;
+ }
+}
+
+static void
+packL16B(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* L -> L;16B, e.g: \xff77 -> \xff\x00\x77\x00 */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[i];
+ out[1] = 0;
+ out += 2;
+ }
+}
+
+
+static void
+packLA(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* LA, pixel interleaved */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[R];
+ out[1] = in[A];
+ out += 2; in += 4;
+ }
+}
+
+static void
+packLAL(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* LA, line interleaved */
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[R];
+ out[i+pixels] = in[A];
+ in += 4;
+ }
+}
+
+void
+ImagingPackRGB(UINT8* out, const UINT8* in, int pixels)
+{
+ int i = 0;
+ /* RGB triplets */
+#ifdef __sparc
+ /* SPARC CPUs cannot read integers from nonaligned addresses. */
+ for (; i < pixels; i++) {
+ out[0] = in[R];
+ out[1] = in[G];
+ out[2] = in[B];
+ out += 3; in += 4;
+ }
+#else
+ for (; i < pixels-1; i++) {
+ memcpy(out, in + i * 4, 4);
+ out += 3;
+ }
+ for (; i < pixels; i++) {
+ out[0] = in[i*4+R];
+ out[1] = in[i*4+G];
+ out[2] = in[i*4+B];
+ out += 3;
+ }
+#endif
+}
+
+void
+ImagingPackXRGB(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* XRGB, triplets with left padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = 0;
+ out[1] = in[R];
+ out[2] = in[G];
+ out[3] = in[B];
+ out += 4; in += 4;
+ }
+}
+
+void
+ImagingPackBGR(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, reversed bytes */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[B];
+ out[1] = in[G];
+ out[2] = in[R];
+ out += 3; in += 4;
+ }
+}
+
+void
+ImagingPackBGRX(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* BGRX, reversed bytes with right padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[B];
+ out[1] = in[G];
+ out[2] = in[R];
+ out[3] = 0;
+ out += 4; in += 4;
+ }
+}
+
+void
+ImagingPackXBGR(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* XBGR, reversed bytes with left padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = 0;
+ out[1] = in[B];
+ out[2] = in[G];
+ out[3] = in[R];
+ out += 4; in += 4;
+ }
+}
+
+void
+ImagingPackBGRA(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* BGRX, reversed bytes with right padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[B];
+ out[1] = in[G];
+ out[2] = in[R];
+ out[3] = in[A];
+ out += 4; in += 4;
+ }
+}
+
+void
+ImagingPackABGR(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* XBGR, reversed bytes with left padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[A];
+ out[1] = in[B];
+ out[2] = in[G];
+ out[3] = in[R];
+ out += 4; in += 4;
+ }
+}
+
+void
+ImagingPackBGRa(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* BGRa, reversed bytes with premultiplied alpha */
+ for (i = 0; i < pixels; i++) {
+ int alpha = out[3] = in[A];
+ int tmp;
+ out[0] = MULDIV255(in[B], alpha, tmp);
+ out[1] = MULDIV255(in[G], alpha, tmp);
+ out[2] = MULDIV255(in[R], alpha, tmp);
+ out += 4; in += 4;
+ }
+}
+
+static void
+packRGBL(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, line interleaved */
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[R];
+ out[i+pixels] = in[G];
+ out[i+pixels+pixels] = in[B];
+ in += 4;
+ }
+}
+
+static void
+packRGBXL(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGBX, line interleaved */
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[R];
+ out[i+pixels] = in[G];
+ out[i+pixels+pixels] = in[B];
+ out[i+pixels+pixels+pixels] = in[X];
+ in += 4;
+ }
+}
+
+static void
+packI16B(UINT8* out, const UINT8* in_, int pixels)
+{
+ int i;
+ UINT16 tmp_;
+ UINT8* tmp = (UINT8*) &tmp_;
+ for (i = 0; i < pixels; i++) {
+ INT32 in;
+ memcpy(&in, in_, sizeof(in));
+ if (in <= 0)
+ tmp_ = 0;
+ else if (in > 65535)
+ tmp_ = 65535;
+ else
+ tmp_ = in;
+ C16B;
+ out += 2; in_ += sizeof(in);
+ }
+}
+
+static void
+packI16N_I16B(UINT8* out, const UINT8* in, int pixels){
+ int i;
+ UINT8* tmp = (UINT8*) in;
+ for (i = 0; i < pixels; i++) {
+ C16B;
+ out += 2; tmp += 2;
+ }
+
+}
+static void
+packI16N_I16(UINT8* out, const UINT8* in, int pixels){
+ int i;
+ UINT8* tmp = (UINT8*) in;
+ for (i = 0; i < pixels; i++) {
+ C16L;
+ out += 2; tmp += 2;
+ }
+}
+
+
+static void
+packI32S(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ UINT8* tmp = (UINT8*) in;
+ for (i = 0; i < pixels; i++) {
+ C32L;
+ out += 4; tmp += 4;
+ }
+}
+
+void
+ImagingPackLAB(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* LAB triplets */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[0];
+ out[1] = in[1] ^ 128; /* signed in outside world */
+ out[2] = in[2] ^ 128;
+ out += 3; in += 4;
+ }
+}
+
+static void
+copy1(UINT8* out, const UINT8* in, int pixels)
+{
+ /* L, P */
+ memcpy(out, in, pixels);
+}
+
+static void
+copy2(UINT8* out, const UINT8* in, int pixels)
+{
+ /* I;16, etc */
+ memcpy(out, in, pixels*2);
+}
+
+static void
+copy3(UINT8* out, const UINT8* in, int pixels)
+{
+ /* BGR;24, etc */
+ memcpy(out, in, pixels*3);
+}
+
+static void
+copy4(UINT8* out, const UINT8* in, int pixels)
+{
+ /* RGBA, CMYK quadruples */
+ memcpy(out, in, 4*pixels);
+}
+
+static void
+copy4I(UINT8* out, const UINT8* in, int pixels)
+{
+ /* RGBA, CMYK quadruples, inverted */
+ int i;
+ for (i = 0; i < pixels*4; i++)
+ out[i] = ~in[i];
+}
+
+static void
+band0(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ for (i = 0; i < pixels; i++, in += 4)
+ out[i] = in[0];
+}
+
+static void
+band1(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ for (i = 0; i < pixels; i++, in += 4)
+ out[i] = in[1];
+}
+
+static void
+band2(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ for (i = 0; i < pixels; i++, in += 4)
+ out[i] = in[2];
+}
+
+static void
+band3(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ for (i = 0; i < pixels; i++, in += 4)
+ out[i] = in[3];
+}
+
+static struct {
+ const char* mode;
+ const char* rawmode;
+ int bits;
+ ImagingShuffler pack;
+} packers[] = {
+
+ /* bilevel */
+ {"1", "1", 1, pack1},
+ {"1", "1;I", 1, pack1I},
+ {"1", "1;R", 1, pack1R},
+ {"1", "1;IR", 1, pack1IR},
+ {"1", "L", 8, pack1L},
+
+ /* greyscale */
+ {"L", "L", 8, copy1},
+ {"L", "L;16", 16, packL16},
+ {"L", "L;16B", 16, packL16B},
+
+ /* greyscale w. alpha */
+ {"LA", "LA", 16, packLA},
+ {"LA", "LA;L", 16, packLAL},
+
+ /* palette */
+ {"P", "P;1", 1, pack1},
+ {"P", "P;2", 2, packP2},
+ {"P", "P;4", 4, packP4},
+ {"P", "P", 8, copy1},
+
+ /* palette w. alpha */
+ {"PA", "PA", 16, packLA},
+ {"PA", "PA;L", 16, packLAL},
+
+ /* true colour */
+ {"RGB", "RGB", 24, ImagingPackRGB},
+ {"RGB", "RGBX", 32, copy4},
+ {"RGB", "XRGB", 32, ImagingPackXRGB},
+ {"RGB", "BGR", 24, ImagingPackBGR},
+ {"RGB", "BGRX", 32, ImagingPackBGRX},
+ {"RGB", "XBGR", 32, ImagingPackXBGR},
+ {"RGB", "RGB;L", 24, packRGBL},
+ {"RGB", "R", 8, band0},
+ {"RGB", "G", 8, band1},
+ {"RGB", "B", 8, band2},
+
+ /* true colour w. alpha */
+ {"RGBA", "RGBA", 32, copy4},
+ {"RGBA", "RGBA;L", 32, packRGBXL},
+ {"RGBA", "RGB", 24, ImagingPackRGB},
+ {"RGBA", "BGR", 24, ImagingPackBGR},
+ {"RGBA", "BGRA", 32, ImagingPackBGRA},
+ {"RGBA", "ABGR", 32, ImagingPackABGR},
+ {"RGBA", "BGRa", 32, ImagingPackBGRa},
+ {"RGBA", "R", 8, band0},
+ {"RGBA", "G", 8, band1},
+ {"RGBA", "B", 8, band2},
+ {"RGBA", "A", 8, band3},
+
+ /* true colour w. alpha premultiplied */
+ {"RGBa", "RGBa", 32, copy4},
+ {"RGBa", "BGRa", 32, ImagingPackBGRA},
+ {"RGBa", "aBGR", 32, ImagingPackABGR},
+
+ /* true colour w. padding */
+ {"RGBX", "RGBX", 32, copy4},
+ {"RGBX", "RGBX;L", 32, packRGBXL},
+ {"RGBX", "RGB", 24, ImagingPackRGB},
+ {"RGBX", "BGR", 24, ImagingPackBGR},
+ {"RGBX", "BGRX", 32, ImagingPackBGRX},
+ {"RGBX", "XBGR", 32, ImagingPackXBGR},
+ {"RGBX", "R", 8, band0},
+ {"RGBX", "G", 8, band1},
+ {"RGBX", "B", 8, band2},
+ {"RGBX", "X", 8, band3},
+
+ /* colour separation */
+ {"CMYK", "CMYK", 32, copy4},
+ {"CMYK", "CMYK;I", 32, copy4I},
+ {"CMYK", "CMYK;L", 32, packRGBXL},
+ {"CMYK", "C", 8, band0},
+ {"CMYK", "M", 8, band1},
+ {"CMYK", "Y", 8, band2},
+ {"CMYK", "K", 8, band3},
+
+ /* video (YCbCr) */
+ {"YCbCr", "YCbCr", 24, ImagingPackRGB},
+ {"YCbCr", "YCbCr;L", 24, packRGBL},
+ {"YCbCr", "YCbCrX", 32, copy4},
+ {"YCbCr", "YCbCrK", 32, copy4},
+ {"YCbCr", "Y", 8, band0},
+ {"YCbCr", "Cb", 8, band1},
+ {"YCbCr", "Cr", 8, band2},
+
+ /* LAB Color */
+ {"LAB", "LAB", 24, ImagingPackLAB},
+ {"LAB", "L", 8, band0},
+ {"LAB", "A", 8, band1},
+ {"LAB", "B", 8, band2},
+
+ /* HSV */
+ {"HSV", "HSV", 24, ImagingPackRGB},
+ {"HSV", "H", 8, band0},
+ {"HSV", "S", 8, band1},
+ {"HSV", "V", 8, band2},
+
+ /* integer */
+ {"I", "I", 32, copy4},
+ {"I", "I;16B", 16, packI16B},
+ {"I", "I;32S", 32, packI32S},
+ {"I", "I;32NS", 32, copy4},
+
+ /* floating point */
+ {"F", "F", 32, copy4},
+ {"F", "F;32F", 32, packI32S},
+ {"F", "F;32NF", 32, copy4},
+
+ /* storage modes */
+ {"I;16", "I;16", 16, copy2},
+ {"I;16", "I;16B", 16, packI16N_I16B},
+ {"I;16B", "I;16B", 16, copy2},
+ {"I;16L", "I;16L", 16, copy2},
+ {"I;16", "I;16N", 16, packI16N_I16}, // LibTiff native->image endian.
+ {"I;16L", "I;16N", 16, packI16N_I16},
+ {"I;16B", "I;16N", 16, packI16N_I16B},
+ {"BGR;15", "BGR;15", 16, copy2},
+ {"BGR;16", "BGR;16", 16, copy2},
+ {"BGR;24", "BGR;24", 24, copy3},
+
+ {NULL} /* sentinel */
+};
+
+
+ImagingShuffler
+ImagingFindPacker(const char* mode, const char* rawmode, int* bits_out)
+{
+ int i;
+
+ /* find a suitable pixel packer */
+ for (i = 0; packers[i].rawmode; i++)
+ if (strcmp(packers[i].mode, mode) == 0 &&
+ strcmp(packers[i].rawmode, rawmode) == 0) {
+ if (bits_out)
+ *bits_out = packers[i].bits;
+ return packers[i].pack;
+ }
+ return NULL;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/PackDecode.c b/contrib/python/Pillow/py2/libImaging/PackDecode.c
new file mode 100644
index 0000000000..ef54f3c9a4
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/PackDecode.c
@@ -0,0 +1,92 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for PackBits image data.
+ *
+ * history:
+ * 96-04-19 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+int
+ImagingPackbitsDecode(Imaging im, ImagingCodecState state,
+ UINT8* buf, Py_ssize_t bytes)
+{
+ UINT8 n;
+ UINT8* ptr;
+ int i;
+
+ ptr = buf;
+
+ for (;;) {
+
+ if (bytes < 1)
+ return ptr - buf;
+
+ if (ptr[0] & 0x80) {
+
+ if (ptr[0] == 0x80) {
+ /* Nop */
+ ptr++; bytes--;
+ continue;
+ }
+
+ /* Run */
+ if (bytes < 2)
+ return ptr - buf;
+
+ for (n = 257 - ptr[0]; n > 0; n--) {
+ if (state->x >= state->bytes) {
+ /* state->errcode = IMAGING_CODEC_OVERRUN; */
+ break;
+ }
+ state->buffer[state->x++] = ptr[1];
+ }
+
+ ptr += 2; bytes -= 2;
+
+ } else {
+
+ /* Literal */
+ n = ptr[0]+2;
+
+ if (bytes < n)
+ return ptr - buf;
+
+ for (i = 1; i < n; i++) {
+ if (state->x >= state->bytes) {
+ /* state->errcode = IMAGING_CODEC_OVERRUN; */
+ break;
+ }
+ state->buffer[state->x++] = ptr[i];
+ }
+
+ ptr += n; bytes -= n;
+
+ }
+
+ if (state->x >= state->bytes) {
+
+ /* Got a full line, unpack it */
+ state->shuffle((UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Palette.c b/contrib/python/Pillow/py2/libImaging/Palette.c
new file mode 100644
index 0000000000..7aee6e8eef
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Palette.c
@@ -0,0 +1,318 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * imaging palette object
+ *
+ * history:
+ * 1996-05-05 fl Added to library
+ * 1996-05-27 fl Added colour mapping stuff
+ * 1997-05-12 fl Support RGBA palettes
+ * 2005-02-09 fl Removed grayscale entries from web palette
+ *
+ * Copyright (c) Secret Labs AB 1997-2005. All rights reserved.
+ * Copyright (c) Fredrik Lundh 1995-1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#include <math.h>
+
+
+ImagingPalette
+ImagingPaletteNew(const char* mode)
+{
+ /* Create a palette object */
+
+ int i;
+ ImagingPalette palette;
+
+ if (strcmp(mode, "RGB") && strcmp(mode, "RGBA"))
+ return (ImagingPalette) ImagingError_ModeError();
+
+ palette = calloc(1, sizeof(struct ImagingPaletteInstance));
+ if (!palette)
+ return (ImagingPalette) ImagingError_MemoryError();
+
+ strncpy(palette->mode, mode, IMAGING_MODE_LENGTH-1);
+ palette->mode[IMAGING_MODE_LENGTH-1] = 0;
+
+ /* Initialize to ramp */
+ for (i = 0; i < 256; i++) {
+ palette->palette[i*4+0] =
+ palette->palette[i*4+1] =
+ palette->palette[i*4+2] = (UINT8) i;
+ palette->palette[i*4+3] = 255; /* opaque */
+ }
+
+ return palette;
+}
+
+ImagingPalette
+ImagingPaletteNewBrowser(void)
+{
+ /* Create a standard "browser" palette object */
+
+ int i, r, g, b;
+ ImagingPalette palette;
+
+ palette = ImagingPaletteNew("RGB");
+ if (!palette)
+ return NULL;
+
+ /* Blank out unused entries */
+ /* FIXME: Add 10-level windows palette here? */
+
+ for (i = 0; i < 10; i++) {
+ palette->palette[i*4+0] =
+ palette->palette[i*4+1] =
+ palette->palette[i*4+2] = 0;
+ }
+
+ /* Simple 6x6x6 colour cube */
+
+ for (b = 0; b < 256; b += 51)
+ for (g = 0; g < 256; g += 51)
+ for (r = 0; r < 256; r += 51) {
+ palette->palette[i*4+0] = r;
+ palette->palette[i*4+1] = g;
+ palette->palette[i*4+2] = b;
+ i++;
+ }
+
+ /* Blank out unused entries */
+ /* FIXME: add 30-level greyscale wedge here? */
+
+ for (; i < 256; i++) {
+ palette->palette[i*4+0] =
+ palette->palette[i*4+1] =
+ palette->palette[i*4+2] = 0;
+ }
+
+ return palette;
+}
+
+ImagingPalette
+ImagingPaletteDuplicate(ImagingPalette palette)
+{
+ /* Duplicate palette descriptor */
+
+ ImagingPalette new_palette;
+
+ if (!palette)
+ return NULL;
+ /* malloc check ok, small constant allocation */
+ new_palette = malloc(sizeof(struct ImagingPaletteInstance));
+ if (!new_palette)
+ return (ImagingPalette) ImagingError_MemoryError();
+
+ memcpy(new_palette, palette, sizeof(struct ImagingPaletteInstance));
+
+ /* Don't share the cache */
+ new_palette->cache = NULL;
+
+ return new_palette;
+}
+
+void
+ImagingPaletteDelete(ImagingPalette palette)
+{
+ /* Destroy palette object */
+
+ if (palette) {
+ if (palette->cache)
+ free(palette->cache);
+ free(palette);
+ }
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Colour mapping */
+/* -------------------------------------------------------------------- */
+
+/* This code is used to map RGB triplets to palette indices, using
+ a palette index cache. */
+
+/*
+ * This implementation is loosely based on the corresponding code in
+ * the IJG JPEG library by Thomas G. Lane. Original algorithms by
+ * Paul Heckbert and Spencer W. Thomas.
+ *
+ * The IJG JPEG library is copyright (C) 1991-1995, Thomas G. Lane. */
+
+#define DIST(a, b, s) (a - b) * (a - b) * s
+
+/* Colour weights (no scaling, for now) */
+#define RSCALE 1
+#define GSCALE 1
+#define BSCALE 1
+
+/* Calculated scaled distances */
+#define RDIST(a, b) DIST(a, b, RSCALE*RSCALE)
+#define GDIST(a, b) DIST(a, b, GSCALE*GSCALE)
+#define BDIST(a, b) DIST(a, b, BSCALE*BSCALE)
+
+/* Incremental steps */
+#define RSTEP (4 * RSCALE)
+#define GSTEP (4 * GSCALE)
+#define BSTEP (4 * BSCALE)
+
+#define BOX 8
+
+#define BOXVOLUME BOX*BOX*BOX
+
+void
+ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b)
+{
+ int i, j;
+ unsigned int dmin[256], dmax;
+ int r0, g0, b0;
+ int r1, g1, b1;
+ int rc, gc, bc;
+ unsigned int d[BOXVOLUME];
+ UINT8 c[BOXVOLUME];
+
+ /* Get box boundaries for the given (r,g,b)-triplet. Each box
+ covers eight cache slots (32 colour values, that is). */
+
+ r0 = r & 0xe0; r1 = r0 + 0x1f; rc = (r0 + r1) / 2;
+ g0 = g & 0xe0; g1 = g0 + 0x1f; gc = (g0 + g1) / 2;
+ b0 = b & 0xe0; b1 = b0 + 0x1f; bc = (b0 + b1) / 2;
+
+ /* Step 1 -- Select relevant palette entries (after Heckbert) */
+
+ /* For each palette entry, calculate the min and max distances to
+ * any position in the box given by the colour we're looking for. */
+
+ dmax = (unsigned int) ~0;
+
+ for (i = 0; i < 256; i++) {
+
+ int r, g, b;
+ unsigned int tmin, tmax;
+
+ /* Find min and max distances to any point in the box */
+ r = palette->palette[i*4+0];
+ tmin = (r < r0) ? RDIST(r, r1) : (r > r1) ? RDIST(r, r0) : 0;
+ tmax = (r <= rc) ? RDIST(r, r1) : RDIST(r, r0);
+
+ g = palette->palette[i*4+1];
+ tmin += (g < g0) ? GDIST(g, g1) : (g > g1) ? GDIST(g, g0) : 0;
+ tmax += (g <= gc) ? GDIST(g, g1) : GDIST(g, g0);
+
+ b = palette->palette[i*4+2];
+ tmin += (b < b0) ? BDIST(b, b1) : (b > b1) ? BDIST(b, b0) : 0;
+ tmax += (b <= bc) ? BDIST(b, b1) : BDIST(b, b0);
+
+ dmin[i] = tmin;
+ if (tmax < dmax)
+ dmax = tmax; /* keep the smallest max distance only */
+
+ }
+
+ /* Step 2 -- Incrementally update cache slot (after Thomas) */
+
+ /* Find the box containing the nearest palette entry, and update
+ * all slots in that box. We only check boxes for which the min
+ * distance is less than or equal the smallest max distance */
+
+ for (i = 0; i < BOXVOLUME; i++)
+ d[i] = (unsigned int) ~0;
+
+ for (i = 0; i < 256; i++)
+
+ if (dmin[i] <= dmax) {
+
+ int rd, gd, bd;
+ int ri, gi, bi;
+ int rx, gx, bx;
+
+ ri = (r0 - palette->palette[i*4+0]) * RSCALE;
+ gi = (g0 - palette->palette[i*4+1]) * GSCALE;
+ bi = (b0 - palette->palette[i*4+2]) * BSCALE;
+
+ rd = ri*ri + gi*gi + bi*bi;
+
+ ri = ri * (2 * RSTEP) + RSTEP * RSTEP;
+ gi = gi * (2 * GSTEP) + GSTEP * GSTEP;
+ bi = bi * (2 * BSTEP) + BSTEP * BSTEP;
+
+ rx = ri;
+ for (r = j = 0; r < BOX; r++) {
+ gd = rd; gx = gi;
+ for (g = 0; g < BOX; g++) {
+ bd = gd; bx = bi;
+ for (b = 0; b < BOX; b++) {
+ if ((unsigned int) bd < d[j]) {
+ d[j] = bd;
+ c[j] = (UINT8) i;
+ }
+ bd += bx;
+ bx += 2 * BSTEP * BSTEP;
+ j++;
+ }
+ gd += gx;
+ gx += 2 * GSTEP * GSTEP;
+ }
+ rd += rx;
+ rx += 2 * RSTEP * RSTEP;
+ }
+ }
+
+ /* Step 3 -- Update cache */
+
+ /* The c array now contains the closest match for each
+ * cache slot in the box. Update the cache. */
+
+ j = 0;
+ for (r = r0; r < r1; r+=4)
+ for (g = g0; g < g1; g+=4)
+ for (b = b0; b < b1; b+=4)
+ ImagingPaletteCache(palette, r, g, b) = c[j++];
+}
+
+
+int
+ImagingPaletteCachePrepare(ImagingPalette palette)
+{
+ /* Add a colour cache to a palette */
+
+ int i;
+ int entries = 64*64*64;
+
+ if (palette->cache == NULL) {
+
+ /* The cache is 512k. It might be a good idea to break it
+ up into a pointer array (e.g. an 8-bit image?) */
+
+ /* malloc check ok, small constant allocation */
+ palette->cache = (INT16*) malloc(entries * sizeof(INT16));
+ if (!palette->cache) {
+ (void) ImagingError_MemoryError();
+ return -1;
+ }
+
+ /* Mark all entries as empty */
+ for (i = 0; i < entries; i++)
+ palette->cache[i] = 0x100;
+
+ }
+
+ return 0;
+}
+
+
+void
+ImagingPaletteCacheDelete(ImagingPalette palette)
+{
+ /* Release the colour cache, if any */
+
+ if (palette && palette->cache) {
+ free(palette->cache);
+ palette->cache = NULL;
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Paste.c b/contrib/python/Pillow/py2/libImaging/Paste.c
new file mode 100644
index 0000000000..0bda25739a
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Paste.c
@@ -0,0 +1,544 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * paste image on another image
+ *
+ * history:
+ * 96-03-27 fl Created
+ * 96-07-16 fl Support "1", "L" and "RGBA" masks
+ * 96-08-16 fl Merged with opaque paste
+ * 97-01-17 fl Faster blending, added support for RGBa images
+ * 97-08-27 fl Faster masking for 32-bit images
+ * 98-02-02 fl Fixed MULDIV255 macro for gcc
+ * 99-02-02 fl Added "RGBa" mask support
+ * 99-02-06 fl Rewritten. Added support for masked fill operations.
+ * 99-12-08 fl Fixed matte fill.
+ *
+ * Copyright (c) Fredrik Lundh 1996-97.
+ * Copyright (c) Secret Labs AB 1997-99.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+
+static inline void
+paste(Imaging imOut, Imaging imIn, int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* paste opaque region */
+
+ int y;
+
+ dx *= pixelsize;
+ sx *= pixelsize;
+
+ xsize *= pixelsize;
+
+ for (y = 0; y < ysize; y++)
+ memcpy(imOut->image[y+dy]+dx, imIn->image[y+sy]+sx, xsize);
+}
+
+static inline void
+paste_mask_1(Imaging imOut, Imaging imIn, Imaging imMask,
+ int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* paste with mode "1" mask */
+
+ int x, y;
+
+ if (imOut->image8) {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = imOut->image8[y+dy]+dx;
+ UINT8* in = imIn->image8[y+sy]+sx;
+ UINT8* mask = imMask->image8[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ if (*mask++)
+ *out = *in;
+ out++, in++;
+ }
+ }
+
+ } else {
+
+ for (y = 0; y < ysize; y++) {
+ INT32* out = imOut->image32[y+dy]+dx;
+ INT32* in = imIn->image32[y+sy]+sx;
+ UINT8* mask = imMask->image8[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ if (*mask++)
+ *out = *in;
+ out++, in++;
+ }
+ }
+ }
+}
+
+static inline void
+paste_mask_L(Imaging imOut, Imaging imIn, Imaging imMask,
+ int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* paste with mode "L" matte */
+
+ int x, y;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = imOut->image8[y+dy]+dx;
+ UINT8* in = imIn->image8[y+sy]+sx;
+ UINT8* mask = imMask->image8[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ *out = BLEND(*mask, *out, *in, tmp1);
+ out++, in++, mask++;
+ }
+ }
+
+ } else {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx);
+ UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx);
+ UINT8* mask = (UINT8*) (imMask->image8[y+sy] + sx);
+ for (x = 0; x < xsize; x++) {
+ UINT8 a = mask[0];
+ out[0] = BLEND(a, out[0], in[0], tmp1);
+ out[1] = BLEND(a, out[1], in[1], tmp1);
+ out[2] = BLEND(a, out[2], in[2], tmp1);
+ out[3] = BLEND(a, out[3], in[3], tmp1);
+ out += 4; in += 4; mask ++;
+ }
+ }
+ }
+}
+
+static inline void
+paste_mask_RGBA(Imaging imOut, Imaging imIn, Imaging imMask,
+ int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* paste with mode "RGBA" matte */
+
+ int x, y;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = imOut->image8[y+dy]+dx;
+ UINT8* in = imIn->image8[y+sy]+sx;
+ UINT8* mask = (UINT8*) imMask->image[y+sy]+sx*4+3;
+ for (x = 0; x < xsize; x++) {
+ *out = BLEND(*mask, *out, *in, tmp1);
+ out++, in++, mask += 4;
+ }
+ }
+
+ } else {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx);
+ UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx);
+ UINT8* mask = (UINT8*) (imMask->image32[y+sy] + sx);
+ for (x = 0; x < xsize; x++) {
+ UINT8 a = mask[3];
+ out[0] = BLEND(a, out[0], in[0], tmp1);
+ out[1] = BLEND(a, out[1], in[1], tmp1);
+ out[2] = BLEND(a, out[2], in[2], tmp1);
+ out[3] = BLEND(a, out[3], in[3], tmp1);
+ out += 4; in += 4; mask += 4;
+ }
+ }
+ }
+}
+
+
+static inline void
+paste_mask_RGBa(Imaging imOut, Imaging imIn, Imaging imMask,
+ int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* paste with mode "RGBa" matte */
+
+ int x, y;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = imOut->image8[y+dy]+dx;
+ UINT8* in = imIn->image8[y+sy]+sx;
+ UINT8* mask = (UINT8*) imMask->image[y+sy]+sx*4+3;
+ for (x = 0; x < xsize; x++) {
+ *out = PREBLEND(*mask, *out, *in, tmp1);
+ out++, in++, mask += 4;
+ }
+ }
+
+ } else {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx);
+ UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx);
+ UINT8* mask = (UINT8*) (imMask->image32[y+sy] + sx);
+ for (x = 0; x < xsize; x++) {
+ UINT8 a = mask[3];
+ out[0] = PREBLEND(a, out[0], in[0], tmp1);
+ out[1] = PREBLEND(a, out[1], in[1], tmp1);
+ out[2] = PREBLEND(a, out[2], in[2], tmp1);
+ out[3] = PREBLEND(a, out[3], in[3], tmp1);
+ out += 4; in += 4; mask += 4;
+ }
+ }
+ }
+}
+
+int
+ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask,
+ int dx0, int dy0, int dx1, int dy1)
+{
+ int xsize, ysize;
+ int pixelsize;
+ int sx0, sy0;
+ ImagingSectionCookie cookie;
+
+ if (!imOut || !imIn) {
+ (void) ImagingError_ModeError();
+ return -1;
+ }
+
+ pixelsize = imOut->pixelsize;
+
+ xsize = dx1 - dx0;
+ ysize = dy1 - dy0;
+
+ if (xsize != imIn->xsize || ysize != imIn->ysize ||
+ pixelsize != imIn->pixelsize) {
+ (void) ImagingError_Mismatch();
+ return -1;
+ }
+
+ if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
+ (void) ImagingError_Mismatch();
+ return -1;
+ }
+
+ /* Determine which region to copy */
+ sx0 = sy0 = 0;
+ if (dx0 < 0)
+ xsize += dx0, sx0 = -dx0, dx0 = 0;
+ if (dx0 + xsize > imOut->xsize)
+ xsize = imOut->xsize - dx0;
+ if (dy0 < 0)
+ ysize += dy0, sy0 = -dy0, dy0 = 0;
+ if (dy0 + ysize > imOut->ysize)
+ ysize = imOut->ysize - dy0;
+
+ if (xsize <= 0 || ysize <= 0)
+ return 0;
+
+ if (!imMask) {
+ ImagingSectionEnter(&cookie);
+ paste(imOut, imIn, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "1") == 0) {
+ ImagingSectionEnter(&cookie);
+ paste_mask_1(imOut, imIn, imMask, dx0, dy0, sx0, sy0,
+ xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "L") == 0) {
+ ImagingSectionEnter(&cookie);
+ paste_mask_L(imOut, imIn, imMask, dx0, dy0, sx0, sy0,
+ xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "RGBA") == 0) {
+ ImagingSectionEnter(&cookie);
+ paste_mask_RGBA(imOut, imIn, imMask, dx0, dy0, sx0, sy0,
+ xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "RGBa") == 0) {
+ ImagingSectionEnter(&cookie);
+ paste_mask_RGBa(imOut, imIn, imMask, dx0, dy0, sx0, sy0,
+ xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else {
+ (void) ImagingError_ValueError("bad transparency mask");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline void
+fill(Imaging imOut, const void* ink_, int dx, int dy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* fill opaque region */
+
+ int x, y;
+ UINT8 ink8 = 0;
+ INT32 ink32 = 0L;
+
+ memcpy(&ink32, ink_, pixelsize);
+ memcpy(&ink8, ink_, sizeof(ink8));
+
+ if (imOut->image8 || ink32 == 0L) {
+
+ dx *= pixelsize;
+ xsize *= pixelsize;
+ for (y = 0; y < ysize; y++)
+ memset(imOut->image[y+dy]+dx, ink8, xsize);
+
+ } else {
+
+ for (y = 0; y < ysize; y++) {
+ INT32* out = imOut->image32[y+dy]+dx;
+ for (x = 0; x < xsize; x++)
+ out[x] = ink32;
+ }
+
+ }
+}
+
+static inline void
+fill_mask_1(Imaging imOut, const void* ink_, Imaging imMask,
+ int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* fill with mode "1" mask */
+
+ int x, y;
+ UINT8 ink8 = 0;
+ INT32 ink32 = 0L;
+
+ memcpy(&ink32, ink_, pixelsize);
+ memcpy(&ink8, ink_, sizeof(ink8));
+
+ if (imOut->image8) {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = imOut->image8[y+dy]+dx;
+ UINT8* mask = imMask->image8[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ if (*mask++)
+ *out = ink8;
+ out++;
+ }
+ }
+
+ } else {
+
+ for (y = 0; y < ysize; y++) {
+ INT32* out = imOut->image32[y+dy]+dx;
+ UINT8* mask = imMask->image8[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ if (*mask++)
+ *out = ink32;
+ out++;
+ }
+ }
+ }
+}
+
+static inline void
+fill_mask_L(Imaging imOut, const UINT8* ink, Imaging imMask,
+ int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* fill with mode "L" matte */
+
+ int x, y, i;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = imOut->image8[y+dy]+dx;
+ UINT8* mask = imMask->image8[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ *out = BLEND(*mask, *out, ink[0], tmp1);
+ out++, mask++;
+ }
+ }
+
+ } else {
+
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = (UINT8*) imOut->image[y+dy]+dx*pixelsize;
+ UINT8* mask = (UINT8*) imMask->image[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ for (i = 0; i < pixelsize; i++) {
+ *out = BLEND(*mask, *out, ink[i], tmp1);
+ out++;
+ }
+ mask++;
+ }
+ }
+ }
+}
+
+static inline void
+fill_mask_RGBA(Imaging imOut, const UINT8* ink, Imaging imMask,
+ int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* fill with mode "RGBA" matte */
+
+ int x, y, i;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+
+ sx = sx*4+3;
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = imOut->image8[y+dy]+dx;
+ UINT8* mask = (UINT8*) imMask->image[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ *out = BLEND(*mask, *out, ink[0], tmp1);
+ out++, mask += 4;
+ }
+ }
+
+ } else {
+
+ dx *= pixelsize;
+ sx = sx*4 + 3;
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = (UINT8*) imOut->image[y+dy]+dx;
+ UINT8* mask = (UINT8*) imMask->image[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ for (i = 0; i < pixelsize; i++) {
+ *out = BLEND(*mask, *out, ink[i], tmp1);
+ out++;
+ }
+ mask += 4;
+ }
+ }
+ }
+}
+
+static inline void
+fill_mask_RGBa(Imaging imOut, const UINT8* ink, Imaging imMask,
+ int dx, int dy, int sx, int sy,
+ int xsize, int ysize, int pixelsize)
+{
+ /* fill with mode "RGBa" matte */
+
+ int x, y, i;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+
+ sx = sx*4 + 3;
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = imOut->image8[y+dy]+dx;
+ UINT8* mask = (UINT8*) imMask->image[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ *out = PREBLEND(*mask, *out, ink[0], tmp1);
+ out++, mask += 4;
+ }
+ }
+
+ } else {
+
+ dx *= pixelsize;
+ sx = sx*4 + 3;
+ for (y = 0; y < ysize; y++) {
+ UINT8* out = (UINT8*) imOut->image[y+dy]+dx;
+ UINT8* mask = (UINT8*) imMask->image[y+sy]+sx;
+ for (x = 0; x < xsize; x++) {
+ for (i = 0; i < pixelsize; i++) {
+ *out = PREBLEND(*mask, *out, ink[i], tmp1);
+ out++;
+ }
+ mask += 4;
+ }
+ }
+ }
+}
+
+int
+ImagingFill2(Imaging imOut, const void* ink, Imaging imMask,
+ int dx0, int dy0, int dx1, int dy1)
+{
+ ImagingSectionCookie cookie;
+ int xsize, ysize;
+ int pixelsize;
+ int sx0, sy0;
+
+ if (!imOut || !ink) {
+ (void) ImagingError_ModeError();
+ return -1;
+ }
+
+ pixelsize = imOut->pixelsize;
+
+ xsize = dx1 - dx0;
+ ysize = dy1 - dy0;
+
+ if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
+ (void) ImagingError_Mismatch();
+ return -1;
+ }
+
+ /* Determine which region to fill */
+ sx0 = sy0 = 0;
+ if (dx0 < 0)
+ xsize += dx0, sx0 = -dx0, dx0 = 0;
+ if (dx0 + xsize > imOut->xsize)
+ xsize = imOut->xsize - dx0;
+ if (dy0 < 0)
+ ysize += dy0, sy0 = -dy0, dy0 = 0;
+ if (dy0 + ysize > imOut->ysize)
+ ysize = imOut->ysize - dy0;
+
+ if (xsize <= 0 || ysize <= 0)
+ return 0;
+
+ if (!imMask) {
+ ImagingSectionEnter(&cookie);
+ fill(imOut, ink, dx0, dy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "1") == 0) {
+ ImagingSectionEnter(&cookie);
+ fill_mask_1(imOut, ink, imMask, dx0, dy0, sx0, sy0,
+ xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "L") == 0) {
+ ImagingSectionEnter(&cookie);
+ fill_mask_L(imOut, ink, imMask, dx0, dy0, sx0, sy0,
+ xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "RGBA") == 0) {
+ ImagingSectionEnter(&cookie);
+ fill_mask_RGBA(imOut, ink, imMask, dx0, dy0, sx0, sy0,
+ xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "RGBa") == 0) {
+ ImagingSectionEnter(&cookie);
+ fill_mask_RGBa(imOut, ink, imMask, dx0, dy0, sx0, sy0,
+ xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else {
+ (void) ImagingError_ValueError("bad transparency mask");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/PcdDecode.c b/contrib/python/Pillow/py2/libImaging/PcdDecode.c
new file mode 100644
index 0000000000..8ff264edfc
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/PcdDecode.c
@@ -0,0 +1,78 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for uncompressed PCD image data.
+ *
+ * history:
+ * 96-05-10 fl Created
+ * 96-05-18 fl New tables
+ * 97-01-25 fl Use PhotoYCC unpacker
+ *
+ * notes:
+ * This driver supports uncompressed PCD modes only
+ * (resolutions up to 768x512).
+ *
+ * Copyright (c) Fredrik Lundh 1996-97.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+int
+ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ int x;
+ int chunk;
+ UINT8* out;
+ UINT8* ptr;
+
+ ptr = buf;
+
+ chunk = 3 * state->xsize;
+
+ for (;;) {
+
+ /* We need data for two full lines before we can do anything */
+ if (bytes < chunk)
+ return ptr - buf;
+
+ /* Unpack first line */
+ out = state->buffer;
+ for (x = 0; x < state->xsize; x++) {
+ out[0] = ptr[x];
+ out[1] = ptr[(x+4*state->xsize)/2];
+ out[2] = ptr[(x+5*state->xsize)/2];
+ out += 3;
+ }
+
+ state->shuffle((UINT8*) im->image[state->y],
+ state->buffer, state->xsize);
+
+ if (++state->y >= state->ysize)
+ return -1; /* This can hardly happen */
+
+ /* Unpack second line */
+ out = state->buffer;
+ for (x = 0; x < state->xsize; x++) {
+ out[0] = ptr[x+state->xsize];
+ out[1] = ptr[(x+4*state->xsize)/2];
+ out[2] = ptr[(x+5*state->xsize)/2];
+ out += 3;
+ }
+
+ state->shuffle((UINT8*) im->image[state->y],
+ state->buffer, state->xsize);
+
+ if (++state->y >= state->ysize)
+ return -1;
+
+ ptr += chunk;
+ bytes -= chunk;
+
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/PcxDecode.c b/contrib/python/Pillow/py2/libImaging/PcxDecode.c
new file mode 100644
index 0000000000..9e9504ce5f
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/PcxDecode.c
@@ -0,0 +1,92 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for PCX image data.
+ *
+ * history:
+ * 95-09-14 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1995.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+int
+ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ UINT8 n;
+ UINT8* ptr;
+
+ if (strcmp(im->mode, "1") == 0 && state->xsize > state->bytes * 8) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ } else if (strcmp(im->mode, "P") == 0 && state->xsize > state->bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ ptr = buf;
+
+ for (;;) {
+
+ if (bytes < 1)
+ return ptr - buf;
+
+ if ((*ptr & 0xC0) == 0xC0) {
+
+ /* Run */
+ if (bytes < 2)
+ return ptr - buf;
+
+ n = ptr[0] & 0x3F;
+
+ while (n > 0) {
+ if (state->x >= state->bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ break;
+ }
+ state->buffer[state->x++] = ptr[1];
+ n--;
+ }
+
+ ptr += 2; bytes -= 2;
+
+ } else {
+
+ /* Literal */
+ state->buffer[state->x++] = ptr[0];
+ ptr++; bytes--;
+
+ }
+
+ if (state->x >= state->bytes) {
+ if (state->bytes % state->xsize && state->bytes > state->xsize) {
+ int bands = state->bytes / state->xsize;
+ int stride = state->bytes / bands;
+ int i;
+ for (i=1; i< bands; i++) { // note -- skipping first band
+ memmove(&state->buffer[i*state->xsize],
+ &state->buffer[i*stride],
+ state->xsize);
+ }
+ }
+ /* Got a full line, unpack it */
+ state->shuffle((UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/PcxEncode.c b/contrib/python/Pillow/py2/libImaging/PcxEncode.c
new file mode 100644
index 0000000000..163b09b139
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/PcxEncode.c
@@ -0,0 +1,191 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * encoder for PCX data
+ *
+ * history:
+ * 99-02-07 fl created
+ *
+ * Copyright (c) Fredrik Lundh 1999.
+ * Copyright (c) Secret Labs AB 1999.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+enum { INIT, FETCH, ENCODE };
+
+/* we're reusing "ystep" to store the last value */
+#define LAST ystep
+
+int
+ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
+{
+ UINT8* ptr;
+ int this;
+ int bytes_per_line = 0;
+ int padding = 0;
+ int stride = 0;
+ int bpp = 0;
+ int planes = 1;
+ int i;
+
+ ptr = buf;
+
+ if (!state->state) {
+ /* sanity check */
+ if (state->xsize <= 0 || state->ysize <= 0) {
+ state->errcode = IMAGING_CODEC_END;
+ return 0;
+ }
+ state->state = FETCH;
+ }
+
+ bpp = state->bits;
+ if (state->bits == 24){
+ planes = 3;
+ bpp = 8;
+ }
+
+ bytes_per_line = (state->xsize*bpp + 7) / 8;
+ /* The stride here needs to be kept in sync with the version in
+ PcxImagePlugin.py. If it's not, the header and the body of the
+ image will be out of sync and bad things will happen on decode.
+ */
+ stride = bytes_per_line + (bytes_per_line % 2);
+
+ padding = stride - bytes_per_line;
+
+
+ for (;;) {
+
+ switch (state->state) {
+ case FETCH:
+
+ /* get a line of data */
+ if (state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_END;
+ return ptr - buf;
+ }
+
+ state->shuffle(state->buffer,
+ (UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->xsize);
+
+ state->y += 1;
+
+ state->count = 1;
+ state->LAST = state->buffer[0];
+
+ state->x = 1;
+
+ state->state = ENCODE;
+ /* fall through */
+
+ case ENCODE:
+ /* compress this line */
+
+ /* when we arrive here, "count" contains the number of
+ bytes having the value of "LAST" that we've already
+ seen */
+ do {
+ /* If we're encoding an odd width file, and we've
+ got more than one plane, we need to pad each
+ color row with padding bytes at the end. Since
+ The pixels are stored RRRRRGGGGGBBBBB, so we need
+ to have the padding be RRRRRPGGGGGPBBBBBP. Hence
+ the double loop
+ */
+ while (state->x % bytes_per_line) {
+
+ if (state->count == 63) {
+ /* this run is full; flush it */
+ if (bytes < 2) {
+ return ptr - buf;
+ }
+ ptr[0] = 0xff;
+ ptr[1] = state->LAST;
+ ptr += 2;
+ bytes -= 2;
+
+ state->count = 0;
+ }
+
+ this = state->buffer[state->x];
+
+ if (this == state->LAST) {
+ /* extend the current run */
+ state->x += 1;
+ state->count += 1;
+
+ } else {
+ /* start a new run */
+ if (state->count == 1 && (state->LAST < 0xc0)) {
+ if (bytes < 1) {
+ return ptr - buf;
+ }
+ ptr[0] = state->LAST;
+ ptr += 1;
+ bytes -= 1;
+ } else {
+ if (state->count > 0) {
+ if (bytes < 2) {
+ return ptr - buf;
+ }
+ ptr[0] = 0xc0 | state->count;
+ ptr[1] = state->LAST;
+ ptr += 2;
+ bytes -= 2;
+ }
+ }
+
+ state->LAST = this;
+ state->count = 1;
+
+ state->x += 1;
+ }
+ }
+
+ /* end of line; flush the current run */
+ if (state->count == 1 && (state->LAST < 0xc0)) {
+ if (bytes < 1 + padding) {
+ return ptr - buf;
+ }
+ ptr[0] = state->LAST;
+ ptr += 1;
+ bytes -= 1;
+ } else {
+ if (state->count > 0) {
+ if (bytes < 2 + padding) {
+ return ptr - buf;
+ }
+ ptr[0] = 0xc0 | state->count;
+ ptr[1] = state->LAST;
+ ptr += 2;
+ bytes -= 2;
+ }
+ }
+ /* add the padding */
+ for (i = 0; i < padding; i++) {
+ ptr[0] = 0;
+ ptr += 1;
+ bytes -= 1;
+ }
+ /* reset for the next color plane. */
+ if (state->x < planes * bytes_per_line) {
+ state->count = 1;
+ state->LAST = state->buffer[state->x];
+ state->x += 1;
+ }
+ } while (state->x < planes * bytes_per_line);
+
+ /* read next line */
+ state->state = FETCH;
+ break;
+ }
+ }
+}
+
diff --git a/contrib/python/Pillow/py2/libImaging/Point.c b/contrib/python/Pillow/py2/libImaging/Point.c
new file mode 100644
index 0000000000..9b4bf6b754
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Point.c
@@ -0,0 +1,265 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * point (pixel) translation
+ *
+ * history:
+ * 1995-11-27 fl Created
+ * 1996-03-31 fl Fixed colour support
+ * 1996-08-13 fl Support 8-bit to "1" thresholding
+ * 1997-05-31 fl Added floating point transform
+ * 1998-07-02 fl Added integer point transform
+ * 1998-07-17 fl Support L to anything lookup
+ * 2004-12-18 fl Refactored; added I to L lookup
+ *
+ * Copyright (c) 1997-2004 by Secret Labs AB.
+ * Copyright (c) 1995-2004 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+typedef struct {
+ const void* table;
+} im_point_context;
+
+static void
+im_point_8_8(Imaging imOut, Imaging imIn, im_point_context* context)
+{
+ int x, y;
+ /* 8-bit source, 8-bit destination */
+ UINT8* table = (UINT8*) context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = imIn->image8[y];
+ UINT8* out = imOut->image8[y];
+ for (x = 0; x < imIn->xsize; x++)
+ out[x] = table[in[x]];
+ }
+}
+
+static void
+im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context* context)
+{
+ int x, y;
+ /* 2x8-bit source, 2x8-bit destination */
+ UINT8* table = (UINT8*) context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out = (UINT8*) imOut->image[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ out[0] = table[in[0]];
+ out[3] = table[in[3]+256];
+ in += 4; out += 4;
+ }
+ }
+}
+
+static void
+im_point_3x8_3x8(Imaging imOut, Imaging imIn, im_point_context* context)
+{
+ int x, y;
+ /* 3x8-bit source, 3x8-bit destination */
+ UINT8* table = (UINT8*) context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out = (UINT8*) imOut->image[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ out[0] = table[in[0]];
+ out[1] = table[in[1]+256];
+ out[2] = table[in[2]+512];
+ in += 4; out += 4;
+ }
+ }
+}
+
+static void
+im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context* context)
+{
+ int x, y;
+ /* 4x8-bit source, 4x8-bit destination */
+ UINT8* table = (UINT8*) context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = (UINT8*) imIn->image[y];
+ UINT8* out = (UINT8*) imOut->image[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ out[0] = table[in[0]];
+ out[1] = table[in[1]+256];
+ out[2] = table[in[2]+512];
+ out[3] = table[in[3]+768];
+ in += 4; out += 4;
+ }
+ }
+}
+
+static void
+im_point_8_32(Imaging imOut, Imaging imIn, im_point_context* context)
+{
+ int x, y;
+ /* 8-bit source, 32-bit destination */
+ char* table = (char*) context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8* in = imIn->image8[y];
+ INT32* out = imOut->image32[y];
+ for (x = 0; x < imIn->xsize; x++)
+ memcpy(out + x, table + in[x] * sizeof(INT32), sizeof(INT32));
+ }
+}
+
+static void
+im_point_32_8(Imaging imOut, Imaging imIn, im_point_context* context)
+{
+ int x, y;
+ /* 32-bit source, 8-bit destination */
+ UINT8* table = (UINT8*) context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ INT32* in = imIn->image32[y];
+ UINT8* out = imOut->image8[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ int v = in[x];
+ if (v < 0)
+ v = 0;
+ else if (v > 65535)
+ v = 65535;
+ out[x] = table[v];
+ }
+ }
+}
+
+Imaging
+ImagingPoint(Imaging imIn, const char* mode, const void* table)
+{
+ /* lookup table transform */
+
+ ImagingSectionCookie cookie;
+ Imaging imOut;
+ im_point_context context;
+ void (*point)(Imaging imIn, Imaging imOut, im_point_context* context);
+
+ if (!imIn)
+ return (Imaging) ImagingError_ModeError();
+
+ if (!mode)
+ mode = imIn->mode;
+
+ if (imIn->type != IMAGING_TYPE_UINT8) {
+ if (imIn->type != IMAGING_TYPE_INT32 || strcmp(mode, "L") != 0)
+ goto mode_mismatch;
+ } else if (!imIn->image8 && strcmp(imIn->mode, mode) != 0)
+ goto mode_mismatch;
+
+ imOut = ImagingNew(mode, imIn->xsize, imIn->ysize);
+ if (!imOut)
+ return NULL;
+
+ /* find appropriate handler */
+ if (imIn->type == IMAGING_TYPE_UINT8) {
+ if (imIn->bands == imOut->bands && imIn->type == imOut->type) {
+ switch (imIn->bands) {
+ case 1:
+ point = im_point_8_8;
+ break;
+ case 2:
+ point = im_point_2x8_2x8;
+ break;
+ case 3:
+ point = im_point_3x8_3x8;
+ break;
+ case 4:
+ point = im_point_4x8_4x8;
+ break;
+ default:
+ /* this cannot really happen */
+ point = im_point_8_8;
+ break;
+ }
+ } else
+ point = im_point_8_32;
+ } else
+ point = im_point_32_8;
+
+ ImagingCopyPalette(imOut, imIn);
+
+ ImagingSectionEnter(&cookie);
+
+ context.table = table;
+ point(imOut, imIn, &context);
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+
+ mode_mismatch:
+ return (Imaging) ImagingError_ValueError(
+ "point operation not supported for this mode"
+ );
+}
+
+
+Imaging
+ImagingPointTransform(Imaging imIn, double scale, double offset)
+{
+ /* scale/offset transform */
+
+ ImagingSectionCookie cookie;
+ Imaging imOut;
+ int x, y;
+
+ if (!imIn || (strcmp(imIn->mode, "I") != 0 &&
+ strcmp(imIn->mode, "I;16") != 0 &&
+ strcmp(imIn->mode, "F") != 0))
+ return (Imaging) ImagingError_ModeError();
+
+ imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
+ if (!imOut)
+ return NULL;
+
+ switch (imIn->type) {
+ case IMAGING_TYPE_INT32:
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ INT32* in = imIn->image32[y];
+ INT32* out = imOut->image32[y];
+ /* FIXME: add clipping? */
+ for (x = 0; x < imIn->xsize; x++)
+ out[x] = in[x] * scale + offset;
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ FLOAT32* in = (FLOAT32*) imIn->image32[y];
+ FLOAT32* out = (FLOAT32*) imOut->image32[y];
+ for (x = 0; x < imIn->xsize; x++)
+ out[x] = in[x] * scale + offset;
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ case IMAGING_TYPE_SPECIAL:
+ if (strcmp(imIn->mode,"I;16") == 0) {
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ char* in = (char*)imIn->image[y];
+ char* out = (char*)imOut->image[y];
+ /* FIXME: add clipping? */
+ for (x = 0; x < imIn->xsize; x++) {
+ UINT16 v;
+ memcpy(&v, in + x * sizeof(v), sizeof(v));
+ v = v * scale + offset;
+ memcpy(out + x * sizeof(UINT16), &v, sizeof(v));
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ ImagingDelete(imOut);
+ return (Imaging) ImagingError_ValueError("internal error");
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Quant.c b/contrib/python/Pillow/py2/libImaging/Quant.c
new file mode 100644
index 0000000000..b94dc6e1d0
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Quant.c
@@ -0,0 +1,1695 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * image quantizer
+ *
+ * history:
+ * 1998-09-10 tjs Contributed
+ * 1998-12-29 fl Added to PIL 1.0b1
+ * 2004-02-21 fl Fixed bogus free() on quantization error
+ * 2005-02-07 fl Limit number of colors to 256
+ *
+ * Written by Toby J Sargeant <tjs@longford.cs.monash.edu.au>.
+ *
+ * Copyright (c) 1998 by Toby J Sargeant
+ * Copyright (c) 1998-2004 by Secret Labs AB. All rights reserved.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <time.h>
+
+#include "QuantTypes.h"
+#include "QuantOctree.h"
+#include "QuantPngQuant.h"
+#include "QuantHash.h"
+#include "QuantHeap.h"
+
+/* MSVC9.0 */
+#ifndef UINT32_MAX
+#define UINT32_MAX 0xffffffff
+#endif
+
+#define NO_OUTPUT
+
+typedef struct {
+ uint32_t scale;
+} PixelHashData;
+
+typedef struct _PixelList {
+ struct _PixelList *next[3],*prev[3];
+ Pixel p;
+ unsigned int flag:1;
+ int count;
+} PixelList;
+
+typedef struct _BoxNode {
+ struct _BoxNode *l,*r;
+ PixelList *head[3],*tail[3];
+ int axis;
+ int volume;
+ uint32_t pixelCount;
+} BoxNode;
+
+#define _SQR(x) ((x)*(x))
+#define _DISTSQR(p1,p2) \
+ _SQR((int)((p1)->c.r)-(int)((p2)->c.r))+ \
+ _SQR((int)((p1)->c.g)-(int)((p2)->c.g))+ \
+ _SQR((int)((p1)->c.b)-(int)((p2)->c.b))
+
+#define MAX_HASH_ENTRIES 65536
+
+#define PIXEL_HASH(r,g,b) \
+ (((unsigned int)(r) )*463 ^ \
+ ((unsigned int)(g)<< 8)*10069 ^ \
+ ((unsigned int)(b)<<16)*64997)
+
+#define PIXEL_UNSCALE(p,q,s) \
+ ((q)->c.r=(p)->c.r<<(s)), \
+ ((q)->c.g=(p)->c.g<<(s)), \
+ ((q)->c.b=(p)->c.b<<(s))
+
+#define PIXEL_SCALE(p,q,s)\
+ ((q)->c.r=(p)->c.r>>(s)), \
+ ((q)->c.g=(p)->c.g>>(s)), \
+ ((q)->c.b=(p)->c.b>>(s))
+
+static uint32_t
+unshifted_pixel_hash(const HashTable *h, const Pixel pixel)
+{
+ return PIXEL_HASH(pixel.c.r, pixel.c.g, pixel.c.b);
+}
+
+static int
+unshifted_pixel_cmp(const HashTable *h, const Pixel pixel1, const Pixel pixel2)
+{
+ if (pixel1.c.r==pixel2.c.r) {
+ if (pixel1.c.g==pixel2.c.g) {
+ if (pixel1.c.b==pixel2.c.b) {
+ return 0;
+ } else {
+ return (int)(pixel1.c.b)-(int)(pixel2.c.b);
+ }
+ } else {
+ return (int)(pixel1.c.g)-(int)(pixel2.c.g);
+ }
+ } else {
+ return (int)(pixel1.c.r)-(int)(pixel2.c.r);
+ }
+}
+
+static uint32_t
+pixel_hash(const HashTable *h,const Pixel pixel)
+{
+ PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
+ return PIXEL_HASH(pixel.c.r>>d->scale, pixel.c.g>>d->scale, pixel.c.b>>d->scale);
+}
+
+static int
+pixel_cmp(const HashTable *h,const Pixel pixel1, const Pixel pixel2)
+{
+ PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
+ uint32_t A,B;
+ A=PIXEL_HASH(pixel1.c.r>>d->scale, pixel1.c.g>>d->scale, pixel1.c.b>>d->scale);
+ B=PIXEL_HASH(pixel2.c.r>>d->scale, pixel2.c.g>>d->scale, pixel2.c.b>>d->scale);
+ return (A==B)?0:((A<B)?-1:1);
+}
+
+static void
+exists_count_func(const HashTable *h, const Pixel key, uint32_t *val)
+{
+ *val+=1;
+}
+
+static void
+new_count_func(const HashTable *h, const Pixel key, uint32_t *val)
+{
+ *val=1;
+}
+
+static void
+rehash_collide(const HashTable *h,
+ Pixel *keyp,
+ uint32_t *valp,
+ Pixel newkey,
+ uint32_t newval)
+{
+ *valp += newval;
+}
+
+/* %% */
+
+static HashTable *
+create_pixel_hash(Pixel *pixelData,uint32_t nPixels)
+{
+ PixelHashData *d;
+ HashTable *hash;
+ uint32_t i;
+#ifndef NO_OUTPUT
+ uint32_t timer,timer2,timer3;
+#endif
+
+ /* malloc check ok, small constant allocation */
+ d=malloc(sizeof(PixelHashData));
+ if (!d) return NULL;
+ hash=hashtable_new(pixel_hash,pixel_cmp);
+ hashtable_set_user_data(hash,d);
+ d->scale=0;
+#ifndef NO_OUTPUT
+ timer=timer3=clock();
+#endif
+ for (i=0;i<nPixels;i++) {
+ if (!hashtable_insert_or_update_computed(hash,
+ pixelData[i],
+ new_count_func,
+ exists_count_func)) {;
+ }
+ while (hashtable_get_count(hash)>MAX_HASH_ENTRIES) {
+ d->scale++;
+#ifndef NO_OUTPUT
+ printf ("rehashing - new scale: %d\n",(int)d->scale);
+ timer2=clock();
+#endif
+ hashtable_rehash_compute(hash,rehash_collide);
+#ifndef NO_OUTPUT
+ timer2=clock()-timer2;
+ printf ("rehash took %f sec\n",timer2/(double)CLOCKS_PER_SEC);
+ timer+=timer2;
+#endif
+ }
+ }
+#ifndef NO_OUTPUT
+ printf ("inserts took %f sec\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+#endif
+#ifndef NO_OUTPUT
+ printf ("total %f sec\n",(clock()-timer3)/(double)CLOCKS_PER_SEC);
+#endif
+ return hash;
+}
+
+static void
+destroy_pixel_hash(HashTable *hash)
+{
+ PixelHashData *d=(PixelHashData *)hashtable_get_user_data(hash);
+ if (d) free(d);
+ hashtable_free(hash);
+}
+
+
+/* 1. hash quantized pixels. */
+/* 2. create R,G,B lists of sorted quantized pixels. */
+/* 3. median cut. */
+/* 4. build hash table from median cut boxes. */
+/* 5. for each pixel, compute entry in hash table, and hence median cut box. */
+/* 6. compute median cut box pixel averages. */
+/* 7. map each pixel to nearest average. */
+
+static int
+compute_box_volume(BoxNode *b)
+{
+ unsigned char rl,rh,gl,gh,bl,bh;
+ if (b->volume>=0) return b->volume;
+ if (!b->head[0]) {
+ b->volume=0;
+ } else {
+ rh=b->head[0]->p.c.r;
+ rl=b->tail[0]->p.c.r;
+ gh=b->head[1]->p.c.g;
+ gl=b->tail[1]->p.c.g;
+ bh=b->head[2]->p.c.b;
+ bl=b->tail[2]->p.c.b;
+ b->volume=(rh-rl+1)*(gh-gl+1)*(bh-bl+1);
+ }
+ return b->volume;
+}
+
+static void
+hash_to_list(const HashTable *h, const Pixel pixel, const uint32_t count, void *u)
+{
+ PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
+ PixelList **pl=(PixelList **)u;
+ PixelList *p;
+ int i;
+ Pixel q;
+
+ PIXEL_SCALE(&pixel,&q,d->scale);
+
+ /* malloc check ok, small constant allocation */
+ p=malloc(sizeof(PixelList));
+ if (!p) return;
+
+ p->flag=0;
+ p->p=q;
+ p->count=count;
+ for (i=0;i<3;i++) {
+ p->next[i]=pl[i];
+ p->prev[i]=NULL;
+ if (pl[i]) pl[i]->prev[i]=p;
+ pl[i]=p;
+ }
+}
+
+static PixelList *
+mergesort_pixels(PixelList *head, int i)
+{
+ PixelList *c,*t,*a,*b,*p;
+ if (!head||!head->next[i]) {
+ if (head) {
+ head->next[i]=NULL;
+ head->prev[i]=NULL;
+ }
+ return head;
+ }
+ for (c=t=head;c&&t;c=c->next[i],t=(t->next[i])?t->next[i]->next[i]:NULL);
+ if (c) {
+ if (c->prev[i]) c->prev[i]->next[i]=NULL;
+ c->prev[i]=NULL;
+ }
+ a=mergesort_pixels(head,i);
+ b=mergesort_pixels(c,i);
+ head=NULL;
+ p=NULL;
+ while (a&&b) {
+ if (a->p.a.v[i]>b->p.a.v[i]) {
+ c=a;
+ a=a->next[i];
+ } else {
+ c=b;
+ b=b->next[i];
+ }
+ c->prev[i]=p;
+ c->next[i]=NULL;
+ if (p) p->next[i]=c;
+ p=c;
+ if (!head) head=c;
+ }
+ if (a) {
+ c->next[i]=a;
+ a->prev[i]=c;
+ } else if (b) {
+ c->next[i]=b;
+ b->prev[i]=c;
+ }
+ return head;
+}
+
+#if defined(TEST_MERGESORT) || defined(TEST_SORTED)
+static int
+test_sorted(PixelList *pl[3])
+{
+ int i,n,l;
+ PixelList *t;
+
+ for(i=0;i<3;i++) {
+ n=0;
+ l=256;
+ for (t=pl[i];t;t=t->next[i]) {
+ if (l<t->p.a.v[i]) return 0;
+ l=t->p.a.v[i];
+ }
+ }
+ return 1;
+}
+#endif
+
+static int
+box_heap_cmp(const Heap *h, const void *A, const void *B)
+{
+ BoxNode *a=(BoxNode *)A;
+ BoxNode *b=(BoxNode *)B;
+ return (int)a->pixelCount-(int)b->pixelCount;
+}
+
+#define LUMINANCE(p) (77*(p)->c.r+150*(p)->c.g+29*(p)->c.b)
+
+static int
+splitlists(PixelList *h[3],
+ PixelList *t[3],
+ PixelList *nh[2][3],
+ PixelList *nt[2][3],
+ uint32_t nCount[2],
+ int axis,
+ uint32_t pixelCount)
+{
+ uint32_t left;
+
+ PixelList *l,*r,*c,*n;
+ int i;
+ int nRight,nLeft;
+ int splitColourVal;
+
+#ifdef TEST_SPLIT
+ {
+ PixelList *_prevTest,*_nextTest;
+ int _i,_nextCount[3],_prevCount[3];
+ for (_i=0;_i<3;_i++) {
+ for (_nextCount[_i]=0,_nextTest=h[_i];_nextTest&&_nextTest->next[_i];_nextTest=_nextTest->next[_i],_nextCount[_i]++);
+ for (_prevCount[_i]=0,_prevTest=t[_i];_prevTest&&_prevTest->prev[_i];_prevTest=_prevTest->prev[_i],_prevCount[_i]++);
+ if (_nextTest!=t[_i]) {
+ printf ("next-list of axis %d does not end at tail\n",_i);
+ exit(1);
+ }
+ if (_prevTest!=h[_i]) {
+ printf ("prev-list of axis %d does not end at head\n",_i);
+ exit(1);
+ }
+ for (;_nextTest&&_nextTest->prev[_i];_nextTest=_nextTest->prev[_i]);
+ for (;_prevTest&&_prevTest->next[_i];_prevTest=_prevTest->next[_i]);
+ if (_nextTest!=h[_i]) {
+ printf ("next-list of axis %d does not loop back to head\n",_i);
+ exit(1);
+ }
+ if (_prevTest!=t[_i]) {
+ printf ("prev-list of axis %d does not loop back to tail\n",_i);
+ exit(1);
+ }
+ }
+ for (_i=1;_i<3;_i++) {
+ if (_prevCount[_i]!=_prevCount[_i-1] ||
+ _nextCount[_i]!=_nextCount[_i-1] ||
+ _prevCount[_i]!=_nextCount[_i]) {
+ printf ("{%d %d %d} {%d %d %d}\n",
+ _prevCount[0],
+ _prevCount[1],
+ _prevCount[2],
+ _nextCount[0],
+ _nextCount[1],
+ _nextCount[2]);
+ exit(1);
+ }
+ }
+ }
+#endif
+ nCount[0]=nCount[1]=0;
+ nLeft=nRight=0;
+ for (left=0,c=h[axis];c;) {
+ left=left+c->count;
+ nCount[0]+=c->count;
+ c->flag=0;
+ nLeft++;
+ c=c->next[axis];
+ if (left*2>pixelCount) {
+ break;
+ }
+ }
+ if (c) {
+ splitColourVal=c->prev[axis]->p.a.v[axis];
+ for (;c;c=c->next[axis]) {
+ if (splitColourVal!=c->p.a.v[axis]) {
+ break;
+ }
+ c->flag=0;
+ nLeft++;
+ nCount[0]+=c->count;
+ }
+ }
+ for (;c;c=c->next[axis]) {
+ c->flag=1;
+ nRight++;
+ nCount[1]+=c->count;
+ }
+ if (!nRight) {
+ for (c=t[axis],splitColourVal=t[axis]->p.a.v[axis];c;c=c->prev[axis]) {
+ if (splitColourVal!=c->p.a.v[axis]) {
+ break;
+ }
+ c->flag=1;
+ nRight++;
+ nLeft--;
+ nCount[0]-=c->count;
+ nCount[1]+=c->count;
+ }
+ }
+#ifndef NO_OUTPUT
+ if (!nLeft) {
+ for (c=h[axis];c;c=c->next[axis]) {
+ printf ("[%d %d %d]\n",c->p.c.r,c->p.c.g,c->p.c.b);
+ }
+ printf ("warning... trivial split\n");
+ }
+#endif
+
+ for (i=0;i<3;i++) {
+ l=r=NULL;
+ nh[0][i]=nt[0][i]=NULL;
+ nh[1][i]=nt[1][i]=NULL;
+ for (c=h[i];c;c=n) {
+ n=c->next[i];
+ if (c->flag) { /* move pixel to right list*/
+ if (r) r->next[i]=c; else nh[1][i]=c;
+ c->prev[i]=r;
+ r=c;
+ } else { /* move pixel to left list */
+ if (l) l->next[i]=c; else nh[0][i]=c;
+ c->prev[i]=l;
+ l=c;
+ }
+ }
+ if (l) l->next[i]=NULL;
+ if (r) r->next[i]=NULL;
+ nt[0][i]=l;
+ nt[1][i]=r;
+ }
+ return 1;
+}
+
+static int
+split(BoxNode *node)
+{
+ unsigned char rl,rh,gl,gh,bl,bh;
+ int f[3];
+ int best,axis;
+ int i;
+ PixelList *heads[2][3];
+ PixelList *tails[2][3];
+ uint32_t newCounts[2];
+ BoxNode *left,*right;
+
+ rh=node->head[0]->p.c.r;
+ rl=node->tail[0]->p.c.r;
+ gh=node->head[1]->p.c.g;
+ gl=node->tail[1]->p.c.g;
+ bh=node->head[2]->p.c.b;
+ bl=node->tail[2]->p.c.b;
+#ifdef TEST_SPLIT
+ printf ("splitting node [%d %d %d] [%d %d %d] ",rl,gl,bl,rh,gh,bh);
+#endif
+ f[0]=(rh-rl)*77;
+ f[1]=(gh-gl)*150;
+ f[2]=(bh-bl)*29;
+
+ best=f[0];
+ axis=0;
+ for (i=1;i<3;i++) {
+ if (best<f[i]) { best=f[i]; axis=i; }
+ }
+#ifdef TEST_SPLIT
+ printf ("along axis %d\n",axis+1);
+#endif
+
+#ifdef TEST_SPLIT
+ {
+ PixelList *_prevTest,*_nextTest;
+ int _i,_nextCount[3],_prevCount[3];
+ for (_i=0;_i<3;_i++) {
+ if (node->tail[_i]->next[_i]) {
+ printf ("tail is not tail\n");
+ printf ("node->tail[%d]->next[%d]=%p\n",_i,_i,node->tail[_i]->next[_i]);
+ }
+ if (node->head[_i]->prev[_i]) {
+ printf ("head is not head\n");
+ printf ("node->head[%d]->prev[%d]=%p\n",_i,_i,node->head[_i]->prev[_i]);
+ }
+ }
+
+ for (_i=0;_i<3;_i++) {
+ for (_nextCount[_i]=0,_nextTest=node->head[_i];_nextTest&&_nextTest->next[_i];_nextTest=_nextTest->next[_i],_nextCount[_i]++);
+ for (_prevCount[_i]=0,_prevTest=node->tail[_i];_prevTest&&_prevTest->prev[_i];_prevTest=_prevTest->prev[_i],_prevCount[_i]++);
+ if (_nextTest!=node->tail[_i]) {
+ printf ("next-list of axis %d does not end at tail\n",_i);
+ }
+ if (_prevTest!=node->head[_i]) {
+ printf ("prev-list of axis %d does not end at head\n",_i);
+ }
+ for (;_nextTest&&_nextTest->prev[_i];_nextTest=_nextTest->prev[_i]);
+ for (;_prevTest&&_prevTest->next[_i];_prevTest=_prevTest->next[_i]);
+ if (_nextTest!=node->head[_i]) {
+ printf ("next-list of axis %d does not loop back to head\n",_i);
+ }
+ if (_prevTest!=node->tail[_i]) {
+ printf ("prev-list of axis %d does not loop back to tail\n",_i);
+ }
+ }
+ for (_i=1;_i<3;_i++) {
+ if (_prevCount[_i]!=_prevCount[_i-1] ||
+ _nextCount[_i]!=_nextCount[_i-1] ||
+ _prevCount[_i]!=_nextCount[_i]) {
+ printf ("{%d %d %d} {%d %d %d}\n",
+ _prevCount[0],
+ _prevCount[1],
+ _prevCount[2],
+ _nextCount[0],
+ _nextCount[1],
+ _nextCount[2]);
+ }
+ }
+ }
+#endif
+ node->axis=axis;
+ if (!splitlists(node->head,
+ node->tail,
+ heads,
+ tails,
+ newCounts,
+ axis,
+ node->pixelCount)) {
+#ifndef NO_OUTPUT
+ printf ("list split failed.\n");
+#endif
+ return 0;
+ }
+#ifdef TEST_SPLIT
+ if (!test_sorted(heads[0])) {
+ printf ("bug in split");
+ exit(1);
+ }
+ if (!test_sorted(heads[1])) {
+ printf ("bug in split");
+ exit(1);
+ }
+#endif
+ /* malloc check ok, small constant allocation */
+ left=malloc(sizeof(BoxNode));
+ right=malloc(sizeof(BoxNode));
+ if (!left||!right) {
+ free(left);
+ free(right);
+ return 0;
+ }
+ for(i=0;i<3;i++) {
+ left->head[i]=heads[0][i];
+ left->tail[i]=tails[0][i];
+ right->head[i]=heads[1][i];
+ right->tail[i]=tails[1][i];
+ node->head[i]=NULL;
+ node->tail[i]=NULL;
+ }
+#ifdef TEST_SPLIT
+ if (left->head[0]) {
+ rh=left->head[0]->p.c.r;
+ rl=left->tail[0]->p.c.r;
+ gh=left->head[1]->p.c.g;
+ gl=left->tail[1]->p.c.g;
+ bh=left->head[2]->p.c.b;
+ bl=left->tail[2]->p.c.b;
+ printf (" left node [%3d %3d %3d] [%3d %3d %3d]\n",rl,gl,bl,rh,gh,bh);
+ }
+ if (right->head[0]) {
+ rh=right->head[0]->p.c.r;
+ rl=right->tail[0]->p.c.r;
+ gh=right->head[1]->p.c.g;
+ gl=right->tail[1]->p.c.g;
+ bh=right->head[2]->p.c.b;
+ bl=right->tail[2]->p.c.b;
+ printf (" right node [%3d %3d %3d] [%3d %3d %3d]\n",rl,gl,bl,rh,gh,bh);
+ }
+#endif
+ left->l=left->r=NULL;
+ right->l=right->r=NULL;
+ left->axis=right->axis=-1;
+ left->volume=right->volume=-1;
+ left->pixelCount=newCounts[0];
+ right->pixelCount=newCounts[1];
+ node->l=left;
+ node->r=right;
+ return 1;
+}
+
+static BoxNode *
+median_cut(PixelList *hl[3],
+ uint32_t imPixelCount,
+ int nPixels)
+{
+ PixelList *tl[3];
+ int i;
+ BoxNode *root;
+ Heap* h;
+ BoxNode *thisNode;
+
+ h=ImagingQuantHeapNew(box_heap_cmp);
+ /* malloc check ok, small constant allocation */
+ root=malloc(sizeof(BoxNode));
+ if (!root) { ImagingQuantHeapFree(h); return NULL; }
+ for(i=0;i<3;i++) {
+ for (tl[i]=hl[i];tl[i]&&tl[i]->next[i];tl[i]=tl[i]->next[i]);
+ root->head[i]=hl[i];
+ root->tail[i]=tl[i];
+ }
+ root->l=root->r=NULL;
+ root->axis=-1;
+ root->volume=-1;
+ root->pixelCount=imPixelCount;
+
+ ImagingQuantHeapAdd(h,(void *)root);
+ while (--nPixels) {
+ do {
+ if (!ImagingQuantHeapRemove(h,(void **)&thisNode)) {
+ goto done;
+ }
+ } while (compute_box_volume(thisNode)==1);
+ if (!split(thisNode)) {
+#ifndef NO_OUTPUT
+ printf ("Oops, split failed...\n");
+#endif
+ exit (1);
+ }
+ ImagingQuantHeapAdd(h,(void *)(thisNode->l));
+ ImagingQuantHeapAdd(h,(void *)(thisNode->r));
+ }
+done:
+ ImagingQuantHeapFree(h);
+ return root;
+}
+
+static void
+free_box_tree(BoxNode *n)
+{
+ PixelList *p,*pp;
+ if (n->l) free_box_tree(n->l);
+ if (n->r) free_box_tree(n->r);
+ for (p=n->head[0];p;p=pp) {
+ pp=p->next[0];
+ free(p);
+ }
+ free(n);
+}
+
+#ifdef TEST_SPLIT_INTEGRITY
+static int
+checkContained(BoxNode *n,Pixel *pp)
+{
+ if (n->l&&n->r) {
+ return checkContained(n->l,pp)+checkContained(n->r,pp);
+ }
+ if (n->l||n->r) {
+#ifndef NO_OUTPUT
+ printf ("box tree is dead\n");
+#endif
+ return 0;
+ }
+ if (
+ pp->c.r<=n->head[0]->p.c.r &&
+ pp->c.r>=n->tail[0]->p.c.r &&
+ pp->c.g<=n->head[1]->p.c.g &&
+ pp->c.g>=n->tail[1]->p.c.g &&
+ pp->c.b<=n->head[2]->p.c.b &&
+ pp->c.b>=n->tail[2]->p.c.b) {
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static int
+annotate_hash_table(BoxNode *n,HashTable *h,uint32_t *box)
+{
+ PixelList *p;
+ PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h);
+ Pixel q;
+ if (n->l&&n->r) {
+ return annotate_hash_table(n->l,h,box) && annotate_hash_table(n->r,h,box);
+ }
+ if (n->l||n->r) {
+#ifndef NO_OUTPUT
+ printf ("box tree is dead\n");
+#endif
+ return 0;
+ }
+ for (p=n->head[0];p;p=p->next[0]) {
+ PIXEL_UNSCALE(&(p->p),&q,d->scale);
+ if (!hashtable_insert(h,q,*box)) {
+#ifndef NO_OUTPUT
+ printf ("hashtable insert failed\n");
+#endif
+ return 0;
+ }
+ }
+ if (n->head[0]) (*box)++;
+ return 1;
+}
+
+static int
+_sort_ulong_ptr_keys(const void *a, const void *b)
+{
+ uint32_t A=**(uint32_t **)a;
+ uint32_t B=**(uint32_t **)b;
+ return (A==B)?0:((A<B)?-1:+1);
+}
+
+static int
+resort_distance_tables(uint32_t *avgDist,
+ uint32_t **avgDistSortKey,
+ Pixel *p,
+ uint32_t nEntries)
+{
+ uint32_t i,j,k;
+ uint32_t **skRow;
+ uint32_t *skElt;
+
+ for (i=0;i<nEntries;i++) {
+ avgDist[i*nEntries+i]=0;
+ for (j=0;j<i;j++) {
+ avgDist[j*nEntries+i]=
+ avgDist[i*nEntries+j]=_DISTSQR(p+i,p+j);
+ }
+ }
+ for (i=0;i<nEntries;i++) {
+ skRow=avgDistSortKey+i*nEntries;
+ for (j=1;j<nEntries;j++) {
+ skElt=skRow[j];
+ for (k=j;k&&(*(skRow[k-1])>*(skRow[k]));k--) {
+ skRow[k]=skRow[k-1];
+ }
+ if (k!=j) skRow[k]=skElt;
+ }
+ }
+ return 1;
+}
+
+static int
+build_distance_tables(uint32_t *avgDist,
+ uint32_t **avgDistSortKey,
+ Pixel *p,
+ uint32_t nEntries)
+{
+ uint32_t i,j;
+
+ for (i=0;i<nEntries;i++) {
+ avgDist[i*nEntries+i]=0;
+ avgDistSortKey[i*nEntries+i]=&(avgDist[i*nEntries+i]);
+ for (j=0;j<i;j++) {
+ avgDist[j*nEntries+i]=
+ avgDist[i*nEntries+j]=_DISTSQR(p+i,p+j);
+ avgDistSortKey[j*nEntries+i]=&(avgDist[j*nEntries+i]);
+ avgDistSortKey[i*nEntries+j]=&(avgDist[i*nEntries+j]);
+ }
+ }
+ for (i=0;i<nEntries;i++) {
+ qsort(avgDistSortKey+i*nEntries,
+ nEntries,
+ sizeof(uint32_t *),
+ _sort_ulong_ptr_keys);
+ }
+ return 1;
+}
+
+static int
+map_image_pixels(Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *paletteData,
+ uint32_t nPaletteEntries,
+ uint32_t *avgDist,
+ uint32_t **avgDistSortKey,
+ uint32_t *pixelArray)
+{
+ uint32_t *aD,**aDSK;
+ uint32_t idx;
+ uint32_t i,j;
+ uint32_t bestdist,bestmatch,dist;
+ uint32_t initialdist;
+ HashTable *h2;
+
+ h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
+ for (i=0;i<nPixels;i++) {
+ if (!hashtable_lookup(h2,pixelData[i],&bestmatch)) {
+ bestmatch=0;
+ initialdist=_DISTSQR(paletteData+bestmatch,pixelData+i);
+ bestdist=initialdist;
+ initialdist<<=2;
+ aDSK=avgDistSortKey+bestmatch*nPaletteEntries;
+ aD=avgDist+bestmatch*nPaletteEntries;
+ for (j=0;j<nPaletteEntries;j++) {
+ idx=aDSK[j]-aD;
+ if (*(aDSK[j])<=initialdist) {
+ dist=_DISTSQR(paletteData+idx,pixelData+i);
+ if (dist<bestdist) {
+ bestdist=dist;
+ bestmatch=idx;
+ }
+ } else {
+ break;
+ }
+ }
+ hashtable_insert(h2,pixelData[i],bestmatch);
+ }
+ pixelArray[i]=bestmatch;
+ }
+ hashtable_free(h2);
+ return 1;
+}
+
+static int
+map_image_pixels_from_quantized_pixels(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *paletteData,
+ uint32_t nPaletteEntries,
+ uint32_t *avgDist,
+ uint32_t **avgDistSortKey,
+ uint32_t *pixelArray,
+ uint32_t *avg[3],
+ uint32_t *count)
+{
+ uint32_t *aD,**aDSK;
+ uint32_t idx;
+ uint32_t i,j;
+ uint32_t bestdist,bestmatch,dist;
+ uint32_t initialdist;
+ HashTable *h2;
+ int changes=0;
+
+ h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
+ for (i=0;i<nPixels;i++) {
+ if (!hashtable_lookup(h2,pixelData[i],&bestmatch)) {
+ bestmatch=pixelArray[i];
+ initialdist=_DISTSQR(paletteData+bestmatch,pixelData+i);
+ bestdist=initialdist;
+ initialdist<<=2;
+ aDSK=avgDistSortKey+bestmatch*nPaletteEntries;
+ aD=avgDist+bestmatch*nPaletteEntries;
+ for (j=0;j<nPaletteEntries;j++) {
+ idx=aDSK[j]-aD;
+ if (*(aDSK[j])<=initialdist) {
+ dist=_DISTSQR(paletteData+idx,pixelData+i);
+ if (dist<bestdist) {
+ bestdist=dist;
+ bestmatch=idx;
+ }
+ } else {
+ break;
+ }
+ }
+ hashtable_insert(h2,pixelData[i],bestmatch);
+ }
+ if (pixelArray[i]!=bestmatch) {
+ changes++;
+ avg[0][bestmatch]+=pixelData[i].c.r;
+ avg[1][bestmatch]+=pixelData[i].c.g;
+ avg[2][bestmatch]+=pixelData[i].c.b;
+ avg[0][pixelArray[i]]-=pixelData[i].c.r;
+ avg[1][pixelArray[i]]-=pixelData[i].c.g;
+ avg[2][pixelArray[i]]-=pixelData[i].c.b;
+ count[bestmatch]++;
+ count[pixelArray[i]]--;
+ pixelArray[i]=bestmatch;
+ }
+ }
+ hashtable_free(h2);
+ return changes;
+}
+
+static int
+map_image_pixels_from_median_box(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *paletteData,
+ uint32_t nPaletteEntries,
+ HashTable *medianBoxHash,
+ uint32_t *avgDist,
+ uint32_t **avgDistSortKey,
+ uint32_t *pixelArray)
+{
+ uint32_t *aD,**aDSK;
+ uint32_t idx;
+ uint32_t i,j;
+ uint32_t bestdist,bestmatch,dist;
+ uint32_t initialdist;
+ HashTable *h2;
+ uint32_t pixelVal;
+
+ h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
+ for (i=0;i<nPixels;i++) {
+ if (hashtable_lookup(h2,pixelData[i],&pixelVal)) {
+ pixelArray[i]=pixelVal;
+ continue;
+ }
+ if (!hashtable_lookup(medianBoxHash,pixelData[i],&pixelVal)) {
+#ifndef NO_OUTPUT
+ printf ("pixel lookup failed\n");
+#endif
+ return 0;
+ }
+ initialdist=_DISTSQR(paletteData+pixelVal,pixelData+i);
+ bestdist=initialdist;
+ bestmatch=pixelVal;
+ initialdist<<=2;
+ aDSK=avgDistSortKey+pixelVal*nPaletteEntries;
+ aD=avgDist+pixelVal*nPaletteEntries;
+ for (j=0;j<nPaletteEntries;j++) {
+ idx=aDSK[j]-aD;
+ if (*(aDSK[j])<=initialdist) {
+ dist=_DISTSQR(paletteData+idx,pixelData+i);
+ if (dist<bestdist) {
+ bestdist=dist;
+ bestmatch=idx;
+ }
+ } else {
+ break;
+ }
+ }
+ pixelArray[i]=bestmatch;
+ hashtable_insert(h2,pixelData[i],bestmatch);
+ }
+ hashtable_free(h2);
+ return 1;
+}
+
+static int
+compute_palette_from_median_cut(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ HashTable *medianBoxHash,
+ Pixel **palette,
+ uint32_t nPaletteEntries)
+{
+ uint32_t i;
+ uint32_t paletteEntry;
+ Pixel *p;
+ uint32_t *avg[3];
+ uint32_t *count;
+
+ *palette=NULL;
+ /* malloc check ok, using calloc */
+ if (!(count=calloc(nPaletteEntries, sizeof(uint32_t)))) {
+ return 0;
+ }
+ for(i=0;i<3;i++) {
+ avg[i]=NULL;
+ }
+ for(i=0;i<3;i++) {
+ /* malloc check ok, using calloc */
+ if (!(avg[i]=calloc(nPaletteEntries, sizeof(uint32_t)))) {
+ for(i=0;i<3;i++) {
+ if (avg[i]) free (avg[i]);
+ }
+ free(count);
+ return 0;
+ }
+ }
+ for (i=0;i<nPixels;i++) {
+#ifdef TEST_SPLIT_INTEGRITY
+ if (!(i%100)) { printf ("%05d\r",i); fflush(stdout); }
+ if (checkContained(root,pixelData+i)>1) {
+ printf ("pixel in two boxes\n");
+ for(i=0;i<3;i++) free (avg[i]);
+ free(count);
+ return 0;
+ }
+#endif
+ if (!hashtable_lookup(medianBoxHash,pixelData[i],&paletteEntry)) {
+#ifndef NO_OUTPUT
+ printf ("pixel lookup failed\n");
+#endif
+ for(i=0;i<3;i++) free (avg[i]);
+ free(count);
+ return 0;
+ }
+ if (paletteEntry>=nPaletteEntries) {
+#ifndef NO_OUTPUT
+ printf ("panic - paletteEntry>=nPaletteEntries (%d>=%d)\n",(int)paletteEntry,(int)nPaletteEntries);
+#endif
+ for(i=0;i<3;i++) free (avg[i]);
+ free(count);
+ return 0;
+ }
+ avg[0][paletteEntry]+=pixelData[i].c.r;
+ avg[1][paletteEntry]+=pixelData[i].c.g;
+ avg[2][paletteEntry]+=pixelData[i].c.b;
+ count[paletteEntry]++;
+ }
+ /* malloc check ok, using calloc */
+ p=calloc(nPaletteEntries, sizeof(Pixel));
+ if (!p) {
+ for(i=0;i<3;i++) free (avg[i]);
+ free(count);
+ return 0;
+ }
+ for (i=0;i<nPaletteEntries;i++) {
+ p[i].c.r=(int)(.5+(double)avg[0][i]/(double)count[i]);
+ p[i].c.g=(int)(.5+(double)avg[1][i]/(double)count[i]);
+ p[i].c.b=(int)(.5+(double)avg[2][i]/(double)count[i]);
+ }
+ *palette=p;
+ for(i=0;i<3;i++) free (avg[i]);
+ free(count);
+ return 1;
+}
+
+static int
+recompute_palette_from_averages(
+ Pixel *palette,
+ uint32_t nPaletteEntries,
+ uint32_t *avg[3],
+ uint32_t *count)
+{
+ uint32_t i;
+
+ for (i=0;i<nPaletteEntries;i++) {
+ palette[i].c.r=(int)(.5+(double)avg[0][i]/(double)count[i]);
+ palette[i].c.g=(int)(.5+(double)avg[1][i]/(double)count[i]);
+ palette[i].c.b=(int)(.5+(double)avg[2][i]/(double)count[i]);
+ }
+ return 1;
+}
+
+static int
+compute_palette_from_quantized_pixels(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *palette,
+ uint32_t nPaletteEntries,
+ uint32_t *avg[3],
+ uint32_t *count,
+ uint32_t *qp)
+{
+ uint32_t i;
+
+ memset(count,0,sizeof(uint32_t)*nPaletteEntries);
+ for(i=0;i<3;i++) {
+ memset(avg[i],0,sizeof(uint32_t)*nPaletteEntries);
+ }
+ for (i=0;i<nPixels;i++) {
+ if (qp[i]>=nPaletteEntries) {
+#ifndef NO_OUTPUT
+ printf ("scream\n");
+#endif
+ return 0;
+ }
+ avg[0][qp[i]]+=pixelData[i].c.r;
+ avg[1][qp[i]]+=pixelData[i].c.g;
+ avg[2][qp[i]]+=pixelData[i].c.b;
+ count[qp[i]]++;
+ }
+ for (i=0;i<nPaletteEntries;i++) {
+ palette[i].c.r=(int)(.5+(double)avg[0][i]/(double)count[i]);
+ palette[i].c.g=(int)(.5+(double)avg[1][i]/(double)count[i]);
+ palette[i].c.b=(int)(.5+(double)avg[2][i]/(double)count[i]);
+ }
+ return 1;
+}
+
+static int
+k_means(Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *paletteData,
+ uint32_t nPaletteEntries,
+ uint32_t *qp,
+ int threshold)
+{
+ uint32_t *avg[3];
+ uint32_t *count;
+ uint32_t i;
+ uint32_t *avgDist;
+ uint32_t **avgDistSortKey;
+ int changes;
+ int built=0;
+
+ if (nPaletteEntries > UINT32_MAX / (sizeof(uint32_t))) {
+ return 0;
+ }
+ /* malloc check ok, using calloc */
+ if (!(count=calloc(nPaletteEntries, sizeof(uint32_t)))) {
+ return 0;
+ }
+ for(i=0;i<3;i++) {
+ avg[i]=NULL;
+ }
+ for(i=0;i<3;i++) {
+ /* malloc check ok, using calloc */
+ if (!(avg[i]=calloc(nPaletteEntries, sizeof(uint32_t)))) {
+ goto error_1;
+ }
+ }
+
+ /* this is enough of a check, since the multiplication n*size is done above */
+ if (nPaletteEntries > UINT32_MAX / nPaletteEntries) {
+ goto error_1;
+ }
+ /* malloc check ok, using calloc, checking n*n above */
+ avgDist=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t));
+ if (!avgDist) { goto error_1; }
+
+ /* malloc check ok, using calloc, checking n*n above */
+ avgDistSortKey=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t *));
+ if (!avgDistSortKey) { goto error_2; }
+
+#ifndef NO_OUTPUT
+ printf("[");fflush(stdout);
+#endif
+ while (1) {
+ if (!built) {
+ compute_palette_from_quantized_pixels(pixelData,nPixels,paletteData,nPaletteEntries,avg,count,qp);
+ build_distance_tables(avgDist,avgDistSortKey,paletteData,nPaletteEntries);
+ built=1;
+ } else {
+ recompute_palette_from_averages(paletteData,nPaletteEntries,avg,count);
+ resort_distance_tables(avgDist,avgDistSortKey,paletteData,nPaletteEntries);
+ }
+ changes=map_image_pixels_from_quantized_pixels(pixelData,
+ nPixels,
+ paletteData,
+ nPaletteEntries,
+ avgDist,
+ avgDistSortKey,
+ qp,
+ avg,
+ count);
+ if (changes<0) {
+ goto error_3;
+ }
+#ifndef NO_OUTPUT
+ printf (".(%d)",changes);fflush(stdout);
+#endif
+ if (changes<=threshold) break;
+ }
+#ifndef NO_OUTPUT
+ printf("]\n");
+#endif
+ if (avgDistSortKey) free(avgDistSortKey);
+ if (avgDist) free(avgDist);
+ for(i=0;i<3;i++) if (avg[i]) free (avg[i]);
+ if (count) free(count);
+ return 1;
+
+error_3:
+ if (avgDistSortKey) free(avgDistSortKey);
+error_2:
+ if (avgDist) free(avgDist);
+error_1:
+ for(i=0;i<3;i++) if (avg[i]) free (avg[i]);
+ if (count) free(count);
+ return 0;
+}
+
+int
+quantize(Pixel *pixelData,
+ uint32_t nPixels,
+ uint32_t nQuantPixels,
+ Pixel **palette,
+ uint32_t *paletteLength,
+ uint32_t **quantizedPixels,
+ int kmeans)
+{
+ PixelList *hl[3];
+ HashTable *h;
+ BoxNode *root;
+ uint32_t i;
+ uint32_t *qp;
+ uint32_t nPaletteEntries;
+
+ uint32_t *avgDist;
+ uint32_t **avgDistSortKey;
+ Pixel *p;
+
+#ifndef NO_OUTPUT
+ uint32_t timer,timer2;
+#endif
+
+#ifndef NO_OUTPUT
+ timer2=clock();
+ printf ("create hash table..."); fflush(stdout); timer=clock();
+#endif
+ h=create_pixel_hash(pixelData,nPixels);
+#ifndef NO_OUTPUT
+ printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+#endif
+ if (!h) {
+ goto error_0;
+ }
+
+#ifndef NO_OUTPUT
+ printf ("create lists from hash table..."); fflush(stdout); timer=clock();
+#endif
+ hl[0]=hl[1]=hl[2]=NULL;
+ hashtable_foreach(h,hash_to_list,hl);
+#ifndef NO_OUTPUT
+ printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+#endif
+
+ if (!hl[0]) {
+ goto error_1;
+ }
+
+#ifndef NO_OUTPUT
+ printf ("mergesort lists..."); fflush(stdout); timer=clock();
+#endif
+ for(i=0;i<3;i++) {
+ hl[i]=mergesort_pixels(hl[i],i);
+ }
+#ifdef TEST_MERGESORT
+ if (!test_sorted(hl)) {
+ printf ("bug in mergesort\n");
+ goto error_1;
+ }
+#endif
+#ifndef NO_OUTPUT
+ printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+#endif
+
+#ifndef NO_OUTPUT
+ printf ("median cut..."); fflush(stdout); timer=clock();
+#endif
+ root=median_cut(hl,nPixels,nQuantPixels);
+#ifndef NO_OUTPUT
+ printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+#endif
+ if (!root) {
+ goto error_1;
+ }
+ nPaletteEntries=0;
+#ifndef NO_OUTPUT
+ printf ("median cut tree to hash table..."); fflush(stdout); timer=clock();
+#endif
+ annotate_hash_table(root,h,&nPaletteEntries);
+#ifndef NO_OUTPUT
+ printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+#endif
+#ifndef NO_OUTPUT
+ printf ("compute palette...\n"); fflush(stdout); timer=clock();
+#endif
+ if (!compute_palette_from_median_cut(pixelData,nPixels,h,&p,nPaletteEntries)) {
+ goto error_3;
+ }
+#ifndef NO_OUTPUT
+ printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+#endif
+
+ free_box_tree(root);
+ root=NULL;
+
+ /* malloc check ok, using calloc for overflow */
+ qp=calloc(nPixels, sizeof(uint32_t));
+ if (!qp) { goto error_4; }
+
+ if (nPaletteEntries > UINT32_MAX / nPaletteEntries ) {
+ goto error_5;
+ }
+ /* malloc check ok, using calloc for overflow, check of n*n above */
+ avgDist=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t));
+ if (!avgDist) { goto error_5; }
+
+ /* malloc check ok, using calloc for overflow, check of n*n above */
+ avgDistSortKey=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t *));
+ if (!avgDistSortKey) { goto error_6; }
+
+ if (!build_distance_tables(avgDist,avgDistSortKey,p,nPaletteEntries)) {
+ goto error_7;
+ }
+
+ if (!map_image_pixels_from_median_box(pixelData,nPixels,p,nPaletteEntries,h,avgDist,avgDistSortKey,qp)) {
+ goto error_7;
+ }
+
+#ifdef TEST_NEAREST_NEIGHBOUR
+#include <math.h>
+ {
+ uint32_t bestmatch,bestdist,dist;
+ HashTable *h2;
+ printf ("nearest neighbour search (full search)..."); fflush(stdout); timer=clock();
+ h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
+ for (i=0;i<nPixels;i++) {
+ if (hashtable_lookup(h2,pixelData[i],&paletteEntry)) {
+ bestmatch=paletteEntry;
+ } else {
+ bestmatch=0;
+ bestdist=
+ _SQR(pixelData[i].c.r-p[0].c.r)+
+ _SQR(pixelData[i].c.g-p[0].c.g)+
+ _SQR(pixelData[i].c.b-p[0].c.b);
+ for (j=1;j<nPaletteEntries;j++) {
+ dist=
+ _SQR(pixelData[i].c.r-p[j].c.r)+
+ _SQR(pixelData[i].c.g-p[j].c.g)+
+ _SQR(pixelData[i].c.b-p[j].c.b);
+ if (dist==bestdist && j==qp[i]) {
+ bestmatch=j;
+ }
+ if (dist<bestdist) {
+ bestdist=dist;
+ bestmatch=j;
+ }
+ }
+ hashtable_insert(h2,pixelData[i],bestmatch);
+ }
+ if (qp[i]!=bestmatch ) {
+ printf ("discrepancy in matching algorithms pixel %d [%d %d] %f %f\n",
+ i,qp[i],bestmatch,
+ sqrt((double)(_SQR(pixelData[i].c.r-p[qp[i]].c.r)+
+ _SQR(pixelData[i].c.g-p[qp[i]].c.g)+
+ _SQR(pixelData[i].c.b-p[qp[i]].c.b))),
+ sqrt((double)(_SQR(pixelData[i].c.r-p[bestmatch].c.r)+
+ _SQR(pixelData[i].c.g-p[bestmatch].c.g)+
+ _SQR(pixelData[i].c.b-p[bestmatch].c.b)))
+ );
+ }
+ }
+ hashtable_free(h2);
+ }
+#endif
+#ifndef NO_OUTPUT
+ printf ("k means...\n"); fflush(stdout); timer=clock();
+#endif
+ if (kmeans) k_means(pixelData,nPixels,p,nPaletteEntries,qp,kmeans-1);
+#ifndef NO_OUTPUT
+ printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+#endif
+
+ *quantizedPixels=qp;
+ *palette=p;
+ *paletteLength=nPaletteEntries;
+
+#ifndef NO_OUTPUT
+ printf ("cleanup..."); fflush(stdout); timer=clock();
+#endif
+ if (avgDist) free(avgDist);
+ if (avgDistSortKey) free(avgDistSortKey);
+ destroy_pixel_hash(h);
+#ifndef NO_OUTPUT
+ printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC);
+ printf ("-----\ntotal time %f\n",(clock()-timer2)/(double)CLOCKS_PER_SEC);
+#endif
+ return 1;
+
+error_7:
+ if (avgDistSortKey) free(avgDistSortKey);
+error_6:
+ if (avgDist) free(avgDist);
+error_5:
+ if (qp) free(qp);
+error_4:
+ if (p) free(p);
+error_3:
+ if (root) free_box_tree(root);
+error_1:
+ destroy_pixel_hash(h);
+error_0:
+ *quantizedPixels=NULL;
+ *paletteLength=0;
+ *palette=NULL;
+ return 0;
+}
+
+typedef struct {
+ Pixel new;
+ Pixel furthest;
+ uint32_t furthestDistance;
+ int secondPixel;
+} DistanceData;
+
+static void
+compute_distances(const HashTable *h, const Pixel pixel, uint32_t *dist, void *u)
+{
+ DistanceData *data=(DistanceData *)u;
+ uint32_t oldDist=*dist;
+ uint32_t newDist;
+ newDist=_DISTSQR(&(data->new),&pixel);
+ if (data->secondPixel || newDist<oldDist) {
+ *dist=newDist;
+ oldDist=newDist;
+ }
+ if (oldDist>data->furthestDistance) {
+ data->furthestDistance=oldDist;
+ data->furthest.v=pixel.v;
+ }
+}
+
+int
+quantize2(Pixel *pixelData,
+ uint32_t nPixels,
+ uint32_t nQuantPixels,
+ Pixel **palette,
+ uint32_t *paletteLength,
+ uint32_t **quantizedPixels,
+ int kmeans)
+{
+ HashTable *h;
+ uint32_t i;
+ uint32_t mean[3];
+ Pixel *p;
+ DistanceData data;
+
+ uint32_t *qp;
+ uint32_t *avgDist;
+ uint32_t **avgDistSortKey;
+
+ /* malloc check ok, using calloc */
+ p=calloc(nQuantPixels, sizeof(Pixel));
+ if (!p) return 0;
+ mean[0]=mean[1]=mean[2]=0;
+ h=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
+ for (i=0;i<nPixels;i++) {
+ hashtable_insert(h,pixelData[i],0xffffffff);
+ mean[0]+=pixelData[i].c.r;
+ mean[1]+=pixelData[i].c.g;
+ mean[2]+=pixelData[i].c.b;
+ }
+ data.new.c.r=(int)(.5+(double)mean[0]/(double)nPixels);
+ data.new.c.g=(int)(.5+(double)mean[1]/(double)nPixels);
+ data.new.c.b=(int)(.5+(double)mean[2]/(double)nPixels);
+ for (i=0;i<nQuantPixels;i++) {
+ data.furthestDistance=0;
+ data.secondPixel=(i==1)?1:0;
+ hashtable_foreach_update(h,compute_distances,&data);
+ p[i].v=data.furthest.v;
+ data.new.v=data.furthest.v;
+ }
+ hashtable_free(h);
+
+ /* malloc check ok, using calloc */
+ qp=calloc(nPixels, sizeof(uint32_t));
+ if (!qp) { goto error_1; }
+
+ if (nQuantPixels > UINT32_MAX / nQuantPixels ) {
+ goto error_2;
+ }
+
+ /* malloc check ok, using calloc for overflow, check of n*n above */
+ avgDist=calloc(nQuantPixels*nQuantPixels, sizeof(uint32_t));
+ if (!avgDist) { goto error_2; }
+
+ /* malloc check ok, using calloc for overflow, check of n*n above */
+ avgDistSortKey=calloc(nQuantPixels*nQuantPixels, sizeof(uint32_t *));
+ if (!avgDistSortKey) { goto error_3; }
+
+ if (!build_distance_tables(avgDist,avgDistSortKey,p,nQuantPixels)) {
+ goto error_4;
+ }
+
+ if (!map_image_pixels(pixelData,nPixels,p,nQuantPixels,avgDist,avgDistSortKey,qp)) {
+ goto error_4;
+ }
+ if (kmeans) k_means(pixelData,nPixels,p,nQuantPixels,qp,kmeans-1);
+
+ *paletteLength=nQuantPixels;
+ *palette=p;
+ *quantizedPixels=qp;
+ free(avgDistSortKey);
+ free(avgDist);
+ return 1;
+
+error_4:
+ free(avgDistSortKey);
+error_3:
+ free(avgDist);
+error_2:
+ free(qp);
+error_1:
+ free(p);
+ return 0;
+}
+
+Imaging
+ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
+{
+ int i, j;
+ int x, y, v;
+ UINT8* pp;
+ Pixel* p;
+ Pixel* palette;
+ uint32_t paletteLength;
+ int result;
+ uint32_t* newData;
+ Imaging imOut;
+ int withAlpha = 0;
+ ImagingSectionCookie cookie;
+
+ if (!im)
+ return ImagingError_ModeError();
+ if (colors < 1 || colors > 256)
+ /* FIXME: for colors > 256, consider returning an RGB image
+ instead (see @PIL205) */
+ return (Imaging) ImagingError_ValueError("bad number of colors");
+
+ if (strcmp(im->mode, "L") != 0 && strcmp(im->mode, "P") != 0 &&
+ strcmp(im->mode, "RGB") != 0 && strcmp(im->mode, "RGBA") !=0)
+ return ImagingError_ModeError();
+
+ /* only octree and imagequant supports RGBA */
+ if (!strcmp(im->mode, "RGBA") && mode != 2 && mode != 3)
+ return ImagingError_ModeError();
+
+ if (im->xsize > INT_MAX / im->ysize) {
+ return ImagingError_MemoryError();
+ }
+ /* malloc check ok, using calloc for final overflow, x*y above */
+ p = calloc(im->xsize * im->ysize, sizeof(Pixel));
+ if (!p)
+ return ImagingError_MemoryError();
+
+ /* collect statistics */
+
+ /* FIXME: maybe we could load the hash tables directly from the
+ image data? */
+
+ if (!strcmp(im->mode, "L")) {
+ /* greyscale */
+
+ /* FIXME: converting a "L" image to "P" with 256 colors
+ should be done by a simple copy... */
+
+ for (i = y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->xsize; x++, i++) {
+ p[i].c.r = p[i].c.g = p[i].c.b = im->image8[y][x];
+ p[i].c.a = 255;
+ }
+
+ } else if (!strcmp(im->mode, "P")) {
+ /* palette */
+
+ pp = im->palette->palette;
+
+ for (i = y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->xsize; x++, i++) {
+ v = im->image8[y][x];
+ p[i].c.r = pp[v*4+0];
+ p[i].c.g = pp[v*4+1];
+ p[i].c.b = pp[v*4+2];
+ p[i].c.a = pp[v*4+3];
+ }
+
+ } else if (!strcmp(im->mode, "RGB") || !strcmp(im->mode, "RGBA")) {
+ /* true colour */
+
+ for (i = y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->xsize; x++, i++)
+ p[i].v = im->image32[y][x];
+
+ } else {
+ free(p);
+ return (Imaging) ImagingError_ValueError("internal error");
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ switch (mode) {
+ case 0:
+ /* median cut */
+ result = quantize(
+ p,
+ im->xsize*im->ysize,
+ colors,
+ &palette,
+ &paletteLength,
+ &newData,
+ kmeans
+ );
+ break;
+ case 1:
+ /* maximum coverage */
+ result = quantize2(
+ p,
+ im->xsize*im->ysize,
+ colors,
+ &palette,
+ &paletteLength,
+ &newData,
+ kmeans
+ );
+ break;
+ case 2:
+ if (!strcmp(im->mode, "RGBA")) {
+ withAlpha = 1;
+ }
+ result = quantize_octree(
+ p,
+ im->xsize*im->ysize,
+ colors,
+ &palette,
+ &paletteLength,
+ &newData,
+ withAlpha
+ );
+ break;
+ case 3:
+#ifdef HAVE_LIBIMAGEQUANT
+ if (!strcmp(im->mode, "RGBA")) {
+ withAlpha = 1;
+ }
+ result = quantize_pngquant(
+ p,
+ im->xsize,
+ im->ysize,
+ colors,
+ &palette,
+ &paletteLength,
+ &newData,
+ withAlpha
+ );
+#else
+ result = -1;
+#endif
+ break;
+ default:
+ result = 0;
+ break;
+ }
+
+ free(p);
+ ImagingSectionLeave(&cookie);
+
+ if (result > 0) {
+ imOut = ImagingNewDirty("P", im->xsize, im->ysize);
+ ImagingSectionEnter(&cookie);
+
+ for (i = y = 0; y < im->ysize; y++)
+ for (x = 0; x < im->xsize; x++)
+ imOut->image8[y][x] = (unsigned char) newData[i++];
+
+ free(newData);
+
+ pp = imOut->palette->palette;
+
+ for (i = j = 0; i < (int) paletteLength; i++) {
+ *pp++ = palette[i].c.r;
+ *pp++ = palette[i].c.g;
+ *pp++ = palette[i].c.b;
+ if (withAlpha) {
+ *pp++ = palette[i].c.a;
+ } else {
+ *pp++ = 255;
+ }
+ }
+ for (; i < 256; i++) {
+ *pp++ = 0;
+ *pp++ = 0;
+ *pp++ = 0;
+ *pp++ = 255;
+ }
+
+ if (withAlpha) {
+ strcpy(imOut->palette->mode, "RGBA");
+ }
+
+ free(palette);
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+
+ } else {
+
+ if (result == -1) {
+ return (Imaging) ImagingError_ValueError(
+ "dependency required by this method was not "
+ "enabled at compile time");
+ }
+
+ return (Imaging) ImagingError_ValueError("quantization error");
+
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/QuantHash.c b/contrib/python/Pillow/py2/libImaging/QuantHash.c
new file mode 100644
index 0000000000..3fcbf3c026
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantHash.c
@@ -0,0 +1,303 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * hash tables used by the image quantizer
+ *
+ * history:
+ * 98-09-10 tjs Contributed
+ * 98-12-29 fl Added to PIL 1.0b1
+ *
+ * Written by Toby J Sargeant <tjs@longford.cs.monash.edu.au>.
+ *
+ * Copyright (c) 1998 by Toby J Sargeant
+ * Copyright (c) 1998 by Secret Labs AB
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "QuantHash.h"
+
+typedef struct _HashNode {
+ struct _HashNode *next;
+ HashKey_t key;
+ HashVal_t value;
+} HashNode;
+
+struct _HashTable {
+ HashNode **table;
+ uint32_t length;
+ uint32_t count;
+ HashFunc hashFunc;
+ HashCmpFunc cmpFunc;
+ void *userData;
+};
+
+#define MIN_LENGTH 11
+#define RESIZE_FACTOR 3
+
+static int _hashtable_insert_node(HashTable *,HashNode *,int,int,CollisionFunc);
+
+HashTable *hashtable_new(HashFunc hf,HashCmpFunc cf) {
+ HashTable *h;
+ h=malloc(sizeof(HashTable));
+ if (!h) { return NULL; }
+ h->hashFunc=hf;
+ h->cmpFunc=cf;
+ h->length=MIN_LENGTH;
+ h->count=0;
+ h->userData=NULL;
+ h->table=malloc(sizeof(HashNode *)*h->length);
+ if (!h->table) { free(h); return NULL; }
+ memset (h->table,0,sizeof(HashNode *)*h->length);
+ return h;
+}
+
+static uint32_t _findPrime(uint32_t start,int dir) {
+ static int unit[]={0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0};
+ uint32_t t;
+ while (start>1) {
+ if (!unit[start&0x0f]) {
+ start+=dir;
+ continue;
+ }
+ for (t=2;t<sqrt((double)start);t++) {
+ if (!start%t) break;
+ }
+ if (t>=sqrt((double)start)) {
+ break;
+ }
+ start+=dir;
+ }
+ return start;
+}
+
+static void _hashtable_rehash(HashTable *h,CollisionFunc cf,uint32_t newSize) {
+ HashNode **oldTable=h->table;
+ uint32_t i;
+ HashNode *n,*nn;
+ uint32_t oldSize;
+ oldSize=h->length;
+ h->table=malloc(sizeof(HashNode *)*newSize);
+ if (!h->table) {
+ h->table=oldTable;
+ return;
+ }
+ h->length=newSize;
+ h->count=0;
+ memset (h->table,0,sizeof(HashNode *)*h->length);
+ for (i=0;i<oldSize;i++) {
+ for (n=oldTable[i];n;n=nn) {
+ nn=n->next;
+ _hashtable_insert_node(h,n,0,0,cf);
+ }
+ }
+ free(oldTable);
+}
+
+static void _hashtable_resize(HashTable *h) {
+ uint32_t newSize;
+ uint32_t oldSize;
+ oldSize=h->length;
+ newSize=oldSize;
+ if (h->count*RESIZE_FACTOR<h->length) {
+ newSize=_findPrime(h->length/2-1,-1);
+ } else if (h->length*RESIZE_FACTOR<h->count) {
+ newSize=_findPrime(h->length*2+1,+1);
+ }
+ if (newSize<MIN_LENGTH) { newSize=oldSize; }
+ if (newSize!=oldSize) {
+ _hashtable_rehash(h,NULL,newSize);
+ }
+}
+
+static int _hashtable_insert_node(HashTable *h,HashNode *node,int resize,int update,CollisionFunc cf) {
+ uint32_t hash=h->hashFunc(h,node->key)%h->length;
+ HashNode **n,*nv;
+ int i;
+
+ for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
+ nv=*n;
+ i=h->cmpFunc(h,nv->key,node->key);
+ if (!i) {
+ if (cf) {
+ nv->key=node->key;
+ cf(h,&(nv->key),&(nv->value),node->key,node->value);
+ free(node);
+ return 1;
+ } else {
+ nv->key=node->key;
+ nv->value=node->value;
+ free(node);
+ return 1;
+ }
+ } else if (i>0) {
+ break;
+ }
+ }
+ if (!update) {
+ node->next=*n;
+ *n=node;
+ h->count++;
+ if (resize) _hashtable_resize(h);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int _hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val,int resize,int update) {
+ HashNode **n,*nv;
+ HashNode *t;
+ int i;
+ uint32_t hash=h->hashFunc(h,key)%h->length;
+
+ for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
+ nv=*n;
+ i=h->cmpFunc(h,nv->key,key);
+ if (!i) {
+ nv->value=val;
+ return 1;
+ } else if (i>0) {
+ break;
+ }
+ }
+ if (!update) {
+ t=malloc(sizeof(HashNode));
+ if (!t) return 0;
+ t->next=*n;
+ *n=t;
+ t->key=key;
+ t->value=val;
+ h->count++;
+ if (resize) _hashtable_resize(h);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int hashtable_insert_or_update_computed(HashTable *h,
+ HashKey_t key,
+ ComputeFunc newFunc,
+ ComputeFunc existsFunc) {
+ HashNode **n,*nv;
+ HashNode *t;
+ int i;
+ uint32_t hash=h->hashFunc(h,key)%h->length;
+
+ for (n=&(h->table[hash]);*n;n=&((*n)->next)) {
+ nv=*n;
+ i=h->cmpFunc(h,nv->key,key);
+ if (!i) {
+ if (existsFunc) {
+ existsFunc(h,nv->key,&(nv->value));
+ } else {
+ return 0;
+ }
+ return 1;
+ } else if (i>0) {
+ break;
+ }
+ }
+ t=malloc(sizeof(HashNode));
+ if (!t) return 0;
+ t->key=key;
+ t->next=*n;
+ *n=t;
+ if (newFunc) {
+ newFunc(h,t->key,&(t->value));
+ } else {
+ free(t);
+ return 0;
+ }
+ h->count++;
+ _hashtable_resize(h);
+ return 1;
+}
+
+int hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val) {
+ return _hashtable_insert(h,key,val,1,0);
+}
+
+void hashtable_foreach_update(HashTable *h,IteratorUpdateFunc i,void *u) {
+ HashNode *n;
+ uint32_t x;
+
+ if (h->table) {
+ for (x=0;x<h->length;x++) {
+ for (n=h->table[x];n;n=n->next) {
+ i(h,n->key,&(n->value),u);
+ }
+ }
+ }
+}
+
+void hashtable_foreach(HashTable *h,IteratorFunc i,void *u) {
+ HashNode *n;
+ uint32_t x;
+
+ if (h->table) {
+ for (x=0;x<h->length;x++) {
+ for (n=h->table[x];n;n=n->next) {
+ i(h,n->key,n->value,u);
+ }
+ }
+ }
+}
+
+void hashtable_free(HashTable *h) {
+ HashNode *n,*nn;
+ uint32_t i;
+
+ if (h->table) {
+ for (i=0;i<h->length;i++) {
+ for (n=h->table[i];n;n=nn) {
+ nn=n->next;
+ free(n);
+ }
+ }
+ free(h->table);
+ }
+ free(h);
+}
+
+void hashtable_rehash_compute(HashTable *h,CollisionFunc cf) {
+ _hashtable_rehash(h,cf,h->length);
+}
+
+int hashtable_lookup(const HashTable *h,const HashKey_t key,HashVal_t *valp) {
+ uint32_t hash=h->hashFunc(h,key)%h->length;
+ HashNode *n;
+ int i;
+
+ for (n=h->table[hash];n;n=n->next) {
+ i=h->cmpFunc(h,n->key,key);
+ if (!i) {
+ *valp=n->value;
+ return 1;
+ } else if (i>0) {
+ break;
+ }
+ }
+ return 0;
+}
+
+uint32_t hashtable_get_count(const HashTable *h) {
+ return h->count;
+}
+
+void *hashtable_get_user_data(const HashTable *h) {
+ return h->userData;
+}
+
+void *hashtable_set_user_data(HashTable *h,void *data) {
+ void *r=h->userData;
+ h->userData=data;
+ return r;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/QuantHash.h b/contrib/python/Pillow/py2/libImaging/QuantHash.h
new file mode 100644
index 0000000000..9874114e58
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantHash.h
@@ -0,0 +1,40 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * image quantizer
+ *
+ * Written by Toby J Sargeant <tjs@longford.cs.monash.edu.au>.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#ifndef __QUANTHASH_H__
+#define __QUANTHASH_H__
+
+#include "QuantTypes.h"
+
+typedef struct _HashTable HashTable;
+typedef Pixel HashKey_t;
+typedef uint32_t HashVal_t;
+
+typedef uint32_t (*HashFunc)(const HashTable *,const HashKey_t);
+typedef int (*HashCmpFunc)(const HashTable *,const HashKey_t,const HashKey_t);
+typedef void (*IteratorFunc)(const HashTable *,const HashKey_t,const HashVal_t,void *);
+typedef void (*IteratorUpdateFunc)(const HashTable *,const HashKey_t,HashVal_t *,void *);
+typedef void (*ComputeFunc)(const HashTable *,const HashKey_t,HashVal_t *);
+typedef void (*CollisionFunc)(const HashTable *,HashKey_t *,HashVal_t *,HashKey_t,HashVal_t);
+
+HashTable * hashtable_new(HashFunc hf,HashCmpFunc cf);
+void hashtable_free(HashTable *h);
+void hashtable_foreach(HashTable *h,IteratorFunc i,void *u);
+void hashtable_foreach_update(HashTable *h,IteratorUpdateFunc i,void *u);
+int hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val);
+int hashtable_lookup(const HashTable *h,const HashKey_t key,HashVal_t *valp);
+int hashtable_insert_or_update_computed(HashTable *h,HashKey_t key,ComputeFunc newFunc,ComputeFunc existsFunc);
+void *hashtable_set_user_data(HashTable *h,void *data);
+void *hashtable_get_user_data(const HashTable *h);
+uint32_t hashtable_get_count(const HashTable *h);
+void hashtable_rehash_compute(HashTable *h,CollisionFunc cf);
+
+#endif // __QUANTHASH_H__
diff --git a/contrib/python/Pillow/py2/libImaging/QuantHeap.c b/contrib/python/Pillow/py2/libImaging/QuantHeap.c
new file mode 100644
index 0000000000..121b872756
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantHeap.c
@@ -0,0 +1,154 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * heap data type used by the image quantizer
+ *
+ * history:
+ * 98-09-10 tjs Contributed
+ * 98-12-29 fl Added to PIL 1.0b1
+ *
+ * Written by Toby J Sargeant <tjs@longford.cs.monash.edu.au>.
+ *
+ * Copyright (c) 1998 by Toby J Sargeant
+ * Copyright (c) 1998 by Secret Labs AB
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+
+#include "QuantHeap.h"
+
+struct _Heap {
+ void **heap;
+ int heapsize;
+ int heapcount;
+ HeapCmpFunc cf;
+};
+
+#define INITIAL_SIZE 256
+
+// #define DEBUG
+
+#ifdef DEBUG
+static int _heap_test(Heap *);
+#endif
+
+void ImagingQuantHeapFree(Heap *h) {
+ free(h->heap);
+ free(h);
+}
+
+static int _heap_grow(Heap *h,int newsize) {
+ void *newheap;
+ if (!newsize) newsize=h->heapsize<<1;
+ if (newsize<h->heapsize) return 0;
+ if (newsize > INT_MAX / sizeof(void *)){
+ return 0;
+ }
+ /* malloc check ok, using calloc for overflow, also checking
+ above due to memcpy below*/
+ newheap=calloc(newsize, sizeof(void *));
+ if (!newheap) return 0;
+ memcpy(newheap,h->heap,sizeof(void *)*h->heapsize);
+ free(h->heap);
+ h->heap=newheap;
+ h->heapsize=newsize;
+ return 1;
+}
+
+#ifdef DEBUG
+static int _heap_test(Heap *h) {
+ int k;
+ for (k=1;k*2<=h->heapcount;k++) {
+ if (h->cf(h,h->heap[k],h->heap[k*2])<0) {
+ printf ("heap is bad\n");
+ return 0;
+ }
+ if (k*2+1<=h->heapcount && h->cf(h,h->heap[k],h->heap[k*2+1])<0) {
+ printf ("heap is bad\n");
+ return 0;
+ }
+ }
+ return 1;
+}
+#endif
+
+int ImagingQuantHeapRemove(Heap* h,void **r) {
+ int k,l;
+ void *v;
+
+ if (!h->heapcount) {
+ return 0;
+ }
+ *r=h->heap[1];
+ v=h->heap[h->heapcount--];
+ for (k=1;k*2<=h->heapcount;k=l) {
+ l=k*2;
+ if (l<h->heapcount) {
+ if (h->cf(h,h->heap[l],h->heap[l+1])<0) {
+ l++;
+ }
+ }
+ if (h->cf(h,v,h->heap[l])>0) {
+ break;
+ }
+ h->heap[k]=h->heap[l];
+ }
+ h->heap[k]=v;
+#ifdef DEBUG
+ if (!_heap_test(h)) { printf ("oops - heap_remove messed up the heap\n"); exit(1); }
+#endif
+ return 1;
+}
+
+int ImagingQuantHeapAdd(Heap *h,void *val) {
+ int k;
+ if (h->heapcount==h->heapsize-1) {
+ _heap_grow(h,0);
+ }
+ k=++h->heapcount;
+ while (k!=1) {
+ if (h->cf(h,val,h->heap[k/2])<=0) {
+ break;
+ }
+ h->heap[k]=h->heap[k/2];
+ k>>=1;
+ }
+ h->heap[k]=val;
+#ifdef DEBUG
+ if (!_heap_test(h)) { printf ("oops - heap_add messed up the heap\n"); exit(1); }
+#endif
+ return 1;
+}
+
+int ImagingQuantHeapTop(Heap *h,void **r) {
+ if (!h->heapcount) {
+ return 0;
+ }
+ *r=h->heap[1];
+ return 1;
+}
+
+Heap *ImagingQuantHeapNew(HeapCmpFunc cf) {
+ Heap *h;
+
+ /* malloc check ok, small constant allocation */
+ h=malloc(sizeof(Heap));
+ if (!h) return NULL;
+ h->heapsize=INITIAL_SIZE;
+ /* malloc check ok, using calloc for overflow */
+ h->heap=calloc(h->heapsize, sizeof(void *));
+ if (!h->heap) {
+ free(h);
+ return NULL;
+ }
+ h->heapcount=0;
+ h->cf=cf;
+ return h;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/QuantHeap.h b/contrib/python/Pillow/py2/libImaging/QuantHeap.h
new file mode 100644
index 0000000000..77bf0d9d55
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantHeap.h
@@ -0,0 +1,27 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * image quantizer
+ *
+ * Written by Toby J Sargeant <tjs@longford.cs.monash.edu.au>.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#ifndef __QUANTHEAP_H__
+#define __QUANTHEAP_H__
+
+#include "QuantTypes.h"
+
+typedef struct _Heap Heap;
+
+typedef int (*HeapCmpFunc)(const Heap *,const void *,const void *);
+
+void ImagingQuantHeapFree(Heap *);
+int ImagingQuantHeapRemove(Heap *,void **);
+int ImagingQuantHeapAdd(Heap *,void *);
+int ImagingQuantHeapTop(Heap *,void **);
+Heap *ImagingQuantHeapNew(HeapCmpFunc);
+
+#endif // __QUANTHEAP_H__
diff --git a/contrib/python/Pillow/py2/libImaging/QuantOctree.c b/contrib/python/Pillow/py2/libImaging/QuantOctree.c
new file mode 100644
index 0000000000..6c0f605c96
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantOctree.c
@@ -0,0 +1,490 @@
+/* Copyright (c) 2010 Oliver Tonnhofer <olt@bogosoft.com>, Omniscale
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+*/
+
+/*
+// This file implements a variation of the octree color quantization algorithm.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "QuantOctree.h"
+
+typedef struct _ColorBucket{
+ /* contains palette index when used for look up cube */
+ uint32_t count;
+ uint64_t r;
+ uint64_t g;
+ uint64_t b;
+ uint64_t a;
+} *ColorBucket;
+
+typedef struct _ColorCube{
+ unsigned int rBits, gBits, bBits, aBits;
+ unsigned int rWidth, gWidth, bWidth, aWidth;
+ unsigned int rOffset, gOffset, bOffset, aOffset;
+
+ long size;
+ ColorBucket buckets;
+} *ColorCube;
+
+#define MAX(a, b) (a)>(b) ? (a) : (b)
+
+static ColorCube
+new_color_cube(int r, int g, int b, int a) {
+ ColorCube cube;
+
+ /* malloc check ok, small constant allocation */
+ cube = malloc(sizeof(struct _ColorCube));
+ if (!cube) return NULL;
+
+ cube->rBits = MAX(r, 0);
+ cube->gBits = MAX(g, 0);
+ cube->bBits = MAX(b, 0);
+ cube->aBits = MAX(a, 0);
+
+ /* overflow check for size multiplication below */
+ if (cube->rBits + cube->gBits + cube->bBits + cube->aBits > 31) {
+ free(cube);
+ return NULL;
+ }
+
+ /* the width of the cube for each dimension */
+ cube->rWidth = 1<<cube->rBits;
+ cube->gWidth = 1<<cube->gBits;
+ cube->bWidth = 1<<cube->bBits;
+ cube->aWidth = 1<<cube->aBits;
+
+ /* the offsets of each color */
+
+ cube->rOffset = cube->gBits + cube->bBits + cube->aBits;
+ cube->gOffset = cube->bBits + cube->aBits;
+ cube->bOffset = cube->aBits;
+ cube->aOffset = 0;
+
+ /* the number of color buckets */
+ cube->size = cube->rWidth * cube->gWidth * cube->bWidth * cube->aWidth;
+ /* malloc check ok, overflow checked above */
+ cube->buckets = calloc(cube->size, sizeof(struct _ColorBucket));
+
+ if (!cube->buckets) {
+ free(cube);
+ return NULL;
+ }
+ return cube;
+}
+
+static void
+free_color_cube(ColorCube cube) {
+ if (cube != NULL) {
+ free(cube->buckets);
+ free(cube);
+ }
+}
+
+static long
+color_bucket_offset_pos(const ColorCube cube,
+ unsigned int r, unsigned int g, unsigned int b, unsigned int a)
+{
+ return r<<cube->rOffset | g<<cube->gOffset | b<<cube->bOffset | a<<cube->aOffset;
+}
+
+static long
+color_bucket_offset(const ColorCube cube, const Pixel *p) {
+ unsigned int r = p->c.r>>(8-cube->rBits);
+ unsigned int g = p->c.g>>(8-cube->gBits);
+ unsigned int b = p->c.b>>(8-cube->bBits);
+ unsigned int a = p->c.a>>(8-cube->aBits);
+ return color_bucket_offset_pos(cube, r, g, b, a);
+}
+
+static ColorBucket
+color_bucket_from_cube(const ColorCube cube, const Pixel *p) {
+ unsigned int offset = color_bucket_offset(cube, p);
+ return &cube->buckets[offset];
+}
+
+static void
+add_color_to_color_cube(const ColorCube cube, const Pixel *p) {
+ ColorBucket bucket = color_bucket_from_cube(cube, p);
+ bucket->count += 1;
+ bucket->r += p->c.r;
+ bucket->g += p->c.g;
+ bucket->b += p->c.b;
+ bucket->a += p->c.a;
+}
+
+static long
+count_used_color_buckets(const ColorCube cube) {
+ long usedBuckets = 0;
+ long i;
+ for (i=0; i < cube->size; i++) {
+ if (cube->buckets[i].count > 0) {
+ usedBuckets += 1;
+ }
+ }
+ return usedBuckets;
+}
+
+static void
+avg_color_from_color_bucket(const ColorBucket bucket, Pixel *dst) {
+ float count = bucket->count;
+ if (count != 0) {
+ dst->c.r = (int)(bucket->r / count);
+ dst->c.g = (int)(bucket->g / count);
+ dst->c.b = (int)(bucket->b / count);
+ dst->c.a = (int)(bucket->a / count);
+ } else {
+ dst->c.r = 0;
+ dst->c.g = 0;
+ dst->c.b = 0;
+ dst->c.a = 0;
+ }
+}
+
+static int
+compare_bucket_count(const ColorBucket a, const ColorBucket b) {
+ return b->count - a->count;
+}
+
+static ColorBucket
+create_sorted_color_palette(const ColorCube cube) {
+ ColorBucket buckets;
+ if (cube->size > LONG_MAX / sizeof(struct _ColorBucket)) {
+ return NULL;
+ }
+ /* malloc check ok, calloc + overflow check above for memcpy */
+ buckets = calloc(cube->size, sizeof(struct _ColorBucket));
+ if (!buckets) return NULL;
+ memcpy(buckets, cube->buckets, sizeof(struct _ColorBucket)*cube->size);
+
+ qsort(buckets, cube->size, sizeof(struct _ColorBucket),
+ (int (*)(void const *, void const *))&compare_bucket_count);
+
+ return buckets;
+}
+
+void add_bucket_values(ColorBucket src, ColorBucket dst) {
+ dst->count += src->count;
+ dst->r += src->r;
+ dst->g += src->g;
+ dst->b += src->b;
+ dst->a += src->a;
+}
+
+/* expand or shrink a given cube to level */
+static ColorCube copy_color_cube(const ColorCube cube,
+ int rBits, int gBits, int bBits, int aBits)
+{
+ unsigned int r, g, b, a;
+ long src_pos, dst_pos;
+ unsigned int src_reduce[4] = {0}, dst_reduce[4] = {0};
+ unsigned int width[4];
+ ColorCube result;
+
+ result = new_color_cube(rBits, gBits, bBits, aBits);
+ if (!result) return NULL;
+
+ if (cube->rBits > rBits) {
+ dst_reduce[0] = cube->rBits - result->rBits;
+ width[0] = cube->rWidth;
+ } else {
+ src_reduce[0] = result->rBits - cube->rBits;
+ width[0] = result->rWidth;
+ }
+ if (cube->gBits > gBits) {
+ dst_reduce[1] = cube->gBits - result->gBits;
+ width[1] = cube->gWidth;
+ } else {
+ src_reduce[1] = result->gBits - cube->gBits;
+ width[1] = result->gWidth;
+ }
+ if (cube->bBits > bBits) {
+ dst_reduce[2] = cube->bBits - result->bBits;
+ width[2] = cube->bWidth;
+ } else {
+ src_reduce[2] = result->bBits - cube->bBits;
+ width[2] = result->bWidth;
+ }
+ if (cube->aBits > aBits) {
+ dst_reduce[3] = cube->aBits - result->aBits;
+ width[3] = cube->aWidth;
+ } else {
+ src_reduce[3] = result->aBits - cube->aBits;
+ width[3] = result->aWidth;
+ }
+
+ for (r=0; r<width[0]; r++) {
+ for (g=0; g<width[1]; g++) {
+ for (b=0; b<width[2]; b++) {
+ for (a=0; a<width[3]; a++) {
+ src_pos = color_bucket_offset_pos(cube,
+ r>>src_reduce[0],
+ g>>src_reduce[1],
+ b>>src_reduce[2],
+ a>>src_reduce[3]);
+ dst_pos = color_bucket_offset_pos(result,
+ r>>dst_reduce[0],
+ g>>dst_reduce[1],
+ b>>dst_reduce[2],
+ a>>dst_reduce[3]);
+ add_bucket_values(
+ &cube->buckets[src_pos],
+ &result->buckets[dst_pos]
+ );
+ }
+ }
+ }
+ }
+ return result;
+}
+
+void
+subtract_color_buckets(ColorCube cube, ColorBucket buckets, long nBuckets) {
+ ColorBucket minuend, subtrahend;
+ long i;
+ Pixel p;
+ for (i=0; i<nBuckets; i++) {
+ subtrahend = &buckets[i];
+
+ // If the subtrahend contains no buckets, there is nothing to subtract.
+ if (subtrahend->count == 0) continue;
+
+ avg_color_from_color_bucket(subtrahend, &p);
+ minuend = color_bucket_from_cube(cube, &p);
+ minuend->count -= subtrahend->count;
+ minuend->r -= subtrahend->r;
+ minuend->g -= subtrahend->g;
+ minuend->b -= subtrahend->b;
+ minuend->a -= subtrahend->a;
+ }
+}
+
+static void
+set_lookup_value(const ColorCube cube, const Pixel *p, long value) {
+ ColorBucket bucket = color_bucket_from_cube(cube, p);
+ bucket->count = value;
+}
+
+uint64_t
+lookup_color(const ColorCube cube, const Pixel *p) {
+ ColorBucket bucket = color_bucket_from_cube(cube, p);
+ return bucket->count;
+}
+
+void add_lookup_buckets(ColorCube cube, ColorBucket palette, long nColors, long offset) {
+ long i;
+ Pixel p;
+ for (i=offset; i<offset+nColors; i++) {
+ avg_color_from_color_bucket(&palette[i], &p);
+ set_lookup_value(cube, &p, i);
+ }
+}
+
+ColorBucket
+combined_palette(ColorBucket bucketsA, long nBucketsA, ColorBucket bucketsB, long nBucketsB) {
+ ColorBucket result;
+ if (nBucketsA > LONG_MAX - nBucketsB ||
+ (nBucketsA+nBucketsB) > LONG_MAX / sizeof(struct _ColorBucket)) {
+ return NULL;
+ }
+ /* malloc check ok, overflow check above */
+ result = calloc(nBucketsA + nBucketsB, sizeof(struct _ColorBucket));
+ if (!result) {
+ return NULL;
+ }
+ memcpy(result, bucketsA, sizeof(struct _ColorBucket) * nBucketsA);
+ memcpy(&result[nBucketsA], bucketsB, sizeof(struct _ColorBucket) * nBucketsB);
+ return result;
+}
+
+static Pixel *
+create_palette_array(const ColorBucket palette, unsigned int paletteLength) {
+ Pixel *paletteArray;
+ unsigned int i;
+
+ /* malloc check ok, calloc for overflow */
+ paletteArray = calloc(paletteLength, sizeof(Pixel));
+ if (!paletteArray) return NULL;
+
+ for (i=0; i<paletteLength; i++) {
+ avg_color_from_color_bucket(&palette[i], &paletteArray[i]);
+ }
+ return paletteArray;
+}
+
+static void
+map_image_pixels(const Pixel *pixelData,
+ uint32_t nPixels,
+ const ColorCube lookupCube,
+ uint32_t *pixelArray)
+{
+ long i;
+ for (i=0; i<nPixels; i++) {
+ pixelArray[i] = lookup_color(lookupCube, &pixelData[i]);
+ }
+}
+
+const int CUBE_LEVELS[8] = {4, 4, 4, 0, 2, 2, 2, 0};
+const int CUBE_LEVELS_ALPHA[8] = {3, 4, 3, 3, 2, 2, 2, 2};
+
+int quantize_octree(Pixel *pixelData,
+ uint32_t nPixels,
+ uint32_t nQuantPixels,
+ Pixel **palette,
+ uint32_t *paletteLength,
+ uint32_t **quantizedPixels,
+ int withAlpha)
+{
+ ColorCube fineCube = NULL;
+ ColorCube coarseCube = NULL;
+ ColorCube lookupCube = NULL;
+ ColorCube coarseLookupCube = NULL;
+ ColorBucket paletteBucketsCoarse = NULL;
+ ColorBucket paletteBucketsFine = NULL;
+ ColorBucket paletteBuckets = NULL;
+ uint32_t *qp = NULL;
+ long i;
+ long nCoarseColors, nFineColors, nAlreadySubtracted;
+ const int *cubeBits;
+
+ if (withAlpha) {
+ cubeBits = CUBE_LEVELS_ALPHA;
+ }
+ else {
+ cubeBits = CUBE_LEVELS;
+ }
+
+ /*
+ Create two color cubes, one fine grained with 8x16x8=1024
+ colors buckets and a coarse with 4x4x4=64 color buckets.
+ The coarse one guarantees that there are color buckets available for
+ the whole color range (assuming nQuantPixels > 64).
+
+ For a quantization to 256 colors all 64 coarse colors will be used
+ plus the 192 most used color buckets from the fine color cube.
+ The average of all colors within one bucket is used as the actual
+ color for that bucket.
+
+ For images with alpha the cubes gets a forth dimension,
+ 8x16x8x8 and 4x4x4x4.
+ */
+
+ /* create fine cube */
+ fineCube = new_color_cube(cubeBits[0], cubeBits[1],
+ cubeBits[2], cubeBits[3]);
+ if (!fineCube) goto error;
+ for (i=0; i<nPixels; i++) {
+ add_color_to_color_cube(fineCube, &pixelData[i]);
+ }
+
+ /* create coarse cube */
+ coarseCube = copy_color_cube(fineCube, cubeBits[4], cubeBits[5],
+ cubeBits[6], cubeBits[7]);
+ if (!coarseCube) goto error;
+ nCoarseColors = count_used_color_buckets(coarseCube);
+
+ /* limit to nQuantPixels */
+ if (nCoarseColors > nQuantPixels)
+ nCoarseColors = nQuantPixels;
+
+ /* how many space do we have in our palette for fine colors? */
+ nFineColors = nQuantPixels - nCoarseColors;
+
+ /* create fine color palette */
+ paletteBucketsFine = create_sorted_color_palette(fineCube);
+ if (!paletteBucketsFine) goto error;
+
+ /* remove the used fine colors from the coarse cube */
+ subtract_color_buckets(coarseCube, paletteBucketsFine, nFineColors);
+
+ /* did the subtraction cleared one or more coarse bucket? */
+ while (nCoarseColors > count_used_color_buckets(coarseCube)) {
+ /* then we can use the free buckets for fine colors */
+ nAlreadySubtracted = nFineColors;
+ nCoarseColors = count_used_color_buckets(coarseCube);
+ nFineColors = nQuantPixels - nCoarseColors;
+ subtract_color_buckets(coarseCube, &paletteBucketsFine[nAlreadySubtracted],
+ nFineColors-nAlreadySubtracted);
+ }
+
+ /* create our palette buckets with fine and coarse combined */
+ paletteBucketsCoarse = create_sorted_color_palette(coarseCube);
+ if (!paletteBucketsCoarse) goto error;
+ paletteBuckets = combined_palette(paletteBucketsCoarse, nCoarseColors,
+ paletteBucketsFine, nFineColors);
+
+ free(paletteBucketsFine);
+ paletteBucketsFine = NULL;
+ free(paletteBucketsCoarse);
+ paletteBucketsCoarse = NULL;
+ if (!paletteBuckets) goto error;
+
+ /* add all coarse colors to our coarse lookup cube. */
+ coarseLookupCube = new_color_cube(cubeBits[4], cubeBits[5],
+ cubeBits[6], cubeBits[7]);
+ if (!coarseLookupCube) goto error;
+ add_lookup_buckets(coarseLookupCube, paletteBuckets, nCoarseColors, 0);
+
+ /* expand coarse cube (64) to larger fine cube (4k). the value of each
+ coarse bucket is then present in the according 64 fine buckets. */
+ lookupCube = copy_color_cube(coarseLookupCube, cubeBits[0], cubeBits[1],
+ cubeBits[2], cubeBits[3]);
+ if (!lookupCube) goto error;
+
+ /* add fine colors to the lookup cube */
+ add_lookup_buckets(lookupCube, paletteBuckets, nFineColors, nCoarseColors);
+
+ /* create result pixels and map palette indices */
+ /* malloc check ok, calloc for overflow */
+ qp = calloc(nPixels, sizeof(Pixel));
+ if (!qp) goto error;
+ map_image_pixels(pixelData, nPixels, lookupCube, qp);
+
+ /* convert palette buckets to RGB pixel palette */
+ *palette = create_palette_array(paletteBuckets, nQuantPixels);
+ if (!(*palette)) goto error;
+
+ *quantizedPixels = qp;
+ *paletteLength = nQuantPixels;
+
+ free_color_cube(coarseCube);
+ free_color_cube(fineCube);
+ free_color_cube(lookupCube);
+ free_color_cube(coarseLookupCube);
+ free(paletteBuckets);
+ return 1;
+
+error:
+ /* everything is initialized to NULL
+ so we are safe to call free */
+ free(qp);
+ free_color_cube(lookupCube);
+ free_color_cube(coarseLookupCube);
+ free(paletteBuckets);
+ free(paletteBucketsCoarse);
+ free(paletteBucketsFine);
+ free_color_cube(coarseCube);
+ free_color_cube(fineCube);
+ return 0;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/QuantOctree.h b/contrib/python/Pillow/py2/libImaging/QuantOctree.h
new file mode 100644
index 0000000000..968644eda0
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantOctree.h
@@ -0,0 +1,14 @@
+#ifndef __QUANT_OCTREE_H__
+#define __QUANT_OCTREE_H__
+
+#include "QuantTypes.h"
+
+int quantize_octree(Pixel *,
+ uint32_t,
+ uint32_t,
+ Pixel **,
+ uint32_t *,
+ uint32_t **,
+ int);
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/QuantPngQuant.c b/contrib/python/Pillow/py2/libImaging/QuantPngQuant.c
new file mode 100644
index 0000000000..e08361aa88
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantPngQuant.c
@@ -0,0 +1,110 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * quantization using libimagequant, a part of pngquant.
+ *
+ * Copyright (c) 2016 Marcin Kurczewski <rr-@sakuya.pl>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "QuantPngQuant.h"
+
+#ifdef HAVE_LIBIMAGEQUANT
+#error #include "libimagequant.h"
+
+int
+quantize_pngquant(
+ Pixel *pixelData,
+ int width,
+ int height,
+ uint32_t quantPixels,
+ Pixel **palette,
+ uint32_t *paletteLength,
+ uint32_t **quantizedPixels,
+ int withAlpha)
+{
+ int result = 0;
+ liq_image *image = NULL;
+ liq_attr *attr = NULL;
+ liq_result *remap = NULL;
+ unsigned char *charMatrix = NULL;
+ unsigned char **charMatrixRows = NULL;
+ unsigned int i, y;
+ *palette = NULL;
+ *paletteLength = 0;
+ *quantizedPixels = NULL;
+
+ /* configure pngquant */
+ attr = liq_attr_create();
+ if (!attr) { goto err; }
+ if (quantPixels) {
+ liq_set_max_colors(attr, quantPixels);
+ }
+
+ /* prepare input image */
+ image = liq_image_create_rgba(
+ attr,
+ pixelData,
+ width,
+ height,
+ 0.45455 /* gamma */);
+ if (!image) { goto err; }
+
+ /* quantize the image */
+ remap = liq_quantize_image(attr, image);
+ if (!remap) { goto err; }
+ liq_set_output_gamma(remap, 0.45455);
+ liq_set_dithering_level(remap, 1);
+
+ /* write output palette */
+ const liq_palette *l_palette = liq_get_palette(remap);
+ *paletteLength = l_palette->count;
+ *palette = malloc(sizeof(Pixel) * l_palette->count);
+ if (!*palette) { goto err; }
+ for (i = 0; i < l_palette->count; i++) {
+ (*palette)[i].c.b = l_palette->entries[i].b;
+ (*palette)[i].c.g = l_palette->entries[i].g;
+ (*palette)[i].c.r = l_palette->entries[i].r;
+ (*palette)[i].c.a = l_palette->entries[i].a;
+ }
+
+ /* write output pixels (pngquant uses char array) */
+ charMatrix = malloc(width * height);
+ if (!charMatrix) { goto err; }
+ charMatrixRows = malloc(height * sizeof(unsigned char*));
+ if (!charMatrixRows) { goto err; }
+ for (y = 0; y < height; y++) {
+ charMatrixRows[y] = &charMatrix[y * width];
+ }
+ if (LIQ_OK != liq_write_remapped_image_rows(remap, image, charMatrixRows)) {
+ goto err;
+ }
+
+ /* transcribe output pixels (pillow uses uint32_t array) */
+ *quantizedPixels = malloc(sizeof(uint32_t) * width * height);
+ if (!*quantizedPixels) { goto err; }
+ for (i = 0; i < width * height; i++) {
+ (*quantizedPixels)[i] = charMatrix[i];
+ }
+
+ result = 1;
+
+err:
+ if (attr) liq_attr_destroy(attr);
+ if (image) liq_image_destroy(image);
+ if (remap) liq_result_destroy(remap);
+ free(charMatrix);
+ free(charMatrixRows);
+ if (!result) {
+ free(*quantizedPixels);
+ free(*palette);
+ }
+ return result;
+}
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/QuantPngQuant.h b/contrib/python/Pillow/py2/libImaging/QuantPngQuant.h
new file mode 100644
index 0000000000..d539a7a0d2
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantPngQuant.h
@@ -0,0 +1,15 @@
+#ifndef __QUANT_PNGQUANT_H__
+#define __QUANT_PNGQUANT_H__
+
+#include "QuantTypes.h"
+
+int quantize_pngquant(Pixel *,
+ int,
+ int,
+ uint32_t,
+ Pixel **,
+ uint32_t *,
+ uint32_t **,
+ int);
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/QuantTypes.h b/contrib/python/Pillow/py2/libImaging/QuantTypes.h
new file mode 100644
index 0000000000..411485498e
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/QuantTypes.h
@@ -0,0 +1,32 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * image quantizer
+ *
+ * Written by Toby J Sargeant <tjs@longford.cs.monash.edu.au>.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#ifdef _MSC_VER
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+typedef union {
+ struct {
+ unsigned char r,g,b,a;
+ } c;
+ struct {
+ unsigned char v[4];
+ } a;
+ uint32_t v;
+} Pixel;
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/RankFilter.c b/contrib/python/Pillow/py2/libImaging/RankFilter.c
new file mode 100644
index 0000000000..0164861bb0
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/RankFilter.c
@@ -0,0 +1,113 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * min, max, median filters
+ *
+ * history:
+ * 2002-06-08 fl Created
+ *
+ * Copyright (c) Secret Labs AB 2002. All rights reserved.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+/* Fast rank algorithm (due to Wirth), based on public domain code
+ by Nicolas Devillard, available at http://ndevilla.free.fr */
+
+#define SWAP(type,a,b) { register type t=(a);(a)=(b);(b)=t; }
+
+#define MakeRankFunction(type)\
+static type Rank##type(type a[], int n, int k)\
+{\
+ register int i, j, l, m;\
+ register type x;\
+ l = 0; m = n-1;\
+ while (l < m) {\
+ x = a[k];\
+ i = l;\
+ j = m;\
+ do {\
+ while (a[i] < x) i++;\
+ while (x < a[j]) j--;\
+ if (i <= j) {\
+ SWAP(type, a[i], a[j]);\
+ i++; j--;\
+ }\
+ } while (i <= j);\
+ if (j < k) l = i;\
+ if (k < i) m = j;\
+ }\
+ return a[k];\
+}
+
+MakeRankFunction(UINT8)
+MakeRankFunction(INT32)
+MakeRankFunction(FLOAT32)
+
+Imaging
+ImagingRankFilter(Imaging im, int size, int rank)
+{
+ Imaging imOut = NULL;
+ int x, y;
+ int i, margin, size2;
+
+ if (!im || im->bands != 1 || im->type == IMAGING_TYPE_SPECIAL)
+ return (Imaging) ImagingError_ModeError();
+
+ if (!(size & 1))
+ return (Imaging) ImagingError_ValueError("bad filter size");
+
+ /* malloc check ok, for overflow in the define below */
+ if (size > INT_MAX / size ||
+ size > INT_MAX / (size * sizeof(FLOAT32))) {
+ return (Imaging) ImagingError_ValueError("filter size too large");
+ }
+
+ size2 = size * size;
+ margin = (size-1) / 2;
+
+ if (rank < 0 || rank >= size2)
+ return (Imaging) ImagingError_ValueError("bad rank value");
+
+ imOut = ImagingNew(im->mode, im->xsize - 2*margin, im->ysize - 2*margin);
+ if (!imOut)
+ return NULL;
+
+ /* malloc check ok, checked above */
+#define RANK_BODY(type) do {\
+ type* buf = malloc(size2 * sizeof(type));\
+ if (!buf)\
+ goto nomemory;\
+ for (y = 0; y < imOut->ysize; y++)\
+ for (x = 0; x < imOut->xsize; x++) {\
+ for (i = 0; i < size; i++)\
+ memcpy(buf + i*size, &IMAGING_PIXEL_##type(im, x, y+i),\
+ size * sizeof(type));\
+ IMAGING_PIXEL_##type(imOut, x, y) = Rank##type(buf, size2, rank);\
+ }\
+ free(buf); \
+} while (0)
+
+ if (im->image8)
+ RANK_BODY(UINT8);
+ else if (im->type == IMAGING_TYPE_INT32)
+ RANK_BODY(INT32);
+ else if (im->type == IMAGING_TYPE_FLOAT32)
+ RANK_BODY(FLOAT32);
+ else {
+ /* safety net (we shouldn't end up here) */
+ ImagingDelete(imOut);
+ return (Imaging) ImagingError_ModeError();
+ }
+
+ ImagingCopyPalette(imOut, im);
+
+ return imOut;
+
+nomemory:
+ ImagingDelete(imOut);
+ return (Imaging) ImagingError_MemoryError();
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Raw.h b/contrib/python/Pillow/py2/libImaging/Raw.h
new file mode 100644
index 0000000000..4d28fa5466
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Raw.h
@@ -0,0 +1,15 @@
+/* Raw.h */
+
+typedef struct {
+
+ /* CONFIGURATION */
+
+ /* Distance between lines (0=no padding) */
+ int stride;
+
+ /* PRIVATE (initialized by decoder) */
+
+ /* Padding between lines */
+ int skip;
+
+} RAWSTATE;
diff --git a/contrib/python/Pillow/py2/libImaging/RawDecode.c b/contrib/python/Pillow/py2/libImaging/RawDecode.c
new file mode 100644
index 0000000000..c069bdb886
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/RawDecode.c
@@ -0,0 +1,96 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for raw (uncompressed) image data
+ *
+ * history:
+ * 96-03-07 fl rewritten
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#include "Raw.h"
+
+
+int
+ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ enum { LINE = 1, SKIP };
+ RAWSTATE* rawstate = state->context;
+
+ UINT8* ptr;
+
+ if (state->state == 0) {
+
+ /* Initialize context variables */
+
+ /* get size of image data and padding */
+ state->bytes = (state->xsize * state->bits + 7) / 8;
+ if (rawstate->stride) {
+ rawstate->skip = rawstate->stride - state->bytes;
+ if (rawstate->skip < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+ } else {
+ rawstate->skip = 0;
+ }
+
+ /* check image orientation */
+ if (state->ystep < 0) {
+ state->y = state->ysize-1;
+ state->ystep = -1;
+ } else
+ state->ystep = 1;
+
+ state->state = LINE;
+
+ }
+
+ ptr = buf;
+
+ for (;;) {
+
+ if (state->state == SKIP) {
+
+ /* Skip padding between lines */
+
+ if (bytes < rawstate->skip)
+ return ptr - buf;
+
+ ptr += rawstate->skip;
+ bytes -= rawstate->skip;
+
+ state->state = LINE;
+
+ }
+
+ if (bytes < state->bytes)
+ return ptr - buf;
+
+ /* Unpack data */
+ state->shuffle((UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, ptr, state->xsize);
+
+ ptr += state->bytes;
+ bytes -= state->bytes;
+
+ state->y += state->ystep;
+
+ if (state->y < 0 || state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+
+ state->state = SKIP;
+
+ }
+
+}
diff --git a/contrib/python/Pillow/py2/libImaging/RawEncode.c b/contrib/python/Pillow/py2/libImaging/RawEncode.c
new file mode 100644
index 0000000000..a3b74b8cff
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/RawEncode.c
@@ -0,0 +1,89 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * coder for raw data
+ *
+ * FIXME: This encoder will fail if the buffer is not large enough to
+ * hold one full line of data. There's a workaround for this problem
+ * in ImageFile.py, but it should be solved here instead.
+ *
+ * history:
+ * 96-04-30 fl created
+ * 97-01-03 fl fixed padding
+ *
+ * Copyright (c) Fredrik Lundh 1996-97.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution. */
+
+
+#include "Imaging.h"
+
+int
+ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
+{
+ UINT8* ptr;
+
+ if (!state->state) {
+
+ /* The "count" field holds the stride, if specified. Fix
+ things up so "bytes" is the full size, and "count" the
+ packed size */
+
+ if (state->count > 0) {
+ int bytes = state->count;
+
+ /* stride must not be less than real size */
+ if (state->count < state->bytes) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+ state->count = state->bytes;
+ state->bytes = bytes;
+ } else
+ state->count = state->bytes;
+
+ /* The "ystep" field specifies the orientation */
+
+ if (state->ystep < 0) {
+ state->y = state->ysize-1;
+ state->ystep = -1;
+ } else
+ state->ystep = 1;
+
+ state->state = 1;
+
+ }
+
+ if (bytes < state->bytes) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return 0;
+ }
+
+ ptr = buf;
+
+ while (bytes >= state->bytes) {
+
+ state->shuffle(ptr, (UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->xsize);
+
+ if (state->bytes > state->count)
+ /* zero-pad the buffer, if necessary */
+ memset(ptr + state->count, 0, state->bytes - state->count);
+
+ ptr += state->bytes;
+ bytes -= state->bytes;
+
+ state->y += state->ystep;
+
+ if (state->y < 0 || state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+
+ }
+
+ return ptr - buf;
+
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Resample.c b/contrib/python/Pillow/py2/libImaging/Resample.c
new file mode 100644
index 0000000000..4a98e84770
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Resample.c
@@ -0,0 +1,695 @@
+#include "Imaging.h"
+
+#include <math.h>
+
+
+#define ROUND_UP(f) ((int) ((f) >= 0.0 ? (f) + 0.5F : (f) - 0.5F))
+
+
+struct filter {
+ double (*filter)(double x);
+ double support;
+};
+
+static inline double box_filter(double x)
+{
+ if (x >= -0.5 && x < 0.5)
+ return 1.0;
+ return 0.0;
+}
+
+static inline double bilinear_filter(double x)
+{
+ if (x < 0.0)
+ x = -x;
+ if (x < 1.0)
+ return 1.0-x;
+ return 0.0;
+}
+
+static inline double hamming_filter(double x)
+{
+ if (x < 0.0)
+ x = -x;
+ if (x == 0.0)
+ return 1.0;
+ if (x >= 1.0)
+ return 0.0;
+ x = x * M_PI;
+ return sin(x) / x * (0.54f + 0.46f * cos(x));
+}
+
+static inline double bicubic_filter(double x)
+{
+ /* https://en.wikipedia.org/wiki/Bicubic_interpolation#Bicubic_convolution_algorithm */
+#define a -0.5
+ if (x < 0.0)
+ x = -x;
+ if (x < 1.0)
+ return ((a + 2.0) * x - (a + 3.0)) * x*x + 1;
+ if (x < 2.0)
+ return (((x - 5) * x + 8) * x - 4) * a;
+ return 0.0;
+#undef a
+}
+
+static inline double sinc_filter(double x)
+{
+ if (x == 0.0)
+ return 1.0;
+ x = x * M_PI;
+ return sin(x) / x;
+}
+
+static inline double lanczos_filter(double x)
+{
+ /* truncated sinc */
+ if (-3.0 <= x && x < 3.0)
+ return sinc_filter(x) * sinc_filter(x/3);
+ return 0.0;
+}
+
+static struct filter BOX = { box_filter, 0.5 };
+static struct filter BILINEAR = { bilinear_filter, 1.0 };
+static struct filter HAMMING = { hamming_filter, 1.0 };
+static struct filter BICUBIC = { bicubic_filter, 2.0 };
+static struct filter LANCZOS = { lanczos_filter, 3.0 };
+
+
+/* 8 bits for result. Filter can have negative areas.
+ In one cases the sum of the coefficients will be negative,
+ in the other it will be more than 1.0. That is why we need
+ two extra bits for overflow and int type. */
+#define PRECISION_BITS (32 - 8 - 2)
+
+
+/* Handles values form -640 to 639. */
+UINT8 _clip8_lookups[1280] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+};
+
+UINT8 *clip8_lookups = &_clip8_lookups[640];
+
+static inline UINT8 clip8(int in)
+{
+ return clip8_lookups[in >> PRECISION_BITS];
+}
+
+
+int
+precompute_coeffs(int inSize, float in0, float in1, int outSize,
+ struct filter *filterp, int **boundsp, double **kkp) {
+ double support, scale, filterscale;
+ double center, ww, ss;
+ int xx, x, ksize, xmin, xmax;
+ int *bounds;
+ double *kk, *k;
+
+ /* prepare for horizontal stretch */
+ filterscale = scale = (double) (in1 - in0) / outSize;
+ if (filterscale < 1.0) {
+ filterscale = 1.0;
+ }
+
+ /* determine support size (length of resampling filter) */
+ support = filterp->support * filterscale;
+
+ /* maximum number of coeffs */
+ ksize = (int) ceil(support) * 2 + 1;
+
+ // check for overflow
+ if (outSize > INT_MAX / (ksize * sizeof(double))) {
+ ImagingError_MemoryError();
+ return 0;
+ }
+
+ /* coefficient buffer */
+ /* malloc check ok, overflow checked above */
+ kk = malloc(outSize * ksize * sizeof(double));
+ if ( ! kk) {
+ ImagingError_MemoryError();
+ return 0;
+ }
+
+ /* malloc check ok, ksize*sizeof(double) > 2*sizeof(int) */
+ bounds = malloc(outSize * 2 * sizeof(int));
+ if ( ! bounds) {
+ free(kk);
+ ImagingError_MemoryError();
+ return 0;
+ }
+
+ for (xx = 0; xx < outSize; xx++) {
+ center = in0 + (xx + 0.5) * scale;
+ ww = 0.0;
+ ss = 1.0 / filterscale;
+ // Round the value
+ xmin = (int) (center - support + 0.5);
+ if (xmin < 0)
+ xmin = 0;
+ // Round the value
+ xmax = (int) (center + support + 0.5);
+ if (xmax > inSize)
+ xmax = inSize;
+ xmax -= xmin;
+ k = &kk[xx * ksize];
+ for (x = 0; x < xmax; x++) {
+ double w = filterp->filter((x + xmin - center + 0.5) * ss);
+ k[x] = w;
+ ww += w;
+ }
+ for (x = 0; x < xmax; x++) {
+ if (ww != 0.0)
+ k[x] /= ww;
+ }
+ // Remaining values should stay empty if they are used despite of xmax.
+ for (; x < ksize; x++) {
+ k[x] = 0;
+ }
+ bounds[xx * 2 + 0] = xmin;
+ bounds[xx * 2 + 1] = xmax;
+ }
+ *boundsp = bounds;
+ *kkp = kk;
+ return ksize;
+}
+
+
+void
+normalize_coeffs_8bpc(int outSize, int ksize, double *prekk)
+{
+ int x;
+ INT32 *kk;
+
+ // use the same buffer for normalized coefficients
+ kk = (INT32 *) prekk;
+
+ for (x = 0; x < outSize * ksize; x++) {
+ if (prekk[x] < 0) {
+ kk[x] = (int) (-0.5 + prekk[x] * (1 << PRECISION_BITS));
+ } else {
+ kk[x] = (int) (0.5 + prekk[x] * (1 << PRECISION_BITS));
+ }
+ }
+}
+
+
+
+void
+ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset,
+ int ksize, int *bounds, double *prekk)
+{
+ ImagingSectionCookie cookie;
+ int ss0, ss1, ss2, ss3;
+ int xx, yy, x, xmin, xmax;
+ INT32 *k, *kk;
+
+ // use the same buffer for normalized coefficients
+ kk = (INT32 *) prekk;
+ normalize_coeffs_8bpc(imOut->xsize, ksize, prekk);
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->image8) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss0 = 1 << (PRECISION_BITS -1);
+ for (x = 0; x < xmax; x++)
+ ss0 += ((UINT8) imIn->image8[yy + offset][x + xmin]) * k[x];
+ imOut->image8[yy][xx] = clip8(ss0);
+ }
+ }
+ } else if (imIn->type == IMAGING_TYPE_UINT8) {
+ if (imIn->bands == 2) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss0 = ss3 = 1 << (PRECISION_BITS -1);
+ for (x = 0; x < xmax; x++) {
+ ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
+ ss3 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 3]) * k[x];
+ }
+ v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ } else if (imIn->bands == 3) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
+ for (x = 0; x < xmax; x++) {
+ ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
+ ss1 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 1]) * k[x];
+ ss2 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 2]) * k[x];
+ }
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0);
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ } else {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
+ for (x = 0; x < xmax; x++) {
+ ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x];
+ ss1 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 1]) * k[x];
+ ss2 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 2]) * k[x];
+ ss3 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 3]) * k[x];
+ }
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+}
+
+
+void
+ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset,
+ int ksize, int *bounds, double *prekk)
+{
+ ImagingSectionCookie cookie;
+ int ss0, ss1, ss2, ss3;
+ int xx, yy, y, ymin, ymax;
+ INT32 *k, *kk;
+
+ // use the same buffer for normalized coefficients
+ kk = (INT32 *) prekk;
+ normalize_coeffs_8bpc(imOut->ysize, ksize, prekk);
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->image8) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ k = &kk[yy * ksize];
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss0 = 1 << (PRECISION_BITS -1);
+ for (y = 0; y < ymax; y++)
+ ss0 += ((UINT8) imIn->image8[y + ymin][xx]) * k[y];
+ imOut->image8[yy][xx] = clip8(ss0);
+ }
+ }
+ } else if (imIn->type == IMAGING_TYPE_UINT8) {
+ if (imIn->bands == 2) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ k = &kk[yy * ksize];
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ ss0 = ss3 = 1 << (PRECISION_BITS -1);
+ for (y = 0; y < ymax; y++) {
+ ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
+ ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
+ }
+ v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ } else if (imIn->bands == 3) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ k = &kk[yy * ksize];
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
+ for (y = 0; y < ymax; y++) {
+ ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
+ ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
+ ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
+ }
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0);
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ } else {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ k = &kk[yy * ksize];
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
+ for (y = 0; y < ymax; y++) {
+ ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
+ ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
+ ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
+ ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
+ }
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+}
+
+
+void
+ImagingResampleHorizontal_32bpc(Imaging imOut, Imaging imIn, int offset,
+ int ksize, int *bounds, double *kk)
+{
+ ImagingSectionCookie cookie;
+ double ss;
+ int xx, yy, x, xmin, xmax;
+ double *k;
+
+ ImagingSectionEnter(&cookie);
+ switch(imIn->type) {
+ case IMAGING_TYPE_INT32:
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss = 0.0;
+ for (x = 0; x < xmax; x++)
+ ss += IMAGING_PIXEL_I(imIn, x + xmin, yy + offset) * k[x];
+ IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
+ }
+ }
+ break;
+
+ case IMAGING_TYPE_FLOAT32:
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss = 0.0;
+ for (x = 0; x < xmax; x++)
+ ss += IMAGING_PIXEL_F(imIn, x + xmin, yy + offset) * k[x];
+ IMAGING_PIXEL_F(imOut, xx, yy) = ss;
+ }
+ }
+ break;
+ }
+ ImagingSectionLeave(&cookie);
+}
+
+
+void
+ImagingResampleVertical_32bpc(Imaging imOut, Imaging imIn, int offset,
+ int ksize, int *bounds, double *kk)
+{
+ ImagingSectionCookie cookie;
+ double ss;
+ int xx, yy, y, ymin, ymax;
+ double *k;
+
+ ImagingSectionEnter(&cookie);
+ switch(imIn->type) {
+ case IMAGING_TYPE_INT32:
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ k = &kk[yy * ksize];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss = 0.0;
+ for (y = 0; y < ymax; y++)
+ ss += IMAGING_PIXEL_I(imIn, xx, y + ymin) * k[y];
+ IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
+ }
+ }
+ break;
+
+ case IMAGING_TYPE_FLOAT32:
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ k = &kk[yy * ksize];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss = 0.0;
+ for (y = 0; y < ymax; y++)
+ ss += IMAGING_PIXEL_F(imIn, xx, y + ymin) * k[y];
+ IMAGING_PIXEL_F(imOut, xx, yy) = ss;
+ }
+ }
+ break;
+ }
+ ImagingSectionLeave(&cookie);
+}
+
+
+typedef void (*ResampleFunction)(Imaging imOut, Imaging imIn, int offset,
+ int ksize, int *bounds, double *kk);
+
+
+Imaging
+ImagingResampleInner(Imaging imIn, int xsize, int ysize,
+ struct filter *filterp, float box[4],
+ ResampleFunction ResampleHorizontal,
+ ResampleFunction ResampleVertical);
+
+
+Imaging
+ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4])
+{
+ struct filter *filterp;
+ ResampleFunction ResampleHorizontal;
+ ResampleFunction ResampleVertical;
+
+ if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
+ return (Imaging) ImagingError_ModeError();
+
+ if (imIn->type == IMAGING_TYPE_SPECIAL) {
+ return (Imaging) ImagingError_ModeError();
+ } else if (imIn->image8) {
+ ResampleHorizontal = ImagingResampleHorizontal_8bpc;
+ ResampleVertical = ImagingResampleVertical_8bpc;
+ } else {
+ switch(imIn->type) {
+ case IMAGING_TYPE_UINT8:
+ ResampleHorizontal = ImagingResampleHorizontal_8bpc;
+ ResampleVertical = ImagingResampleVertical_8bpc;
+ break;
+ case IMAGING_TYPE_INT32:
+ case IMAGING_TYPE_FLOAT32:
+ ResampleHorizontal = ImagingResampleHorizontal_32bpc;
+ ResampleVertical = ImagingResampleVertical_32bpc;
+ break;
+ default:
+ return (Imaging) ImagingError_ModeError();
+ }
+ }
+
+ /* check filter */
+ switch (filter) {
+ case IMAGING_TRANSFORM_BOX:
+ filterp = &BOX;
+ break;
+ case IMAGING_TRANSFORM_BILINEAR:
+ filterp = &BILINEAR;
+ break;
+ case IMAGING_TRANSFORM_HAMMING:
+ filterp = &HAMMING;
+ break;
+ case IMAGING_TRANSFORM_BICUBIC:
+ filterp = &BICUBIC;
+ break;
+ case IMAGING_TRANSFORM_LANCZOS:
+ filterp = &LANCZOS;
+ break;
+ default:
+ return (Imaging) ImagingError_ValueError(
+ "unsupported resampling filter"
+ );
+ }
+
+ return ImagingResampleInner(imIn, xsize, ysize, filterp, box,
+ ResampleHorizontal, ResampleVertical);
+}
+
+
+Imaging
+ImagingResampleInner(Imaging imIn, int xsize, int ysize,
+ struct filter *filterp, float box[4],
+ ResampleFunction ResampleHorizontal,
+ ResampleFunction ResampleVertical)
+{
+ Imaging imTemp = NULL;
+ Imaging imOut = NULL;
+
+ int i, need_horizontal, need_vertical;
+ int ybox_first, ybox_last;
+ int ksize_horiz, ksize_vert;
+ int *bounds_horiz, *bounds_vert;
+ double *kk_horiz, *kk_vert;
+
+ need_horizontal = xsize != imIn->xsize || box[0] || box[2] != xsize;
+ need_vertical = ysize != imIn->ysize || box[1] || box[3] != ysize;
+
+ ksize_horiz = precompute_coeffs(imIn->xsize, box[0], box[2], xsize,
+ filterp, &bounds_horiz, &kk_horiz);
+ if ( ! ksize_horiz) {
+ return NULL;
+ }
+
+ ksize_vert = precompute_coeffs(imIn->ysize, box[1], box[3], ysize,
+ filterp, &bounds_vert, &kk_vert);
+ if ( ! ksize_vert) {
+ free(bounds_horiz);
+ free(kk_horiz);
+ free(bounds_vert);
+ free(kk_vert);
+ return NULL;
+ }
+
+ // First used row in the source image
+ ybox_first = bounds_vert[0];
+ // Last used row in the source image
+ ybox_last = bounds_vert[ysize*2 - 2] + bounds_vert[ysize*2 - 1];
+
+
+ /* two-pass resize, horizontal pass */
+ if (need_horizontal) {
+ // Shift bounds for vertical pass
+ for (i = 0; i < ysize; i++) {
+ bounds_vert[i * 2] -= ybox_first;
+ }
+
+ imTemp = ImagingNewDirty(imIn->mode, xsize, ybox_last - ybox_first);
+ if (imTemp) {
+ ResampleHorizontal(imTemp, imIn, ybox_first,
+ ksize_horiz, bounds_horiz, kk_horiz);
+ }
+ free(bounds_horiz);
+ free(kk_horiz);
+ if ( ! imTemp) {
+ free(bounds_vert);
+ free(kk_vert);
+ return NULL;
+ }
+ imOut = imIn = imTemp;
+ } else {
+ // Free in any case
+ free(bounds_horiz);
+ free(kk_horiz);
+ }
+
+ /* vertical pass */
+ if (need_vertical) {
+ imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
+ if (imOut) {
+ /* imIn can be the original image or horizontally resampled one */
+ ResampleVertical(imOut, imIn, 0,
+ ksize_vert, bounds_vert, kk_vert);
+ }
+ /* it's safe to call ImagingDelete with empty value
+ if previous step was not performed. */
+ ImagingDelete(imTemp);
+ free(bounds_vert);
+ free(kk_vert);
+ if ( ! imOut) {
+ return NULL;
+ }
+ } else {
+ // Free in any case
+ free(bounds_vert);
+ free(kk_vert);
+ }
+
+ /* none of the previous steps are performed, copying */
+ if ( ! imOut) {
+ imOut = ImagingCopy(imIn);
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Sgi.h b/contrib/python/Pillow/py2/libImaging/Sgi.h
new file mode 100644
index 0000000000..8015d6661e
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Sgi.h
@@ -0,0 +1,40 @@
+/* Sgi.h */
+
+typedef struct {
+
+ /* CONFIGURATION */
+
+ /* Number of bytes per channel per pixel */
+ int bpc;
+
+ /* RLE offsets table */
+ UINT32 *starttab;
+
+ /* RLE lengths table */
+ UINT32 *lengthtab;
+
+ /* current row offset */
+ UINT32 rleoffset;
+
+ /* current row length */
+ UINT32 rlelength;
+
+ /* RLE table size */
+ int tablen;
+
+ /* RLE table index */
+ int tabindex;
+
+ /* buffer index */
+ int bufindex;
+
+ /* current row index */
+ int rowno;
+
+ /* current channel index */
+ int channo;
+
+ /* image data size from file descriptor */
+ long bufsize;
+
+} SGISTATE; \ No newline at end of file
diff --git a/contrib/python/Pillow/py2/libImaging/SgiRleDecode.c b/contrib/python/Pillow/py2/libImaging/SgiRleDecode.c
new file mode 100644
index 0000000000..1ba56b8c7b
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/SgiRleDecode.c
@@ -0,0 +1,205 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for Sgi RLE data.
+ *
+ * history:
+ * 2017-07-28 mb fixed for images larger than 64KB
+ * 2017-07-20 mb created
+ *
+ * Copyright (c) Mickael Bonfill 2017.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+#include "Sgi.h"
+
+#define SGI_HEADER_SIZE 512
+#define RLE_COPY_FLAG 0x80
+#define RLE_MAX_RUN 0x7f
+
+static void read4B(UINT32* dest, UINT8* buf)
+{
+ *dest = (UINT32)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+}
+
+static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize)
+{
+ UINT8 pixel, count;
+
+ for (;n > 0; n--)
+ {
+ pixel = *src++;
+ if (n == 1 && pixel != 0)
+ return n;
+ count = pixel & RLE_MAX_RUN;
+ if (!count)
+ return count;
+ if (count > xsize) {
+ return -1;
+ }
+ if (pixel & RLE_COPY_FLAG) {
+ while(count--) {
+ *dest = *src++;
+ dest += z;
+ }
+
+ }
+ else {
+ pixel = *src++;
+ while (count--) {
+ *dest = pixel;
+ dest += z;
+ }
+ }
+
+ }
+ return 0;
+}
+
+static int expandrow2(UINT8* dest, const UINT8* src, int n, int z, int xsize)
+{
+ UINT8 pixel, count;
+
+
+ for (;n > 0; n--)
+ {
+ pixel = src[1];
+ src+=2;
+ if (n == 1 && pixel != 0)
+ return n;
+ count = pixel & RLE_MAX_RUN;
+ if (!count)
+ return count;
+ if (count > xsize) {
+ return -1;
+ }
+ if (pixel & RLE_COPY_FLAG) {
+ while(count--) {
+ memcpy(dest, src, 2);
+ src += 2;
+ dest += z * 2;
+ }
+ }
+ else {
+ while (count--) {
+ memcpy(dest, src, 2);
+ dest += z * 2;
+ }
+ src+=2;
+ }
+ }
+ return 0;
+}
+
+
+int
+ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
+ UINT8* buf, Py_ssize_t bytes)
+{
+ UINT8 *ptr;
+ SGISTATE *c;
+ int err = 0;
+ int status;
+
+ /* Get all data from File descriptor */
+ c = (SGISTATE*)state->context;
+ _imaging_seek_pyFd(state->fd, 0L, SEEK_END);
+ c->bufsize = _imaging_tell_pyFd(state->fd);
+ c->bufsize -= SGI_HEADER_SIZE;
+ ptr = malloc(sizeof(UINT8) * c->bufsize);
+ if (!ptr) {
+ return IMAGING_CODEC_MEMORY;
+ }
+ _imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET);
+ _imaging_read_pyFd(state->fd, (char*)ptr, c->bufsize);
+
+
+ /* decoder initialization */
+ state->count = 0;
+ state->y = 0;
+ if (state->ystep < 0) {
+ state->y = im->ysize - 1;
+ } else {
+ state->ystep = 1;
+ }
+
+ if (im->xsize > INT_MAX / im->bands ||
+ im->ysize > INT_MAX / im->bands) {
+ err = IMAGING_CODEC_MEMORY;
+ goto sgi_finish_decode;
+ }
+
+ /* Allocate memory for RLE tables and rows */
+ free(state->buffer);
+ state->buffer = NULL;
+ /* malloc overflow check above */
+ state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2);
+ c->tablen = im->bands * im->ysize;
+ c->starttab = calloc(c->tablen, sizeof(UINT32));
+ c->lengthtab = calloc(c->tablen, sizeof(UINT32));
+ if (!state->buffer ||
+ !c->starttab ||
+ !c->lengthtab) {
+ err = IMAGING_CODEC_MEMORY;
+ goto sgi_finish_decode;
+ }
+ /* populate offsets table */
+ for (c->tabindex = 0, c->bufindex = 0; c->tabindex < c->tablen; c->tabindex++, c->bufindex+=4)
+ read4B(&c->starttab[c->tabindex], &ptr[c->bufindex]);
+ /* populate lengths table */
+ for (c->tabindex = 0, c->bufindex = c->tablen * sizeof(UINT32); c->tabindex < c->tablen; c->tabindex++, c->bufindex+=4)
+ read4B(&c->lengthtab[c->tabindex], &ptr[c->bufindex]);
+
+ state->count += c->tablen * sizeof(UINT32) * 2;
+
+ /* read compressed rows */
+ for (c->rowno = 0; c->rowno < im->ysize; c->rowno++, state->y += state->ystep)
+ {
+ for (c->channo = 0; c->channo < im->bands; c->channo++)
+ {
+ c->rleoffset = c->starttab[c->rowno + c->channo * im->ysize];
+ c->rlelength = c->lengthtab[c->rowno + c->channo * im->ysize];
+ c->rleoffset -= SGI_HEADER_SIZE;
+
+ if (c->rleoffset + c->rlelength > c->bufsize) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ /* row decompression */
+ if (c->bpc ==1) {
+ status = expandrow(&state->buffer[c->channo], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize);
+ }
+ else {
+ status = expandrow2(&state->buffer[c->channo * 2], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize);
+ }
+ if (status == -1) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ } else if (status == 1) {
+ goto sgi_finish_decode;
+ }
+
+ state->count += c->rlelength;
+ }
+
+ /* store decompressed data in image */
+ state->shuffle((UINT8*)im->image[state->y], state->buffer, im->xsize);
+
+ }
+
+ c->bufsize++;
+
+sgi_finish_decode: ;
+
+ free(c->starttab);
+ free(c->lengthtab);
+ free(ptr);
+ if (err != 0){
+ return err;
+ }
+ return state->count - c->bufsize;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Storage.c b/contrib/python/Pillow/py2/libImaging/Storage.c
new file mode 100644
index 0000000000..ab476939ac
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Storage.c
@@ -0,0 +1,594 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * imaging storage object
+ *
+ * This baseline implementation is designed to efficiently handle
+ * large images, provided they fit into the available memory.
+ *
+ * history:
+ * 1995-06-15 fl Created
+ * 1995-09-12 fl Updated API, compiles silently under ANSI C++
+ * 1995-11-26 fl Compiles silently under Borland 4.5 as well
+ * 1996-05-05 fl Correctly test status from Prologue
+ * 1997-05-12 fl Increased THRESHOLD (to speed up Tk interface)
+ * 1997-05-30 fl Added support for floating point images
+ * 1997-11-17 fl Added support for "RGBX" images
+ * 1998-01-11 fl Added support for integer images
+ * 1998-03-05 fl Exported Prologue/Epilogue functions
+ * 1998-07-01 fl Added basic "YCrCb" support
+ * 1998-07-03 fl Attach palette in prologue for "P" images
+ * 1998-07-09 hk Don't report MemoryError on zero-size images
+ * 1998-07-12 fl Change "YCrCb" to "YCbCr" (!)
+ * 1998-10-26 fl Added "I;16" and "I;16B" storage modes (experimental)
+ * 1998-12-29 fl Fixed allocation bug caused by previous fix
+ * 1999-02-03 fl Added "RGBa" and "BGR" modes (experimental)
+ * 2001-04-22 fl Fixed potential memory leak in ImagingCopyPalette
+ * 2003-09-26 fl Added "LA" and "PA" modes (experimental)
+ * 2005-10-02 fl Added image counter
+ *
+ * Copyright (c) 1998-2005 by Secret Labs AB
+ * Copyright (c) 1995-2005 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+#include <string.h>
+
+
+int ImagingNewCount = 0;
+
+/* --------------------------------------------------------------------
+ * Standard image object.
+ */
+
+Imaging
+ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size)
+{
+ Imaging im;
+
+ /* linesize overflow check, roughly the current largest space req'd */
+ if (xsize > (INT_MAX / 4) - 1) {
+ return (Imaging) ImagingError_MemoryError();
+ }
+
+ im = (Imaging) calloc(1, size);
+ if (!im) {
+ return (Imaging) ImagingError_MemoryError();
+ }
+
+ /* Setup image descriptor */
+ im->xsize = xsize;
+ im->ysize = ysize;
+
+ im->type = IMAGING_TYPE_UINT8;
+
+ if (strcmp(mode, "1") == 0) {
+ /* 1-bit images */
+ im->bands = im->pixelsize = 1;
+ im->linesize = xsize;
+
+ } else if (strcmp(mode, "P") == 0) {
+ /* 8-bit palette mapped images */
+ im->bands = im->pixelsize = 1;
+ im->linesize = xsize;
+ im->palette = ImagingPaletteNew("RGB");
+
+ } else if (strcmp(mode, "PA") == 0) {
+ /* 8-bit palette with alpha */
+ im->bands = 2;
+ im->pixelsize = 4; /* store in image32 memory */
+ im->linesize = xsize * 4;
+ im->palette = ImagingPaletteNew("RGB");
+
+ } else if (strcmp(mode, "L") == 0) {
+ /* 8-bit greyscale (luminance) images */
+ im->bands = im->pixelsize = 1;
+ im->linesize = xsize;
+
+ } else if (strcmp(mode, "LA") == 0) {
+ /* 8-bit greyscale (luminance) with alpha */
+ im->bands = 2;
+ im->pixelsize = 4; /* store in image32 memory */
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "La") == 0) {
+ /* 8-bit greyscale (luminance) with premultiplied alpha */
+ im->bands = 2;
+ im->pixelsize = 4; /* store in image32 memory */
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "F") == 0) {
+ /* 32-bit floating point images */
+ im->bands = 1;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+ im->type = IMAGING_TYPE_FLOAT32;
+
+ } else if (strcmp(mode, "I") == 0) {
+ /* 32-bit integer images */
+ im->bands = 1;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+ im->type = IMAGING_TYPE_INT32;
+
+ } else if (strcmp(mode, "I;16") == 0 || strcmp(mode, "I;16L") == 0 \
+ || strcmp(mode, "I;16B") == 0 || strcmp(mode, "I;16N") == 0) {
+ /* EXPERIMENTAL */
+ /* 16-bit raw integer images */
+ im->bands = 1;
+ im->pixelsize = 2;
+ im->linesize = xsize * 2;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "RGB") == 0) {
+ /* 24-bit true colour images */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "BGR;15") == 0) {
+ /* EXPERIMENTAL */
+ /* 15-bit reversed true colour */
+ im->bands = 1;
+ im->pixelsize = 2;
+ im->linesize = (xsize*2 + 3) & -4;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "BGR;16") == 0) {
+ /* EXPERIMENTAL */
+ /* 16-bit reversed true colour */
+ im->bands = 1;
+ im->pixelsize = 2;
+ im->linesize = (xsize*2 + 3) & -4;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "BGR;24") == 0) {
+ /* EXPERIMENTAL */
+ /* 24-bit reversed true colour */
+ im->bands = 1;
+ im->pixelsize = 3;
+ im->linesize = (xsize*3 + 3) & -4;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "BGR;32") == 0) {
+ /* EXPERIMENTAL */
+ /* 32-bit reversed true colour */
+ im->bands = 1;
+ im->pixelsize = 4;
+ im->linesize = (xsize*4 + 3) & -4;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "RGBX") == 0) {
+ /* 32-bit true colour images with padding */
+ im->bands = im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "RGBA") == 0) {
+ /* 32-bit true colour images with alpha */
+ im->bands = im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "RGBa") == 0) {
+ /* 32-bit true colour images with premultiplied alpha */
+ im->bands = im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "CMYK") == 0) {
+ /* 32-bit colour separation */
+ im->bands = im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "YCbCr") == 0) {
+ /* 24-bit video format */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "LAB") == 0) {
+ /* 24-bit color, luminance, + 2 color channels */
+ /* L is uint8, a,b are int8 */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "HSV") == 0) {
+ /* 24-bit color, luminance, + 2 color channels */
+ /* L is uint8, a,b are int8 */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else {
+ free(im);
+ return (Imaging) ImagingError_ValueError("unrecognized image mode");
+ }
+
+ /* Setup image descriptor */
+ strcpy(im->mode, mode);
+
+ /* Pointer array (allocate at least one line, to avoid MemoryError
+ exceptions on platforms where calloc(0, x) returns NULL) */
+ im->image = (char **) calloc((ysize > 0) ? ysize : 1, sizeof(void *));
+
+ if ( ! im->image) {
+ free(im);
+ return (Imaging) ImagingError_MemoryError();
+ }
+
+ /* Initialize alias pointers to pixel data. */
+ switch (im->pixelsize) {
+ case 1: case 2: case 3:
+ im->image8 = (UINT8 **) im->image;
+ break;
+ case 4:
+ im->image32 = (INT32 **) im->image;
+ break;
+ }
+
+ ImagingDefaultArena.stats_new_count += 1;
+
+ return im;
+}
+
+Imaging
+ImagingNewPrologue(const char *mode, int xsize, int ysize)
+{
+ return ImagingNewPrologueSubtype(
+ mode, xsize, ysize, sizeof(struct ImagingMemoryInstance));
+}
+
+void
+ImagingDelete(Imaging im)
+{
+ if (!im)
+ return;
+
+ if (im->palette)
+ ImagingPaletteDelete(im->palette);
+
+ if (im->destroy)
+ im->destroy(im);
+
+ if (im->image)
+ free(im->image);
+
+ free(im);
+}
+
+
+/* Array Storage Type */
+/* ------------------ */
+/* Allocate image as an array of line buffers. */
+
+#define IMAGING_PAGE_SIZE (4096)
+
+struct ImagingMemoryArena ImagingDefaultArena = {
+ 1, // alignment
+ 16*1024*1024, // block_size
+ 0, // blocks_max
+ 0, // blocks_cached
+ NULL, // blocks_pool
+ 0, 0, 0, 0, 0 // Stats
+};
+
+int
+ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max)
+{
+ void *p;
+ /* Free already cached blocks */
+ ImagingMemoryClearCache(arena, blocks_max);
+
+ if (blocks_max == 0 && arena->blocks_pool != NULL) {
+ free(arena->blocks_pool);
+ arena->blocks_pool = NULL;
+ } else if (arena->blocks_pool != NULL) {
+ p = realloc(arena->blocks_pool, sizeof(*arena->blocks_pool) * blocks_max);
+ if ( ! p) {
+ // Leave previous blocks_max value
+ return 0;
+ }
+ arena->blocks_pool = p;
+ } else {
+ arena->blocks_pool = calloc(sizeof(*arena->blocks_pool), blocks_max);
+ if ( ! arena->blocks_pool) {
+ return 0;
+ }
+ }
+ arena->blocks_max = blocks_max;
+
+ return 1;
+}
+
+void
+ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size)
+{
+ while (arena->blocks_cached > new_size) {
+ arena->blocks_cached -= 1;
+ free(arena->blocks_pool[arena->blocks_cached].ptr);
+ arena->stats_freed_blocks += 1;
+ }
+}
+
+ImagingMemoryBlock
+memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty)
+{
+ ImagingMemoryBlock block = {NULL, 0};
+
+ if (arena->blocks_cached > 0) {
+ // Get block from cache
+ arena->blocks_cached -= 1;
+ block = arena->blocks_pool[arena->blocks_cached];
+ // Reallocate if needed
+ if (block.size != requested_size){
+ block.ptr = realloc(block.ptr, requested_size);
+ }
+ if ( ! block.ptr) {
+ // Can't allocate, free previous pointer (it is still valid)
+ free(arena->blocks_pool[arena->blocks_cached].ptr);
+ arena->stats_freed_blocks += 1;
+ return block;
+ }
+ if ( ! dirty) {
+ memset(block.ptr, 0, requested_size);
+ }
+ arena->stats_reused_blocks += 1;
+ if (block.ptr != arena->blocks_pool[arena->blocks_cached].ptr) {
+ arena->stats_reallocated_blocks += 1;
+ }
+ } else {
+ if (dirty) {
+ block.ptr = malloc(requested_size);
+ } else {
+ block.ptr = calloc(1, requested_size);
+ }
+ arena->stats_allocated_blocks += 1;
+ }
+ block.size = requested_size;
+ return block;
+}
+
+void
+memory_return_block(ImagingMemoryArena arena, ImagingMemoryBlock block)
+{
+ if (arena->blocks_cached < arena->blocks_max) {
+ // Reduce block size
+ if (block.size > arena->block_size) {
+ block.size = arena->block_size;
+ block.ptr = realloc(block.ptr, arena->block_size);
+ }
+ arena->blocks_pool[arena->blocks_cached] = block;
+ arena->blocks_cached += 1;
+ } else {
+ free(block.ptr);
+ arena->stats_freed_blocks += 1;
+ }
+}
+
+
+static void
+ImagingDestroyArray(Imaging im)
+{
+ int y = 0;
+
+ if (im->blocks) {
+ while (im->blocks[y].ptr) {
+ memory_return_block(&ImagingDefaultArena, im->blocks[y]);
+ y += 1;
+ }
+ free(im->blocks);
+ }
+}
+
+Imaging
+ImagingAllocateArray(Imaging im, int dirty, int block_size)
+{
+ int y, line_in_block, current_block;
+ ImagingMemoryArena arena = &ImagingDefaultArena;
+ ImagingMemoryBlock block = {NULL, 0};
+ int aligned_linesize, lines_per_block, blocks_count;
+ char *aligned_ptr = NULL;
+
+ /* 0-width or 0-height image. No need to do anything */
+ if ( ! im->linesize || ! im->ysize) {
+ return im;
+ }
+
+ aligned_linesize = (im->linesize + arena->alignment - 1) & -arena->alignment;
+ lines_per_block = (block_size - (arena->alignment - 1)) / aligned_linesize;
+ if (lines_per_block == 0)
+ lines_per_block = 1;
+ blocks_count = (im->ysize + lines_per_block - 1) / lines_per_block;
+ // printf("NEW size: %dx%d, ls: %d, lpb: %d, blocks: %d\n",
+ // im->xsize, im->ysize, aligned_linesize, lines_per_block, blocks_count);
+
+ /* One extra pointer is always NULL */
+ im->blocks = calloc(sizeof(*im->blocks), blocks_count + 1);
+ if ( ! im->blocks) {
+ return (Imaging) ImagingError_MemoryError();
+ }
+
+ /* Allocate image as an array of lines */
+ line_in_block = 0;
+ current_block = 0;
+ for (y = 0; y < im->ysize; y++) {
+ if (line_in_block == 0) {
+ int required;
+ int lines_remaining = lines_per_block;
+ if (lines_remaining > im->ysize - y) {
+ lines_remaining = im->ysize - y;
+ }
+ required = lines_remaining * aligned_linesize + arena->alignment - 1;
+ block = memory_get_block(arena, required, dirty);
+ if ( ! block.ptr) {
+ ImagingDestroyArray(im);
+ return (Imaging) ImagingError_MemoryError();
+ }
+ im->blocks[current_block] = block;
+ /* Bulletproof code from libc _int_memalign */
+ aligned_ptr = (char *)(
+ ((size_t) (block.ptr + arena->alignment - 1)) &
+ -((Py_ssize_t) arena->alignment));
+ }
+
+ im->image[y] = aligned_ptr + aligned_linesize * line_in_block;
+
+ line_in_block += 1;
+ if (line_in_block >= lines_per_block) {
+ /* Reset counter and start new block */
+ line_in_block = 0;
+ current_block += 1;
+ }
+ }
+
+ im->destroy = ImagingDestroyArray;
+
+ return im;
+}
+
+
+/* Block Storage Type */
+/* ------------------ */
+/* Allocate image as a single block. */
+
+static void
+ImagingDestroyBlock(Imaging im)
+{
+ if (im->block)
+ free(im->block);
+}
+
+Imaging
+ImagingAllocateBlock(Imaging im)
+{
+ Py_ssize_t y, i;
+
+ /* overflow check for malloc */
+ if (im->linesize &&
+ im->ysize > INT_MAX / im->linesize) {
+ return (Imaging) ImagingError_MemoryError();
+ }
+
+ if (im->ysize * im->linesize <= 0) {
+ /* some platforms return NULL for malloc(0); this fix
+ prevents MemoryError on zero-sized images on such
+ platforms */
+ im->block = (char *) malloc(1);
+ } else {
+ /* malloc check ok, overflow check above */
+ im->block = (char *) calloc(im->ysize, im->linesize);
+ }
+
+ if ( ! im->block) {
+ return (Imaging) ImagingError_MemoryError();
+ }
+
+ for (y = i = 0; y < im->ysize; y++) {
+ im->image[y] = im->block + i;
+ i += im->linesize;
+ }
+
+ im->destroy = ImagingDestroyBlock;
+
+ return im;
+}
+
+/* --------------------------------------------------------------------
+ * Create a new, internally allocated, image.
+ */
+
+Imaging
+ImagingNewInternal(const char* mode, int xsize, int ysize, int dirty)
+{
+ Imaging im;
+
+ if (xsize < 0 || ysize < 0) {
+ return (Imaging) ImagingError_ValueError("bad image size");
+ }
+
+ im = ImagingNewPrologue(mode, xsize, ysize);
+ if ( ! im)
+ return NULL;
+
+ if (ImagingAllocateArray(im, dirty, ImagingDefaultArena.block_size)) {
+ return im;
+ }
+
+ ImagingError_Clear();
+
+ // Try to allocate the image once more with smallest possible block size
+ if (ImagingAllocateArray(im, dirty, IMAGING_PAGE_SIZE)) {
+ return im;
+ }
+
+ ImagingDelete(im);
+ return NULL;
+}
+
+Imaging
+ImagingNew(const char* mode, int xsize, int ysize)
+{
+ return ImagingNewInternal(mode, xsize, ysize, 0);
+}
+
+Imaging
+ImagingNewDirty(const char* mode, int xsize, int ysize)
+{
+ return ImagingNewInternal(mode, xsize, ysize, 1);
+}
+
+Imaging
+ImagingNewBlock(const char* mode, int xsize, int ysize)
+{
+ Imaging im;
+
+ if (xsize < 0 || ysize < 0) {
+ return (Imaging) ImagingError_ValueError("bad image size");
+ }
+
+ im = ImagingNewPrologue(mode, xsize, ysize);
+ if ( ! im)
+ return NULL;
+
+ if (ImagingAllocateBlock(im)) {
+ return im;
+ }
+
+ ImagingDelete(im);
+ return NULL;
+}
+
+Imaging
+ImagingNew2Dirty(const char* mode, Imaging imOut, Imaging imIn)
+{
+ /* allocate or validate output image */
+
+ if (imOut) {
+ /* make sure images match */
+ if (strcmp(imOut->mode, mode) != 0
+ || imOut->xsize != imIn->xsize
+ || imOut->ysize != imIn->ysize) {
+ return ImagingError_Mismatch();
+ }
+ } else {
+ /* create new image */
+ imOut = ImagingNewDirty(mode, imIn->xsize, imIn->ysize);
+ if (!imOut)
+ return NULL;
+ }
+
+ return imOut;
+}
+
+void
+ImagingCopyPalette(Imaging destination, Imaging source)
+{
+ if (source->palette) {
+ if (destination->palette)
+ ImagingPaletteDelete(destination->palette);
+ destination->palette = ImagingPaletteDuplicate(source->palette);
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/SunRleDecode.c b/contrib/python/Pillow/py2/libImaging/SunRleDecode.c
new file mode 100644
index 0000000000..e627c2c9a2
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/SunRleDecode.c
@@ -0,0 +1,146 @@
+/*
+ * THIS IS WORK IN PROGRESS
+ *
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for SUN RLE data.
+ *
+ * history:
+ * 97-01-04 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1997.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+int
+ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ int n;
+ UINT8* ptr;
+ UINT8 extra_data = 0;
+ UINT8 extra_bytes = 0;
+
+ ptr = buf;
+
+ for (;;) {
+
+ if (bytes < 1)
+ return ptr - buf;
+
+ if (ptr[0] == 0x80) {
+
+ if (bytes < 2)
+ break;
+
+ n = ptr[1];
+
+
+ if (n == 0) {
+
+ /* Literal 0x80 (2 bytes) */
+ n = 1;
+
+ state->buffer[state->x] = 0x80;
+
+ ptr += 2;
+ bytes -= 2;
+
+ } else {
+
+ /* Run (3 bytes) */
+ if (bytes < 3)
+ break;
+
+ /* from (https://www.fileformat.info/format/sunraster/egff.htm)
+
+ For example, a run of 100 pixels with the value of
+ 0Ah would encode as the values 80h 64h 0Ah. A
+ single pixel value of 80h would encode as the
+ values 80h 00h. The four unencoded bytes 12345678h
+ would be stored in the RLE stream as 12h 34h 56h
+ 78h. 100 pixels, n=100, not 100 pixels, n=99.
+
+ But Wait! There's More!
+ (https://www.fileformat.info/format/sunraster/spec/598a59c4fac64c52897585d390d86360/view.htm)
+
+ If the first byte is 0x80, and the second byte is
+ not zero, the record is three bytes long. The
+ second byte is a count and the third byte is a
+ value. Output (count+1) pixels of that value.
+
+ 2 specs, same site, but Imagemagick and GIMP seem
+ to agree on the second one.
+ */
+ n += 1;
+
+ if (state->x + n > state->bytes) {
+ extra_bytes = n; /* full value */
+ n = state->bytes - state->x;
+ extra_bytes -= n;
+ extra_data = ptr[2];
+ }
+
+ memset(state->buffer + state->x, ptr[2], n);
+
+ ptr += 3;
+ bytes -= 3;
+
+ }
+
+ } else {
+
+ /* Literal byte */
+ n = 1;
+
+ state->buffer[state->x] = ptr[0];
+
+ ptr += 1;
+ bytes -= 1;
+
+ }
+
+ for (;;) {
+ state->x += n;
+
+ if (state->x >= state->bytes) {
+
+ /* Got a full line, unpack it */
+ state->shuffle((UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+
+ if (extra_bytes == 0) {
+ break;
+ }
+
+ if (state->x > 0) {
+ break; // assert
+ }
+
+ if (extra_bytes >= state->bytes) {
+ n = state->bytes;
+ } else {
+ n = extra_bytes;
+ }
+ memset(state->buffer + state->x, extra_data, n);
+ extra_bytes -= n;
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/TgaRleDecode.c b/contrib/python/Pillow/py2/libImaging/TgaRleDecode.c
new file mode 100644
index 0000000000..d1971e5462
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/TgaRleDecode.c
@@ -0,0 +1,118 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for Targa RLE data.
+ *
+ * history:
+ * 97-01-04 fl created
+ * 98-09-11 fl don't one byte per pixel; take orientation into account
+ *
+ * Copyright (c) Fredrik Lundh 1997.
+ * Copyright (c) Secret Labs AB 1997-98.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+int
+ImagingTgaRleDecode(Imaging im, ImagingCodecState state,
+ UINT8* buf, Py_ssize_t bytes)
+{
+ int n, depth;
+ UINT8* ptr;
+
+ ptr = buf;
+
+ if (state->state == 0) {
+
+ /* check image orientation */
+ if (state->ystep < 0) {
+ state->y = state->ysize-1;
+ state->ystep = -1;
+ } else
+ state->ystep = 1;
+
+ state->state = 1;
+
+ }
+
+ depth = state->count;
+
+ for (;;) {
+
+ if (bytes < 1)
+ return ptr - buf;
+
+ if (ptr[0] & 0x80) {
+
+ /* Run (1 + pixelsize bytes) */
+
+ if (bytes < 1 + depth)
+ break;
+
+ n = depth * ((ptr[0] & 0x7f) + 1);
+
+ if (state->x + n > state->bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ if (depth == 1)
+ memset(state->buffer + state->x, ptr[1], n);
+ else {
+ int i;
+ for (i = 0; i < n; i += depth)
+ memcpy(state->buffer + state->x + i, ptr+1, depth);
+ }
+
+ ptr += 1 + depth;
+ bytes -= 1 + depth;
+
+ } else {
+
+ /* Literal (1+n+1 bytes block) */
+ n = depth * (ptr[0] + 1);
+
+ if (bytes < 1 + n)
+ break;
+
+ if (state->x + n > state->bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ memcpy(state->buffer + state->x, ptr + 1, n);
+
+ ptr += 1 + n;
+ bytes -= 1 + n;
+
+ }
+
+ state->x += n;
+
+ if (state->x >= state->bytes) {
+
+ /* Got a full line, unpack it */
+ state->shuffle((UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ state->y += state->ystep;
+
+ if (state->y < 0 || state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+
+ }
+
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/TgaRleEncode.c b/contrib/python/Pillow/py2/libImaging/TgaRleEncode.c
new file mode 100644
index 0000000000..2fb831e6b1
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/TgaRleEncode.c
@@ -0,0 +1,153 @@
+
+#include "Imaging.h"
+
+#include <assert.h>
+#include <string.h>
+
+
+static int comparePixels(const UINT8* buf, int x, int bytesPerPixel)
+{
+ buf += x * bytesPerPixel;
+ return memcmp(buf, buf + bytesPerPixel, bytesPerPixel) == 0;
+}
+
+
+int
+ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
+{
+ UINT8* dst;
+ int bytesPerPixel;
+
+ if (state->state == 0) {
+ if (state->ystep < 0) {
+ state->ystep = -1;
+ state->y = state->ysize - 1;
+ } else
+ state->ystep = 1;
+
+ state->state = 1;
+ }
+
+ dst = buf;
+ bytesPerPixel = (state->bits + 7) / 8;
+
+ while (1) {
+ int flushCount;
+
+ /*
+ * state->count is the numbers of bytes in the packet,
+ * excluding the 1-byte descriptor.
+ */
+ if (state->count == 0) {
+ UINT8* row;
+ UINT8 descriptor;
+ int startX;
+
+ assert(state->x <= state->xsize);
+
+ /* Make sure we have space for the descriptor. */
+ if (bytes < 1)
+ break;
+
+ if (state->x == state->xsize) {
+ state->x = 0;
+
+ state->y += state->ystep;
+ if (state->y < 0 || state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+ }
+
+ if (state->x == 0)
+ state->shuffle(
+ state->buffer,
+ (UINT8*)im->image[state->y + state->yoff]
+ + state->xoff * im->pixelsize,
+ state->xsize);
+
+ row = state->buffer;
+
+ /* Start with a raw packet for 1 px. */
+ descriptor = 0;
+ startX = state->x;
+ state->count = bytesPerPixel;
+
+ if (state->x + 1 < state->xsize) {
+ int maxLookup;
+ int isRaw;
+
+ isRaw = !comparePixels(row, state->x, bytesPerPixel);
+ ++state->x;
+
+ /*
+ * A packet can contain up to 128 pixels;
+ * 2 are already behind (state->x points to
+ * the second one).
+ */
+ maxLookup = state->x + 126;
+ /* A packet must not span multiple rows. */
+ if (maxLookup > state->xsize - 1)
+ maxLookup = state->xsize - 1;
+
+ if (isRaw) {
+ while (state->x < maxLookup)
+ if (!comparePixels(row, state->x, bytesPerPixel))
+ ++state->x;
+ else {
+ /* Two identical pixels will go to RLE packet. */
+ --state->x;
+ break;
+ }
+
+ state->count += (state->x - startX) * bytesPerPixel;
+ } else {
+ descriptor |= 0x80;
+
+ while (state->x < maxLookup)
+ if (comparePixels(row, state->x, bytesPerPixel))
+ ++state->x;
+ else
+ break;
+ }
+ }
+
+ /*
+ * state->x currently points to the last pixel to be
+ * included in the packet. The pixel count in the
+ * descriptor is 1 less than actual number of pixels in
+ * the packet, that is, state->x == startX if we encode
+ * only 1 pixel.
+ */
+ descriptor += state->x - startX;
+ *dst++ = descriptor;
+ --bytes;
+
+ /* Advance to past-the-last encoded pixel. */
+ ++state->x;
+ }
+
+ assert(bytes >= 0);
+ assert(state->count > 0);
+ assert(state->x > 0);
+ assert(state->count <= state->x * bytesPerPixel);
+
+ if (bytes == 0)
+ break;
+
+ flushCount = state->count;
+ if (flushCount > bytes)
+ flushCount = bytes;
+
+ memcpy(
+ dst,
+ state->buffer + (state->x * bytesPerPixel - state->count),
+ flushCount);
+ dst += flushCount;
+ bytes -= flushCount;
+
+ state->count -= flushCount;
+ }
+
+ return dst - buf;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/TiffDecode.c b/contrib/python/Pillow/py2/libImaging/TiffDecode.c
new file mode 100644
index 0000000000..c3df1174eb
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/TiffDecode.c
@@ -0,0 +1,682 @@
+/*
+ * The Python Imaging Library.
+ * $Id: //modules/pil/libImaging/TiffDecode.c#1 $
+ *
+ * LibTiff-based Group3 and Group4 decoder
+ *
+ *
+ * started modding to use non-private tiff functions to port to libtiff 4.x
+ * eds 3/12/12
+ *
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBTIFF
+
+#ifndef uint
+#define uint uint32
+#endif
+
+#include "TiffDecode.h"
+
+void dump_state(const TIFFSTATE *state){
+ TRACE(("State: Location %u size %d eof %d data: %p ifd: %d\n", (uint)state->loc,
+ (int)state->size, (uint)state->eof, state->data, state->ifd));
+}
+
+/*
+ procs for TIFFOpenClient
+*/
+
+tsize_t _tiffReadProc(thandle_t hdata, tdata_t buf, tsize_t size) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+ tsize_t to_read;
+
+ TRACE(("_tiffReadProc: %d \n", (int)size));
+ dump_state(state);
+
+ to_read = min(size, min(state->size, (tsize_t)state->eof) - (tsize_t)state->loc);
+ TRACE(("to_read: %d\n", (int)to_read));
+
+ _TIFFmemcpy(buf, (UINT8 *)state->data + state->loc, to_read);
+ state->loc += (toff_t)to_read;
+
+ TRACE( ("location: %u\n", (uint)state->loc));
+ return to_read;
+}
+
+tsize_t _tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+ tsize_t to_write;
+
+ TRACE(("_tiffWriteProc: %d \n", (int)size));
+ dump_state(state);
+
+ to_write = min(size, state->size - (tsize_t)state->loc);
+ if (state->flrealloc && size>to_write) {
+ tdata_t new_data;
+ tsize_t newsize=state->size;
+ while (newsize < (size + state->size)) {
+ if (newsize > INT_MAX - 64*1024){
+ return 0;
+ }
+ newsize += 64*1024;
+ // newsize*=2; // UNDONE, by 64k chunks?
+ }
+ TRACE(("Reallocing in write to %d bytes\n", (int)newsize));
+ /* malloc check ok, overflow checked above */
+ new_data = realloc(state->data, newsize);
+ if (!new_data) {
+ // fail out
+ return 0;
+ }
+ state->data = new_data;
+ state->size = newsize;
+ to_write = size;
+ }
+
+ TRACE(("to_write: %d\n", (int)to_write));
+
+ _TIFFmemcpy((UINT8 *)state->data + state->loc, buf, to_write);
+ state->loc += (toff_t)to_write;
+ state->eof = max(state->loc, state->eof);
+
+ dump_state(state);
+ return to_write;
+}
+
+toff_t _tiffSeekProc(thandle_t hdata, toff_t off, int whence) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+
+ TRACE(("_tiffSeekProc: off: %u whence: %d \n", (uint)off, whence));
+ dump_state(state);
+ switch (whence) {
+ case 0:
+ state->loc = off;
+ break;
+ case 1:
+ state->loc += off;
+ break;
+ case 2:
+ state->loc = state->eof + off;
+ break;
+ }
+ dump_state(state);
+ return state->loc;
+}
+
+int _tiffCloseProc(thandle_t hdata) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+
+ TRACE(("_tiffCloseProc \n"));
+ dump_state(state);
+
+ return 0;
+}
+
+
+toff_t _tiffSizeProc(thandle_t hdata) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+
+ TRACE(("_tiffSizeProc \n"));
+ dump_state(state);
+
+ return (toff_t)state->size;
+}
+
+int _tiffMapProc(thandle_t hdata, tdata_t* pbase, toff_t* psize) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+
+ TRACE(("_tiffMapProc input size: %u, data: %p\n", (uint)*psize, *pbase));
+ dump_state(state);
+
+ *pbase = state->data;
+ *psize = state->size;
+ TRACE(("_tiffMapProc returning size: %u, data: %p\n", (uint)*psize, *pbase));
+ return (1);
+}
+
+int _tiffNullMapProc(thandle_t hdata, tdata_t* pbase, toff_t* psize) {
+ (void) hdata; (void) pbase; (void) psize;
+ return (0);
+}
+
+void _tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) {
+ TRACE(("_tiffUnMapProc\n"));
+ (void) hdata; (void) base; (void) size;
+}
+
+int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) {
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+
+ TRACE(("initing libtiff\n"));
+ TRACE(("filepointer: %d \n", fp));
+ TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
+ state->x, state->y, state->ystep));
+ TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
+ state->xoff, state->yoff));
+ TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
+ TRACE(("State: context %p \n", state->context));
+
+ clientstate->loc = 0;
+ clientstate->size = 0;
+ clientstate->data = 0;
+ clientstate->fp = fp;
+ clientstate->ifd = offset;
+ clientstate->eof = 0;
+
+ return 1;
+}
+
+
+int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) {
+ uint16 photometric;
+
+ TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
+
+ // To avoid dealing with YCbCr subsampling, let libtiff handle it
+ if (photometric == PHOTOMETRIC_YCBCR) {
+ UINT32 tile_width, tile_height, swap_line_size, i_row;
+ UINT32* swap_line;
+
+ TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width);
+ TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_height);
+
+ swap_line_size = tile_width * sizeof(UINT32);
+ if (tile_width != swap_line_size / sizeof(UINT32)) {
+ return -1;
+ }
+
+ /* Read the tile into an RGBA array */
+ if (!TIFFReadRGBATile(tiff, col, row, buffer)) {
+ return -1;
+ }
+
+ swap_line = (UINT32*)malloc(swap_line_size);
+ if (swap_line == NULL) {
+ return -1;
+ }
+ /*
+ * For some reason the TIFFReadRGBATile() function chooses the
+ * lower left corner as the origin. Vertically mirror scanlines.
+ */
+ for(i_row = 0; i_row < tile_height / 2; i_row++) {
+ UINT32 *top_line, *bottom_line;
+
+ top_line = buffer + tile_width * i_row;
+ bottom_line = buffer + tile_width * (tile_height - i_row - 1);
+
+ memcpy(swap_line, top_line, 4*tile_width);
+ memcpy(top_line, bottom_line, 4*tile_width);
+ memcpy(bottom_line, swap_line, 4*tile_width);
+ }
+
+ free(swap_line);
+
+ return 0;
+ }
+
+ if (TIFFReadTile(tiff, (tdata_t)buffer, col, row, 0, 0) == -1) {
+ TRACE(("Decode Error, Tile at %dx%d\n", col, row));
+ return -1;
+ }
+
+ TRACE(("Successfully read tile at %dx%d; \n\n", col, row));
+
+ return 0;
+}
+
+int ReadStrip(TIFF* tiff, UINT32 row, UINT32* buffer) {
+ uint16 photometric;
+ TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
+
+ // To avoid dealing with YCbCr subsampling, let libtiff handle it
+ if (photometric == PHOTOMETRIC_YCBCR) {
+ TIFFRGBAImage img;
+ char emsg[1024] = "";
+ UINT32 rows_per_strip, rows_to_read;
+ int ok;
+
+
+ TIFFGetFieldDefaulted(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
+ if ((row % rows_per_strip) != 0) {
+ TRACE(("Row passed to ReadStrip() must be first in a strip."));
+ return -1;
+ }
+
+ if (TIFFRGBAImageOK(tiff, emsg) && TIFFRGBAImageBegin(&img, tiff, 0, emsg)) {
+ TRACE(("Initialized RGBAImage\n"));
+
+ img.req_orientation = ORIENTATION_TOPLEFT;
+ img.row_offset = row;
+ img.col_offset = 0;
+
+ rows_to_read = min(rows_per_strip, img.height - row);
+
+ TRACE(("rows to read: %d\n", rows_to_read));
+ ok = TIFFRGBAImageGet(&img, buffer, img.width, rows_to_read);
+
+ TIFFRGBAImageEnd(&img);
+ } else {
+ ok = 0;
+ }
+
+ if (ok == 0) {
+ TRACE(("Decode Error, row %d; msg: %s\n", row, emsg));
+ return -1;
+ }
+
+ return 0;
+ }
+
+ if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, row, 0), (tdata_t)buffer, -1) == -1) {
+ TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, row, 0)));
+ return -1;
+ }
+
+ return 0;
+}
+
+int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes) {
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ char *filename = "tempfile.tif";
+ char *mode = "r";
+ TIFF *tiff;
+
+ /* buffer is the encoded file, bytes is the length of the encoded file */
+ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */
+
+ TRACE(("in decoder: bytes %d\n", bytes));
+ TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
+ state->x, state->y, state->ystep));
+ TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
+ state->xoff, state->yoff));
+ TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
+ TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
+ TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3]));
+ TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
+ im->mode, im->type, im->bands, im->xsize, im->ysize));
+ TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n",
+ im->image8, im->image32, im->image, im->block));
+ TRACE(("Image: pixelsize: %d, linesize %d \n",
+ im->pixelsize, im->linesize));
+
+ dump_state(clientstate);
+ clientstate->size = bytes;
+ clientstate->eof = clientstate->size;
+ clientstate->loc = 0;
+ clientstate->data = (tdata_t)buffer;
+ clientstate->flrealloc = 0;
+ dump_state(clientstate);
+
+ TIFFSetWarningHandler(NULL);
+ TIFFSetWarningHandlerExt(NULL);
+
+ if (clientstate->fp) {
+ TRACE(("Opening using fd: %d\n",clientstate->fp));
+ lseek(clientstate->fp,0,SEEK_SET); // Sometimes, I get it set to the end.
+ tiff = TIFFFdOpen(clientstate->fp, filename, mode);
+ } else {
+ TRACE(("Opening from string\n"));
+ tiff = TIFFClientOpen(filename, mode,
+ (thandle_t) clientstate,
+ _tiffReadProc, _tiffWriteProc,
+ _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
+ _tiffMapProc, _tiffUnmapProc);
+ }
+
+ if (!tiff){
+ TRACE(("Error, didn't get the tiff\n"));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (clientstate->ifd){
+ int rv;
+ uint32 ifdoffset = clientstate->ifd;
+ TRACE(("reading tiff ifd %u\n", ifdoffset));
+ rv = TIFFSetSubDirectory(tiff, ifdoffset);
+ if (!rv){
+ TRACE(("error in TIFFSetSubDirectory"));
+ return -1;
+ }
+ }
+
+ if (TIFFIsTiled(tiff)) {
+ UINT32 x, y, tile_y, row_byte_size;
+ UINT32 tile_width, tile_length, current_tile_width;
+ UINT8 *new_data;
+
+ TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width);
+ TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length);
+
+ // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size
+ row_byte_size = (tile_width * state->bits + 7) / 8;
+
+ /* overflow check for realloc */
+ if (INT_MAX / row_byte_size < tile_length) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ TIFFClose(tiff);
+ return -1;
+ }
+
+ state->bytes = row_byte_size * tile_length;
+
+ /* realloc to fit whole tile */
+ /* malloc check above */
+ new_data = realloc (state->buffer, state->bytes);
+ if (!new_data) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ TIFFClose(tiff);
+ return -1;
+ }
+
+ state->buffer = new_data;
+
+ TRACE(("TIFFTileSize: %d\n", state->bytes));
+
+ for (y = state->yoff; y < state->ysize; y += tile_length) {
+ for (x = state->xoff; x < state->xsize; x += tile_width) {
+ if (ReadTile(tiff, x, y, (UINT32*) state->buffer) == -1) {
+ TRACE(("Decode Error, Tile at %dx%d\n", x, y));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ TIFFClose(tiff);
+ return -1;
+ }
+
+ TRACE(("Read tile at %dx%d; \n\n", x, y));
+
+ current_tile_width = min(tile_width, state->xsize - x);
+
+ // iterate over each line in the tile and stuff data into image
+ for (tile_y = 0; tile_y < min(tile_length, state->ysize - y); tile_y++) {
+ TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width));
+
+ // UINT8 * bbb = state->buffer + tile_y * row_byte_size;
+ // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
+
+ state->shuffle((UINT8*) im->image[tile_y + y] + x * im->pixelsize,
+ state->buffer + tile_y * row_byte_size,
+ current_tile_width
+ );
+ }
+ }
+ }
+ } else {
+ UINT32 strip_row, row_byte_size;
+ UINT8 *new_data;
+ UINT32 rows_per_strip;
+ int ret;
+
+ ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
+ if (ret != 1) {
+ rows_per_strip = state->ysize;
+ }
+ TRACE(("RowsPerStrip: %u \n", rows_per_strip));
+
+ // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size
+ row_byte_size = (state->xsize * state->bits + 7) / 8;
+
+ /* overflow check for realloc */
+ if (INT_MAX / row_byte_size < rows_per_strip) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ TIFFClose(tiff);
+ return -1;
+ }
+
+ state->bytes = rows_per_strip * row_byte_size;
+
+ TRACE(("StripSize: %d \n", state->bytes));
+
+ /* realloc to fit whole strip */
+ /* malloc check above */
+ new_data = realloc (state->buffer, state->bytes);
+ if (!new_data) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ TIFFClose(tiff);
+ return -1;
+ }
+
+ state->buffer = new_data;
+
+ for (; state->y < state->ysize; state->y += rows_per_strip) {
+ if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) {
+ TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0)));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ TIFFClose(tiff);
+ return -1;
+ }
+
+ TRACE(("Decoded strip for row %d \n", state->y));
+
+ // iterate over each row in the strip and stuff data into image
+ for (strip_row = 0; strip_row < min(rows_per_strip, state->ysize - state->y); strip_row++) {
+ TRACE(("Writing data into line %d ; \n", state->y + strip_row));
+
+ // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip);
+ // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
+
+ state->shuffle((UINT8*) im->image[state->y + state->yoff + strip_row] +
+ state->xoff * im->pixelsize,
+ state->buffer + strip_row * row_byte_size,
+ state->xsize);
+ }
+ }
+ }
+
+ TIFFClose(tiff);
+ TRACE(("Done Decoding, Returning \n"));
+ // Returning -1 here to force ImageFile.load to break, rather than
+ // even think about looping back around.
+ return -1;
+}
+
+int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) {
+ // Open the FD or the pointer as a tiff file, for writing.
+ // We may have to do some monkeying around to make this really work.
+ // If we have a fp, then we're good.
+ // If we have a memory string, we're probably going to have to malloc, then
+ // shuffle bytes into the writescanline process.
+ // Going to have to deal with the directory as well.
+
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ int bufsize = 64*1024;
+ char *mode = "w";
+
+ TRACE(("initing libtiff\n"));
+ TRACE(("Filename %s, filepointer: %d \n", filename, fp));
+ TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
+ state->x, state->y, state->ystep));
+ TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
+ state->xoff, state->yoff));
+ TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
+ TRACE(("State: context %p \n", state->context));
+
+ clientstate->loc = 0;
+ clientstate->size = 0;
+ clientstate->eof =0;
+ clientstate->data = 0;
+ clientstate->flrealloc = 0;
+ clientstate->fp = fp;
+
+ state->state = 0;
+
+ if (fp) {
+ TRACE(("Opening using fd: %d for writing \n",clientstate->fp));
+ clientstate->tiff = TIFFFdOpen(clientstate->fp, filename, mode);
+ } else {
+ // malloc a buffer to write the tif, we're going to need to realloc or something if we need bigger.
+ TRACE(("Opening a buffer for writing \n"));
+ /* malloc check ok, small constant allocation */
+ clientstate->data = malloc(bufsize);
+ clientstate->size = bufsize;
+ clientstate->flrealloc=1;
+
+ if (!clientstate->data) {
+ TRACE(("Error, couldn't allocate a buffer of size %d\n", bufsize));
+ return 0;
+ }
+
+ clientstate->tiff = TIFFClientOpen(filename, mode,
+ (thandle_t) clientstate,
+ _tiffReadProc, _tiffWriteProc,
+ _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
+ _tiffNullMapProc, _tiffUnmapProc); /*force no mmap*/
+
+ }
+
+ if (!clientstate->tiff) {
+ TRACE(("Error, couldn't open tiff file\n"));
+ return 0;
+ }
+
+ return 1;
+
+}
+
+int ImagingLibTiffMergeFieldInfo(ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length){
+ // Refer to libtiff docs (http://www.simplesystems.org/libtiff/addingtags.html)
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ char field_name[10];
+ uint32 n;
+ int status = 0;
+
+ // custom fields added with ImagingLibTiffMergeFieldInfo are only used for
+ // decoding, ignore readcount;
+ int readcount = 0;
+ // we support writing a single value, or a variable number of values
+ int writecount = 1;
+ // whether the first value should encode the number of values.
+ int passcount = 0;
+
+ TIFFFieldInfo info[] = {
+ { key, readcount, writecount, field_type, FIELD_CUSTOM, 1, passcount, field_name }
+ };
+
+ if (is_var_length) {
+ info[0].field_writecount = -1;
+ }
+
+ if (is_var_length && field_type != TIFF_ASCII) {
+ info[0].field_passcount = 1;
+ }
+
+ n = sizeof(info) / sizeof(info[0]);
+
+ // Test for libtiff 4.0 or later, excluding libtiff 3.9.6 and 3.9.7
+#if TIFFLIB_VERSION >= 20111221 && TIFFLIB_VERSION != 20120218 && TIFFLIB_VERSION != 20120922
+ status = TIFFMergeFieldInfo(clientstate->tiff, info, n);
+#else
+ TIFFMergeFieldInfo(clientstate->tiff, info, n);
+#endif
+ return status;
+}
+
+int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...){
+ // after tif_dir.c->TIFFSetField.
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ va_list ap;
+ int status;
+
+ va_start(ap, tag);
+ status = TIFFVSetField(clientstate->tiff, tag, ap);
+ va_end(ap);
+ return status;
+}
+
+
+int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes) {
+ /* One shot encoder. Encode everything to the tiff in the clientstate.
+ If we're running off of a FD, then run once, we're good, everything
+ ends up in the file, we close and we're done.
+
+ If we're going to memory, then we need to write the whole file into memory, then
+ parcel it back out to the pystring buffer bytes at a time.
+
+ */
+
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ TIFF *tiff = clientstate->tiff;
+
+ TRACE(("in encoder: bytes %d\n", bytes));
+ TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
+ state->x, state->y, state->ystep));
+ TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
+ state->xoff, state->yoff));
+ TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
+ TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
+ TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3]));
+ TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
+ im->mode, im->type, im->bands, im->xsize, im->ysize));
+ TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n",
+ im->image8, im->image32, im->image, im->block));
+ TRACE(("Image: pixelsize: %d, linesize %d \n",
+ im->pixelsize, im->linesize));
+
+ dump_state(clientstate);
+
+ if (state->state == 0) {
+ TRACE(("Encoding line bt line"));
+ while(state->y < state->ysize){
+ state->shuffle(state->buffer,
+ (UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->xsize);
+
+ if (TIFFWriteScanline(tiff, (tdata_t)(state->buffer), (uint32)state->y, 0) == -1) {
+ TRACE(("Encode Error, row %d\n", state->y));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ TIFFClose(tiff);
+ if (!clientstate->fp){
+ free(clientstate->data);
+ }
+ return -1;
+ }
+ state->y++;
+ }
+
+ if (state->y == state->ysize) {
+ state->state=1;
+
+ TRACE(("Flushing \n"));
+ if (!TIFFFlush(tiff)) {
+ TRACE(("Error flushing the tiff"));
+ // likely reason is memory.
+ state->errcode = IMAGING_CODEC_MEMORY;
+ TIFFClose(tiff);
+ if (!clientstate->fp){
+ free(clientstate->data);
+ }
+ return -1;
+ }
+ TRACE(("Closing \n"));
+ TIFFClose(tiff);
+ // reset the clientstate metadata to use it to read out the buffer.
+ clientstate->loc = 0;
+ clientstate->size = clientstate->eof; // redundant?
+ }
+ }
+
+ if (state->state == 1 && !clientstate->fp) {
+ int read = (int)_tiffReadProc(clientstate, (tdata_t)buffer, (tsize_t)bytes);
+ TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
+ if (clientstate->loc == clientstate->eof) {
+ TRACE(("Hit EOF, calling an end, freeing data"));
+ state->errcode = IMAGING_CODEC_END;
+ free(clientstate->data);
+ }
+ return read;
+ }
+
+ state->errcode = IMAGING_CODEC_END;
+ return 0;
+}
+
+const char*
+ImagingTiffVersion(void)
+{
+ return TIFFGetVersion();
+}
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/TiffDecode.h b/contrib/python/Pillow/py2/libImaging/TiffDecode.h
new file mode 100644
index 0000000000..08ef35cfd3
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/TiffDecode.h
@@ -0,0 +1,64 @@
+/*
+ * The Python Imaging Library.
+ * $Id: //modules/pil/libImaging/Tiff.h#1 $
+ *
+ * declarations for the LibTiff-based Group3 and Group4 decoder
+ *
+ */
+
+#ifndef _TIFFIO_
+#include <tiffio.h>
+#endif
+#ifndef _TIFF_
+#include <tiff.h>
+#endif
+
+/* UNDONE -- what are we using from this? */
+/*#ifndef _UNISTD_H
+ # include <unistd.h>
+ # endif
+*/
+
+#ifndef min
+#define min(x,y) (( x > y ) ? y : x )
+#define max(x,y) (( x < y ) ? y : x )
+#endif
+
+#ifndef _PIL_LIBTIFF_
+#define _PIL_LIBTIFF_
+
+typedef struct {
+ tdata_t data; /* tdata_t == void* */
+ toff_t loc; /* toff_t == uint32 */
+ tsize_t size; /* tsize_t == int32 */
+ int fp;
+ uint32 ifd; /* offset of the ifd, used for multipage
+ * Should be uint32 for libtiff 3.9.x
+ * uint64 for libtiff 4.0.x
+ */
+ TIFF *tiff; /* Used in write */
+ toff_t eof;
+ int flrealloc;/* may we realloc */
+} TIFFSTATE;
+
+
+
+extern int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset);
+extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp);
+extern int ImagingLibTiffMergeFieldInfo(ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length);
+extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...);
+
+
+/*
+ Trace debugging
+ legacy, don't enable for Python 3.x, unicode issues.
+*/
+
+/*
+#define VA_ARGS(...) __VA_ARGS__
+#define TRACE(args) fprintf(stderr, VA_ARGS args)
+*/
+
+#define TRACE(args)
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/Unpack.c b/contrib/python/Pillow/py2/libImaging/Unpack.c
new file mode 100644
index 0000000000..ab0c8dc608
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Unpack.c
@@ -0,0 +1,1533 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * code to unpack raw data from various file formats
+ *
+ * history:
+ * 1996-03-07 fl Created (from various decoders)
+ * 1996-04-19 fl Added band unpackers
+ * 1996-05-12 fl Published RGB unpackers
+ * 1996-05-27 fl Added nibble unpacker
+ * 1996-12-10 fl Added complete set of PNG unpackers
+ * 1996-12-29 fl Set alpha byte in RGB unpackers
+ * 1997-01-05 fl Added remaining TGA unpackers
+ * 1997-01-18 fl Added inverting band unpackers
+ * 1997-01-25 fl Added FlashPix unpackers
+ * 1997-05-31 fl Added floating point unpackers
+ * 1998-02-08 fl Added I unpacker
+ * 1998-07-01 fl Added YCbCr unpacker
+ * 1998-07-02 fl Added full set of integer unpackers
+ * 1998-12-29 fl Added mode field, I;16 unpackers
+ * 1998-12-30 fl Added RGBX modes
+ * 1999-02-04 fl Fixed I;16 unpackers
+ * 2003-05-13 fl Added L/RGB reversed unpackers
+ * 2003-09-26 fl Added LA/PA and RGBa->RGB unpackers
+ *
+ * Copyright (c) 1997-2003 by Secret Labs AB.
+ * Copyright (c) 1996-1997 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define X 3
+
+#define A 3
+
+#define C 0
+#define M 1
+#define Y 2
+#define K 3
+
+/* byte-swapping macros */
+
+#define C16N\
+ (tmp[0]=in[0], tmp[1]=in[1]);
+#define C16S\
+ (tmp[1]=in[0], tmp[0]=in[1]);
+#define C32N\
+ (tmp[0]=in[0], tmp[1]=in[1], tmp[2]=in[2], tmp[3]=in[3]);
+#define C32S\
+ (tmp[3]=in[0], tmp[2]=in[1], tmp[1]=in[2], tmp[0]=in[3]);
+#define C64N\
+ (tmp[0]=in[0], tmp[1]=in[1], tmp[2]=in[2], tmp[3]=in[3],\
+ tmp[4]=in[4], tmp[5]=in[5], tmp[6]=in[6], tmp[7]=in[7]);
+#define C64S\
+ (tmp[7]=in[0], tmp[6]=in[1], tmp[5]=in[2], tmp[4]=in[3],\
+ tmp[3]=in[4], tmp[2]=in[5], tmp[1]=in[6], tmp[0]=in[7]);
+
+#ifdef WORDS_BIGENDIAN
+#define C16B C16N
+#define C16L C16S
+#define C32B C32N
+#define C32L C32S
+#define C64B C64N
+#define C64L C64S
+#else
+#define C16B C16S
+#define C16L C16N
+#define C32B C32S
+#define C32L C32N
+#define C64B C64S
+#define C64L C64N
+#endif
+
+/* bit-swapping */
+
+static UINT8 BITFLIP[] = {
+ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112,
+ 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184,
+ 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52,
+ 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220,
+ 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82,
+ 210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154,
+ 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22,
+ 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238,
+ 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97,
+ 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169,
+ 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, 197, 37,
+ 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205,
+ 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 3, 131, 67,
+ 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 11, 139,
+ 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 7,
+ 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127,
+ 255
+};
+
+/* Unpack to "1" image */
+
+static void
+unpack1(UINT8* out, const UINT8* in, int pixels)
+{
+ /* bits (msb first, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = (byte & 128) ? 255 : 0; byte <<= 1;
+ case 7: *out++ = (byte & 128) ? 255 : 0; byte <<= 1;
+ case 6: *out++ = (byte & 128) ? 255 : 0; byte <<= 1;
+ case 5: *out++ = (byte & 128) ? 255 : 0; byte <<= 1;
+ case 4: *out++ = (byte & 128) ? 255 : 0; byte <<= 1;
+ case 3: *out++ = (byte & 128) ? 255 : 0; byte <<= 1;
+ case 2: *out++ = (byte & 128) ? 255 : 0; byte <<= 1;
+ case 1: *out++ = (byte & 128) ? 255 : 0;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpack1I(UINT8* out, const UINT8* in, int pixels)
+{
+ /* bits (msb first, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = (byte & 128) ? 0 : 255; byte <<= 1;
+ case 7: *out++ = (byte & 128) ? 0 : 255; byte <<= 1;
+ case 6: *out++ = (byte & 128) ? 0 : 255; byte <<= 1;
+ case 5: *out++ = (byte & 128) ? 0 : 255; byte <<= 1;
+ case 4: *out++ = (byte & 128) ? 0 : 255; byte <<= 1;
+ case 3: *out++ = (byte & 128) ? 0 : 255; byte <<= 1;
+ case 2: *out++ = (byte & 128) ? 0 : 255; byte <<= 1;
+ case 1: *out++ = (byte & 128) ? 0 : 255;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpack1R(UINT8* out, const UINT8* in, int pixels)
+{
+ /* bits (lsb first, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = (byte & 1) ? 255 : 0; byte >>= 1;
+ case 7: *out++ = (byte & 1) ? 255 : 0; byte >>= 1;
+ case 6: *out++ = (byte & 1) ? 255 : 0; byte >>= 1;
+ case 5: *out++ = (byte & 1) ? 255 : 0; byte >>= 1;
+ case 4: *out++ = (byte & 1) ? 255 : 0; byte >>= 1;
+ case 3: *out++ = (byte & 1) ? 255 : 0; byte >>= 1;
+ case 2: *out++ = (byte & 1) ? 255 : 0; byte >>= 1;
+ case 1: *out++ = (byte & 1) ? 255 : 0;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpack1IR(UINT8* out, const UINT8* in, int pixels)
+{
+ /* bits (lsb first, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = (byte & 1) ? 0 : 255; byte >>= 1;
+ case 7: *out++ = (byte & 1) ? 0 : 255; byte >>= 1;
+ case 6: *out++ = (byte & 1) ? 0 : 255; byte >>= 1;
+ case 5: *out++ = (byte & 1) ? 0 : 255; byte >>= 1;
+ case 4: *out++ = (byte & 1) ? 0 : 255; byte >>= 1;
+ case 3: *out++ = (byte & 1) ? 0 : 255; byte >>= 1;
+ case 2: *out++ = (byte & 1) ? 0 : 255; byte >>= 1;
+ case 1: *out++ = (byte & 1) ? 0 : 255;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpack18(UINT8* out, const UINT8* in, int pixels)
+{
+ /* Unpack a '|b1' image, which is a numpy boolean.
+ 1 == true, 0==false, in bytes */
+
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[i] > 0 ? 255 : 0;
+ }
+}
+
+
+
+/* Unpack to "L" image */
+
+static void
+unpackL2(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles (msb first, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
+ case 3: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
+ case 2: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
+ case 1: *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackL2I(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles (msb first, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
+ case 3: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
+ case 2: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
+ case 1: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackL2R(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles (bit order reversed, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ byte = BITFLIP[byte];
+ switch (pixels) {
+ default: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
+ case 3: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
+ case 2: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
+ case 1: *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackL2IR(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles (bit order reversed, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ byte = BITFLIP[byte];
+ switch (pixels) {
+ default: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
+ case 3: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
+ case 2: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
+ case 1: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackL4(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles (msb first, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = ((byte >> 4) & 0x0FU) * 0x11U; byte <<= 4;
+ case 1: *out++ = ((byte >> 4) & 0x0FU) * 0x11U;
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackL4I(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles (msb first, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); byte <<= 4;
+ case 1: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U);
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackL4R(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles (bit order reversed, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ byte = BITFLIP[byte];
+ switch (pixels) {
+ default: *out++ = ((byte >> 4) & 0x0FU) * 0x11U; byte <<= 4;
+ case 1: *out++ = ((byte >> 4) & 0x0FU) * 0x11U;
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackL4IR(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles (bit order reversed, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ byte = BITFLIP[byte];
+ switch (pixels) {
+ default: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); byte <<= 4;
+ case 1: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U);
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackLA(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* LA, pixel interleaved */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[1]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 2; _out += 4;
+ }
+}
+
+static void
+unpackLAL(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* LA, line interleaved */
+ for (i = 0; i < pixels; i++, _out+=4) {
+ UINT32 iv = MAKE_UINT32(in[i], in[i], in[i], in[i+pixels]);
+ memcpy(_out, &iv, sizeof(iv));
+ }
+}
+
+static void
+unpackLI(UINT8* out, const UINT8* in, int pixels)
+{
+ /* negative */
+ int i;
+ for (i = 0; i < pixels; i++)
+ out[i] = ~in[i];
+}
+
+static void
+unpackLR(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, bit reversed */
+ for (i = 0; i < pixels; i++) {
+ out[i] = BITFLIP[in[i]];
+ }
+}
+
+static void
+unpackL16(UINT8* out, const UINT8* in, int pixels)
+{
+ /* int16 (upper byte, little endian) */
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[1];
+ in += 2;
+ }
+}
+
+static void
+unpackL16B(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* int16 (upper byte, big endian) */
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[0];
+ in += 2;
+ }
+}
+
+
+/* Unpack to "P" image */
+
+static void
+unpackP1(UINT8* out, const UINT8* in, int pixels)
+{
+ /* bits */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = (byte >> 7) & 1; byte <<= 1;
+ case 7: *out++ = (byte >> 7) & 1; byte <<= 1;
+ case 6: *out++ = (byte >> 7) & 1; byte <<= 1;
+ case 5: *out++ = (byte >> 7) & 1; byte <<= 1;
+ case 4: *out++ = (byte >> 7) & 1; byte <<= 1;
+ case 3: *out++ = (byte >> 7) & 1; byte <<= 1;
+ case 2: *out++ = (byte >> 7) & 1; byte <<= 1;
+ case 1: *out++ = (byte >> 7) & 1;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpackP2(UINT8* out, const UINT8* in, int pixels)
+{
+ /* bit pairs */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = (byte >> 6) & 3; byte <<= 2;
+ case 3: *out++ = (byte >> 6) & 3; byte <<= 2;
+ case 2: *out++ = (byte >> 6) & 3; byte <<= 2;
+ case 1: *out++ = (byte >> 6) & 3;
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackP4(UINT8* out, const UINT8* in, int pixels)
+{
+ /* nibbles */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default: *out++ = (byte >> 4) & 15; byte <<= 4;
+ case 1: *out++ = (byte >> 4) & 15;
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackP2L(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, j, m, s;
+ /* bit layers */
+ m = 128;
+ s = (pixels+7)/8;
+ for (i = j = 0; i < pixels; i++) {
+ out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0);
+ if ((m >>= 1) == 0) {
+ m = 128;
+ j++;
+ }
+ }
+}
+
+static void
+unpackP4L(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, j, m, s;
+ /* bit layers (trust the optimizer ;-) */
+ m = 128;
+ s = (pixels+7)/8;
+ for (i = j = 0; i < pixels; i++) {
+ out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0) +
+ ((in[j + 2*s] & m) ? 4 : 0) + ((in[j + 3*s] & m) ? 8 : 0);
+ if ((m >>= 1) == 0) {
+ m = 128;
+ j++;
+ }
+ }
+}
+
+
+/* Unpack to "RGB" image */
+
+void
+ImagingUnpackRGB(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i = 0;
+ /* RGB triplets */
+ for (; i < pixels-1; i++) {
+ UINT32 iv;
+ memcpy(&iv, in, sizeof(iv));
+ iv |= MASK_UINT32_CHANNEL_3;
+ memcpy(_out, &iv, sizeof(iv));
+ in += 3; _out += 4;
+ }
+ for (; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[1], in[2], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 3; _out += 4;
+ }
+}
+
+void
+unpackRGB16L(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* 16-bit RGB triplets, little-endian order */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[1], in[3], in[5], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 6; _out += 4;
+ }
+}
+
+void
+unpackRGB16B(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* 16-bit RGB triplets, big-endian order */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[2], in[4], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 6; _out += 4;
+ }
+}
+
+static void
+unpackRGBL(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, line interleaved */
+ for (i = 0; i < pixels; i++, _out+=4) {
+ UINT32 iv = MAKE_UINT32(in[i], in[i+pixels], in[i+pixels+pixels], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ }
+}
+
+static void
+unpackRGBR(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, bit reversed */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(BITFLIP[in[0]], BITFLIP[in[1]],
+ BITFLIP[in[2]], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 3; _out += 4;
+ }
+}
+
+void
+ImagingUnpackBGR(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, reversed bytes */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 3; _out += 4;
+ }
+}
+
+void
+ImagingUnpackRGB15(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, pixel;
+ /* RGB, 5 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel>>5) & 31) * 255 / 31;
+ out[B] = ((pixel>>10) & 31) * 255 / 31;
+ out[A] = 255;
+ out += 4; in += 2;
+ }
+}
+
+void
+ImagingUnpackRGBA15(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, pixel;
+ /* RGB, 5/5/5/1 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel>>5) & 31) * 255 / 31;
+ out[B] = ((pixel>>10) & 31) * 255 / 31;
+ out[A] = (pixel>>15) * 255;
+ out += 4; in += 2;
+ }
+}
+
+void
+ImagingUnpackBGR15(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, pixel;
+ /* RGB, reversed bytes, 5 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[B] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel>>5) & 31) * 255 / 31;
+ out[R] = ((pixel>>10) & 31) * 255 / 31;
+ out[A] = 255;
+ out += 4; in += 2;
+ }
+}
+
+void
+ImagingUnpackBGRA15(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, pixel;
+ /* RGB, reversed bytes, 5/5/5/1 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[B] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel>>5) & 31) * 255 / 31;
+ out[R] = ((pixel>>10) & 31) * 255 / 31;
+ out[A] = (pixel>>15) * 255;
+ out += 4; in += 2;
+ }
+}
+
+void
+ImagingUnpackRGB16(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, pixel;
+ /* RGB, 5/6/5 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel>>5) & 63) * 255 / 63;
+ out[B] = ((pixel>>11) & 31) * 255 / 31;
+ out[A] = 255;
+ out += 4; in += 2;
+ }
+}
+
+void
+ImagingUnpackBGR16(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, pixel;
+ /* RGB, reversed bytes, 5/6/5 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[B] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel>>5) & 63) * 255 / 63;
+ out[R] = ((pixel>>11) & 31) * 255 / 31;
+ out[A] = 255;
+ out += 4; in += 2;
+ }
+}
+
+void
+ImagingUnpackRGB4B(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, pixel;
+ /* RGB, 4 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 15) * 17;
+ out[G] = ((pixel>>4) & 15) * 17;
+ out[B] = ((pixel>>8) & 15) * 17;
+ out[A] = 255;
+ out += 4; in += 2;
+ }
+}
+
+void
+ImagingUnpackRGBA4B(UINT8* out, const UINT8* in, int pixels)
+{
+ int i, pixel;
+ /* RGBA, 4 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 15) * 17;
+ out[G] = ((pixel>>4) & 15) * 17;
+ out[B] = ((pixel>>8) & 15) * 17;
+ out[A] = ((pixel>>12) & 15) * 17;
+ out += 4; in += 2;
+ }
+}
+
+static void
+ImagingUnpackBGRX(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, reversed bytes with padding */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+static void
+ImagingUnpackXRGB(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, leading pad */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[1], in[2], in[3], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+static void
+ImagingUnpackXBGR(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGB, reversed bytes, leading pad */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[3], in[2], in[1], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+/* Unpack to "RGBA" image */
+
+static void
+unpackRGBALA(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* greyscale with alpha */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[1]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 2; _out += 4;
+ }
+}
+
+static void
+unpackRGBALA16B(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* 16-bit greyscale with alpha, big-endian */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[2]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+static void
+unpackRGBa16L(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* premultiplied 16-bit RGBA, little-endian */
+ for (i = 0; i < pixels; i++) {
+ int a = in[7];
+ UINT32 iv;
+ if ( ! a) {
+ iv = 0;
+ } else if (a == 255) {
+ iv = MAKE_UINT32(in[1], in[3], in[5], a);
+ } else {
+ iv = MAKE_UINT32(CLIP8(in[1] * 255 / a),
+ CLIP8(in[3] * 255 / a),
+ CLIP8(in[5] * 255 / a), a);
+ }
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8; _out += 4;
+ }
+}
+
+static void
+unpackRGBa16B(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* premultiplied 16-bit RGBA, big-endian */
+ for (i = 0; i < pixels; i++) {
+ int a = in[6];
+ UINT32 iv;
+ if ( ! a) {
+ iv = 0;
+ } else if (a == 255) {
+ iv = MAKE_UINT32(in[0], in[2], in[4], a);
+ } else {
+ iv = MAKE_UINT32(CLIP8(in[0] * 255 / a),
+ CLIP8(in[2] * 255 / a),
+ CLIP8(in[4] * 255 / a), a);
+ }
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8; _out += 4;
+ }
+}
+
+static void
+unpackRGBa(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* premultiplied RGBA */
+ for (i = 0; i < pixels; i++) {
+ int a = in[3];
+ UINT32 iv;
+ if ( ! a) {
+ iv = 0;
+ } else if (a == 255) {
+ iv = MAKE_UINT32(in[0], in[1], in[2], a);
+ } else {
+ iv = MAKE_UINT32(CLIP8(in[0] * 255 / a),
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[2] * 255 / a), a);
+ }
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+static void
+unpackRGBaskip1(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ UINT32* out = (UINT32*) _out;
+ /* premultiplied RGBA */
+ for (i = 0; i < pixels; i++) {
+ int a = in[3];
+ if ( ! a) {
+ out[i] = 0;
+ } else if (a == 255) {
+ out[i] = MAKE_UINT32(in[0], in[1], in[2], a);
+ } else {
+ out[i] = MAKE_UINT32(CLIP8(in[0] * 255 / a),
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[2] * 255 / a), a);
+ }
+ in += 5;
+ }
+}
+
+static void
+unpackRGBaskip2(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ UINT32* out = (UINT32*) _out;
+ /* premultiplied RGBA */
+ for (i = 0; i < pixels; i++) {
+ int a = in[3];
+ if ( ! a) {
+ out[i] = 0;
+ } else if (a == 255) {
+ out[i] = MAKE_UINT32(in[0], in[1], in[2], a);
+ } else {
+ out[i] = MAKE_UINT32(CLIP8(in[0] * 255 / a),
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[2] * 255 / a), a);
+ }
+ in += 6;
+ }
+}
+
+static void
+unpackBGRa(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* premultiplied BGRA */
+ for (i = 0; i < pixels; i++) {
+ int a = in[3];
+ UINT32 iv;
+ if ( ! a) {
+ iv = 0;
+ } else if (a == 255) {
+ iv = MAKE_UINT32(in[2], in[1], in[0], a);
+ } else {
+ iv = MAKE_UINT32(CLIP8(in[2] * 255 / a),
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[0] * 255 / a), a);
+ }
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+static void
+unpackRGBAI(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGBA, inverted RGB bytes (FlashPix) */
+ for (i = 0; i < pixels; i++) {
+ out[R] = ~in[0];
+ out[G] = ~in[1];
+ out[B] = ~in[2];
+ out[A] = in[3];
+ out += 4; in += 4;
+ }
+}
+
+static void
+unpackRGBAL(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGBA, line interleaved */
+ for (i = 0; i < pixels; i++, _out+=4) {
+ UINT32 iv = MAKE_UINT32(in[i], in[i+pixels], in[i+pixels+pixels],
+ in[i+pixels+pixels+pixels]);
+ memcpy(_out, &iv, sizeof(iv));
+ }
+}
+
+void
+unpackRGBA16L(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* 16-bit RGBA, little-endian order */
+ for (i = 0; i < pixels; i++, _out+=4) {
+ UINT32 iv = MAKE_UINT32(in[1], in[3], in[5], in[7]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8;
+ }
+}
+
+void
+unpackRGBA16B(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* 16-bit RGBA, big-endian order */
+ for (i = 0; i < pixels; i++, _out+=4) {
+ UINT32 iv = MAKE_UINT32(in[0], in[2], in[4], in[6]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8;
+ }
+}
+
+static void
+unpackARGB(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGBA, leading pad */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[1], in[2], in[3], in[0]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+static void
+unpackABGR(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGBA, reversed bytes */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[3], in[2], in[1], in[0]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+static void
+unpackBGRA(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* RGBA, reversed bytes */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], in[3]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+
+/* Unpack to "CMYK" image */
+
+static void
+unpackCMYKI(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ /* CMYK, inverted bytes (Photoshop 2.5) */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = ~MAKE_UINT32(in[0], in[1], in[2], in[3]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4; _out += 4;
+ }
+}
+
+/* Unpack to "LAB" image */
+/* There are two representations of LAB images for whatever precision:
+ L: Uint (in PS, it's 0-100)
+ A: Int (in ps, -128 .. 128, or elsewhere 0..255, with 128 as middle.
+ Channels in PS display a 0 value as middle grey,
+ LCMS appears to use 128 as the 0 value for these channels)
+ B: Int (as above)
+
+ Since we don't have any signed ints, we're going with the shifted versions
+ internally, and we'll unshift for saving and whatnot.
+*/
+void
+ImagingUnpackLAB(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* LAB triplets */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[0];
+ out[1] = in[1] ^ 128; /* signed in outside world */
+ out[2] = in[2] ^ 128;
+ out[3] = 255;
+ out += 4; in += 3;
+ }
+}
+
+static void
+unpackI16N_I16B(UINT8* out, const UINT8* in, int pixels){
+ int i;
+ UINT8* tmp = (UINT8*) out;
+ for (i = 0; i < pixels; i++) {
+ C16B;
+ in += 2; tmp += 2;
+ }
+
+}
+static void
+unpackI16N_I16(UINT8* out, const UINT8* in, int pixels){
+ int i;
+ UINT8* tmp = (UINT8*) out;
+ for (i = 0; i < pixels; i++) {
+ C16L;
+ in += 2; tmp += 2;
+ }
+}
+
+static void
+unpackI12_I16(UINT8* out, const UINT8* in, int pixels){
+ /* Fillorder 1/MSB -> LittleEndian, for 12bit integer greyscale tiffs.
+
+ According to the TIFF spec:
+
+ FillOrder = 2 should be used only when BitsPerSample = 1 and
+ the data is either uncompressed or compressed using CCITT 1D
+ or 2D compression, to avoid potentially ambiguous situations.
+
+ Yeah. I thought so. We'll see how well people read the spec.
+ We've got several fillorder=2 modes in TiffImagePlugin.py
+
+ There's no spec I can find. It appears that the in storage
+ layout is: 00 80 00 ... -> (128 , 0 ...). The samples are
+ stored in a single big bitian 12bit block, but need to be
+ pulled out to little endian format to be stored in a 2 byte
+ int.
+ */
+
+ int i;
+ UINT16 pixel;
+#ifdef WORDS_BIGENDIAN
+ UINT8* tmp = (UINT8 *)&pixel;
+#endif
+ for (i = 0; i < pixels-1; i+=2) {
+ pixel = (((UINT16) in[0]) << 4 ) + (in[1] >>4);
+#ifdef WORDS_BIGENDIAN
+ out[0] = tmp[1]; out[1] = tmp[0];
+#else
+ memcpy(out, &pixel, sizeof(pixel));
+#endif
+
+ out+=2;
+ pixel = (((UINT16) (in[1] & 0x0F)) << 8) + in[2];
+#ifdef WORDS_BIGENDIAN
+ out[0] = tmp[1]; out[1] = tmp[0];
+#else
+ memcpy(out, &pixel, sizeof(pixel));
+#endif
+
+ in += 3; out+=2;
+ }
+ if (i == pixels-1) {
+ pixel = (((UINT16) in[0]) << 4 ) + (in[1] >>4);
+#ifdef WORDS_BIGENDIAN
+ out[0] = tmp[1]; out[1] = tmp[0];
+#else
+ memcpy(out, &pixel, sizeof(pixel));
+#endif
+ }
+}
+
+
+static void
+copy1(UINT8* out, const UINT8* in, int pixels)
+{
+ /* L, P */
+ memcpy(out, in, pixels);
+}
+
+static void
+copy2(UINT8* out, const UINT8* in, int pixels)
+{
+ /* I;16 */
+ memcpy(out, in, pixels*2);
+}
+
+static void
+copy4(UINT8* out, const UINT8* in, int pixels)
+{
+ /* RGBA, CMYK quadruples */
+ memcpy(out, in, 4 * pixels);
+}
+
+static void
+copy4skip1(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ for (i = 0; i < pixels; i++) {
+ memcpy(_out, in, 4);
+ in += 5; _out += 4;
+ }
+}
+
+static void
+copy4skip2(UINT8* _out, const UINT8* in, int pixels)
+{
+ int i;
+ for (i = 0; i < pixels; i++) {
+ memcpy(_out, in, 4);
+ in += 6; _out += 4;
+ }
+}
+
+
+/* Unpack to "I" and "F" images */
+
+#define UNPACK_RAW(NAME, GET, INTYPE, OUTTYPE)\
+static void NAME(UINT8* out_, const UINT8* in, int pixels)\
+{\
+ int i;\
+ OUTTYPE* out = (OUTTYPE*) out_;\
+ for (i = 0; i < pixels; i++, in += sizeof(INTYPE))\
+ out[i] = (OUTTYPE) ((INTYPE) GET);\
+}
+
+#define UNPACK(NAME, COPY, INTYPE, OUTTYPE)\
+static void NAME(UINT8* out_, const UINT8* in, int pixels)\
+{\
+ int i;\
+ OUTTYPE* out = (OUTTYPE*) out_;\
+ INTYPE tmp_;\
+ UINT8* tmp = (UINT8*) &tmp_;\
+ for (i = 0; i < pixels; i++, in += sizeof(INTYPE)) {\
+ COPY;\
+ out[i] = (OUTTYPE) tmp_;\
+ }\
+}
+
+UNPACK_RAW(unpackI8, in[0], UINT8, INT32)
+UNPACK_RAW(unpackI8S, in[0], INT8, INT32)
+UNPACK(unpackI16, C16L, UINT16, INT32)
+UNPACK(unpackI16S, C16L, INT16, INT32)
+UNPACK(unpackI16B, C16B, UINT16, INT32)
+UNPACK(unpackI16BS, C16B, INT16, INT32)
+UNPACK(unpackI16N, C16N, UINT16, INT32)
+UNPACK(unpackI16NS, C16N, INT16, INT32)
+UNPACK(unpackI32, C32L, UINT32, INT32)
+UNPACK(unpackI32S, C32L, INT32, INT32)
+UNPACK(unpackI32B, C32B, UINT32, INT32)
+UNPACK(unpackI32BS, C32B, INT32, INT32)
+UNPACK(unpackI32N, C32N, UINT32, INT32)
+UNPACK(unpackI32NS, C32N, INT32, INT32)
+
+UNPACK_RAW(unpackF8, in[0], UINT8, FLOAT32)
+UNPACK_RAW(unpackF8S, in[0], INT8, FLOAT32)
+UNPACK(unpackF16, C16L, UINT16, FLOAT32)
+UNPACK(unpackF16S, C16L, INT16, FLOAT32)
+UNPACK(unpackF16B, C16B, UINT16, FLOAT32)
+UNPACK(unpackF16BS, C16B, INT16, FLOAT32)
+UNPACK(unpackF16N, C16N, UINT16, FLOAT32)
+UNPACK(unpackF16NS, C16N, INT16, FLOAT32)
+UNPACK(unpackF32, C32L, UINT32, FLOAT32)
+UNPACK(unpackF32S, C32L, INT32, FLOAT32)
+UNPACK(unpackF32B, C32B, UINT32, FLOAT32)
+UNPACK(unpackF32BS, C32B, INT32, FLOAT32)
+UNPACK(unpackF32N, C32N, UINT32, FLOAT32)
+UNPACK(unpackF32NS, C32N, INT32, FLOAT32)
+UNPACK(unpackF32F, C32L, FLOAT32, FLOAT32)
+UNPACK(unpackF32BF, C32B, FLOAT32, FLOAT32)
+UNPACK(unpackF32NF, C32N, FLOAT32, FLOAT32)
+#ifdef FLOAT64
+UNPACK(unpackF64F, C64L, FLOAT64, FLOAT32)
+UNPACK(unpackF64BF, C64B, FLOAT64, FLOAT32)
+UNPACK(unpackF64NF, C64N, FLOAT64, FLOAT32)
+#endif
+
+
+/* Misc. unpackers */
+
+static void
+band0(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 0 only */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[i];
+ out += 4;
+ }
+}
+
+static void
+band1(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 1 only */
+ for (i = 0; i < pixels; i++) {
+ out[1] = in[i];
+ out += 4;
+ }
+}
+
+static void
+band2(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 2 only */
+ for (i = 0; i < pixels; i++) {
+ out[2] = in[i];
+ out += 4;
+ }
+}
+
+static void
+band3(UINT8* out, const UINT8* in, int pixels)
+{
+ /* band 3 only */
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[3] = in[i];
+ out += 4;
+ }
+}
+
+static void
+band0I(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 0 only */
+ for (i = 0; i < pixels; i++) {
+ out[0] = ~in[i];
+ out += 4;
+ }
+}
+
+static void
+band1I(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 1 only */
+ for (i = 0; i < pixels; i++) {
+ out[1] = ~in[i];
+ out += 4;
+ }
+}
+
+static void
+band2I(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 2 only */
+ for (i = 0; i < pixels; i++) {
+ out[2] = ~in[i];
+ out += 4;
+ }
+}
+
+static void
+band3I(UINT8* out, const UINT8* in, int pixels)
+{
+ /* band 3 only */
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[3] = ~in[i];
+ out += 4;
+ }
+}
+
+static struct {
+ const char* mode;
+ const char* rawmode;
+ int bits;
+ ImagingShuffler unpack;
+} unpackers[] = {
+
+ /* raw mode syntax is "<mode>;<bits><flags>" where "bits" defaults
+ depending on mode (1 for "1", 8 for "P" and "L", etc), and
+ "flags" should be given in alphabetical order. if both bits
+ and flags have their default values, the ; should be left out */
+
+ /* flags: "I" inverted data; "R" reversed bit order; "B" big
+ endian byte order (default is little endian); "L" line
+ interleave, "S" signed, "F" floating point */
+
+ /* exception: rawmodes "I" and "F" are always native endian byte order */
+
+ /* bilevel */
+ {"1", "1", 1, unpack1},
+ {"1", "1;I", 1, unpack1I},
+ {"1", "1;R", 1, unpack1R},
+ {"1", "1;IR", 1, unpack1IR},
+ {"1", "1;8", 8, unpack18},
+
+ /* greyscale */
+ {"L", "L;2", 2, unpackL2},
+ {"L", "L;2I", 2, unpackL2I},
+ {"L", "L;2R", 2, unpackL2R},
+ {"L", "L;2IR", 2, unpackL2IR},
+
+ {"L", "L;4", 4, unpackL4},
+ {"L", "L;4I", 4, unpackL4I},
+ {"L", "L;4R", 4, unpackL4R},
+ {"L", "L;4IR", 4, unpackL4IR},
+
+ {"L", "L", 8, copy1},
+ {"L", "L;I", 8, unpackLI},
+ {"L", "L;R", 8, unpackLR},
+ {"L", "L;16", 16, unpackL16},
+ {"L", "L;16B", 16, unpackL16B},
+
+ /* greyscale w. alpha */
+ {"LA", "LA", 16, unpackLA},
+ {"LA", "LA;L", 16, unpackLAL},
+
+ /* palette */
+ {"P", "P;1", 1, unpackP1},
+ {"P", "P;2", 2, unpackP2},
+ {"P", "P;2L", 2, unpackP2L},
+ {"P", "P;4", 4, unpackP4},
+ {"P", "P;4L", 4, unpackP4L},
+ {"P", "P", 8, copy1},
+ {"P", "P;R", 8, unpackLR},
+
+ /* palette w. alpha */
+ {"PA", "PA", 16, unpackLA},
+ {"PA", "PA;L", 16, unpackLAL},
+
+ /* true colour */
+ {"RGB", "RGB", 24, ImagingUnpackRGB},
+ {"RGB", "RGB;L", 24, unpackRGBL},
+ {"RGB", "RGB;R", 24, unpackRGBR},
+ {"RGB", "RGB;16L", 48, unpackRGB16L},
+ {"RGB", "RGB;16B", 48, unpackRGB16B},
+ {"RGB", "BGR", 24, ImagingUnpackBGR},
+ {"RGB", "RGB;15", 16, ImagingUnpackRGB15},
+ {"RGB", "BGR;15", 16, ImagingUnpackBGR15},
+ {"RGB", "RGB;16", 16, ImagingUnpackRGB16},
+ {"RGB", "BGR;16", 16, ImagingUnpackBGR16},
+ {"RGB", "RGB;4B", 16, ImagingUnpackRGB4B},
+ {"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */
+ {"RGB", "RGBX", 32, copy4},
+ {"RGB", "RGBX;L", 32, unpackRGBAL},
+ {"RGB", "RGBA;L", 32, unpackRGBAL},
+ {"RGB", "BGRX", 32, ImagingUnpackBGRX},
+ {"RGB", "XRGB", 32, ImagingUnpackXRGB},
+ {"RGB", "XBGR", 32, ImagingUnpackXBGR},
+ {"RGB", "YCC;P", 24, ImagingUnpackYCC},
+ {"RGB", "R", 8, band0},
+ {"RGB", "G", 8, band1},
+ {"RGB", "B", 8, band2},
+
+ /* true colour w. alpha */
+ {"RGBA", "LA", 16, unpackRGBALA},
+ {"RGBA", "LA;16B", 32, unpackRGBALA16B},
+ {"RGBA", "RGBA", 32, copy4},
+ {"RGBA", "RGBAX", 40, copy4skip1},
+ {"RGBA", "RGBAXX", 48, copy4skip2},
+ {"RGBA", "RGBa", 32, unpackRGBa},
+ {"RGBA", "RGBaX", 40, unpackRGBaskip1},
+ {"RGBA", "RGBaXX", 48, unpackRGBaskip2},
+ {"RGBA", "RGBa;16L", 64, unpackRGBa16L},
+ {"RGBA", "RGBa;16B", 64, unpackRGBa16B},
+ {"RGBA", "BGRa", 32, unpackBGRa},
+ {"RGBA", "RGBA;I", 32, unpackRGBAI},
+ {"RGBA", "RGBA;L", 32, unpackRGBAL},
+ {"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15},
+ {"RGBA", "BGRA;15", 16, ImagingUnpackBGRA15},
+ {"RGBA", "RGBA;4B", 16, ImagingUnpackRGBA4B},
+ {"RGBA", "RGBA;16L", 64, unpackRGBA16L},
+ {"RGBA", "RGBA;16B", 64, unpackRGBA16B},
+ {"RGBA", "BGRA", 32, unpackBGRA},
+ {"RGBA", "ARGB", 32, unpackARGB},
+ {"RGBA", "ABGR", 32, unpackABGR},
+ {"RGBA", "YCCA;P", 32, ImagingUnpackYCCA},
+ {"RGBA", "R", 8, band0},
+ {"RGBA", "G", 8, band1},
+ {"RGBA", "B", 8, band2},
+ {"RGBA", "A", 8, band3},
+
+#ifdef WORDS_BIGENDIAN
+ {"RGB", "RGB;16N", 48, unpackRGB16B},
+ {"RGBA", "RGBa;16N", 64, unpackRGBa16B},
+ {"RGBA", "RGBA;16N", 64, unpackRGBA16B},
+ {"RGBX", "RGBX;16N", 64, unpackRGBA16B},
+#else
+ {"RGB", "RGB;16N", 48, unpackRGB16L},
+ {"RGBA", "RGBa;16N", 64, unpackRGBa16L},
+ {"RGBA", "RGBA;16N", 64, unpackRGBA16L},
+ {"RGBX", "RGBX;16N", 64, unpackRGBA16B},
+#endif
+
+
+ /* true colour w. alpha premultiplied */
+ {"RGBa", "RGBa", 32, copy4},
+ {"RGBa", "BGRa", 32, unpackBGRA},
+ {"RGBa", "aRGB", 32, unpackARGB},
+ {"RGBa", "aBGR", 32, unpackABGR},
+
+ /* true colour w. padding */
+ {"RGBX", "RGB", 24, ImagingUnpackRGB},
+ {"RGBX", "RGB;L", 24, unpackRGBL},
+ {"RGBX", "RGB;16B", 48, unpackRGB16B},
+ {"RGBX", "BGR", 24, ImagingUnpackBGR},
+ {"RGBX", "RGB;15", 16, ImagingUnpackRGB15},
+ {"RGBX", "BGR;15", 16, ImagingUnpackBGR15},
+ {"RGBX", "RGB;4B", 16, ImagingUnpackRGB4B},
+ {"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */
+ {"RGBX", "RGBX", 32, copy4},
+ {"RGBX", "RGBXX", 40, copy4skip1},
+ {"RGBX", "RGBXXX", 48, copy4skip2},
+ {"RGBX", "RGBX;L", 32, unpackRGBAL},
+ {"RGBX", "RGBX;16L", 64, unpackRGBA16L},
+ {"RGBX", "RGBX;16B", 64, unpackRGBA16B},
+ {"RGBX", "BGRX", 32, ImagingUnpackBGRX},
+ {"RGBX", "XRGB", 32, ImagingUnpackXRGB},
+ {"RGBX", "XBGR", 32, ImagingUnpackXBGR},
+ {"RGBX", "YCC;P", 24, ImagingUnpackYCC},
+ {"RGBX", "R", 8, band0},
+ {"RGBX", "G", 8, band1},
+ {"RGBX", "B", 8, band2},
+ {"RGBX", "X", 8, band3},
+
+ /* colour separation */
+ {"CMYK", "CMYK", 32, copy4},
+ {"CMYK", "CMYKX", 40, copy4skip1},
+ {"CMYK", "CMYKXX", 48, copy4skip2},
+ {"CMYK", "CMYK;I", 32, unpackCMYKI},
+ {"CMYK", "CMYK;L", 32, unpackRGBAL},
+ {"CMYK", "CMYK;16L", 64, unpackRGBA16L},
+ {"CMYK", "CMYK;16B", 64, unpackRGBA16B},
+ {"CMYK", "C", 8, band0},
+ {"CMYK", "M", 8, band1},
+ {"CMYK", "Y", 8, band2},
+ {"CMYK", "K", 8, band3},
+ {"CMYK", "C;I", 8, band0I},
+ {"CMYK", "M;I", 8, band1I},
+ {"CMYK", "Y;I", 8, band2I},
+ {"CMYK", "K;I", 8, band3I},
+
+#ifdef WORDS_BIGENDIAN
+ {"CMYK", "CMYK;16N", 64, unpackRGBA16B},
+#else
+ {"CMYK", "CMYK;16N", 64, unpackRGBA16L},
+#endif
+
+ /* video (YCbCr) */
+ {"YCbCr", "YCbCr", 24, ImagingUnpackRGB},
+ {"YCbCr", "YCbCr;L", 24, unpackRGBL},
+ {"YCbCr", "YCbCrX", 32, copy4},
+ {"YCbCr", "YCbCrK", 32, copy4},
+
+ /* LAB Color */
+ {"LAB", "LAB", 24, ImagingUnpackLAB},
+ {"LAB", "L", 8, band0},
+ {"LAB", "A", 8, band1},
+ {"LAB", "B", 8, band2},
+
+ /* HSV Color */
+ {"HSV", "HSV", 24, ImagingUnpackRGB},
+ {"HSV", "H", 8, band0},
+ {"HSV", "S", 8, band1},
+ {"HSV", "V", 8, band2},
+
+ /* integer variations */
+ {"I", "I", 32, copy4},
+ {"I", "I;8", 8, unpackI8},
+ {"I", "I;8S", 8, unpackI8S},
+ {"I", "I;16", 16, unpackI16},
+ {"I", "I;16S", 16, unpackI16S},
+ {"I", "I;16B", 16, unpackI16B},
+ {"I", "I;16BS", 16, unpackI16BS},
+ {"I", "I;16N", 16, unpackI16N},
+ {"I", "I;16NS", 16, unpackI16NS},
+ {"I", "I;32", 32, unpackI32},
+ {"I", "I;32S", 32, unpackI32S},
+ {"I", "I;32B", 32, unpackI32B},
+ {"I", "I;32BS", 32, unpackI32BS},
+ {"I", "I;32N", 32, unpackI32N},
+ {"I", "I;32NS", 32, unpackI32NS},
+
+ /* floating point variations */
+ {"F", "F", 32, copy4},
+ {"F", "F;8", 8, unpackF8},
+ {"F", "F;8S", 8, unpackF8S},
+ {"F", "F;16", 16, unpackF16},
+ {"F", "F;16S", 16, unpackF16S},
+ {"F", "F;16B", 16, unpackF16B},
+ {"F", "F;16BS", 16, unpackF16BS},
+ {"F", "F;16N", 16, unpackF16N},
+ {"F", "F;16NS", 16, unpackF16NS},
+ {"F", "F;32", 32, unpackF32},
+ {"F", "F;32S", 32, unpackF32S},
+ {"F", "F;32B", 32, unpackF32B},
+ {"F", "F;32BS", 32, unpackF32BS},
+ {"F", "F;32N", 32, unpackF32N},
+ {"F", "F;32NS", 32, unpackF32NS},
+ {"F", "F;32F", 32, unpackF32F},
+ {"F", "F;32BF", 32, unpackF32BF},
+ {"F", "F;32NF", 32, unpackF32NF},
+#ifdef FLOAT64
+ {"F", "F;64F", 64, unpackF64F},
+ {"F", "F;64BF", 64, unpackF64BF},
+ {"F", "F;64NF", 64, unpackF64NF},
+#endif
+
+ /* storage modes */
+ {"I;16", "I;16", 16, copy2},
+ {"I;16B", "I;16B", 16, copy2},
+ {"I;16L", "I;16L", 16, copy2},
+
+ {"I;16", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian.
+ {"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian.
+ {"I;16B", "I;16N", 16, unpackI16N_I16B},
+
+ {"I;16", "I;12", 12, unpackI12_I16}, // 12 bit Tiffs stored in 16bits.
+
+ {NULL} /* sentinel */
+};
+
+
+ImagingShuffler
+ImagingFindUnpacker(const char* mode, const char* rawmode, int* bits_out)
+{
+ int i;
+
+ /* find a suitable pixel unpacker */
+ for (i = 0; unpackers[i].rawmode; i++)
+ if (strcmp(unpackers[i].mode, mode) == 0 &&
+ strcmp(unpackers[i].rawmode, rawmode) == 0) {
+ if (bits_out)
+ *bits_out = unpackers[i].bits;
+ return unpackers[i].unpack;
+ }
+
+ /* FIXME: configure a general unpacker based on the type codes... */
+
+ return NULL;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/UnpackYCC.c b/contrib/python/Pillow/py2/libImaging/UnpackYCC.c
new file mode 100644
index 0000000000..19da1f6544
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/UnpackYCC.c
@@ -0,0 +1,162 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * code to convert and unpack PhotoYCC data
+ *
+ * history:
+ * 97-01-25 fl Moved from PcdDecode.c
+ *
+ * Copyright (c) Fredrik Lundh 1996-97.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+/* Tables generated by pcdtables.py, based on transforms taken from
+ the "Colour Space Conversions FAQ" by Roberts/Ford. */
+
+static INT16 L[] = { 0, 1, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18,
+19, 20, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 35, 37, 38, 39, 41,
+42, 43, 45, 46, 48, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 62, 64,
+65, 67, 68, 69, 71, 72, 73, 75, 76, 77, 79, 80, 82, 83, 84, 86, 87,
+88, 90, 91, 92, 94, 95, 96, 98, 99, 101, 102, 103, 105, 106, 107, 109,
+110, 111, 113, 114, 115, 117, 118, 120, 121, 122, 124, 125, 126, 128,
+129, 130, 132, 133, 134, 136, 137, 139, 140, 141, 143, 144, 145, 147,
+148, 149, 151, 152, 153, 155, 156, 158, 159, 160, 162, 163, 164, 166,
+167, 168, 170, 171, 173, 174, 175, 177, 178, 179, 181, 182, 183, 185,
+186, 187, 189, 190, 192, 193, 194, 196, 197, 198, 200, 201, 202, 204,
+205, 206, 208, 209, 211, 212, 213, 215, 216, 217, 219, 220, 221, 223,
+224, 225, 227, 228, 230, 231, 232, 234, 235, 236, 238, 239, 240, 242,
+243, 245, 246, 247, 249, 250, 251, 253, 254, 255, 257, 258, 259, 261,
+262, 264, 265, 266, 268, 269, 270, 272, 273, 274, 276, 277, 278, 280,
+281, 283, 284, 285, 287, 288, 289, 291, 292, 293, 295, 296, 297, 299,
+300, 302, 303, 304, 306, 307, 308, 310, 311, 312, 314, 315, 317, 318,
+319, 321, 322, 323, 325, 326, 327, 329, 330, 331, 333, 334, 336, 337,
+338, 340, 341, 342, 344, 345, 346 };
+
+static INT16 CB[] = { -345, -343, -341, -338, -336, -334, -332, -329,
+-327, -325, -323, -321, -318, -316, -314, -312, -310, -307, -305,
+-303, -301, -298, -296, -294, -292, -290, -287, -285, -283, -281,
+-278, -276, -274, -272, -270, -267, -265, -263, -261, -258, -256,
+-254, -252, -250, -247, -245, -243, -241, -239, -236, -234, -232,
+-230, -227, -225, -223, -221, -219, -216, -214, -212, -210, -207,
+-205, -203, -201, -199, -196, -194, -192, -190, -188, -185, -183,
+-181, -179, -176, -174, -172, -170, -168, -165, -163, -161, -159,
+-156, -154, -152, -150, -148, -145, -143, -141, -139, -137, -134,
+-132, -130, -128, -125, -123, -121, -119, -117, -114, -112, -110,
+-108, -105, -103, -101, -99, -97, -94, -92, -90, -88, -85, -83, -81,
+-79, -77, -74, -72, -70, -68, -66, -63, -61, -59, -57, -54, -52, -50,
+-48, -46, -43, -41, -39, -37, -34, -32, -30, -28, -26, -23, -21, -19,
+-17, -15, -12, -10, -8, -6, -3, -1, 0, 2, 4, 7, 9, 11, 13, 16, 18, 20,
+22, 24, 27, 29, 31, 33, 35, 38, 40, 42, 44, 47, 49, 51, 53, 55, 58,
+60, 62, 64, 67, 69, 71, 73, 75, 78, 80, 82, 84, 86, 89, 91, 93, 95,
+98, 100, 102, 104, 106, 109, 111, 113, 115, 118, 120, 122, 124, 126,
+129, 131, 133, 135, 138, 140, 142, 144, 146, 149, 151, 153, 155, 157,
+160, 162, 164, 166, 169, 171, 173, 175, 177, 180, 182, 184, 186, 189,
+191, 193, 195, 197, 200, 202, 204, 206, 208, 211, 213, 215, 217, 220 };
+
+static INT16 GB[] = { 67, 67, 66, 66, 65, 65, 65, 64, 64, 63, 63, 62,
+62, 62, 61, 61, 60, 60, 59, 59, 59, 58, 58, 57, 57, 56, 56, 56, 55,
+55, 54, 54, 53, 53, 52, 52, 52, 51, 51, 50, 50, 49, 49, 49, 48, 48,
+47, 47, 46, 46, 46, 45, 45, 44, 44, 43, 43, 43, 42, 42, 41, 41, 40,
+40, 40, 39, 39, 38, 38, 37, 37, 37, 36, 36, 35, 35, 34, 34, 34, 33,
+33, 32, 32, 31, 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26,
+25, 25, 25, 24, 24, 23, 23, 22, 22, 22, 21, 21, 20, 20, 19, 19, 19,
+18, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 13, 13, 12, 12, 12, 11,
+11, 10, 10, 9, 9, 9, 8, 8, 7, 7, 6, 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2,
+1, 1, 0, 0, 0, 0, 0, -1, -1, -2, -2, -2, -3, -3, -4, -4, -5, -5, -5,
+-6, -6, -7, -7, -8, -8, -8, -9, -9, -10, -10, -11, -11, -11, -12, -12,
+-13, -13, -14, -14, -14, -15, -15, -16, -16, -17, -17, -18, -18, -18,
+-19, -19, -20, -20, -21, -21, -21, -22, -22, -23, -23, -24, -24, -24,
+-25, -25, -26, -26, -27, -27, -27, -28, -28, -29, -29, -30, -30, -30,
+-31, -31, -32, -32, -33, -33, -33, -34, -34, -35, -35, -36, -36, -36,
+-37, -37, -38, -38, -39, -39, -39, -40, -40, -41, -41, -42 };
+
+static INT16 CR[] = { -249, -247, -245, -243, -241, -239, -238, -236,
+-234, -232, -230, -229, -227, -225, -223, -221, -219, -218, -216,
+-214, -212, -210, -208, -207, -205, -203, -201, -199, -198, -196,
+-194, -192, -190, -188, -187, -185, -183, -181, -179, -178, -176,
+-174, -172, -170, -168, -167, -165, -163, -161, -159, -157, -156,
+-154, -152, -150, -148, -147, -145, -143, -141, -139, -137, -136,
+-134, -132, -130, -128, -127, -125, -123, -121, -119, -117, -116,
+-114, -112, -110, -108, -106, -105, -103, -101, -99, -97, -96, -94,
+-92, -90, -88, -86, -85, -83, -81, -79, -77, -76, -74, -72, -70, -68,
+-66, -65, -63, -61, -59, -57, -55, -54, -52, -50, -48, -46, -45, -43,
+-41, -39, -37, -35, -34, -32, -30, -28, -26, -25, -23, -21, -19, -17,
+-15, -14, -12, -10, -8, -6, -4, -3, -1, 0, 2, 4, 5, 7, 9, 11, 13, 15,
+16, 18, 20, 22, 24, 26, 27, 29, 31, 33, 35, 36, 38, 40, 42, 44, 46,
+47, 49, 51, 53, 55, 56, 58, 60, 62, 64, 66, 67, 69, 71, 73, 75, 77,
+78, 80, 82, 84, 86, 87, 89, 91, 93, 95, 97, 98, 100, 102, 104, 106,
+107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 129, 131,
+133, 135, 137, 138, 140, 142, 144, 146, 148, 149, 151, 153, 155, 157,
+158, 160, 162, 164, 166, 168, 169, 171, 173, 175, 177, 179, 180, 182,
+184, 186, 188, 189, 191, 193, 195, 197, 199, 200, 202, 204, 206, 208,
+209, 211, 213, 215 };
+
+static INT16 GR[] = { 127, 126, 125, 124, 123, 122, 121, 121, 120, 119,
+118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 108, 107, 106,
+105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 95, 94, 93, 92, 91,
+90, 89, 88, 87, 86, 85, 84, 83, 83, 82, 81, 80, 79, 78, 77, 76, 75,
+74, 73, 72, 71, 70, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59,
+58, 57, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 45, 44,
+43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 32, 31, 30, 29, 28,
+27, 26, 25, 24, 23, 22, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12,
+11, 10, 9, 8, 7, 6, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2, -3, -4, -5, -5,
+-6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -18, -19,
+-20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -31, -32,
+-33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -44, -45,
+-46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58,
+-59, -60, -61, -62, -63, -64, -65, -66, -67, -68, -69, -69, -70, -71,
+-72, -73, -74, -75, -76, -77, -78, -79, -80, -81, -82, -82, -83, -84,
+-85, -86, -87, -88, -89, -90, -91, -92, -93, -94, -94, -95, -96, -97,
+-98, -99, -100, -101, -102, -103, -104, -105, -106, -107, -107, -108 };
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+#define YCC2RGB(rgb, y, cb, cr) {\
+ int l = L[y];\
+ int r = l + CR[cr];\
+ int g = l + GR[cr] + GB[cb];\
+ int b = l + CB[cb];\
+ rgb[0] = (r <= 0) ? 0 : (r >= 255) ? 255 : r;\
+ rgb[1] = (g <= 0) ? 0 : (g >= 255) ? 255 : g;\
+ rgb[2] = (b <= 0) ? 0 : (b >= 255) ? 255 : b;\
+}
+
+void
+ImagingUnpackYCC(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* PhotoYCC triplets */
+ for (i = 0; i < pixels; i++) {
+ YCC2RGB(out, in[0], in[1], in[2]);
+ out[A] = 255;
+ out += 4; in += 3;
+ }
+}
+
+void
+ImagingUnpackYCCA(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* PhotoYCC triplets plus premultiplied alpha */
+ for (i = 0; i < pixels; i++) {
+ /* Divide by alpha */
+ UINT8 rgb[3];
+ rgb[0] = (in[3] == 0) ? 0 : (((int) in[0] * 255) / in[3]);
+ rgb[1] = (in[3] == 0) ? 0 : (((int) in[1] * 255) / in[3]);
+ rgb[2] = (in[3] == 0) ? 0 : (((int) in[2] * 255) / in[3]);
+ /* Convert non-multiplied data to RGB */
+ YCC2RGB(out, rgb[0], rgb[1], rgb[2]);
+ out[A] = in[3];
+ out += 4; in += 4;
+ }
+}
diff --git a/contrib/python/Pillow/py2/libImaging/UnsharpMask.c b/contrib/python/Pillow/py2/libImaging/UnsharpMask.c
new file mode 100644
index 0000000000..a034bebf2f
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/UnsharpMask.c
@@ -0,0 +1,95 @@
+/* PILusm, a gaussian blur and unsharp masking library for PIL
+ By Kevin Cazabon, copyright 2003
+ kevin_cazabon@hotmail.com
+ kevin@cazabon.com */
+
+/* Originally released under LGPL. Graciously donated to PIL
+ for distribution under the standard PIL license in 2009." */
+
+#include "Imaging.h"
+
+
+typedef UINT8 pixel[4];
+
+
+static inline UINT8 clip8(int in)
+{
+ if (in >= 255)
+ return 255;
+ if (in <= 0)
+ return 0;
+ return (UINT8) in;
+}
+
+
+Imaging
+ImagingUnsharpMask(Imaging imOut, Imaging imIn, float radius, int percent,
+ int threshold)
+{
+ ImagingSectionCookie cookie;
+ Imaging result;
+
+ int x, y, diff;
+
+ pixel *lineIn = NULL;
+ pixel *lineOut = NULL;
+ UINT8 *lineIn8 = NULL;
+ UINT8 *lineOut8 = NULL;
+
+ /* First, do a gaussian blur on the image, putting results in imOut
+ temporarily. All format checks are in gaussian blur. */
+ result = ImagingGaussianBlur(imOut, imIn, radius, 3);
+ if (!result)
+ return NULL;
+
+ /* Now, go through each pixel, compare "normal" pixel to blurred
+ pixel. If the difference is more than threshold values, apply
+ the OPPOSITE correction to the amount of blur, multiplied by
+ percent. */
+
+ ImagingSectionEnter(&cookie);
+
+ for (y = 0; y < imIn->ysize; y++) {
+ if (imIn->image8)
+ {
+ lineIn8 = imIn->image8[y];
+ lineOut8 = imOut->image8[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ /* compare in/out pixels, apply sharpening */
+ diff = lineIn8[x] - lineOut8[x];
+ if (abs(diff) > threshold) {
+ /* add the diff*percent to the original pixel */
+ lineOut8[x] = clip8(lineIn8[x] + diff * percent / 100);
+ } else {
+ /* new pixel is the same as imIn */
+ lineOut8[x] = lineIn8[x];
+ }
+ }
+ } else {
+ lineIn = (pixel *)imIn->image32[y];
+ lineOut = (pixel *)imOut->image32[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ /* compare in/out pixels, apply sharpening */
+ diff = lineIn[x][0] - lineOut[x][0];
+ lineOut[x][0] = abs(diff) > threshold ?
+ clip8(lineIn[x][0] + diff * percent / 100) : lineIn[x][0];
+
+ diff = lineIn[x][1] - lineOut[x][1];
+ lineOut[x][1] = abs(diff) > threshold ?
+ clip8(lineIn[x][1] + diff * percent / 100) : lineIn[x][1];
+
+ diff = lineIn[x][2] - lineOut[x][2];
+ lineOut[x][2] = abs(diff) > threshold ?
+ clip8(lineIn[x][2] + diff * percent / 100) : lineIn[x][2];
+
+ diff = lineIn[x][3] - lineOut[x][3];
+ lineOut[x][3] = abs(diff) > threshold ?
+ clip8(lineIn[x][3] + diff * percent / 100) : lineIn[x][3];
+ }
+ }
+ }
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/XbmDecode.c b/contrib/python/Pillow/py2/libImaging/XbmDecode.c
new file mode 100644
index 0000000000..75b4961aba
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/XbmDecode.c
@@ -0,0 +1,81 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for XBM hex image data
+ *
+ * history:
+ * 96-04-13 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#define HEX(v) ((v >= '0' && v <= '9') ? v - '0' :\
+ (v >= 'a' && v <= 'f') ? v - 'a' + 10 :\
+ (v >= 'A' && v <= 'F') ? v - 'A' + 10 : 0)
+
+int
+ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ enum { BYTE = 1, SKIP };
+
+ UINT8* ptr;
+
+ if (!state->state)
+ state->state = SKIP;
+
+ ptr = buf;
+
+ for (;;) {
+
+ if (state->state == SKIP) {
+
+ /* Skip forward until next 'x' */
+
+ while (bytes > 0) {
+ if (*ptr == 'x')
+ break;
+ ptr++;
+ bytes--;
+ }
+
+ if (bytes == 0)
+ return ptr - buf;
+
+ state->state = BYTE;
+
+ }
+
+ if (bytes < 3)
+ return ptr - buf;
+
+ state->buffer[state->x] = (HEX(ptr[1])<<4) + HEX(ptr[2]);
+
+ if (++state->x >= state->bytes) {
+
+ /* Got a full line, unpack it */
+ state->shuffle((UINT8*) im->image[state->y], state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+
+ ptr += 3;
+ bytes -= 3;
+
+ state->state = SKIP;
+
+ }
+
+}
diff --git a/contrib/python/Pillow/py2/libImaging/XbmEncode.c b/contrib/python/Pillow/py2/libImaging/XbmEncode.c
new file mode 100644
index 0000000000..e066fd6b58
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/XbmEncode.c
@@ -0,0 +1,106 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * encoder for Xbm data
+ *
+ * history:
+ * 96-11-01 fl created
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+
+int
+ImagingXbmEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
+{
+ const char *hex = "0123456789abcdef";
+
+ UINT8* ptr = buf;
+ int i, n;
+
+ if (!state->state) {
+
+ /* 8 pixels are stored in no more than 6 bytes */
+ state->bytes = 6*(state->xsize+7)/8;
+
+ state->state = 1;
+
+ }
+
+ if (bytes < state->bytes) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return 0;
+ }
+
+ ptr = buf;
+
+ while (bytes >= state->bytes) {
+
+ state->shuffle(state->buffer,
+ (UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->xsize);
+
+ if (state->y < state->ysize-1) {
+
+ /* any line but the last */
+ for (n = 0; n < state->xsize; n += 8) {
+
+ i = state->buffer[n/8];
+
+ *ptr++ = '0';
+ *ptr++ = 'x';
+ *ptr++ = hex[(i>>4)&15];
+ *ptr++ = hex[i&15];
+ *ptr++ = ',';
+ bytes -= 5;
+
+ if (++state->count >= 79/5) {
+ *ptr++ = '\n';
+ bytes--;
+ state->count = 0;
+ }
+
+ }
+
+ state->y++;
+
+ } else {
+
+ /* last line */
+ for (n = 0; n < state->xsize; n += 8) {
+
+ i = state->buffer[n/8];
+
+ *ptr++ = '0';
+ *ptr++ = 'x';
+ *ptr++ = hex[(i>>4)&15];
+ *ptr++ = hex[i&15];
+
+ if (n < state->xsize-8) {
+ *ptr++ = ',';
+ if (++state->count >= 79/5) {
+ *ptr++ = '\n';
+ bytes--;
+ state->count = 0;
+ }
+ } else
+ *ptr++ = '\n';
+
+ bytes -= 5;
+
+ }
+
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/Zip.h b/contrib/python/Pillow/py2/libImaging/Zip.h
new file mode 100644
index 0000000000..21a336f908
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/Zip.h
@@ -0,0 +1,62 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * declarations for the ZIP codecs
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ */
+
+
+#include "zlib.h"
+
+
+/* modes */
+#define ZIP_PNG 0 /* continuous, filtered image data */
+#define ZIP_PNG_PALETTE 1 /* non-continuous data, disable filtering */
+#define ZIP_TIFF_PREDICTOR 2 /* TIFF, with predictor */
+#define ZIP_TIFF 3 /* TIFF, without predictor */
+
+
+typedef struct {
+
+ /* CONFIGURATION */
+
+ /* Codec mode */
+ int mode;
+
+ /* Optimize (max compression) SLOW!!! */
+ int optimize;
+
+ /* 0 no compression, 9 best compression, -1 default compression */
+ int compress_level;
+ /* compression strategy Z_XXX */
+ int compress_type;
+
+ /* Predefined dictionary (experimental) */
+ char* dictionary;
+ int dictionary_size;
+
+ /* PRIVATE CONTEXT (set by decoder/encoder) */
+
+ z_stream z_stream; /* (de)compression stream */
+
+ UINT8* previous; /* previous line (allocated) */
+
+ int last_output; /* # bytes last output by inflate */
+
+ /* Compressor specific stuff */
+ UINT8* prior; /* filter storage (allocated) */
+ UINT8* up;
+ UINT8* average;
+ UINT8* paeth;
+
+ UINT8* output; /* output data */
+
+ int prefix; /* size of filter prefix (0 for TIFF data) */
+
+ int interlaced; /* is the image interlaced? (PNG) */
+
+ int pass; /* current pass of the interlaced image (PNG) */
+
+} ZIPSTATE;
diff --git a/contrib/python/Pillow/py2/libImaging/ZipDecode.c b/contrib/python/Pillow/py2/libImaging/ZipDecode.c
new file mode 100644
index 0000000000..43601c38ee
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/ZipDecode.c
@@ -0,0 +1,298 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for ZIP (deflated) image data.
+ *
+ * history:
+ * 1996-12-14 fl Created (for PNG)
+ * 1997-01-15 fl Prepared to read TIFF/ZIP
+ * 2001-11-19 fl PNG incomplete read patch (from Bernhard Herzog)
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997-2001.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBZ
+
+#include "Zip.h"
+
+static const int OFFSET[] = { 7, 3, 3, 1, 1, 0, 0 };
+static const int STARTING_COL[] = { 0, 4, 0, 2, 0, 1, 0 };
+static const int STARTING_ROW[] = { 0, 0, 4, 0, 2, 0, 1 };
+static const int COL_INCREMENT[] = { 8, 8, 4, 4, 2, 2, 1 };
+static const int ROW_INCREMENT[] = { 8, 8, 8, 4, 4, 2, 2 };
+
+/* Get the length in bytes of a scanline in the pass specified,
+ * for interlaced images */
+static int get_row_len(ImagingCodecState state, int pass)
+{
+ int row_len = (state->xsize + OFFSET[pass]) / COL_INCREMENT[pass];
+ return ((row_len * state->bits) + 7) / 8;
+}
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
+{
+ ZIPSTATE* context = (ZIPSTATE*) state->context;
+ int err;
+ int n;
+ UINT8* ptr;
+ int i, bpp;
+ int row_len;
+
+ if (!state->state) {
+
+ /* Initialization */
+ if (context->mode == ZIP_PNG || context->mode == ZIP_PNG_PALETTE)
+ context->prefix = 1; /* PNG */
+
+ /* overflow check for malloc */
+ if (state->bytes > INT_MAX - 1) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+ /* Expand standard buffer to make room for the (optional) filter
+ prefix, and allocate a buffer to hold the previous line */
+ free(state->buffer);
+ /* malloc check ok, overflow checked above */
+ state->buffer = (UINT8*) malloc(state->bytes+1);
+ context->previous = (UINT8*) malloc(state->bytes+1);
+ if (!state->buffer || !context->previous) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ context->last_output = 0;
+
+ /* Initialize to black */
+ memset(context->previous, 0, state->bytes+1);
+
+ /* Setup decompression context */
+ context->z_stream.zalloc = (alloc_func) NULL;
+ context->z_stream.zfree = (free_func) NULL;
+ context->z_stream.opaque = (voidpf) NULL;
+
+ err = inflateInit(&context->z_stream);
+ if (err < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ free(context->previous);
+ context->previous = NULL;
+ return -1;
+ }
+
+ if (context->interlaced) {
+ context->pass = 0;
+ state->y = STARTING_ROW[context->pass];
+ }
+
+ /* Ready to decode */
+ state->state = 1;
+
+ }
+
+ if (context->interlaced) {
+ row_len = get_row_len(state, context->pass);
+ } else {
+ row_len = state->bytes;
+ }
+
+ /* Setup the source buffer */
+ context->z_stream.next_in = buf;
+ context->z_stream.avail_in = bytes;
+
+ /* Decompress what we've got this far */
+ while (context->z_stream.avail_in > 0) {
+
+ context->z_stream.next_out = state->buffer + context->last_output;
+ context->z_stream.avail_out =
+ row_len + context->prefix - context->last_output;
+
+ err = inflate(&context->z_stream, Z_NO_FLUSH);
+
+ if (err < 0) {
+ /* Something went wrong inside the compression library */
+ if (err == Z_DATA_ERROR)
+ state->errcode = IMAGING_CODEC_BROKEN;
+ else if (err == Z_MEM_ERROR)
+ state->errcode = IMAGING_CODEC_MEMORY;
+ else
+ state->errcode = IMAGING_CODEC_CONFIG;
+ free(context->previous);
+ context->previous = NULL;
+ inflateEnd(&context->z_stream);
+ return -1;
+ }
+
+ n = row_len + context->prefix - context->z_stream.avail_out;
+
+ if (n < row_len + context->prefix) {
+ context->last_output = n;
+ break; /* need more input data */
+ }
+
+ /* Apply predictor */
+ switch (context->mode) {
+ case ZIP_PNG:
+ switch (state->buffer[0]) {
+ case 0:
+ break;
+ case 1:
+ /* prior */
+ bpp = (state->bits + 7) / 8;
+ for (i = bpp+1; i <= row_len; i++)
+ state->buffer[i] += state->buffer[i-bpp];
+ break;
+ case 2:
+ /* up */
+ for (i = 1; i <= row_len; i++)
+ state->buffer[i] += context->previous[i];
+ break;
+ case 3:
+ /* average */
+ bpp = (state->bits + 7) / 8;
+ for (i = 1; i <= bpp; i++)
+ state->buffer[i] += context->previous[i]/2;
+ for (; i <= row_len; i++)
+ state->buffer[i] +=
+ (state->buffer[i-bpp] + context->previous[i])/2;
+ break;
+ case 4:
+ /* paeth filtering */
+ bpp = (state->bits + 7) / 8;
+ for (i = 1; i <= bpp; i++)
+ state->buffer[i] += context->previous[i];
+ for (; i <= row_len; i++) {
+ int a, b, c;
+ int pa, pb, pc;
+
+ /* fetch pixels */
+ a = state->buffer[i-bpp];
+ b = context->previous[i];
+ c = context->previous[i-bpp];
+
+ /* distances to surrounding pixels */
+ pa = abs(b - c);
+ pb = abs(a - c);
+ pc = abs(a + b - 2*c);
+
+ /* pick predictor with the shortest distance */
+ state->buffer[i] +=
+ (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
+
+ }
+ break;
+ default:
+ state->errcode = IMAGING_CODEC_UNKNOWN;
+ free(context->previous);
+ context->previous = NULL;
+ inflateEnd(&context->z_stream);
+ return -1;
+ }
+ break;
+ case ZIP_TIFF_PREDICTOR:
+ bpp = (state->bits + 7) / 8;
+ for (i = bpp+1; i <= row_len; i++)
+ state->buffer[i] += state->buffer[i-bpp];
+ break;
+ }
+
+ /* Stuff data into the image */
+ if (context->interlaced) {
+ int col = STARTING_COL[context->pass];
+ if (state->bits >= 8) {
+ /* Stuff pixels in their correct location, one by one */
+ for (i = 0; i < row_len; i += ((state->bits + 7) / 8)) {
+ state->shuffle((UINT8*) im->image[state->y] +
+ col * im->pixelsize,
+ state->buffer + context->prefix + i, 1);
+ col += COL_INCREMENT[context->pass];
+ }
+ } else {
+ /* Handle case with more than a pixel in each byte */
+ int row_bits = ((state->xsize + OFFSET[context->pass])
+ / COL_INCREMENT[context->pass]) * state->bits;
+ for (i = 0; i < row_bits; i += state->bits) {
+ UINT8 byte = *(state->buffer + context->prefix + (i / 8));
+ byte <<= (i % 8);
+ state->shuffle((UINT8*) im->image[state->y] +
+ col * im->pixelsize, &byte, 1);
+ col += COL_INCREMENT[context->pass];
+ }
+ }
+ /* Find next valid scanline */
+ state->y += ROW_INCREMENT[context->pass];
+ while (state->y >= state->ysize || row_len <= 0) {
+ context->pass++;
+ if (context->pass == 7) {
+ /* Force exit below */
+ state->y = state->ysize;
+ break;
+ }
+ state->y = STARTING_ROW[context->pass];
+ row_len = get_row_len(state, context->pass);
+ /* Since we're moving to the "first" line, the previous line
+ * should be black to make filters work correctly */
+ memset(state->buffer, 0, state->bytes+1);
+ }
+ } else {
+ state->shuffle((UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->buffer + context->prefix,
+ state->xsize);
+ state->y++;
+ }
+
+ /* all inflate output has been consumed */
+ context->last_output = 0;
+
+ if (state->y >= state->ysize || err == Z_STREAM_END) {
+
+ /* The image and the data should end simultaneously */
+ /* if (state->y < state->ysize || err != Z_STREAM_END)
+ state->errcode = IMAGING_CODEC_BROKEN; */
+
+ free(context->previous);
+ context->previous = NULL;
+ inflateEnd(&context->z_stream);
+ return -1; /* end of file (errcode=0) */
+
+ }
+
+ /* Swap buffer pointers */
+ ptr = state->buffer;
+ state->buffer = context->previous;
+ context->previous = ptr;
+
+ }
+
+ return bytes; /* consumed all of it */
+
+}
+
+
+int ImagingZipDecodeCleanup(ImagingCodecState state){
+ /* called to free the decompression engine when the decode terminates
+ due to a corrupt or truncated image
+ */
+ ZIPSTATE* context = (ZIPSTATE*) state->context;
+
+ /* Clean up */
+ if (context->previous) {
+ inflateEnd(&context->z_stream);
+ free(context->previous);
+ context->previous = NULL;
+ }
+ return -1;
+}
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/ZipEncode.c b/contrib/python/Pillow/py2/libImaging/ZipEncode.c
new file mode 100644
index 0000000000..fa1c4e7287
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/ZipEncode.c
@@ -0,0 +1,375 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * coder for ZIP (deflated) image data
+ *
+ * History:
+ * 96-12-29 fl created
+ * 96-12-30 fl adaptive filter selection, encoder tuning
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBZ
+
+#include "Zip.h"
+
+int
+ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
+{
+ ZIPSTATE* context = (ZIPSTATE*) state->context;
+ int err;
+ int compress_level, compress_type;
+ UINT8* ptr;
+ int i, bpp, s, sum;
+ ImagingSectionCookie cookie;
+
+ if (!state->state) {
+
+ /* Initialization */
+
+ /* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */
+
+ /* overflow check for malloc */
+ if (state->bytes > INT_MAX - 1) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ /* Expand standard buffer to make room for the filter selector,
+ and allocate filter buffers */
+ free(state->buffer);
+ /* malloc check ok, overflow checked above */
+ state->buffer = (UINT8*) malloc(state->bytes+1);
+ context->previous = (UINT8*) malloc(state->bytes+1);
+ context->prior = (UINT8*) malloc(state->bytes+1);
+ context->up = (UINT8*) malloc(state->bytes+1);
+ context->average = (UINT8*) malloc(state->bytes+1);
+ context->paeth = (UINT8*) malloc(state->bytes+1);
+ if (!state->buffer || !context->previous || !context->prior ||
+ !context->up || !context->average || !context->paeth) {
+ free(context->paeth);
+ free(context->average);
+ free(context->up);
+ free(context->prior);
+ free(context->previous);
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ /* Initialise filter buffers */
+ state->buffer[0] = 0;
+ context->prior[0] = 1;
+ context->up[0] = 2;
+ context->average[0] = 3;
+ context->paeth[0] = 4;
+
+ /* Initialise previous buffer to black */
+ memset(context->previous, 0, state->bytes+1);
+
+ /* Setup compression context */
+ context->z_stream.zalloc = (alloc_func)0;
+ context->z_stream.zfree = (free_func)0;
+ context->z_stream.opaque = (voidpf)0;
+ context->z_stream.next_in = 0;
+ context->z_stream.avail_in = 0;
+
+ compress_level = (context->optimize) ? Z_BEST_COMPRESSION
+ : context->compress_level;
+
+ if (context->compress_type == -1) {
+ compress_type = (context->mode == ZIP_PNG) ? Z_FILTERED
+ : Z_DEFAULT_STRATEGY;
+ } else {
+ compress_type = context->compress_type;
+ }
+
+ err = deflateInit2(&context->z_stream,
+ /* compression level */
+ compress_level,
+ /* compression method */
+ Z_DEFLATED,
+ /* compression memory resources */
+ 15, 9,
+ /* compression strategy (image data are filtered)*/
+ compress_type);
+ if (err < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ if (context->dictionary && context->dictionary_size > 0) {
+ err = deflateSetDictionary(&context->z_stream, (unsigned char *)context->dictionary,
+ context->dictionary_size);
+ if (err < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+ }
+
+ /* Ready to decode */
+ state->state = 1;
+
+ }
+
+ /* Setup the destination buffer */
+ context->z_stream.next_out = buf;
+ context->z_stream.avail_out = bytes;
+ if (context->z_stream.next_in && context->z_stream.avail_in > 0) {
+ /* We have some data from previous round, deflate it first */
+ err = deflate(&context->z_stream, Z_NO_FLUSH);
+
+ if (err < 0) {
+ /* Something went wrong inside the compression library */
+ if (err == Z_DATA_ERROR)
+ state->errcode = IMAGING_CODEC_BROKEN;
+ else if (err == Z_MEM_ERROR)
+ state->errcode = IMAGING_CODEC_MEMORY;
+ else
+ state->errcode = IMAGING_CODEC_CONFIG;
+ free(context->paeth);
+ free(context->average);
+ free(context->up);
+ free(context->prior);
+ free(context->previous);
+ deflateEnd(&context->z_stream);
+ return -1;
+ }
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (;;) {
+
+ switch (state->state) {
+
+ case 1:
+
+ /* Compress image data */
+ while (context->z_stream.avail_out > 0) {
+
+ if (state->y >= state->ysize) {
+ /* End of image; now flush compressor buffers */
+ state->state = 2;
+ break;
+
+ }
+
+ /* Stuff image data into the compressor */
+ state->shuffle(state->buffer+1,
+ (UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->xsize);
+
+ state->y++;
+
+ context->output = state->buffer;
+
+ if (context->mode == ZIP_PNG) {
+
+ /* Filter the image data. For each line, select
+ the filter that gives the least total distance
+ from zero for the filtered data (taken from
+ LIBPNG) */
+
+ bpp = (state->bits + 7) / 8;
+
+ /* 0. No filter */
+ for (i = 1, sum = 0; i <= state->bytes; i++) {
+ UINT8 v = state->buffer[i];
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+ /* 2. Up. We'll test this first to save time when
+ an image line is identical to the one above. */
+ if (sum > 0) {
+ for (i = 1, s = 0; i <= state->bytes; i++) {
+ UINT8 v = state->buffer[i] - context->previous[i];
+ context->up[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ if (s < sum) {
+ context->output = context->up;
+ sum = s; /* 0 if line was duplicated */
+ }
+ }
+
+ /* 1. Prior */
+ if (sum > 0) {
+ for (i = 1, s = 0; i <= bpp; i++) {
+ UINT8 v = state->buffer[i];
+ context->prior[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ for (; i <= state->bytes; i++) {
+ UINT8 v = state->buffer[i] - state->buffer[i-bpp];
+ context->prior[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ if (s < sum) {
+ context->output = context->prior;
+ sum = s; /* 0 if line is solid */
+ }
+ }
+
+ /* 3. Average (not very common in real-life images,
+ so its only used with the optimize option) */
+ if (context->optimize && sum > 0) {
+ for (i = 1, s = 0; i <= bpp; i++) {
+ UINT8 v = state->buffer[i] - context->previous[i]/2;
+ context->average[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ for (; i <= state->bytes; i++) {
+ UINT8 v = state->buffer[i] -
+ (state->buffer[i-bpp] + context->previous[i])/2;
+ context->average[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ if (s < sum) {
+ context->output = context->average;
+ sum = s;
+ }
+ }
+
+ /* 4. Paeth */
+ if (sum > 0) {
+ for (i = 1, s = 0; i <= bpp; i++) {
+ UINT8 v = state->buffer[i] - context->previous[i];
+ context->paeth[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ for (; i <= state->bytes; i++) {
+ UINT8 v;
+ int a, b, c;
+ int pa, pb, pc;
+
+ /* fetch pixels */
+ a = state->buffer[i-bpp];
+ b = context->previous[i];
+ c = context->previous[i-bpp];
+
+ /* distances to surrounding pixels */
+ pa = abs(b - c);
+ pb = abs(a - c);
+ pc = abs(a + b - 2*c);
+
+ /* pick predictor with the shortest distance */
+ v = state->buffer[i] -
+ ((pa <= pb && pa <= pc) ? a :
+ (pb <= pc) ? b : c);
+ context->paeth[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ if (s < sum) {
+ context->output = context->paeth;
+ sum = s;
+ }
+ }
+ }
+
+ /* Compress this line */
+ context->z_stream.next_in = context->output;
+ context->z_stream.avail_in = state->bytes+1;
+
+ err = deflate(&context->z_stream, Z_NO_FLUSH);
+
+ if (err < 0) {
+ /* Something went wrong inside the compression library */
+ if (err == Z_DATA_ERROR)
+ state->errcode = IMAGING_CODEC_BROKEN;
+ else if (err == Z_MEM_ERROR)
+ state->errcode = IMAGING_CODEC_MEMORY;
+ else
+ state->errcode = IMAGING_CODEC_CONFIG;
+ free(context->paeth);
+ free(context->average);
+ free(context->up);
+ free(context->prior);
+ free(context->previous);
+ deflateEnd(&context->z_stream);
+ ImagingSectionLeave(&cookie);
+ return -1;
+ }
+
+ /* Swap buffer pointers */
+ ptr = state->buffer;
+ state->buffer = context->previous;
+ context->previous = ptr;
+
+ }
+
+ if (context->z_stream.avail_out == 0)
+ break; /* Buffer full */
+
+ case 2:
+
+ /* End of image data; flush compressor buffers */
+
+ while (context->z_stream.avail_out > 0) {
+
+ err = deflate(&context->z_stream, Z_FINISH);
+
+ if (err == Z_STREAM_END) {
+
+ free(context->paeth);
+ free(context->average);
+ free(context->up);
+ free(context->prior);
+ free(context->previous);
+
+ deflateEnd(&context->z_stream);
+
+ state->errcode = IMAGING_CODEC_END;
+
+ break;
+ }
+
+ if (context->z_stream.avail_out == 0)
+ break; /* Buffer full */
+
+ }
+
+ }
+ ImagingSectionLeave(&cookie);
+ return bytes - context->z_stream.avail_out;
+
+ }
+
+ /* Should never ever arrive here... */
+ state->errcode = IMAGING_CODEC_CONFIG;
+ ImagingSectionLeave(&cookie);
+ return -1;
+}
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingZipEncodeCleanup(ImagingCodecState state) {
+ ZIPSTATE* context = (ZIPSTATE*) state->context;
+
+ if (context->dictionary) {
+ free (context->dictionary);
+ context->dictionary = NULL;
+ }
+
+ return -1;
+}
+
+
+
+const char*
+ImagingZipVersion(void)
+{
+ return ZLIB_VERSION;
+}
+
+#endif
diff --git a/contrib/python/Pillow/py2/libImaging/codec_fd.c b/contrib/python/Pillow/py2/libImaging/codec_fd.c
new file mode 100644
index 0000000000..7bd4dadf86
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/codec_fd.c
@@ -0,0 +1,79 @@
+#include "Python.h"
+#include "Imaging.h"
+#include "../py3.h"
+
+
+Py_ssize_t
+_imaging_read_pyFd(PyObject *fd, char* dest, Py_ssize_t bytes)
+{
+ /* dest should be a buffer bytes long, returns length of read
+ -1 on error */
+
+ PyObject *result;
+ char *buffer;
+ Py_ssize_t length;
+ int bytes_result;
+
+ result = PyObject_CallMethod(fd, "read", "n", bytes);
+
+ bytes_result = PyBytes_AsStringAndSize(result, &buffer, &length);
+ if (bytes_result == -1) {
+ goto err;
+ }
+
+ if (length > bytes) {
+ goto err;
+ }
+
+ memcpy(dest, buffer, length);
+
+ Py_DECREF(result);
+ return length;
+
+ err:
+ Py_DECREF(result);
+ return -1;
+
+}
+
+Py_ssize_t
+_imaging_write_pyFd(PyObject *fd, char* src, Py_ssize_t bytes)
+{
+
+ PyObject *result;
+ PyObject *byteObj;
+
+ byteObj = PyBytes_FromStringAndSize(src, bytes);
+ result = PyObject_CallMethod(fd, "write", "O", byteObj);
+
+ Py_DECREF(byteObj);
+ Py_DECREF(result);
+
+ return bytes;
+
+}
+
+int
+_imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence)
+{
+ PyObject *result;
+
+ result = PyObject_CallMethod(fd, "seek", "ni", offset, whence);
+
+ Py_DECREF(result);
+ return 0;
+
+}
+
+Py_ssize_t
+_imaging_tell_pyFd(PyObject *fd)
+{
+ PyObject *result;
+ Py_ssize_t location;
+
+ result = PyObject_CallMethod(fd, "tell", NULL);
+ location = PyInt_AsSsize_t(result);
+
+ Py_DECREF(result);
+ return location;
+}
diff --git a/contrib/python/Pillow/py2/libImaging/raqm.h b/contrib/python/Pillow/py2/libImaging/raqm.h
new file mode 100644
index 0000000000..92c6368b6a
--- /dev/null
+++ b/contrib/python/Pillow/py2/libImaging/raqm.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>
+ * Copyright © 2016 Khaled Hosny <khaledhosny@eglug.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _RAQM_H_
+#define _RAQM_H_
+
+#ifdef HAVE_CONFIG_H
+#error #include "config.h"
+#endif
+
+#ifndef bool
+typedef int bool;
+#endif
+#ifndef uint32_t
+typedef UINT32 uint32_t;
+#endif
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * raqm_t:
+ *
+ * This is the main object holding all state of the currently processed text as
+ * well as its output.
+ *
+ * Since: 0.1
+ */
+typedef struct _raqm raqm_t;
+
+/**
+ * raqm_direction_t:
+ * @RAQM_DIRECTION_DEFAULT: Detect paragraph direction automatically.
+ * @RAQM_DIRECTION_RTL: Paragraph is mainly right-to-left text.
+ * @RAQM_DIRECTION_LTR: Paragraph is mainly left-to-right text.
+ * @RAQM_DIRECTION_TTB: Paragraph is mainly vertical top-to-bottom text.
+ *
+ * Base paragraph direction, see raqm_set_par_direction().
+ *
+ * Since: 0.1
+ */
+typedef enum
+{
+ RAQM_DIRECTION_DEFAULT,
+ RAQM_DIRECTION_RTL,
+ RAQM_DIRECTION_LTR,
+ RAQM_DIRECTION_TTB
+} raqm_direction_t;
+
+/**
+ * raqm_glyph_t:
+ * @index: the index of the glyph in the font file.
+ * @x_advance: the glyph advance width in horizontal text.
+ * @y_advance: the glyph advance width in vertical text.
+ * @x_offset: the horizontal movement of the glyph from the current point.
+ * @y_offset: the vertical movement of the glyph from the current point.
+ * @cluster: the index of original character in input text.
+ * @ftface: the @FT_Face of the glyph.
+ *
+ * The structure that holds information about output glyphs, returned from
+ * raqm_get_glyphs().
+ */
+typedef struct raqm_glyph_t {
+ unsigned int index;
+ int x_advance;
+ int y_advance;
+ int x_offset;
+ int y_offset;
+ uint32_t cluster;
+ FT_Face ftface;
+} raqm_glyph_t;
+
+/**
+ * version 0.1 of the raqm_glyph_t structure
+ */
+typedef struct raqm_glyph_t_01 {
+ unsigned int index;
+ int x_advance;
+ int y_advance;
+ int x_offset;
+ int y_offset;
+ uint32_t cluster;
+} raqm_glyph_t_01;
+
+
+raqm_t *
+raqm_create (void);
+
+raqm_t *
+raqm_reference (raqm_t *rq);
+
+void
+raqm_destroy (raqm_t *rq);
+
+bool
+raqm_set_text (raqm_t *rq,
+ const uint32_t *text,
+ size_t len);
+
+bool
+raqm_set_text_utf8 (raqm_t *rq,
+ const char *text,
+ size_t len);
+
+bool
+raqm_set_par_direction (raqm_t *rq,
+ raqm_direction_t dir);
+
+bool
+raqm_set_language (raqm_t *rq,
+ const char *lang,
+ size_t start,
+ size_t len);
+
+bool
+raqm_add_font_feature (raqm_t *rq,
+ const char *feature,
+ int len);
+
+bool
+raqm_set_freetype_face (raqm_t *rq,
+ FT_Face face);
+
+bool
+raqm_set_freetype_face_range (raqm_t *rq,
+ FT_Face face,
+ size_t start,
+ size_t len);
+
+bool
+raqm_set_freetype_load_flags (raqm_t *rq,
+ int flags);
+
+bool
+raqm_layout (raqm_t *rq);
+
+raqm_glyph_t *
+raqm_get_glyphs (raqm_t *rq,
+ size_t *length);
+
+bool
+raqm_index_to_position (raqm_t *rq,
+ size_t *index,
+ int *x,
+ int *y);
+
+bool
+raqm_position_to_index (raqm_t *rq,
+ int x,
+ int y,
+ size_t *index);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _RAQM_H_ */
diff --git a/contrib/python/Pillow/py2/map.c b/contrib/python/Pillow/py2/map.c
new file mode 100644
index 0000000000..099bb4b3ef
--- /dev/null
+++ b/contrib/python/Pillow/py2/map.c
@@ -0,0 +1,388 @@
+/*
+ * The Python Imaging Library.
+ *
+ * standard memory mapping interface for the Imaging library
+ *
+ * history:
+ * 1998-03-05 fl added Win32 read mapping
+ * 1999-02-06 fl added "I;16" support
+ * 2003-04-21 fl added PyImaging_MapBuffer primitive
+ *
+ * Copyright (c) 1998-2003 by Secret Labs AB.
+ * Copyright (c) 2003 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+/*
+ * FIXME: should move the memory mapping primitives into libImaging!
+ */
+
+#include "Python.h"
+
+#include "Imaging.h"
+
+#include "py3.h"
+
+/* compatibility wrappers (defined in _imaging.c) */
+extern int PyImaging_CheckBuffer(PyObject* buffer);
+extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view);
+
+/* -------------------------------------------------------------------- */
+/* Standard mapper */
+
+typedef struct {
+ PyObject_HEAD
+ char* base;
+ int size;
+ int offset;
+#ifdef _WIN32
+ HANDLE hFile;
+ HANDLE hMap;
+#endif
+} ImagingMapperObject;
+
+static PyTypeObject ImagingMapperType;
+
+ImagingMapperObject*
+PyImaging_MapperNew(const char* filename, int readonly)
+{
+ ImagingMapperObject *mapper;
+
+ if (PyType_Ready(&ImagingMapperType) < 0)
+ return NULL;
+
+ mapper = PyObject_New(ImagingMapperObject, &ImagingMapperType);
+ if (mapper == NULL)
+ return NULL;
+
+ mapper->base = NULL;
+ mapper->size = mapper->offset = 0;
+
+#ifdef _WIN32
+ mapper->hFile = (HANDLE)-1;
+ mapper->hMap = (HANDLE)-1;
+
+ /* FIXME: currently supports readonly mappings only */
+ mapper->hFile = CreateFile(
+ filename,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (mapper->hFile == (HANDLE)-1) {
+ PyErr_SetString(PyExc_IOError, "cannot open file");
+ Py_DECREF(mapper);
+ return NULL;
+ }
+
+ mapper->hMap = CreateFileMapping(
+ mapper->hFile, NULL,
+ PAGE_READONLY,
+ 0, 0, NULL);
+ if (mapper->hMap == (HANDLE)-1) {
+ CloseHandle(mapper->hFile);
+ PyErr_SetString(PyExc_IOError, "cannot map file");
+ Py_DECREF(mapper);
+ return NULL;
+ }
+
+ mapper->base = (char*) MapViewOfFile(
+ mapper->hMap,
+ FILE_MAP_READ,
+ 0, 0, 0);
+
+ mapper->size = GetFileSize(mapper->hFile, 0);
+#endif
+
+ return mapper;
+}
+
+static void
+mapping_dealloc(ImagingMapperObject* mapper)
+{
+#ifdef _WIN32
+ if (mapper->base != 0)
+ UnmapViewOfFile(mapper->base);
+ if (mapper->hMap != (HANDLE)-1)
+ CloseHandle(mapper->hMap);
+ if (mapper->hFile != (HANDLE)-1)
+ CloseHandle(mapper->hFile);
+ mapper->base = 0;
+ mapper->hMap = mapper->hFile = (HANDLE)-1;
+#endif
+ PyObject_Del(mapper);
+}
+
+/* -------------------------------------------------------------------- */
+/* standard file operations */
+
+static PyObject*
+mapping_read(ImagingMapperObject* mapper, PyObject* args)
+{
+ PyObject* buf;
+
+ int size = -1;
+ if (!PyArg_ParseTuple(args, "|i", &size))
+ return NULL;
+
+ /* check size */
+ if (size < 0 || mapper->offset + size > mapper->size)
+ size = mapper->size - mapper->offset;
+ if (size < 0)
+ size = 0;
+
+ buf = PyBytes_FromStringAndSize(NULL, size);
+ if (!buf)
+ return NULL;
+
+ if (size > 0) {
+ memcpy(PyBytes_AsString(buf), mapper->base + mapper->offset, size);
+ mapper->offset += size;
+ }
+
+ return buf;
+}
+
+static PyObject*
+mapping_seek(ImagingMapperObject* mapper, PyObject* args)
+{
+ int offset;
+ int whence = 0;
+ if (!PyArg_ParseTuple(args, "i|i", &offset, &whence))
+ return NULL;
+
+ switch (whence) {
+ case 0: /* SEEK_SET */
+ mapper->offset = offset;
+ break;
+ case 1: /* SEEK_CUR */
+ mapper->offset += offset;
+ break;
+ case 2: /* SEEK_END */
+ mapper->offset = mapper->size + offset;
+ break;
+ default:
+ /* FIXME: raise ValueError? */
+ break;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* -------------------------------------------------------------------- */
+/* map entire image */
+
+extern PyObject*PyImagingNew(Imaging im);
+
+static void
+ImagingDestroyMap(Imaging im)
+{
+ return; /* nothing to do! */
+}
+
+static PyObject*
+mapping_readimage(ImagingMapperObject* mapper, PyObject* args)
+{
+ int y, size;
+ Imaging im;
+
+ char* mode;
+ int xsize;
+ int ysize;
+ int stride;
+ int orientation;
+ if (!PyArg_ParseTuple(args, "s(ii)ii", &mode, &xsize, &ysize,
+ &stride, &orientation))
+ return NULL;
+
+ if (stride <= 0) {
+ /* FIXME: maybe we should call ImagingNewPrologue instead */
+ if (!strcmp(mode, "L") || !strcmp(mode, "P"))
+ stride = xsize;
+ else if (!strcmp(mode, "I;16") || !strcmp(mode, "I;16B"))
+ stride = xsize * 2;
+ else
+ stride = xsize * 4;
+ }
+
+ size = ysize * stride;
+
+ if (mapper->offset + size > mapper->size) {
+ PyErr_SetString(PyExc_IOError, "image file truncated");
+ return NULL;
+ }
+
+ im = ImagingNewPrologue(mode, xsize, ysize);
+ if (!im)
+ return NULL;
+
+ /* setup file pointers */
+ if (orientation > 0)
+ for (y = 0; y < ysize; y++)
+ im->image[y] = mapper->base + mapper->offset + y * stride;
+ else
+ for (y = 0; y < ysize; y++)
+ im->image[ysize-y-1] = mapper->base + mapper->offset + y * stride;
+
+ im->destroy = ImagingDestroyMap;
+
+ mapper->offset += size;
+
+ return PyImagingNew(im);
+}
+
+static struct PyMethodDef methods[] = {
+ /* standard file interface */
+ {"read", (PyCFunction)mapping_read, 1},
+ {"seek", (PyCFunction)mapping_seek, 1},
+ /* extensions */
+ {"readimage", (PyCFunction)mapping_readimage, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject ImagingMapperType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ImagingMapper", /*tp_name*/
+ sizeof(ImagingMapperObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)mapping_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+};
+
+PyObject*
+PyImaging_Mapper(PyObject* self, PyObject* args)
+{
+ char* filename;
+ if (!PyArg_ParseTuple(args, "s", &filename))
+ return NULL;
+
+ return (PyObject*) PyImaging_MapperNew(filename, 1);
+}
+
+/* -------------------------------------------------------------------- */
+/* Buffer mapper */
+
+typedef struct ImagingBufferInstance {
+ struct ImagingMemoryInstance im;
+ PyObject* target;
+ Py_buffer view;
+} ImagingBufferInstance;
+
+static void
+mapping_destroy_buffer(Imaging im)
+{
+ ImagingBufferInstance* buffer = (ImagingBufferInstance*) im;
+
+ PyBuffer_Release(&buffer->view);
+ Py_XDECREF(buffer->target);
+}
+
+PyObject*
+PyImaging_MapBuffer(PyObject* self, PyObject* args)
+{
+ Py_ssize_t y, size;
+ Imaging im;
+
+ PyObject* target;
+ Py_buffer view;
+ char* mode;
+ char* codec;
+ PyObject* bbox;
+ Py_ssize_t offset;
+ int xsize, ysize;
+ int stride;
+ int ystep;
+
+ if (!PyArg_ParseTuple(args, "O(ii)sOn(sii)", &target, &xsize, &ysize,
+ &codec, &bbox, &offset, &mode, &stride, &ystep))
+ return NULL;
+
+ if (!PyImaging_CheckBuffer(target)) {
+ PyErr_SetString(PyExc_TypeError, "expected string or buffer");
+ return NULL;
+ }
+
+ if (stride <= 0) {
+ if (!strcmp(mode, "L") || !strcmp(mode, "P"))
+ stride = xsize;
+ else if (!strncmp(mode, "I;16", 4))
+ stride = xsize * 2;
+ else
+ stride = xsize * 4;
+ }
+
+ if (stride > 0 && ysize > PY_SSIZE_T_MAX / stride) {
+ PyErr_SetString(PyExc_MemoryError, "Integer overflow in ysize");
+ return NULL;
+ }
+
+ size = (Py_ssize_t) ysize * stride;
+
+ if (offset > PY_SSIZE_T_MAX - size) {
+ PyErr_SetString(PyExc_MemoryError, "Integer overflow in offset");
+ return NULL;
+ }
+
+ /* check buffer size */
+ if (PyImaging_GetBuffer(target, &view) < 0)
+ return NULL;
+
+ if (view.len < 0) {
+ PyErr_SetString(PyExc_ValueError, "buffer has negative size");
+ return NULL;
+ }
+ if (offset + size > view.len) {
+ PyErr_SetString(PyExc_ValueError, "buffer is not large enough");
+ return NULL;
+ }
+
+ im = ImagingNewPrologueSubtype(
+ mode, xsize, ysize, sizeof(ImagingBufferInstance));
+ if (!im)
+ return NULL;
+
+ /* setup file pointers */
+ if (ystep > 0)
+ for (y = 0; y < ysize; y++)
+ im->image[y] = (char*)view.buf + offset + y * stride;
+ else
+ for (y = 0; y < ysize; y++)
+ im->image[ysize-y-1] = (char*)view.buf + offset + y * stride;
+
+ im->destroy = mapping_destroy_buffer;
+
+ Py_INCREF(target);
+ ((ImagingBufferInstance*) im)->target = target;
+ ((ImagingBufferInstance*) im)->view = view;
+
+ return PyImagingNew(im);
+}
+
diff --git a/contrib/python/Pillow/py2/outline.c b/contrib/python/Pillow/py2/outline.c
new file mode 100644
index 0000000000..25e63aeaf5
--- /dev/null
+++ b/contrib/python/Pillow/py2/outline.c
@@ -0,0 +1,192 @@
+/*
+ * THIS IS WORK IN PROGRESS.
+ *
+ * The Python Imaging Library.
+ *
+ * "arrow" outline stuff. the contents of this module
+ * will be merged with the path module and the rest of
+ * the arrow graphics package, but not before PIL 1.1.
+ * use at your own risk.
+ *
+ * history:
+ * 99-01-10 fl Added to PIL (experimental)
+ *
+ * Copyright (c) Secret Labs AB 1999.
+ * Copyright (c) Fredrik Lundh 1999.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Python.h"
+
+#include "Imaging.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Class */
+
+typedef struct {
+ PyObject_HEAD
+ ImagingOutline outline;
+} OutlineObject;
+
+static PyTypeObject OutlineType;
+
+#define PyOutline_Check(op) (Py_TYPE(op) == &OutlineType)
+
+static OutlineObject*
+_outline_new(void)
+{
+ OutlineObject *self;
+
+ if (PyType_Ready(&OutlineType) < 0)
+ return NULL;
+
+ self = PyObject_New(OutlineObject, &OutlineType);
+ if (self == NULL)
+ return NULL;
+
+ self->outline = ImagingOutlineNew();
+
+ return self;
+}
+
+static void
+_outline_dealloc(OutlineObject* self)
+{
+ ImagingOutlineDelete(self->outline);
+ PyObject_Del(self);
+}
+
+ImagingOutline
+PyOutline_AsOutline(PyObject* outline)
+{
+ if (PyOutline_Check(outline))
+ return ((OutlineObject*) outline)->outline;
+
+ return NULL;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Factories */
+
+PyObject*
+PyOutline_Create(PyObject* self, PyObject* args)
+{
+ if (!PyArg_ParseTuple(args, ":outline"))
+ return NULL;
+
+ return (PyObject*) _outline_new();
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Methods */
+
+static PyObject*
+_outline_move(OutlineObject* self, PyObject* args)
+{
+ float x0, y0;
+ if (!PyArg_ParseTuple(args, "ff", &x0, &y0))
+ return NULL;
+
+ ImagingOutlineMove(self->outline, x0, y0);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_outline_line(OutlineObject* self, PyObject* args)
+{
+ float x1, y1;
+ if (!PyArg_ParseTuple(args, "ff", &x1, &y1))
+ return NULL;
+
+ ImagingOutlineLine(self->outline, x1, y1);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_outline_curve(OutlineObject* self, PyObject* args)
+{
+ float x1, y1, x2, y2, x3, y3;
+ if (!PyArg_ParseTuple(args, "ffffff", &x1, &y1, &x2, &y2, &x3, &y3))
+ return NULL;
+
+ ImagingOutlineCurve(self->outline, x1, y1, x2, y2, x3, y3);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_outline_close(OutlineObject* self, PyObject* args)
+{
+ if (!PyArg_ParseTuple(args, ":close"))
+ return NULL;
+
+ ImagingOutlineClose(self->outline);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject*
+_outline_transform(OutlineObject* self, PyObject* args)
+{
+ double a[6];
+ if (!PyArg_ParseTuple(args, "(dddddd)", a+0, a+1, a+2, a+3, a+4, a+5))
+ return NULL;
+
+ ImagingOutlineTransform(self->outline, a);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct PyMethodDef _outline_methods[] = {
+ {"line", (PyCFunction)_outline_line, 1},
+ {"curve", (PyCFunction)_outline_curve, 1},
+ {"move", (PyCFunction)_outline_move, 1},
+ {"close", (PyCFunction)_outline_close, 1},
+ {"transform", (PyCFunction)_outline_transform, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject OutlineType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Outline", /*tp_name*/
+ sizeof(OutlineObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)_outline_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ _outline_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+};
diff --git a/contrib/python/Pillow/py2/path.c b/contrib/python/Pillow/py2/path.c
new file mode 100644
index 0000000000..5f0541b0be
--- /dev/null
+++ b/contrib/python/Pillow/py2/path.c
@@ -0,0 +1,632 @@
+/*
+ * The Python Imaging Library.
+ *
+ * 2D path utilities
+ *
+ * history:
+ * 1996-11-04 fl Added to PIL (incomplete)
+ * 1996-11-05 fl Added sequence semantics
+ * 1997-02-28 fl Fixed getbbox
+ * 1997-06-12 fl Added id attribute
+ * 1997-06-14 fl Added slicing and setitem
+ * 1998-12-29 fl Improved sequence handling (from Richard Jones)
+ * 1999-01-10 fl Fixed IndexError test for 1.5 (from Fred Drake)
+ * 2000-10-12 fl Added special cases for tuples and lists
+ * 2002-10-27 fl Added clipping boilerplate
+ * 2004-09-19 fl Added tolist(flat) variant
+ * 2005-05-06 fl Added buffer interface support to path constructor
+ *
+ * notes:
+ * FIXME: fill in remaining slots in the sequence api
+ *
+ * Copyright (c) 1997-2005 by Secret Labs AB
+ * Copyright (c) 1997-2005 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+
+#include "Python.h"
+#include "Imaging.h"
+
+#include <math.h>
+
+#include "py3.h"
+
+/* compatibility wrappers (defined in _imaging.c) */
+extern int PyImaging_CheckBuffer(PyObject* buffer);
+extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view);
+
+/* -------------------------------------------------------------------- */
+/* Class */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ PyObject_HEAD
+ Py_ssize_t count;
+ double *xy;
+ int index; /* temporary use, e.g. in decimate */
+} PyPathObject;
+
+static PyTypeObject PyPathType;
+
+static double*
+alloc_array(Py_ssize_t count)
+{
+ double* xy;
+ if (count < 0) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ if (count > (SIZE_MAX / (2 * sizeof(double))) - 1 ) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ xy = malloc(2 * count * sizeof(double) + 1);
+ if (!xy)
+ PyErr_NoMemory();
+ return xy;
+}
+
+static PyPathObject*
+path_new(Py_ssize_t count, double* xy, int duplicate)
+{
+ PyPathObject *path;
+
+ if (duplicate) {
+ /* duplicate path */
+ double* p = alloc_array(count);
+ if (!p)
+ return NULL;
+ memcpy(p, xy, count * 2 * sizeof(double));
+ xy = p;
+ }
+
+ if (PyType_Ready(&PyPathType) < 0) {
+ free(xy);
+ return NULL;
+ }
+
+ path = PyObject_New(PyPathObject, &PyPathType);
+ if (path == NULL) {
+ free(xy);
+ return NULL;
+ }
+
+ path->count = count;
+ path->xy = xy;
+
+ return path;
+}
+
+static void
+path_dealloc(PyPathObject* path)
+{
+ free(path->xy);
+ PyObject_Del(path);
+}
+
+/* -------------------------------------------------------------------- */
+/* Helpers */
+/* -------------------------------------------------------------------- */
+
+#define PyPath_Check(op) (Py_TYPE(op) == &PyPathType)
+
+Py_ssize_t
+PyPath_Flatten(PyObject* data, double **pxy)
+{
+ Py_ssize_t i, j, n;
+ double *xy;
+
+ if (PyPath_Check(data)) {
+ /* This was another path object. */
+ PyPathObject *path = (PyPathObject*) data;
+ xy = alloc_array(path->count);
+ if (!xy)
+ return -1;
+ memcpy(xy, path->xy, 2 * path->count * sizeof(double));
+ *pxy = xy;
+ return path->count;
+ }
+
+ if (PyImaging_CheckBuffer(data)) {
+ /* Assume the buffer contains floats */
+ Py_buffer buffer;
+ if (PyImaging_GetBuffer(data, &buffer) == 0) {
+ float *ptr = (float*) buffer.buf;
+ n = buffer.len / (2 * sizeof(float));
+ xy = alloc_array(n);
+ if (!xy)
+ return -1;
+ for (i = 0; i < n+n; i++)
+ xy[i] = ptr[i];
+ *pxy = xy;
+ PyBuffer_Release(&buffer);
+ return n;
+ }
+ PyErr_Clear();
+ }
+
+ if (!PySequence_Check(data)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be sequence");
+ return -1;
+ }
+
+ j = 0;
+ n = PyObject_Length(data);
+ /* Just in case __len__ breaks (or doesn't exist) */
+ if (PyErr_Occurred())
+ return -1;
+
+ /* Allocate for worst case */
+ xy = alloc_array(n);
+ if (!xy)
+ return -1;
+
+ /* Copy table to path array */
+ if (PyList_Check(data)) {
+ for (i = 0; i < n; i++) {
+ double x, y;
+ PyObject *op = PyList_GET_ITEM(data, i);
+ if (PyFloat_Check(op))
+ xy[j++] = PyFloat_AS_DOUBLE(op);
+ else if (PyInt_Check(op))
+ xy[j++] = (float) PyInt_AS_LONG(op);
+ else if (PyNumber_Check(op))
+ xy[j++] = PyFloat_AsDouble(op);
+ else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
+ xy[j++] = x;
+ xy[j++] = y;
+ } else {
+ free(xy);
+ return -1;
+ }
+ }
+ } else if (PyTuple_Check(data)) {
+ for (i = 0; i < n; i++) {
+ double x, y;
+ PyObject *op = PyTuple_GET_ITEM(data, i);
+ if (PyFloat_Check(op))
+ xy[j++] = PyFloat_AS_DOUBLE(op);
+ else if (PyInt_Check(op))
+ xy[j++] = (float) PyInt_AS_LONG(op);
+ else if (PyNumber_Check(op))
+ xy[j++] = PyFloat_AsDouble(op);
+ else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
+ xy[j++] = x;
+ xy[j++] = y;
+ } else {
+ free(xy);
+ return -1;
+ }
+ }
+ } else {
+ for (i = 0; i < n; i++) {
+ double x, y;
+ PyObject *op = PySequence_GetItem(data, i);
+ if (!op) {
+ /* treat IndexError as end of sequence */
+ if (PyErr_Occurred() &&
+ PyErr_ExceptionMatches(PyExc_IndexError)) {
+ PyErr_Clear();
+ break;
+ } else {
+ free(xy);
+ return -1;
+ }
+ }
+ if (PyFloat_Check(op))
+ xy[j++] = PyFloat_AS_DOUBLE(op);
+ else if (PyInt_Check(op))
+ xy[j++] = (float) PyInt_AS_LONG(op);
+ else if (PyNumber_Check(op))
+ xy[j++] = PyFloat_AsDouble(op);
+ else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
+ xy[j++] = x;
+ xy[j++] = y;
+ } else {
+ Py_DECREF(op);
+ free(xy);
+ return -1;
+ }
+ Py_DECREF(op);
+ }
+ }
+
+ if (j & 1) {
+ PyErr_SetString(PyExc_ValueError, "wrong number of coordinates");
+ free(xy);
+ return -1;
+ }
+
+ *pxy = xy;
+ return j/2;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Factories */
+/* -------------------------------------------------------------------- */
+
+PyObject*
+PyPath_Create(PyObject* self, PyObject* args)
+{
+ PyObject* data;
+ Py_ssize_t count;
+ double *xy;
+
+ if (PyArg_ParseTuple(args, "n:Path", &count)) {
+
+ /* number of vertices */
+ xy = alloc_array(count);
+ if (!xy)
+ return NULL;
+
+ } else {
+
+ /* sequence or other path */
+ PyErr_Clear();
+ if (!PyArg_ParseTuple(args, "O", &data))
+ return NULL;
+
+ count = PyPath_Flatten(data, &xy);
+ if (count < 0)
+ return NULL;
+ }
+
+ return (PyObject*) path_new(count, xy, 0);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Methods */
+/* -------------------------------------------------------------------- */
+
+static PyObject*
+path_compact(PyPathObject* self, PyObject* args)
+{
+ /* Simple-minded method to shorten path. A point is removed if
+ the city block distance to the previous point is less than the
+ given distance */
+ Py_ssize_t i, j;
+ double *xy;
+
+ double cityblock = 2.0;
+
+ if (!PyArg_ParseTuple(args, "|d:compact", &cityblock))
+ return NULL;
+
+ xy = self->xy;
+
+ /* remove bogus vertices */
+ for (i = j = 1; i < self->count; i++) {
+ if (fabs(xy[j+j-2]-xy[i+i]) + fabs(xy[j+j-1]-xy[i+i+1]) >= cityblock) {
+ xy[j+j] = xy[i+i];
+ xy[j+j+1] = xy[i+i+1];
+ j++;
+ }
+ }
+
+ i = self->count - j;
+ self->count = j;
+
+ /* shrink coordinate array */
+ /* malloc check ok, self->count is smaller than it was before */
+ self->xy = realloc(self->xy, 2 * self->count * sizeof(double));
+
+ return Py_BuildValue("i", i); /* number of removed vertices */
+}
+
+static PyObject*
+path_getbbox(PyPathObject* self, PyObject* args)
+{
+ /* Find bounding box */
+ Py_ssize_t i;
+ double *xy;
+ double x0, y0, x1, y1;
+
+ if (!PyArg_ParseTuple(args, ":getbbox"))
+ return NULL;
+
+ xy = self->xy;
+
+ x0 = x1 = xy[0];
+ y0 = y1 = xy[1];
+
+ for (i = 1; i < self->count; i++) {
+ if (xy[i+i] < x0)
+ x0 = xy[i+i];
+ if (xy[i+i] > x1)
+ x1 = xy[i+i];
+ if (xy[i+i+1] < y0)
+ y0 = xy[i+i+1];
+ if (xy[i+i+1] > y1)
+ y1 = xy[i+i+1];
+ }
+
+ return Py_BuildValue("dddd", x0, y0, x1, y1);
+}
+
+static PyObject*
+path_getitem(PyPathObject* self, Py_ssize_t i)
+{
+ if (i < 0)
+ i = self->count + i;
+ if (i < 0 || i >= self->count) {
+ PyErr_SetString(PyExc_IndexError, "path index out of range");
+ return NULL;
+ }
+
+ return Py_BuildValue("dd", self->xy[i+i], self->xy[i+i+1]);
+}
+
+static PyObject*
+path_getslice(PyPathObject* self, Py_ssize_t ilow, Py_ssize_t ihigh)
+{
+ /* adjust arguments */
+ if (ilow < 0)
+ ilow = 0;
+ else if (ilow >= self->count)
+ ilow = self->count;
+ if (ihigh < 0)
+ ihigh = 0;
+ if (ihigh < ilow)
+ ihigh = ilow;
+ else if (ihigh > self->count)
+ ihigh = self->count;
+
+ return (PyObject*) path_new(ihigh - ilow, self->xy + ilow * 2, 1);
+}
+
+static Py_ssize_t
+path_len(PyPathObject* self)
+{
+ return self->count;
+}
+
+static PyObject*
+path_map(PyPathObject* self, PyObject* args)
+{
+ /* Map coordinate set through function */
+ Py_ssize_t i;
+ double *xy;
+ PyObject* function;
+
+ if (!PyArg_ParseTuple(args, "O:map", &function))
+ return NULL;
+
+ xy = self->xy;
+
+ /* apply function to coordinate set */
+ for (i = 0; i < self->count; i++) {
+ double x = xy[i+i];
+ double y = xy[i+i+1];
+ PyObject* item = PyObject_CallFunction(function, "dd", x, y);
+ if (!item || !PyArg_ParseTuple(item, "dd", &x, &y)) {
+ Py_XDECREF(item);
+ return NULL;
+ }
+ xy[i+i] = x;
+ xy[i+i+1] = y;
+ Py_DECREF(item);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static int
+path_setitem(PyPathObject* self, Py_ssize_t i, PyObject* op)
+{
+ double* xy;
+
+ if (i < 0 || i >= self->count) {
+ PyErr_SetString(PyExc_IndexError,
+ "path assignment index out of range");
+ return -1;
+ }
+
+ if (op == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "cannot delete from path");
+ return -1;
+ }
+
+ xy = &self->xy[i+i];
+
+ if (!PyArg_ParseTuple(op, "dd", &xy[0], &xy[1]))
+ return -1;
+
+ return 0;
+}
+
+static PyObject*
+path_tolist(PyPathObject* self, PyObject* args)
+{
+ PyObject *list;
+ Py_ssize_t i;
+
+ int flat = 0;
+ if (!PyArg_ParseTuple(args, "|i:tolist", &flat))
+ return NULL;
+
+ if (flat) {
+ list = PyList_New(self->count*2);
+ for (i = 0; i < self->count*2; i++) {
+ PyObject* item;
+ item = PyFloat_FromDouble(self->xy[i]);
+ if (!item)
+ goto error;
+ PyList_SetItem(list, i, item);
+ }
+ } else {
+ list = PyList_New(self->count);
+ for (i = 0; i < self->count; i++) {
+ PyObject* item;
+ item = Py_BuildValue("dd", self->xy[i+i], self->xy[i+i+1]);
+ if (!item)
+ goto error;
+ PyList_SetItem(list, i, item);
+ }
+ }
+
+ return list;
+
+error:
+ Py_DECREF(list);
+ return NULL;
+}
+
+static PyObject*
+path_transform(PyPathObject* self, PyObject* args)
+{
+ /* Apply affine transform to coordinate set */
+ Py_ssize_t i;
+ double *xy;
+ double a, b, c, d, e, f;
+
+ double wrap = 0.0;
+
+ if (!PyArg_ParseTuple(args, "(dddddd)|d:transform",
+ &a, &b, &c, &d, &e, &f,
+ &wrap))
+ return NULL;
+
+ xy = self->xy;
+
+ /* transform the coordinate set */
+ if (b == 0.0 && d == 0.0)
+ /* scaling */
+ for (i = 0; i < self->count; i++) {
+ xy[i+i] = a*xy[i+i]+c;
+ xy[i+i+1] = e*xy[i+i+1]+f;
+ }
+ else
+ /* affine transform */
+ for (i = 0; i < self->count; i++) {
+ double x = xy[i+i];
+ double y = xy[i+i+1];
+ xy[i+i] = a*x+b*y+c;
+ xy[i+i+1] = d*x+e*y+f;
+ }
+
+ /* special treatment of geographical map data */
+ if (wrap != 0.0)
+ for (i = 0; i < self->count; i++)
+ xy[i+i] = fmod(xy[i+i], wrap);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static struct PyMethodDef methods[] = {
+ {"getbbox", (PyCFunction)path_getbbox, 1},
+ {"tolist", (PyCFunction)path_tolist, 1},
+ {"compact", (PyCFunction)path_compact, 1},
+ {"map", (PyCFunction)path_map, 1},
+ {"transform", (PyCFunction)path_transform, 1},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject*
+path_getattr_id(PyPathObject* self, void* closure)
+{
+ return Py_BuildValue("n", (Py_ssize_t) self->xy);
+}
+
+static struct PyGetSetDef getsetters[] = {
+ { "id", (getter) path_getattr_id },
+ { NULL }
+};
+
+static PyObject*
+path_subscript(PyPathObject* self, PyObject* item) {
+ if (PyIndex_Check(item)) {
+ Py_ssize_t i;
+ i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ return path_getitem(self, i);
+ }
+ if (PySlice_Check(item)) {
+ int len = 4;
+ Py_ssize_t start, stop, step, slicelength;
+
+#if PY_VERSION_HEX >= 0x03020000
+ if (PySlice_GetIndicesEx(item, len, &start, &stop, &step, &slicelength) < 0)
+ return NULL;
+#else
+ if (PySlice_GetIndicesEx((PySliceObject*)item, len, &start, &stop, &step, &slicelength) < 0)
+ return NULL;
+#endif
+
+ if (slicelength <= 0) {
+ double *xy = alloc_array(0);
+ return (PyObject*) path_new(0, xy, 0);
+ }
+ else if (step == 1) {
+ return path_getslice(self, start, stop);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "slice steps not supported");
+ return NULL;
+ }
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "Path indices must be integers, not %.200s",
+ Py_TYPE(item)->tp_name);
+ return NULL;
+ }
+}
+
+static PySequenceMethods path_as_sequence = {
+ (lenfunc)path_len, /*sq_length*/
+ (binaryfunc)0, /*sq_concat*/
+ (ssizeargfunc)0, /*sq_repeat*/
+ (ssizeargfunc)path_getitem, /*sq_item*/
+ (ssizessizeargfunc)path_getslice, /*sq_slice*/
+ (ssizeobjargproc)path_setitem, /*sq_ass_item*/
+ (ssizessizeobjargproc)0, /*sq_ass_slice*/
+};
+
+static PyMappingMethods path_as_mapping = {
+ (lenfunc)path_len,
+ (binaryfunc)path_subscript,
+ NULL
+};
+
+static PyTypeObject PyPathType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Path", /*tp_name*/
+ sizeof(PyPathObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)path_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number */
+ &path_as_sequence, /*tp_as_sequence */
+ &path_as_mapping, /*tp_as_mapping */
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ methods, /*tp_methods*/
+ 0, /*tp_members*/
+ getsetters, /*tp_getset*/
+};
+
diff --git a/contrib/python/Pillow/py2/py3.h b/contrib/python/Pillow/py2/py3.h
new file mode 100644
index 0000000000..310583845f
--- /dev/null
+++ b/contrib/python/Pillow/py2/py3.h
@@ -0,0 +1,56 @@
+/*
+ Python3 definition file to consistently map the code to Python 2 or
+ Python 3.
+
+ PyInt and PyLong were merged into PyLong in Python 3, so all PyInt functions
+ are mapped to PyLong.
+
+ PyString, on the other hand, was split into PyBytes and PyUnicode. We map
+ both back onto PyString, so use PyBytes or PyUnicode where appropriate. The
+ only exception to this is _imagingft.c, where PyUnicode is left alone.
+*/
+
+#if PY_VERSION_HEX >= 0x03000000
+#define PY_ARG_BYTES_LENGTH "y#"
+
+/* Map PyInt -> PyLong */
+#define PyInt_AsLong PyLong_AsLong
+#define PyInt_Check PyLong_Check
+#define PyInt_FromLong PyLong_FromLong
+#define PyInt_AS_LONG PyLong_AS_LONG
+#define PyInt_FromSsize_t PyLong_FromSsize_t
+#define PyInt_AsSsize_t PyLong_AsSsize_t
+
+#else /* PY_VERSION_HEX < 0x03000000 */
+#define PY_ARG_BYTES_LENGTH "s#"
+
+#if !defined(KEEP_PY_UNICODE)
+/* Map PyUnicode -> PyString */
+#undef PyUnicode_AsString
+#undef PyUnicode_AS_STRING
+#undef PyUnicode_Check
+#undef PyUnicode_FromStringAndSize
+#undef PyUnicode_FromString
+#undef PyUnicode_FromFormat
+#undef PyUnicode_DecodeFSDefault
+
+#define PyUnicode_AsString PyString_AsString
+#define PyUnicode_AS_STRING PyString_AS_STRING
+#define PyUnicode_Check PyString_Check
+#define PyUnicode_FromStringAndSize PyString_FromStringAndSize
+#define PyUnicode_FromString PyString_FromString
+#define PyUnicode_FromFormat PyString_FromFormat
+#define PyUnicode_DecodeFSDefault PyString_FromString
+#endif
+
+/* Map PyBytes -> PyString */
+#define PyBytesObject PyStringObject
+#define PyBytes_AsString PyString_AsString
+#define PyBytes_AS_STRING PyString_AS_STRING
+#define PyBytes_Check PyString_Check
+#define PyBytes_AsStringAndSize PyString_AsStringAndSize
+#define PyBytes_FromStringAndSize PyString_FromStringAndSize
+#define PyBytes_FromString PyString_FromString
+#define _PyBytes_Resize _PyString_Resize
+
+#endif /* PY_VERSION_HEX < 0x03000000 */
diff --git a/contrib/python/Pillow/py2/ya.make b/contrib/python/Pillow/py2/ya.make
new file mode 100644
index 0000000000..dd9ed9b073
--- /dev/null
+++ b/contrib/python/Pillow/py2/ya.make
@@ -0,0 +1,237 @@
+PY2_LIBRARY()
+
+LICENSE(PIL)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+VERSION(6.2.2)
+
+ORIGINAL_SOURCE(mirror://pypi/P/Pillow/Pillow-6.2.2.tar.gz)
+
+PEERDIR(
+ contrib/libs/freetype
+ contrib/libs/lcms2
+ contrib/libs/libjpeg-turbo
+ contrib/libs/libtiff
+ contrib/libs/libwebp
+ contrib/libs/libwebp/demux
+ contrib/libs/libwebp/mux
+ contrib/libs/openjpeg
+ contrib/libs/python
+ contrib/libs/zlib
+ contrib/python/cffi
+ contrib/python/olefile
+)
+
+ADDINCL(
+ contrib/libs/freetype/include
+ contrib/libs/lcms2/include
+ contrib/libs/libjpeg-turbo
+ contrib/libs/libwebp
+ contrib/libs/openjpeg/include
+ contrib/python/Pillow/py2/libImaging
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_LINT()
+
+CFLAGS(
+ -DHAVE_LIBJPEG
+ -DHAVE_LIBTIFF
+ -DHAVE_LIBZ
+ -DHAVE_OPENJPEG
+ -DHAVE_WEBPMUX
+ -DPILLOW_VERSION=\"6.2.2\"
+)
+
+SRCS(
+ _imaging.c
+ _imagingcms.c
+ _imagingft.c
+ _imagingmath.c
+ _imagingmorph.c
+ _webp.c
+ decode.c
+ display.c
+ encode.c
+ libImaging/Access.c
+ libImaging/AlphaComposite.c
+ libImaging/Bands.c
+ libImaging/BcnDecode.c
+ libImaging/BitDecode.c
+ libImaging/Blend.c
+ libImaging/BoxBlur.c
+ libImaging/Chops.c
+ libImaging/ColorLUT.c
+ libImaging/Convert.c
+ libImaging/ConvertYCbCr.c
+ libImaging/Copy.c
+ libImaging/Crop.c
+ libImaging/Dib.c
+ libImaging/Draw.c
+ libImaging/Effects.c
+ libImaging/EpsEncode.c
+ libImaging/File.c
+ libImaging/Fill.c
+ libImaging/Filter.c
+ libImaging/FliDecode.c
+ libImaging/Geometry.c
+ libImaging/GetBBox.c
+ libImaging/GifDecode.c
+ libImaging/GifEncode.c
+ libImaging/HexDecode.c
+ libImaging/Histo.c
+ libImaging/Jpeg2KDecode.c
+ libImaging/Jpeg2KEncode.c
+ libImaging/JpegDecode.c
+ libImaging/JpegEncode.c
+ libImaging/Matrix.c
+ libImaging/ModeFilter.c
+ libImaging/Negative.c
+ libImaging/Offset.c
+ libImaging/Pack.c
+ libImaging/PackDecode.c
+ libImaging/Palette.c
+ libImaging/Paste.c
+ libImaging/PcdDecode.c
+ libImaging/PcxDecode.c
+ libImaging/PcxEncode.c
+ libImaging/Point.c
+ libImaging/Quant.c
+ libImaging/QuantHash.c
+ libImaging/QuantHeap.c
+ libImaging/QuantOctree.c
+ libImaging/QuantPngQuant.c
+ libImaging/RankFilter.c
+ libImaging/RawDecode.c
+ libImaging/RawEncode.c
+ libImaging/Resample.c
+ libImaging/SgiRleDecode.c
+ libImaging/Storage.c
+ libImaging/SunRleDecode.c
+ libImaging/TgaRleDecode.c
+ libImaging/TgaRleEncode.c
+ libImaging/TiffDecode.c
+ libImaging/Unpack.c
+ libImaging/UnpackYCC.c
+ libImaging/UnsharpMask.c
+ libImaging/XbmDecode.c
+ libImaging/XbmEncode.c
+ libImaging/ZipDecode.c
+ libImaging/ZipEncode.c
+ libImaging/codec_fd.c
+ map.c
+ outline.c
+ path.c
+)
+
+PY_REGISTER(
+ PIL._imaging
+ PIL._imagingcms
+ PIL._imagingft
+ PIL._imagingmath
+ PIL._imagingmorph
+ PIL._webp
+)
+
+PY_SRCS(
+ TOP_LEVEL
+ PIL/__init__.py
+ PIL/__main__.py
+ PIL/_binary.py
+ PIL/_util.py
+ PIL/_version.py
+ PIL/BdfFontFile.py
+ PIL/BlpImagePlugin.py
+ PIL/BmpImagePlugin.py
+ PIL/BufrStubImagePlugin.py
+ PIL/ContainerIO.py
+ PIL/CurImagePlugin.py
+ PIL/DcxImagePlugin.py
+ PIL/DdsImagePlugin.py
+ PIL/EpsImagePlugin.py
+ PIL/ExifTags.py
+ PIL/features.py
+ PIL/FitsStubImagePlugin.py
+ PIL/FliImagePlugin.py
+ PIL/FontFile.py
+ PIL/FpxImagePlugin.py
+ PIL/FtexImagePlugin.py
+ PIL/GbrImagePlugin.py
+ PIL/GdImageFile.py
+ PIL/GifImagePlugin.py
+ PIL/GimpGradientFile.py
+ PIL/GimpPaletteFile.py
+ PIL/GribStubImagePlugin.py
+ PIL/Hdf5StubImagePlugin.py
+ PIL/IcnsImagePlugin.py
+ PIL/IcoImagePlugin.py
+ PIL/Image.py
+ PIL/ImageChops.py
+ PIL/ImageCms.py
+ PIL/ImageColor.py
+ PIL/ImageDraw.py
+ PIL/ImageDraw2.py
+ PIL/ImageEnhance.py
+ PIL/ImageFile.py
+ PIL/ImageFilter.py
+ PIL/ImageFont.py
+ PIL/ImageMath.py
+ PIL/ImageMode.py
+ PIL/ImageMorph.py
+ PIL/ImageOps.py
+ PIL/ImagePalette.py
+ PIL/ImagePath.py
+ PIL/ImageSequence.py
+ PIL/ImageShow.py
+ PIL/ImageStat.py
+ PIL/ImageTransform.py
+ PIL/ImageWin.py
+ PIL/ImImagePlugin.py
+ PIL/ImtImagePlugin.py
+ PIL/IptcImagePlugin.py
+ PIL/Jpeg2KImagePlugin.py
+ PIL/JpegImagePlugin.py
+ PIL/JpegPresets.py
+ PIL/McIdasImagePlugin.py
+ PIL/MicImagePlugin.py
+ PIL/MpegImagePlugin.py
+ PIL/MpoImagePlugin.py
+ PIL/MspImagePlugin.py
+ PIL/PaletteFile.py
+ PIL/PalmImagePlugin.py
+ PIL/PcdImagePlugin.py
+ PIL/PcfFontFile.py
+ PIL/PcxImagePlugin.py
+ PIL/PdfImagePlugin.py
+ PIL/PdfParser.py
+ PIL/PixarImagePlugin.py
+ PIL/PngImagePlugin.py
+ PIL/PpmImagePlugin.py
+ PIL/PsdImagePlugin.py
+ PIL/PSDraw.py
+ PIL/PyAccess.py
+ PIL/SgiImagePlugin.py
+ PIL/SpiderImagePlugin.py
+ PIL/SunImagePlugin.py
+ PIL/TarIO.py
+ PIL/TgaImagePlugin.py
+ PIL/TiffImagePlugin.py
+ PIL/TiffTags.py
+ PIL/WalImageFile.py
+ PIL/WebPImagePlugin.py
+ PIL/WmfImagePlugin.py
+ PIL/XbmImagePlugin.py
+ PIL/XpmImagePlugin.py
+ PIL/XVThumbImagePlugin.py
+)
+
+IF (OS_DARWIN OR OS_WINDOWS)
+ PY_SRCS(
+ TOP_LEVEL
+ PIL/ImageGrab.py
+ )
+ENDIF()
+
+END()