mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 18:26:17 +03:00
Merge branch 'master' into mime-types
This commit is contained in:
commit
0ad09f7386
28
.azure-pipelines/jobs/lint.yml
Normal file
28
.azure-pipelines/jobs/lint.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
parameters:
|
||||
name: '' # defaults for any parameters that aren't specified
|
||||
vmImage: ''
|
||||
|
||||
jobs:
|
||||
|
||||
- job: ${{ parameters.name }}
|
||||
pool:
|
||||
vmImage: ${{ parameters.vmImage }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
Python37:
|
||||
python.version: '3.7'
|
||||
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '$(python.version)'
|
||||
architecture: 'x64'
|
||||
|
||||
- script: |
|
||||
python -m pip install --upgrade tox
|
||||
displayName: 'Install dependencies'
|
||||
|
||||
- script: |
|
||||
tox -e lint
|
||||
displayName: 'Lint'
|
22
.azure-pipelines/jobs/test-docker.yml
Normal file
22
.azure-pipelines/jobs/test-docker.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
parameters:
|
||||
docker: '' # defaults for any parameters that aren't specified
|
||||
dockerTag: 'master'
|
||||
name: ''
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
|
||||
jobs:
|
||||
|
||||
- job: ${{ parameters.name }}
|
||||
pool:
|
||||
vmImage: ${{ parameters.vmImage }}
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
docker pull pythonpillow/${{ parameters.docker }}:${{ parameters.dockerTag }}
|
||||
displayName: 'Docker pull'
|
||||
|
||||
- script: |
|
||||
# The Pillow user in the docker container is UID 1000
|
||||
sudo chown -R 1000 $(Build.SourcesDirectory)
|
||||
docker run -v $(Build.SourcesDirectory):/Pillow pythonpillow/${{ parameters.docker }}:${{ parameters.dockerTag }}
|
||||
displayName: 'Docker build'
|
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
|
@ -34,6 +34,6 @@ The best reproductions are self-contained scripts with minimal dependencies. If
|
|||
|
||||
## Security vulnerabilities
|
||||
|
||||
To report sensitive vulnerability information, email security@python-pillow.org.
|
||||
To report sensitive vulnerability information, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
|
||||
|
||||
If your organisation/employer is a distributor of Pillow and would like advance notification of security-related bugs, please let us know your preferred contact method.
|
||||
|
|
33
CHANGES.rst
33
CHANGES.rst
|
@ -8,6 +8,39 @@ Changelog (Pillow)
|
|||
- Python 2.7 support will be removed in Pillow 7.0.0 #3682
|
||||
[hugovk]
|
||||
|
||||
- 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]
|
||||
|
||||
|
|
|
@ -23,9 +23,10 @@ exclude .codecov.yml
|
|||
exclude .editorconfig
|
||||
exclude .landscape.yaml
|
||||
exclude .readthedocs.yml
|
||||
exclude .travis
|
||||
exclude .travis/*
|
||||
exclude azure-pipelines.yml
|
||||
exclude tox.ini
|
||||
global-exclude .git*
|
||||
global-exclude *.pyc
|
||||
global-exclude *.so
|
||||
prune .azure-pipelines
|
||||
prune .travis
|
||||
|
|
BIN
Tests/images/exif.png
Normal file
BIN
Tests/images/exif.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 175 KiB |
BIN
Tests/images/old-style-jpeg-compression.png
Normal file
BIN
Tests/images/old-style-jpeg-compression.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
BIN
Tests/images/old-style-jpeg-compression.tif
Normal file
BIN
Tests/images/old-style-jpeg-compression.tif
Normal file
Binary file not shown.
BIN
Tests/images/rgb32bf-rgba.bmp
Normal file
BIN
Tests/images/rgb32bf-rgba.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
Tests/images/test_language.png
Normal file
BIN
Tests/images/test_language.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 777 B |
BIN
Tests/images/uncompressed_rgb.dds
Executable file
BIN
Tests/images/uncompressed_rgb.dds
Executable file
Binary file not shown.
BIN
Tests/images/uncompressed_rgb.png
Normal file
BIN
Tests/images/uncompressed_rgb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 143 KiB |
BIN
Tests/images/unimplemented_dxgi_format.dds
Normal file
BIN
Tests/images/unimplemented_dxgi_format.dds
Normal file
Binary file not shown.
BIN
Tests/images/unimplemented_pixel_format.dds
Executable file
BIN
Tests/images/unimplemented_pixel_format.dds
Executable file
Binary file not shown.
|
@ -16,6 +16,7 @@ class TestFileBmp(PillowTestCase):
|
|||
self.assertEqual(im.mode, reloaded.mode)
|
||||
self.assertEqual(im.size, reloaded.size)
|
||||
self.assertEqual(reloaded.format, "BMP")
|
||||
self.assertEqual(reloaded.get_format_mimetype(), "image/bmp")
|
||||
|
||||
def test_sanity(self):
|
||||
self.roundtrip(hopper())
|
||||
|
@ -72,6 +73,32 @@ class TestFileBmp(PillowTestCase):
|
|||
|
||||
def test_load_dib(self):
|
||||
# test for #1293, Imagegrab returning Unsupported Bitfields Format
|
||||
im = BmpImagePlugin.DibImageFile('Tests/images/clipboard.dib')
|
||||
im = Image.open('Tests/images/clipboard.dib')
|
||||
self.assertEqual(im.format, "DIB")
|
||||
self.assertEqual(im.get_format_mimetype(), "image/bmp")
|
||||
|
||||
target = Image.open('Tests/images/clipboard_target.png')
|
||||
self.assert_image_equal(im, target)
|
||||
|
||||
def test_save_dib(self):
|
||||
outfile = self.tempfile("temp.dib")
|
||||
|
||||
im = Image.open('Tests/images/clipboard.dib')
|
||||
im.save(outfile)
|
||||
|
||||
reloaded = Image.open(outfile)
|
||||
self.assertEqual(reloaded.format, "DIB")
|
||||
self.assertEqual(reloaded.get_format_mimetype(), "image/bmp")
|
||||
self.assert_image_equal(im, reloaded)
|
||||
|
||||
def test_rgba_bitfields(self):
|
||||
# This test image has been manually hexedited
|
||||
# to change the bitfield compression in the header from XBGR to RGBA
|
||||
im = Image.open("Tests/images/rgb32bf-rgba.bmp")
|
||||
|
||||
# So before the comparing the image, swap the channels
|
||||
b, g, r = im.split()[1:]
|
||||
im = Image.merge("RGB", (r, g, b))
|
||||
|
||||
target = Image.open("Tests/images/bmp/q/rgb32bf-xbgr.bmp")
|
||||
self.assert_image_equal(im, target)
|
||||
|
|
|
@ -7,6 +7,7 @@ TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds"
|
|||
TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds"
|
||||
TEST_FILE_DXT5 = "Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds"
|
||||
TEST_FILE_DX10_BC7 = "Tests/images/bc7-argb-8bpp_MipMaps-1.dds"
|
||||
TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/uncompressed_rgb.dds"
|
||||
|
||||
|
||||
class TestFileDds(PillowTestCase):
|
||||
|
@ -67,6 +68,24 @@ class TestFileDds(PillowTestCase):
|
|||
|
||||
self.assert_image_equal(target, im)
|
||||
|
||||
def test_unimplemented_dxgi_format(self):
|
||||
self.assertRaises(NotImplementedError, Image.open,
|
||||
"Tests/images/unimplemented_dxgi_format.dds")
|
||||
|
||||
def test_uncompressed_rgb(self):
|
||||
"""Check uncompressed RGB images can be opened"""
|
||||
|
||||
target = Image.open(TEST_FILE_UNCOMPRESSED_RGB.replace('.dds', '.png'))
|
||||
|
||||
im = Image.open(TEST_FILE_UNCOMPRESSED_RGB)
|
||||
im.load()
|
||||
|
||||
self.assertEqual(im.format, "DDS")
|
||||
self.assertEqual(im.mode, "RGBA")
|
||||
self.assertEqual(im.size, (800, 600))
|
||||
|
||||
self.assert_image_equal(target, im)
|
||||
|
||||
def test__validate_true(self):
|
||||
"""Check valid prefix"""
|
||||
# Arrange
|
||||
|
@ -110,3 +129,7 @@ class TestFileDds(PillowTestCase):
|
|||
im.load()
|
||||
|
||||
self.assertRaises(IOError, short_file)
|
||||
|
||||
def test_unimplemented_pixel_format(self):
|
||||
self.assertRaises(NotImplementedError, Image.open,
|
||||
"Tests/images/unimplemented_pixel_format.dds")
|
||||
|
|
|
@ -234,11 +234,11 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
|
||||
def test_custom_metadata(self):
|
||||
custom = {
|
||||
37000: 4,
|
||||
37001: 4.2,
|
||||
37002: 'custom tag value',
|
||||
37003: u'custom tag value',
|
||||
37004: b'custom tag value'
|
||||
37000: [4, TiffTags.SHORT],
|
||||
37001: [4.2, TiffTags.RATIONAL],
|
||||
37002: ['custom tag value', TiffTags.ASCII],
|
||||
37003: [u'custom tag value', TiffTags.ASCII],
|
||||
37004: [b'custom tag value', TiffTags.BYTE]
|
||||
}
|
||||
|
||||
libtiff_version = TiffImagePlugin._libtiff_version()
|
||||
|
@ -251,17 +251,33 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
for libtiff in libtiffs:
|
||||
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
||||
|
||||
im = hopper()
|
||||
def check_tags(tiffinfo):
|
||||
im = hopper()
|
||||
|
||||
out = self.tempfile("temp.tif")
|
||||
im.save(out, tiffinfo=custom)
|
||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||
out = self.tempfile("temp.tif")
|
||||
im.save(out, tiffinfo=tiffinfo)
|
||||
|
||||
reloaded = Image.open(out)
|
||||
for tag, value in custom.items():
|
||||
if libtiff and isinstance(value, bytes):
|
||||
value = value.decode()
|
||||
self.assertEqual(reloaded.tag_v2[tag], value)
|
||||
reloaded = Image.open(out)
|
||||
for tag, value in tiffinfo.items():
|
||||
reloaded_value = reloaded.tag_v2[tag]
|
||||
if isinstance(reloaded_value, TiffImagePlugin.IFDRational):
|
||||
reloaded_value = float(reloaded_value)
|
||||
|
||||
if libtiff and isinstance(value, bytes):
|
||||
value = value.decode()
|
||||
|
||||
self.assertEqual(reloaded_value, value)
|
||||
|
||||
# Test with types
|
||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||
for tag, tagdata in custom.items():
|
||||
ifd[tag] = tagdata[0]
|
||||
ifd.tagtype[tag] = tagdata[1]
|
||||
check_tags(ifd)
|
||||
|
||||
# Test without types
|
||||
check_tags({tag: tagdata[0] for tag, tagdata in custom.items()})
|
||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||
|
||||
def test_int_dpi(self):
|
||||
# issue #1765
|
||||
|
@ -700,3 +716,10 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
im = Image.open(infile)
|
||||
|
||||
self.assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5)
|
||||
|
||||
def test_old_style_jpeg(self):
|
||||
infile = "Tests/images/old-style-jpeg-compression.tif"
|
||||
im = Image.open(infile)
|
||||
|
||||
self.assert_image_equal_tofile(im,
|
||||
"Tests/images/old-style-jpeg-compression.png")
|
||||
|
|
|
@ -88,20 +88,13 @@ class TestFilePng(PillowTestCase):
|
|||
self.assertEqual(im.format, "PNG")
|
||||
self.assertEqual(im.get_format_mimetype(), 'image/png')
|
||||
|
||||
hopper("1").save(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
hopper("L").save(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
hopper("P").save(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
hopper("RGB").save(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
hopper("I").save(test_file)
|
||||
Image.open(test_file)
|
||||
for mode in ["1", "L", "P", "RGB", "I", "I;16"]:
|
||||
im = hopper(mode)
|
||||
im.save(test_file)
|
||||
reloaded = Image.open(test_file)
|
||||
if mode == "I;16":
|
||||
reloaded = reloaded.convert(mode)
|
||||
self.assert_image_equal(reloaded, im)
|
||||
|
||||
def test_invalid_file(self):
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
@ -590,6 +583,40 @@ class TestFilePng(PillowTestCase):
|
|||
im = Image.open("Tests/images/hopper_idat_after_image_end.png")
|
||||
self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
|
||||
|
||||
def test_exif(self):
|
||||
im = Image.open("Tests/images/exif.png")
|
||||
exif = im._getexif()
|
||||
self.assertEqual(exif[274], 1)
|
||||
|
||||
def test_exif_save(self):
|
||||
im = Image.open("Tests/images/exif.png")
|
||||
|
||||
test_file = self.tempfile("temp.png")
|
||||
im.save(test_file)
|
||||
|
||||
reloaded = Image.open(test_file)
|
||||
exif = reloaded._getexif()
|
||||
self.assertEqual(exif[274], 1)
|
||||
|
||||
def test_exif_from_jpg(self):
|
||||
im = Image.open("Tests/images/pil_sample_rgb.jpg")
|
||||
|
||||
test_file = self.tempfile("temp.png")
|
||||
im.save(test_file)
|
||||
|
||||
reloaded = Image.open(test_file)
|
||||
exif = reloaded._getexif()
|
||||
self.assertEqual(exif[305], "Adobe Photoshop CS Macintosh")
|
||||
|
||||
def test_exif_argument(self):
|
||||
im = Image.open(TEST_PNG_FILE)
|
||||
|
||||
test_file = self.tempfile("temp.png")
|
||||
im.save(test_file, exif=b"exifstring")
|
||||
|
||||
reloaded = Image.open(test_file)
|
||||
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
|
||||
|
||||
@unittest.skipUnless(HAVE_WEBP and _webp.HAVE_WEBPANIM,
|
||||
"WebP support not installed with animation")
|
||||
def test_apng(self):
|
||||
|
|
|
@ -28,3 +28,10 @@ class TestImageLoad(PillowTestCase):
|
|||
os.fstat(fn)
|
||||
|
||||
self.assertRaises(OSError, os.fstat, fn)
|
||||
|
||||
def test_contextmanager_non_exclusive_fp(self):
|
||||
with open("Tests/images/hopper.gif", "rb") as fp:
|
||||
with Image.open(fp):
|
||||
pass
|
||||
|
||||
self.assertFalse(fp.closed)
|
||||
|
|
|
@ -46,3 +46,19 @@ class TestImageQuantize(PillowTestCase):
|
|||
converted = image.quantize()
|
||||
self.assert_image(converted, 'P', converted.size)
|
||||
self.assert_image_similar(converted.convert('RGB'), image, 1)
|
||||
|
||||
def test_quantize_no_dither(self):
|
||||
image = hopper()
|
||||
palette = Image.open('Tests/images/caption_6_33_22.png').convert('P')
|
||||
|
||||
converted = image.quantize(dither=0, palette=palette)
|
||||
self.assert_image(converted, 'P', converted.size)
|
||||
|
||||
def test_quantize_dither_diff(self):
|
||||
image = hopper()
|
||||
palette = Image.open('Tests/images/caption_6_33_22.png').convert('P')
|
||||
|
||||
dither = image.quantize(dither=1, palette=palette)
|
||||
nodither = image.quantize(dither=0, palette=palette)
|
||||
|
||||
self.assertNotEqual(dither.tobytes(), nodither.tobytes())
|
||||
|
|
|
@ -525,6 +525,15 @@ class TestImageFont(PillowTestCase):
|
|||
self.assertEqual(t.getsize_multiline('ABC\nA'), (36, 36))
|
||||
self.assertEqual(t.getsize_multiline('ABC\nAaaa'), (48, 36))
|
||||
|
||||
def test_complex_font_settings(self):
|
||||
# Arrange
|
||||
t = self.get_font()
|
||||
# Act / Assert
|
||||
if t.layout_engine == ImageFont.LAYOUT_BASIC:
|
||||
self.assertRaises(KeyError, t.getmask, 'абвг', direction='rtl')
|
||||
self.assertRaises(KeyError, t.getmask, 'абвг', features=['-kern'])
|
||||
self.assertRaises(KeyError, t.getmask, 'абвг', language='sr')
|
||||
|
||||
|
||||
@unittest.skipUnless(HAS_RAQM, "Raqm not Available")
|
||||
class TestImageFont_RaqmLayout(TestImageFont):
|
||||
|
|
|
@ -130,3 +130,16 @@ class TestImagecomplextext(PillowTestCase):
|
|||
target_img = Image.open(target)
|
||||
|
||||
self.assert_image_similar(im, target_img, .5)
|
||||
|
||||
def test_language(self):
|
||||
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||
|
||||
im = Image.new(mode='RGB', size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.text((0, 0), 'абвг', font=ttf, fill=500,
|
||||
language='sr')
|
||||
|
||||
target = 'Tests/images/test_language.png'
|
||||
target_img = Image.open(target)
|
||||
|
||||
self.assert_image_similar(im, target_img, .5)
|
||||
|
|
67
azure-pipelines.yml
Normal file
67
azure-pipelines.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Python package
|
||||
# Create and test a Python package on multiple Python versions.
|
||||
# Add steps that analyze code, save the dist with the build record,
|
||||
# publish to a PyPI-compatible index, and more:
|
||||
# https://docs.microsoft.com/azure/devops/pipelines/languages/python
|
||||
|
||||
jobs:
|
||||
|
||||
- template: .azure-pipelines/jobs/lint.yml
|
||||
parameters:
|
||||
name: Lint
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'alpine'
|
||||
name: 'alpine'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'arch'
|
||||
name: 'arch'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'ubuntu-trusty-x86'
|
||||
name: 'ubuntu_trusty_x86'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'ubuntu-xenial-amd64'
|
||||
name: 'ubuntu_xenial_amd64'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'debian-stretch-x86'
|
||||
name: 'debian_stretch_x86'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'centos-6-amd64'
|
||||
name: 'centos_6_amd64'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'centos-7-amd64'
|
||||
name: 'centos_7_amd64'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'amazon-1-amd64'
|
||||
name: 'amazon_1_amd64'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'amazon-2-amd64'
|
||||
name: 'amazon_2_amd64'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'fedora-28-amd64'
|
||||
name: 'fedora_28_amd64'
|
||||
|
||||
- template: .azure-pipelines/jobs/test-docker.yml
|
||||
parameters:
|
||||
docker: 'fedora-29-amd64'
|
||||
name: 'fedora_29_amd64'
|
|
@ -21,7 +21,7 @@ Fully supported formats
|
|||
BMP
|
||||
^^^
|
||||
|
||||
PIL reads and writes Windows and OS/2 BMP files containing ``1``, ``L``, ``P``,
|
||||
Pillow reads and writes Windows and OS/2 BMP files containing ``1``, ``L``, ``P``,
|
||||
or ``RGB`` data. 16-colour images are read as ``P`` images. Run-length encoding
|
||||
is not supported.
|
||||
|
||||
|
@ -31,13 +31,21 @@ The :py:meth:`~PIL.Image.Image.open` method sets the following
|
|||
**compression**
|
||||
Set to ``bmp_rle`` if the file is run-length encoded.
|
||||
|
||||
DIB
|
||||
^^^
|
||||
|
||||
Pillow reads and writes DIB files. DIB files are similar to BMP files, so see
|
||||
above for more information.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
EPS
|
||||
^^^
|
||||
|
||||
PIL identifies EPS files containing image data, and can read files that contain
|
||||
embedded raster images (ImageData descriptors). If Ghostscript is available,
|
||||
other EPS files can be read as well. The EPS driver can also write EPS
|
||||
images. The EPS driver can read EPS images in ``L``, ``LAB``, ``RGB`` and
|
||||
Pillow identifies EPS files containing image data, and can read files that
|
||||
contain embedded raster images (ImageData descriptors). If Ghostscript is
|
||||
available, other EPS files can be read as well. The EPS driver can also write
|
||||
EPS images. The EPS driver can read EPS images in ``L``, ``LAB``, ``RGB`` and
|
||||
``CMYK`` mode, but Ghostscript may convert the images to ``RGB`` mode rather
|
||||
than leaving them in the original color space. The EPS driver can write images
|
||||
in ``L``, ``RGB`` and ``CMYK`` modes.
|
||||
|
@ -59,8 +67,8 @@ method with the following parameter to affect how Ghostscript renders the EPS
|
|||
GIF
|
||||
^^^
|
||||
|
||||
PIL reads GIF87a and GIF89a versions of the GIF file format. The library writes
|
||||
run-length encoded files in GIF87a by default, unless GIF89a features
|
||||
Pillow reads GIF87a and GIF89a versions of the GIF file format. The library
|
||||
writes run-length encoded files in GIF87a by default, unless GIF89a features
|
||||
are used or GIF89a is already in use.
|
||||
|
||||
Note that GIF files are always read as grayscale (``L``)
|
||||
|
@ -192,7 +200,7 @@ attributes before loading the file::
|
|||
ICNS
|
||||
^^^^
|
||||
|
||||
PIL reads and (macOS only) writes macOS ``.icns`` files. By default, the
|
||||
Pillow reads and (macOS only) writes macOS ``.icns`` files. By default, the
|
||||
largest available icon is read, though you can override this by setting the
|
||||
:py:attr:`~PIL.Image.Image.size` property before calling
|
||||
:py:meth:`~PIL.Image.Image.load`. The :py:meth:`~PIL.Image.Image.open` method
|
||||
|
@ -237,12 +245,12 @@ IM is a format used by LabEye and other applications based on the IFUNC image
|
|||
processing library. The library reads and writes most uncompressed interchange
|
||||
versions of this format.
|
||||
|
||||
IM is the only format that can store all internal PIL formats.
|
||||
IM is the only format that can store all internal Pillow formats.
|
||||
|
||||
JPEG
|
||||
^^^^
|
||||
|
||||
PIL reads JPEG, JFIF, and Adobe JPEG files containing ``L``, ``RGB``, or
|
||||
Pillow reads JPEG, JFIF, and Adobe JPEG files containing ``L``, ``RGB``, or
|
||||
``CMYK`` data. It writes standard and progressive JFIF files.
|
||||
|
||||
Using the :py:meth:`~PIL.Image.Image.draft` method, you can speed things up by
|
||||
|
@ -354,15 +362,15 @@ JPEG 2000
|
|||
|
||||
.. versionadded:: 2.4.0
|
||||
|
||||
PIL reads and writes JPEG 2000 files containing ``L``, ``LA``, ``RGB`` or
|
||||
Pillow reads and writes JPEG 2000 files containing ``L``, ``LA``, ``RGB`` or
|
||||
``RGBA`` data. It can also read files containing ``YCbCr`` data, which it
|
||||
converts on read into ``RGB`` or ``RGBA`` depending on whether or not there is
|
||||
an alpha channel. PIL supports JPEG 2000 raw codestreams (``.j2k`` files), as
|
||||
well as boxed JPEG 2000 files (``.j2p`` or ``.jpx`` files). PIL does *not*
|
||||
support files whose components have different sampling frequencies.
|
||||
an alpha channel. Pillow supports JPEG 2000 raw codestreams (``.j2k`` files),
|
||||
as well as boxed JPEG 2000 files (``.j2p`` or ``.jpx`` files). Pillow does
|
||||
*not* support files whose components have different sampling frequencies.
|
||||
|
||||
When loading, if you set the ``mode`` on the image prior to the
|
||||
:py:meth:`~PIL.Image.Image.load` method being invoked, you can ask PIL to
|
||||
:py:meth:`~PIL.Image.Image.load` method being invoked, you can ask Pillow to
|
||||
convert the image to either ``RGB`` or ``RGBA`` rather than choosing for
|
||||
itself. It is also possible to set ``reduce`` to the number of resolutions to
|
||||
discard (each one reduces the size of the resulting image by a factor of 2),
|
||||
|
@ -433,26 +441,31 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
|||
Library.
|
||||
|
||||
Windows users can install the OpenJPEG binaries available on the
|
||||
OpenJPEG website, but must add them to their PATH in order to use PIL (if
|
||||
OpenJPEG website, but must add them to their PATH in order to use Pillow (if
|
||||
you fail to do this, you will get errors about not being able to load the
|
||||
``_imaging`` DLL).
|
||||
|
||||
MSP
|
||||
^^^
|
||||
|
||||
PIL identifies and reads MSP files from Windows 1 and 2. The library writes
|
||||
Pillow identifies and reads MSP files from Windows 1 and 2. The library writes
|
||||
uncompressed (Windows 1) versions of this format.
|
||||
|
||||
PCX
|
||||
^^^
|
||||
|
||||
PIL reads and writes PCX files containing ``1``, ``L``, ``P``, or ``RGB`` data.
|
||||
Pillow reads and writes PCX files containing ``1``, ``L``, ``P``, or ``RGB`` data.
|
||||
|
||||
PNG
|
||||
^^^
|
||||
|
||||
PIL identifies, reads, and writes PNG files containing ``1``, ``L``, ``P``,
|
||||
``RGB``, or ``RGBA`` data. Interlaced files are supported as of v1.1.7.
|
||||
Pillow identifies, reads, and writes PNG files containing ``1``, ``L``, ``LA``,
|
||||
``I``, ``P``, ``RGB`` or ``RGBA`` data. Interlaced files are supported as of
|
||||
v1.1.7.
|
||||
|
||||
As of Pillow 6.0, EXIF data can be read from PNG images. However, unlike other
|
||||
image formats, EXIF data is not guaranteed to have been read until
|
||||
:py:meth:`~PIL.Image.Image.load` has been called.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties, when appropriate:
|
||||
|
@ -519,6 +532,11 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
|||
**icc_profile**
|
||||
The ICC Profile to include in the saved file.
|
||||
|
||||
**exif**
|
||||
The exif data to include in the saved file.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
**bits (experimental)**
|
||||
For ``P`` images, this option controls how many bits to store. If omitted,
|
||||
the PNG writer uses 8 bits (256 colors).
|
||||
|
@ -535,7 +553,7 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
|||
PPM
|
||||
^^^
|
||||
|
||||
PIL reads and writes PBM, PGM, PPM and PNM files containing ``1``, ``L`` or
|
||||
Pillow reads and writes PBM, PGM, PPM and PNM files containing ``1``, ``L`` or
|
||||
``RGB`` data.
|
||||
|
||||
SGI
|
||||
|
@ -547,10 +565,10 @@ Pillow reads and writes uncompressed ``L``, ``RGB``, and ``RGBA`` files.
|
|||
SPIDER
|
||||
^^^^^^
|
||||
|
||||
PIL reads and writes SPIDER image files of 32-bit floating point data
|
||||
Pillow reads and writes SPIDER image files of 32-bit floating point data
|
||||
("F;32F").
|
||||
|
||||
PIL also reads SPIDER stack files containing sequences of SPIDER images. The
|
||||
Pillow also reads SPIDER stack files containing sequences of SPIDER images. The
|
||||
:py:meth:`~file.seek` and :py:meth:`~file.tell` methods are supported, and
|
||||
random access is allowed.
|
||||
|
||||
|
@ -587,8 +605,8 @@ For more information about the SPIDER image processing package, see the
|
|||
TGA
|
||||
^^^
|
||||
|
||||
PIL reads and writes TGA images containing ``L``, ``LA``, ``P``,
|
||||
``RGB``, and ``RGBA`` data. PIL can read and write both uncompressed and
|
||||
Pillow reads and writes TGA images containing ``L``, ``LA``, ``P``,
|
||||
``RGB``, and ``RGBA`` data. Pillow can read and write both uncompressed and
|
||||
run-length encoded TGAs.
|
||||
|
||||
TIFF
|
||||
|
@ -596,8 +614,8 @@ TIFF
|
|||
|
||||
Pillow reads and writes TIFF files. It can read both striped and tiled
|
||||
images, pixel and plane interleaved multi-band images. If you have
|
||||
libtiff and its headers installed, PIL can read and write many kinds
|
||||
of compressed TIFF files. If not, PIL will only read and write
|
||||
libtiff and its headers installed, Pillow can read and write many kinds
|
||||
of compressed TIFF files. If not, Pillow will only read and write
|
||||
uncompressed files.
|
||||
|
||||
.. note::
|
||||
|
@ -734,8 +752,8 @@ using the general tags available through tiffinfo.
|
|||
WebP
|
||||
^^^^
|
||||
|
||||
PIL reads and writes WebP files. The specifics of PIL's capabilities with this
|
||||
format are currently undocumented.
|
||||
Pillow reads and writes WebP files. The specifics of Pillow's capabilities with
|
||||
this format are currently undocumented.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
||||
|
||||
|
@ -807,7 +825,7 @@ are available when the `save_all` argument is present and true.
|
|||
XBM
|
||||
^^^
|
||||
|
||||
PIL reads and writes X bitmap files (mode ``1``).
|
||||
Pillow reads and writes X bitmap files (mode ``1``).
|
||||
|
||||
Read-only formats
|
||||
-----------------
|
||||
|
@ -841,15 +859,15 @@ DDS
|
|||
|
||||
DDS is a popular container texture format used in video games and natively
|
||||
supported by DirectX.
|
||||
Currently, DXT1, DXT3, and DXT5 pixel formats are supported and only in ``RGBA``
|
||||
mode.
|
||||
Currently, uncompressed RGB data and DXT1, DXT3, and DXT5 pixel formats are
|
||||
supported, and only in ``RGBA`` mode.
|
||||
|
||||
.. versionadded:: 3.4.0 DXT3
|
||||
|
||||
FLI, FLC
|
||||
^^^^^^^^
|
||||
|
||||
PIL reads Autodesk FLI and FLC animations.
|
||||
Pillow reads Autodesk FLI and FLC animations.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
@ -860,7 +878,7 @@ The :py:meth:`~PIL.Image.Image.open` method sets the following
|
|||
FPX
|
||||
^^^
|
||||
|
||||
PIL reads Kodak FlashPix files. In the current version, only the highest
|
||||
Pillow reads Kodak FlashPix files. In the current version, only the highest
|
||||
resolution image is read from the file, and the viewing transform is not taken
|
||||
into account.
|
||||
|
||||
|
@ -896,7 +914,7 @@ The :py:meth:`~PIL.Image.Image.open` method sets the following
|
|||
GD
|
||||
^^
|
||||
|
||||
PIL reads uncompressed GD2 files. Note that you must use
|
||||
Pillow reads uncompressed GD2 files. Note that you must use
|
||||
:py:func:`PIL.GdImageFile.open` to read such a file.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
|
@ -909,23 +927,23 @@ The :py:meth:`~PIL.Image.Image.open` method sets the following
|
|||
IMT
|
||||
^^^
|
||||
|
||||
PIL reads Image Tools images containing ``L`` data.
|
||||
Pillow reads Image Tools images containing ``L`` data.
|
||||
|
||||
IPTC/NAA
|
||||
^^^^^^^^
|
||||
|
||||
PIL provides limited read support for IPTC/NAA newsphoto files.
|
||||
Pillow provides limited read support for IPTC/NAA newsphoto files.
|
||||
|
||||
MCIDAS
|
||||
^^^^^^
|
||||
|
||||
PIL identifies and reads 8-bit McIdas area files.
|
||||
Pillow identifies and reads 8-bit McIdas area files.
|
||||
|
||||
MIC
|
||||
^^^
|
||||
|
||||
PIL identifies and reads Microsoft Image Composer (MIC) files. When opened, the
|
||||
first sprite in the file is loaded. You can use :py:meth:`~file.seek` and
|
||||
Pillow identifies and reads Microsoft Image Composer (MIC) files. When opened,
|
||||
the first sprite in the file is loaded. You can use :py:meth:`~file.seek` and
|
||||
:py:meth:`~file.tell` to read other sprites from the file.
|
||||
|
||||
Note that there may be an embedded gamma of 2.2 in MIC files.
|
||||
|
@ -941,22 +959,22 @@ zero-indexed and random access is supported.
|
|||
PCD
|
||||
^^^
|
||||
|
||||
PIL reads PhotoCD files containing ``RGB`` data. This only reads the 768x512
|
||||
Pillow reads PhotoCD files containing ``RGB`` data. This only reads the 768x512
|
||||
resolution image from the file. Higher resolutions are encoded in a proprietary
|
||||
encoding.
|
||||
|
||||
PIXAR
|
||||
^^^^^
|
||||
|
||||
PIL provides limited support for PIXAR raster files. The library can identify
|
||||
and read “dumped” RGB files.
|
||||
Pillow provides limited support for PIXAR raster files. The library can
|
||||
identify and read “dumped” RGB files.
|
||||
|
||||
The format code is ``PIXAR``.
|
||||
|
||||
PSD
|
||||
^^^
|
||||
|
||||
PIL identifies and reads PSD files written by Adobe Photoshop 2.5 and 3.0.
|
||||
Pillow identifies and reads PSD files written by Adobe Photoshop 2.5 and 3.0.
|
||||
|
||||
|
||||
WAL
|
||||
|
@ -964,7 +982,7 @@ WAL
|
|||
|
||||
.. versionadded:: 1.1.4
|
||||
|
||||
PIL reads Quake2 WAL texture files.
|
||||
Pillow reads Quake2 WAL texture files.
|
||||
|
||||
Note that this file format cannot be automatically identified, so you must use
|
||||
the open function in the :py:mod:`~PIL.WalImageFile` module to read files in
|
||||
|
@ -976,7 +994,7 @@ the palette, use the putpalette method.
|
|||
XPM
|
||||
^^^
|
||||
|
||||
PIL reads X pixmap files (mode ``P``) with 256 colors or less.
|
||||
Pillow reads X pixmap files (mode ``P``) with 256 colors or less.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
@ -991,14 +1009,14 @@ Write-only formats
|
|||
PALM
|
||||
^^^^
|
||||
|
||||
PIL provides write-only support for PALM pixmap files.
|
||||
Pillow provides write-only support for PALM pixmap files.
|
||||
|
||||
The format code is ``Palm``, the extension is ``.palm``.
|
||||
|
||||
PDF
|
||||
^^^
|
||||
|
||||
PIL can write PDF (Acrobat) images. Such images are written as binary PDF 1.4
|
||||
Pillow can write PDF (Acrobat) images. Such images are written as binary PDF 1.4
|
||||
files, using either JPEG or HEX encoding depending on the image mode (and
|
||||
whether JPEG support is available or not).
|
||||
|
||||
|
@ -1077,7 +1095,7 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum
|
|||
XV Thumbnails
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
PIL can read XV thumbnail files.
|
||||
Pillow can read XV thumbnail files.
|
||||
|
||||
Identify-only formats
|
||||
---------------------
|
||||
|
@ -1087,7 +1105,7 @@ BUFR
|
|||
|
||||
.. versionadded:: 1.1.3
|
||||
|
||||
PIL provides a stub driver for BUFR files.
|
||||
Pillow provides a stub driver for BUFR files.
|
||||
|
||||
To add read or write support to your application, use
|
||||
:py:func:`PIL.BufrStubImagePlugin.register_handler`.
|
||||
|
@ -1097,7 +1115,7 @@ FITS
|
|||
|
||||
.. versionadded:: 1.1.5
|
||||
|
||||
PIL provides a stub driver for FITS files.
|
||||
Pillow provides a stub driver for FITS files.
|
||||
|
||||
To add read or write support to your application, use
|
||||
:py:func:`PIL.FitsStubImagePlugin.register_handler`.
|
||||
|
@ -1107,11 +1125,11 @@ GRIB
|
|||
|
||||
.. versionadded:: 1.1.5
|
||||
|
||||
PIL provides a stub driver for GRIB files.
|
||||
Pillow provides a stub driver for GRIB files.
|
||||
|
||||
The driver requires the file to start with a GRIB header. If you have files
|
||||
with embedded GRIB data, or files with multiple GRIB fields, your application
|
||||
has to seek to the header before passing the file handle to PIL.
|
||||
has to seek to the header before passing the file handle to Pillow.
|
||||
|
||||
To add read or write support to your application, use
|
||||
:py:func:`PIL.GribStubImagePlugin.register_handler`.
|
||||
|
@ -1121,7 +1139,7 @@ HDF5
|
|||
|
||||
.. versionadded:: 1.1.5
|
||||
|
||||
PIL provides a stub driver for HDF5 files.
|
||||
Pillow provides a stub driver for HDF5 files.
|
||||
|
||||
To add read or write support to your application, use
|
||||
:py:func:`PIL.Hdf5StubImagePlugin.register_handler`.
|
||||
|
@ -1129,12 +1147,12 @@ To add read or write support to your application, use
|
|||
MPEG
|
||||
^^^^
|
||||
|
||||
PIL identifies MPEG files.
|
||||
Pillow identifies MPEG files.
|
||||
|
||||
WMF
|
||||
^^^
|
||||
|
||||
PIL can identify playable WMF files.
|
||||
Pillow can identify playable WMF files.
|
||||
|
||||
In PIL 1.1.4 and earlier, the WMF driver provides some limited rendering
|
||||
support, but not enough to be useful for any real application.
|
||||
|
|
|
@ -255,7 +255,7 @@ Methods
|
|||
|
||||
Draw a shape.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None)
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None, language=None)
|
||||
|
||||
Draws the string at the given position.
|
||||
|
||||
|
@ -287,7 +287,17 @@ Methods
|
|||
|
||||
.. versionadded:: 4.2.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None)
|
||||
: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 `BCP47 language code
|
||||
<https://www.w3.org/International/articles/language-tags/>`
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None, language=None)
|
||||
|
||||
Draws the string at the given position.
|
||||
|
||||
|
@ -316,7 +326,17 @@ Methods
|
|||
|
||||
.. versionadded:: 4.2.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None)
|
||||
: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 `BCP47 language code
|
||||
<https://www.w3.org/International/articles/language-tags/>`
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None)
|
||||
|
||||
Return the size of the given string, in pixels.
|
||||
|
||||
|
@ -330,7 +350,6 @@ Methods
|
|||
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,
|
||||
|
@ -343,8 +362,17 @@ Methods
|
|||
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 `BCP47 language code
|
||||
<https://www.w3.org/International/articles/language-tags/>`
|
||||
Requires libraqm.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None)
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None)
|
||||
|
||||
Return the size of the given string, in pixels.
|
||||
|
||||
|
@ -370,6 +398,16 @@ Methods
|
|||
|
||||
.. 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 `BCP47 language code
|
||||
<https://www.w3.org/International/articles/language-tags/>`
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.getdraw(im=None, hints=None)
|
||||
|
||||
.. warning:: This method is experimental.
|
||||
|
|
|
@ -47,11 +47,45 @@ Functions
|
|||
Methods
|
||||
-------
|
||||
|
||||
.. py:method:: PIL.ImageFont.ImageFont.getsize(text)
|
||||
.. py:method:: PIL.ImageFont.ImageFont.getsize(text, direction=None, features=[], language=None)
|
||||
|
||||
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 `BCP47 language code
|
||||
<https://www.w3.org/International/articles/language-tags/>`
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
:return: (width, height)
|
||||
|
||||
.. py:method:: PIL.ImageFont.ImageFont.getmask(text, mode='', direction=None, features=[])
|
||||
.. py:method:: PIL.ImageFont.ImageFont.getmask(text, mode='', direction=None, features=[], language=None)
|
||||
|
||||
Create a bitmap for the text.
|
||||
|
||||
|
@ -85,5 +119,15 @@ Methods
|
|||
|
||||
.. 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 `BCP47 language code
|
||||
<https://www.w3.org/International/articles/language-tags/>`
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
:return: An internal PIL storage memory instance as defined by the
|
||||
:py:mod:`PIL.Image.core` interface module.
|
||||
|
|
|
@ -102,15 +102,48 @@ Use ``PIL.__version__`` instead.
|
|||
API Additions
|
||||
=============
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
DIB file format
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
TODO
|
||||
Pillow now supports reading and writing the Device Independent Bitmap file format.
|
||||
|
||||
Image.quantize
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The ``dither`` option is now a customisable parameter (was previously hardcoded to ``1``).
|
||||
This parameter takes the same values used in ``Image.convert``.
|
||||
|
||||
New language parameter
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These text-rendering functions now accept a ``language`` parameter to request
|
||||
language-specific glyphs and ligatures from the font:
|
||||
|
||||
* ``ImageDraw.ImageDraw.multiline_text()``
|
||||
* ``ImageDraw.ImageDraw.multiline_textsize()``
|
||||
* ``ImageDraw.ImageDraw.text()``
|
||||
* ``ImageDraw.ImageDraw.textsize()``
|
||||
* ``ImageFont.ImageFont.getmask()``
|
||||
* ``ImageFont.ImageFont.getsize_multiline()``
|
||||
* ``ImageFont.ImageFont.getsize()``
|
||||
|
||||
PNG EXIF data
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
EXIF data can now be read from and saved to PNG images. However, unlike other image
|
||||
formats, EXIF data is not guaranteed to have been read until
|
||||
:py:meth:`~PIL.Image.Image.load` has been called.
|
||||
|
||||
Other Changes
|
||||
=============
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
Reading new DDS image format
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
TODO
|
||||
Pillow can now read uncompressed RGB data from DDS images.
|
||||
|
||||
Reading TIFF with old-style JPEG compression
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Added support reading TIFF files with old-style JPEG compression through LibTIFF. All YCbCr
|
||||
TIFF images are now always read as RGB.
|
||||
|
|
|
@ -52,6 +52,10 @@ 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.
|
||||
# =============================================================================
|
||||
|
@ -176,6 +180,7 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
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)],
|
||||
|
@ -184,6 +189,7 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
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",
|
||||
|
@ -196,7 +202,7 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
raw_mode = MASK_MODES[
|
||||
(file_info["bits"], file_info["rgba_mask"])
|
||||
]
|
||||
self.mode = "RGBA" if raw_mode in ("BGRA",) else self.mode
|
||||
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[
|
||||
|
@ -291,7 +297,11 @@ SAVE = {
|
|||
}
|
||||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
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:
|
||||
|
@ -306,14 +316,15 @@ def _save(im, fp, filename):
|
|||
|
||||
stride = ((im.size[0]*bits+7)//8+3) & (~3)
|
||||
header = 40 # or 64 for OS/2 version 2
|
||||
offset = 14 + header + colors * 4
|
||||
image = stride * im.size[1]
|
||||
|
||||
# bitmap header
|
||||
fp.write(b"BM" + # file type (magic)
|
||||
o32(offset+image) + # file size
|
||||
o32(0) + # reserved
|
||||
o32(offset)) # image data offset
|
||||
if bitmap_header:
|
||||
offset = 14 + header + colors * 4
|
||||
fp.write(b"BM" + # file type (magic)
|
||||
o32(offset+image) + # file size
|
||||
o32(0) + # reserved
|
||||
o32(offset)) # image data offset
|
||||
|
||||
# bitmap info header
|
||||
fp.write(o32(header) + # info header size
|
||||
|
@ -352,3 +363,10 @@ 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")
|
||||
|
|
|
@ -123,43 +123,52 @@ class DdsImageFile(ImageFile.ImageFile):
|
|||
# pixel format
|
||||
pfsize, pfflags = struct.unpack("<2I", header.read(8))
|
||||
fourcc = header.read(4)
|
||||
bitcount, rmask, gmask, bmask, amask = struct.unpack("<5I",
|
||||
header.read(20))
|
||||
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]
|
||||
|
||||
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))
|
||||
self.tile = [("raw", (0, 0) + self.size, 0, (rawmode, 0, 1))]
|
||||
else:
|
||||
raise NotImplementedError("Unimplemented pixel format %r" %
|
||||
(fourcc))
|
||||
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))
|
||||
]
|
||||
self.tile = [
|
||||
("bcn", (0, 0) + self.size, data_start, (n))
|
||||
]
|
||||
|
||||
def load_seek(self, pos):
|
||||
pass
|
||||
|
|
|
@ -141,13 +141,11 @@ def Ghostscript(tile, size, fp, scale=1):
|
|||
|
||||
# push data through Ghostscript
|
||||
try:
|
||||
with open(os.devnull, 'w+b') as devnull:
|
||||
startupinfo = None
|
||||
if sys.platform.startswith('win'):
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
subprocess.check_call(command, stdout=devnull,
|
||||
startupinfo=startupinfo)
|
||||
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:
|
||||
|
|
|
@ -578,7 +578,12 @@ class Image(object):
|
|||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.close()
|
||||
if hasattr(self, "_close__fp"):
|
||||
self._close__fp()
|
||||
if (hasattr(self, 'fp') and hasattr(self, '_exclusive_fp')
|
||||
and self.fp and self._exclusive_fp):
|
||||
self.fp.close()
|
||||
self.fp = None
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
|
@ -610,12 +615,7 @@ class Image(object):
|
|||
|
||||
if sys.version_info.major >= 3:
|
||||
def __del__(self):
|
||||
if hasattr(self, "_close__fp"):
|
||||
self._close__fp()
|
||||
if (hasattr(self, 'fp') and hasattr(self, '_exclusive_fp')
|
||||
and self.fp and self._exclusive_fp):
|
||||
self.fp.close()
|
||||
self.fp = None
|
||||
self.__exit__()
|
||||
|
||||
def _copy(self):
|
||||
self.load()
|
||||
|
@ -1049,7 +1049,7 @@ class Image(object):
|
|||
new_im.info['transparency'] = trns
|
||||
return new_im
|
||||
|
||||
def quantize(self, colors=256, method=None, kmeans=0, palette=None):
|
||||
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.
|
||||
|
@ -1062,6 +1062,10 @@ class Image(object):
|
|||
: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
|
||||
|
||||
"""
|
||||
|
@ -1089,7 +1093,7 @@ class Image(object):
|
|||
raise ValueError(
|
||||
"only RGB or L mode images can be quantized to a palette"
|
||||
)
|
||||
im = self.im.convert("P", 1, palette.im)
|
||||
im = self.im.convert("P", dither, palette.im)
|
||||
return self._new(im)
|
||||
|
||||
return self._new(self.im.quantize(colors, method, kmeans))
|
||||
|
@ -2002,7 +2006,7 @@ class Image(object):
|
|||
library automatically seeks to frame 0.
|
||||
|
||||
Note that in the current version of the library, most sequence
|
||||
formats only allows you to seek to the next frame.
|
||||
formats only allow you to seek to the next frame.
|
||||
|
||||
See :py:meth:`~PIL.Image.Image.tell`.
|
||||
|
||||
|
@ -2021,10 +2025,10 @@ class Image(object):
|
|||
debugging purposes.
|
||||
|
||||
On Unix platforms, this method saves the image to a temporary
|
||||
PPM file, and calls either the **xv** utility or the **display**
|
||||
PPM file, and calls the **display**, **eog** or **xv**
|
||||
utility, depending on which one can be found.
|
||||
|
||||
On macOS, this method saves the image to a temporary BMP file, and
|
||||
On macOS, this method saves the image to a temporary PNG file, and
|
||||
opens it with the native Preview application.
|
||||
|
||||
On Windows, it saves the image to a temporary BMP file, and uses
|
||||
|
|
|
@ -282,13 +282,17 @@ class ImageDraw(object):
|
|||
self.draw.draw_bitmap(xy, mask, ink)
|
||||
|
||||
def multiline_text(self, xy, text, fill=None, font=None, anchor=None,
|
||||
spacing=4, align="left", direction=None, features=None):
|
||||
spacing=4, align="left", direction=None, features=None,
|
||||
language=None):
|
||||
widths = []
|
||||
max_width = 0
|
||||
lines = self._multiline_split(text)
|
||||
line_spacing = self.textsize('A', font=font)[1] + spacing
|
||||
for line in lines:
|
||||
line_width, line_height = self.textsize(line, font)
|
||||
line_width, line_height = self.textsize(line, font,
|
||||
direction=direction,
|
||||
features=features,
|
||||
language=language)
|
||||
widths.append(line_width)
|
||||
max_width = max(max_width, line_width)
|
||||
left, top = xy
|
||||
|
@ -302,29 +306,30 @@ class ImageDraw(object):
|
|||
else:
|
||||
raise ValueError('align must be "left", "center" or "right"')
|
||||
self.text((left, top), line, fill, font, anchor,
|
||||
direction=direction, features=features)
|
||||
direction=direction, features=features, language=language)
|
||||
top += line_spacing
|
||||
left = xy[0]
|
||||
|
||||
def textsize(self, text, font=None, spacing=4, direction=None,
|
||||
features=None):
|
||||
features=None, language=None):
|
||||
"""Get the size of a given string, in pixels."""
|
||||
if self._multiline_check(text):
|
||||
return self.multiline_textsize(text, font, spacing,
|
||||
direction, features)
|
||||
direction, features, language)
|
||||
|
||||
if font is None:
|
||||
font = self.getfont()
|
||||
return font.getsize(text, direction, features)
|
||||
return font.getsize(text, direction, features, language)
|
||||
|
||||
def multiline_textsize(self, text, font=None, spacing=4, direction=None,
|
||||
features=None):
|
||||
features=None, language=None):
|
||||
max_width = 0
|
||||
lines = self._multiline_split(text)
|
||||
line_spacing = self.textsize('A', font=font)[1] + spacing
|
||||
for line in lines:
|
||||
line_width, line_height = self.textsize(line, font, spacing,
|
||||
direction, features)
|
||||
direction, features,
|
||||
language)
|
||||
max_width = max(max_width, line_width)
|
||||
return max_width, len(lines)*line_spacing - spacing
|
||||
|
||||
|
|
|
@ -120,9 +120,10 @@ class ImageFile(Image.Image):
|
|||
pass
|
||||
|
||||
def get_format_mimetype(self):
|
||||
if self.format is None:
|
||||
return
|
||||
return self.custom_mimetype or Image.MIME.get(self.format.upper())
|
||||
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"""
|
||||
|
|
|
@ -158,17 +158,17 @@ class FreeTypeFont(object):
|
|||
def getmetrics(self):
|
||||
return self.font.ascent, self.font.descent
|
||||
|
||||
def getsize(self, text, direction=None, features=None):
|
||||
size, offset = self.font.getsize(text, direction, features)
|
||||
def getsize(self, text, direction=None, features=None, language=None):
|
||||
size, offset = self.font.getsize(text, direction, features, language)
|
||||
return (size[0] + offset[0], size[1] + offset[1])
|
||||
|
||||
def getsize_multiline(self, text, direction=None,
|
||||
spacing=4, features=None):
|
||||
def getsize_multiline(self, text, direction=None, spacing=4,
|
||||
features=None, language=None):
|
||||
max_width = 0
|
||||
lines = self._multiline_split(text)
|
||||
line_spacing = self.getsize('A')[1] + spacing
|
||||
for line in lines:
|
||||
line_width, line_height = self.getsize(line, direction, features)
|
||||
line_width, line_height = self.getsize(line, direction, features, language)
|
||||
max_width = max(max_width, line_width)
|
||||
|
||||
return max_width, len(lines)*line_spacing - spacing
|
||||
|
@ -176,15 +176,15 @@ class FreeTypeFont(object):
|
|||
def getoffset(self, text):
|
||||
return self.font.getsize(text)[1]
|
||||
|
||||
def getmask(self, text, mode="", direction=None, features=None):
|
||||
return self.getmask2(text, mode, direction=direction,
|
||||
features=features)[0]
|
||||
def getmask(self, text, mode="", direction=None, features=None, language=None):
|
||||
return self.getmask2(text, mode, direction=direction, features=features,
|
||||
language=language)[0]
|
||||
|
||||
def getmask2(self, text, mode="", fill=Image.core.fill, direction=None,
|
||||
features=None, *args, **kwargs):
|
||||
size, offset = self.font.getsize(text, direction, features)
|
||||
features=None, language=None, *args, **kwargs):
|
||||
size, offset = self.font.getsize(text, direction, features, language)
|
||||
im = fill("L", size, 0)
|
||||
self.font.render(text, im.id, mode == "1", direction, features)
|
||||
self.font.render(text, im.id, mode == "1", direction, features, language)
|
||||
return im, offset
|
||||
|
||||
def font_variant(self, font=None, size=None, index=None, encoding=None,
|
||||
|
|
|
@ -529,6 +529,11 @@ class PngStream(ChunkStream):
|
|||
|
||||
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)
|
||||
|
@ -683,6 +688,12 @@ class PngImageFile(ImageFile.ImageFile):
|
|||
self.png.close()
|
||||
self.png = None
|
||||
|
||||
def _getexif(self):
|
||||
if "exif" not in self.info:
|
||||
self.load()
|
||||
from .JpegImagePlugin import _getexif
|
||||
return _getexif(self)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# PNG writer
|
||||
|
@ -696,6 +707,7 @@ _OUTMODES = {
|
|||
"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'),
|
||||
|
@ -861,6 +873,12 @@ def _save(im, fp, filename, chunk=putchunk):
|
|||
chunks.remove(cid)
|
||||
chunk(fp, cid, data)
|
||||
|
||||
exif = im.encoderinfo.get("exif", im.info.get("exif"))
|
||||
if exif:
|
||||
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)])
|
||||
|
||||
|
|
|
@ -263,10 +263,10 @@ OPEN_INFO = {
|
|||
(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"),
|
||||
|
||||
# JPEG compressed images handled by LibTiff and auto-converted to RGB
|
||||
# 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", "RGB"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
|
||||
(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"),
|
||||
|
@ -819,7 +819,7 @@ class ImageFileDirectory_v2(MutableMapping):
|
|||
print("- value:", values)
|
||||
|
||||
# count is sum of lengths for string and arbitrary data
|
||||
if typ in [TiffTags.ASCII, TiffTags.UNDEFINED]:
|
||||
if typ in [TiffTags.BYTE, TiffTags.ASCII, TiffTags.UNDEFINED]:
|
||||
count = len(data)
|
||||
else:
|
||||
count = len(values)
|
||||
|
@ -1191,6 +1191,10 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# 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:
|
||||
|
|
|
@ -87,6 +87,10 @@ typedef bool (*t_raqm_set_text_utf8) (raqm_t *rq,
|
|||
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);
|
||||
|
@ -106,6 +110,7 @@ typedef struct {
|
|||
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;
|
||||
|
@ -160,6 +165,7 @@ setraqm(void)
|
|||
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");
|
||||
|
@ -176,6 +182,7 @@ setraqm(void)
|
|||
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 &&
|
||||
|
@ -190,6 +197,7 @@ setraqm(void)
|
|||
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");
|
||||
|
@ -205,6 +213,7 @@ setraqm(void)
|
|||
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 &&
|
||||
|
@ -332,8 +341,8 @@ font_getchar(PyObject* string, int index, FT_ULong* char_out)
|
|||
}
|
||||
|
||||
static size_t
|
||||
text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
||||
PyObject *features ,GlyphInfo **glyph_info, int mask)
|
||||
text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
||||
const char* lang, GlyphInfo **glyph_info, int mask)
|
||||
{
|
||||
int i = 0;
|
||||
raqm_t *rq;
|
||||
|
@ -341,6 +350,7 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
|||
raqm_glyph_t *glyphs = NULL;
|
||||
raqm_glyph_t_01 *glyphs_01 = NULL;
|
||||
raqm_direction_t direction;
|
||||
size_t start = 0;
|
||||
|
||||
rq = (*p_raqm.create)();
|
||||
if (rq == NULL) {
|
||||
|
@ -360,6 +370,13 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
|||
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)) {
|
||||
|
@ -372,6 +389,12 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
|||
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 {
|
||||
|
@ -498,8 +521,8 @@ failed:
|
|||
}
|
||||
|
||||
static size_t
|
||||
text_layout_fallback(PyObject* string, FontObject* self, const char* dir,
|
||||
PyObject *features ,GlyphInfo **glyph_info, int mask)
|
||||
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;
|
||||
|
@ -509,8 +532,8 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir,
|
|||
FT_UInt last_index = 0;
|
||||
int i;
|
||||
|
||||
if (features != Py_None || dir != NULL) {
|
||||
PyErr_SetString(PyExc_KeyError, "setting text direction or font features is not supported without libraqm");
|
||||
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)) {
|
||||
|
@ -564,15 +587,15 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir,
|
|||
}
|
||||
|
||||
static size_t
|
||||
text_layout(PyObject* string, FontObject* self, const char* dir,
|
||||
PyObject *features, GlyphInfo **glyph_info, int mask)
|
||||
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, glyph_info, mask);
|
||||
count = text_layout_raqm(string, self, dir, features, lang, glyph_info, mask);
|
||||
} else {
|
||||
count = text_layout_fallback(string, self, dir, features, glyph_info, mask);
|
||||
count = text_layout_fallback(string, self, dir, features, lang, glyph_info, mask);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -584,6 +607,7 @@ font_getsize(FontObject* self, PyObject* args)
|
|||
FT_Face face;
|
||||
int xoffset, yoffset;
|
||||
const char *dir = NULL;
|
||||
const char *lang = NULL;
|
||||
size_t count;
|
||||
GlyphInfo *glyph_info = NULL;
|
||||
PyObject *features = Py_None;
|
||||
|
@ -591,14 +615,14 @@ font_getsize(FontObject* self, PyObject* args)
|
|||
/* calculate size and bearing for a given string */
|
||||
|
||||
PyObject* string;
|
||||
if (!PyArg_ParseTuple(args, "O|zO:getsize", &string, &dir, &features))
|
||||
if (!PyArg_ParseTuple(args, "O|zOz:getsize", &string, &dir, &features, &lang))
|
||||
return NULL;
|
||||
|
||||
face = NULL;
|
||||
xoffset = yoffset = 0;
|
||||
y_max = y_min = 0;
|
||||
|
||||
count = text_layout(string, self, dir, features, &glyph_info, 0);
|
||||
count = text_layout(string, self, dir, features, lang, &glyph_info, 0);
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -691,16 +715,17 @@ font_render(FontObject* self, PyObject* args)
|
|||
int temp;
|
||||
int xx, x0, x1;
|
||||
const char *dir = NULL;
|
||||
const char *lang = NULL;
|
||||
size_t count;
|
||||
GlyphInfo *glyph_info;
|
||||
PyObject *features = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "On|izO:render", &string, &id, &mask, &dir, &features)) {
|
||||
if (!PyArg_ParseTuple(args, "On|izOz:render", &string, &id, &mask, &dir, &features, &lang)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
glyph_info = NULL;
|
||||
count = text_layout(string, self, dir, features, &glyph_info, mask);
|
||||
count = text_layout(string, self, dir, features, lang, &glyph_info, mask);
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -639,6 +639,7 @@ static struct {
|
|||
|
||||
/* 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.
|
||||
|
|
|
@ -124,6 +124,7 @@ toff_t _tiffSizeProc(thandle_t hdata) {
|
|||
|
||||
return (toff_t)state->size;
|
||||
}
|
||||
|
||||
int _tiffMapProc(thandle_t hdata, tdata_t* pbase, toff_t* psize) {
|
||||
TIFFSTATE *state = (TIFFSTATE *)hdata;
|
||||
|
||||
|
@ -168,13 +169,117 @@ int ImagingLibTiffInit(ImagingCodecState state, int fp, int offset) {
|
|||
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);
|
||||
/*
|
||||
* 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, int bytes) {
|
||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||
char *filename = "tempfile.tif";
|
||||
char *mode = "r";
|
||||
TIFF *tiff;
|
||||
uint16 photometric = 0, compression;
|
||||
|
||||
|
||||
/* 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 */
|
||||
|
@ -235,19 +340,17 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
|
|||
}
|
||||
}
|
||||
|
||||
TIFFGetFieldDefaulted(tiff, TIFFTAG_COMPRESSION, &compression);
|
||||
TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
|
||||
if (compression == COMPRESSION_JPEG && photometric == PHOTOMETRIC_YCBCR) {
|
||||
/* Set pseudo-tag to force automatic YCbCr->RGB conversion */
|
||||
TIFFSetField(tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
|
||||
}
|
||||
|
||||
if (TIFFIsTiled(tiff)) {
|
||||
uint32 x, y, tile_y;
|
||||
uint32 tileWidth, tileLength;
|
||||
UINT32 x, y, tile_y, row_byte_size;
|
||||
UINT32 tile_width, tile_length, current_tile_width;
|
||||
UINT8 *new_data;
|
||||
|
||||
state->bytes = TIFFTileSize(tiff);
|
||||
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;
|
||||
state->bytes = row_byte_size * tile_length;
|
||||
|
||||
/* overflow check for malloc */
|
||||
if (state->bytes > INT_MAX - 1) {
|
||||
|
@ -268,12 +371,9 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
|
|||
|
||||
TRACE(("TIFFTileSize: %d\n", state->bytes));
|
||||
|
||||
TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileWidth);
|
||||
TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileLength);
|
||||
|
||||
for (y = state->yoff; y < state->ysize; y += tileLength) {
|
||||
for (x = state->xoff; x < state->xsize; x += tileWidth) {
|
||||
if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, 0) == -1) {
|
||||
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);
|
||||
|
@ -282,53 +382,68 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
|
|||
|
||||
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(tileLength, state->ysize - y); tile_y++) {
|
||||
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));
|
||||
|
||||
TRACE(("Writing tile data at %dx%d using tilwWidth: %d; \n", tile_y + y, x, min(tileWidth, state->xsize - x)));
|
||||
|
||||
// UINT8 * bbb = state->buffer + tile_y * (state->bytes / tileLength);
|
||||
// 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 * (state->bytes / tileLength),
|
||||
min(tileWidth, state->xsize - x)
|
||||
state->buffer + tile_y * row_byte_size,
|
||||
current_tile_width
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tsize_t size;
|
||||
UINT32 strip_row, row_byte_size;
|
||||
UINT8 *new_data;
|
||||
UINT32 rows_per_strip;
|
||||
|
||||
size = TIFFScanlineSize(tiff);
|
||||
TRACE(("ScanlineSize: %lu \n", size));
|
||||
if (size > state->bytes) {
|
||||
TRACE(("Error, scanline size > buffer size\n"));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
|
||||
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;
|
||||
state->bytes = rows_per_strip * row_byte_size;
|
||||
|
||||
TRACE(("StripSize: %d \n", state->bytes));
|
||||
|
||||
/* realloc to fit whole strip */
|
||||
new_data = realloc (state->buffer, state->bytes);
|
||||
if (!new_data) {
|
||||
state->errcode = IMAGING_CODEC_MEMORY;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Have to do this row by row and shove stuff into the buffer that way,
|
||||
// with shuffle. (or, just alloc a buffer myself, then figure out how to get it
|
||||
// back in. Can't use read encoded stripe.
|
||||
state->buffer = new_data;
|
||||
|
||||
// This thing pretty much requires that I have the whole image in one shot.
|
||||
// Perhaps a stub version would work better???
|
||||
while(state->y < state->ysize){
|
||||
if (TIFFReadScanline(tiff, (tdata_t)state->buffer, (uint32)state->y, 0) == -1) {
|
||||
TRACE(("Decode Error, row %d\n", state->y));
|
||||
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 row %d \n", state->y)); */
|
||||
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
|
||||
state->xoff * im->pixelsize,
|
||||
state->buffer,
|
||||
state->xsize);
|
||||
|
||||
state->y++;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,11 @@ def fetch(url):
|
|||
|
||||
if not os.path.exists(name):
|
||||
print("Fetching", url)
|
||||
content = urllib.request.urlopen(url).read()
|
||||
try:
|
||||
r = urllib.request.urlopen(url)
|
||||
except urllib.error.URLError:
|
||||
r = urllib.request.urlopen(url)
|
||||
content = r.read()
|
||||
with open(name, 'wb') as fd:
|
||||
fd.write(content)
|
||||
return name
|
||||
|
|
Loading…
Reference in New Issue
Block a user