mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-27 09:44:31 +03:00
Merge branch 'master' into tiff-jpeg-quality
This commit is contained in:
commit
c994b783ec
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -67,6 +67,9 @@ docs/_build/
|
||||||
\#*#
|
\#*#
|
||||||
.#*
|
.#*
|
||||||
|
|
||||||
|
#VS Code
|
||||||
|
.vscode
|
||||||
|
|
||||||
#Komodo
|
#Komodo
|
||||||
*.komodoproject
|
*.komodoproject
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ make clean
|
||||||
make install-coverage
|
make install-coverage
|
||||||
|
|
||||||
python selftest.py
|
python selftest.py
|
||||||
python -m pytest -vx --cov PIL --cov-report term Tests
|
python -m pytest -v -x --cov PIL --cov-report term Tests
|
||||||
|
|
||||||
pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd
|
pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd
|
||||||
|
|
||||||
|
|
30
CHANGES.rst
30
CHANGES.rst
|
@ -5,6 +5,36 @@ Changelog (Pillow)
|
||||||
6.1.0 (unreleased)
|
6.1.0 (unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- 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
|
- Fixed bugs in calculating text size #3864
|
||||||
[radarhere]
|
[radarhere]
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,8 @@ class TestCoreMemory(PillowTestCase):
|
||||||
Image.new("RGB", (10, 10))
|
Image.new("RGB", (10, 10))
|
||||||
|
|
||||||
self.assertRaises(ValueError, Image.core.set_blocks_max, -1)
|
self.assertRaises(ValueError, Image.core.set_blocks_max, -1)
|
||||||
|
if sys.maxsize < 2 ** 32:
|
||||||
|
self.assertRaises(ValueError, Image.core.set_blocks_max, 2 ** 29)
|
||||||
|
|
||||||
@unittest.skipIf(is_pypy, "images are not collected")
|
@unittest.skipIf(is_pypy, "images are not collected")
|
||||||
def test_set_blocks_max_stats(self):
|
def test_set_blocks_max_stats(self):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from .helper import unittest, PillowTestCase, hopper, netpbm_available
|
from .helper import unittest, PillowTestCase, hopper, netpbm_available
|
||||||
|
|
||||||
from PIL import Image, ImagePalette, GifImagePlugin
|
from PIL import Image, ImagePalette, GifImagePlugin, ImageDraw
|
||||||
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class TestFileGif(PillowTestCase):
|
||||||
return len(test_file.getvalue())
|
return len(test_file.getvalue())
|
||||||
|
|
||||||
self.assertEqual(test_grayscale(0), 800)
|
self.assertEqual(test_grayscale(0), 800)
|
||||||
self.assertEqual(test_grayscale(1), 38)
|
self.assertEqual(test_grayscale(1), 44)
|
||||||
self.assertEqual(test_bilevel(0), 800)
|
self.assertEqual(test_bilevel(0), 800)
|
||||||
self.assertEqual(test_bilevel(1), 800)
|
self.assertEqual(test_bilevel(1), 800)
|
||||||
|
|
||||||
|
@ -318,6 +318,103 @@ class TestFileGif(PillowTestCase):
|
||||||
img.seek(img.tell() + 1)
|
img.seek(img.tell() + 1)
|
||||||
self.assertEqual(img.disposal_method, i + 1)
|
self.assertEqual(img.disposal_method, i + 1)
|
||||||
|
|
||||||
|
def test_dispose2_palette(self):
|
||||||
|
out = self.tempfile("temp.gif")
|
||||||
|
|
||||||
|
# 4 backgrounds: White, Grey, Black, Red
|
||||||
|
circles = [(255, 255, 255), (153, 153, 153), (0, 0, 0), (255, 0, 0)]
|
||||||
|
|
||||||
|
im_list = []
|
||||||
|
for circle in circles:
|
||||||
|
img = Image.new("RGB", (100, 100), (255, 0, 0))
|
||||||
|
|
||||||
|
# Red circle in center of each frame
|
||||||
|
d = ImageDraw.Draw(img)
|
||||||
|
d.ellipse([(40, 40), (60, 60)], fill=circle)
|
||||||
|
|
||||||
|
im_list.append(img)
|
||||||
|
|
||||||
|
im_list[0].save(out, save_all=True, append_images=im_list[1:], disposal=2)
|
||||||
|
|
||||||
|
img = Image.open(out)
|
||||||
|
|
||||||
|
for i, circle in enumerate(circles):
|
||||||
|
img.seek(i)
|
||||||
|
rgb_img = img.convert("RGB")
|
||||||
|
|
||||||
|
# Check top left pixel matches background
|
||||||
|
self.assertEqual(rgb_img.getpixel((0, 0)), (255, 0, 0))
|
||||||
|
|
||||||
|
# Center remains red every frame
|
||||||
|
self.assertEqual(rgb_img.getpixel((50, 50)), circle)
|
||||||
|
|
||||||
|
def test_dispose2_diff(self):
|
||||||
|
out = self.tempfile("temp.gif")
|
||||||
|
|
||||||
|
# 4 frames: red/blue, red/red, blue/blue, red/blue
|
||||||
|
circles = [
|
||||||
|
((255, 0, 0, 255), (0, 0, 255, 255)),
|
||||||
|
((255, 0, 0, 255), (255, 0, 0, 255)),
|
||||||
|
((0, 0, 255, 255), (0, 0, 255, 255)),
|
||||||
|
((255, 0, 0, 255), (0, 0, 255, 255)),
|
||||||
|
]
|
||||||
|
|
||||||
|
im_list = []
|
||||||
|
for i in range(len(circles)):
|
||||||
|
# Transparent BG
|
||||||
|
img = Image.new("RGBA", (100, 100), (255, 255, 255, 0))
|
||||||
|
|
||||||
|
# Two circles per frame
|
||||||
|
d = ImageDraw.Draw(img)
|
||||||
|
d.ellipse([(0, 30), (40, 70)], fill=circles[i][0])
|
||||||
|
d.ellipse([(60, 30), (100, 70)], fill=circles[i][1])
|
||||||
|
|
||||||
|
im_list.append(img)
|
||||||
|
|
||||||
|
im_list[0].save(
|
||||||
|
out, save_all=True, append_images=im_list[1:], disposal=2, transparency=0
|
||||||
|
)
|
||||||
|
|
||||||
|
img = Image.open(out)
|
||||||
|
|
||||||
|
for i, colours in enumerate(circles):
|
||||||
|
img.seek(i)
|
||||||
|
rgb_img = img.convert("RGBA")
|
||||||
|
|
||||||
|
# Check left circle is correct colour
|
||||||
|
self.assertEqual(rgb_img.getpixel((20, 50)), colours[0])
|
||||||
|
|
||||||
|
# Check right circle is correct colour
|
||||||
|
self.assertEqual(rgb_img.getpixel((80, 50)), colours[1])
|
||||||
|
|
||||||
|
# Check BG is correct colour
|
||||||
|
self.assertEqual(rgb_img.getpixel((1, 1)), (255, 255, 255, 0))
|
||||||
|
|
||||||
|
def test_dispose2_background(self):
|
||||||
|
out = self.tempfile("temp.gif")
|
||||||
|
|
||||||
|
im_list = []
|
||||||
|
|
||||||
|
im = Image.new("P", (100, 100))
|
||||||
|
d = ImageDraw.Draw(im)
|
||||||
|
d.rectangle([(50, 0), (100, 100)], fill="#f00")
|
||||||
|
d.rectangle([(0, 0), (50, 100)], fill="#0f0")
|
||||||
|
im_list.append(im)
|
||||||
|
|
||||||
|
im = Image.new("P", (100, 100))
|
||||||
|
d = ImageDraw.Draw(im)
|
||||||
|
d.rectangle([(0, 0), (100, 50)], fill="#f00")
|
||||||
|
d.rectangle([(0, 50), (100, 100)], fill="#0f0")
|
||||||
|
im_list.append(im)
|
||||||
|
|
||||||
|
im_list[0].save(
|
||||||
|
out, save_all=True, append_images=im_list[1:], disposal=[0, 2], background=1
|
||||||
|
)
|
||||||
|
|
||||||
|
im = Image.open(out)
|
||||||
|
im.seek(1)
|
||||||
|
self.assertEqual(im.getpixel((0, 0)), 0)
|
||||||
|
|
||||||
def test_iss634(self):
|
def test_iss634(self):
|
||||||
img = Image.open("Tests/images/iss634.gif")
|
img = Image.open("Tests/images/iss634.gif")
|
||||||
# seek to the second frame
|
# seek to the second frame
|
||||||
|
|
|
@ -122,7 +122,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
self.assertEqual(im.mode, "RGB")
|
self.assertEqual(im.mode, "RGB")
|
||||||
self.assertEqual(im.size, (278, 374))
|
self.assertEqual(im.size, (278, 374))
|
||||||
self.assertEqual(im.tile[0][:3], ("tiff_adobe_deflate", (0, 0, 278, 374), 0))
|
self.assertEqual(im.tile[0][:3], ("libtiff", (0, 0, 278, 374), 0))
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
||||||
|
@ -710,10 +710,10 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
im.tile,
|
im.tile,
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"tiff_adobe_deflate",
|
"libtiff",
|
||||||
(0, 0, 100, 40),
|
(0, 0, 100, 40),
|
||||||
0,
|
0,
|
||||||
("RGB;16N", "tiff_adobe_deflate", False),
|
("RGB;16N", "tiff_adobe_deflate", False, 8),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -727,7 +727,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
self.assertEqual(im.mode, "RGBA")
|
self.assertEqual(im.mode, "RGBA")
|
||||||
self.assertEqual(im.size, (100, 40))
|
self.assertEqual(im.size, (100, 40))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.tile, [("tiff_lzw", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False))]
|
im.tile,
|
||||||
|
[("libtiff", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False, 38236))],
|
||||||
)
|
)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
|
@ -746,7 +747,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
self.assertEqual(im.mode, "RGB")
|
self.assertEqual(im.mode, "RGB")
|
||||||
self.assertEqual(im.size, (256, 256))
|
self.assertEqual(im.size, (256, 256))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.tile, [("jpeg", (0, 0, 256, 256), 0, ("RGB", "jpeg", False))]
|
im.tile, [("libtiff", (0, 0, 256, 256), 0, ("RGB", "jpeg", False, 5122))]
|
||||||
)
|
)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
|
|
17
Tests/test_image_entropy.py
Normal file
17
Tests/test_image_entropy.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from .helper import PillowTestCase, hopper
|
||||||
|
|
||||||
|
|
||||||
|
class TestImageEntropy(PillowTestCase):
|
||||||
|
def test_entropy(self):
|
||||||
|
def entropy(mode):
|
||||||
|
return hopper(mode).entropy()
|
||||||
|
|
||||||
|
self.assertAlmostEqual(entropy("1"), 0.9138803254693582)
|
||||||
|
self.assertAlmostEqual(entropy("L"), 7.06650513081286)
|
||||||
|
self.assertAlmostEqual(entropy("I"), 7.06650513081286)
|
||||||
|
self.assertAlmostEqual(entropy("F"), 7.06650513081286)
|
||||||
|
self.assertAlmostEqual(entropy("P"), 5.0530452472519745)
|
||||||
|
self.assertAlmostEqual(entropy("RGB"), 8.821286587714319)
|
||||||
|
self.assertAlmostEqual(entropy("RGBA"), 7.42724306524488)
|
||||||
|
self.assertAlmostEqual(entropy("CMYK"), 7.4272430652448795)
|
||||||
|
self.assertAlmostEqual(entropy("YCbCr"), 7.698360534903628)
|
|
@ -420,6 +420,10 @@ class TestImageFont(PillowTestCase):
|
||||||
self.assertRaises(IOError, ImageFont.load_path, filename)
|
self.assertRaises(IOError, ImageFont.load_path, filename)
|
||||||
self.assertRaises(IOError, ImageFont.truetype, filename)
|
self.assertRaises(IOError, ImageFont.truetype, filename)
|
||||||
|
|
||||||
|
def test_load_non_font_bytes(self):
|
||||||
|
with open("Tests/images/hopper.jpg", "rb") as f:
|
||||||
|
self.assertRaises(IOError, ImageFont.truetype, f)
|
||||||
|
|
||||||
def test_default_font(self):
|
def test_default_font(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
txt = 'This is a "better than nothing" default font.'
|
txt = 'This is a "better than nothing" default font.'
|
||||||
|
|
|
@ -74,3 +74,25 @@ class TestImageSequence(PillowTestCase):
|
||||||
im.seek(0)
|
im.seek(0)
|
||||||
color2 = im.getpalette()[0:3]
|
color2 = im.getpalette()[0:3]
|
||||||
self.assertEqual(color1, color2)
|
self.assertEqual(color1, color2)
|
||||||
|
|
||||||
|
def test_all_frames(self):
|
||||||
|
# Test a single image
|
||||||
|
im = Image.open("Tests/images/iss634.gif")
|
||||||
|
ims = ImageSequence.all_frames(im)
|
||||||
|
|
||||||
|
self.assertEqual(len(ims), 42)
|
||||||
|
for i, im_frame in enumerate(ims):
|
||||||
|
self.assertFalse(im_frame is im)
|
||||||
|
|
||||||
|
im.seek(i)
|
||||||
|
self.assert_image_equal(im, im_frame)
|
||||||
|
|
||||||
|
# Test a series of images
|
||||||
|
ims = ImageSequence.all_frames([im, hopper(), im])
|
||||||
|
self.assertEqual(len(ims), 85)
|
||||||
|
|
||||||
|
# Test an operation
|
||||||
|
ims = ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90))
|
||||||
|
for i, im_frame in enumerate(ims):
|
||||||
|
im.seek(i)
|
||||||
|
self.assert_image_equal(im.rotate(90), im_frame)
|
||||||
|
|
|
@ -16,7 +16,7 @@ Open, rotate, and display an image (using the default viewer)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The following script loads an image, rotates it 45 degrees, and displays it
|
The following script loads an image, rotates it 45 degrees, and displays it
|
||||||
using an external viewer (usually xv on Unix, and the paint program on
|
using an external viewer (usually xv on Unix, and the Paint program on
|
||||||
Windows).
|
Windows).
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -116,15 +116,66 @@ ITU-R 709, using the D65 luminant) to the CIE XYZ color space:
|
||||||
rgb2xyz = (
|
rgb2xyz = (
|
||||||
0.412453, 0.357580, 0.180423, 0,
|
0.412453, 0.357580, 0.180423, 0,
|
||||||
0.212671, 0.715160, 0.072169, 0,
|
0.212671, 0.715160, 0.072169, 0,
|
||||||
0.019334, 0.119193, 0.950227, 0 )
|
0.019334, 0.119193, 0.950227, 0)
|
||||||
out = im.convert("RGB", rgb2xyz)
|
out = im.convert("RGB", rgb2xyz)
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.copy
|
.. automethod:: PIL.Image.Image.copy
|
||||||
.. automethod:: PIL.Image.Image.crop
|
.. automethod:: PIL.Image.Image.crop
|
||||||
|
|
||||||
|
This crops the input image with the provided coordinates:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
im = Image.open("hopper.jpg")
|
||||||
|
|
||||||
|
# The crop method from the Image module takes four coordinates as input.
|
||||||
|
# The right can also be represented as (left+width)
|
||||||
|
# and lower can be represented as (upper+height).
|
||||||
|
(left, upper, right, lower) = (20, 20, 100, 100)
|
||||||
|
|
||||||
|
# Here the image "im" is cropped and assigned to new variable im_crop
|
||||||
|
im_crop = im.crop((left, upper, right, lower))
|
||||||
|
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.draft
|
.. automethod:: PIL.Image.Image.draft
|
||||||
.. automethod:: PIL.Image.Image.filter
|
.. automethod:: PIL.Image.Image.filter
|
||||||
|
|
||||||
|
This blurs the input image using a filter from the ``ImageFilter`` module:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from PIL import Image, ImageFilter
|
||||||
|
|
||||||
|
im = Image.open("hopper.jpg")
|
||||||
|
|
||||||
|
# Blur the input image using the filter ImageFilter.BLUR
|
||||||
|
im_blurred = im.filter(filter=ImageFilter.BLUR)
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.getbands
|
.. automethod:: PIL.Image.Image.getbands
|
||||||
|
|
||||||
|
This helps to get the bands of the input image:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
im = Image.open("hopper.jpg")
|
||||||
|
print(im.getbands()) # Returns ('R', 'G', 'B')
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.getbbox
|
.. automethod:: PIL.Image.Image.getbbox
|
||||||
|
|
||||||
|
This helps to get the bounding box coordinates of the input image:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
im = Image.open("hopper.jpg")
|
||||||
|
print(im.getbbox())
|
||||||
|
# Returns four coordinates in the format (left, upper, right, lower)
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.getcolors
|
.. automethod:: PIL.Image.Image.getcolors
|
||||||
.. automethod:: PIL.Image.Image.getdata
|
.. automethod:: PIL.Image.Image.getdata
|
||||||
.. automethod:: PIL.Image.Image.getextrema
|
.. automethod:: PIL.Image.Image.getextrema
|
||||||
|
@ -140,8 +191,35 @@ ITU-R 709, using the D65 luminant) to the CIE XYZ color space:
|
||||||
.. automethod:: PIL.Image.Image.putpixel
|
.. automethod:: PIL.Image.Image.putpixel
|
||||||
.. automethod:: PIL.Image.Image.quantize
|
.. automethod:: PIL.Image.Image.quantize
|
||||||
.. automethod:: PIL.Image.Image.resize
|
.. automethod:: PIL.Image.Image.resize
|
||||||
|
|
||||||
|
This resizes the given image from ``(width, height)`` to ``(width/2, height/2)``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
im = Image.open("hopper.jpg")
|
||||||
|
|
||||||
|
# Provide the target width and height of the image
|
||||||
|
(width, height) = (im.width // 2, im.height // 2)
|
||||||
|
im_resized = im.resize((width, height))
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.remap_palette
|
.. automethod:: PIL.Image.Image.remap_palette
|
||||||
.. automethod:: PIL.Image.Image.rotate
|
.. automethod:: PIL.Image.Image.rotate
|
||||||
|
|
||||||
|
This rotates the input image by ``theta`` degrees counter clockwise:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
im = Image.open("hopper.jpg")
|
||||||
|
|
||||||
|
# Rotate the image by 60 degrees counter clockwise
|
||||||
|
theta = 60
|
||||||
|
# Angle is in degrees counter clockwise
|
||||||
|
im_rotated = im.rotate(angle=theta)
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.save
|
.. automethod:: PIL.Image.Image.save
|
||||||
.. automethod:: PIL.Image.Image.seek
|
.. automethod:: PIL.Image.Image.seek
|
||||||
.. automethod:: PIL.Image.Image.show
|
.. automethod:: PIL.Image.Image.show
|
||||||
|
@ -154,6 +232,21 @@ ITU-R 709, using the D65 luminant) to the CIE XYZ color space:
|
||||||
.. automethod:: PIL.Image.Image.tostring
|
.. automethod:: PIL.Image.Image.tostring
|
||||||
.. automethod:: PIL.Image.Image.transform
|
.. automethod:: PIL.Image.Image.transform
|
||||||
.. automethod:: PIL.Image.Image.transpose
|
.. automethod:: PIL.Image.Image.transpose
|
||||||
|
|
||||||
|
This flips the input image by using the ``Image.FLIP_LEFT_RIGHT`` method.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
im = Image.open("hopper.jpg")
|
||||||
|
|
||||||
|
# Flip the image from left to right
|
||||||
|
im_flipped = im.transpose(method=Image.FLIP_LEFT_RIGHT)
|
||||||
|
# To flip the image from top to bottom,
|
||||||
|
# use the method "Image.FLIP_TOP_BOTTOM"
|
||||||
|
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.verify
|
.. automethod:: PIL.Image.Image.verify
|
||||||
|
|
||||||
.. automethod:: PIL.Image.Image.fromstring
|
.. automethod:: PIL.Image.Image.fromstring
|
||||||
|
|
|
@ -11,6 +11,14 @@ An optional ``include_layered_windows`` parameter has been added to ``ImageGrab.
|
||||||
defaulting to ``False``. If true, layered windows will be included in the resulting
|
defaulting to ``False``. If true, layered windows will be included in the resulting
|
||||||
image on Windows.
|
image on Windows.
|
||||||
|
|
||||||
|
ImageSequence.all_frames
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
A new method to facilitate applying a given function to all frames in an image, or to
|
||||||
|
all frames in a list of images. The frames are returned as a list of separate images.
|
||||||
|
For example, ``ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90))``
|
||||||
|
could be used to return all frames from an image, each rotated 90 degrees.
|
||||||
|
|
||||||
Variation fonts
|
Variation fonts
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,8 @@ def testimage():
|
||||||
2
|
2
|
||||||
>>> len(im.histogram())
|
>>> len(im.histogram())
|
||||||
768
|
768
|
||||||
|
>>> '%.7f' % im.entropy()
|
||||||
|
'8.8212866'
|
||||||
>>> _info(im.point(list(range(256))*3))
|
>>> _info(im.point(list(range(256))*3))
|
||||||
(None, 'RGB', (128, 128))
|
(None, 'RGB', (128, 128))
|
||||||
>>> _info(im.resize((64, 64)))
|
>>> _info(im.resize((64, 64)))
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -386,8 +386,8 @@ class pil_build_ext(build_ext):
|
||||||
_add_directory(library_dirs, lib_root)
|
_add_directory(library_dirs, lib_root)
|
||||||
_add_directory(include_dirs, include_root)
|
_add_directory(include_dirs, include_root)
|
||||||
|
|
||||||
# respect CFLAGS/LDFLAGS
|
# respect CFLAGS/CPPFLAGS/LDFLAGS
|
||||||
for k in ("CFLAGS", "LDFLAGS"):
|
for k in ("CFLAGS", "CPPFLAGS", "LDFLAGS"):
|
||||||
if k in os.environ:
|
if k in os.environ:
|
||||||
for match in re.finditer(r"-I([^\s]+)", os.environ[k]):
|
for match in re.finditer(r"-I([^\s]+)", os.environ[k]):
|
||||||
_add_directory(include_dirs, match.group(1))
|
_add_directory(include_dirs, match.group(1))
|
||||||
|
|
|
@ -426,6 +426,7 @@ def _write_multiple_frames(im, fp, palette):
|
||||||
|
|
||||||
im_frames = []
|
im_frames = []
|
||||||
frame_count = 0
|
frame_count = 0
|
||||||
|
background_im = None
|
||||||
for imSequence in itertools.chain([im], im.encoderinfo.get("append_images", [])):
|
for imSequence in itertools.chain([im], im.encoderinfo.get("append_images", [])):
|
||||||
for im_frame in ImageSequence.Iterator(imSequence):
|
for im_frame in ImageSequence.Iterator(imSequence):
|
||||||
# a copy is required here since seek can still mutate the image
|
# a copy is required here since seek can still mutate the image
|
||||||
|
@ -445,11 +446,22 @@ def _write_multiple_frames(im, fp, palette):
|
||||||
if im_frames:
|
if im_frames:
|
||||||
# delta frame
|
# delta frame
|
||||||
previous = im_frames[-1]
|
previous = im_frames[-1]
|
||||||
if _get_palette_bytes(im_frame) == _get_palette_bytes(previous["im"]):
|
if encoderinfo.get("disposal") == 2:
|
||||||
delta = ImageChops.subtract_modulo(im_frame, previous["im"])
|
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:
|
else:
|
||||||
delta = ImageChops.subtract_modulo(
|
delta = ImageChops.subtract_modulo(
|
||||||
im_frame.convert("RGB"), previous["im"].convert("RGB")
|
im_frame.convert("RGB"), base_im.convert("RGB")
|
||||||
)
|
)
|
||||||
bbox = delta.getbbox()
|
bbox = delta.getbbox()
|
||||||
if not bbox:
|
if not bbox:
|
||||||
|
@ -683,10 +695,12 @@ def _get_color_table_size(palette_bytes):
|
||||||
# calculate the palette size for the header
|
# calculate the palette size for the header
|
||||||
import math
|
import math
|
||||||
|
|
||||||
color_table_size = int(math.ceil(math.log(len(palette_bytes) // 3, 2))) - 1
|
if not palette_bytes:
|
||||||
if color_table_size < 0:
|
return 0
|
||||||
color_table_size = 0
|
elif len(palette_bytes) < 9:
|
||||||
return color_table_size
|
return 1
|
||||||
|
else:
|
||||||
|
return int(math.ceil(math.log(len(palette_bytes) // 3, 2))) - 1
|
||||||
|
|
||||||
|
|
||||||
def _get_header_palette(palette_bytes):
|
def _get_header_palette(palette_bytes):
|
||||||
|
@ -717,6 +731,18 @@ def _get_palette_bytes(im):
|
||||||
return im.palette.palette
|
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):
|
def _get_global_header(im, info):
|
||||||
"""Return a list of strings representing a GIF header"""
|
"""Return a list of strings representing a GIF header"""
|
||||||
|
|
||||||
|
@ -736,14 +762,7 @@ def _get_global_header(im, info):
|
||||||
if im.info.get("version") == b"89a":
|
if im.info.get("version") == b"89a":
|
||||||
version = b"89a"
|
version = b"89a"
|
||||||
|
|
||||||
background = 0
|
background = _get_background(im, info.get("background"))
|
||||||
if "background" in info:
|
|
||||||
background = info["background"]
|
|
||||||
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)
|
|
||||||
|
|
||||||
palette_bytes = _get_palette_bytes(im)
|
palette_bytes = _get_palette_bytes(im)
|
||||||
color_table_size = _get_color_table_size(palette_bytes)
|
color_table_size = _get_color_table_size(palette_bytes)
|
||||||
|
|
|
@ -1405,6 +1405,7 @@ class Image(object):
|
||||||
bi-level image (mode "1") or a greyscale image ("L").
|
bi-level image (mode "1") or a greyscale image ("L").
|
||||||
|
|
||||||
:param mask: An optional mask.
|
:param mask: An optional mask.
|
||||||
|
:param extrema: An optional tuple of manually-specified extrema.
|
||||||
:returns: A list containing pixel counts.
|
:returns: A list containing pixel counts.
|
||||||
"""
|
"""
|
||||||
self.load()
|
self.load()
|
||||||
|
@ -1417,6 +1418,32 @@ class Image(object):
|
||||||
return self.im.histogram(extrema)
|
return self.im.histogram(extrema)
|
||||||
return self.im.histogram()
|
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):
|
def offset(self, xoffset, yoffset=None):
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"offset() has been removed. Please call ImageChops.offset() instead."
|
"offset() has been removed. Please call ImageChops.offset() instead."
|
||||||
|
|
|
@ -545,6 +545,8 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
||||||
try:
|
try:
|
||||||
return freetype(font)
|
return freetype(font)
|
||||||
except IOError:
|
except IOError:
|
||||||
|
if not isPath(font):
|
||||||
|
raise
|
||||||
ttf_filename = os.path.basename(font)
|
ttf_filename = os.path.basename(font)
|
||||||
|
|
||||||
dirs = []
|
dirs = []
|
||||||
|
|
|
@ -54,3 +54,25 @@ class Iterator(object):
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
return self.__next__()
|
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
|
||||||
|
|
|
@ -1124,7 +1124,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
# (self._compression, (extents tuple),
|
# (self._compression, (extents tuple),
|
||||||
# 0, (rawmode, self._compression, fp))
|
# 0, (rawmode, self._compression, fp))
|
||||||
extents = self.tile[0][1]
|
extents = self.tile[0][1]
|
||||||
args = list(self.tile[0][3]) + [self.tag_v2.offset]
|
args = list(self.tile[0][3])
|
||||||
|
|
||||||
# To be nice on memory footprint, if there's a
|
# To be nice on memory footprint, if there's a
|
||||||
# file descriptor, use that instead of reading
|
# file descriptor, use that instead of reading
|
||||||
|
@ -1331,8 +1331,8 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# Offset in the tile tuple is 0, we go from 0,0 to
|
# Offset in the tile tuple is 0, we go from 0,0 to
|
||||||
# w,h, and we only do this once -- eds
|
# w,h, and we only do this once -- eds
|
||||||
a = (rawmode, self._compression, False)
|
a = (rawmode, self._compression, False, self.tag_v2.offset)
|
||||||
self.tile.append((self._compression, (0, 0, xsize, ysize), 0, a))
|
self.tile.append(("libtiff", (0, 0, xsize, ysize), 0, a))
|
||||||
|
|
||||||
elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2:
|
elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2:
|
||||||
# striped image
|
# striped image
|
||||||
|
|
|
@ -37,8 +37,8 @@ def i16le(c, o=0):
|
||||||
"""
|
"""
|
||||||
Converts a 2-bytes (16 bits) string to an unsigned integer.
|
Converts a 2-bytes (16 bits) string to an unsigned integer.
|
||||||
|
|
||||||
c: string containing bytes to convert
|
:param c: string containing bytes to convert
|
||||||
o: offset of bytes to convert in string
|
:param o: offset of bytes to convert in string
|
||||||
"""
|
"""
|
||||||
return unpack_from("<H", c, o)[0]
|
return unpack_from("<H", c, o)[0]
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ def si16le(c, o=0):
|
||||||
"""
|
"""
|
||||||
Converts a 2-bytes (16 bits) string to a signed integer.
|
Converts a 2-bytes (16 bits) string to a signed integer.
|
||||||
|
|
||||||
c: string containing bytes to convert
|
:param c: string containing bytes to convert
|
||||||
o: offset of bytes to convert in string
|
:param o: offset of bytes to convert in string
|
||||||
"""
|
"""
|
||||||
return unpack_from("<h", c, o)[0]
|
return unpack_from("<h", c, o)[0]
|
||||||
|
|
||||||
|
@ -57,8 +57,8 @@ def i32le(c, o=0):
|
||||||
"""
|
"""
|
||||||
Converts a 4-bytes (32 bits) string to an unsigned integer.
|
Converts a 4-bytes (32 bits) string to an unsigned integer.
|
||||||
|
|
||||||
c: string containing bytes to convert
|
:param c: string containing bytes to convert
|
||||||
o: offset of bytes to convert in string
|
:param o: offset of bytes to convert in string
|
||||||
"""
|
"""
|
||||||
return unpack_from("<I", c, o)[0]
|
return unpack_from("<I", c, o)[0]
|
||||||
|
|
||||||
|
@ -67,8 +67,8 @@ def si32le(c, o=0):
|
||||||
"""
|
"""
|
||||||
Converts a 4-bytes (32 bits) string to a signed integer.
|
Converts a 4-bytes (32 bits) string to a signed integer.
|
||||||
|
|
||||||
c: string containing bytes to convert
|
:param c: string containing bytes to convert
|
||||||
o: offset of bytes to convert in string
|
:param o: offset of bytes to convert in string
|
||||||
"""
|
"""
|
||||||
return unpack_from("<i", c, o)[0]
|
return unpack_from("<i", c, o)[0]
|
||||||
|
|
||||||
|
|
146
src/_imaging.c
146
src/_imaging.c
|
@ -86,6 +86,9 @@
|
||||||
|
|
||||||
#include "py3.h"
|
#include "py3.h"
|
||||||
|
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
/* Configuration stuff. Feel free to undef things you don't need. */
|
/* Configuration stuff. Feel free to undef things you don't need. */
|
||||||
#define WITH_IMAGECHOPS /* ImageChops support */
|
#define WITH_IMAGECHOPS /* ImageChops support */
|
||||||
#define WITH_IMAGEDRAW /* ImageDraw support */
|
#define WITH_IMAGEDRAW /* ImageDraw support */
|
||||||
|
@ -1176,59 +1179,68 @@ _getpixel(ImagingObject* self, PyObject* args)
|
||||||
return getpixel(self->image, self->access, x, y);
|
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*
|
static PyObject*
|
||||||
_histogram(ImagingObject* self, PyObject* args)
|
_histogram(ImagingObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingHistogram h;
|
ImagingHistogram h;
|
||||||
PyObject* list;
|
PyObject* list;
|
||||||
int i;
|
int i;
|
||||||
union {
|
union hist_extrema extrema;
|
||||||
UINT8 u[2];
|
union hist_extrema* ep;
|
||||||
INT32 i[2];
|
|
||||||
FLOAT32 f[2];
|
|
||||||
} extrema;
|
|
||||||
void* ep;
|
|
||||||
int i0, i1;
|
|
||||||
double f0, f1;
|
|
||||||
|
|
||||||
PyObject* extremap = NULL;
|
PyObject* extremap = NULL;
|
||||||
ImagingObject* maskp = NULL;
|
ImagingObject* maskp = NULL;
|
||||||
if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp))
|
if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (extremap) {
|
|
||||||
ep = &extrema;
|
|
||||||
switch (self->image->type) {
|
|
||||||
case IMAGING_TYPE_UINT8:
|
|
||||||
if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1))
|
|
||||||
return NULL;
|
|
||||||
/* FIXME: clip */
|
|
||||||
extrema.u[0] = i0;
|
|
||||||
extrema.u[1] = i1;
|
|
||||||
break;
|
|
||||||
case IMAGING_TYPE_INT32:
|
|
||||||
if (!PyArg_ParseTuple(extremap, "ii", &i0, &i1))
|
|
||||||
return NULL;
|
|
||||||
extrema.i[0] = i0;
|
|
||||||
extrema.i[1] = i1;
|
|
||||||
break;
|
|
||||||
case IMAGING_TYPE_FLOAT32:
|
|
||||||
if (!PyArg_ParseTuple(extremap, "dd", &f0, &f1))
|
|
||||||
return NULL;
|
|
||||||
extrema.f[0] = (FLOAT32) f0;
|
|
||||||
extrema.f[1] = (FLOAT32) f1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ep = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
ep = NULL;
|
|
||||||
|
|
||||||
|
/* Using a var to avoid allocations. */
|
||||||
|
ep = parse_histogram_extremap(self, extremap, &extrema);
|
||||||
h = ImagingGetHistogram(self->image, (maskp) ? maskp->image : NULL, ep);
|
h = ImagingGetHistogram(self->image, (maskp) ? maskp->image : NULL, ep);
|
||||||
|
|
||||||
if (!h)
|
if (!h)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Build an integer list containing the histogram */
|
/* Build an integer list containing the histogram */
|
||||||
list = PyList_New(h->bands * 256);
|
list = PyList_New(h->bands * 256);
|
||||||
|
@ -1243,11 +1255,59 @@ _histogram(ImagingObject* self, PyObject* args)
|
||||||
PyList_SetItem(list, i, item);
|
PyList_SetItem(list, i, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Destroy the histogram structure */
|
||||||
ImagingHistogramDelete(h);
|
ImagingHistogramDelete(h);
|
||||||
|
|
||||||
return list;
|
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
|
#ifdef WITH_MODEFILTER
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_modefilter(ImagingObject* self, PyObject* args)
|
_modefilter(ImagingObject* self, PyObject* args)
|
||||||
|
@ -3193,6 +3253,7 @@ static struct PyMethodDef methods[] = {
|
||||||
{"expand", (PyCFunction)_expand_image, 1},
|
{"expand", (PyCFunction)_expand_image, 1},
|
||||||
{"filter", (PyCFunction)_filter, 1},
|
{"filter", (PyCFunction)_filter, 1},
|
||||||
{"histogram", (PyCFunction)_histogram, 1},
|
{"histogram", (PyCFunction)_histogram, 1},
|
||||||
|
{"entropy", (PyCFunction)_entropy, 1},
|
||||||
#ifdef WITH_MODEFILTER
|
#ifdef WITH_MODEFILTER
|
||||||
{"modefilter", (PyCFunction)_modefilter, 1},
|
{"modefilter", (PyCFunction)_modefilter, 1},
|
||||||
#endif
|
#endif
|
||||||
|
@ -3625,6 +3686,12 @@ _set_blocks_max(PyObject* self, PyObject* args)
|
||||||
"blocks_max should be greater than 0");
|
"blocks_max should be greater than 0");
|
||||||
return NULL;
|
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)) {
|
if ( ! ImagingMemorySetBlocksMax(&ImagingDefaultArena, blocks_max)) {
|
||||||
ImagingError_MemoryError();
|
ImagingError_MemoryError();
|
||||||
|
@ -3912,4 +3979,3 @@ init_imaging(void)
|
||||||
setup_module(m);
|
setup_module(m);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,7 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|is"PY_ARG_BYTES_LENGTH"i",
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "etn|ns"PY_ARG_BYTES_LENGTH"n",
|
||||||
kwlist,
|
kwlist,
|
||||||
Py_FileSystemDefaultEncoding, &filename,
|
Py_FileSystemDefaultEncoding, &filename,
|
||||||
&size, &index, &encoding, &font_bytes,
|
&size, &index, &encoding, &font_bytes,
|
||||||
|
@ -315,6 +315,7 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
if (error) {
|
if (error) {
|
||||||
if (self->font_bytes) {
|
if (self->font_bytes) {
|
||||||
PyMem_Free(self->font_bytes);
|
PyMem_Free(self->font_bytes);
|
||||||
|
self->font_bytes = NULL;
|
||||||
}
|
}
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
return geterror(error);
|
return geterror(error);
|
||||||
|
@ -1006,6 +1007,9 @@ font_render(FontObject* self, PyObject* args)
|
||||||
|
|
||||||
num_coords = PyObject_Length(axes);
|
num_coords = PyObject_Length(axes);
|
||||||
coords = malloc(2 * sizeof(coords));
|
coords = malloc(2 * sizeof(coords));
|
||||||
|
if (coords == NULL) {
|
||||||
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
for (i = 0; i < num_coords; i++) {
|
for (i = 0; i < num_coords; i++) {
|
||||||
item = PyList_GET_ITEM(axes, i);
|
item = PyList_GET_ITEM(axes, i);
|
||||||
if (PyFloat_Check(item))
|
if (PyFloat_Check(item))
|
||||||
|
@ -1015,6 +1019,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
else if (PyNumber_Check(item))
|
else if (PyNumber_Check(item))
|
||||||
coord = PyFloat_AsDouble(item);
|
coord = PyFloat_AsDouble(item);
|
||||||
else {
|
else {
|
||||||
|
free(coords);
|
||||||
PyErr_SetString(PyExc_TypeError, "list must contain numbers");
|
PyErr_SetString(PyExc_TypeError, "list must contain numbers");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1022,6 +1027,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
error = FT_Set_Var_Design_Coordinates(self->face, num_coords, coords);
|
error = FT_Set_Var_Design_Coordinates(self->face, num_coords, coords);
|
||||||
|
free(coords);
|
||||||
if (error)
|
if (error)
|
||||||
return geterror(error);
|
return geterror(error);
|
||||||
|
|
||||||
|
|
|
@ -503,9 +503,9 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
|
||||||
char* rawmode;
|
char* rawmode;
|
||||||
char* compname;
|
char* compname;
|
||||||
int fp;
|
int fp;
|
||||||
int ifdoffset;
|
uint32 ifdoffset;
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "sssii", &mode, &rawmode, &compname, &fp, &ifdoffset))
|
if (! PyArg_ParseTuple(args, "sssiI", &mode, &rawmode, &compname, &fp, &ifdoffset))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
TRACE(("new tiff decoder %s\n", compname));
|
TRACE(("new tiff decoder %s\n", compname));
|
||||||
|
|
23
src/encode.c
23
src/encode.c
|
@ -126,7 +126,7 @@ _encode(ImagingEncoderObject* encoder, PyObject* args)
|
||||||
|
|
||||||
Py_ssize_t bufsize = 16384;
|
Py_ssize_t bufsize = 16384;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|i", &bufsize))
|
if (!PyArg_ParseTuple(args, "|n", &bufsize))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
buf = PyBytes_FromStringAndSize(NULL, bufsize);
|
buf = PyBytes_FromStringAndSize(NULL, bufsize);
|
||||||
|
@ -180,7 +180,7 @@ _encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
|
||||||
Py_ssize_t fh;
|
Py_ssize_t fh;
|
||||||
Py_ssize_t bufsize = 16384;
|
Py_ssize_t bufsize = 16384;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i|i", &fh, &bufsize))
|
if (!PyArg_ParseTuple(args, "n|n", &fh, &bufsize))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Allocate an encoder buffer */
|
/* Allocate an encoder buffer */
|
||||||
|
@ -229,7 +229,7 @@ _setimage(ImagingEncoderObject* encoder, PyObject* args)
|
||||||
x0 = y0 = x1 = y1 = 0;
|
x0 = y0 = x1 = y1 = 0;
|
||||||
|
|
||||||
/* FIXME: should publish the ImagingType descriptor */
|
/* FIXME: should publish the ImagingType descriptor */
|
||||||
if (!PyArg_ParseTuple(args, "O|(iiii)", &op, &x0, &y0, &x1, &y1))
|
if (!PyArg_ParseTuple(args, "O|(nnnn)", &op, &x0, &y0, &x1, &y1))
|
||||||
return NULL;
|
return NULL;
|
||||||
im = PyImaging_AsImaging(op);
|
im = PyImaging_AsImaging(op);
|
||||||
if (!im)
|
if (!im)
|
||||||
|
@ -409,7 +409,7 @@ PyImaging_GifEncoderNew(PyObject* self, PyObject* args)
|
||||||
char *rawmode;
|
char *rawmode;
|
||||||
Py_ssize_t bits = 8;
|
Py_ssize_t bits = 8;
|
||||||
Py_ssize_t interlace = 0;
|
Py_ssize_t interlace = 0;
|
||||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits, &interlace))
|
if (!PyArg_ParseTuple(args, "ss|nn", &mode, &rawmode, &bits, &interlace))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
encoder = PyImaging_EncoderNew(sizeof(GIFENCODERSTATE));
|
encoder = PyImaging_EncoderNew(sizeof(GIFENCODERSTATE));
|
||||||
|
@ -441,7 +441,7 @@ PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
|
||||||
char *rawmode;
|
char *rawmode;
|
||||||
Py_ssize_t bits = 8;
|
Py_ssize_t bits = 8;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits)) {
|
if (!PyArg_ParseTuple(args, "ss|n", &mode, &rawmode, &bits)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +474,7 @@ PyImaging_RawEncoderNew(PyObject* self, PyObject* args)
|
||||||
Py_ssize_t stride = 0;
|
Py_ssize_t stride = 0;
|
||||||
Py_ssize_t ystep = 1;
|
Py_ssize_t ystep = 1;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &stride, &ystep))
|
if (!PyArg_ParseTuple(args, "ss|nn", &mode, &rawmode, &stride, &ystep))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
encoder = PyImaging_EncoderNew(0);
|
encoder = PyImaging_EncoderNew(0);
|
||||||
|
@ -506,7 +506,7 @@ PyImaging_TgaRleEncoderNew(PyObject* self, PyObject* args)
|
||||||
char *rawmode;
|
char *rawmode;
|
||||||
Py_ssize_t ystep = 1;
|
Py_ssize_t ystep = 1;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ss|i", &mode, &rawmode, &ystep))
|
if (!PyArg_ParseTuple(args, "ss|n", &mode, &rawmode, &ystep))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
encoder = PyImaging_EncoderNew(0);
|
encoder = PyImaging_EncoderNew(0);
|
||||||
|
@ -567,7 +567,7 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
|
||||||
Py_ssize_t compress_type = -1;
|
Py_ssize_t compress_type = -1;
|
||||||
char* dictionary = NULL;
|
char* dictionary = NULL;
|
||||||
Py_ssize_t dictionary_size = 0;
|
Py_ssize_t dictionary_size = 0;
|
||||||
if (!PyArg_ParseTuple(args, "ss|iii"PY_ARG_BYTES_LENGTH, &mode, &rawmode,
|
if (!PyArg_ParseTuple(args, "ss|nnn"PY_ARG_BYTES_LENGTH, &mode, &rawmode,
|
||||||
&optimize,
|
&optimize,
|
||||||
&compress_level, &compress_type,
|
&compress_level, &compress_type,
|
||||||
&dictionary, &dictionary_size))
|
&dictionary, &dictionary_size))
|
||||||
|
@ -650,7 +650,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
||||||
PyObject *item;
|
PyObject *item;
|
||||||
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "sssisOO", &mode, &rawmode, &compname, &fp, &filename, &tags, &types)) {
|
if (! PyArg_ParseTuple(args, "sssnsOO", &mode, &rawmode, &compname, &fp, &filename, &tags, &types)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,7 +1025,7 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
||||||
char* rawExif = NULL;
|
char* rawExif = NULL;
|
||||||
Py_ssize_t rawExifLen = 0;
|
Py_ssize_t rawExifLen = 0;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ss|iiiiiiiiO"PY_ARG_BYTES_LENGTH""PY_ARG_BYTES_LENGTH,
|
if (!PyArg_ParseTuple(args, "ss|nnnnnnnnO"PY_ARG_BYTES_LENGTH""PY_ARG_BYTES_LENGTH,
|
||||||
&mode, &rawmode, &quality,
|
&mode, &rawmode, &quality,
|
||||||
&progressive, &smooth, &optimize, &streamtype,
|
&progressive, &smooth, &optimize, &streamtype,
|
||||||
&xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size,
|
&xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size,
|
||||||
|
@ -1095,7 +1095,6 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* JPEG 2000 */
|
/* JPEG 2000 */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -1141,7 +1140,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
|
||||||
OPJ_CINEMA_MODE cine_mode;
|
OPJ_CINEMA_MODE cine_mode;
|
||||||
Py_ssize_t fd = -1;
|
Py_ssize_t fd = -1;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ss|OOOsOIOOOssi", &mode, &format,
|
if (!PyArg_ParseTuple(args, "ss|OOOsOnOOOssn", &mode, &format,
|
||||||
&offset, &tile_offset, &tile_size,
|
&offset, &tile_offset, &tile_size,
|
||||||
&quality_mode, &quality_layers, &num_resolutions,
|
&quality_mode, &quality_layers, &num_resolutions,
|
||||||
&cblk_size, &precinct_size,
|
&cblk_size, &precinct_size,
|
||||||
|
|
|
@ -251,6 +251,15 @@ ImagingPackRGB(UINT8* out, const UINT8* in, int pixels)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
/* RGB triplets */
|
/* 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++) {
|
for (; i < pixels-1; i++) {
|
||||||
((UINT32*)out)[0] = ((UINT32*)in)[i];
|
((UINT32*)out)[0] = ((UINT32*)in)[i];
|
||||||
out += 3;
|
out += 3;
|
||||||
|
@ -261,6 +270,7 @@ ImagingPackRGB(UINT8* out, const UINT8* in, int pixels)
|
||||||
out[2] = in[i*4+B];
|
out[2] = in[i*4+B];
|
||||||
out += 3;
|
out += 3;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -147,7 +147,7 @@ void _tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) {
|
||||||
(void) hdata; (void) base; (void) size;
|
(void) hdata; (void) base; (void) size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImagingLibTiffInit(ImagingCodecState state, int fp, int offset) {
|
int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) {
|
||||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||||
|
|
||||||
TRACE(("initing libtiff\n"));
|
TRACE(("initing libtiff\n"));
|
||||||
|
@ -194,6 +194,9 @@ int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
swap_line = (UINT32*)malloc(swap_line_size);
|
swap_line = (UINT32*)malloc(swap_line_size);
|
||||||
|
if (swap_line == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* For some reason the TIFFReadRGBATile() function chooses the
|
* For some reason the TIFFReadRGBATile() function chooses the
|
||||||
* lower left corner as the origin. Vertically mirror scanlines.
|
* lower left corner as the origin. Vertically mirror scanlines.
|
||||||
|
|
|
@ -43,7 +43,7 @@ typedef struct {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern int ImagingLibTiffInit(ImagingCodecState state, int fp, int offset);
|
extern int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset);
|
||||||
extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp);
|
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 ImagingLibTiffMergeFieldInfo(ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length);
|
||||||
extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...);
|
extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...);
|
||||||
|
|
|
@ -480,6 +480,16 @@ void
|
||||||
ImagingUnpackRGB(UINT8* _out, const UINT8* in, int pixels)
|
ImagingUnpackRGB(UINT8* _out, const UINT8* in, int pixels)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
#ifdef __sparc
|
||||||
|
/* SPARC CPUs cannot read integers from nonaligned addresses. */
|
||||||
|
for (; i < pixels; i++) {
|
||||||
|
_out[R] = in[0];
|
||||||
|
_out[G] = in[1];
|
||||||
|
_out[B] = in[2];
|
||||||
|
_out[A] = 255;
|
||||||
|
_out += 4; in += 3;
|
||||||
|
}
|
||||||
|
#else
|
||||||
UINT32* out = (UINT32*) _out;
|
UINT32* out = (UINT32*) _out;
|
||||||
/* RGB triplets */
|
/* RGB triplets */
|
||||||
for (; i < pixels-1; i++) {
|
for (; i < pixels-1; i++) {
|
||||||
|
@ -490,6 +500,7 @@ ImagingUnpackRGB(UINT8* _out, const UINT8* in, int pixels)
|
||||||
out[i] = MAKE_UINT32(in[0], in[1], in[2], 255);
|
out[i] = MAKE_UINT32(in[0], in[1], in[2], 255);
|
||||||
in += 3;
|
in += 3;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1085,22 +1096,44 @@ static void
|
||||||
copy4skip1(UINT8* _out, const UINT8* in, int pixels)
|
copy4skip1(UINT8* _out, const UINT8* in, int pixels)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
#ifdef __sparc
|
||||||
|
/* SPARC CPUs cannot read integers from nonaligned addresses. */
|
||||||
|
for (i = 0; i < pixels; i++) {
|
||||||
|
_out[0] = in[0];
|
||||||
|
_out[1] = in[1];
|
||||||
|
_out[2] = in[2];
|
||||||
|
_out[3] = in[3];
|
||||||
|
_out += 4; in += 5;
|
||||||
|
}
|
||||||
|
#else
|
||||||
UINT32* out = (UINT32*) _out;
|
UINT32* out = (UINT32*) _out;
|
||||||
for (i = 0; i < pixels; i++) {
|
for (i = 0; i < pixels; i++) {
|
||||||
out[i] = *(UINT32*)&in[0];
|
out[i] = *(UINT32*)&in[0];
|
||||||
in += 5;
|
in += 5;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
copy4skip2(UINT8* _out, const UINT8* in, int pixels)
|
copy4skip2(UINT8* _out, const UINT8* in, int pixels)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
#ifdef __sparc
|
||||||
|
/* SPARC CPUs cannot read integers from nonaligned addresses. */
|
||||||
|
for (i = 0; i < pixels; i++) {
|
||||||
|
_out[0] = in[0];
|
||||||
|
_out[1] = in[1];
|
||||||
|
_out[2] = in[2];
|
||||||
|
_out[3] = in[3];
|
||||||
|
_out += 4; in += 6;
|
||||||
|
}
|
||||||
|
#else
|
||||||
UINT32* out = (UINT32*) _out;
|
UINT32* out = (UINT32*) _out;
|
||||||
for (i = 0; i < pixels; i++) {
|
for (i = 0; i < pixels; i++) {
|
||||||
out[i] = *(UINT32*)&in[0];
|
out[i] = *(UINT32*)&in[0];
|
||||||
in += 6;
|
in += 6;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -133,8 +133,8 @@ PyPath_Flatten(PyObject* data, double **pxy)
|
||||||
/* Assume the buffer contains floats */
|
/* Assume the buffer contains floats */
|
||||||
Py_buffer buffer;
|
Py_buffer buffer;
|
||||||
if (PyImaging_GetBuffer(data, &buffer) == 0) {
|
if (PyImaging_GetBuffer(data, &buffer) == 0) {
|
||||||
int n = buffer.len / (2 * sizeof(float));
|
|
||||||
float *ptr = (float*) buffer.buf;
|
float *ptr = (float*) buffer.buf;
|
||||||
|
n = buffer.len / (2 * sizeof(float));
|
||||||
xy = alloc_array(n);
|
xy = alloc_array(n);
|
||||||
if (!xy)
|
if (!xy)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user