mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 16:07:30 +03:00 
			
		
		
		
	Merge branch 'main' into int_def
This commit is contained in:
		
						commit
						68edbbca94
					
				|  | @ -22,7 +22,8 @@ set -e | |||
| if [[ $(uname) != CYGWIN* ]]; then | ||||
|     sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\ | ||||
|                              ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\ | ||||
|                              cmake meson imagemagick libharfbuzz-dev libfribidi-dev | ||||
|                              cmake meson imagemagick libharfbuzz-dev libfribidi-dev\ | ||||
|                              sway wl-clipboard | ||||
| fi | ||||
| 
 | ||||
| python3 -m pip install --upgrade pip | ||||
|  | @ -41,7 +42,7 @@ if [[ $(uname) != CYGWIN* ]]; then | |||
|     if ! [ "$GHA_PYTHON_VERSION" == "3.12-dev" ]; then python3 -m pip install numpy ; fi | ||||
| 
 | ||||
|     # PyQt6 doesn't support PyPy3 | ||||
|     if [[ $GHA_PYTHON_VERSION == 3.* ]]; then | ||||
|     if [[ "$GHA_PYTHON_VERSION" != "3.12-dev" && $GHA_PYTHON_VERSION == 3.* ]]; then | ||||
|         sudo apt-get -qq install libegl1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxkbcommon-x11-0 | ||||
|         python3 -m pip install pyqt6 | ||||
|     fi | ||||
|  |  | |||
|  | @ -13,10 +13,6 @@ indent_style = space | |||
| 
 | ||||
| trim_trailing_whitespace = true | ||||
| 
 | ||||
| [*.rst] | ||||
| # Four-space indentation | ||||
| indent_size = 4 | ||||
| 
 | ||||
| [*.yml] | ||||
| # Two-space indentation | ||||
| indent_size = 2 | ||||
|  |  | |||
							
								
								
									
										1
									
								
								.github/workflows/test-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/test-docker.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -39,6 +39,7 @@ jobs: | |||
|           centos-stream-8-amd64, | ||||
|           centos-stream-9-amd64, | ||||
|           debian-11-bullseye-x86, | ||||
|           debian-12-bookworm-x86, | ||||
|           fedora-37-amd64, | ||||
|           fedora-38-amd64, | ||||
|           gentoo, | ||||
|  |  | |||
							
								
								
									
										4
									
								
								.github/workflows/test-windows.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/test-windows.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -65,8 +65,8 @@ jobs: | |||
|     - name: Print build system information | ||||
|       run: python3 .github/workflows/system-info.py | ||||
| 
 | ||||
|     - name: python3 -m pip install wheel pytest pytest-cov pytest-timeout defusedxml | ||||
|       run: python3 -m pip install wheel pytest pytest-cov pytest-timeout defusedxml | ||||
|     - name: python3 -m pip install setuptools wheel pytest pytest-cov pytest-timeout defusedxml | ||||
|       run: python3 -m pip install setuptools wheel pytest pytest-cov pytest-timeout defusedxml | ||||
| 
 | ||||
|     - name: Install dependencies | ||||
|       id: install | ||||
|  |  | |||
							
								
								
									
										4
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -84,7 +84,9 @@ jobs: | |||
|           python3 -m pip install pytest-reverse | ||||
|         fi | ||||
|         if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then | ||||
|           xvfb-run -s '-screen 0 1024x768x24' .ci/test.sh | ||||
|           xvfb-run -s '-screen 0 1024x768x24' sway& | ||||
|           export WAYLAND_DISPLAY=wayland-1 | ||||
|           .ci/test.sh | ||||
|         else | ||||
|           .ci/test.sh | ||||
|         fi | ||||
|  |  | |||
|  | @ -4,9 +4,6 @@ repos: | |||
|     hooks: | ||||
|       - id: black | ||||
|         args: [--target-version=py38] | ||||
|         # Only .py files, until https://github.com/psf/black/issues/402 resolved | ||||
|         files: \.py$ | ||||
|         types: [] | ||||
| 
 | ||||
|   - repo: https://github.com/PyCQA/isort | ||||
|     rev: 5.12.0 | ||||
|  |  | |||
							
								
								
									
										24
									
								
								CHANGES.rst
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								CHANGES.rst
									
									
									
									
									
								
							|  | @ -5,6 +5,30 @@ Changelog (Pillow) | |||
| 10.0.0 (unreleased) | ||||
| ------------------- | ||||
| 
 | ||||
| - Fixed combining single duration across duplicate APNG frames #7146 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - Remove temporary file when error is raised #7148 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - Do not use temporary file when grabbing clipboard on Linux #7200 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - If the clipboard fails to open on Windows, wait and try again #7141 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - Fixed saving multiple 1 mode frames to GIF #7181 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - Replaced absolute PIL import with relative import #7173 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - Replaced deprecated Py_FileSystemDefaultEncoding for Python >= 3.12 #7192 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - Improved wl-paste mimetype handling in ImageGrab #7094 | ||||
|   [rrcgat, radarhere] | ||||
| 
 | ||||
| - Added _repr_jpeg_() for IPython display_jpeg #7135 | ||||
|   [n3011, radarhere, nulano] | ||||
| 
 | ||||
|  |  | |||
|  | @ -447,6 +447,17 @@ def test_apng_save_duration_loop(tmp_path): | |||
|         assert im.info.get("duration") == 750 | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save_duplicate_duration(tmp_path): | ||||
|     test_file = str(tmp_path / "temp.png") | ||||
|     frame = Image.new("RGB", (1, 1)) | ||||
| 
 | ||||
|     # Test a single duration is correctly combined across duplicate frames | ||||
|     frame.save(test_file, save_all=True, append_images=[frame, frame], duration=500) | ||||
|     with Image.open(test_file) as im: | ||||
|         assert im.n_frames == 1 | ||||
|         assert im.info.get("duration") == 1500 | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save_disposal(tmp_path): | ||||
|     test_file = str(tmp_path / "temp.png") | ||||
|     size = (128, 64) | ||||
|  |  | |||
|  | @ -252,6 +252,19 @@ def test_roundtrip_save_all(tmp_path): | |||
|         assert reread.n_frames == 5 | ||||
| 
 | ||||
| 
 | ||||
| def test_roundtrip_save_all_1(tmp_path): | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = Image.new("1", (1, 1)) | ||||
|     im2 = Image.new("1", (1, 1), 1) | ||||
|     im.save(out, save_all=True, append_images=[im2]) | ||||
| 
 | ||||
|     with Image.open(out) as reloaded: | ||||
|         assert reloaded.getpixel((0, 0)) == 0 | ||||
| 
 | ||||
|         reloaded.seek(1) | ||||
|         assert reloaded.getpixel((0, 0)) == 255 | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize( | ||||
|     "path, mode", | ||||
|     ( | ||||
|  |  | |||
|  | @ -96,10 +96,17 @@ class TestFileTiff: | |||
| 
 | ||||
|             assert_image_similar_tofile(im, "Tests/images/pil136.png", 1) | ||||
| 
 | ||||
|     def test_bigtiff(self): | ||||
|     def test_bigtiff(self, tmp_path): | ||||
|         with Image.open("Tests/images/hopper_bigtiff.tif") as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/hopper.tif") | ||||
| 
 | ||||
|         with Image.open("Tests/images/hopper_bigtiff.tif") as im: | ||||
|             # multistrip support not yet implemented | ||||
|             del im.tag_v2[273] | ||||
| 
 | ||||
|             outfile = str(tmp_path / "temp.tif") | ||||
|             im.save(outfile, save_all=True, append_images=[im], tiffinfo=im.tag_v2) | ||||
| 
 | ||||
|     def test_set_legacy_api(self): | ||||
|         ifd = TiffImagePlugin.ImageFileDirectory_v2() | ||||
|         with pytest.raises(Exception) as e: | ||||
|  |  | |||
|  | @ -32,6 +32,14 @@ def test_putpalette(): | |||
|     with pytest.raises(ValueError): | ||||
|         palette("YCbCr") | ||||
| 
 | ||||
|     with Image.open("Tests/images/hopper_gray.jpg") as im: | ||||
|         assert im.mode == "L" | ||||
|         im.putpalette(list(range(256)) * 3) | ||||
| 
 | ||||
|     with Image.open("Tests/images/la.tga") as im: | ||||
|         assert im.mode == "LA" | ||||
|         im.putpalette(list(range(256)) * 3) | ||||
| 
 | ||||
| 
 | ||||
| def test_imagepalette(): | ||||
|     im = hopper("P") | ||||
|  |  | |||
|  | @ -463,6 +463,11 @@ def test_default_font(): | |||
|     assert_image_equal_tofile(im, "Tests/images/default_font.png") | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("mode", (None, "1", "RGBA")) | ||||
| def test_getbbox(font, mode): | ||||
|     assert (0, 4, 12, 16) == font.getbbox("A", mode) | ||||
| 
 | ||||
| 
 | ||||
| def test_getbbox_empty(font): | ||||
|     # issue #2614, should not crash. | ||||
|     assert (0, 0, 0, 0) == font.getbbox("") | ||||
|  |  | |||
|  | @ -98,3 +98,18 @@ $ms = new-object System.IO.MemoryStream(, $bytes) | |||
| 
 | ||||
|         im = ImageGrab.grabclipboard() | ||||
|         assert_image_equal_tofile(im, "Tests/images/hopper.png") | ||||
| 
 | ||||
|     @pytest.mark.skipif( | ||||
|         ( | ||||
|             sys.platform != "linux" | ||||
|             or not all(shutil.which(cmd) for cmd in ("wl-paste", "wl-copy")) | ||||
|         ), | ||||
|         reason="Linux with wl-clipboard only", | ||||
|     ) | ||||
|     @pytest.mark.parametrize("ext", ("gif", "png", "ico")) | ||||
|     def test_grabclipboard_wl_clipboard(self, ext): | ||||
|         image_path = "Tests/images/hopper." + ext | ||||
|         with open(image_path, "rb") as fp: | ||||
|             subprocess.call(["wl-copy"], stdin=fp) | ||||
|         im = ImageGrab.grabclipboard() | ||||
|         assert_image_equal_tofile(im, image_path) | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| # Documentation: https://docs.codecov.io/docs/codecov-yaml | ||||
| # Documentation: https://docs.codecov.com/docs/codecov-yaml | ||||
| 
 | ||||
| codecov: | ||||
|   # Avoid "Missing base report" due to committing CHANGES.rst with "[CI skip]" | ||||
|   # https://github.com/codecov/support/issues/363 | ||||
|   # https://docs.codecov.io/docs/comparing-commits | ||||
|   # https://docs.codecov.com/docs/comparing-commits | ||||
|   allow_coverage_offsets: true | ||||
| 
 | ||||
| comment: false | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| from livereload.compiler import shell | ||||
| from livereload.task import Task | ||||
| 
 | ||||
| Task.add('*.rst', shell('make html')) | ||||
| Task.add('*/*.rst', shell('make html')) | ||||
| Task.add('Makefile', shell('make html')) | ||||
| Task.add('conf.py', shell('make html')) | ||||
| Task.add("*.rst", shell("make html")) | ||||
| Task.add("*/*.rst", shell("make html")) | ||||
| Task.add("Makefile", shell("make html")) | ||||
| Task.add("conf.py", shell("make html")) | ||||
|  |  | |||
|  | @ -95,9 +95,8 @@ in the upper left corner. Note that the coordinates refer to the implied pixel | |||
| corners; the centre of a pixel addressed as (0, 0) actually lies at (0.5, 0.5). | ||||
| 
 | ||||
| Coordinates are usually passed to the library as 2-tuples (x, y). Rectangles | ||||
| are represented as 4-tuples, with the upper left corner given first. For | ||||
| example, a rectangle covering all of an 800x600 pixel image is written as (0, | ||||
| 0, 800, 600). | ||||
| are represented as 4-tuples, (x1, y1, x2, y2), with the upper left corner given | ||||
| first. | ||||
| 
 | ||||
| Palette | ||||
| ------- | ||||
|  |  | |||
|  | @ -448,6 +448,8 @@ These platforms are built and tested for every change. | |||
| +----------------------------------+----------------------------+---------------------+ | ||||
| | Debian 11 Bullseye               | 3.9                        | x86                 | | ||||
| +----------------------------------+----------------------------+---------------------+ | ||||
| | Debian 12 Bookworm               | 3.11                       | x86                 | | ||||
| +----------------------------------+----------------------------+---------------------+ | ||||
| | Fedora 37                        | 3.11                       | x86-64              | | ||||
| +----------------------------------+----------------------------+---------------------+ | ||||
| | Fedora 38                        | 3.11                       | x86-64              | | ||||
|  |  | |||
|  | @ -134,6 +134,13 @@ def Ghostscript(tile, size, fp, scale=1, transparency=False): | |||
| 
 | ||||
|     if gs_windows_binary is not None: | ||||
|         if not gs_windows_binary: | ||||
|             try: | ||||
|                 os.unlink(outfile) | ||||
|                 if infile_temp: | ||||
|                     os.unlink(infile_temp) | ||||
|             except OSError: | ||||
|                 pass | ||||
| 
 | ||||
|             msg = "Unable to locate Ghostscript on paths" | ||||
|             raise OSError(msg) | ||||
|         command[0] = gs_windows_binary | ||||
|  | @ -354,7 +361,6 @@ class EpsImageFile(ImageFile.ImageFile): | |||
|         check_required_header_comments() | ||||
| 
 | ||||
|         if not self._size: | ||||
|             self._size = 1, 1  # errors if this isn't set. why (1,1)? | ||||
|             msg = "cannot determine EPS bounding box" | ||||
|             raise OSError(msg) | ||||
| 
 | ||||
|  |  | |||
|  | @ -879,7 +879,7 @@ def _get_palette_bytes(im): | |||
|     :param im: Image object | ||||
|     :returns: Bytes, len<=768 suitable for inclusion in gif header | ||||
|     """ | ||||
|     return im.palette.palette | ||||
|     return im.palette.palette if im.palette else b"" | ||||
| 
 | ||||
| 
 | ||||
| def _get_background(im, info_background): | ||||
|  |  | |||
|  | @ -22,11 +22,11 @@ import os | |||
| import struct | ||||
| import sys | ||||
| 
 | ||||
| from PIL import Image, ImageFile, PngImagePlugin, features | ||||
| from . import Image, ImageFile, PngImagePlugin, features | ||||
| 
 | ||||
| enable_jpeg2k = features.check_codec("jpg_2000") | ||||
| if enable_jpeg2k: | ||||
|     from PIL import Jpeg2KImagePlugin | ||||
|     from . import Jpeg2KImagePlugin | ||||
| 
 | ||||
| MAGIC = b"icns" | ||||
| HEADERSIZE = 8 | ||||
|  |  | |||
|  | @ -1254,7 +1254,7 @@ class Image: | |||
|         if ymargin is None: | ||||
|             ymargin = xmargin | ||||
|         self.load() | ||||
|         return self._new(self.im.expand(xmargin, ymargin, 0)) | ||||
|         return self._new(self.im.expand(xmargin, ymargin)) | ||||
| 
 | ||||
|     def filter(self, filter): | ||||
|         """ | ||||
|  |  | |||
|  | @ -18,10 +18,10 @@ | |||
| import sys | ||||
| from enum import IntEnum | ||||
| 
 | ||||
| from PIL import Image | ||||
| from . import Image | ||||
| 
 | ||||
| try: | ||||
|     from PIL import _imagingcms | ||||
|     from . import _imagingcms | ||||
| except ImportError as ex: | ||||
|     # Allow error import for doc purposes, but error out when accessing | ||||
|     # anything in core. | ||||
|  | @ -271,7 +271,7 @@ def get_display_profile(handle=None): | |||
|     if sys.platform != "win32": | ||||
|         return None | ||||
| 
 | ||||
|     from PIL import ImageWin | ||||
|     from . import ImageWin | ||||
| 
 | ||||
|     if isinstance(handle, ImageWin.HDC): | ||||
|         profile = core.get_display_profile_win32(handle, 1) | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ class BuiltinFilter(MultibandFilter): | |||
| 
 | ||||
| class Kernel(BuiltinFilter): | ||||
|     """ | ||||
|     Create a convolution kernel.  The current version only | ||||
|     Create a convolution kernel. The current version only | ||||
|     supports 3x3 and 5x5 integer and floating point kernels. | ||||
| 
 | ||||
|     In the current version, kernels can only be applied to | ||||
|  | @ -43,9 +43,10 @@ class Kernel(BuiltinFilter): | |||
| 
 | ||||
|     :param size: Kernel size, given as (width, height). In the current | ||||
|                     version, this must be (3,3) or (5,5). | ||||
|     :param kernel: A sequence containing kernel weights. | ||||
|     :param kernel: A sequence containing kernel weights. The kernel will | ||||
|                    be flipped vertically before being applied to the image. | ||||
|     :param scale: Scale factor. If given, the result for each pixel is | ||||
|                     divided by this value.  The default is the sum of the | ||||
|                     divided by this value. The default is the sum of the | ||||
|                     kernel weights. | ||||
|     :param offset: Offset. If given, this value is added to the result, | ||||
|                     after it has been divided by the scale factor. | ||||
|  |  | |||
|  | @ -26,7 +26,6 @@ | |||
| # | ||||
| 
 | ||||
| import base64 | ||||
| import math | ||||
| import os | ||||
| import sys | ||||
| import warnings | ||||
|  | @ -226,10 +225,6 @@ class FreeTypeFont: | |||
|         path, size, index, encoding, layout_engine = state | ||||
|         self.__init__(path, size, index, encoding, layout_engine) | ||||
| 
 | ||||
|     def _multiline_split(self, text): | ||||
|         split_character = "\n" if isinstance(text, str) else b"\n" | ||||
|         return text.split(split_character) | ||||
| 
 | ||||
|     def getname(self): | ||||
|         """ | ||||
|         :return: A tuple of the font family (e.g. Helvetica) and the font style | ||||
|  | @ -551,28 +546,23 @@ class FreeTypeFont: | |||
|                  :py:mod:`PIL.Image.core` interface module, and the text offset, the | ||||
|                  gap between the starting coordinate and the first marking | ||||
|         """ | ||||
|         size, offset = self.font.getsize( | ||||
|             text, mode, direction, features, language, anchor | ||||
|         ) | ||||
|         if start is None: | ||||
|             start = (0, 0) | ||||
|         size = tuple(math.ceil(size[i] + stroke_width * 2 + start[i]) for i in range(2)) | ||||
|         offset = offset[0] - stroke_width, offset[1] - stroke_width | ||||
|         im, size, offset = self.font.render( | ||||
|             text, | ||||
|             Image.core.fill, | ||||
|             mode, | ||||
|             direction, | ||||
|             features, | ||||
|             language, | ||||
|             stroke_width, | ||||
|             anchor, | ||||
|             ink, | ||||
|             start[0], | ||||
|             start[1], | ||||
|             Image.MAX_IMAGE_PIXELS, | ||||
|         ) | ||||
|         Image._decompression_bomb_check(size) | ||||
|         im = Image.core.fill("RGBA" if mode == "RGBA" else "L", size, 0) | ||||
|         if min(size): | ||||
|             self.font.render( | ||||
|                 text, | ||||
|                 im.id, | ||||
|                 mode, | ||||
|                 direction, | ||||
|                 features, | ||||
|                 language, | ||||
|                 stroke_width, | ||||
|                 ink, | ||||
|                 start[0], | ||||
|                 start[1], | ||||
|             ) | ||||
|         return im, offset | ||||
| 
 | ||||
|     def font_variant( | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| # See the README file for information on usage and redistribution. | ||||
| # | ||||
| 
 | ||||
| import io | ||||
| import os | ||||
| import shutil | ||||
| import subprocess | ||||
|  | @ -128,8 +129,6 @@ def grabclipboard(): | |||
|                 files = data[o:].decode("mbcs").split("\0") | ||||
|             return files[: files.index("")] | ||||
|         if isinstance(data, bytes): | ||||
|             import io | ||||
| 
 | ||||
|             data = io.BytesIO(data) | ||||
|             if fmt == "png": | ||||
|                 from . import PngImagePlugin | ||||
|  | @ -142,19 +141,29 @@ def grabclipboard(): | |||
|         return None | ||||
|     else: | ||||
|         if shutil.which("wl-paste"): | ||||
|             output = subprocess.check_output(["wl-paste", "-l"]).decode() | ||||
|             mimetypes = output.splitlines() | ||||
|             if "image/png" in mimetypes: | ||||
|                 mimetype = "image/png" | ||||
|             elif mimetypes: | ||||
|                 mimetype = mimetypes[0] | ||||
|             else: | ||||
|                 mimetype = None | ||||
| 
 | ||||
|             args = ["wl-paste"] | ||||
|             if mimetype: | ||||
|                 args.extend(["-t", mimetype]) | ||||
|         elif shutil.which("xclip"): | ||||
|             args = ["xclip", "-selection", "clipboard", "-t", "image/png", "-o"] | ||||
|         else: | ||||
|             msg = "wl-paste or xclip is required for ImageGrab.grabclipboard() on Linux" | ||||
|             raise NotImplementedError(msg) | ||||
|         fh, filepath = tempfile.mkstemp() | ||||
|         err = subprocess.run(args, stdout=fh, stderr=subprocess.PIPE).stderr | ||||
|         os.close(fh) | ||||
|         p = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||||
|         err = p.stderr | ||||
|         if err: | ||||
|             msg = f"{args[0]} error: {err.strip().decode()}" | ||||
|             raise ChildProcessError(msg) | ||||
|         im = Image.open(filepath) | ||||
|         data = io.BytesIO(p.stdout) | ||||
|         im = Image.open(data) | ||||
|         im.load() | ||||
|         os.unlink(filepath) | ||||
|         return im | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ import subprocess | |||
| import sys | ||||
| from shlex import quote | ||||
| 
 | ||||
| from PIL import Image | ||||
| from . import Image | ||||
| 
 | ||||
| _viewers = [] | ||||
| 
 | ||||
|  |  | |||
|  | @ -457,6 +457,11 @@ class JpegImageFile(ImageFile.ImageFile): | |||
|         if os.path.exists(self.filename): | ||||
|             subprocess.check_call(["djpeg", "-outfile", path, self.filename]) | ||||
|         else: | ||||
|             try: | ||||
|                 os.unlink(path) | ||||
|             except OSError: | ||||
|                 pass | ||||
| 
 | ||||
|             msg = "Invalid Filename" | ||||
|             raise ValueError(msg) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1146,11 +1146,14 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images) | |||
|                     and prev_disposal == encoderinfo.get("disposal") | ||||
|                     and prev_blend == encoderinfo.get("blend") | ||||
|                 ): | ||||
|                     if isinstance(duration, (list, tuple)): | ||||
|                         previous["encoderinfo"]["duration"] += encoderinfo["duration"] | ||||
|                     previous["encoderinfo"]["duration"] += encoderinfo.get( | ||||
|                         "duration", duration | ||||
|                     ) | ||||
|                     continue | ||||
|             else: | ||||
|                 bbox = None | ||||
|             if "duration" not in encoderinfo: | ||||
|                 encoderinfo["duration"] = duration | ||||
|             im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo}) | ||||
| 
 | ||||
|     # animation control | ||||
|  | @ -1175,7 +1178,7 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images) | |||
|             im_frame = im_frame.crop(bbox) | ||||
|         size = im_frame.size | ||||
|         encoderinfo = frame_data["encoderinfo"] | ||||
|         frame_duration = int(round(encoderinfo.get("duration", duration))) | ||||
|         frame_duration = int(round(encoderinfo["duration"])) | ||||
|         frame_disposal = encoderinfo.get("disposal", disposal) | ||||
|         frame_blend = encoderinfo.get("blend", blend) | ||||
|         # frame control | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ import os | |||
| import struct | ||||
| import sys | ||||
| 
 | ||||
| from PIL import Image, ImageFile | ||||
| from . import Image, ImageFile | ||||
| 
 | ||||
| 
 | ||||
| def isInt(f): | ||||
|  | @ -191,7 +191,7 @@ class SpiderImageFile(ImageFile.ImageFile): | |||
| 
 | ||||
|     # returns a ImageTk.PhotoImage object, after rescaling to 0..255 | ||||
|     def tkPhotoImage(self): | ||||
|         from PIL import ImageTk | ||||
|         from . import ImageTk | ||||
| 
 | ||||
|         return ImageTk.PhotoImage(self.convert2byte(), palette=256) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1894,6 +1894,10 @@ class AppendingTiffWriter: | |||
|         8,  # srational | ||||
|         4,  # float | ||||
|         8,  # double | ||||
|         4,  # ifd | ||||
|         2,  # unicode | ||||
|         4,  # complex | ||||
|         8,  # long8 | ||||
|     ] | ||||
| 
 | ||||
|     #    StripOffsets = 273 | ||||
|  |  | |||
|  | @ -1027,12 +1027,11 @@ _crop(ImagingObject *self, PyObject *args) { | |||
| static PyObject * | ||||
| _expand_image(ImagingObject *self, PyObject *args) { | ||||
|     int x, y; | ||||
|     int mode = 0; | ||||
|     if (!PyArg_ParseTuple(args, "ii|i", &x, &y, &mode)) { | ||||
|     if (!PyArg_ParseTuple(args, "ii", &x, &y)) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return PyImagingNew(ImagingExpand(self->image, x, y, mode)); | ||||
|     return PyImagingNew(ImagingExpand(self->image, x, y)); | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
|  |  | |||
							
								
								
									
										243
									
								
								src/_imagingft.c
									
									
									
									
									
								
							
							
						
						
									
										243
									
								
								src/_imagingft.c
									
									
									
									
									
								
							|  | @ -132,6 +132,27 @@ getfont(PyObject *self_, PyObject *args, PyObject *kw) { | |||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
| #if PY_MAJOR_VERSION > 3 || PY_MINOR_VERSION > 11 | ||||
|     PyConfig config; | ||||
|     PyConfig_InitPythonConfig(&config); | ||||
|     if (!PyArg_ParseTupleAndKeywords( | ||||
|             args, | ||||
|             kw, | ||||
|             "etf|nsy#n", | ||||
|             kwlist, | ||||
|             config.filesystem_encoding, | ||||
|             &filename, | ||||
|             &size, | ||||
|             &index, | ||||
|             &encoding, | ||||
|             &font_bytes, | ||||
|             &font_bytes_size, | ||||
|             &layout_engine)) { | ||||
|         PyConfig_Clear(&config); | ||||
|         return NULL; | ||||
|     } | ||||
|     PyConfig_Clear(&config); | ||||
| #else | ||||
|     if (!PyArg_ParseTupleAndKeywords( | ||||
|             args, | ||||
|             kw, | ||||
|  | @ -147,6 +168,7 @@ getfont(PyObject *self_, PyObject *args, PyObject *kw) { | |||
|             &layout_engine)) { | ||||
|         return NULL; | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     self = PyObject_New(FontObject, &Font_Type); | ||||
|     if (!self) { | ||||
|  | @ -232,9 +254,7 @@ text_layout_raqm( | |||
|     const char *dir, | ||||
|     PyObject *features, | ||||
|     const char *lang, | ||||
|     GlyphInfo **glyph_info, | ||||
|     int mask, | ||||
|     int color) { | ||||
|     GlyphInfo **glyph_info) { | ||||
|     size_t i = 0, count = 0, start = 0; | ||||
|     raqm_t *rq; | ||||
|     raqm_glyph_t *glyphs = NULL; | ||||
|  | @ -471,7 +491,7 @@ text_layout( | |||
| #ifdef HAVE_RAQM | ||||
|     if (have_raqm && self->layout_engine == LAYOUT_RAQM) { | ||||
|         count = text_layout_raqm( | ||||
|             string, self, dir, features, lang, glyph_info,  mask, color); | ||||
|             string, self, dir, features, lang, glyph_info); | ||||
|     } else | ||||
| #endif | ||||
|     { | ||||
|  | @ -529,73 +549,25 @@ font_getlength(FontObject *self, PyObject *args) { | |||
|     return PyLong_FromLong(length); | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| font_getsize(FontObject *self, PyObject *args) { | ||||
| static int | ||||
| bounding_box_and_anchors(FT_Face face, const char *anchor, int horizontal_dir, GlyphInfo *glyph_info, size_t count, int load_flags, int *width, int *height, int *x_offset, int *y_offset) { | ||||
|     int position; /* pen position along primary axis, in 26.6 precision */ | ||||
|     int advanced; /* pen position along primary axis, in pixels */ | ||||
|     int px, py;   /* position of current glyph, in pixels */ | ||||
|     int x_min, x_max, y_min, y_max; /* text bounding box, in pixels */ | ||||
|     int x_anchor, y_anchor;         /* offset of point drawn at (0, 0), in pixels */ | ||||
|     int load_flags;                 /* FreeType load_flags parameter */ | ||||
|     int error; | ||||
|     FT_Face face; | ||||
|     FT_Glyph glyph; | ||||
|     FT_BBox bbox;                 /* glyph bounding box */ | ||||
|     GlyphInfo *glyph_info = NULL; /* computed text layout */ | ||||
|     size_t i, count;              /* glyph_info index and length */ | ||||
|     int horizontal_dir;           /* is primary axis horizontal? */ | ||||
|     int mask = 0;                 /* is FT_LOAD_TARGET_MONO enabled? */ | ||||
|     int color = 0;                /* is FT_LOAD_COLOR enabled? */ | ||||
|     const char *mode = NULL; | ||||
|     const char *dir = NULL; | ||||
|     const char *lang = NULL; | ||||
|     const char *anchor = NULL; | ||||
|     PyObject *features = Py_None; | ||||
|     PyObject *string; | ||||
| 
 | ||||
|     /* calculate size and bearing for a given string */ | ||||
| 
 | ||||
|     if (!PyArg_ParseTuple( | ||||
|             args, "O|zzOzz:getsize", &string, &mode, &dir, &features, &lang, &anchor)) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1; | ||||
| 
 | ||||
|     mask = mode && strcmp(mode, "1") == 0; | ||||
|     color = mode && strcmp(mode, "RGBA") == 0; | ||||
| 
 | ||||
|     if (anchor == NULL) { | ||||
|         anchor = horizontal_dir ? "la" : "lt"; | ||||
|     } | ||||
|     if (strlen(anchor) != 2) { | ||||
|         goto bad_anchor; | ||||
|     } | ||||
| 
 | ||||
|     count = text_layout(string, self, dir, features, lang, &glyph_info, mask, color); | ||||
|     if (PyErr_Occurred()) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     load_flags = FT_LOAD_DEFAULT; | ||||
|     if (mask) { | ||||
|         load_flags |= FT_LOAD_TARGET_MONO; | ||||
|     } | ||||
|     if (color) { | ||||
|         load_flags |= FT_LOAD_COLOR; | ||||
|     } | ||||
| 
 | ||||
|     FT_BBox bbox;                   /* glyph bounding box */ | ||||
|     size_t i;                       /* glyph_info index */ | ||||
|     /*
 | ||||
|      * text bounds are given by: | ||||
|      *   - bounding boxes of individual glyphs | ||||
|      *   - pen line, i.e. 0 to `advanced` along primary axis | ||||
|      *     this means point (0, 0) is part of the text bounding box | ||||
|      */ | ||||
|     face = NULL; | ||||
|     position = x_min = x_max = y_min = y_max = 0; | ||||
|     for (i = 0; i < count; i++) { | ||||
|         face = self->face; | ||||
| 
 | ||||
|         if (horizontal_dir) { | ||||
|             px = PIXEL(position + glyph_info[i].x_offset); | ||||
|             py = PIXEL(glyph_info[i].y_offset); | ||||
|  | @ -618,12 +590,14 @@ font_getsize(FontObject *self, PyObject *args) { | |||
| 
 | ||||
|         error = FT_Load_Glyph(face, glyph_info[i].index, load_flags); | ||||
|         if (error) { | ||||
|             return geterror(error); | ||||
|             geterror(error); | ||||
|             return 1; | ||||
|         } | ||||
| 
 | ||||
|         error = FT_Get_Glyph(face->glyph, &glyph); | ||||
|         if (error) { | ||||
|             return geterror(error); | ||||
|             geterror(error); | ||||
|             return 1; | ||||
|         } | ||||
| 
 | ||||
|         FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox); | ||||
|  | @ -647,13 +621,15 @@ font_getsize(FontObject *self, PyObject *args) { | |||
|         FT_Done_Glyph(glyph); | ||||
|     } | ||||
| 
 | ||||
|     if (glyph_info) { | ||||
|         PyMem_Free(glyph_info); | ||||
|         glyph_info = NULL; | ||||
|     if (anchor == NULL) { | ||||
|         anchor = horizontal_dir ? "la" : "lt"; | ||||
|     } | ||||
|     if (strlen(anchor) != 2) { | ||||
|         goto bad_anchor; | ||||
|     } | ||||
| 
 | ||||
|     x_anchor = y_anchor = 0; | ||||
|     if (face) { | ||||
|     if (count) { | ||||
|         if (horizontal_dir) { | ||||
|             switch (anchor[0]) { | ||||
|                 case 'l':  // left
 | ||||
|  | @ -671,15 +647,15 @@ font_getsize(FontObject *self, PyObject *args) { | |||
|             } | ||||
|             switch (anchor[1]) { | ||||
|                 case 'a':  // ascender
 | ||||
|                     y_anchor = PIXEL(self->face->size->metrics.ascender); | ||||
|                     y_anchor = PIXEL(face->size->metrics.ascender); | ||||
|                     break; | ||||
|                 case 't':  // top
 | ||||
|                     y_anchor = y_max; | ||||
|                     break; | ||||
|                 case 'm':  // middle (ascender + descender) / 2
 | ||||
|                     y_anchor = PIXEL( | ||||
|                         (self->face->size->metrics.ascender + | ||||
|                          self->face->size->metrics.descender) / | ||||
|                         (face->size->metrics.ascender + | ||||
|                          face->size->metrics.descender) / | ||||
|                         2); | ||||
|                     break; | ||||
|                 case 's':  // horizontal baseline
 | ||||
|  | @ -689,7 +665,7 @@ font_getsize(FontObject *self, PyObject *args) { | |||
|                     y_anchor = y_min; | ||||
|                     break; | ||||
|                 case 'd':  // descender
 | ||||
|                     y_anchor = PIXEL(self->face->size->metrics.descender); | ||||
|                     y_anchor = PIXEL(face->size->metrics.descender); | ||||
|                     break; | ||||
|                 default: | ||||
|                     goto bad_anchor; | ||||
|  | @ -729,17 +705,74 @@ font_getsize(FontObject *self, PyObject *args) { | |||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return Py_BuildValue( | ||||
|         "(ii)(ii)", | ||||
|         (x_max - x_min), | ||||
|         (y_max - y_min), | ||||
|         (-x_anchor + x_min), | ||||
|         -(-y_anchor + y_max)); | ||||
|     *width = x_max - x_min; | ||||
|     *height = y_max - y_min; | ||||
|     *x_offset = -x_anchor + x_min; | ||||
|     *y_offset = -(-y_anchor + y_max); | ||||
|     return 0; | ||||
| 
 | ||||
| bad_anchor: | ||||
|     PyErr_Format(PyExc_ValueError, "bad anchor specified: %s", anchor); | ||||
|     return NULL; | ||||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| font_getsize(FontObject *self, PyObject *args) { | ||||
|     int width, height, x_offset, y_offset; | ||||
|     int load_flags;               /* FreeType load_flags parameter */ | ||||
|     int error; | ||||
|     GlyphInfo *glyph_info = NULL; /* computed text layout */ | ||||
|     size_t count;                 /* glyph_info length */ | ||||
|     int horizontal_dir;           /* is primary axis horizontal? */ | ||||
|     int mask = 0;                 /* is FT_LOAD_TARGET_MONO enabled? */ | ||||
|     int color = 0;                /* is FT_LOAD_COLOR enabled? */ | ||||
|     const char *mode = NULL; | ||||
|     const char *dir = NULL; | ||||
|     const char *lang = NULL; | ||||
|     const char *anchor = NULL; | ||||
|     PyObject *features = Py_None; | ||||
|     PyObject *string; | ||||
| 
 | ||||
|     /* calculate size and bearing for a given string */ | ||||
| 
 | ||||
|     if (!PyArg_ParseTuple( | ||||
|             args, "O|zzOzz:getsize", &string, &mode, &dir, &features, &lang, &anchor)) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1; | ||||
| 
 | ||||
|     mask = mode && strcmp(mode, "1") == 0; | ||||
|     color = mode && strcmp(mode, "RGBA") == 0; | ||||
| 
 | ||||
|     count = text_layout(string, self, dir, features, lang, &glyph_info, mask, color); | ||||
|     if (PyErr_Occurred()) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     load_flags = FT_LOAD_DEFAULT; | ||||
|     if (mask) { | ||||
|         load_flags |= FT_LOAD_TARGET_MONO; | ||||
|     } | ||||
|     if (color) { | ||||
|         load_flags |= FT_LOAD_COLOR; | ||||
|     } | ||||
| 
 | ||||
|     error = bounding_box_and_anchors(self->face, anchor, horizontal_dir, glyph_info, count, load_flags, &width, &height, &x_offset, &y_offset); | ||||
|     if (glyph_info) { | ||||
|         PyMem_Free(glyph_info); | ||||
|         glyph_info = NULL; | ||||
|     } | ||||
|     if (error) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return Py_BuildValue( | ||||
|         "(ii)(ii)", | ||||
|         width, | ||||
|         height, | ||||
|         x_offset, | ||||
|         y_offset); | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
|  | @ -763,6 +796,7 @@ font_render(FontObject *self, PyObject *args) { | |||
|     unsigned int bitmap_y;          /* glyph bitmap y index */ | ||||
|     unsigned char *source;          /* glyph bitmap source buffer */ | ||||
|     unsigned char convert_scale;    /* scale factor for non-8bpp bitmaps */ | ||||
|     PyObject *image; | ||||
|     Imaging im; | ||||
|     Py_ssize_t id; | ||||
|     int mask = 0;  /* is FT_LOAD_TARGET_MONO enabled? */ | ||||
|  | @ -773,27 +807,34 @@ font_render(FontObject *self, PyObject *args) { | |||
|     const char *mode = NULL; | ||||
|     const char *dir = NULL; | ||||
|     const char *lang = NULL; | ||||
|     const char *anchor = NULL; | ||||
|     PyObject *features = Py_None; | ||||
|     PyObject *string; | ||||
|     PyObject *fill; | ||||
|     float x_start = 0; | ||||
|     float y_start = 0; | ||||
|     int width, height, x_offset, y_offset; | ||||
|     int horizontal_dir; /* is primary axis horizontal? */ | ||||
|     PyObject *max_image_pixels = Py_None; | ||||
| 
 | ||||
|     /* render string into given buffer (the buffer *must* have
 | ||||
|        the right size, or this will crash) */ | ||||
| 
 | ||||
|     if (!PyArg_ParseTuple( | ||||
|             args, | ||||
|             "On|zzOziLff:render", | ||||
|             "OO|zzOzizLffO:render", | ||||
|             &string, | ||||
|             &id, | ||||
|             &fill, | ||||
|             &mode, | ||||
|             &dir, | ||||
|             &features, | ||||
|             &lang, | ||||
|             &stroke_width, | ||||
|             &anchor, | ||||
|             &foreground_ink_long, | ||||
|             &x_start, | ||||
|             &y_start)) { | ||||
|             &y_start, | ||||
|             &max_image_pixels)) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|  | @ -819,8 +860,41 @@ font_render(FontObject *self, PyObject *args) { | |||
|     if (PyErr_Occurred()) { | ||||
|         return NULL; | ||||
|     } | ||||
|     if (count == 0) { | ||||
|         Py_RETURN_NONE; | ||||
| 
 | ||||
|     load_flags = stroke_width ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT; | ||||
|     if (mask) { | ||||
|         load_flags |= FT_LOAD_TARGET_MONO; | ||||
|     } | ||||
|     if (color) { | ||||
|         load_flags |= FT_LOAD_COLOR; | ||||
|     } | ||||
| 
 | ||||
|     horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1; | ||||
| 
 | ||||
|     error = bounding_box_and_anchors(self->face, anchor, horizontal_dir, glyph_info, count, load_flags, &width, &height, &x_offset, &y_offset); | ||||
|     if (error) { | ||||
|         PyMem_Del(glyph_info); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     width += stroke_width * 2 + ceil(x_start); | ||||
|     height += stroke_width * 2 + ceil(y_start); | ||||
|     if (max_image_pixels != Py_None) { | ||||
|         if (width * height > PyLong_AsLong(max_image_pixels) * 2) { | ||||
|             PyMem_Del(glyph_info); | ||||
|             return Py_BuildValue("O(ii)(ii)", Py_None, width, height, 0, 0); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     image = PyObject_CallFunction(fill, "s(ii)", strcmp(mode, "RGBA") == 0 ? "RGBA" : "L", width, height); | ||||
|     id = PyLong_AsSsize_t(PyObject_GetAttrString(image, "id")); | ||||
|     im = (Imaging)id; | ||||
| 
 | ||||
|     x_offset -= stroke_width; | ||||
|     y_offset -= stroke_width; | ||||
|     if (count == 0 || width == 0 || height == 0) { | ||||
|         PyMem_Del(glyph_info); | ||||
|         return Py_BuildValue("O(ii)(ii)", image, width, height, x_offset, y_offset); | ||||
|     } | ||||
| 
 | ||||
|     if (stroke_width) { | ||||
|  | @ -837,15 +911,6 @@ font_render(FontObject *self, PyObject *args) { | |||
|             0); | ||||
|     } | ||||
| 
 | ||||
|     im = (Imaging)id; | ||||
|     load_flags = stroke_width ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT; | ||||
|     if (mask) { | ||||
|         load_flags |= FT_LOAD_TARGET_MONO; | ||||
|     } | ||||
|     if (color) { | ||||
|         load_flags |= FT_LOAD_COLOR; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * calculate x_min and y_max | ||||
|      * must match font_getsize or there may be clipping! | ||||
|  | @ -1042,7 +1107,7 @@ font_render(FontObject *self, PyObject *args) { | |||
|     } | ||||
|     FT_Stroker_Done(stroker); | ||||
|     PyMem_Del(glyph_info); | ||||
|     Py_RETURN_NONE; | ||||
|     return Py_BuildValue("O(ii)(ii)", image, width, height, x_offset, y_offset); | ||||
| 
 | ||||
| glyph_error: | ||||
|     if (stroker != NULL) { | ||||
|  |  | |||
|  | @ -437,8 +437,14 @@ PyImaging_GrabClipboardWin32(PyObject *self, PyObject *args) { | |||
|     LPCSTR format_names[] = {"DIB", "DIB", "file", "png", NULL}; | ||||
| 
 | ||||
|     if (!OpenClipboard(NULL)) { | ||||
|         PyErr_SetString(PyExc_OSError, "failed to open clipboard"); | ||||
|         return NULL; | ||||
|         // Maybe the clipboard is temporarily in use by another process.
 | ||||
|         // Wait and try again
 | ||||
|         Sleep(500); | ||||
| 
 | ||||
|         if (!OpenClipboard(NULL)) { | ||||
|             PyErr_SetString(PyExc_OSError, "failed to open clipboard"); | ||||
|             return NULL; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // find best format as set by clipboard owner
 | ||||
|  |  | |||
|  | @ -49,7 +49,7 @@ clip32(float in) { | |||
| } | ||||
| 
 | ||||
| Imaging | ||||
| ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) { | ||||
| ImagingExpand(Imaging imIn, int xmargin, int ymargin) { | ||||
|     Imaging imOut; | ||||
|     int x, y; | ||||
|     ImagingSectionCookie cookie; | ||||
|  |  | |||
|  | @ -53,10 +53,6 @@ | |||
| #define UINT16 uint16_t | ||||
| #define INT32 int32_t | ||||
| #define UINT32 uint32_t | ||||
| #ifdef INT64_MAX | ||||
| #define INT64 int64_t | ||||
| #define UINT64 uint64_t | ||||
| #endif | ||||
| 
 | ||||
| #else /* < C99 */ | ||||
| 
 | ||||
|  | @ -80,20 +76,9 @@ | |||
| #error Cannot find required 32-bit integer type | ||||
| #endif | ||||
| 
 | ||||
| #if SIZEOF_LONG == 8 | ||||
| #define INT64 long | ||||
| #elif SIZEOF_LONG_LONG == 8 | ||||
| #define INT64 long long | ||||
| #else | ||||
| #warning Cannot find required 64-bit integer type | ||||
| #endif | ||||
| 
 | ||||
| #define UINT8 unsigned char | ||||
| #define UINT16 unsigned INT16 | ||||
| #define UINT32 unsigned INT32 | ||||
| #ifdef INT64 | ||||
| #define UINT64 unsigned INT64 | ||||
| #endif | ||||
| 
 | ||||
| #endif /* < C99 */ | ||||
| 
 | ||||
|  |  | |||
|  | @ -290,7 +290,7 @@ ImagingConvertTransparent(Imaging im, const char *mode, int r, int g, int b); | |||
| extern Imaging | ||||
| ImagingCrop(Imaging im, int x0, int y0, int x1, int y1); | ||||
| extern Imaging | ||||
| ImagingExpand(Imaging im, int x, int y, int mode); | ||||
| ImagingExpand(Imaging im, int x, int y); | ||||
| extern Imaging | ||||
| ImagingFill(Imaging im, const void *ink); | ||||
| extern int | ||||
|  |  | |||
|  | @ -464,7 +464,7 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) { | |||
|     } | ||||
| 
 | ||||
|     if (!context->num_resolutions) { | ||||
|         while (tile_width < (1 << (params.numresolution - 1U)) || tile_height < (1 << (params.numresolution - 1U))) { | ||||
|         while (tile_width < (1U << (params.numresolution - 1U)) || tile_height < (1U << (params.numresolution - 1U))) { | ||||
|             params.numresolution -= 1; | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -37,8 +37,6 @@ | |||
| #include "Imaging.h" | ||||
| #include <string.h> | ||||
| 
 | ||||
| int ImagingNewCount = 0; | ||||
| 
 | ||||
| /* --------------------------------------------------------------------
 | ||||
|  * Standard image object. | ||||
|  */ | ||||
|  |  | |||
|  | @ -1552,10 +1552,12 @@ static struct { | |||
|     {"P", "P;4L", 4, unpackP4L}, | ||||
|     {"P", "P", 8, copy1}, | ||||
|     {"P", "P;R", 8, unpackLR}, | ||||
|     {"P", "L", 8, copy1}, | ||||
| 
 | ||||
|     /* palette w. alpha */ | ||||
|     {"PA", "PA", 16, unpackLA}, | ||||
|     {"PA", "PA;L", 16, unpackLAL}, | ||||
|     {"PA", "LA", 16, unpackLA}, | ||||
| 
 | ||||
|     /* true colour */ | ||||
|     {"RGB", "RGB", 24, ImagingUnpackRGB}, | ||||
|  |  | |||
|  | @ -152,9 +152,9 @@ deps = { | |||
|         "libs": [r"*.lib"], | ||||
|     }, | ||||
|     "xz": { | ||||
|         "url": SF_PROJECTS + "/lzmautils/files/xz-5.4.2.tar.gz/download", | ||||
|         "filename": "xz-5.4.2.tar.gz", | ||||
|         "dir": "xz-5.4.2", | ||||
|         "url": SF_PROJECTS + "/lzmautils/files/xz-5.4.3.tar.gz/download", | ||||
|         "filename": "xz-5.4.3.tar.gz", | ||||
|         "dir": "xz-5.4.3", | ||||
|         "license": "COPYING", | ||||
|         "build": [ | ||||
|             *cmds_cmake("liblzma", "-DBUILD_SHARED_LIBS:BOOL=OFF"), | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user