diff --git a/.appveyor.yml b/.appveyor.yml index a77033ec1..0cf1d5a9e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -23,16 +23,16 @@ install: - 7z x pillow-depends.zip -oc:\ - mv c:\pillow-depends-master c:\pillow-depends - xcopy /S /Y c:\pillow-depends\test_images\* c:\pillow\tests\images -- 7z x ..\pillow-depends\nasm-2.14.02-win64.zip -oc:\ -- ..\pillow-depends\gs9533w32.exe /S -- path c:\nasm-2.14.02;C:\Program Files (x86)\gs\gs9.53.3\bin;%PATH% +- 7z x ..\pillow-depends\nasm-2.15.05-win64.zip -oc:\ +- ..\pillow-depends\gs9540w32.exe /S +- path c:\nasm-2.15.05;C:\Program Files (x86)\gs\gs9.54.0\bin;%PATH% - cd c:\pillow\winbuild\ - ps: | c:\python37\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\ c:\pillow\winbuild\build\build_dep_all.cmd $host.SetShouldExit(0) - path C:\pillow\winbuild\build\bin;%PATH% -- '%PYTHON%\%EXECUTABLE% -m pip install -U "setuptools>=49.3.2"' +- '%PYTHON%\%EXECUTABLE% -m pip install -U setuptools' build_script: - ps: | @@ -45,6 +45,7 @@ test_script: - cd c:\pillow - '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov' - c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE% +- '%PYTHON%\%EXECUTABLE% -c "from PIL import Image"' - '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests' #- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest? diff --git a/.ci/install.sh b/.ci/install.sh index 9372d0c51..fbe85ded7 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -27,15 +27,12 @@ python3 -m pip install coverage python3 -m pip install olefile python3 -m pip install -U pytest python3 -m pip install -U pytest-cov +python3 -m pip install -U pytest-timeout python3 -m pip install pyroma python3 -m pip install test-image-results # TODO Remove condition when numpy supports 3.10 if ! [ "$GHA_PYTHON_VERSION" == "3.10-dev" ]; then python3 -m pip install numpy ; fi -# TODO Remove when 3.8 / 3.9 includes setuptools 49.3.2+: -if [ "$GHA_PYTHON_VERSION" == "3.8" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi -if [ "$GHA_PYTHON_VERSION" == "3.9" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi - # PyQt5 doesn't support PyPy3 # Wheel doesn't yet support 3.10 if [[ $GHA_PYTHON_VERSION == 3.* && $GHA_PYTHON_VERSION != "3.10-dev" ]]; then diff --git a/.ci/test.sh b/.ci/test.sh index 5a19ec9b4..8ff7c5f64 100755 --- a/.ci/test.sh +++ b/.ci/test.sh @@ -2,4 +2,6 @@ set -e -python -bb -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests +python3 -c "from PIL import Image" + +python3 -bb -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests $REVERSE diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..be32e6d1a --- /dev/null +++ b/.clang-format @@ -0,0 +1,20 @@ +# A clang-format style that approximates Python's PEP 7 +# Useful for IDE integration +BasedOnStyle: Google +AlwaysBreakAfterReturnType: All +AllowShortIfStatementsOnASingleLine: false +AlignAfterOpenBracket: AlwaysBreak +BinPackArguments: false +BinPackParameters: false +BreakBeforeBraces: Attach +ColumnLimit: 88 +DerivePointerAlignment: false +IndentWidth: 4 +Language: Cpp +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SpaceBeforeParens: ControlStatements +SpacesInParentheses: false +TabWidth: 4 +UseTab: Never diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 563fcda6a..35bd47be8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -18,6 +18,7 @@ Please send a pull request to the master branch. Please include [documentation]( - Provide tests for any newly added code. - Follow PEP 8. - When committing only documentation changes please include `[ci skip]` in the commit message to avoid running tests on AppVeyor. +- Include [release notes](https://github.com/python-pillow/Pillow/tree/master/docs/releasenotes) as needed or appropriate with your bug fixes, feature additions and tests. ## Reporting Issues diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml new file mode 100644 index 000000000..9fe8f774f --- /dev/null +++ b/.github/workflows/cifuzz.yml @@ -0,0 +1,47 @@ +name: CIFuzz +on: + push: + paths: + - "**.c" + - "**.h" + pull_request: + paths: + - "**.c" + - "**.h" + +jobs: + Fuzzing: + runs-on: ubuntu-latest + steps: + - name: Build Fuzzers + id: build + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'pillow' + language: python + dry-run: false + - name: Run Fuzzers + id: run + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'pillow' + fuzz-seconds: 600 + language: python + dry-run: false + - name: Upload New Crash + uses: actions/upload-artifact@v2 + if: failure() && steps.build.outcome == 'success' + with: + name: artifacts + path: ./out/artifacts + - name: Upload Legacy Crash + uses: actions/upload-artifact@v2 + if: steps.run.outcome == 'success' + with: + name: crash + path: ./out/crash* + - name: Fail on legacy crash + if: success() + run: | + [ ! -e out/crash-* ] + echo No legacy crash detected diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3c658293e..bddeb6150 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,12 +34,12 @@ jobs: python-version: 3.8 - name: Build system information - run: python .github/workflows/system-info.py + run: python3 .github/workflows/system-info.py - name: Install dependencies run: | - python -m pip install -U pip - python -m pip install -U tox + python3 -m pip install -U pip + python3 -m pip install -U tox - name: Lint run: tox -e lint diff --git a/.github/workflows/macos-install.sh b/.github/workflows/macos-install.sh index afcb9a5a7..b20ecb4dc 100755 --- a/.github/workflows/macos-install.sh +++ b/.github/workflows/macos-install.sh @@ -9,6 +9,7 @@ python3 -m pip install coverage python3 -m pip install olefile python3 -m pip install -U pytest python3 -m pip install -U pytest-cov +python3 -m pip install -U pytest-timeout python3 -m pip install pyroma python3 -m pip install test-image-results @@ -16,9 +17,5 @@ echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openbla # TODO Remove condition when numpy supports 3.10 if ! [ "$GHA_PYTHON_VERSION" == "3.10-dev" ]; then python3 -m pip install numpy ; fi -# TODO Remove when 3.8 / 3.9 includes setuptools 49.3.2+: -if [ "$GHA_PYTHON_VERSION" == "3.8" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi -if [ "$GHA_PYTHON_VERSION" == "3.9" ]; then python3 -m pip install -U "setuptools>=49.3.2" ; fi - # extra test images pushd depends && ./install_extra_test_images.sh && popd diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index eb173c359..8274549d4 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -21,8 +21,8 @@ jobs: centos-7-amd64, centos-8-amd64, debian-10-buster-x86, - fedora-32-amd64, fedora-33-amd64, + fedora-34-amd64, ubuntu-18.04-bionic-amd64, ubuntu-20.04-focal-amd64, ] @@ -41,7 +41,7 @@ jobs: - uses: actions/checkout@v2 - name: Build system information - run: python .github/workflows/system-info.py + run: python3 .github/workflows/system-info.py - name: Set up QEMU if: "matrix.qemu-arch" diff --git a/.github/workflows/test-valgrind.yml b/.github/workflows/test-valgrind.yml new file mode 100644 index 000000000..7b8474d0f --- /dev/null +++ b/.github/workflows/test-valgrind.yml @@ -0,0 +1,52 @@ +name: Test Valgrind + +# like the docker tests, but running valgrind only on *.c/*.h changes. + +on: + push: + paths: + - "**.c" + - "**.h" + pull_request: + paths: + - "**.c" + - "**.h" + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + docker: [ + ubuntu-20.04-focal-amd64-valgrind, + ] + dockerTag: [master] + + name: ${{ matrix.docker }} + + steps: + - uses: actions/checkout@v2 + + - name: Build system information + run: python3 .github/workflows/system-info.py + + - name: Docker pull + run: | + docker pull pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} + + - name: Build and Run Valgrind + run: | + # The Pillow user in the docker container is UID 1000 + sudo chown -R 1000 $GITHUB_WORKSPACE + docker run --name pillow_container -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} + sudo chown -R runner $GITHUB_WORKSPACE + + success: + needs: build + runs-on: ubuntu-latest + name: Valgrind Test Successful + steps: + - name: Success + run: echo Valgrind Test Successful diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 562b2b7b4..cdb8493dc 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -8,19 +8,13 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["pypy-3.6", "pypy-3.7", "3.6", "3.7", "3.8", "3.9", "3.10-dev"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10-dev"] architecture: ["x86", "x64"] include: - - architecture: "x86" - platform-vcvars: "x86" - platform-msbuild: "Win32" - - architecture: "x64" - platform-vcvars: "x86_amd64" - platform-msbuild: "x64" - exclude: - # PyPy does not support 64-bit on Windows + # PyPy3.6 only ships 32-bit binaries for Windows - python-version: "pypy-3.6" - architecture: "x64" + architecture: "x86" + # PyPy 7.3.4+ only ships 64-bit binaries for Windows - python-version: "pypy-3.7" architecture: "x64" timeout-minutes: 30 @@ -57,22 +51,17 @@ jobs: - name: Print build system information run: python .github/workflows/system-info.py - - name: python -m pip install wheel pytest pytest-cov - run: python -m pip install wheel pytest pytest-cov - - # TODO Remove when 3.8 / 3.9 includes setuptools 49.3.2+: - - name: Upgrade setuptools - if: "contains(matrix.python-version, '3.8') || contains(matrix.python-version, '3.9')" - run: python -m pip install -U "setuptools>=49.3.2" + - name: python -m pip install wheel pytest pytest-cov pytest-timeout + run: python -m pip install wheel pytest pytest-cov pytest-timeout - name: Install dependencies id: install run: | - 7z x winbuild\depends\nasm-2.14.02-win64.zip "-o$env:RUNNER_WORKSPACE\" - echo "$env:RUNNER_WORKSPACE\nasm-2.14.02" >> $env:GITHUB_PATH + 7z x winbuild\depends\nasm-2.15.05-win64.zip "-o$env:RUNNER_WORKSPACE\" + echo "$env:RUNNER_WORKSPACE\nasm-2.15.05" >> $env:GITHUB_PATH - winbuild\depends\gs9533w32.exe /S - echo "C:\Program Files (x86)\gs\gs9.53.3\bin" >> $env:GITHUB_PATH + winbuild\depends\gs9540w32.exe /S + echo "C:\Program Files (x86)\gs\gs9.54.0\bin" >> $env:GITHUB_PATH xcopy /S /Y winbuild\depends\test_images\* Tests\images\ @@ -110,7 +99,7 @@ jobs: if: steps.build-cache.outputs.cache-hit != 'true' run: "& winbuild\\build\\build_dep_libwebp.cmd" - # for FreeType CBDT font support + # for FreeType CBDT/SBIX font support - name: Build dependencies / libpng if: steps.build-cache.outputs.cache-hit != 'true' run: "& winbuild\\build\\build_dep_libpng.cmd" @@ -137,14 +126,11 @@ jobs: if: steps.build-cache.outputs.cache-hit != 'true' run: "& winbuild\\build\\build_dep_harfbuzz.cmd" + # Raqm dependencies - name: Build dependencies / FriBidi if: steps.build-cache.outputs.cache-hit != 'true' run: "& winbuild\\build\\build_dep_fribidi.cmd" - - name: Build dependencies / Raqm - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_libraqm.cmd" - # trim ~150MB x 9 - name: Optimize build cache if: steps.build-cache.outputs.cache-hit != 'true' @@ -174,7 +160,7 @@ jobs: if: failure() run: | mkdir -p Tests/errors - shell: pwsh + shell: bash - name: Upload errors uses: actions/upload-artifact@v2 @@ -197,16 +183,14 @@ jobs: - name: Build wheel id: wheel - # Skip wheels on 3.10 due to https://github.com/pypa/wheel/issues/354 - if: "github.event_name == 'push' && !contains(matrix.python-version, '3.10')" + if: "github.event_name == 'push'" run: | for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo ::set-output name=dist::dist-%%a winbuild\\build\\build_pillow.cmd --disable-imagequant bdist_wheel shell: cmd - uses: actions/upload-artifact@v2 - # Skip wheels on 3.10 due to https://github.com/pypa/wheel/issues/354 - if: "github.event_name == 'push' && !contains(matrix.python-version, '3.10')" + if: "github.event_name == 'push'" with: name: ${{ steps.wheel.outputs.dist }} path: dist\*.whl @@ -251,8 +235,6 @@ jobs: ${{ matrix.package }}-python3-olefile \ ${{ matrix.package }}-python3-pip \ ${{ matrix.package }}-python3-pyqt5 \ - ${{ matrix.package }}-python3-pytest \ - ${{ matrix.package }}-python3-pytest-cov \ ${{ matrix.package }}-python3-setuptools \ ${{ matrix.package }}-freetype \ ${{ matrix.package }}-ghostscript \ @@ -265,7 +247,7 @@ jobs: ${{ matrix.package }}-openjpeg2 \ subversion - python3 -m pip install pyroma + python3 -m pip install pyroma pytest pytest-cov pushd depends && ./install_extra_test_images.sh && popd @@ -275,6 +257,7 @@ jobs: - name: Test Pillow run: | python3 selftest.py --installed + python3 -c "from PIL import Image" python3 -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests - name: Upload coverage diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d127916ea..042e6d83e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,6 +24,7 @@ jobs: include: - python-version: "3.6" PYTHONOPTIMIZE: 1 + REVERSE: "--reverse" - python-version: "3.7" PYTHONOPTIMIZE: 2 # Include new variables for Codecov @@ -58,7 +59,7 @@ jobs: ${{ matrix.os }}-${{ matrix.python-version }}- - name: Build system information - run: python .github/workflows/system-info.py + run: python3 .github/workflows/system-info.py - name: Install Linux dependencies if: startsWith(matrix.os, 'ubuntu') @@ -80,6 +81,9 @@ jobs: - name: Test run: | + if [ $REVERSE ]; then + python3 -m pip install pytest-reverse + fi if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then xvfb-run -s '-screen 0 1024x768x24' .ci/test.sh else @@ -87,12 +91,12 @@ jobs: fi env: PYTHONOPTIMIZE: ${{ matrix.PYTHONOPTIMIZE }} + REVERSE: ${{ matrix.REVERSE }} - name: Prepare to upload errors if: failure() run: | mkdir -p Tests/errors - shell: pwsh - name: Upload errors uses: actions/upload-artifact@v2 @@ -104,7 +108,7 @@ jobs: - name: Docs if: startsWith(matrix.os, 'ubuntu') && matrix.python-version == 3.9 run: | - python3 -m pip install sphinx-issues sphinx-removed-in sphinx-rtd-theme + python3 -m pip install sphinx-copybutton sphinx-issues sphinx-removed-in sphinx-rtd-theme sphinxext-opengraph make doccheck - name: After success diff --git a/.gitignore b/.gitignore index 15add232b..5500ec037 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,6 @@ Tests/images/jpeg2000 Tests/images/msp Tests/images/picins Tests/images/sunraster + +# pyinstaller +*.spec diff --git a/CHANGES.rst b/CHANGES.rst index 691a7a220..6506b0b80 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,9 +2,315 @@ Changelog (Pillow) ================== -8.1.0 (unreleased) +8.3.0 (unreleased) ------------------ +- Added tag data for IFD groups #5554 + [radarhere] + +- Improved ImagePalette #5552 + [radarhere] + +- Add DDS saving #5402 + [radarhere] + +- Improved getxmp() #5455 + [radarhere] + +- Convert to float for comparison with float in IFDRational __eq__ #5412 + [radarhere] + +- Allow getexif() to access TIFF tag_v2 data #5416 + [radarhere] + +- Read FITS image mode and size #5405 + [radarhere] + +- Merge parallel horizontal edges in ImagingDrawPolygon #5347 + [radarhere, hrdrq] + +- Use transparency behind first GIF frame and when disposing to background #5557 + [radarhere, zewt] + +- Avoid unstable nature of qsort in Quant.c #5367 + [radarhere] + +- Copy palette to new images in ImageOps expand #5551 + [radarhere] + +- Ensure palette string matches RGB mode #5549 + [radarhere] + +- Do not modify EXIF of original image instance in exif_transpose() #5547 + [radarhere] + +- Fixed default numresolution for small JPEG2000 images #5540 + [radarhere] + +- Added DDS BC5 reading #5501 + [radarhere] + +- Raise an error if ImageDraw.textbbox is used without a TrueType font #5510 + [radarhere] + +- Added ICO saving in BMP format #5513 + [radarhere] + +- Ensure PNG seeks to end of previous chunk at start of load_end #5493 + [radarhere] + +- Do not allow TIFF to seek to a past frame #5473 + [radarhere] + +- Avoid race condition when displaying images with eog #5507 + [mconst] + +- Added specific error messages when ink has incorrect number of bands #5504 + [radarhere] + +- Allow converting an image to a numpy array to raise errors #5379 + [radarhere] + +- Removed DPI rounding from BMP, JPEG, PNG and WMF loading #5476, #5470 + [radarhere] + +- Remove spikes when drawing thin pieslices #5460 + [xtsm] + +- Updated default value for SAMPLESPERPIXEL TIFF tag #5452 + [radarhere] + +- Removed TIFF DPI rounding #5446 + [radarhere, hugovk] + +- Include code in WebP error #5471 + [radarhere] + +- Do not alter pixels outside mask when drawing text on an image with transparency #5434 + [radarhere] + +- Reset handle when seeking backwards in TIFF #5443 + [radarhere] + +- Replace sys.stdout with sys.stdout.buffer when saving #5437 + [radarhere] + +- Fixed UNDEFINED TIFF tag of length 0 being changed in roundtrip #5426 + [radarhere] + +- Fixed bug when checking FreeType2 version if it is not installed #5445 + [radarhere] + +- Do not round dimensions when saving PDF #5459 + [radarhere] + +- Added ImageOps contain() #5417 + [radarhere, hugovk] + +- Changed WebP default "method" value to 4 #5450 + [radarhere] + +- Switched to saving 1-bit PDFs with DCTDecode #5430 + [radarhere] + +- Use bpp from ICO header #5429 + [radarhere] + +- Corrected JPEG APP14 transform value #5408 + [radarhere] + +- Changed TIFF tag 33723 length to 1 #5425 + [radarhere] + +- Changed ImageMorph incorrect mode errors to ValueError #5414 + [radarhere] + +- Add EXIF tags specified in EXIF 2.32 #5419 + [gladiusglad] + +- Treat previous contents of first GIF frame as transparent #5391 + [radarhere] + +- For special image modes, revert default resize resampling to NEAREST #5411 + [radarhere] + +- JPEG2000: Support decoding subsampled RGB and YCbCr images #4996 + [nulano, radarhere] + +- Stop decoding BC1 punchthrough alpha in BC2&3 #4144 + [jansol] + +- Use zero if GIF background color index is missing #5390 + [radarhere] + +- Fixed ensuring that GIF previous frame was loaded #5386 + [radarhere] + +- Valgrind fixes #5397 + [wiredfool] + +- Round down the radius in rounded_rectangle #5382 + [radarhere] + +- Fixed reading uncompressed RGB data from DDS #5383 + [radarhere] + +8.2.0 (2021-04-01) +------------------ + +- Added getxmp() method #5144 + [UrielMaD, radarhere] + +- Add ImageShow support for GraphicsMagick #5349 + [latosha-maltba, radarhere] + +- Do not load transparent pixels from subsequent GIF frames #5333 + [zewt, radarhere] + +- Use LZW encoding when saving GIF images #5291 + [raygard] + +- Set all transparent colors to be equal in quantize() #5282 + [radarhere] + +- Allow PixelAccess to use Python __int__ when parsing x and y #5206 + [radarhere] + +- Removed Image._MODEINFO #5316 + [radarhere] + +- Add preserve_tone option to autocontrast #5350 + [elejke, radarhere] + +- Fixed linear_gradient and radial_gradient I and F modes #5274 + [radarhere] + +- Add support for reading TIFFs with PlanarConfiguration=2 #5364 + [kkopachev, wiredfool, nulano] + +- Deprecated categories #5351 + [radarhere] + +- Do not premultiply alpha when resizing with Image.NEAREST resampling #5304 + [nulano] + +- Dynamically link FriBiDi instead of Raqm #5062 + [nulano] + +- Allow fewer PNG palette entries than the bit depth maximum when saving #5330 + [radarhere] + +- Use duration from info dictionary when saving WebP #5338 + [radarhere] + +- Stop flattening EXIF IFD into getexif() #4947 + [radarhere, kkopachev] + +- Replaced tiff_deflate with tiff_adobe_deflate compression when saving TIFF images #5343 + [radarhere] + +- Save ICC profile from TIFF encoderinfo #5321 + [radarhere] + +- Moved RGB fix inside ImageQt class #5268 + [radarhere] + +- Allow alpha_composite destination to be negative #5313 + [radarhere] + +- Ensure file is closed if it is opened by ImageQt.ImageQt #5260 + [radarhere] + +- Added ImageDraw rounded_rectangle method #5208 + [radarhere] + +- Added IPythonViewer #5289 + [radarhere, Kipkurui-mutai] + +- Only draw each rectangle outline pixel once #5183 + [radarhere] + +- Use mmap instead of built-in Win32 mapper #5224 + [radarhere, cgohlke] + +- Handle PCX images with an odd stride #5214 + [radarhere] + +- Only read different sizes for "Large Thumbnail" MPO frames #5168 + [radarhere] + +- Added PyQt6 support #5258 + [radarhere] + +- Changed Image.open formats parameter to be case-insensitive #5250 + [Piolie, radarhere] + +- Deprecate Tk/Tcl 8.4, to be removed in Pillow 10 (2023-01-02) #5216 + [radarhere] + +- Added tk version to pilinfo #5226 + [radarhere, nulano] + +- Support for ignoring tests when running valgrind #5150 + [wiredfool, radarhere, hugovk] + +- OSS-Fuzz support #5189 + [wiredfool, radarhere] + +8.1.2 (2021-03-06) +------------------ + +- Fix Memory DOS in BLP (CVE-2021-27921), ICNS (CVE-2021-27922) and ICO (CVE-2021-27923) Image Plugins + [wiredfool] + +8.1.1 (2021-03-01) +------------------ + +- Use more specific regex chars to prevent ReDoS. CVE-2021-25292 + [hugovk] + +- Fix OOB Read in TiffDecode.c, and check the tile validity before reading. CVE-2021-25291 + [wiredfool] + +- Fix negative size read in TiffDecode.c. CVE-2021-25290 + [wiredfool] + +- Fix OOB read in SgiRleDecode.c. CVE-2021-25293 + [wiredfool] + +- Incorrect error code checking in TiffDecode.c. CVE-2021-25289 + [wiredfool] + +- PyModule_AddObject fix for Python 3.10 #5194 + [radarhere] + +8.1.0 (2021-01-02) +------------------ + +- Fix TIFF OOB Write error. CVE-2020-35654 #5175 + [wiredfool] + +- Fix for Read Overflow in PCX Decoding. CVE-2020-35653 #5174 + [wiredfool, radarhere] + +- Fix for SGI Decode buffer overrun. CVE-2020-35655 #5173 + [wiredfool, radarhere] + +- Fix OOB Read when saving GIF of xsize=1 #5149 + [wiredfool] + +- Makefile updates #5159 + [wiredfool, radarhere] + +- Add support for PySide6 #5161 + [hugovk] + +- Use disposal settings from previous frame in APNG #5126 + [radarhere] + +- Added exception explaining that _repr_png_ saves to PNG #5139 + [radarhere] + - Use previous disposal method in GIF load_end #5125 [radarhere] diff --git a/LICENSE b/LICENSE index eb9c41f56..1197291bc 100644 --- a/LICENSE +++ b/LICENSE @@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is Pillow is the friendly PIL fork. It is - Copyright © 2010-2020 by Alex Clark and contributors + Copyright © 2010-2021 by Alex Clark and contributors Like PIL, Pillow is licensed under the open source HPND License: diff --git a/MANIFEST.in b/MANIFEST.in index f5d367fdd..e9aaa8318 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -18,6 +18,7 @@ graft docs # build/src control detritus exclude .appveyor.yml +exclude .clang-format exclude .coveragerc exclude .editorconfig exclude .readthedocs.yml diff --git a/Makefile b/Makefile index 6430c9776..af3059f34 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.DEFAULT_GOAL := release-test +.DEFAULT_GOAL := help .PHONY: clean clean: @@ -7,13 +7,6 @@ clean: rm -r build || true find . -name __pycache__ | xargs rm -r || true -BRANCHES=`git branch -a | grep -v HEAD | grep -v master | grep remote` -.PHONY: co -co: - -for i in $(BRANCHES) ; do \ - git checkout -t $$i ; \ - done - .PHONY: coverage coverage: pytest -qq @@ -47,7 +40,9 @@ help: @echo " install make and install" @echo " install-coverage make and install with C coverage" @echo " install-req install documentation and test dependencies" - @echo " install-venv install in virtualenv" + @echo " install-venv (deprecated) install in virtualenv" + @echo " lint run the lint checks" + @echo " lint-fix run black and isort to (mostly) fix lint issues." @echo " release-test run code and package tests before release" @echo " test run tests on installed pillow" @echo " upload build and upload sdists to PyPI" @@ -81,6 +76,7 @@ install-req: .PHONY: install-venv install-venv: + echo "'install-venv' is deprecated and will be removed in a future Pillow release" virtualenv . bin/pip install -r requirements.txt @@ -106,6 +102,24 @@ sdist: test: pytest -qq +.PHONY: valgrind +valgrind: + python3 -c "import pytest_valgrind" || pip3 install pytest-valgrind + PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp --leak-check=no \ + --log-file=/tmp/valgrind-output \ + python3 -m pytest --no-memcheck -vv --valgrind --valgrind-log=/tmp/valgrind-output + .PHONY: readme readme: python3 setup.py --long-description | markdown2 > .long-description.html && open .long-description.html + + +.PHONY: lint +lint: + tox --help > /dev/null || python3 -m pip install tox + tox -e lint + +.PHONY: lint-fix +lint-fix: + black --target-version py36 . + isort . diff --git a/README.md b/README.md index 0408f4c28..29b5b8a6a 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,12 @@ As of 2019, Pillow development is AppVeyor CI build status (Windows) + GitHub Actions wheels build status (Wheels) Travis CI build status (macOS) + alt="Travis CI wheels build status (aarch64)" + src="https://img.shields.io/travis/com/python-pillow/pillow-wheels/master.svg?label=aarch64%20wheels"> Code coverage diff --git a/Tests/32bit_segfault_check.py b/Tests/32bit_segfault_check.py index 26a91d5cd..e19cdf7a9 100755 --- a/Tests/32bit_segfault_check.py +++ b/Tests/32bit_segfault_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys diff --git a/Tests/check_fli_oob.py b/Tests/check_fli_oob.py index 739ad224e..6b63a6826 100644 --- a/Tests/check_fli_oob.py +++ b/Tests/check_fli_oob.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from PIL import Image diff --git a/Tests/check_icns_dos.py b/Tests/check_icns_dos.py index 3f4fb6518..a34bee45c 100644 --- a/Tests/check_icns_dos.py +++ b/Tests/check_icns_dos.py @@ -5,4 +5,5 @@ from io import BytesIO from PIL import Image -Image.open(BytesIO(b"icns\x00\x00\x00\x10hang\x00\x00\x00\x00")) +with Image.open(BytesIO(b"icns\x00\x00\x00\x10hang\x00\x00\x00\x00")): + pass diff --git a/Tests/check_imaging_leaks.py b/Tests/check_imaging_leaks.py index 407f3ea80..d07082aba 100755 --- a/Tests/check_imaging_leaks.py +++ b/Tests/check_imaging_leaks.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import pytest from PIL import Image diff --git a/Tests/check_j2k_dos.py b/Tests/check_j2k_dos.py index 273c18585..71dcea4f3 100644 --- a/Tests/check_j2k_dos.py +++ b/Tests/check_j2k_dos.py @@ -5,4 +5,7 @@ from io import BytesIO from PIL import Image -Image.open(BytesIO(b"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang")) +with Image.open( + BytesIO(b"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang") +): + pass diff --git a/Tests/check_jp2_overflow.py b/Tests/check_jp2_overflow.py index a7a343c98..f81a360ce 100755 --- a/Tests/check_jp2_overflow.py +++ b/Tests/check_jp2_overflow.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Reproductions/tests for OOB read errors in FliDecode.c diff --git a/Tests/conftest.py b/Tests/conftest.py index 082f2f7c3..66da7593c 100644 --- a/Tests/conftest.py +++ b/Tests/conftest.py @@ -10,3 +10,22 @@ def pytest_report_header(config): return out.getvalue() except Exception as e: return f"pytest_report_header failed: {e}" + + +def pytest_configure(config): + config.addinivalue_line( + "markers", + "pil_noop_mark: A conditional mark where nothing special happens", + ) + + # We're marking some tests to ignore valgrind errors and XFAIL them. + # Ensure that the mark is defined + # even in cases where pytest-valgrind isn't installed + try: + config.addinivalue_line( + "markers", + "valgrind_known_error: Tests that have known issues with valgrind", + ) + except Exception: + # valgrind is already installed + pass diff --git a/Tests/createfontdatachunk.py b/Tests/createfontdatachunk.py index 011bb0bed..e318eb732 100755 --- a/Tests/createfontdatachunk.py +++ b/Tests/createfontdatachunk.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import base64 import os diff --git a/Tests/fonts/DejaVuSans-24-1-stripped.ttf b/Tests/fonts/DejaVuSans/DejaVuSans-24-1-stripped.ttf similarity index 100% rename from Tests/fonts/DejaVuSans-24-1-stripped.ttf rename to Tests/fonts/DejaVuSans/DejaVuSans-24-1-stripped.ttf diff --git a/Tests/fonts/DejaVuSans-24-2-stripped.ttf b/Tests/fonts/DejaVuSans/DejaVuSans-24-2-stripped.ttf similarity index 100% rename from Tests/fonts/DejaVuSans-24-2-stripped.ttf rename to Tests/fonts/DejaVuSans/DejaVuSans-24-2-stripped.ttf diff --git a/Tests/fonts/DejaVuSans-24-4-stripped.ttf b/Tests/fonts/DejaVuSans/DejaVuSans-24-4-stripped.ttf similarity index 100% rename from Tests/fonts/DejaVuSans-24-4-stripped.ttf rename to Tests/fonts/DejaVuSans/DejaVuSans-24-4-stripped.ttf diff --git a/Tests/fonts/DejaVuSans-24-8-stripped.ttf b/Tests/fonts/DejaVuSans/DejaVuSans-24-8-stripped.ttf similarity index 100% rename from Tests/fonts/DejaVuSans-24-8-stripped.ttf rename to Tests/fonts/DejaVuSans/DejaVuSans-24-8-stripped.ttf diff --git a/Tests/fonts/DejaVuSans.ttf b/Tests/fonts/DejaVuSans/DejaVuSans.ttf similarity index 100% rename from Tests/fonts/DejaVuSans.ttf rename to Tests/fonts/DejaVuSans/DejaVuSans.ttf diff --git a/Tests/fonts/DejaVuSans/LICENSE.txt b/Tests/fonts/DejaVuSans/LICENSE.txt new file mode 100644 index 000000000..30516578f --- /dev/null +++ b/Tests/fonts/DejaVuSans/LICENSE.txt @@ -0,0 +1,40 @@ +DejaVuSans-24-{1,2,4,8}-stripped.ttf are based on DejaVuSans.ttf converted using FontForge to add bitmap strikes and keep only the ASCII range. + +DejaVu Fonts — License +Fonts are © Bitstream (see below). DejaVu changes are in public domain. Explanation of copyright is on Gnome page on Bitstream Vera fonts. Glyphs imported from Arev fonts are © Tavmjung Bah (see below) + +Bitstream Vera Fonts Copyright +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. + +Arev Fonts Copyright +Original text + +Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the modifications to the Bitstream Vera Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Tavmjong Bah" or the word "Arev". + +This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Tavmjong Bah Arev" names. + +The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the name of Tavmjong Bah shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from Tavmjong Bah. For further information, contact: tavmjong @ free . fr. \ No newline at end of file diff --git a/Tests/fonts/LICENSE.txt b/Tests/fonts/LICENSE.txt index 06eaa9a4e..104ff677c 100644 --- a/Tests/fonts/LICENSE.txt +++ b/Tests/fonts/LICENSE.txt @@ -15,8 +15,11 @@ FreeMono.ttf is licensed under GPLv3, with the GPL font exception. OpenSansCondensed-LightItalic.tt, from https://fonts.google.com/specimen/Open+Sans, under Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0) -DejaVuSans-24-{1,2,4,8}-stripped.ttf are based on DejaVuSans.ttf converted using FontForge to add bitmap strikes and keep only the ASCII range. +chromacheck-sbix.woff, from https://github.com/RoelN/ChromaCheck, under The MIT License (MIT), Copyright (c) 2018 Roel Nieskens, https://pixelambacht.nl Copyright (c) 2018 Google LLC +KhmerOSBattambang-Regular.ttf is licensed under LGPL-2.1 or later. + +FreeMono.ttf is licensed under GPLv3. 10x20-ISO8859-1.pcf, from https://packages.ubuntu.com/xenial/xfonts-base diff --git a/Tests/fonts/chromacheck-sbix.woff b/Tests/fonts/chromacheck-sbix.woff new file mode 100644 index 000000000..518d4b7ea Binary files /dev/null and b/Tests/fonts/chromacheck-sbix.woff differ diff --git a/Tests/fonts/oom-e8e927ba6c0d38274a37c1567560eb33baf74627.ttf b/Tests/fonts/oom-e8e927ba6c0d38274a37c1567560eb33baf74627.ttf new file mode 100644 index 000000000..790132515 Binary files /dev/null and b/Tests/fonts/oom-e8e927ba6c0d38274a37c1567560eb33baf74627.ttf differ diff --git a/Tests/helper.py b/Tests/helper.py index be3bdb76f..8504993fb 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -173,6 +173,21 @@ def skip_unless_feature_version(feature, version_required, reason=None): return pytest.mark.skipif(version_available < version_required, reason=reason) +def mark_if_feature_version(mark, feature, version_blacklist, reason=None): + if not features.check(feature): + return pytest.mark.pil_noop_mark() + if reason is None: + reason = f"{feature} is {version_blacklist}" + version_required = parse_version(version_blacklist) + version_available = parse_version(features.version(feature)) + if ( + version_available.major == version_required.major + and version_available.minor == version_required.minor + ): + return mark(reason=reason) + return pytest.mark.pil_noop_mark() + + @pytest.mark.skipif(sys.platform.startswith("win32"), reason="Requires Unix or macOS") class PillowLeakTestCase: # requires unix/macOS @@ -257,8 +272,23 @@ def netpbm_available(): return bool(shutil.which("ppmquant") and shutil.which("ppmtogif")) -def imagemagick_available(): - return bool(IMCONVERT and shutil.which(IMCONVERT)) +def magick_command(): + if sys.platform == "win32": + magickhome = os.environ.get("MAGICK_HOME", "") + if magickhome: + imagemagick = [os.path.join(magickhome, "convert.exe")] + graphicsmagick = [os.path.join(magickhome, "gm.exe"), "convert"] + else: + imagemagick = None + graphicsmagick = None + else: + imagemagick = ["convert"] + graphicsmagick = ["gm", "convert"] + + if imagemagick and shutil.which(imagemagick[0]): + return imagemagick + elif graphicsmagick and shutil.which(graphicsmagick[0]): + return graphicsmagick def on_appveyor(): @@ -296,14 +326,6 @@ def is_mingw(): return sysconfig.get_platform() == "mingw" -if sys.platform == "win32": - IMCONVERT = os.environ.get("MAGICK_HOME", "") - if IMCONVERT: - IMCONVERT = os.path.join(IMCONVERT, "convert.exe") -else: - IMCONVERT = "convert" - - class cached_property: def __init__(self, func): self.func = func diff --git a/Tests/images/200x32_p_bl_raw_origin.tga b/Tests/images/200x32_p_bl_raw_origin.tga new file mode 100644 index 000000000..329f0ca4d Binary files /dev/null and b/Tests/images/200x32_p_bl_raw_origin.tga differ diff --git a/Tests/images/apng/dispose_op_previous_frame.png b/Tests/images/apng/dispose_op_previous_frame.png new file mode 100644 index 000000000..14168da89 Binary files /dev/null and b/Tests/images/apng/dispose_op_previous_frame.png differ diff --git a/Tests/images/bc5_snorm.dds b/Tests/images/bc5_snorm.dds new file mode 100644 index 000000000..7458c67c6 Binary files /dev/null and b/Tests/images/bc5_snorm.dds differ diff --git a/Tests/images/bc5_typeless.dds b/Tests/images/bc5_typeless.dds new file mode 100644 index 000000000..b5bae52bb Binary files /dev/null and b/Tests/images/bc5_typeless.dds differ diff --git a/Tests/images/bc5_unorm.dds b/Tests/images/bc5_unorm.dds new file mode 100644 index 000000000..a04a026eb Binary files /dev/null and b/Tests/images/bc5_unorm.dds differ diff --git a/Tests/images/bc5_unorm.png b/Tests/images/bc5_unorm.png new file mode 100644 index 000000000..05279ddfb Binary files /dev/null and b/Tests/images/bc5_unorm.png differ diff --git a/Tests/images/bc5s.dds b/Tests/images/bc5s.dds new file mode 100644 index 000000000..0b999eed3 Binary files /dev/null and b/Tests/images/bc5s.dds differ diff --git a/Tests/images/bc5s.png b/Tests/images/bc5s.png new file mode 100644 index 000000000..39d7811bf Binary files /dev/null and b/Tests/images/bc5s.png differ diff --git a/Tests/images/black_and_white.ico b/Tests/images/black_and_white.ico new file mode 100644 index 000000000..f98d7ac8e Binary files /dev/null and b/Tests/images/black_and_white.ico differ diff --git a/Tests/images/chromacheck-sbix.png b/Tests/images/chromacheck-sbix.png new file mode 100644 index 000000000..b906ef133 Binary files /dev/null and b/Tests/images/chromacheck-sbix.png differ diff --git a/Tests/images/chromacheck-sbix_mask.png b/Tests/images/chromacheck-sbix_mask.png new file mode 100644 index 000000000..4b68ff91b Binary files /dev/null and b/Tests/images/chromacheck-sbix_mask.png differ diff --git a/Tests/images/crash-0c7e0e8e11ce787078f00b5b0ca409a167f070e0.tif b/Tests/images/crash-0c7e0e8e11ce787078f00b5b0ca409a167f070e0.tif new file mode 100644 index 000000000..5275075e9 Binary files /dev/null and b/Tests/images/crash-0c7e0e8e11ce787078f00b5b0ca409a167f070e0.tif differ diff --git a/Tests/images/crash-0da013a13571cc8eb457a39fee8db18f8a3c7127.tif b/Tests/images/crash-0da013a13571cc8eb457a39fee8db18f8a3c7127.tif new file mode 100644 index 000000000..6e4e9b9ca Binary files /dev/null and b/Tests/images/crash-0da013a13571cc8eb457a39fee8db18f8a3c7127.tif differ diff --git a/Tests/images/crash-0e16d3bfb83be87356d026d66919deaefca44dac.tif b/Tests/images/crash-0e16d3bfb83be87356d026d66919deaefca44dac.tif new file mode 100644 index 000000000..f59aab21a Binary files /dev/null and b/Tests/images/crash-0e16d3bfb83be87356d026d66919deaefca44dac.tif differ diff --git a/Tests/images/crash-1152ec2d1a1a71395b6f2ce6721c38924d025bf3.tif b/Tests/images/crash-1152ec2d1a1a71395b6f2ce6721c38924d025bf3.tif new file mode 100644 index 000000000..c8d6e2aad Binary files /dev/null and b/Tests/images/crash-1152ec2d1a1a71395b6f2ce6721c38924d025bf3.tif differ diff --git a/Tests/images/crash-1185209cf7655b5aed8ae5e77784dfdd18ab59e9.tif b/Tests/images/crash-1185209cf7655b5aed8ae5e77784dfdd18ab59e9.tif new file mode 100644 index 000000000..ecf7db38f Binary files /dev/null and b/Tests/images/crash-1185209cf7655b5aed8ae5e77784dfdd18ab59e9.tif differ diff --git a/Tests/images/crash-2020-10-test.tif b/Tests/images/crash-2020-10-test.tif new file mode 100644 index 000000000..958cdde22 Binary files /dev/null and b/Tests/images/crash-2020-10-test.tif differ diff --git a/Tests/images/crash-338516dbd2f0e83caddb8ce256c22db3bd6dc40f.tif b/Tests/images/crash-338516dbd2f0e83caddb8ce256c22db3bd6dc40f.tif new file mode 100644 index 000000000..344d62b27 Binary files /dev/null and b/Tests/images/crash-338516dbd2f0e83caddb8ce256c22db3bd6dc40f.tif differ diff --git a/Tests/images/crash-465703f71a0f0094873a3e0e82c9f798161171b8.sgi b/Tests/images/crash-465703f71a0f0094873a3e0e82c9f798161171b8.sgi new file mode 100644 index 000000000..81ae11823 Binary files /dev/null and b/Tests/images/crash-465703f71a0f0094873a3e0e82c9f798161171b8.sgi differ diff --git a/Tests/images/crash-4f085cc12ece8cde18758d42608bed6a2a2cfb1c.tif b/Tests/images/crash-4f085cc12ece8cde18758d42608bed6a2a2cfb1c.tif new file mode 100644 index 000000000..18197c15f Binary files /dev/null and b/Tests/images/crash-4f085cc12ece8cde18758d42608bed6a2a2cfb1c.tif differ diff --git a/Tests/images/crash-4fb027452e6988530aa5dabee76eecacb3b79f8a.j2k b/Tests/images/crash-4fb027452e6988530aa5dabee76eecacb3b79f8a.j2k new file mode 100644 index 000000000..c9bd7fc0a Binary files /dev/null and b/Tests/images/crash-4fb027452e6988530aa5dabee76eecacb3b79f8a.j2k differ diff --git a/Tests/images/crash-63b1dffefc8c075ddc606c0a2f5fdc15ece78863.tif b/Tests/images/crash-63b1dffefc8c075ddc606c0a2f5fdc15ece78863.tif new file mode 100644 index 000000000..b89203f75 Binary files /dev/null and b/Tests/images/crash-63b1dffefc8c075ddc606c0a2f5fdc15ece78863.tif differ diff --git a/Tests/images/crash-64834657ee604b8797bf99eac6a194c124a9a8ba.sgi b/Tests/images/crash-64834657ee604b8797bf99eac6a194c124a9a8ba.sgi new file mode 100644 index 000000000..f31d810e4 Binary files /dev/null and b/Tests/images/crash-64834657ee604b8797bf99eac6a194c124a9a8ba.sgi differ diff --git a/Tests/images/crash-6b7f2244da6d0ae297ee0754a424213444e92778.sgi b/Tests/images/crash-6b7f2244da6d0ae297ee0754a424213444e92778.sgi new file mode 100644 index 000000000..74396935b Binary files /dev/null and b/Tests/images/crash-6b7f2244da6d0ae297ee0754a424213444e92778.sgi differ diff --git a/Tests/images/crash-74d2a78403a5a59db1fb0a2b8735ac068a75f6e3.tif b/Tests/images/crash-74d2a78403a5a59db1fb0a2b8735ac068a75f6e3.tif new file mode 100644 index 000000000..053e4e4e9 Binary files /dev/null and b/Tests/images/crash-74d2a78403a5a59db1fb0a2b8735ac068a75f6e3.tif differ diff --git a/Tests/images/crash-754d9c7ec485ffb76a90eeaab191ef69a2a3a3cd.sgi b/Tests/images/crash-754d9c7ec485ffb76a90eeaab191ef69a2a3a3cd.sgi new file mode 100644 index 000000000..8e093bdfd Binary files /dev/null and b/Tests/images/crash-754d9c7ec485ffb76a90eeaab191ef69a2a3a3cd.sgi differ diff --git a/Tests/images/crash-7d4c83eb92150fb8f1653a697703ae06ae7c4998.j2k b/Tests/images/crash-7d4c83eb92150fb8f1653a697703ae06ae7c4998.j2k new file mode 100644 index 000000000..fd2f4dd36 Binary files /dev/null and b/Tests/images/crash-7d4c83eb92150fb8f1653a697703ae06ae7c4998.j2k differ diff --git a/Tests/images/crash-86214e58da443d2b80820cff9677a38a33dcbbca.tif b/Tests/images/crash-86214e58da443d2b80820cff9677a38a33dcbbca.tif new file mode 100644 index 000000000..34e4f6014 Binary files /dev/null and b/Tests/images/crash-86214e58da443d2b80820cff9677a38a33dcbbca.tif differ diff --git a/Tests/images/crash-abcf1c97b8fe42a6c68f1fb0b978530c98d57ced.sgi b/Tests/images/crash-abcf1c97b8fe42a6c68f1fb0b978530c98d57ced.sgi new file mode 100644 index 000000000..790cb3744 Binary files /dev/null and b/Tests/images/crash-abcf1c97b8fe42a6c68f1fb0b978530c98d57ced.sgi differ diff --git a/Tests/images/crash-b82e64d4f3f76d7465b6af535283029eda211259.sgi b/Tests/images/crash-b82e64d4f3f76d7465b6af535283029eda211259.sgi new file mode 100644 index 000000000..8b7d87765 Binary files /dev/null and b/Tests/images/crash-b82e64d4f3f76d7465b6af535283029eda211259.sgi differ diff --git a/Tests/images/crash-c1b2595b8b0b92cc5f38b6635e98e3a119ade807.sgi b/Tests/images/crash-c1b2595b8b0b92cc5f38b6635e98e3a119ade807.sgi new file mode 100644 index 000000000..e9d2ca1a6 Binary files /dev/null and b/Tests/images/crash-c1b2595b8b0b92cc5f38b6635e98e3a119ade807.sgi differ diff --git a/Tests/images/crash-ccca68ff40171fdae983d924e127a721cab2bd50.j2k b/Tests/images/crash-ccca68ff40171fdae983d924e127a721cab2bd50.j2k new file mode 100644 index 000000000..c3ad0d633 Binary files /dev/null and b/Tests/images/crash-ccca68ff40171fdae983d924e127a721cab2bd50.j2k differ diff --git a/Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k b/Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k new file mode 100644 index 000000000..3aadfc377 Binary files /dev/null and b/Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k differ diff --git a/Tests/images/crash-db8bfa78b19721225425530c5946217720d7df4e.sgi b/Tests/images/crash-db8bfa78b19721225425530c5946217720d7df4e.sgi new file mode 100644 index 000000000..b02aacea9 Binary files /dev/null and b/Tests/images/crash-db8bfa78b19721225425530c5946217720d7df4e.sgi differ diff --git a/Tests/images/crash-f46f5b2f43c370fe65706c11449f567ecc345e74.tif b/Tests/images/crash-f46f5b2f43c370fe65706c11449f567ecc345e74.tif new file mode 100644 index 000000000..c6774d459 Binary files /dev/null and b/Tests/images/crash-f46f5b2f43c370fe65706c11449f567ecc345e74.tif differ diff --git a/Tests/images/different_transparency.gif b/Tests/images/different_transparency.gif new file mode 100644 index 000000000..2d36bef9e Binary files /dev/null and b/Tests/images/different_transparency.gif differ diff --git a/Tests/images/different_transparency_merged.gif b/Tests/images/different_transparency_merged.gif new file mode 100644 index 000000000..94d0f53e0 Binary files /dev/null and b/Tests/images/different_transparency_merged.gif differ diff --git a/Tests/images/dispose_prev_first_frame.gif b/Tests/images/dispose_prev_first_frame.gif new file mode 100644 index 000000000..4c19dd1ed Binary files /dev/null and b/Tests/images/dispose_prev_first_frame.gif differ diff --git a/Tests/images/dispose_prev_first_frame_seeked.gif b/Tests/images/dispose_prev_first_frame_seeked.gif new file mode 100644 index 000000000..bc3eb1393 Binary files /dev/null and b/Tests/images/dispose_prev_first_frame_seeked.gif differ diff --git a/Tests/images/drawing_roundDown.emf b/Tests/images/drawing_roundDown.emf deleted file mode 100644 index 6c3e20248..000000000 Binary files a/Tests/images/drawing_roundDown.emf and /dev/null differ diff --git a/Tests/images/dxt5-colorblock-alpha-issue-4142.dds b/Tests/images/dxt5-colorblock-alpha-issue-4142.dds new file mode 100644 index 000000000..905527ead Binary files /dev/null and b/Tests/images/dxt5-colorblock-alpha-issue-4142.dds differ diff --git a/Tests/images/first_frame_transparency.gif b/Tests/images/first_frame_transparency.gif new file mode 100644 index 000000000..86dc0de64 Binary files /dev/null and b/Tests/images/first_frame_transparency.gif differ diff --git a/Tests/images/hopper.dds b/Tests/images/hopper.dds new file mode 100644 index 000000000..8b9af9ed9 Binary files /dev/null and b/Tests/images/hopper.dds differ diff --git a/Tests/images/hopper_roundUp_2.tif b/Tests/images/hopper_float_dpi_2.tif similarity index 100% rename from Tests/images/hopper_roundUp_2.tif rename to Tests/images/hopper_float_dpi_2.tif diff --git a/Tests/images/hopper_roundUp_3.tif b/Tests/images/hopper_float_dpi_3.tif similarity index 100% rename from Tests/images/hopper_roundUp_3.tif rename to Tests/images/hopper_float_dpi_3.tif diff --git a/Tests/images/hopper_roundUp_None.tif b/Tests/images/hopper_float_dpi_None.tif similarity index 100% rename from Tests/images/hopper_roundUp_None.tif rename to Tests/images/hopper_float_dpi_None.tif diff --git a/Tests/images/hopper_naxis_zero.fits b/Tests/images/hopper_naxis_zero.fits new file mode 100644 index 000000000..580cf3a2c Binary files /dev/null and b/Tests/images/hopper_naxis_zero.fits differ diff --git a/Tests/images/hopper_resized.gif b/Tests/images/hopper_resized.gif new file mode 100644 index 000000000..f7be6c262 Binary files /dev/null and b/Tests/images/hopper_resized.gif differ diff --git a/Tests/images/hopper_roundDown.bmp b/Tests/images/hopper_roundDown.bmp deleted file mode 100644 index 62aada050..000000000 Binary files a/Tests/images/hopper_roundDown.bmp and /dev/null differ diff --git a/Tests/images/hopper_roundDown_2.tif b/Tests/images/hopper_roundDown_2.tif deleted file mode 100644 index ac8cd057d..000000000 Binary files a/Tests/images/hopper_roundDown_2.tif and /dev/null differ diff --git a/Tests/images/hopper_roundDown_3.tif b/Tests/images/hopper_roundDown_3.tif deleted file mode 100644 index 0542fab9a..000000000 Binary files a/Tests/images/hopper_roundDown_3.tif and /dev/null differ diff --git a/Tests/images/hopper_roundDown_None.tif b/Tests/images/hopper_roundDown_None.tif deleted file mode 100644 index 21c40e8fe..000000000 Binary files a/Tests/images/hopper_roundDown_None.tif and /dev/null differ diff --git a/Tests/images/ignore_frame_size.mpo b/Tests/images/ignore_frame_size.mpo new file mode 100644 index 000000000..c4d60707a Binary files /dev/null and b/Tests/images/ignore_frame_size.mpo differ diff --git a/Tests/images/imagedraw/continuous_horizontal_edges_polygon.png b/Tests/images/imagedraw/continuous_horizontal_edges_polygon.png new file mode 100644 index 000000000..beffed5b9 Binary files /dev/null and b/Tests/images/imagedraw/continuous_horizontal_edges_polygon.png differ diff --git a/Tests/images/imagedraw_rectangle_translucent_outline.png b/Tests/images/imagedraw_rectangle_translucent_outline.png new file mode 100644 index 000000000..845648762 Binary files /dev/null and b/Tests/images/imagedraw_rectangle_translucent_outline.png differ diff --git a/Tests/images/imagedraw_rounded_rectangle.png b/Tests/images/imagedraw_rounded_rectangle.png new file mode 100644 index 000000000..2e815f4ad Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle.png differ diff --git a/Tests/images/imagedraw_rounded_rectangle_both.png b/Tests/images/imagedraw_rounded_rectangle_both.png new file mode 100644 index 000000000..24f600e39 Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle_both.png differ diff --git a/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_given.png b/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_given.png new file mode 100644 index 000000000..59e55b2a1 Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_given.png differ diff --git a/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_height.png b/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_height.png new file mode 100644 index 000000000..c4e54896b Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_height.png differ diff --git a/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_width.png b/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_width.png new file mode 100644 index 000000000..6b0f11fa6 Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle_non_integer_radius_width.png differ diff --git a/Tests/images/imagedraw_rounded_rectangle_x.png b/Tests/images/imagedraw_rounded_rectangle_x.png new file mode 100644 index 000000000..4bf5211a3 Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle_x.png differ diff --git a/Tests/images/imagedraw_rounded_rectangle_y.png b/Tests/images/imagedraw_rounded_rectangle_y.png new file mode 100644 index 000000000..9b391b95e Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle_y.png differ diff --git a/Tests/images/iptc_roundDown.jpg b/Tests/images/iptc_roundDown.jpg deleted file mode 100644 index f98206f18..000000000 Binary files a/Tests/images/iptc_roundDown.jpg and /dev/null differ diff --git a/Tests/images/missing_background.gif b/Tests/images/missing_background.gif new file mode 100644 index 000000000..550d68d81 Binary files /dev/null and b/Tests/images/missing_background.gif differ diff --git a/Tests/images/missing_background_first_frame.gif b/Tests/images/missing_background_first_frame.gif new file mode 100644 index 000000000..be2c95b99 Binary files /dev/null and b/Tests/images/missing_background_first_frame.gif differ diff --git a/Tests/images/multipage_multiple_frame_loop.tiff b/Tests/images/multipage_multiple_frame_loop.tiff new file mode 100644 index 000000000..b6759b080 Binary files /dev/null and b/Tests/images/multipage_multiple_frame_loop.tiff differ diff --git a/Tests/images/multipage_out_of_order.tiff b/Tests/images/multipage_out_of_order.tiff new file mode 100644 index 000000000..1576a549b Binary files /dev/null and b/Tests/images/multipage_out_of_order.tiff differ diff --git a/Tests/images/multipage_single_frame_loop.tiff b/Tests/images/multipage_single_frame_loop.tiff new file mode 100644 index 000000000..26f27c421 Binary files /dev/null and b/Tests/images/multipage_single_frame_loop.tiff differ diff --git a/Tests/images/odd_stride.pcx b/Tests/images/odd_stride.pcx new file mode 100644 index 000000000..ee0c2eeca Binary files /dev/null and b/Tests/images/odd_stride.pcx differ diff --git a/Tests/images/old-style-jpeg-compression-no-samplesperpixel.tif b/Tests/images/old-style-jpeg-compression-no-samplesperpixel.tif new file mode 100644 index 000000000..d43ba9192 Binary files /dev/null and b/Tests/images/old-style-jpeg-compression-no-samplesperpixel.tif differ diff --git a/Tests/images/oom-8ed3316a4109213ca96fb8a256a0bfefdece1461.icns b/Tests/images/oom-8ed3316a4109213ca96fb8a256a0bfefdece1461.icns new file mode 100644 index 000000000..0521f5cf1 Binary files /dev/null and b/Tests/images/oom-8ed3316a4109213ca96fb8a256a0bfefdece1461.icns differ diff --git a/Tests/images/ossfuzz-4836216264589312.pcx b/Tests/images/ossfuzz-4836216264589312.pcx new file mode 100644 index 000000000..fdde9716a Binary files /dev/null and b/Tests/images/ossfuzz-4836216264589312.pcx differ diff --git a/Tests/images/ossfuzz-5730089102868480.sgi b/Tests/images/ossfuzz-5730089102868480.sgi new file mode 100644 index 000000000..a92c1ed01 Binary files /dev/null and b/Tests/images/ossfuzz-5730089102868480.sgi differ diff --git a/Tests/images/p_16.png b/Tests/images/p_16.png new file mode 100644 index 000000000..e35886412 Binary files /dev/null and b/Tests/images/p_16.png differ diff --git a/Tests/images/p_16.tga b/Tests/images/p_16.tga new file mode 100644 index 000000000..2b2ca4c70 Binary files /dev/null and b/Tests/images/p_16.tga differ diff --git a/Tests/images/padded_idat.png b/Tests/images/padded_idat.png new file mode 100644 index 000000000..18c5a4990 Binary files /dev/null and b/Tests/images/padded_idat.png differ diff --git a/Tests/images/sugarshack_frame_size.mpo b/Tests/images/sugarshack_frame_size.mpo index 81d58e64b..009280a79 100644 Binary files a/Tests/images/sugarshack_frame_size.mpo and b/Tests/images/sugarshack_frame_size.mpo differ diff --git a/Tests/images/tiff_strip_planar_16bit_RGB.tiff b/Tests/images/tiff_strip_planar_16bit_RGB.tiff new file mode 100644 index 000000000..360b4c165 Binary files /dev/null and b/Tests/images/tiff_strip_planar_16bit_RGB.tiff differ diff --git a/Tests/images/tiff_strip_planar_16bit_RGBa.tiff b/Tests/images/tiff_strip_planar_16bit_RGBa.tiff new file mode 100644 index 000000000..b8c3dcf64 Binary files /dev/null and b/Tests/images/tiff_strip_planar_16bit_RGBa.tiff differ diff --git a/Tests/images/tiff_strip_planar_lzw.tiff b/Tests/images/tiff_strip_planar_lzw.tiff new file mode 100644 index 000000000..8145703f4 Binary files /dev/null and b/Tests/images/tiff_strip_planar_lzw.tiff differ diff --git a/Tests/images/tiff_tiled_planar_16bit_RGB.tiff b/Tests/images/tiff_tiled_planar_16bit_RGB.tiff new file mode 100644 index 000000000..0376e90a7 Binary files /dev/null and b/Tests/images/tiff_tiled_planar_16bit_RGB.tiff differ diff --git a/Tests/images/tiff_tiled_planar_16bit_RGBa.tiff b/Tests/images/tiff_tiled_planar_16bit_RGBa.tiff new file mode 100644 index 000000000..ae7773867 Binary files /dev/null and b/Tests/images/tiff_tiled_planar_16bit_RGBa.tiff differ diff --git a/Tests/images/tiff_tiled_planar_lzw.tiff b/Tests/images/tiff_tiled_planar_lzw.tiff new file mode 100644 index 000000000..57cd6094a Binary files /dev/null and b/Tests/images/tiff_tiled_planar_lzw.tiff differ diff --git a/Tests/images/timeout-060745d3f534ad6e4128c51d336ea5489182c69d.blp b/Tests/images/timeout-060745d3f534ad6e4128c51d336ea5489182c69d.blp new file mode 100644 index 000000000..97def320f Binary files /dev/null and b/Tests/images/timeout-060745d3f534ad6e4128c51d336ea5489182c69d.blp differ diff --git a/Tests/images/timeout-1ee28a249896e05b83840ae8140622de8e648ba9.psd b/Tests/images/timeout-1ee28a249896e05b83840ae8140622de8e648ba9.psd new file mode 100644 index 000000000..63319e545 Binary files /dev/null and b/Tests/images/timeout-1ee28a249896e05b83840ae8140622de8e648ba9.psd differ diff --git a/Tests/images/timeout-31c8f86233ea728339c6e586be7af661a09b5b98.blp b/Tests/images/timeout-31c8f86233ea728339c6e586be7af661a09b5b98.blp new file mode 100644 index 000000000..73022abfc Binary files /dev/null and b/Tests/images/timeout-31c8f86233ea728339c6e586be7af661a09b5b98.blp differ diff --git a/Tests/images/timeout-598843abc37fc080ec36a2699ebbd44f795d3a6f.psd b/Tests/images/timeout-598843abc37fc080ec36a2699ebbd44f795d3a6f.psd new file mode 100644 index 000000000..c259a15e7 Binary files /dev/null and b/Tests/images/timeout-598843abc37fc080ec36a2699ebbd44f795d3a6f.psd differ diff --git a/Tests/images/timeout-60d8b7c8469d59fc9ffff6b3a3dc0faeae6ea8ee.blp b/Tests/images/timeout-60d8b7c8469d59fc9ffff6b3a3dc0faeae6ea8ee.blp new file mode 100644 index 000000000..79e97dce3 Binary files /dev/null and b/Tests/images/timeout-60d8b7c8469d59fc9ffff6b3a3dc0faeae6ea8ee.blp differ diff --git a/Tests/images/timeout-8073b430977660cdd48d96f6406ddfd4114e69c7.blp b/Tests/images/timeout-8073b430977660cdd48d96f6406ddfd4114e69c7.blp new file mode 100644 index 000000000..9b9ecbcb0 Binary files /dev/null and b/Tests/images/timeout-8073b430977660cdd48d96f6406ddfd4114e69c7.blp differ diff --git a/Tests/images/timeout-9139147ce93e20eb14088fe238e541443ffd64b3.fli b/Tests/images/timeout-9139147ce93e20eb14088fe238e541443ffd64b3.fli new file mode 100644 index 000000000..ce4607d2d Binary files /dev/null and b/Tests/images/timeout-9139147ce93e20eb14088fe238e541443ffd64b3.fli differ diff --git a/Tests/images/timeout-bba4f2e026b5786529370e5dfe9a11b1bf991f07.blp b/Tests/images/timeout-bba4f2e026b5786529370e5dfe9a11b1bf991f07.blp new file mode 100644 index 000000000..cb9a4e8b3 Binary files /dev/null and b/Tests/images/timeout-bba4f2e026b5786529370e5dfe9a11b1bf991f07.blp differ diff --git a/Tests/images/timeout-bff0a9dc7243a8e6ede2408d2ffa6a9964698b87.fli b/Tests/images/timeout-bff0a9dc7243a8e6ede2408d2ffa6a9964698b87.fli new file mode 100644 index 000000000..77a94b87a Binary files /dev/null and b/Tests/images/timeout-bff0a9dc7243a8e6ede2408d2ffa6a9964698b87.fli differ diff --git a/Tests/images/timeout-c8efc3fded6426986ba867a399791bae544f59bc.psd b/Tests/images/timeout-c8efc3fded6426986ba867a399791bae544f59bc.psd new file mode 100644 index 000000000..955fc3325 Binary files /dev/null and b/Tests/images/timeout-c8efc3fded6426986ba867a399791bae544f59bc.psd differ diff --git a/Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps b/Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps new file mode 100644 index 000000000..5000ca9aa Binary files /dev/null and b/Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps differ diff --git a/Tests/images/timeout-d6ec061c4afdef39d3edf6da8927240bb07fe9b7.blp b/Tests/images/timeout-d6ec061c4afdef39d3edf6da8927240bb07fe9b7.blp new file mode 100644 index 000000000..5044fbde1 Binary files /dev/null and b/Tests/images/timeout-d6ec061c4afdef39d3edf6da8927240bb07fe9b7.blp differ diff --git a/Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd b/Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd new file mode 100644 index 000000000..c658ea45c Binary files /dev/null and b/Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd differ diff --git a/Tests/images/timeout-ef9112a065e7183fa7faa2e18929b03e44ee16bf.blp b/Tests/images/timeout-ef9112a065e7183fa7faa2e18929b03e44ee16bf.blp new file mode 100644 index 000000000..7ef78eeec Binary files /dev/null and b/Tests/images/timeout-ef9112a065e7183fa7faa2e18929b03e44ee16bf.blp differ diff --git a/Tests/images/transparent_background_text.png b/Tests/images/transparent_background_text.png index 40acd92b6..8ddd65cc6 100644 Binary files a/Tests/images/transparent_background_text.png and b/Tests/images/transparent_background_text.png differ diff --git a/Tests/images/transparent_background_text_L.png b/Tests/images/transparent_background_text_L.png new file mode 100644 index 000000000..d37de20a7 Binary files /dev/null and b/Tests/images/transparent_background_text_L.png differ diff --git a/Tests/images/transparent_dispose.gif b/Tests/images/transparent_dispose.gif new file mode 100644 index 000000000..92b615543 Binary files /dev/null and b/Tests/images/transparent_dispose.gif differ diff --git a/Tests/images/truncated_app14.jpg b/Tests/images/truncated_app14.jpg new file mode 100644 index 000000000..232a4c35f Binary files /dev/null and b/Tests/images/truncated_app14.jpg differ diff --git a/Tests/images/uncompressed_rgb.png b/Tests/images/uncompressed_rgb.png index 50bca09ee..f02b50f6f 100644 Binary files a/Tests/images/uncompressed_rgb.png and b/Tests/images/uncompressed_rgb.png differ diff --git a/Tests/images/xmp_test.jpg b/Tests/images/xmp_test.jpg new file mode 100644 index 000000000..4b9354f3a Binary files /dev/null and b/Tests/images/xmp_test.jpg differ diff --git a/Tests/oss-fuzz/build.sh b/Tests/oss-fuzz/build.sh new file mode 100755 index 000000000..513136fff --- /dev/null +++ b/Tests/oss-fuzz/build.sh @@ -0,0 +1,48 @@ +#!/bin/bash -eu +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +python3 setup.py build --build-base=/tmp/build install + +# Build fuzzers in $OUT. +for fuzzer in $(find $SRC -name 'fuzz_*.py'); do + fuzzer_basename=$(basename -s .py $fuzzer) + fuzzer_package=${fuzzer_basename}.pkg + pyinstaller \ + --add-binary /usr/local/lib/libjpeg.so.9:. \ + --add-binary /usr/local/lib/libfreetype.so.6:. \ + --add-binary /usr/local/lib/liblcms2.so.2:. \ + --add-binary /usr/local/lib/libopenjp2.so.7:. \ + --add-binary /usr/local/lib/libpng16.so.16:. \ + --add-binary /usr/local/lib/libtiff.so.5:. \ + --add-binary /usr/local/lib/libwebp.so.7:. \ + --add-binary /usr/local/lib/libwebpdemux.so.2:. \ + --add-binary /usr/local/lib/libwebpmux.so.3:. \ + --add-binary /usr/local/lib/libxcb.so.1:. \ + --distpath $OUT --onefile --name $fuzzer_package $fuzzer + + # Create execution wrapper. + echo "#!/bin/sh +# LLVMFuzzerTestOneInput for fuzzer detection. +this_dir=\$(dirname \"\$0\") +LD_PRELOAD=\$this_dir/sanitizer_with_fuzzer.so \ +ASAN_OPTIONS=\$ASAN_OPTIONS:symbolize=1:external_symbolizer_path=\$this_dir/llvm-symbolizer:detect_leaks=0 \ +\$this_dir/$fuzzer_package \$@" > $OUT/$fuzzer_basename + chmod u+x $OUT/$fuzzer_basename +done + +find Tests/images Tests/icc -print | zip -q $OUT/fuzz_pillow_seed_corpus.zip -@ +find Tests/fonts -print | zip -q $OUT/fuzz_font_seed_corpus.zip -@ diff --git a/Tests/oss-fuzz/build_dictionaries.sh b/Tests/oss-fuzz/build_dictionaries.sh new file mode 100755 index 000000000..9aae56ca8 --- /dev/null +++ b/Tests/oss-fuzz/build_dictionaries.sh @@ -0,0 +1,33 @@ +#!/bin/bash -eu +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +# Generate image dictionaries here for each of the fuzzers and put them in the +# $OUT directory, named for the fuzzer + +git clone --depth 1 https://github.com/google/fuzzing +cat fuzzing/dictionaries/bmp.dict \ + fuzzing/dictionaries/dds.dict \ + fuzzing/dictionaries/gif.dict \ + fuzzing/dictionaries/icns.dict \ + fuzzing/dictionaries/jpeg.dict \ + fuzzing/dictionaries/jpeg2000.dict \ + fuzzing/dictionaries/pbm.dict \ + fuzzing/dictionaries/png.dict \ + fuzzing/dictionaries/psd.dict \ + fuzzing/dictionaries/tiff.dict \ + fuzzing/dictionaries/webp.dict \ + > $OUT/fuzz_pillow.dict diff --git a/Tests/oss-fuzz/fuzz_font.py b/Tests/oss-fuzz/fuzz_font.py new file mode 100755 index 000000000..e11471011 --- /dev/null +++ b/Tests/oss-fuzz/fuzz_font.py @@ -0,0 +1,41 @@ +#!/usr/bin/python3 + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys + +import atheris_no_libfuzzer as atheris +import fuzzers + + +def TestOneInput(data): + try: + fuzzers.fuzz_font(data) + except Exception: + # We're catching all exceptions because Pillow's exceptions are + # directly inheriting from Exception. + return + return + + +def main(): + fuzzers.enable_decompressionbomb_error() + atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True) + atheris.Fuzz() + fuzzers.disable_decompressionbomb_error() + + +if __name__ == "__main__": + main() diff --git a/Tests/oss-fuzz/fuzz_pillow.py b/Tests/oss-fuzz/fuzz_pillow.py new file mode 100644 index 000000000..b3c55fe22 --- /dev/null +++ b/Tests/oss-fuzz/fuzz_pillow.py @@ -0,0 +1,41 @@ +#!/usr/bin/python3 + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys + +import atheris_no_libfuzzer as atheris +import fuzzers + + +def TestOneInput(data): + try: + fuzzers.fuzz_image(data) + except Exception: + # We're catching all exceptions because Pillow's exceptions are + # directly inheriting from Exception. + return + return + + +def main(): + fuzzers.enable_decompressionbomb_error() + atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True) + atheris.Fuzz() + fuzzers.disable_decompressionbomb_error() + + +if __name__ == "__main__": + main() diff --git a/Tests/oss-fuzz/fuzzers.py b/Tests/oss-fuzz/fuzzers.py new file mode 100644 index 000000000..5786764a6 --- /dev/null +++ b/Tests/oss-fuzz/fuzzers.py @@ -0,0 +1,41 @@ +import io +import warnings + +from PIL import Image, ImageDraw, ImageFile, ImageFilter, ImageFont + + +def enable_decompressionbomb_error(): + ImageFile.LOAD_TRUNCATED_IMAGES = True + warnings.filterwarnings("ignore") + warnings.simplefilter("error", Image.DecompressionBombWarning) + + +def disable_decompressionbomb_error(): + ImageFile.LOAD_TRUNCATED_IMAGES = False + warnings.resetwarnings() + + +def fuzz_image(data): + # This will fail on some images in the corpus, as we have many + # invalid images in the test suite. + with Image.open(io.BytesIO(data)) as im: + im.rotate(45) + im.filter(ImageFilter.DETAIL) + im.save(io.BytesIO(), "BMP") + + +def fuzz_font(data): + wrapper = io.BytesIO(data) + try: + font = ImageFont.truetype(wrapper) + except OSError: + # Catch pcf/pilfonts/random garbage here. They return + # different font objects. + return + + font.getsize_multiline("ABC\nAaaa") + font.getmask("test text") + with Image.new(mode="RGBA", size=(200, 200)) as im: + draw = ImageDraw.Draw(im) + draw.multiline_textsize("ABC\nAaaa", font, stroke_width=2) + draw.text((10, 10), "Test Text", font=font, fill="#000") diff --git a/Tests/oss-fuzz/python.supp b/Tests/oss-fuzz/python.supp new file mode 100644 index 000000000..94cc87db9 --- /dev/null +++ b/Tests/oss-fuzz/python.supp @@ -0,0 +1,16 @@ +{ + + Memcheck:Cond + ... + fun:encode_current_locale +} + + +{ + + Memcheck:Cond + fun:inflate + fun:ZIPDecode + fun:_TIFFReadEncodedTileAndAllocBuffer + ... +} diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py new file mode 100644 index 000000000..629e9ac00 --- /dev/null +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -0,0 +1,62 @@ +import subprocess +import sys + +import fuzzers +import packaging +import pytest + +from PIL import Image, features + +if sys.platform.startswith("win32"): + pytest.skip("Fuzzer is linux only", allow_module_level=True) +if features.check("libjpeg_turbo"): + version = packaging.version.parse(features.version("libjpeg_turbo")) + if version.major == 2 and version.minor == 0: + pytestmark = pytest.mark.valgrind_known_error( + reason="Known failing with libjpeg_turbo 2.0" + ) + + +@pytest.mark.parametrize( + "path", + subprocess.check_output("find Tests/images -type f", shell=True).split(b"\n"), +) +def test_fuzz_images(path): + fuzzers.enable_decompressionbomb_error() + try: + with open(path, "rb") as f: + fuzzers.fuzz_image(f.read()) + assert True + except ( + OSError, + SyntaxError, + MemoryError, + ValueError, + NotImplementedError, + OverflowError, + ): + # Known exceptions that are through from Pillow + assert True + except ( + Image.DecompressionBombError, + Image.DecompressionBombWarning, + Image.UnidentifiedImageError, + ): + # Known Image.* exceptions + assert True + finally: + fuzzers.disable_decompressionbomb_error() + + +@pytest.mark.parametrize( + "path", subprocess.check_output("find Tests/fonts -type f", shell=True).split(b"\n") +) +def test_fuzz_fonts(path): + if not path: + return + with open(path, "rb") as f: + try: + fuzzers.fuzz_font(f.read()) + except (Image.DecompressionBombError, Image.DecompressionBombWarning): + pass + assert True diff --git a/Tests/test_bmp_reference.py b/Tests/test_bmp_reference.py index 19602c1e7..99e16391a 100644 --- a/Tests/test_bmp_reference.py +++ b/Tests/test_bmp_reference.py @@ -20,7 +20,7 @@ def test_bad(): either""" for f in get_files("b"): - def open(f): + with pytest.warns(None) as record: try: with Image.open(f) as im: im.load() @@ -28,7 +28,7 @@ def test_bad(): pass # Assert that there is no unclosed file warning - pytest.warns(None, open, f) + assert not record def test_questionable(): diff --git a/Tests/test_decompression_bomb.py b/Tests/test_decompression_bomb.py index 132269933..d918ef941 100644 --- a/Tests/test_decompression_bomb.py +++ b/Tests/test_decompression_bomb.py @@ -10,8 +10,7 @@ ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS class TestDecompressionBomb: - @classmethod - def teardown_class(self): + def teardown_method(self, method): Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT def test_no_warning_small_file(self): @@ -52,17 +51,21 @@ class TestDecompressionBomb: with Image.open(TEST_FILE): pass + @pytest.mark.xfail(reason="different exception") def test_exception_ico(self): with pytest.raises(Image.DecompressionBombError): - Image.open("Tests/images/decompression_bomb.ico") + with Image.open("Tests/images/decompression_bomb.ico"): + pass def test_exception_gif(self): with pytest.raises(Image.DecompressionBombError): - Image.open("Tests/images/decompression_bomb.gif") + with Image.open("Tests/images/decompression_bomb.gif"): + pass def test_exception_bmp(self): with pytest.raises(Image.DecompressionBombError): - Image.open("Tests/images/bmp/b/reallybig.bmp") + with Image.open("Tests/images/bmp/b/reallybig.bmp"): + pass class TestDecompressionCrop: diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index 2d50748bd..7fb6f59d4 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -105,6 +105,31 @@ def test_apng_dispose_region(): assert im.getpixel((64, 32)) == (0, 255, 0, 255) +def test_apng_dispose_op_previous_frame(): + # Test that the dispose settings being used are from the previous frame + # + # Image created with: + # red = Image.new("RGBA", (128, 64), (255, 0, 0, 255)) + # green = red.copy() + # green.paste(Image.new("RGBA", (64, 32), (0, 255, 0, 255))) + # blue = red.copy() + # blue.paste(Image.new("RGBA", (64, 32), (0, 255, 0, 255)), (64, 32)) + # + # red.save( + # "Tests/images/apng/dispose_op_previous_frame.png", + # save_all=True, + # append_images=[green, blue], + # disposal=[ + # PngImagePlugin.APNG_DISPOSE_OP_NONE, + # PngImagePlugin.APNG_DISPOSE_OP_PREVIOUS, + # PngImagePlugin.APNG_DISPOSE_OP_PREVIOUS + # ], + # ) + with Image.open("Tests/images/apng/dispose_op_previous_frame.png") as im: + im.seek(im.n_frames - 1) + assert im.getpixel((0, 0)) == (255, 0, 0, 255) + + def test_apng_dispose_op_background_p_mode(): with Image.open("Tests/images/apng/dispose_op_background_p_mode.png") as im: im.seek(1) @@ -224,8 +249,8 @@ def test_apng_mode(): assert im.mode == "P" im.seek(im.n_frames - 1) im = im.convert("RGBA") - assert im.getpixel((0, 0)) == (0, 255, 0, 255) - assert im.getpixel((64, 32)) == (0, 255, 0, 255) + assert im.getpixel((0, 0)) == (255, 0, 0, 0) + assert im.getpixel((64, 32)) == (255, 0, 0, 0) with Image.open("Tests/images/apng/mode_palette_1bit_alpha.png") as im: assert im.mode == "P" @@ -287,7 +312,7 @@ def test_apng_syntax_errors(): exception = e assert exception is None - with pytest.raises(SyntaxError): + with pytest.raises(OSError): with Image.open("Tests/images/apng/syntax_num_frames_high.png") as im: im.seek(im.n_frames - 1) im.load() diff --git a/Tests/test_file_blp.py b/Tests/test_file_blp.py index 94c469c7f..15bd7e4f8 100644 --- a/Tests/test_file_blp.py +++ b/Tests/test_file_blp.py @@ -1,21 +1,39 @@ +import pytest + from PIL import Image -from .helper import assert_image_equal +from .helper import assert_image_equal_tofile def test_load_blp2_raw(): with Image.open("Tests/images/blp/blp2_raw.blp") as im: - with Image.open("Tests/images/blp/blp2_raw.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/blp/blp2_raw.png") def test_load_blp2_dxt1(): with Image.open("Tests/images/blp/blp2_dxt1.blp") as im: - with Image.open("Tests/images/blp/blp2_dxt1.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1.png") def test_load_blp2_dxt1a(): with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im: - with Image.open("Tests/images/blp/blp2_dxt1a.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1a.png") + + +@pytest.mark.parametrize( + "test_file", + [ + "Tests/images/timeout-060745d3f534ad6e4128c51d336ea5489182c69d.blp", + "Tests/images/timeout-31c8f86233ea728339c6e586be7af661a09b5b98.blp", + "Tests/images/timeout-60d8b7c8469d59fc9ffff6b3a3dc0faeae6ea8ee.blp", + "Tests/images/timeout-8073b430977660cdd48d96f6406ddfd4114e69c7.blp", + "Tests/images/timeout-bba4f2e026b5786529370e5dfe9a11b1bf991f07.blp", + "Tests/images/timeout-d6ec061c4afdef39d3edf6da8927240bb07fe9b7.blp", + "Tests/images/timeout-ef9112a065e7183fa7faa2e18929b03e44ee16bf.blp", + ], +) +def test_crashes(test_file): + with open(test_file, "rb") as f: + with Image.open(f) as im: + with pytest.raises(OSError): + im.load() diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py index e2381df1e..3374fe54e 100644 --- a/Tests/test_file_bmp.py +++ b/Tests/test_file_bmp.py @@ -4,7 +4,7 @@ import pytest from PIL import BmpImagePlugin, Image -from .helper import assert_image_equal, hopper +from .helper import assert_image_equal, assert_image_equal_tofile, hopper def test_sanity(tmp_path): @@ -63,7 +63,7 @@ def test_dpi(): output.seek(0) with Image.open(output) as reloaded: - assert reloaded.info["dpi"] == dpi + assert reloaded.info["dpi"] == (72.008961115161, 72.008961115161) def test_save_bmp_with_dpi(tmp_path): @@ -71,6 +71,7 @@ def test_save_bmp_with_dpi(tmp_path): # Arrange outfile = str(tmp_path / "temp.jpg") with Image.open("Tests/images/hopper.bmp") as im: + assert im.info["dpi"] == (95.98654816726399, 95.98654816726399) # Act im.save(outfile, "JPEG", dpi=im.info["dpi"]) @@ -78,31 +79,17 @@ def test_save_bmp_with_dpi(tmp_path): # Assert with Image.open(outfile) as reloaded: reloaded.load() - assert im.info["dpi"] == reloaded.info["dpi"] - assert im.size == reloaded.size + assert reloaded.info["dpi"] == (96, 96) + assert reloaded.size == im.size assert reloaded.format == "JPEG" -def test_load_dpi_rounding(): - # Round up - with Image.open("Tests/images/hopper.bmp") as im: - assert im.info["dpi"] == (96, 96) - - # Round down - with Image.open("Tests/images/hopper_roundDown.bmp") as im: - assert im.info["dpi"] == (72, 72) - - -def test_save_dpi_rounding(tmp_path): +def test_save_float_dpi(tmp_path): outfile = str(tmp_path / "temp.bmp") with Image.open("Tests/images/hopper.bmp") as im: - im.save(outfile, dpi=(72.2, 72.2)) + im.save(outfile, dpi=(72.21216100543306, 72.21216100543306)) with Image.open(outfile) as reloaded: - assert reloaded.info["dpi"] == (72, 72) - - im.save(outfile, dpi=(72.8, 72.8)) - with Image.open(outfile) as reloaded: - assert reloaded.info["dpi"] == (73, 73) + assert reloaded.info["dpi"] == (72.21216100543306, 72.21216100543306) def test_load_dib(): @@ -111,8 +98,7 @@ def test_load_dib(): assert im.format == "DIB" assert im.get_format_mimetype() == "image/bmp" - with Image.open("Tests/images/clipboard_target.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/clipboard_target.png") def test_save_dib(tmp_path): @@ -136,5 +122,4 @@ def test_rgba_bitfields(): b, g, r = im.split()[1:] im = Image.merge("RGB", (r, g, b)) - with Image.open("Tests/images/bmp/q/rgb32bf-xbgr.bmp") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/bmp/q/rgb32bf-xbgr.bmp") diff --git a/Tests/test_file_dcx.py b/Tests/test_file_dcx.py index 818d6ed5e..58d5cbf1a 100644 --- a/Tests/test_file_dcx.py +++ b/Tests/test_file_dcx.py @@ -31,20 +31,20 @@ def test_unclosed_file(): def test_closed_file(): - def open(): + with pytest.warns(None) as record: im = Image.open(TEST_FILE) im.load() im.close() - pytest.warns(None, open) + assert not record def test_context_manager(): - def open(): + with pytest.warns(None) as record: with Image.open(TEST_FILE) as im: im.load() - pytest.warns(None, open) + assert not record def test_invalid_file(): diff --git a/Tests/test_file_dds.py b/Tests/test_file_dds.py index 1cd7a1be7..46ebcad0c 100644 --- a/Tests/test_file_dds.py +++ b/Tests/test_file_dds.py @@ -5,16 +5,21 @@ import pytest from PIL import DdsImagePlugin, Image -from .helper import assert_image_equal +from .helper import assert_image_equal, assert_image_equal_tofile, hopper TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds" TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds" TEST_FILE_DXT5 = "Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds" +TEST_FILE_DX10_BC5_TYPELESS = "Tests/images/bc5_typeless.dds" +TEST_FILE_DX10_BC5_UNORM = "Tests/images/bc5_unorm.dds" +TEST_FILE_DX10_BC5_SNORM = "Tests/images/bc5_snorm.dds" +TEST_FILE_BC5S = "Tests/images/bc5s.dds" TEST_FILE_DX10_BC7 = "Tests/images/bc7-argb-8bpp_MipMaps-1.dds" TEST_FILE_DX10_BC7_UNORM_SRGB = "Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds" TEST_FILE_DX10_R8G8B8A8 = "Tests/images/argb-32bpp_MipMaps-1.dds" TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB = "Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.dds" -TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/uncompressed_rgb.dds" +TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/hopper.dds" +TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds" def test_sanity_dxt1(): @@ -31,6 +36,19 @@ def test_sanity_dxt1(): assert_image_equal(im, target) +def test_sanity_dxt3(): + """Check DXT3 images can be opened""" + + with Image.open(TEST_FILE_DXT3) as im: + im.load() + + assert im.format == "DDS" + assert im.mode == "RGBA" + assert im.size == (256, 256) + + assert_image_equal_tofile(im, TEST_FILE_DXT3.replace(".dds", ".png")) + + def test_sanity_dxt5(): """Check DXT5 images can be opened""" @@ -41,22 +59,31 @@ def test_sanity_dxt5(): assert im.mode == "RGBA" assert im.size == (256, 256) - with Image.open(TEST_FILE_DXT5.replace(".dds", ".png")) as target: - assert_image_equal(target, im) + assert_image_equal_tofile(im, TEST_FILE_DXT5.replace(".dds", ".png")) -def test_sanity_dxt3(): - """Check DXT3 images can be opened""" +@pytest.mark.parametrize( + ("image_path", "expected_path"), + ( + # hexeditted to be typeless + (TEST_FILE_DX10_BC5_TYPELESS, TEST_FILE_DX10_BC5_UNORM), + (TEST_FILE_DX10_BC5_UNORM, TEST_FILE_DX10_BC5_UNORM), + # hexeditted to use DX10 FourCC + (TEST_FILE_DX10_BC5_SNORM, TEST_FILE_BC5S), + (TEST_FILE_BC5S, TEST_FILE_BC5S), + ), +) +def test_dx10_bc5(image_path, expected_path): + """Check DX10 BC5 images can be opened""" - with Image.open(TEST_FILE_DXT3.replace(".dds", ".png")) as target: - with Image.open(TEST_FILE_DXT3) as im: - im.load() + with Image.open(image_path) as im: + im.load() - assert im.format == "DDS" - assert im.mode == "RGBA" - assert im.size == (256, 256) + assert im.format == "DDS" + assert im.mode == "RGB" + assert im.size == (256, 256) - assert_image_equal(target, im) + assert_image_equal_tofile(im, expected_path.replace(".dds", ".png")) def test_dx10_bc7(): @@ -69,8 +96,7 @@ def test_dx10_bc7(): assert im.mode == "RGBA" assert im.size == (256, 256) - with Image.open(TEST_FILE_DX10_BC7.replace(".dds", ".png")) as target: - assert_image_equal(target, im) + assert_image_equal_tofile(im, TEST_FILE_DX10_BC7.replace(".dds", ".png")) def test_dx10_bc7_unorm_srgb(): @@ -84,10 +110,9 @@ def test_dx10_bc7_unorm_srgb(): assert im.size == (16, 16) assert im.info["gamma"] == 1 / 2.2 - with Image.open( - TEST_FILE_DX10_BC7_UNORM_SRGB.replace(".dds", ".png") - ) as target: - assert_image_equal(target, im) + assert_image_equal_tofile( + im, TEST_FILE_DX10_BC7_UNORM_SRGB.replace(".dds", ".png") + ) def test_dx10_r8g8b8a8(): @@ -100,8 +125,7 @@ def test_dx10_r8g8b8a8(): assert im.mode == "RGBA" assert im.size == (256, 256) - with Image.open(TEST_FILE_DX10_R8G8B8A8.replace(".dds", ".png")) as target: - assert_image_equal(target, im) + assert_image_equal_tofile(im, TEST_FILE_DX10_R8G8B8A8.replace(".dds", ".png")) def test_dx10_r8g8b8a8_unorm_srgb(): @@ -115,50 +139,58 @@ def test_dx10_r8g8b8a8_unorm_srgb(): assert im.size == (16, 16) assert im.info["gamma"] == 1 / 2.2 - with Image.open( - TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB.replace(".dds", ".png") - ) as target: - assert_image_equal(target, im) + assert_image_equal_tofile( + im, TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB.replace(".dds", ".png") + ) def test_unimplemented_dxgi_format(): with pytest.raises(NotImplementedError): - Image.open("Tests/images/unimplemented_dxgi_format.dds") + with Image.open("Tests/images/unimplemented_dxgi_format.dds"): + pass def test_uncompressed_rgb(): """Check uncompressed RGB images can be opened""" + # convert -format dds -define dds:compression=none hopper.jpg hopper.dds with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im: - im.load() + assert im.format == "DDS" + assert im.mode == "RGB" + assert im.size == (128, 128) + assert_image_equal_tofile(im, "Tests/images/hopper.png") + + # Test image with alpha + with Image.open(TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA) as im: assert im.format == "DDS" assert im.mode == "RGBA" assert im.size == (800, 600) - with Image.open(TEST_FILE_UNCOMPRESSED_RGB.replace(".dds", ".png")) as target: - assert_image_equal(target, im) + assert_image_equal_tofile( + im, TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA.replace(".dds", ".png") + ) -def test__validate_true(): +def test__accept_true(): """Check valid prefix""" # Arrange prefix = b"DDS etc" # Act - output = DdsImagePlugin._validate(prefix) + output = DdsImagePlugin._accept(prefix) # Assert assert output -def test__validate_false(): +def test__accept_false(): """Check invalid prefix""" # Arrange prefix = b"something invalid" # Act - output = DdsImagePlugin._validate(prefix) + output = DdsImagePlugin._accept(prefix) # Assert assert not output @@ -170,7 +202,8 @@ def test_short_header(): img_file = f.read() def short_header(): - Image.open(BytesIO(img_file[:119])) + with Image.open(BytesIO(img_file[:119])): + pass # pragma: no cover with pytest.raises(OSError): short_header() @@ -190,6 +223,46 @@ def test_short_file(): short_file() +def test_dxt5_colorblock_alpha_issue_4142(): + """ Check that colorblocks are decoded correctly in DXT5""" + + with Image.open("Tests/images/dxt5-colorblock-alpha-issue-4142.dds") as im: + px = im.getpixel((0, 0)) + assert px[0] != 0 + assert px[1] != 0 + assert px[2] != 0 + + px = im.getpixel((1, 0)) + assert px[0] != 0 + assert px[1] != 0 + assert px[2] != 0 + + def test_unimplemented_pixel_format(): with pytest.raises(NotImplementedError): - Image.open("Tests/images/unimplemented_pixel_format.dds") + with Image.open("Tests/images/unimplemented_pixel_format.dds"): + pass + + +def test_save_unsupported_mode(tmp_path): + out = str(tmp_path / "temp.dds") + im = hopper("HSV") + with pytest.raises(OSError): + im.save(out) + + +@pytest.mark.parametrize( + ("mode", "test_file"), + [ + ("RGB", "Tests/images/hopper.png"), + ("RGBA", "Tests/images/pil123rgba.png"), + ], +) +def test_save(mode, test_file, tmp_path): + out = str(tmp_path / "temp.dds") + with Image.open(test_file) as im: + assert im.mode == mode + im.save(out) + + with Image.open(out) as reloaded: + assert_image_equal(im, reloaded) diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index f585a0669..1994a124c 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -4,7 +4,13 @@ import pytest from PIL import EpsImagePlugin, Image, features -from .helper import assert_image_similar, hopper, skip_unless_feature +from .helper import ( + assert_image_similar, + assert_image_similar_tofile, + hopper, + mark_if_feature_version, + skip_unless_feature, +) HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript() @@ -59,6 +65,9 @@ def test_invalid_file(): EpsImagePlugin.EpsImageFile(invalid_file) +@mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" +) @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") def test_cmyk(): with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image: @@ -71,8 +80,9 @@ def test_cmyk(): assert cmyk_image.mode == "RGB" if features.check("jpg"): - with Image.open("Tests/images/pil_sample_rgb.jpg") as target: - assert_image_similar(cmyk_image, target, 10) + assert_image_similar_tofile( + cmyk_image, "Tests/images/pil_sample_rgb.jpg", 10 + ) @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @@ -257,3 +267,15 @@ def test_emptyline(): assert image.mode == "RGB" assert image.size == (460, 352) assert image.format == "EPS" + + +@pytest.mark.timeout(timeout=5) +@pytest.mark.parametrize( + "test_file", + ["Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps"], +) +def test_timeout(test_file): + with open(test_file, "rb") as f: + with pytest.raises(Image.UnidentifiedImageError): + with Image.open(f): + pass diff --git a/Tests/test_file_fitsstub.py b/Tests/test_file_fitsstub.py index 6dc7c4602..c77457947 100644 --- a/Tests/test_file_fitsstub.py +++ b/Tests/test_file_fitsstub.py @@ -1,3 +1,5 @@ +from io import BytesIO + import pytest from PIL import FitsStubImagePlugin, Image @@ -11,10 +13,8 @@ def test_open(): # Assert assert im.format == "FITS" - - # Dummy data from the stub - assert im.mode == "F" - assert im.size == (1, 1) + assert im.size == (128, 128) + assert im.mode == "L" def test_invalid_file(): @@ -35,6 +35,21 @@ def test_load(): im.load() +def test_truncated_fits(): + # No END to headers + image_data = b"SIMPLE = T" + b" " * 50 + b"TRUNCATE" + with pytest.raises(OSError): + FitsStubImagePlugin.FITSStubImageFile(BytesIO(image_data)) + + +def test_naxis_zero(): + # This test image has been manually hexedited + # to set the number of data axes to zero + with pytest.raises(ValueError): + with Image.open("Tests/images/hopper_naxis_zero.fits"): + pass + + def test_save(): # Arrange with Image.open(TEST_FILE) as im: diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index 16b3dc59a..1c1abf2b1 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -2,7 +2,7 @@ import pytest from PIL import FliImagePlugin, Image -from .helper import assert_image_equal, is_pypy +from .helper import assert_image_equal_tofile, is_pypy # created as an export of a palette image from Gimp2.6 # save as...-> hopper.fli, default options. @@ -38,20 +38,20 @@ def test_unclosed_file(): def test_closed_file(): - def open(): + with pytest.warns(None) as record: im = Image.open(static_test_file) im.load() im.close() - pytest.warns(None, open) + assert not record def test_context_manager(): - def open(): + with pytest.warns(None) as record: with Image.open(static_test_file) as im: im.load() - pytest.warns(None, open) + assert not record def test_tell(): @@ -122,5 +122,19 @@ def test_seek(): with Image.open(animated_test_file) as im: im.seek(50) - with Image.open("Tests/images/a_fli.png") as expected: - assert_image_equal(im, expected) + assert_image_equal_tofile(im, "Tests/images/a_fli.png") + + +@pytest.mark.parametrize( + "test_file", + [ + "Tests/images/timeout-9139147ce93e20eb14088fe238e541443ffd64b3.fli", + "Tests/images/timeout-bff0a9dc7243a8e6ede2408d2ffa6a9964698b87.fli", + ], +) +@pytest.mark.timeout(timeout=3) +def test_timeouts(test_file): + with open(test_file, "rb") as f: + with Image.open(f) as im: + with pytest.raises(OSError): + im.load() diff --git a/Tests/test_file_fpx.py b/Tests/test_file_fpx.py index c3cc37ddf..818565f88 100644 --- a/Tests/test_file_fpx.py +++ b/Tests/test_file_fpx.py @@ -21,4 +21,5 @@ def test_invalid_file(): def test_fpx_invalid_number_of_bands(): with pytest.raises(OSError, match="Invalid number of bands"): - Image.open("Tests/images/input_bw_five_bands.fpx") + with Image.open("Tests/images/input_bw_five_bands.fpx"): + pass diff --git a/Tests/test_file_ftex.py b/Tests/test_file_ftex.py index 9b4375cd4..f76fd895a 100644 --- a/Tests/test_file_ftex.py +++ b/Tests/test_file_ftex.py @@ -1,12 +1,11 @@ from PIL import Image -from .helper import assert_image_equal, assert_image_similar +from .helper import assert_image_equal_tofile, assert_image_similar def test_load_raw(): with Image.open("Tests/images/ftex_uncompressed.ftu") as im: - with Image.open("Tests/images/ftex_uncompressed.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/ftex_uncompressed.png") def test_load_dxt1(): diff --git a/Tests/test_file_gbr.py b/Tests/test_file_gbr.py index 760f12e4d..8d7fcf147 100644 --- a/Tests/test_file_gbr.py +++ b/Tests/test_file_gbr.py @@ -2,7 +2,7 @@ import pytest from PIL import GbrImagePlugin, Image -from .helper import assert_image_equal +from .helper import assert_image_equal_tofile def test_invalid_file(): @@ -14,13 +14,11 @@ def test_invalid_file(): def test_gbr_file(): with Image.open("Tests/images/gbr.gbr") as im: - with Image.open("Tests/images/gbr.png") as target: - assert_image_equal(target, im) + assert_image_equal_tofile(im, "Tests/images/gbr.png") def test_multiple_load_operations(): with Image.open("Tests/images/gbr.gbr") as im: im.load() im.load() - with Image.open("Tests/images/gbr.png") as target: - assert_image_equal(target, im) + assert_image_equal_tofile(im, "Tests/images/gbr.png") diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 833294d81..2632ab7c0 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -6,6 +6,7 @@ from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette, features from .helper import ( assert_image_equal, + assert_image_equal_tofile, assert_image_similar, hopper, is_pypy, @@ -38,20 +39,20 @@ def test_unclosed_file(): def test_closed_file(): - def open(): + with pytest.warns(None) as record: im = Image.open(TEST_GIF) im.load() im.close() - pytest.warns(None, open) + assert not record def test_context_manager(): - def open(): + with pytest.warns(None) as record: with Image.open(TEST_GIF) as im: im.load() - pytest.warns(None, open) + assert not record def test_invalid_file(): @@ -74,10 +75,10 @@ def test_optimize(): im.save(test_file, "GIF", optimize=optimize) return len(test_file.getvalue()) - assert test_grayscale(0) == 800 - assert test_grayscale(1) == 44 - assert test_bilevel(0) == 800 - assert test_bilevel(1) == 800 + assert test_grayscale(0) == 799 + assert test_grayscale(1) == 43 + assert test_bilevel(0) == 799 + assert test_bilevel(1) == 799 def test_optimize_correctness(): @@ -297,6 +298,12 @@ def test_eoferror(): im.seek(n_frames - 1) +def test_first_frame_transparency(): + with Image.open("Tests/images/first_frame_transparency.gif") as im: + px = im.load() + assert px[0, 0] == im.info["transparency"] + + def test_dispose_none(): with Image.open("Tests/images/dispose_none.gif") as img: try: @@ -317,8 +324,7 @@ def test_dispose_none_load_end(): with Image.open("Tests/images/dispose_none_load_end.gif") as img: img.seek(1) - with Image.open("Tests/images/dispose_none_load_end_second.gif") as expected: - assert_image_equal(img, expected) + assert_image_equal_tofile(img, "Tests/images/dispose_none_load_end_second.gif") def test_dispose_background(): @@ -331,6 +337,16 @@ def test_dispose_background(): pass +def test_transparent_dispose(): + expected_colors = [(2, 1, 2), (0, 1, 0), (2, 1, 2)] + with Image.open("Tests/images/transparent_dispose.gif") as img: + for frame in range(3): + img.seek(frame) + for x in range(3): + color = img.getpixel((x, 0)) + assert color == expected_colors[frame][x] + + def test_dispose_previous(): with Image.open("Tests/images/dispose_prev.gif") as img: try: @@ -341,6 +357,25 @@ def test_dispose_previous(): pass +def test_dispose_previous_first_frame(): + with Image.open("Tests/images/dispose_prev_first_frame.gif") as im: + im.seek(1) + assert_image_equal_tofile( + im, "Tests/images/dispose_prev_first_frame_seeked.gif" + ) + + +def test_previous_frame_loaded(): + with Image.open("Tests/images/dispose_none.gif") as img: + img.load() + img.seek(1) + img.load() + img.seek(2) + with Image.open("Tests/images/dispose_none.gif") as img_skipped: + img_skipped.seek(2) + assert_image_equal(img_skipped, img) + + def test_save_dispose(tmp_path): out = str(tmp_path / "temp.gif") im_list = [ @@ -373,14 +408,15 @@ def test_save_dispose(tmp_path): def test_dispose2_palette(tmp_path): out = str(tmp_path / "temp.gif") - # 4 backgrounds: White, Grey, Black, Red + # Four colors: white, grey, black, red circles = [(255, 255, 255), (153, 153, 153), (0, 0, 0), (255, 0, 0)] im_list = [] for circle in circles: + # Red background img = Image.new("RGB", (100, 100), (255, 0, 0)) - # Red circle in center of each frame + # Circle in center of each frame d = ImageDraw.Draw(img) d.ellipse([(40, 40), (60, 60)], fill=circle) @@ -468,12 +504,25 @@ def test_dispose2_background(tmp_path): assert im.getpixel((0, 0)) == 0 -def test_iss634(): +def test_transparency_in_second_frame(): + with Image.open("Tests/images/different_transparency.gif") as im: + assert im.info["transparency"] == 0 + + # Seek to the second frame + im.seek(im.tell() + 1) + assert im.info["transparency"] == 0 + + assert_image_equal_tofile(im, "Tests/images/different_transparency_merged.gif") + + +def test_no_transparency_in_second_frame(): with Image.open("Tests/images/iss634.gif") as img: # Seek to the second frame img.seek(img.tell() + 1) + assert "transparency" not in img.info + # All transparent pixels should be replaced with the color from the first frame - assert img.histogram()[img.info["transparency"]] == 0 + assert img.histogram()[255] == 0 def test_duration(tmp_path): @@ -629,8 +678,7 @@ def test_comment_over_255(tmp_path): def test_zero_comment_subblocks(): with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im: - with Image.open(TEST_GIF) as expected: - assert_image_equal(im, expected) + assert_image_equal_tofile(im, TEST_GIF) def test_version(tmp_path): @@ -718,10 +766,10 @@ def test_rgb_transparency(tmp_path): # Single frame im = Image.new("RGB", (1, 1)) im.info["transparency"] = (255, 0, 0) - pytest.warns(UserWarning, im.save, out) + im.save(out) with Image.open(out) as reloaded: - assert "transparency" not in reloaded.info + assert "transparency" in reloaded.info # Multiple frames im = Image.new("RGB", (1, 1)) @@ -841,3 +889,11 @@ def test_extents(): assert im.size == (100, 100) im.seek(1) assert im.size == (150, 150) + + +def test_missing_background(): + # The Global Color Table Flag isn't set, so there is no background color index, + # but the disposal method is "Restore to background color" + with Image.open("Tests/images/missing_background.gif") as im: + im.seek(1) + assert_image_equal_tofile(im, "Tests/images/missing_background_first_frame.gif") diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index eb9448bfe..47de38d06 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -4,7 +4,7 @@ import pytest from PIL import IcnsImagePlugin, Image, features -from .helper import assert_image_equal, assert_image_similar +from .helper import assert_image_equal, assert_image_similar_tofile # sample icon file TEST_FILE = "Tests/images/pillow.icns" @@ -18,7 +18,9 @@ def test_sanity(): with Image.open(TEST_FILE) as im: # Assert that there is no unclosed file warning - pytest.warns(None, im.load) + with pytest.warns(None) as record: + im.load() + assert not record assert im.mode == "RGBA" assert im.size == (1024, 1024) @@ -44,8 +46,7 @@ def test_save_append_images(tmp_path): with Image.open(TEST_FILE) as im: im.save(temp_file, append_images=[provided_im]) - with Image.open(temp_file) as reread: - assert_image_similar(reread, im, 1) + assert_image_similar_tofile(im, temp_file, 1) with Image.open(temp_file) as reread: reread.size = (16, 16, 2) @@ -135,3 +136,11 @@ def test_not_an_icns_file(): with io.BytesIO(b"invalid\n") as fp: with pytest.raises(SyntaxError): IcnsImagePlugin.IcnsFile(fp) + + +def test_icns_decompression_bomb(): + with Image.open( + "Tests/images/oom-8ed3316a4109213ca96fb8a256a0bfefdece1461.icns" + ) as im: + with pytest.raises(Image.DecompressionBombError): + im.load() diff --git a/Tests/test_file_ico.py b/Tests/test_file_ico.py index 940001a21..8060d1b76 100644 --- a/Tests/test_file_ico.py +++ b/Tests/test_file_ico.py @@ -4,7 +4,7 @@ import pytest from PIL import IcoImagePlugin, Image, ImageDraw -from .helper import assert_image_equal, hopper +from .helper import assert_image_equal, assert_image_equal_tofile, hopper TEST_ICO_FILE = "Tests/images/hopper.ico" @@ -18,6 +18,12 @@ def test_sanity(): assert im.get_format_mimetype() == "image/x-icon" +def test_black_and_white(): + with Image.open("Tests/images/black_and_white.ico") as im: + assert im.mode == "RGBA" + assert im.size == (16, 16) + + def test_invalid_file(): with open("Tests/images/flower.jpg", "rb") as fp: with pytest.raises(SyntaxError): @@ -50,6 +56,35 @@ def test_save_to_bytes(): assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS)) +@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA")) +def test_save_to_bytes_bmp(mode): + output = io.BytesIO() + im = hopper(mode) + im.save(output, "ico", bitmap_format="bmp", sizes=[(32, 32), (64, 64)]) + + # The default image + output.seek(0) + with Image.open(output) as reloaded: + assert reloaded.info["sizes"] == {(32, 32), (64, 64)} + + assert "RGBA" == reloaded.mode + assert (64, 64) == reloaded.size + assert reloaded.format == "ICO" + im = hopper(mode).resize((64, 64), Image.LANCZOS).convert("RGBA") + assert_image_equal(reloaded, im) + + # The other one + output.seek(0) + with Image.open(output) as reloaded: + reloaded.size = (32, 32) + + assert "RGBA" == reloaded.mode + assert (32, 32) == reloaded.size + assert reloaded.format == "ICO" + im = hopper(mode).resize((32, 32), Image.LANCZOS).convert("RGBA") + assert_image_equal(reloaded, im) + + def test_incorrect_size(): with Image.open(TEST_ICO_FILE) as im: with pytest.raises(ValueError): @@ -119,6 +154,4 @@ def test_draw_reloaded(tmp_path): im.save(outfile) with Image.open(outfile) as im: - im.save("Tests/images/hopper_draw.ico") - with Image.open("Tests/images/hopper_draw.ico") as reloaded: - assert_image_equal(im, reloaded) + assert_image_equal_tofile(im, "Tests/images/hopper_draw.ico") diff --git a/Tests/test_file_im.py b/Tests/test_file_im.py index afea82359..9d25a4d1a 100644 --- a/Tests/test_file_im.py +++ b/Tests/test_file_im.py @@ -4,7 +4,7 @@ import pytest from PIL import Image, ImImagePlugin -from .helper import assert_image_equal, hopper, is_pypy +from .helper import assert_image_equal_tofile, hopper, is_pypy # sample im TEST_IM = "Tests/images/hopper.im" @@ -35,20 +35,20 @@ def test_unclosed_file(): def test_closed_file(): - def open(): + with pytest.warns(None) as record: im = Image.open(TEST_IM) im.load() im.close() - pytest.warns(None, open) + assert not record def test_context_manager(): - def open(): + with pytest.warns(None) as record: with Image.open(TEST_IM) as im: im.load() - pytest.warns(None, open) + assert not record def test_tell(): @@ -86,8 +86,7 @@ def test_roundtrip(tmp_path): out = str(tmp_path / "temp.im") im = hopper(mode) im.save(out) - with Image.open(out) as reread: - assert_image_equal(reread, im) + assert_image_equal_tofile(im, out) for mode in ["RGB", "P", "PA"]: roundtrip(mode) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index ff469d15c..a090d73e4 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -17,11 +17,14 @@ from PIL import ( from .helper import ( assert_image, assert_image_equal, + assert_image_equal_tofile, assert_image_similar, + assert_image_similar_tofile, cjpeg_available, djpeg_available, hopper, is_win32, + mark_if_feature_version, skip_unless_feature, ) @@ -114,6 +117,9 @@ class TestFileJpeg: assert test(100, 200) == (100, 200) assert test(0) is None # square pixels + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_icc(self, tmp_path): # Test ICC support with Image.open("Tests/images/rgb.jpg") as im1: @@ -153,6 +159,9 @@ class TestFileJpeg: test(ImageFile.MAXBLOCK + 1) # full buffer block plus one byte test(ImageFile.MAXBLOCK * 4 + 3) # large block + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_large_icc_meta(self, tmp_path): # https://github.com/python-pillow/Pillow/issues/148 # Sometimes the meta data on the icc_profile block is bigger than @@ -260,11 +269,11 @@ class TestFileJpeg: assert exif[0x0112] == Image.TRANSVERSE # Assert that the GPS IFD is present and empty - assert exif[0x8825] == {} + assert exif.get_ifd(0x8825) == {} transposed = ImageOps.exif_transpose(im) exif = transposed.getexif() - assert exif[0x8825] == {} + assert exif.get_ifd(0x8825) == {} # Assert that it was transposed assert 0x0112 not in exif @@ -419,6 +428,9 @@ class TestFileJpeg: with Image.open(filename): pass + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_truncated_jpeg_should_read_all_the_data(self): filename = "Tests/images/truncated_jpeg.jpg" ImageFile.LOAD_TRUNCATED_IMAGES = True @@ -437,6 +449,9 @@ class TestFileJpeg: with pytest.raises(OSError): im.load() + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_qtables(self, tmp_path): def _n_qtables_helper(n, test_file): with Image.open(test_file) as im: @@ -573,7 +588,7 @@ class TestFileJpeg: def test_load_djpeg(self): with Image.open(TEST_FILE) as img: img.load_djpeg() - assert_image_similar(img, Image.open(TEST_FILE), 5) + assert_image_similar_tofile(img, TEST_FILE, 5) @pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available") def test_save_cjpeg(self, tmp_path): @@ -581,7 +596,7 @@ class TestFileJpeg: tempfile = str(tmp_path / "temp.jpg") JpegImagePlugin._save_cjpeg(img, 0, tempfile) # Default save quality is 75%, so a tiny bit of difference is alright - assert_image_similar(img, Image.open(tempfile), 17) + assert_image_similar_tofile(img, tempfile, 17) def test_no_duplicate_0x1001_tag(self): # Arrange @@ -641,15 +656,6 @@ class TestFileJpeg: reloaded.load() assert im.info["dpi"] == reloaded.info["dpi"] - def test_load_dpi_rounding(self): - # Round up - with Image.open("Tests/images/iptc_roundUp.jpg") as im: - assert im.info["dpi"] == (44, 44) - - # Round down - with Image.open("Tests/images/iptc_roundDown.jpg") as im: - assert im.info["dpi"] == (2, 2) - def test_save_dpi_rounding(self, tmp_path): outfile = str(tmp_path / "temp.jpg") with Image.open("Tests/images/hopper.jpg") as im: @@ -720,6 +726,9 @@ class TestFileJpeg: # OSError for unidentified image. assert im.info.get("dpi") == (72, 72) + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_exif_x_resolution(self, tmp_path): with Image.open("Tests/images/flower.jpg") as im: exif = im.getexif() @@ -728,7 +737,7 @@ class TestFileJpeg: out = str(tmp_path / "out.jpg") with pytest.warns(None) as record: im.save(out, exif=exif) - assert len(record) == 0 + assert not record with Image.open(out) as reloaded: assert reloaded.getexif()[282] == 180 @@ -750,6 +759,9 @@ class TestFileJpeg: # Act / Assert assert im._getexif()[306] == "2017:03:13 23:03:09" + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_photoshop(self): with Image.open("Tests/images/photoshop-200dpi.jpg") as im: assert im.info["photoshop"][0x03ED] == { @@ -761,8 +773,7 @@ class TestFileJpeg: # Test that the image can still load, even with broken Photoshop data # This image had the APP13 length hexedited to be smaller - with Image.open("Tests/images/photoshop-200dpi-broken.jpg") as im_broken: - assert_image_equal(im_broken, im) + assert_image_equal_tofile(im, "Tests/images/photoshop-200dpi-broken.jpg") # This image does not contain a Photoshop header string with Image.open("Tests/images/app13.jpg") as im: @@ -775,6 +786,20 @@ class TestFileJpeg: apps_13_lengths = [len(v) for k, v in im.applist if k == "APP13"] assert [65504, 24] == apps_13_lengths + def test_adobe_transform(self): + with Image.open("Tests/images/pil_sample_rgb.jpg") as im: + assert im.info["adobe_transform"] == 1 + + with Image.open("Tests/images/pil_sample_cmyk.jpg") as im: + assert im.info["adobe_transform"] == 2 + + # This image has been manually hexedited + # so that the APP14 reports its length to be 11, + # leaving no room for "adobe_transform" + with Image.open("Tests/images/truncated_app14.jpg") as im: + assert "adobe" in im.info + assert "adobe_transform" not in im.info + def test_icc_after_SOF(self): with Image.open("Tests/images/icc-after-SOF.jpg") as im: assert im.info["icc_profile"] == b"profile" @@ -792,11 +817,35 @@ class TestFileJpeg: buffer.read = read with pytest.raises(UnidentifiedImageError): - Image.open(buffer) + with Image.open(buffer): + pass # Assert the entire file has not been read assert 0 < buffer.max_pos < size + def test_getxmp(self): + with Image.open("Tests/images/xmp_test.jpg") as im: + xmp = im.getxmp() + + assert isinstance(xmp, dict) + + description = xmp["xmpmeta"]["RDF"]["Description"] + assert description["DerivedFrom"] == { + "documentID": "8367D410E636EA95B7DE7EBA1C43A412", + "originalDocumentID": "8367D410E636EA95B7DE7EBA1C43A412", + } + assert description["Look"]["Description"]["Group"]["Alt"]["li"] == { + "lang": "x-default", + "text": "Profiles", + } + assert description["ToneCurve"]["Seq"]["li"] == ["0, 0", "255, 255"] + + # Attribute + assert description["Version"] == "10.4" + + with Image.open("Tests/images/hopper.jpg") as im: + assert im.getxmp() == {} + @pytest.mark.skipif(not is_win32(), reason="Windows only") @skip_unless_feature("jpg") diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index c9e37f8b0..20280a579 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -1,3 +1,4 @@ +import os import re from io import BytesIO @@ -8,10 +9,13 @@ from PIL import Image, ImageFile, Jpeg2KImagePlugin, features from .helper import ( assert_image_equal, assert_image_similar, + assert_image_similar_tofile, is_big_endian, skip_unless_feature, ) +EXTRA_DIR = "Tests/images/jpeg2000" + pytestmark = skip_unless_feature("jpg_2000") test_card = Image.open("Tests/images/test-card.png") @@ -62,9 +66,7 @@ def test_invalid_file(): def test_bytesio(): with open("Tests/images/test-card-lossless.jp2", "rb") as f: data = BytesIO(f.read()) - with Image.open(data) as im: - im.load() - assert_image_similar(im, test_card, 1.0e-3) + assert_image_similar_tofile(test_card, data, 1.0e-3) # These two test pre-written JPEG 2000 files that were not written with @@ -80,9 +82,9 @@ def test_lossless(tmp_path): def test_lossy_tiled(): - with Image.open("Tests/images/test-card-lossy-tiled.jp2") as im: - im.load() - assert_image_similar(im, test_card, 2.0) + assert_image_similar_tofile( + test_card, "Tests/images/test-card-lossy-tiled.jp2", 2.0 + ) def test_lossless_rt(): @@ -125,6 +127,16 @@ def test_prog_res_rt(): assert_image_equal(im, test_card) +def test_default_num_resolutions(): + for num_resolutions in range(2, 6): + d = 1 << (num_resolutions - 1) + im = test_card.resize((d - 1, d - 1)) + with pytest.raises(OSError): + roundtrip(im, num_resolutions=num_resolutions) + reloaded = roundtrip(im) + assert_image_equal(im, reloaded) + + def test_reduce(): with Image.open("Tests/images/test-card-lossless.jp2") as im: assert callable(im.reduce) @@ -193,15 +205,13 @@ def test_16bit_monochrome_has_correct_mode(): @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_16bit_monochrome_jp2_like_tiff(): with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit: - with Image.open("Tests/images/16bit.cropped.jp2") as jp2: - assert_image_similar(jp2, tiff_16bit, 1e-3) + assert_image_similar_tofile(tiff_16bit, "Tests/images/16bit.cropped.jp2", 1e-3) @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_16bit_monochrome_j2k_like_tiff(): with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit: - with Image.open("Tests/images/16bit.cropped.j2k") as j2k: - assert_image_similar(j2k, tiff_16bit, 1e-3) + assert_image_similar_tofile(tiff_16bit, "Tests/images/16bit.cropped.j2k", 1e-3) def test_16bit_j2k_roundtrips(): @@ -219,7 +229,8 @@ def test_16bit_jp2_roundtrips(): def test_unbound_local(): # prepatch, a malformed jp2 file could cause an UnboundLocalError exception. with pytest.raises(OSError): - Image.open("Tests/images/unbound_variable.jp2") + with Image.open("Tests/images/unbound_variable.jp2"): + pass def test_parser_feed(): @@ -233,3 +244,42 @@ def test_parser_feed(): # Assert assert p.image.size == (640, 480) + + +@pytest.mark.skipif( + not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" +) +@pytest.mark.parametrize("name", ("subsampling_1", "subsampling_2", "zoo1", "zoo2")) +def test_subsampling_decode(name): + test = f"{EXTRA_DIR}/{name}.jp2" + reference = f"{EXTRA_DIR}/{name}.ppm" + + with Image.open(test) as im: + epsilon = 3 # for YCbCr images + with Image.open(reference) as im2: + width, height = im2.size + if name[-1] == "2": + # RGB reference images are downscaled + epsilon = 3e-3 + width, height = width * 2, height * 2 + expected = im2.resize((width, height), Image.NEAREST) + assert_image_similar(im, expected, epsilon) + + +@pytest.mark.parametrize( + "test_file", + [ + "Tests/images/crash-4fb027452e6988530aa5dabee76eecacb3b79f8a.j2k", + "Tests/images/crash-7d4c83eb92150fb8f1653a697703ae06ae7c4998.j2k", + "Tests/images/crash-ccca68ff40171fdae983d924e127a721cab2bd50.j2k", + "Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k", + ], +) +def test_crashes(test_file): + with open(test_file, "rb") as f: + with Image.open(f) as im: + # Valgrind should not complain here + try: + im.load() + except OSError: + pass diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 7d3e10c24..b7ec00ef1 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -9,6 +9,7 @@ from ctypes import c_float import pytest from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features +from PIL.TiffImagePlugin import SUBIFD from .helper import ( assert_image_equal, @@ -16,7 +17,7 @@ from .helper import ( assert_image_similar, assert_image_similar_tofile, hopper, - is_big_endian, + mark_if_feature_version, skip_unless_feature, ) @@ -98,15 +99,13 @@ class TestFileLibTiff(LibTiffTestCase): def test_g4_eq_png(self): """ Checking that we're actually getting the data that we expect""" with Image.open("Tests/images/hopper_bw_500.png") as png: - with Image.open("Tests/images/hopper_g4_500.tif") as g4: - assert_image_equal(g4, png) + assert_image_equal_tofile(png, "Tests/images/hopper_g4_500.tif") # see https://github.com/python-pillow/Pillow/issues/279 def test_g4_fillorder_eq_png(self): """ Checking that we're actually getting the data that we expect""" - with Image.open("Tests/images/g4-fillorder-test.png") as png: - with Image.open("Tests/images/g4-fillorder-test.tif") as g4: - assert_image_equal(g4, png) + with Image.open("Tests/images/g4-fillorder-test.tif") as g4: + assert_image_equal_tofile(g4, "Tests/images/g4-fillorder-test.png") def test_g4_write(self, tmp_path): """Checking to see that the saved image is the same as what we wrote""" @@ -185,6 +184,7 @@ class TestFileLibTiff(LibTiffTestCase): for field in requested_fields: assert field in reloaded, f"{field} not in metadata" + @pytest.mark.valgrind_known_error(reason="Known invalid metadata") def test_additional_metadata(self, tmp_path): # these should not crash. Seriously dummy data, most of it doesn't make # any sense, so we're running up against limits where we're asking @@ -323,6 +323,14 @@ class TestFileLibTiff(LibTiffTestCase): ) TiffImagePlugin.WRITE_LIBTIFF = False + def test_subifd(self, tmp_path): + outfile = str(tmp_path / "temp.tif") + with Image.open("Tests/images/g4_orientation_6.tif") as im: + im.tag_v2[SUBIFD] = 10000 + + # Should not segfault + im.save(outfile) + def test_xmlpacket_tag(self, tmp_path): TiffImagePlugin.WRITE_LIBTIFF = True @@ -427,10 +435,7 @@ class TestFileLibTiff(LibTiffTestCase): im = im.filter(ImageFilter.GaussianBlur(4)) im.save(out, compression="tiff_adobe_deflate") - with Image.open(out) as im2: - im2.load() - - assert_image_equal(im, im2) + assert_image_equal_tofile(im, out) def test_compressions(self, tmp_path): # Test various tiff compressions and assert similar image content but reduced @@ -443,8 +448,7 @@ class TestFileLibTiff(LibTiffTestCase): for compression in ("packbits", "tiff_lzw"): im.save(out, compression=compression) size_compressed = os.path.getsize(out) - with Image.open(out) as im2: - assert_image_equal(im, im2) + assert_image_equal_tofile(im, out) im.save(out, compression="jpeg") size_jpeg = os.path.getsize(out) @@ -453,8 +457,7 @@ class TestFileLibTiff(LibTiffTestCase): im.save(out, compression="jpeg", quality=30) size_jpeg_30 = os.path.getsize(out) - with Image.open(out) as im3: - assert_image_similar(im2, im3, 30) + assert_image_similar_tofile(im2, out, 30) assert size_raw > size_compressed assert size_compressed > size_jpeg @@ -468,6 +471,14 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(out) as reloaded: assert reloaded.info["compression"] == "jpeg" + def test_tiff_deflate_compression(self, tmp_path): + im = hopper("RGB") + out = str(tmp_path / "temp.tif") + im.save(out, compression="tiff_deflate") + + with Image.open(out) as reloaded: + assert reloaded.info["compression"] == "tiff_adobe_deflate" + def test_quality(self, tmp_path): im = hopper("RGB") out = str(tmp_path / "temp.tif") @@ -488,8 +499,7 @@ class TestFileLibTiff(LibTiffTestCase): out = str(tmp_path / "temp.tif") im.save(out, compression="tiff_adobe_deflate") - with Image.open(out) as im2: - assert_image_equal(im, im2) + assert_image_equal_tofile(im, out) def test_palette_save(self, tmp_path): im = hopper("P") @@ -568,6 +578,17 @@ class TestFileLibTiff(LibTiffTestCase): TiffImagePlugin.READ_LIBTIFF = False + def test_multipage_seek_backwards(self): + TiffImagePlugin.READ_LIBTIFF = True + with Image.open("Tests/images/multipage.tiff") as im: + im.seek(1) + im.load() + + im.seek(0) + assert im.convert("RGB").getpixel((0, 0)) == (0, 128, 0) + + TiffImagePlugin.READ_LIBTIFF = False + def test__next(self): TiffImagePlugin.READ_LIBTIFF = True with Image.open("Tests/images/hopper.tif") as im: @@ -639,8 +660,7 @@ class TestFileLibTiff(LibTiffTestCase): pilim.save(buffer_io, format="tiff", compression=compression) buffer_io.seek(0) - with Image.open(buffer_io) as pilim_load: - assert_image_similar(pilim, pilim_load, 0) + assert_image_similar_tofile(pilim, buffer_io, 0) save_bytesio() save_bytesio("raw") @@ -814,13 +834,17 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_strip_ycbcr_jpeg_2x2_sampling(self): infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif" with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5) - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_strip_ycbcr_jpeg_1x1_sampling(self): infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif" with Image.open(infile) as im: @@ -831,22 +855,70 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_tiled_ycbcr_jpeg_1x1_sampling(self): infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif" with Image.open(infile) as im: assert_image_equal_tofile(im, "Tests/images/flower2.jpg") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_tiled_ycbcr_jpeg_2x2_sampling(self): infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif" with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5) - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") - def test_old_style_jpeg(self): - infile = "Tests/images/old-style-jpeg-compression.tif" + def test_strip_planar_rgb(self): + # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_strip_raw.tif tiff_strip_planar_lzw.tiff + infile = "Tests/images/tiff_strip_planar_lzw.tiff" with Image.open(infile) as im: + assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") + + def test_tiled_planar_rgb(self): + # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_tiled_raw.tif tiff_tiled_planar_lzw.tiff + infile = "Tests/images/tiff_tiled_planar_lzw.tiff" + with Image.open(infile) as im: + assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") + + def test_tiled_planar_16bit_RGB(self): + # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_16bit_RGB.tiff tiff_tiled_planar_16bit_RGB.tiff + with Image.open("Tests/images/tiff_tiled_planar_16bit_RGB.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") + + def test_strip_planar_16bit_RGB(self): + # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_16bit_RGB.tiff tiff_strip_planar_16bit_RGB.tiff + with Image.open("Tests/images/tiff_strip_planar_16bit_RGB.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") + + def test_tiled_planar_16bit_RGBa(self): + # gdal_translate -co TILED=yes \ + # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ + # tiff_16bit_RGBa.tiff tiff_tiled_planar_16bit_RGBa.tiff + with Image.open("Tests/images/tiff_tiled_planar_16bit_RGBa.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") + + def test_strip_planar_16bit_RGBa(self): + # gdal_translate -co TILED=no \ + # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ + # tiff_16bit_RGBa.tiff tiff_strip_planar_16bit_RGBa.tiff + with Image.open("Tests/images/tiff_strip_planar_16bit_RGBa.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") + + def test_old_style_jpeg(self): + with Image.open("Tests/images/old-style-jpeg-compression.tif") as im: + assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png") + + def test_open_missing_samplesperpixel(self): + with Image.open( + "Tests/images/old-style-jpeg-compression-no-samplesperpixel.tif" + ) as im: assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png") def test_no_rows_per_strip(self): @@ -864,6 +936,7 @@ class TestFileLibTiff(LibTiffTestCase): assert_image_similar(base_im, im, 0.7) + @pytest.mark.valgrind_known_error(reason="Backtrace in Python Core") def test_sampleformat_not_corrupted(self): # Assert that a TIFF image with SampleFormat=UINT tag is not corrupted # when saving to a new file. diff --git a/Tests/test_file_mcidas.py b/Tests/test_file_mcidas.py index 88c8f8f4f..41f22cf0c 100644 --- a/Tests/test_file_mcidas.py +++ b/Tests/test_file_mcidas.py @@ -2,7 +2,7 @@ import pytest from PIL import Image, McIdasImagePlugin -from .helper import assert_image_equal +from .helper import assert_image_equal_tofile def test_invalid_file(): @@ -27,5 +27,4 @@ def test_valid_file(): assert im.format == "MCIDAS" assert im.mode == "I" assert im.size == (1800, 400) - with Image.open(saved_file) as im2: - assert_image_equal(im, im2) + assert_image_equal_tofile(im, saved_file) diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index 791efcc3f..9de096458 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -41,20 +41,20 @@ def test_unclosed_file(): def test_closed_file(): - def open(): + with pytest.warns(None) as record: im = Image.open(test_files[0]) im.load() im.close() - pytest.warns(None, open) + assert not record def test_context_manager(): - def open(): + with pytest.warns(None) as record: with Image.open(test_files[0]) as im: im.load() - pytest.warns(None, open) + assert not record def test_app(): @@ -89,6 +89,20 @@ def test_frame_size(): assert im.size == (680, 480) +def test_ignore_frame_size(): + # Ignore the different size of the second frame + # since this is not a "Large Thumbnail" image + with Image.open("Tests/images/ignore_frame_size.mpo") as im: + assert im.size == (64, 64) + + im.seek(1) + assert ( + im.mpinfo[0xB002][1]["Attribute"]["MPType"] + == "Multi-Frame Image: (Disparity)" + ) + assert im.size == (64, 64) + + def test_parallax(): # Nintendo with Image.open("Tests/images/sugarshack.mpo") as im: @@ -132,7 +146,7 @@ def test_mp_attribute(): with Image.open(test_file) as im: mpinfo = im._getmp() frameNumber = 0 - for mpentry in mpinfo[45058]: + for mpentry in mpinfo[0xB002]: mpattr = mpentry["Attribute"] if frameNumber: assert not mpattr["RepresentativeImageFlag"] diff --git a/Tests/test_file_msp.py b/Tests/test_file_msp.py index 293b856b0..50d7c590b 100644 --- a/Tests/test_file_msp.py +++ b/Tests/test_file_msp.py @@ -4,7 +4,7 @@ import pytest from PIL import Image, MspImagePlugin -from .helper import assert_image_equal, hopper +from .helper import assert_image_equal, assert_image_equal_tofile, hopper TEST_FILE = "Tests/images/hopper.msp" EXTRA_DIR = "Tests/images/picins" @@ -52,8 +52,7 @@ def test_open_windows_v1(): def _assert_file_image_equal(source_path, target_path): with Image.open(source_path) as im: - with Image.open(target_path) as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, target_path) @pytest.mark.skipif( diff --git a/Tests/test_file_palm.py b/Tests/test_file_palm.py index 25d194b62..e1c1c361b 100644 --- a/Tests/test_file_palm.py +++ b/Tests/test_file_palm.py @@ -5,9 +5,7 @@ import pytest from PIL import Image -from .helper import IMCONVERT, assert_image_equal, hopper, imagemagick_available - -_roundtrip = imagemagick_available() +from .helper import assert_image_equal, hopper, magick_command def helper_save_as_palm(tmp_path, mode): @@ -23,13 +21,10 @@ def helper_save_as_palm(tmp_path, mode): assert os.path.getsize(outfile) > 0 -def open_with_imagemagick(tmp_path, f): - if not imagemagick_available(): - raise OSError() - +def open_with_magick(magick, tmp_path, f): outfile = str(tmp_path / "temp.png") rc = subprocess.call( - [IMCONVERT, f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT + magick + [f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT ) if rc: raise OSError @@ -37,14 +32,15 @@ def open_with_imagemagick(tmp_path, f): def roundtrip(tmp_path, mode): - if not _roundtrip: + magick = magick_command() + if not magick: return im = hopper(mode) outfile = str(tmp_path / "temp.palm") im.save(outfile) - converted = open_with_imagemagick(tmp_path, outfile) + converted = open_with_magick(magick, tmp_path, outfile) assert_image_equal(converted, im) diff --git a/Tests/test_file_pcx.py b/Tests/test_file_pcx.py index 670c03b95..61e33a57b 100644 --- a/Tests/test_file_pcx.py +++ b/Tests/test_file_pcx.py @@ -44,6 +44,14 @@ def test_odd(tmp_path): _roundtrip(tmp_path, hopper(mode).resize((511, 511))) +def test_odd_read(): + # Reading an image with an odd stride, making it malformed + with Image.open("Tests/images/odd_stride.pcx") as im: + im.load() + + assert im.size == (371, 150) + + def test_pil184(): # Check reading of files where xmin/xmax is not zero. diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index 3e23beae7..40a027cc5 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -8,7 +8,7 @@ import pytest from PIL import Image, PdfParser -from .helper import hopper +from .helper import hopper, mark_if_feature_version def helper_save_as_pdf(tmp_path, mode, **kwargs): @@ -30,7 +30,7 @@ def helper_save_as_pdf(tmp_path, mode, **kwargs): with open(outfile, "rb") as fp: contents = fp.read() size = tuple( - int(d) for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split() + float(d) for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split() ) assert im.size == size @@ -42,7 +42,8 @@ def test_monochrome(tmp_path): mode = "1" # Act / Assert - helper_save_as_pdf(tmp_path, mode) + outfile = helper_save_as_pdf(tmp_path, mode) + assert os.path.getsize(outfile) < 15000 def test_greyscale(tmp_path): @@ -85,6 +86,30 @@ def test_unsupported_mode(tmp_path): im.save(outfile) +def test_resolution(tmp_path): + im = hopper() + + outfile = str(tmp_path / "temp.pdf") + im.save(outfile, resolution=150) + + with open(outfile, "rb") as fp: + contents = fp.read() + + size = tuple( + float(d) + for d in contents.split(b"stream\nq ")[1].split(b" 0 0 cm")[0].split(b" 0 0 ") + ) + assert size == (61.44, 61.44) + + size = tuple( + float(d) for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split() + ) + assert size == (61.44, 61.44) + + +@mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" +) def test_save_all(tmp_path): # Single frame image helper_save_as_pdf(tmp_path, "RGB", save_all=True) @@ -285,3 +310,13 @@ def test_pdf_append_to_bytesio(): f = io.BytesIO(f.getvalue()) im.save(f, format="PDF", append=True) assert len(f.getvalue()) > initial_size + + +@pytest.mark.timeout(1) +def test_redos(): + malicious = b" trailer<<>>" + b"\n" * 3456 + + # This particular exception isn't relevant here. + # The important thing is it doesn't timeout, cause a ReDoS (CVE-2021-25292). + with pytest.raises(PdfParser.PdfFormatError): + PdfParser.PdfParser(buf=malicious) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 9028aaf23..a7e5684d3 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -1,4 +1,5 @@ import re +import sys import zlib from io import BytesIO @@ -10,9 +11,11 @@ from .helper import ( PillowLeakTestCase, assert_image, assert_image_equal, + assert_image_equal_tofile, hopper, is_big_endian, is_win32, + mark_if_feature_version, skip_unless_feature, ) @@ -106,7 +109,8 @@ class TestFilePng: test_file = "Tests/images/broken.png" with pytest.raises(OSError): - Image.open(test_file) + with Image.open(test_file): + pass def test_bad_text(self): # Make sure PIL can read malformed tEXt chunks (@PIL152) @@ -324,7 +328,9 @@ class TestFilePng: with Image.open(TEST_PNG_FILE) as im: # Assert that there is no unclosed file warning - pytest.warns(None, im.verify) + with pytest.warns(None) as record: + im.verify() + assert not record with Image.open(TEST_PNG_FILE) as im: im.load() @@ -380,25 +386,12 @@ class TestFilePng: # Check dpi roundtripping with Image.open(TEST_PNG_FILE) as im: - im = roundtrip(im, dpi=(100, 100)) - assert im.info["dpi"] == (100, 100) + im = roundtrip(im, dpi=(100.33, 100.33)) + assert im.info["dpi"] == (100.33, 100.33) - def test_load_dpi_rounding(self): - # Round up + def test_load_float_dpi(self): with Image.open(TEST_PNG_FILE) as im: - assert im.info["dpi"] == (96, 96) - - # Round down - with Image.open("Tests/images/icc_profile_none.png") as im: - assert im.info["dpi"] == (72, 72) - - def test_save_dpi_rounding(self): - with Image.open(TEST_PNG_FILE) as im: - im = roundtrip(im, dpi=(72.2, 72.2)) - assert im.info["dpi"] == (72, 72) - - im = roundtrip(im, dpi=(72.8, 72.8)) - assert im.info["dpi"] == (73, 73) + assert im.info["dpi"] == (95.9866, 95.9866) def test_roundtrip_text(self): # Check text roundtripping @@ -464,7 +457,8 @@ class TestFilePng: pngfile = BytesIO(data) with pytest.raises(OSError): - Image.open(pngfile) + with Image.open(pngfile): + pass def test_trns_rgb(self): # Check writing and reading of tRNS chunks for RGB images. @@ -513,6 +507,8 @@ class TestFilePng: def test_discard_icc_profile(self): with Image.open("Tests/images/icc_profile.png") as im: + assert "icc_profile" in im.info + im = roundtrip(im, icc_profile=None) assert "icc_profile" not in im.info @@ -571,8 +567,8 @@ class TestFilePng: assert len(chunks) == 3 def test_read_private_chunks(self): - im = Image.open("Tests/images/exif.png") - assert im.private_chunks == [(b"orNT", b"\x01")] + with Image.open("Tests/images/exif.png") as im: + assert im.private_chunks == [(b"orNT", b"\x01")] def test_roundtrip_private_chunk(self): # Check private chunk roundtripping @@ -619,6 +615,52 @@ class TestFilePng: with Image.open("Tests/images/hopper_idat_after_image_end.png") as im: assert im.text == {"TXT": "VALUE", "ZIP": "VALUE"} + def test_padded_idat(self): + # This image has been manually hexedited + # so that the IDAT chunk has padding at the end + # Set MAXBLOCK to the length of the actual data + # so that the decoder finishes reading before the chunk ends + MAXBLOCK = ImageFile.MAXBLOCK + ImageFile.MAXBLOCK = 45 + ImageFile.LOAD_TRUNCATED_IMAGES = True + + with Image.open("Tests/images/padded_idat.png") as im: + im.load() + + ImageFile.MAXBLOCK = MAXBLOCK + ImageFile.LOAD_TRUNCATED_IMAGES = False + + assert_image_equal_tofile(im, "Tests/images/bw_gradient.png") + + def test_specify_bits(self, tmp_path): + im = hopper("P") + + out = str(tmp_path / "temp.png") + im.save(out, bits=4) + + with Image.open(out) as reloaded: + assert len(reloaded.png.im_palette[1]) == 48 + + def test_plte_length(self, tmp_path): + im = Image.new("P", (1, 1)) + im.putpalette((1, 1, 1)) + + out = str(tmp_path / "temp.png") + im.save(str(tmp_path / "temp.png")) + + with Image.open(out) as reloaded: + assert len(reloaded.png.im_palette[1]) == 3 + + def test_xmp(self): + with Image.open("Tests/images/color_snakes.png") as im: + xmp = im.getxmp() + + assert isinstance(xmp, dict) + + description = xmp["xmpmeta"]["RDF"]["Description"] + assert description["PixelXDimension"] == "10" + assert description["subject"]["Seq"] is None + def test_exif(self): # With an EXIF chunk with Image.open("Tests/images/exif.png") as im: @@ -654,6 +696,9 @@ class TestFilePng: exif = reloaded._getexif() assert exif[274] == 1 + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_exif_from_jpg(self, tmp_path): with Image.open("Tests/images/pil_sample_rgb.jpg") as im: test_file = str(tmp_path / "temp.png") @@ -682,6 +727,32 @@ class TestFilePng: with pytest.raises(EOFError): im.seek(1) + @pytest.mark.parametrize("buffer", (True, False)) + def test_save_stdout(self, buffer): + old_stdout = sys.stdout + + if buffer: + + class MyStdOut: + buffer = BytesIO() + + mystdout = MyStdOut() + else: + mystdout = BytesIO() + + sys.stdout = mystdout + + with Image.open(TEST_PNG_FILE) as im: + im.save(sys.stdout, "PNG") + + # Reset stdout + sys.stdout = old_stdout + + if buffer: + mystdout = mystdout.buffer + reloaded = Image.open(mystdout) + assert_image_equal_tofile(reloaded, TEST_PNG_FILE) + @pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS") @skip_unless_feature("zlib") diff --git a/Tests/test_file_ppm.py b/Tests/test_file_ppm.py index e7c3fb06f..0ccfb5e88 100644 --- a/Tests/test_file_ppm.py +++ b/Tests/test_file_ppm.py @@ -2,7 +2,7 @@ import pytest from PIL import Image -from .helper import assert_image_equal, assert_image_similar, hopper +from .helper import assert_image_equal_tofile, assert_image_similar, hopper # sample ppm stream TEST_FILE = "Tests/images/hopper.ppm" @@ -24,8 +24,7 @@ def test_16bit_pgm(): assert im.size == (20, 100) assert im.get_format_mimetype() == "image/x-portable-graymap" - with Image.open("Tests/images/16_bit_binary_pgm.png") as tgt: - assert_image_equal(im, tgt) + assert_image_equal_tofile(im, "Tests/images/16_bit_binary_pgm.png") def test_16bit_pgm_write(tmp_path): @@ -35,8 +34,7 @@ def test_16bit_pgm_write(tmp_path): f = str(tmp_path / "temp.pgm") im.save(f, "PPM") - with Image.open(f) as reloaded: - assert_image_equal(im, reloaded) + assert_image_equal_tofile(im, f) def test_pnm(tmp_path): @@ -46,8 +44,7 @@ def test_pnm(tmp_path): f = str(tmp_path / "temp.pnm") im.save(f) - with Image.open(f) as reloaded: - assert_image_equal(im, reloaded) + assert_image_equal_tofile(im, f) def test_truncated_file(tmp_path): @@ -56,7 +53,8 @@ def test_truncated_file(tmp_path): f.write("P6") with pytest.raises(ValueError): - Image.open(path) + with Image.open(path): + pass def test_neg_ppm(): @@ -66,7 +64,8 @@ def test_neg_ppm(): # sizes. with pytest.raises(OSError): - Image.open("Tests/images/negative_size.ppm") + with Image.open("Tests/images/negative_size.ppm"): + pass def test_mimetypes(tmp_path): diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index 8bb45630e..bf2a5fea0 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -29,20 +29,20 @@ def test_unclosed_file(): def test_closed_file(): - def open(): + with pytest.warns(None) as record: im = Image.open(test_file) im.load() im.close() - pytest.warns(None, open) + assert not record def test_context_manager(): - def open(): + with pytest.warns(None) as record: with Image.open(test_file) as im: im.load() - pytest.warns(None, open) + assert not record def test_invalid_file(): @@ -128,4 +128,27 @@ def test_combined_larger_than_size(): # If we instead take the 'size' of the extra data field as the source of truth, # then the seek can't be negative with pytest.raises(OSError): - Image.open("Tests/images/combined_larger_than_size.psd") + with Image.open("Tests/images/combined_larger_than_size.psd"): + pass + + +@pytest.mark.parametrize( + "test_file,raises", + [ + ( + "Tests/images/timeout-1ee28a249896e05b83840ae8140622de8e648ba9.psd", + Image.UnidentifiedImageError, + ), + ( + "Tests/images/timeout-598843abc37fc080ec36a2699ebbd44f795d3a6f.psd", + Image.UnidentifiedImageError, + ), + ("Tests/images/timeout-c8efc3fded6426986ba867a399791bae544f59bc.psd", OSError), + ("Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd", OSError), + ], +) +def test_crashes(test_file, raises): + with open(test_file, "rb") as f: + with pytest.raises(raises): + with Image.open(f): + pass diff --git a/Tests/test_file_sgi.py b/Tests/test_file_sgi.py index a197fa775..0210dd4f1 100644 --- a/Tests/test_file_sgi.py +++ b/Tests/test_file_sgi.py @@ -2,7 +2,12 @@ import pytest from PIL import Image, SgiImagePlugin -from .helper import assert_image_equal, assert_image_similar, hopper +from .helper import ( + assert_image_equal, + assert_image_equal_tofile, + assert_image_similar, + hopper, +) def test_rgb(): @@ -16,10 +21,7 @@ def test_rgb(): def test_rgb16(): - test_file = "Tests/images/hopper16.rgb" - - with Image.open(test_file) as im: - assert_image_equal(im, hopper()) + assert_image_equal_tofile(hopper(), "Tests/images/hopper16.rgb") def test_l(): @@ -38,8 +40,7 @@ def test_rgba(): test_file = "Tests/images/transparent.sgi" with Image.open(test_file) as im: - with Image.open("Tests/images/transparent.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/transparent.png") assert im.get_format_mimetype() == "image/sgi" @@ -49,16 +50,14 @@ def test_rle(): test_file = "Tests/images/hopper.sgi" with Image.open(test_file) as im: - with Image.open("Tests/images/hopper.rgb") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/hopper.rgb") def test_rle16(): test_file = "Tests/images/tv16.sgi" with Image.open(test_file) as im: - with Image.open("Tests/images/tv.rgb") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/tv.rgb") def test_invalid_file(): @@ -72,8 +71,7 @@ def test_write(tmp_path): def roundtrip(img): out = str(tmp_path / "temp.sgi") img.save(out, format="sgi") - with Image.open(out) as reloaded: - assert_image_equal(img, reloaded) + assert_image_equal_tofile(img, out) for mode in ("L", "RGB", "RGBA"): roundtrip(hopper(mode)) @@ -89,8 +87,7 @@ def test_write16(tmp_path): out = str(tmp_path / "temp.sgi") im.save(out, format="sgi", bpc=2) - with Image.open(out) as reloaded: - assert_image_equal(im, reloaded) + assert_image_equal_tofile(im, out) def test_unsupported_mode(tmp_path): diff --git a/Tests/test_file_spider.py b/Tests/test_file_spider.py index 9cdb451c9..3c93160f1 100644 --- a/Tests/test_file_spider.py +++ b/Tests/test_file_spider.py @@ -5,7 +5,7 @@ import pytest from PIL import Image, ImageSequence, SpiderImagePlugin -from .helper import assert_image_equal, hopper, is_pypy +from .helper import assert_image_equal_tofile, hopper, is_pypy TEST_FILE = "Tests/images/hopper.spider" @@ -28,20 +28,20 @@ def test_unclosed_file(): def test_closed_file(): - def open(): + with pytest.warns(None) as record: im = Image.open(TEST_FILE) im.load() im.close() - pytest.warns(None, open) + assert not record def test_context_manager(): - def open(): + with pytest.warns(None) as record: with Image.open(TEST_FILE) as im: im.load() - pytest.warns(None, open) + assert not record def test_save(tmp_path): @@ -136,7 +136,8 @@ def test_invalid_file(): invalid_file = "Tests/images/invalid.spider" with pytest.raises(OSError): - Image.open(invalid_file) + with Image.open(invalid_file): + pass def test_nonstack_file(): @@ -159,5 +160,4 @@ def test_odd_size(): im.save(data, format="SPIDER") data.seek(0) - with Image.open(data) as im2: - assert_image_equal(im, im2) + assert_image_equal_tofile(im, data) diff --git a/Tests/test_file_sun.py b/Tests/test_file_sun.py index 8421106a2..05c78c316 100644 --- a/Tests/test_file_sun.py +++ b/Tests/test_file_sun.py @@ -4,7 +4,7 @@ import pytest from PIL import Image, SunImagePlugin -from .helper import assert_image_equal, assert_image_similar, hopper +from .helper import assert_image_equal_tofile, assert_image_similar, hopper EXTRA_DIR = "Tests/images/sunraster" @@ -29,8 +29,7 @@ def test_sanity(): def test_im1(): with Image.open("Tests/images/sunraster.im1") as im: - with Image.open("Tests/images/sunraster.im1.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/sunraster.im1.png") @pytest.mark.skipif( @@ -46,7 +45,4 @@ def test_others(): with Image.open(path) as im: im.load() assert isinstance(im, SunImagePlugin.SunImageFile) - target_path = f"{os.path.splitext(path)[0]}.png" - # im.save(target_file) - with Image.open(target_path) as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, f"{os.path.splitext(path)[0]}.png") diff --git a/Tests/test_file_tar.py b/Tests/test_file_tar.py index 02001e5b1..b38727fb9 100644 --- a/Tests/test_file_tar.py +++ b/Tests/test_file_tar.py @@ -31,16 +31,16 @@ def test_unclosed_file(): def test_close(): - def open(): + with pytest.warns(None) as record: tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") tar.close() - pytest.warns(None, open) + assert not record def test_contextmanager(): - def open(): + with pytest.warns(None) as record: with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"): pass - pytest.warns(None, open) + assert not record diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py index 465e13316..3450c9274 100644 --- a/Tests/test_file_tga.py +++ b/Tests/test_file_tga.py @@ -6,7 +6,7 @@ import pytest from PIL import Image -from .helper import assert_image_equal, hopper +from .helper import assert_image_equal, assert_image_equal_tofile, hopper _TGA_DIR = os.path.join("Tests", "images", "tga") _TGA_DIR_COMMON = os.path.join(_TGA_DIR, "common") @@ -65,6 +65,16 @@ def test_sanity(tmp_path): roundtrip(original_im) +def test_palette_depth_16(tmp_path): + with Image.open("Tests/images/p_16.tga") as im: + assert_image_equal_tofile(im.convert("RGB"), "Tests/images/p_16.png") + + out = str(tmp_path / "temp.png") + im.save(out) + with Image.open(out) as reloaded: + assert_image_equal_tofile(reloaded.convert("RGB"), "Tests/images/p_16.png") + + def test_id_field(): # tga file with id field test_file = "Tests/images/tga_id_field.tga" @@ -112,6 +122,14 @@ def test_save_wrong_mode(tmp_path): im.save(out) +def test_save_mapdepth(): + # This image has been manually hexedited from 200x32_p_bl_raw.tga + # to include an origin + test_file = "Tests/images/200x32_p_bl_raw_origin.tga" + with Image.open(test_file) as im: + assert_image_equal_tofile(im, "Tests/images/tga/common/200x32_p.png") + + def test_save_id_section(tmp_path): test_file = "Tests/images/rgb32rle.tga" with Image.open(test_file) as im: diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index bb1bbda3e..d3de203d8 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -4,7 +4,7 @@ from io import BytesIO import pytest from PIL import Image, TiffImagePlugin -from PIL.TiffImagePlugin import RESOLUTION_UNIT, SUBIFD, X_RESOLUTION, Y_RESOLUTION +from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION from .helper import ( assert_image_equal, @@ -59,19 +59,19 @@ class TestFileTiff: pytest.warns(ResourceWarning, open) def test_closed_file(self): - def open(): + with pytest.warns(None) as record: im = Image.open("Tests/images/multipage.tiff") im.load() im.close() - pytest.warns(None, open) + assert not record def test_context_manager(self): - def open(): + with pytest.warns(None) as record: with Image.open("Tests/images/multipage.tiff") as im: im.load() - pytest.warns(None, open) + assert not record def test_mac_tiff(self): # Read RGBa images from macOS [@PIL136] @@ -137,46 +137,33 @@ class TestFileTiff: im._setup() assert im.info["dpi"] == (71.0, 71.0) - def test_load_dpi_rounding(self): - for resolutionUnit, dpi in ((None, (72, 73)), (2, (72, 73)), (3, (183, 185))): - with Image.open( - "Tests/images/hopper_roundDown_" + str(resolutionUnit) + ".tif" - ) as im: - assert im.tag_v2.get(RESOLUTION_UNIT) == resolutionUnit - assert im.info["dpi"] == (dpi[0], dpi[0]) + @pytest.mark.parametrize( + "resolutionUnit, dpi", + [(None, 72.8), (2, 72.8), (3, 184.912)], + ) + def test_load_float_dpi(self, resolutionUnit, dpi): + with Image.open( + "Tests/images/hopper_float_dpi_" + str(resolutionUnit) + ".tif" + ) as im: + assert im.tag_v2.get(RESOLUTION_UNIT) == resolutionUnit + assert im.info["dpi"] == (dpi, dpi) - with Image.open( - "Tests/images/hopper_roundUp_" + str(resolutionUnit) + ".tif" - ) as im: - assert im.tag_v2.get(RESOLUTION_UNIT) == resolutionUnit - assert im.info["dpi"] == (dpi[1], dpi[1]) - - def test_save_dpi_rounding(self, tmp_path): + def test_save_float_dpi(self, tmp_path): outfile = str(tmp_path / "temp.tif") with Image.open("Tests/images/hopper.tif") as im: - for dpi in (72.2, 72.8): - im.save(outfile, dpi=(dpi, dpi)) + dpi = (72.2, 72.2) + im.save(outfile, dpi=dpi) - with Image.open(outfile) as reloaded: - reloaded.load() - assert (round(dpi), round(dpi)) == reloaded.info["dpi"] - - def test_subifd(self, tmp_path): - outfile = str(tmp_path / "temp.tif") - with Image.open("Tests/images/g4_orientation_6.tif") as im: - im.tag_v2[SUBIFD] = 10000 - - # Should not segfault - im.save(outfile) + with Image.open(outfile) as reloaded: + assert reloaded.info["dpi"] == dpi def test_save_setting_missing_resolution(self): b = BytesIO() - Image.open("Tests/images/10ct_32bit_128.tiff").save( - b, format="tiff", resolution=123.45 - ) + with Image.open("Tests/images/10ct_32bit_128.tiff") as im: + im.save(b, format="tiff", resolution=123.45) with Image.open(b) as im: - assert float(im.tag_v2[X_RESOLUTION]) == 123.45 - assert float(im.tag_v2[Y_RESOLUTION]) == 123.45 + assert im.tag_v2[X_RESOLUTION] == 123.45 + assert im.tag_v2[Y_RESOLUTION] == 123.45 def test_invalid_file(self): invalid_file = "Tests/images/flower.jpg" @@ -256,7 +243,8 @@ class TestFileTiff: def test_unknown_pixel_mode(self): with pytest.raises(OSError): - Image.open("Tests/images/hopper_unknown_pixel_mode.tif") + with Image.open("Tests/images/hopper_unknown_pixel_mode.tif"): + pass def test_n_frames(self): for path, n_frames in [ @@ -309,6 +297,19 @@ class TestFileTiff: assert im.size == (20, 20) assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 255) + def test_frame_order(self): + # A frame can't progress to itself after reading + with Image.open("Tests/images/multipage_single_frame_loop.tiff") as im: + assert im.n_frames == 1 + + # A frame can't progress to a frame that has already been read + with Image.open("Tests/images/multipage_multiple_frame_loop.tiff") as im: + assert im.n_frames == 2 + + # Frames don't have to be in sequence + with Image.open("Tests/images/multipage_out_of_order.tiff") as im: + assert im.n_frames == 3 + def test___str__(self): filename = "Tests/images/pil136.tiff" with Image.open(filename) as im: @@ -397,6 +398,50 @@ class TestFileTiff: with Image.open("Tests/images/ifd_tag_type.tiff") as im: assert 0x8825 in im.tag_v2 + def test_exif(self): + with Image.open("Tests/images/ifd_tag_type.tiff") as im: + exif = im.getexif() + + assert sorted(exif.keys()) == [ + 256, + 257, + 258, + 259, + 262, + 271, + 272, + 273, + 277, + 278, + 279, + 282, + 283, + 284, + 296, + 297, + 305, + 339, + 700, + 34665, + 34853, + 50735, + ] + assert exif[256] == 640 + assert exif[271] == "FLIR" + + gps = exif.get_ifd(0x8825) + assert list(gps.keys()) == [0, 1, 2, 3, 4, 5, 6, 18] + assert gps[0] == b"\x03\x02\x00\x00" + assert gps[18] == "WGS-84" + + def test_exif_frames(self): + # Test that EXIF data can change across frames + with Image.open("Tests/images/g4-multi.tiff") as im: + assert im.getexif()[273] == (328, 815) + + im.seek(1) + assert im.getexif()[273] == (1408, 1907) + def test_seek(self): filename = "Tests/images/pil136.tiff" with Image.open(filename) as im: @@ -491,8 +536,7 @@ class TestFileTiff: tmpfile = str(tmp_path / "temp.tif") im.save(tmpfile) - with Image.open(tmpfile) as reloaded: - assert_image_equal(im, reloaded) + assert_image_equal_tofile(im, tmpfile) def test_strip_raw(self): infile = "Tests/images/tiff_strip_raw.tif" @@ -577,6 +621,38 @@ class TestFileTiff: with Image.open(tmpfile) as reloaded: assert b"Dummy value" == reloaded.info["icc_profile"] + def test_save_icc_profile(self, tmp_path): + im = hopper() + assert "icc_profile" not in im.info + + outfile = str(tmp_path / "temp.tif") + icc_profile = b"Dummy value" + im.save(outfile, icc_profile=icc_profile) + + with Image.open(outfile) as reloaded: + assert reloaded.info["icc_profile"] == icc_profile + + def test_discard_icc_profile(self, tmp_path): + outfile = str(tmp_path / "temp.tif") + + with Image.open("Tests/images/icc_profile.png") as im: + assert "icc_profile" in im.info + + im.save(outfile, icc_profile=None) + + with Image.open(outfile) as reloaded: + assert "icc_profile" not in reloaded.info + + def test_xmp(self): + with Image.open("Tests/images/lab.tif") as im: + xmp = im.getxmp() + + assert isinstance(xmp, dict) + + description = xmp["xmpmeta"]["RDF"]["Description"] + assert description[0]["format"] == "image/tiff" + assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"] + def test_close_on_load_exclusive(self, tmp_path): # similar to test_fd_leak, but runs on unixlike os tmpfile = str(tmp_path / "temp.tif") @@ -612,8 +688,9 @@ class TestFileTiff: ) def test_string_dimension(self): # Assert that an error is raised if one of the dimensions is a string - with pytest.raises(ValueError): - Image.open("Tests/images/string_dimension.tiff") + with Image.open("Tests/images/string_dimension.tiff") as im: + with pytest.raises(OSError): + im.load() @pytest.mark.skipif(not is_win32(), reason="Windows only") diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index 0f7f8adf1..0adbaf016 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -179,6 +179,27 @@ def test_no_duplicate_50741_tag(): assert TAG_IDS["BestQualityScale"] == 50780 +def test_iptc(tmp_path): + out = str(tmp_path / "temp.tiff") + with Image.open("Tests/images/hopper.Lab.tif") as im: + im.save(out) + + +def test_undefined_zero(tmp_path): + # Check that the tag has not been changed since this test was created + tag = TiffTags.TAGS_V2[45059] + assert tag.type == TiffTags.UNDEFINED + assert tag.length == 0 + + info = TiffImagePlugin.ImageFileDirectory(b"II*\x00\x08\x00\x00\x00") + info[45059] = b"test" + + # Assert that the tag value does not change by setting it to itself + original = info[45059] + info[45059] = info[45059] + assert info[45059] == original + + def test_empty_metadata(): f = io.BytesIO(b"II*\x00\x08\x00\x00\x00") head = f.read(8) @@ -355,3 +376,30 @@ def test_too_many_entries(): # Should not raise ValueError. pytest.warns(UserWarning, lambda: ifd[277]) + + +def test_tag_group_data(): + base_ifd = TiffImagePlugin.ImageFileDirectory_v2() + interop_ifd = TiffImagePlugin.ImageFileDirectory_v2(group=40965) + for ifd in (base_ifd, interop_ifd): + ifd[2] = "test" + ifd[256] = 10 + + assert base_ifd.tagtype[256] == 4 + assert interop_ifd.tagtype[256] != base_ifd.tagtype[256] + + assert interop_ifd.tagtype[2] == 7 + assert base_ifd.tagtype[2] != interop_ifd.tagtype[256] + + +def test_empty_subifd(tmp_path): + out = str(tmp_path / "temp.jpg") + + im = hopper() + exif = im.getexif() + exif[TiffImagePlugin.EXIFIFD] = {} + im.save(out, exif=exif) + + with Image.open(out) as reloaded: + exif = reloaded.getexif() + assert exif.get_ifd(TiffImagePlugin.EXIFIFD) == {} diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 11fbd9fd5..7fdb32ef4 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -1,5 +1,6 @@ import io import re +import sys import pytest @@ -119,6 +120,14 @@ class TestFileWebp: self._roundtrip(tmp_path, "P", 50.0) + @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="Requires 64-bit system") + def test_write_encoding_error_message(self, tmp_path): + temp_file = str(tmp_path / "temp.webp") + im = Image.new("RGB", (15000, 15000)) + with pytest.raises(ValueError) as e: + im.save(temp_file, method=0) + assert str(e.value) == "encoding error 6" + def test_WebPEncode_with_invalid_args(self): """ Calling encoder functions with no arguments should result in an error. @@ -145,7 +154,9 @@ class TestFileWebp: file_path = "Tests/images/hopper.webp" with Image.open(file_path) as image: temp_file = str(tmp_path / "temp.webp") - pytest.warns(None, image.save, temp_file) + with pytest.warns(None) as record: + image.save(temp_file) + assert not record def test_file_pointer_could_be_reused(self): file_path = "Tests/images/hopper.webp" @@ -165,7 +176,8 @@ class TestFileWebp: # Save as GIF out_gif = str(tmp_path / "temp.gif") - Image.open(out_webp).save(out_gif) + with Image.open(out_webp) as im: + im.save(out_gif) with Image.open(out_gif) as reread: reread_value = reread.convert("RGB").getpixel((1, 1)) @@ -173,3 +185,16 @@ class TestFileWebp: [abs(original_value[i] - reread_value[i]) for i in range(0, 3)] ) assert difference < 5 + + @skip_unless_feature("webp") + @skip_unless_feature("webp_anim") + def test_duration(self, tmp_path): + with Image.open("Tests/images/dispose_bgnd.gif") as im: + assert im.info["duration"] == 1000 + + out_webp = str(tmp_path / "temp.webp") + im.save(out_webp, save_all=True) + + with Image.open(out_webp) as reloaded: + reloaded.load() + assert reloaded.info["duration"] == 1000 diff --git a/Tests/test_file_webp_alpha.py b/Tests/test_file_webp_alpha.py index 362edac1a..dc82fb742 100644 --- a/Tests/test_file_webp_alpha.py +++ b/Tests/test_file_webp_alpha.py @@ -2,7 +2,12 @@ import pytest from PIL import Image -from .helper import assert_image_equal, assert_image_similar, hopper +from .helper import ( + assert_image_equal, + assert_image_similar, + assert_image_similar_tofile, + hopper, +) _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") @@ -29,8 +34,7 @@ def test_read_rgba(): image.tobytes() - with Image.open("Tests/images/transparent.png") as target: - assert_image_similar(image, target, 20.0) + assert_image_similar_tofile(image, "Tests/images/transparent.png", 20.0) def test_write_lossless_rgb(tmp_path): diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index 26e903488..25ebffe02 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -45,12 +45,12 @@ def test_write_animation_L(tmp_path): # Compare first and last frames to the original animated GIF orig.load() im.load() - assert_image_similar(im, orig.convert("RGBA"), 25.0) + assert_image_similar(im, orig.convert("RGBA"), 32.9) orig.seek(orig.n_frames - 1) im.seek(im.n_frames - 1) orig.load() im.load() - assert_image_similar(im, orig.convert("RGBA"), 25.0) + assert_image_similar(im, orig.convert("RGBA"), 32.9) @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index a2a05f96b..e6d6fc63f 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -1,8 +1,10 @@ from io import BytesIO +import pytest + from PIL import Image -from .helper import skip_unless_feature +from .helper import mark_if_feature_version, skip_unless_feature pytestmark = [ skip_unless_feature("webp"), @@ -39,6 +41,9 @@ def test_read_exif_metadata_without_prefix(): assert exif[305] == "Adobe Photoshop CS6 (Macintosh)" +@mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" +) def test_write_exif_metadata(): file_path = "Tests/images/flower.jpg" test_buffer = BytesIO() @@ -71,6 +76,9 @@ def test_read_icc_profile(): assert icc == expected_icc +@mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" +) def test_write_icc_metadata(): file_path = "Tests/images/flower2.jpg" test_buffer = BytesIO() @@ -88,6 +96,9 @@ def test_write_icc_metadata(): assert webp_icc_profile == expected_icc_profile, "Webp ICC didn't match" +@mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" +) def test_read_no_exif(): file_path = "Tests/images/flower.jpg" test_buffer = BytesIO() diff --git a/Tests/test_file_wmf.py b/Tests/test_file_wmf.py index d18225680..3f8bc96cc 100644 --- a/Tests/test_file_wmf.py +++ b/Tests/test_file_wmf.py @@ -2,7 +2,7 @@ import pytest from PIL import Image, WmfImagePlugin -from .helper import assert_image_similar, hopper +from .helper import assert_image_similar_tofile, hopper def test_load_raw(): @@ -13,9 +13,7 @@ def test_load_raw(): # Currently, support for WMF/EMF is Windows-only im.load() # Compare to reference rendering - with Image.open("Tests/images/drawing_emf_ref.png") as imref: - imref.load() - assert_image_similar(im, imref, 0) + assert_image_similar_tofile(im, "Tests/images/drawing_emf_ref.png", 0) # Test basic WMF open and rendering with Image.open("Tests/images/drawing.wmf") as im: @@ -23,9 +21,7 @@ def test_load_raw(): # Currently, support for WMF/EMF is Windows-only im.load() # Compare to reference rendering - with Image.open("Tests/images/drawing_wmf_ref.png") as imref: - imref.load() - assert_image_similar(im, imref, 2.0) + assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref.png", 2.0) def test_register_handler(tmp_path): @@ -48,14 +44,9 @@ def test_register_handler(tmp_path): WmfImagePlugin.register_handler(original_handler) -def test_load_dpi_rounding(): - # Round up +def test_load_float_dpi(): with Image.open("Tests/images/drawing.emf") as im: - assert im.info["dpi"] == 1424 - - # Round down - with Image.open("Tests/images/drawing_roundDown.emf") as im: - assert im.info["dpi"] == 1426 + assert im.info["dpi"] == 1423.7668161434979 def test_load_set_dpi(): @@ -66,8 +57,7 @@ def test_load_set_dpi(): im.load(144) assert im.size == (164, 164) - with Image.open("Tests/images/drawing_wmf_ref_144.png") as expected: - assert_image_similar(im, expected, 2.1) + assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref_144.png", 2.1) def test_save(tmp_path): diff --git a/Tests/test_font_pcf.py b/Tests/test_font_pcf.py index 4db73e56e..288848f26 100644 --- a/Tests/test_font_pcf.py +++ b/Tests/test_font_pcf.py @@ -4,7 +4,11 @@ import pytest from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile -from .helper import assert_image_equal, assert_image_similar, skip_unless_feature +from .helper import ( + assert_image_equal_tofile, + assert_image_similar_tofile, + skip_unless_feature, +) fontname = "Tests/fonts/10x20-ISO8859-1.pcf" @@ -33,8 +37,7 @@ def save_font(request, tmp_path): font.save(tempname) with Image.open(tempname.replace(".pil", ".pbm")) as loaded: - with Image.open("Tests/fonts/10x20.pbm") as target: - assert_image_equal(loaded, target) + assert_image_equal_tofile(loaded, "Tests/fonts/10x20.pbm") with open(tempname, "rb") as f_loaded: with open("Tests/fonts/10x20.pil", "rb") as f_target: @@ -58,8 +61,7 @@ def test_draw(request, tmp_path): im = Image.new("L", (130, 30), "white") draw = ImageDraw.Draw(im) draw.text((0, 0), message, "black", font=font) - with Image.open("Tests/images/test_draw_pbm_target.png") as target: - assert_image_similar(im, target, 0) + assert_image_similar_tofile(im, "Tests/images/test_draw_pbm_target.png", 0) def test_textsize(request, tmp_path): @@ -80,8 +82,7 @@ def _test_high_characters(request, tmp_path, message): im = Image.new("L", (750, 30), "white") draw = ImageDraw.Draw(im) draw.text((0, 0), message, "black", font=font) - with Image.open("Tests/images/high_ascii_chars.png") as target: - assert_image_similar(im, target, 0) + assert_image_similar_tofile(im, "Tests/images/high_ascii_chars.png", 0) def test_high_characters(request, tmp_path): diff --git a/Tests/test_font_pcf_charsets.py b/Tests/test_font_pcf_charsets.py index d7d1bf200..a1036fd28 100644 --- a/Tests/test_font_pcf_charsets.py +++ b/Tests/test_font_pcf_charsets.py @@ -2,7 +2,11 @@ import os from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile -from .helper import assert_image_equal, assert_image_similar, skip_unless_feature +from .helper import ( + assert_image_equal_tofile, + assert_image_similar_tofile, + skip_unless_feature, +) fontname = "Tests/fonts/ter-x20b.pcf" @@ -47,8 +51,7 @@ def save_font(request, tmp_path, encoding): font.save(tempname) with Image.open(tempname.replace(".pil", ".pbm")) as loaded: - with Image.open(f"Tests/fonts/ter-x20b-{encoding}.pbm") as target: - assert_image_equal(loaded, target) + assert_image_equal_tofile(loaded, f"Tests/fonts/ter-x20b-{encoding}.pbm") with open(tempname, "rb") as f_loaded: with open(f"Tests/fonts/ter-x20b-{encoding}.pil", "rb") as f_target: @@ -79,8 +82,7 @@ def _test_draw(request, tmp_path, encoding): draw = ImageDraw.Draw(im) message = charsets[encoding]["message"].encode(encoding) draw.text((0, 0), message, "black", font=font) - with Image.open(charsets[encoding]["image1"]) as target: - assert_image_similar(im, target, 0) + assert_image_similar_tofile(im, charsets[encoding]["image1"], 0) def test_draw_iso8859_1(request, tmp_path): diff --git a/Tests/test_image.py b/Tests/test_image.py index 84c098cc8..c4e6f8ade 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1,6 +1,7 @@ import io import os import shutil +import sys import tempfile import pytest @@ -10,10 +11,12 @@ from PIL import Image, ImageDraw, ImagePalette, ImageShow, UnidentifiedImageErro from .helper import ( assert_image_equal, - assert_image_similar, + assert_image_equal_tofile, + assert_image_similar_tofile, assert_not_all_same, hopper, is_win32, + mark_if_feature_version, skip_unless_feature, ) @@ -92,11 +95,13 @@ class TestImage: JPGFILE = "Tests/images/hopper.jpg" with pytest.raises(TypeError): - Image.open(PNGFILE, formats=123) + with Image.open(PNGFILE, formats=123): + pass - for formats in [["JPEG"], ("JPEG",)]: + for formats in [["JPEG"], ("JPEG",), ["jpeg"], ["Jpeg"], ["jPeG"], ["JpEg"]]: with pytest.raises(UnidentifiedImageError): - Image.open(PNGFILE, formats=formats) + with Image.open(PNGFILE, formats=formats): + pass with Image.open(JPGFILE, formats=formats) as im: assert im.mode == "RGB" @@ -120,15 +125,18 @@ class TestImage: im = io.BytesIO(b"") with pytest.raises(UnidentifiedImageError): - Image.open(im) + with Image.open(im): + pass def test_bad_mode(self): with pytest.raises(ValueError): - Image.open("filename", "bad mode") + with Image.open("filename", "bad mode"): + pass def test_stringio(self): with pytest.raises(ValueError): - Image.open(io.StringIO()) + with Image.open(io.StringIO()): + pass def test_pathlib(self, tmp_path): from PIL.Image import Path @@ -166,8 +174,7 @@ class TestImage: with tempfile.TemporaryFile() as fp: im.save(fp, "JPEG") fp.seek(0) - with Image.open(fp) as reloaded: - assert_image_similar(im, reloaded, 20) + assert_image_similar_tofile(im, fp, 20) def test_unknown_extension(self, tmp_path): im = hopper() @@ -339,6 +346,12 @@ class TestImage: assert_image_equal(offset.crop((64, 64, 127, 127)), target.crop((0, 0, 63, 63))) assert offset.size == (128, 128) + # with negative offset + offset = src.copy() + offset.alpha_composite(over, (-64, -64)) + assert_image_equal(offset.crop((0, 0, 63, 63)), target.crop((64, 64, 127, 127))) + assert offset.size == (128, 128) + # offset and crop box = src.copy() box.alpha_composite(over, (64, 64), (0, 0, 32, 32)) @@ -362,8 +375,6 @@ class TestImage: source.alpha_composite(over, 0) with pytest.raises(ValueError): source.alpha_composite(over, (0, 0), 0) - with pytest.raises(ValueError): - source.alpha_composite(over, (0, -1)) with pytest.raises(ValueError): source.alpha_composite(over, (0, 0), (0, -1)) @@ -408,8 +419,7 @@ class TestImage: # Assert assert im.size == (512, 512) - with Image.open("Tests/images/effect_mandelbrot.png") as im2: - assert_image_equal(im, im2) + assert_image_equal_tofile(im, "Tests/images/effect_mandelbrot.png") def test_effect_mandelbrot_bad_arguments(self): # Arrange @@ -451,8 +461,7 @@ class TestImage: # Assert assert im.size == (128, 128) - with Image.open("Tests/images/effect_spread.png") as im3: - assert_image_similar(im2, im3, 110) + assert_image_similar_tofile(im2, "Tests/images/effect_spread.png", 110) def test_effect_spread_zero(self): # Arrange @@ -516,7 +525,7 @@ class TestImage: # Arrange target_file = "Tests/images/linear_gradient.png" - for mode in ["L", "P"]: + for mode in ["L", "P", "I", "F"]: # Act im = Image.linear_gradient(mode) @@ -542,7 +551,7 @@ class TestImage: # Arrange target_file = "Tests/images/radial_gradient.png" - for mode in ["L", "P"]: + for mode in ["L", "P", "I", "F"]: # Act im = Image.radial_gradient(mode) @@ -573,6 +582,10 @@ class TestImage: assert ext_individual == ext_multiple def test_remap_palette(self): + # Test identity transform + with Image.open("Tests/images/hopper.gif") as im: + assert_image_equal(im, im.remap_palette(list(range(256)))) + # Test illegal image mode with hopper() as im: with pytest.raises(ValueError): @@ -597,7 +610,7 @@ class TestImage: else: assert new_im.palette is None - _make_new(im, im_p, im_p.palette) + _make_new(im, im_p, ImagePalette.ImagePalette(list(range(256)) * 3)) _make_new(im_p, im, None) _make_new(im, blank_p, ImagePalette.ImagePalette()) _make_new(im, blank_pa, ImagePalette.ImagePalette()) @@ -636,7 +649,9 @@ class TestImage: # Act/Assert with Image.open(test_file) as im: - pytest.warns(None, im.save, temp_file) + with pytest.warns(None) as record: + im.save(temp_file) + assert not record def test_load_on_nonexclusive_multiframe(self): with open("Tests/images/frozenpond.mpo", "rb") as fp: @@ -652,48 +667,51 @@ class TestImage: assert not fp.closed + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_exif_jpeg(self, tmp_path): with Image.open("Tests/images/exif-72dpi-int.jpg") as im: # Little endian exif = im.getexif() assert 258 not in exif assert 274 in exif - assert 40960 in exif - assert exif[40963] == 450 + assert 282 in exif + assert exif[296] == 2 assert exif[11] == "gThumb 3.0.1" out = str(tmp_path / "temp.jpg") exif[258] = 8 del exif[274] - del exif[40960] - exif[40963] = 455 + del exif[282] + exif[296] = 455 exif[11] = "Pillow test" im.save(out, exif=exif) with Image.open(out) as reloaded: reloaded_exif = reloaded.getexif() assert reloaded_exif[258] == 8 assert 274 not in reloaded_exif - assert 40960 not in reloaded_exif - assert reloaded_exif[40963] == 455 + assert 282 not in reloaded_exif + assert reloaded_exif[296] == 455 assert reloaded_exif[11] == "Pillow test" with Image.open("Tests/images/no-dpi-in-exif.jpg") as im: # Big endian exif = im.getexif() assert 258 not in exif - assert 40962 in exif - assert exif[40963] == 200 + assert 306 in exif + assert exif[274] == 1 assert exif[305] == "Adobe Photoshop CC 2017 (Macintosh)" out = str(tmp_path / "temp.jpg") exif[258] = 8 - del exif[34665] - exif[40963] = 455 + del exif[306] + exif[274] = 455 exif[305] = "Pillow test" im.save(out, exif=exif) with Image.open(out) as reloaded: reloaded_exif = reloaded.getexif() assert reloaded_exif[258] == 8 - assert 34665 not in reloaded_exif - assert reloaded_exif[40963] == 455 + assert 306 not in reloaded_exif + assert reloaded_exif[274] == 455 assert reloaded_exif[305] == "Pillow test" @skip_unless_feature("webp") @@ -746,6 +764,54 @@ class TestImage: 4098: 1704, } + reloaded_exif = Image.Exif() + reloaded_exif.load(exif.tobytes()) + assert reloaded_exif.get_ifd(0xA005) == exif.get_ifd(0xA005) + + def test_exif_ifd(self): + with Image.open("Tests/images/flower.jpg") as im: + exif = im.getexif() + del exif.get_ifd(0x8769)[0xA005] + + reloaded_exif = Image.Exif() + reloaded_exif.load(exif.tobytes()) + assert reloaded_exif.get_ifd(0x8769) == exif.get_ifd(0x8769) + + def test_exif_load_from_fp(self): + with Image.open("Tests/images/flower.jpg") as im: + data = im.info["exif"] + if data.startswith(b"Exif\x00\x00"): + data = data[6:] + fp = io.BytesIO(data) + + exif = Image.Exif() + exif.load_from_fp(fp) + assert exif == { + 271: "Canon", + 272: "Canon PowerShot S40", + 274: 1, + 282: 180.0, + 283: 180.0, + 296: 2, + 306: "2003:12:14 12:01:44", + 531: 1, + 34665: 196, + } + + @pytest.mark.skipif( + sys.version_info < (3, 7), reason="Python 3.7 or greater required" + ) + def test_categories_deprecation(self): + with pytest.warns(DeprecationWarning): + assert hopper().category == 0 + + with pytest.warns(DeprecationWarning): + assert Image.NORMAL == 0 + with pytest.warns(DeprecationWarning): + assert Image.SEQUENCE == 1 + with pytest.warns(DeprecationWarning): + assert Image.CONTAINER == 2 + @pytest.mark.parametrize( "test_module", [PIL, Image], @@ -775,26 +841,34 @@ class TestImage: with pytest.warns(DeprecationWarning): assert test_module.PILLOW_VERSION > "7.0.0" - def test_overrun(self): - """For overrun completeness, test as: - valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c - """ - for file in [ + @pytest.mark.parametrize( + "path", + [ "fli_overrun.bin", "sgi_overrun.bin", "sgi_overrun_expandrow.bin", "sgi_overrun_expandrow2.bin", "pcx_overrun.bin", "pcx_overrun2.bin", + "ossfuzz-4836216264589312.pcx", "01r_00.pcx", - ]: - with Image.open(os.path.join("Tests/images", file)) as im: - try: - im.load() - assert False - except OSError as e: - assert str(e) == "buffer overrun when reading image file" + ], + ) + def test_overrun(self, path): + """For overrun completeness, test as: + valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c + """ + with Image.open(os.path.join("Tests/images", path)) as im: + try: + im.load() + assert False + except OSError as e: + buffer_overrun = str(e) == "buffer overrun when reading image file" + truncated = "image file is truncated" in str(e) + assert buffer_overrun or truncated + + def test_fli_overrun2(self): with Image.open("Tests/images/fli_overrun2.bin") as im: try: im.seek(1) diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index e86dc8530..7b3036979 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -23,6 +23,11 @@ else: except ImportError: cffi = None +try: + import numpy +except ImportError: + numpy = None + class AccessTest: # initial value @@ -66,6 +71,10 @@ class TestImagePutPixel(AccessTest): pix1 = im1.load() pix2 = im2.load() + for x, y in ((0, "0"), ("0", 0)): + with pytest.raises(TypeError): + pix1[x, y] + for y in range(im1.size[1]): for x in range(im1.size[0]): pix2[x, y] = pix1[x, y] @@ -109,6 +118,13 @@ class TestImagePutPixel(AccessTest): assert_image_equal(im1, im2) + @pytest.mark.skipif(numpy is None, reason="NumPy not installed") + def test_numpy(self): + im = hopper() + pix = im.load() + + assert pix[numpy.int32(1), numpy.int32(2)] == (18, 20, 59) + class TestImageGetPixel(AccessTest): @staticmethod @@ -339,6 +355,24 @@ class TestImagePutPixelError(AccessTest): with pytest.raises(TypeError, match="color must be int or tuple"): im.putpixel((0, 0), v) + @pytest.mark.parametrize( + ("mode", "band_numbers", "match"), + ( + ("L", (0, 2), "color must be int or single-element tuple"), + ("LA", (0, 3), "color must be int, or tuple of one or two elements"), + ( + "RGB", + (0, 2, 5), + "color must be int, or tuple of one, three or four elements", + ), + ), + ) + def test_putpixel_invalid_number_of_bands(self, mode, band_numbers, match): + im = hopper(mode) + for band_number in band_numbers: + with pytest.raises(TypeError, match=match): + im.putpixel((0, 0), (0,) * band_number) + @pytest.mark.parametrize("mode", IMAGE_MODES2) def test_putpixel_type_error2(self, mode): im = hopper(mode) diff --git a/Tests/test_image_array.py b/Tests/test_image_array.py index 980458407..4dbbdd218 100644 --- a/Tests/test_image_array.py +++ b/Tests/test_image_array.py @@ -4,26 +4,32 @@ from PIL import Image from .helper import hopper +numpy = pytest.importorskip("numpy", reason="NumPy not installed") + im = hopper().resize((128, 100)) def test_toarray(): def test(mode): - ai = im.convert(mode).__array_interface__ - return ai["version"], ai["shape"], ai["typestr"], len(ai["data"]) + ai = numpy.array(im.convert(mode)) + return ai.shape, ai.dtype.str, ai.nbytes - # assert test("1") == (3, (100, 128), '|b1', 1600)) - assert test("L") == (3, (100, 128), "|u1", 12800) + # assert test("1") == ((100, 128), '|b1', 1600)) + assert test("L") == ((100, 128), "|u1", 12800) # FIXME: wrong? - assert test("I") == (3, (100, 128), Image._ENDIAN + "i4", 51200) + assert test("I") == ((100, 128), Image._ENDIAN + "i4", 51200) # FIXME: wrong? - assert test("F") == (3, (100, 128), Image._ENDIAN + "f4", 51200) + assert test("F") == ((100, 128), Image._ENDIAN + "f4", 51200) - assert test("LA") == (3, (100, 128, 2), "|u1", 25600) - assert test("RGB") == (3, (100, 128, 3), "|u1", 38400) - assert test("RGBA") == (3, (100, 128, 4), "|u1", 51200) - assert test("RGBX") == (3, (100, 128, 4), "|u1", 51200) + assert test("LA") == ((100, 128, 2), "|u1", 25600) + assert test("RGB") == ((100, 128, 3), "|u1", 38400) + assert test("RGBA") == ((100, 128, 4), "|u1", 51200) + assert test("RGBX") == ((100, 128, 4), "|u1", 51200) + + with Image.open("Tests/images/truncated_jpeg.jpg") as im_truncated: + with pytest.raises(OSError): + numpy.array(im_truncated) def test_fromarray(): @@ -39,10 +45,18 @@ def test_fromarray(): def test(mode): i = im.convert(mode) - a = i.__array_interface__ - a["strides"] = 1 # pretend it's non-contiguous + a = numpy.array(i) # Make wrapper instance for image, new array interface - wrapped = Wrapper(i, a) + wrapped = Wrapper( + i, + { + "shape": a.shape, + "typestr": a.dtype.str, + "version": 3, + "data": a.data, + "strides": 1, # pretend it's non-contiguous + }, + ) out = Image.fromarray(wrapped) return out.mode, out.size, list(i.getdata()) == list(out.getdata()) diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index 6fe1bd962..5dcdac0e4 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -93,7 +93,7 @@ def test_trns_p(tmp_path): im_l.save(f) im_rgb = im.convert("RGB") - assert im_rgb.info["transparency"] == (0, 0, 0) # undone + assert im_rgb.info["transparency"] == (0, 1, 2) # undone im_rgb.save(f) @@ -128,8 +128,8 @@ def test_trns_l(tmp_path): assert "transparency" in im_p.info im_p.save(f) - im_p = pytest.warns(UserWarning, im.convert, "P", palette=Image.ADAPTIVE) - assert "transparency" not in im_p.info + im_p = im.convert("P", palette=Image.ADAPTIVE) + assert "transparency" in im_p.info im_p.save(f) @@ -155,13 +155,19 @@ def test_trns_RGB(tmp_path): assert "transparency" not in im_p.info im_p.save(f) + im = Image.new("RGB", (1, 1)) + im.info["transparency"] = im.getpixel((0, 0)) + im_p = im.convert("P", palette=Image.ADAPTIVE) + assert im_p.info["transparency"] == im_p.getpixel((0, 0)) + im_p.save(f) + def test_gif_with_rgba_palette_to_p(): # See https://github.com/python-pillow/Pillow/issues/2433 with Image.open("Tests/images/hopper.gif") as im: im.info["transparency"] = 255 im.load() - assert im.palette.mode == "RGBA" + assert im.palette.mode == "RGB" im_p = im.convert("P") # Should not raise ValueError: unrecognized raw mode diff --git a/Tests/test_image_paste.py b/Tests/test_image_paste.py index 3740fbcdc..1d3ca8135 100644 --- a/Tests/test_image_paste.py +++ b/Tests/test_image_paste.py @@ -236,7 +236,7 @@ class TestImagingPaste: [ (127, 191, 254, 191), (111, 207, 206, 110), - (255, 255, 255, 0) if mode == "RGBA" else (127, 254, 127, 0), + (127, 254, 127, 0), (207, 207, 239, 239), (191, 191, 190, 191), (207, 206, 111, 112), diff --git a/Tests/test_image_quantize.py b/Tests/test_image_quantize.py index af4172c88..1ceff0842 100644 --- a/Tests/test_image_quantize.py +++ b/Tests/test_image_quantize.py @@ -74,3 +74,13 @@ def test_quantize_dither_diff(): nodither = image.quantize(dither=0, palette=palette) assert dither.tobytes() != nodither.tobytes() + + +def test_transparent_colors_equal(): + im = Image.new("RGBA", (1, 2), (0, 0, 0, 0)) + px = im.load() + px[0, 1] = (255, 255, 255, 0) + + converted = im.quantize() + converted_px = converted.load() + assert converted_px[0, 0] == converted_px[0, 1] diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index ef4ca4101..8bf2ce916 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -4,7 +4,12 @@ import pytest from PIL import Image, ImageDraw -from .helper import assert_image_equal, assert_image_similar, hopper +from .helper import ( + assert_image_equal, + assert_image_similar, + hopper, + mark_if_feature_version, +) class TestImagingResampleVulnerability: @@ -455,6 +460,9 @@ class TestCoreResampleBox: tiled.paste(tile, (x0, y0)) return tiled + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_tiles(self): with Image.open("Tests/images/flower.jpg") as im: assert im.size == (480, 360) @@ -465,6 +473,9 @@ class TestCoreResampleBox: tiled = self.resize_tiled(im, dst_size, *tiles) assert_image_similar(reference, tiled, 0.01) + @mark_if_feature_version( + pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" + ) def test_subsample(self): # This test shows advantages of the subpixel resizing # after supersampling (e.g. during JPEG decoding). diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py index a49abe1b9..17490e1a8 100644 --- a/Tests/test_image_resize.py +++ b/Tests/test_image_resize.py @@ -7,7 +7,12 @@ import pytest from PIL import Image -from .helper import assert_image_equal, assert_image_similar, hopper +from .helper import ( + assert_image_equal, + assert_image_equal_tofile, + assert_image_similar, + hopper, +) class TestImagingCoreResize: @@ -135,6 +140,17 @@ class TestImagingCoreResize: with pytest.raises(ValueError): self.resize(hopper(), (10, 10), 9) + def test_cross_platform(self, tmp_path): + # This test is intended for only check for consistent behaviour across + # platforms. So if a future Pillow change requires that the test file + # be updated, that is okay. + im = hopper().resize((64, 64)) + temp_file = str(tmp_path / "temp.gif") + im.save(temp_file) + + with Image.open(temp_file) as reloaded: + assert_image_equal_tofile(reloaded, "Tests/images/hopper_resized.gif") + @pytest.fixture def gradients_image(): @@ -250,3 +266,7 @@ class TestImageResize: for mode in "1", "P": im = hopper(mode) assert im.resize((20, 20), Image.NEAREST) == im.resize((20, 20)) + + for mode in "I;16", "I;16L", "I;16B", "BGR;15", "BGR;16": + im = hopper(mode) + assert im.resize((20, 20), Image.NEAREST) == im.resize((20, 20)) diff --git a/Tests/test_image_rotate.py b/Tests/test_image_rotate.py index a41d850bb..79ed79042 100644 --- a/Tests/test_image_rotate.py +++ b/Tests/test_image_rotate.py @@ -1,6 +1,11 @@ from PIL import Image -from .helper import assert_image_equal, assert_image_similar, hopper +from .helper import ( + assert_image_equal, + assert_image_equal_tofile, + assert_image_similar, + hopper, +) def rotate(im, mode, angle, center=None, translate=None): @@ -113,15 +118,13 @@ def test_center(): def test_rotate_no_fill(): im = Image.new("RGB", (100, 100), "green") im = im.rotate(45) - with Image.open("Tests/images/rotate_45_no_fill.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/rotate_45_no_fill.png") def test_rotate_with_fill(): im = Image.new("RGB", (100, 100), "green") im = im.rotate(45, fillcolor="white") - with Image.open("Tests/images/rotate_45_with_fill.png") as target: - assert_image_equal(im, target) + assert_image_equal_tofile(im, "Tests/images/rotate_45_with_fill.png") def test_alpha_rotate_no_fill(): diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index c42310c32..dd140955d 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -88,6 +88,8 @@ def test_no_resize(): assert im.size == (64, 64) +# valgrind test is failing with memory allocated in libjpeg +@pytest.mark.valgrind_known_error(reason="Known Failing") def test_DCT_scaling_edges(): # Make an image with red borders and size (N * 8) + 1 to cross DCT grid im = Image.new("RGB", (257, 257), "red") diff --git a/Tests/test_image_transform.py b/Tests/test_image_transform.py index 3ee51178d..845900267 100644 --- a/Tests/test_image_transform.py +++ b/Tests/test_image_transform.py @@ -143,6 +143,41 @@ class TestImageTransform: self._test_alpha_premult(op) + def _test_nearest(self, op, mode): + # create white image with half transparent, + # do op, + # the image should remain white with half transparent + transparent, opaque = { + "RGBA": ((255, 255, 255, 0), (255, 255, 255, 255)), + "LA": ((255, 0), (255, 255)), + }[mode] + im = Image.new(mode, (10, 10), transparent) + im2 = Image.new(mode, (5, 10), opaque) + im.paste(im2, (0, 0)) + + im = op(im, (40, 10)) + + colors = im.getcolors() + assert colors == [ + (20 * 10, opaque), + (20 * 10, transparent), + ] + + @pytest.mark.parametrize("mode", ("RGBA", "LA")) + def test_nearest_resize(self, mode): + def op(im, sz): + return im.resize(sz, Image.NEAREST) + + self._test_nearest(op, mode) + + @pytest.mark.parametrize("mode", ("RGBA", "LA")) + def test_nearest_transform(self, mode): + def op(im, sz): + (w, h) = im.size + return im.transform(sz, Image.EXTENT, (0, 0, w, h), Image.NEAREST) + + self._test_nearest(op, mode) + def test_blank_fill(self): # attempting to hit # https://github.com/python-pillow/Pillow/issues/254 reported diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index 9fab41746..99f3b4e03 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -8,7 +8,13 @@ import pytest from PIL import Image, ImageMode, features -from .helper import assert_image, assert_image_equal, assert_image_similar, hopper +from .helper import ( + assert_image, + assert_image_equal, + assert_image_similar, + assert_image_similar_tofile, + hopper, +) try: from PIL import ImageCms @@ -240,8 +246,7 @@ def test_lab_color(): # i.save('temp.lab.tif') # visually verified vs PS. - with Image.open("Tests/images/hopper.Lab.tif") as target: - assert_image_similar(i, target, 3.5) + assert_image_similar_tofile(i, "Tests/images/hopper.Lab.tif", 3.5) def test_lab_srgb(): diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index a87c1f2be..6be8fafa1 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -6,6 +6,7 @@ from PIL import Image, ImageColor, ImageDraw, ImageFont from .helper import ( assert_image_equal, + assert_image_equal_tofile, assert_image_similar_tofile, hopper, skip_unless_feature, @@ -96,7 +97,7 @@ def test_arc_end_le_start(): draw.arc(BBOX1, start=start, end=end) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_arc_end_le_start.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_arc_end_le_start.png") def test_arc_no_loops(): @@ -174,7 +175,7 @@ def test_arc_high(): draw.arc([110, 10, 189, 189], 20, 150, width=20, fill="white") # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_arc_high.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_arc_high.png") def test_bitmap(): @@ -188,7 +189,7 @@ def test_bitmap(): draw.bitmap((10, 10), small) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_bitmap.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_bitmap.png") def helper_chord(mode, bbox, start, end): @@ -247,8 +248,7 @@ def test_chord_zero_width(): draw.chord(BBOX1, 10, 260, fill="red", outline="yellow", width=0) # Assert - with Image.open("Tests/images/imagedraw_chord_zero_width.png") as expected: - assert_image_equal(im, expected) + assert_image_equal_tofile(im, "Tests/images/imagedraw_chord_zero_width.png") def test_chord_too_fat(): @@ -260,7 +260,7 @@ def test_chord_too_fat(): draw.chord([-150, -150, 99, 99], 15, 60, width=10, fill="white", outline="red") # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_chord_too_fat.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_chord_too_fat.png") def helper_ellipse(mode, bbox): @@ -367,8 +367,7 @@ def test_ellipse_zero_width(): draw.ellipse(BBOX1, fill="green", outline="blue", width=0) # Assert - with Image.open("Tests/images/imagedraw_ellipse_zero_width.png") as expected: - assert_image_equal(im, expected) + assert_image_equal_tofile(im, "Tests/images/imagedraw_ellipse_zero_width.png") def ellipse_various_sizes_helper(filled): @@ -395,17 +394,15 @@ def ellipse_various_sizes_helper(filled): def test_ellipse_various_sizes(): im = ellipse_various_sizes_helper(False) - with Image.open("Tests/images/imagedraw_ellipse_various_sizes.png") as expected: - assert_image_equal(im, expected) + assert_image_equal_tofile(im, "Tests/images/imagedraw_ellipse_various_sizes.png") def test_ellipse_various_sizes_filled(): im = ellipse_various_sizes_helper(True) - with Image.open( - "Tests/images/imagedraw_ellipse_various_sizes_filled.png" - ) as expected: - assert_image_equal(im, expected) + assert_image_equal_tofile( + im, "Tests/images/imagedraw_ellipse_various_sizes_filled.png" + ) def helper_line(points): @@ -417,7 +414,7 @@ def helper_line(points): draw.line(points, fill="yellow", width=2) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_line.png") def test_line1(): @@ -446,7 +443,7 @@ def test_shape1(): draw.shape(s, fill=1) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_shape1.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_shape1.png") def test_shape2(): @@ -467,7 +464,7 @@ def test_shape2(): draw.shape(s, outline="blue") # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_shape2.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_shape2.png") def helper_pieslice(bbox, start, end): @@ -526,8 +523,7 @@ def test_pieslice_zero_width(): draw.pieslice(BBOX1, 10, 260, fill="white", outline="blue", width=0) # Assert - with Image.open("Tests/images/imagedraw_pieslice_zero_width.png") as expected: - assert_image_equal(im, expected) + assert_image_equal_tofile(im, "Tests/images/imagedraw_pieslice_zero_width.png") def test_pieslice_wide(): @@ -539,7 +535,37 @@ def test_pieslice_wide(): draw.pieslice([0, 0, 199, 99], 190, 170, width=10, fill="white", outline="red") # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_pieslice_wide.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_pieslice_wide.png") + + +def test_pieslice_no_spikes(): + im = Image.new("RGB", (161, 161), "white") + draw = ImageDraw.Draw(im) + cxs = ( + [140] * 3 + + list(range(140, 19, -20)) + + [20] * 5 + + list(range(20, 141, 20)) + + [140] * 2 + ) + cys = ( + list(range(80, 141, 20)) + + [140] * 5 + + list(range(140, 19, -20)) + + [20] * 5 + + list(range(20, 80, 20)) + ) + + for cx, cy, angle in zip(cxs, cys, range(0, 360, 15)): + draw.pieslice( + [cx - 100, cy - 100, cx + 100, cy + 100], angle, angle + 1, fill="black" + ) + draw.point([cx, cy], fill="red") + + im_pre_erase = im.copy() + draw.rectangle([21, 21, 139, 139], fill="white") + + assert_image_equal(im, im_pre_erase) def helper_point(points): @@ -551,7 +577,7 @@ def helper_point(points): draw.point(points, fill="yellow") # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_point.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_point.png") def test_point1(): @@ -571,7 +597,7 @@ def helper_polygon(points): draw.polygon(points, fill="red", outline="blue") # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_polygon.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_polygon.png") def test_polygon1(): @@ -595,7 +621,7 @@ def test_polygon_kite(): draw.polygon(KITE_POINTS, fill="blue", outline="yellow") # Assert - assert_image_equal(im, Image.open(expected)) + assert_image_equal_tofile(im, expected) def test_polygon_1px_high(): @@ -609,7 +635,7 @@ def test_polygon_1px_high(): draw.polygon([(0, 1), (0, 1), (2, 1), (2, 1)], "#f00") # Assert - assert_image_equal(im, Image.open(expected)) + assert_image_equal_tofile(im, expected) def helper_rectangle(bbox): @@ -621,7 +647,7 @@ def helper_rectangle(bbox): draw.rectangle(bbox, fill="black", outline="green") # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_rectangle.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle.png") def test_rectangle1(): @@ -656,7 +682,7 @@ def test_rectangle_width(): draw.rectangle(BBOX1, outline="green", width=5) # Assert - assert_image_equal(im, Image.open(expected)) + assert_image_equal_tofile(im, expected) def test_rectangle_width_fill(): @@ -669,7 +695,7 @@ def test_rectangle_width_fill(): draw.rectangle(BBOX1, fill="blue", outline="green", width=5) # Assert - assert_image_equal(im, Image.open(expected)) + assert_image_equal_tofile(im, expected) def test_rectangle_zero_width(): @@ -681,8 +707,7 @@ def test_rectangle_zero_width(): draw.rectangle(BBOX1, fill="blue", outline="green", width=0) # Assert - with Image.open("Tests/images/imagedraw_rectangle_zero_width.png") as expected: - assert_image_equal(im, expected) + assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle_zero_width.png") def test_rectangle_I16(): @@ -694,8 +719,95 @@ def test_rectangle_I16(): draw.rectangle(BBOX1, fill="black", outline="green") # Assert - assert_image_equal( - im.convert("I"), Image.open("Tests/images/imagedraw_rectangle_I.png") + assert_image_equal_tofile(im.convert("I"), "Tests/images/imagedraw_rectangle_I.png") + + +def test_rectangle_translucent_outline(): + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im, "RGBA") + + # Act + draw.rectangle(BBOX1, fill="black", outline=(0, 255, 0, 127), width=5) + + # Assert + assert_image_equal_tofile( + im, "Tests/images/imagedraw_rectangle_translucent_outline.png" + ) + + +@pytest.mark.parametrize( + "xy", + [(10, 20, 190, 180), ([10, 20], [190, 180]), ((10, 20), (190, 180))], +) +def test_rounded_rectangle(xy): + # Arrange + im = Image.new("RGB", (200, 200)) + draw = ImageDraw.Draw(im) + + # Act + draw.rounded_rectangle(xy, 30, fill="red", outline="green", width=5) + + # Assert + assert_image_equal_tofile(im, "Tests/images/imagedraw_rounded_rectangle.png") + + +@pytest.mark.parametrize( + "xy, radius, type", + [ + ((10, 20, 190, 180), 30.5, "given"), + ((10, 10, 181, 190), 90, "width"), + ((10, 20, 190, 181), 85, "height"), + ], +) +def test_rounded_rectangle_non_integer_radius(xy, radius, type): + # Arrange + im = Image.new("RGB", (200, 200)) + draw = ImageDraw.Draw(im) + + # Act + draw.rounded_rectangle(xy, radius, fill="red", outline="green", width=5) + + # Assert + assert_image_equal_tofile( + im, + "Tests/images/imagedraw_rounded_rectangle_non_integer_radius_" + type + ".png", + ) + + +def test_rounded_rectangle_zero_radius(): + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + + # Act + draw.rounded_rectangle(BBOX1, 0, fill="blue", outline="green", width=5) + + # Assert + assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle_width_fill.png") + + +@pytest.mark.parametrize( + "xy, suffix", + [ + ((20, 10, 80, 90), "x"), + ((10, 20, 90, 80), "y"), + ((20, 20, 80, 80), "both"), + ], +) +def test_rounded_rectangle_translucent(xy, suffix): + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im, "RGBA") + + # Act + draw.rounded_rectangle( + xy, 30, fill=(255, 0, 0, 127), outline=(0, 255, 0, 127), width=5 + ) + + # Assert + assert_image_equal_tofile( + im, "Tests/images/imagedraw_rounded_rectangle_" + suffix + ".png" ) @@ -749,7 +861,7 @@ def test_floodfill_border(): ) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_floodfill2.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_floodfill2.png") def test_floodfill_thresh(): @@ -765,7 +877,7 @@ def test_floodfill_thresh(): ImageDraw.floodfill(im, centre_point, ImageColor.getrgb("red"), thresh=30) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_floodfill2.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_floodfill2.png") def test_floodfill_not_negative(): @@ -782,9 +894,7 @@ def test_floodfill_not_negative(): ImageDraw.floodfill(im, (int(W / 4), int(H / 4)), ImageColor.getrgb("red")) # Assert - assert_image_equal( - im, Image.open("Tests/images/imagedraw_floodfill_not_negative.png") - ) + assert_image_equal_tofile(im, "Tests/images/imagedraw_floodfill_not_negative.png") def create_base_image_draw( @@ -799,147 +909,144 @@ def create_base_image_draw( def test_square(): - with Image.open(os.path.join(IMAGES_PATH, "square.png")) as expected: - expected.load() - img, draw = create_base_image_draw((10, 10)) - draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK) - assert_image_equal(img, expected, "square as normal polygon failed") - img, draw = create_base_image_draw((10, 10)) - draw.polygon([(7, 7), (7, 2), (2, 2), (2, 7)], BLACK) - assert_image_equal(img, expected, "square as inverted polygon failed") - img, draw = create_base_image_draw((10, 10)) - draw.rectangle((2, 2, 7, 7), BLACK) - assert_image_equal(img, expected, "square as normal rectangle failed") - img, draw = create_base_image_draw((10, 10)) - draw.rectangle((7, 7, 2, 2), BLACK) - assert_image_equal(img, expected, "square as inverted rectangle failed") + expected = os.path.join(IMAGES_PATH, "square.png") + img, draw = create_base_image_draw((10, 10)) + draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK) + assert_image_equal_tofile(img, expected, "square as normal polygon failed") + img, draw = create_base_image_draw((10, 10)) + draw.polygon([(7, 7), (7, 2), (2, 2), (2, 7)], BLACK) + assert_image_equal_tofile(img, expected, "square as inverted polygon failed") + img, draw = create_base_image_draw((10, 10)) + draw.rectangle((2, 2, 7, 7), BLACK) + assert_image_equal_tofile(img, expected, "square as normal rectangle failed") + img, draw = create_base_image_draw((10, 10)) + draw.rectangle((7, 7, 2, 2), BLACK) + assert_image_equal_tofile(img, expected, "square as inverted rectangle failed") def test_triangle_right(): - with Image.open(os.path.join(IMAGES_PATH, "triangle_right.png")) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK) - assert_image_equal(img, expected, "triangle right failed") + img, draw = create_base_image_draw((20, 20)) + draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK) + assert_image_equal_tofile( + img, os.path.join(IMAGES_PATH, "triangle_right.png"), "triangle right failed" + ) def test_line_horizontal(): - with Image.open( - os.path.join(IMAGES_PATH, "line_horizontal_w2px_normal.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 5, 14, 5), BLACK, 2) - assert_image_equal( - img, expected, "line straight horizontal normal 2px wide failed" - ) - with Image.open( - os.path.join(IMAGES_PATH, "line_horizontal_w2px_inverted.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((14, 5, 5, 5), BLACK, 2) - assert_image_equal( - img, expected, "line straight horizontal inverted 2px wide failed" - ) - with Image.open(os.path.join(IMAGES_PATH, "line_horizontal_w3px.png")) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 5, 14, 5), BLACK, 3) - assert_image_equal( - img, expected, "line straight horizontal normal 3px wide failed" - ) - img, draw = create_base_image_draw((20, 20)) - draw.line((14, 5, 5, 5), BLACK, 3) - assert_image_equal( - img, expected, "line straight horizontal inverted 3px wide failed" - ) - with Image.open( - os.path.join(IMAGES_PATH, "line_horizontal_w101px.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((200, 110)) - draw.line((5, 55, 195, 55), BLACK, 101) - assert_image_equal(img, expected, "line straight horizontal 101px wide failed") + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 5, 14, 5), BLACK, 2) + assert_image_equal_tofile( + img, + os.path.join(IMAGES_PATH, "line_horizontal_w2px_normal.png"), + "line straight horizontal normal 2px wide failed", + ) + + img, draw = create_base_image_draw((20, 20)) + draw.line((14, 5, 5, 5), BLACK, 2) + assert_image_equal_tofile( + img, + os.path.join(IMAGES_PATH, "line_horizontal_w2px_inverted.png"), + "line straight horizontal inverted 2px wide failed", + ) + + expected = os.path.join(IMAGES_PATH, "line_horizontal_w3px.png") + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 5, 14, 5), BLACK, 3) + assert_image_equal_tofile( + img, expected, "line straight horizontal normal 3px wide failed" + ) + img, draw = create_base_image_draw((20, 20)) + draw.line((14, 5, 5, 5), BLACK, 3) + assert_image_equal_tofile( + img, expected, "line straight horizontal inverted 3px wide failed" + ) + + img, draw = create_base_image_draw((200, 110)) + draw.line((5, 55, 195, 55), BLACK, 101) + assert_image_equal_tofile( + img, + os.path.join(IMAGES_PATH, "line_horizontal_w101px.png"), + "line straight horizontal 101px wide failed", + ) def test_line_h_s1_w2(): pytest.skip("failing") - with Image.open( - os.path.join(IMAGES_PATH, "line_horizontal_slope1px_w2px.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 5, 14, 6), BLACK, 2) - assert_image_equal(img, expected, "line horizontal 1px slope 2px wide failed") + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 5, 14, 6), BLACK, 2) + assert_image_equal_tofile( + img, + os.path.join(IMAGES_PATH, "line_horizontal_slope1px_w2px.png"), + "line horizontal 1px slope 2px wide failed", + ) def test_line_vertical(): - with Image.open( - os.path.join(IMAGES_PATH, "line_vertical_w2px_normal.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 5, 5, 14), BLACK, 2) - assert_image_equal( - img, expected, "line straight vertical normal 2px wide failed" - ) - with Image.open( - os.path.join(IMAGES_PATH, "line_vertical_w2px_inverted.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 14, 5, 5), BLACK, 2) - assert_image_equal( - img, expected, "line straight vertical inverted 2px wide failed" - ) - with Image.open(os.path.join(IMAGES_PATH, "line_vertical_w3px.png")) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 5, 5, 14), BLACK, 3) - assert_image_equal( - img, expected, "line straight vertical normal 3px wide failed" - ) - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 14, 5, 5), BLACK, 3) - assert_image_equal( - img, expected, "line straight vertical inverted 3px wide failed" - ) - with Image.open(os.path.join(IMAGES_PATH, "line_vertical_w101px.png")) as expected: - expected.load() - img, draw = create_base_image_draw((110, 200)) - draw.line((55, 5, 55, 195), BLACK, 101) - assert_image_equal(img, expected, "line straight vertical 101px wide failed") - with Image.open( - os.path.join(IMAGES_PATH, "line_vertical_slope1px_w2px.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 5, 6, 14), BLACK, 2) - assert_image_equal(img, expected, "line vertical 1px slope 2px wide failed") + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 5, 5, 14), BLACK, 2) + assert_image_equal_tofile( + img, + os.path.join(IMAGES_PATH, "line_vertical_w2px_normal.png"), + "line straight vertical normal 2px wide failed", + ) + + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 14, 5, 5), BLACK, 2) + assert_image_equal_tofile( + img, + os.path.join(IMAGES_PATH, "line_vertical_w2px_inverted.png"), + "line straight vertical inverted 2px wide failed", + ) + + expected = os.path.join(IMAGES_PATH, "line_vertical_w3px.png") + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 5, 5, 14), BLACK, 3) + assert_image_equal_tofile( + img, expected, "line straight vertical normal 3px wide failed" + ) + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 14, 5, 5), BLACK, 3) + assert_image_equal_tofile( + img, expected, "line straight vertical inverted 3px wide failed" + ) + + img, draw = create_base_image_draw((110, 200)) + draw.line((55, 5, 55, 195), BLACK, 101) + assert_image_equal_tofile( + img, + os.path.join(IMAGES_PATH, "line_vertical_w101px.png"), + "line straight vertical 101px wide failed", + ) + + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 5, 6, 14), BLACK, 2) + assert_image_equal_tofile( + img, + os.path.join(IMAGES_PATH, "line_vertical_slope1px_w2px.png"), + "line vertical 1px slope 2px wide failed", + ) def test_line_oblique_45(): - with Image.open( - os.path.join(IMAGES_PATH, "line_oblique_45_w3px_a.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 5, 14, 14), BLACK, 3) - assert_image_equal(img, expected, "line oblique 45 normal 3px wide A failed") - img, draw = create_base_image_draw((20, 20)) - draw.line((14, 14, 5, 5), BLACK, 3) - assert_image_equal(img, expected, "line oblique 45 inverted 3px wide A failed") - with Image.open( - os.path.join(IMAGES_PATH, "line_oblique_45_w3px_b.png") - ) as expected: - expected.load() - img, draw = create_base_image_draw((20, 20)) - draw.line((14, 5, 5, 14), BLACK, 3) - assert_image_equal(img, expected, "line oblique 45 normal 3px wide B failed") - img, draw = create_base_image_draw((20, 20)) - draw.line((5, 14, 14, 5), BLACK, 3) - assert_image_equal(img, expected, "line oblique 45 inverted 3px wide B failed") + expected = os.path.join(IMAGES_PATH, "line_oblique_45_w3px_a.png") + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 5, 14, 14), BLACK, 3) + assert_image_equal_tofile(img, expected, "line oblique 45 normal 3px wide A failed") + img, draw = create_base_image_draw((20, 20)) + draw.line((14, 14, 5, 5), BLACK, 3) + assert_image_equal_tofile( + img, expected, "line oblique 45 inverted 3px wide A failed" + ) + + expected = os.path.join(IMAGES_PATH, "line_oblique_45_w3px_b.png") + img, draw = create_base_image_draw((20, 20)) + draw.line((14, 5, 5, 14), BLACK, 3) + assert_image_equal_tofile(img, expected, "line oblique 45 normal 3px wide B failed") + img, draw = create_base_image_draw((20, 20)) + draw.line((5, 14, 14, 5), BLACK, 3) + assert_image_equal_tofile( + img, expected, "line oblique 45 inverted 3px wide B failed" + ) def test_wide_line_dot(): @@ -1185,7 +1292,7 @@ def test_draw_regular_polygon(n_sides, rotation, polygon_name): draw = ImageDraw.Draw(im) bounding_circle = ((W // 2, H // 2), 25) draw.regular_polygon(bounding_circle, n_sides, rotation=rotation, fill="red") - assert_image_equal(im, Image.open(filename)) + assert_image_equal_tofile(im, filename) @pytest.mark.parametrize( @@ -1272,3 +1379,22 @@ def test_compute_regular_polygon_vertices_input_error_handling( with pytest.raises(expected_error) as e: ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, rotation) assert str(e.value) == error_message + + +def test_continuous_horizontal_edges_polygon(): + xy = [ + (2, 6), + (6, 6), + (12, 6), + (12, 12), + (8, 12), + (8, 8), + (4, 8), + (2, 8), + ] + img, draw = create_base_image_draw((16, 16)) + draw.polygon(xy, BLACK) + expected = os.path.join(IMAGES_PATH, "continuous_horizontal_edges_polygon.png") + assert_image_equal_tofile( + img, expected, "continuous horizontal edges polygon failed" + ) diff --git a/Tests/test_imagedraw2.py b/Tests/test_imagedraw2.py index b78dfe85b..3a70176ce 100644 --- a/Tests/test_imagedraw2.py +++ b/Tests/test_imagedraw2.py @@ -4,7 +4,8 @@ from PIL import Image, ImageDraw, ImageDraw2 from .helper import ( assert_image_equal, - assert_image_similar, + assert_image_equal_tofile, + assert_image_similar_tofile, hopper, skip_unless_feature, ) @@ -61,7 +62,7 @@ def helper_ellipse(mode, bbox): draw.ellipse(bbox, pen, brush) # Assert - assert_image_similar(im, Image.open(expected), 1) + assert_image_similar_tofile(im, expected, 1) def test_ellipse1(): @@ -82,7 +83,7 @@ def test_ellipse_edge(): draw.ellipse(((0, 0), (W - 1, H - 1)), brush) # Assert - assert_image_similar(im, Image.open("Tests/images/imagedraw_ellipse_edge.png"), 1) + assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_edge.png", 1) def helper_line(points): @@ -95,7 +96,7 @@ def helper_line(points): draw.line(points, pen) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_line.png") def test_line1_pen(): @@ -118,7 +119,7 @@ def test_line_pen_as_brush(): draw.line(POINTS1, pen, brush) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_line.png") def helper_polygon(points): @@ -132,7 +133,7 @@ def helper_polygon(points): draw.polygon(points, pen, brush) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_polygon.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_polygon.png") def test_polygon1(): @@ -154,7 +155,7 @@ def helper_rectangle(bbox): draw.rectangle(bbox, pen, brush) # Assert - assert_image_equal(im, Image.open("Tests/images/imagedraw_rectangle.png")) + assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle.png") def test_rectangle1(): @@ -178,7 +179,7 @@ def test_big_rectangle(): draw.rectangle(bbox, brush) # Assert - assert_image_similar(im, Image.open(expected), 1) + assert_image_similar_tofile(im, expected, 1) @skip_unless_feature("freetype2") @@ -193,7 +194,7 @@ def test_text(): draw.text((5, 5), "ImageDraw2", font) # Assert - assert_image_similar(im, Image.open(expected), 13) + assert_image_similar_tofile(im, expected, 13) @skip_unless_feature("freetype2") diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index b4107e8e3..892087916 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -248,4 +248,4 @@ class TestPyDecoder: def test_oserror(self): im = Image.new("RGB", (1, 1)) with pytest.raises(OSError): - im.save(BytesIO(), "JPEG2000") + im.save(BytesIO(), "JPEG2000", num_resolutions=2) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 0c219fed1..892bd0ed1 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -13,7 +13,6 @@ from PIL import Image, ImageDraw, ImageFont, features from .helper import ( assert_image_equal, assert_image_equal_tofile, - assert_image_similar, assert_image_similar_tofile, is_win32, skip_unless_feature, @@ -52,7 +51,7 @@ class TestImageFont: ttf_copy = ttf.font_variant(size=FONT_SIZE + 1) assert ttf_copy.size == FONT_SIZE + 1 - second_font_path = "Tests/fonts/DejaVuSans.ttf" + second_font_path = "Tests/fonts/DejaVuSans/DejaVuSans.ttf" ttf_copy = ttf.font_variant(font=second_font_path) assert ttf_copy.path == second_font_path @@ -130,8 +129,10 @@ class TestImageFont: draw.text((10, 10), txt, font=ttf) target = "Tests/images/transparent_background_text.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 4.09) + assert_image_similar_tofile(im, target, 4.09) + + target = "Tests/images/transparent_background_text_L.png" + assert_image_similar_tofile(im.convert("L"), target, 0.01) def test_textsize_equal(self): im = Image.new(mode="RGB", size=(300, 100)) @@ -143,11 +144,10 @@ class TestImageFont: draw.text((10, 10), txt, font=ttf) draw.rectangle((10, 10, 10 + size[0], 10 + size[1])) - target = "Tests/images/rectangle_surrounding_text.png" - with Image.open(target) as target_img: - - # Epsilon ~.5 fails with FreeType 2.7 - assert_image_similar(im, target_img, 2.5) + # Epsilon ~.5 fails with FreeType 2.7 + assert_image_similar_tofile( + im, "Tests/images/rectangle_surrounding_text.png", 2.5 + ) @pytest.mark.parametrize( "text, mode, font, size, length_basic, length_raqm", @@ -156,8 +156,8 @@ class TestImageFont: ("text", "L", "FreeMono.ttf", 15, 36, 36), ("text", "1", "FreeMono.ttf", 15, 36, 36), # issue 4177 - ("rrr", "L", "DejaVuSans.ttf", 18, 21, 22.21875), - ("rrr", "1", "DejaVuSans.ttf", 18, 24, 22.21875), + ("rrr", "L", "DejaVuSans/DejaVuSans.ttf", 18, 21, 22.21875), + ("rrr", "1", "DejaVuSans/DejaVuSans.ttf", 18, 24, 22.21875), # test 'l' not including extra margin # using exact value 2047 / 64 for raqm, checked with debugger ("ill", "L", "OpenSansCondensed-LightItalic.ttf", 63, 33, 31.984375), @@ -191,13 +191,10 @@ class TestImageFont: draw.text((0, y), line, font=ttf) y += line_spacing - target = "Tests/images/multiline_text.png" - with Image.open(target) as target_img: - - # some versions of freetype have different horizontal spacing. - # setting a tight epsilon, I'm showing the original test failure - # at epsilon = ~38. - assert_image_similar(im, target_img, 6.2) + # some versions of freetype have different horizontal spacing. + # setting a tight epsilon, I'm showing the original test failure + # at epsilon = ~38. + assert_image_similar_tofile(im, "Tests/images/multiline_text.png", 6.2) def test_render_multiline_text(self): ttf = self.get_font() @@ -208,11 +205,8 @@ class TestImageFont: draw = ImageDraw.Draw(im) draw.text((0, 0), TEST_TEXT, font=ttf) - target = "Tests/images/multiline_text.png" - with Image.open(target) as target_img: - - # Epsilon ~.5 fails with FreeType 2.7 - assert_image_similar(im, target_img, 6.2) + # Epsilon ~.5 fails with FreeType 2.7 + assert_image_similar_tofile(im, "Tests/images/multiline_text.png", 6.2) # Test that text() can pass on additional arguments # to multiline_text() @@ -227,11 +221,10 @@ class TestImageFont: draw = ImageDraw.Draw(im) draw.multiline_text((0, 0), TEST_TEXT, font=ttf, align=align) - target = "Tests/images/multiline_text" + ext + ".png" - with Image.open(target) as target_img: - - # Epsilon ~.5 fails with FreeType 2.7 - assert_image_similar(im, target_img, 6.2) + # Epsilon ~.5 fails with FreeType 2.7 + assert_image_similar_tofile( + im, "Tests/images/multiline_text" + ext + ".png", 6.2 + ) def test_unknown_align(self): im = Image.new(mode="RGB", size=(300, 100)) @@ -285,11 +278,8 @@ class TestImageFont: draw = ImageDraw.Draw(im) draw.multiline_text((0, 0), TEST_TEXT, font=ttf, spacing=10) - target = "Tests/images/multiline_text_spacing.png" - with Image.open(target) as target_img: - - # Epsilon ~.5 fails with FreeType 2.7 - assert_image_similar(im, target_img, 6.2) + # Epsilon ~.5 fails with FreeType 2.7 + assert_image_similar_tofile(im, "Tests/images/multiline_text_spacing.png", 6.2) def test_rotated_transposed_font(self): img_grey = Image.new("L", (100, 100)) @@ -423,15 +413,12 @@ class TestImageFont: im = Image.new(mode="RGB", size=(300, 100)) draw = ImageDraw.Draw(im) - target = "Tests/images/default_font.png" - with Image.open(target) as target_img: + # Act + default_font = ImageFont.load_default() + draw.text((10, 10), txt, font=default_font) - # Act - default_font = ImageFont.load_default() - draw.text((10, 10), txt, font=default_font) - - # Assert - assert_image_equal(im, target_img) + # Assert + assert_image_equal_tofile(im, "Tests/images/default_font.png") def test_getsize_empty(self): # issue #2614 @@ -680,13 +667,11 @@ class TestImageFont: d.text((10, 10), "Text", font=font, fill="black") try: - with Image.open(path) as expected: - assert_image_similar(im, expected, epsilon) + assert_image_similar_tofile(im, path, epsilon) except AssertionError: if "_adobe" in path: path = path.replace("_adobe", "_adobe_older_harfbuzz") - with Image.open(path) as expected: - assert_image_similar(im, expected, epsilon) + assert_image_similar_tofile(im, path, epsilon) else: raise @@ -734,6 +719,13 @@ class TestImageFont: font.set_variation_by_axes([100]) self._check_text(font, "Tests/images/variation_tiny_axes.png", 32.5) + def test_textbbox_non_freetypefont(self): + im = Image.new("RGB", (200, 200)) + d = ImageDraw.Draw(im) + default_font = ImageFont.load_default() + with pytest.raises(ValueError): + d.textbbox((0, 0), "test", font=default_font) + @pytest.mark.parametrize( "anchor, left, left_old, top", ( @@ -777,8 +769,7 @@ class TestImageFont: assert d.textbbox((0, 0), text, f, anchor=anchor) == bbox_expected - with Image.open(path) as expected: - assert_image_similar(im, expected, 7) + assert_image_similar_tofile(im, path, 7) @pytest.mark.parametrize( "anchor, align", @@ -816,8 +807,7 @@ class TestImageFont: (300, 200), text, fill="black", anchor=anchor, font=f, align=align ) - with Image.open(target) as expected: - assert_image_similar(im, expected, 4) + assert_image_similar_tofile(im, target, 4) def test_anchor_invalid(self): font = self.get_font() @@ -855,7 +845,7 @@ class TestImageFont: layout_name = ["basic", "raqm"][self.LAYOUT_ENGINE] target = f"Tests/images/bitmap_font_{bpp}_{layout_name}.png" font = ImageFont.truetype( - f"Tests/fonts/DejaVuSans-24-{bpp}-stripped.ttf", + f"Tests/fonts/DejaVuSans/DejaVuSans-24-{bpp}-stripped.ttf", 24, layout_engine=self.LAYOUT_ENGINE, ) @@ -875,8 +865,7 @@ class TestImageFont: d = ImageDraw.Draw(im) d.text((10, 10), txt, font=ttf, fill="#fa6", embedded_color=True) - with Image.open("Tests/images/standard_embedded.png") as expected: - assert_image_similar(im, expected, 6.2) + assert_image_similar_tofile(im, "Tests/images/standard_embedded.png", 6.2) @skip_unless_feature_version("freetype2", "2.5.0") def test_cbdt(self): @@ -890,13 +879,12 @@ class TestImageFont: im = Image.new("RGB", (150, 150), "white") d = ImageDraw.Draw(im) - d.text((10, 10), "\U0001f469", embedded_color=True, font=font) + d.text((10, 10), "\U0001f469", font=font, embedded_color=True) - with Image.open("Tests/images/cbdt_notocoloremoji.png") as expected: - assert_image_similar(im, expected, 6.2) - except IOError as e: + assert_image_similar_tofile(im, "Tests/images/cbdt_notocoloremoji.png", 6.2) + except IOError as e: # pragma: no cover assert str(e) in ("unimplemented feature", "unknown file format") - pytest.skip("freetype compiled without libpng or unsupported") + pytest.skip("freetype compiled without libpng or CBDT support") @skip_unless_feature_version("freetype2", "2.5.0") def test_cbdt_mask(self): @@ -912,11 +900,50 @@ class TestImageFont: d.text((10, 10), "\U0001f469", "black", font=font) - with Image.open("Tests/images/cbdt_notocoloremoji_mask.png") as expected: - assert_image_similar(im, expected, 6.2) - except IOError as e: + assert_image_similar_tofile( + im, "Tests/images/cbdt_notocoloremoji_mask.png", 6.2 + ) + except IOError as e: # pragma: no cover assert str(e) in ("unimplemented feature", "unknown file format") - pytest.skip("freetype compiled without libpng or unsupported") + pytest.skip("freetype compiled without libpng or CBDT support") + + @skip_unless_feature_version("freetype2", "2.5.1") + def test_sbix(self): + try: + font = ImageFont.truetype( + "Tests/fonts/chromacheck-sbix.woff", + size=300, + layout_engine=self.LAYOUT_ENGINE, + ) + + im = Image.new("RGB", (400, 400), "white") + d = ImageDraw.Draw(im) + + d.text((50, 50), "\uE901", font=font, embedded_color=True) + + assert_image_similar_tofile(im, "Tests/images/chromacheck-sbix.png", 1) + except IOError as e: # pragma: no cover + assert str(e) in ("unimplemented feature", "unknown file format") + pytest.skip("freetype compiled without libpng or SBIX support") + + @skip_unless_feature_version("freetype2", "2.5.1") + def test_sbix_mask(self): + try: + font = ImageFont.truetype( + "Tests/fonts/chromacheck-sbix.woff", + size=300, + layout_engine=self.LAYOUT_ENGINE, + ) + + im = Image.new("RGB", (400, 400), "white") + d = ImageDraw.Draw(im) + + d.text((50, 50), "\uE901", (100, 0, 0), font=font) + + assert_image_similar_tofile(im, "Tests/images/chromacheck-sbix_mask.png", 1) + except IOError as e: # pragma: no cover + assert str(e) in ("unimplemented feature", "unknown file format") + pytest.skip("freetype compiled without libpng or SBIX support") @skip_unless_feature_version("freetype2", "2.10.0") def test_colr(self): @@ -929,10 +956,9 @@ class TestImageFont: im = Image.new("RGB", (300, 75), "white") d = ImageDraw.Draw(im) - d.text((15, 5), "Bungee", embedded_color=True, font=font) + d.text((15, 5), "Bungee", font=font, embedded_color=True) - with Image.open("Tests/images/colr_bungee.png") as expected: - assert_image_similar(im, expected, 21) + assert_image_similar_tofile(im, "Tests/images/colr_bungee.png", 21) @skip_unless_feature_version("freetype2", "2.10.0") def test_colr_mask(self): @@ -947,8 +973,7 @@ class TestImageFont: d.text((15, 5), "Bungee", "black", font=font) - with Image.open("Tests/images/colr_bungee_mask.png") as expected: - assert_image_similar(im, expected, 22) + assert_image_similar_tofile(im, "Tests/images/colr_bungee_mask.png", 22) @skip_unless_feature("raqm") @@ -963,7 +988,9 @@ def test_render_mono_size(): im = Image.new("P", (100, 30), "white") draw = ImageDraw.Draw(im) ttf = ImageFont.truetype( - "Tests/fonts/DejaVuSans.ttf", 18, layout_engine=ImageFont.LAYOUT_BASIC + "Tests/fonts/DejaVuSans/DejaVuSans.ttf", + 18, + layout_engine=ImageFont.LAYOUT_BASIC, ) draw.text((10, 10), "r" * 10, "black", ttf) @@ -980,3 +1007,16 @@ def test_freetype_deprecation(monkeypatch): # Act / Assert with pytest.warns(DeprecationWarning): ImageFont.truetype(FONT_PATH, FONT_SIZE) + + +@pytest.mark.parametrize( + "test_file", + [ + "Tests/fonts/oom-e8e927ba6c0d38274a37c1567560eb33baf74627.ttf", + ], +) +def test_oom(test_file): + with open(test_file, "rb") as f: + font = ImageFont.truetype(BytesIO(f.read())) + with pytest.raises(Image.DecompressionBombError): + font.getmask("Test Text") diff --git a/Tests/test_imagefontctl.py b/Tests/test_imagefontctl.py index 82e2b4ebc..f2a914ff7 100644 --- a/Tests/test_imagefontctl.py +++ b/Tests/test_imagefontctl.py @@ -4,13 +4,13 @@ from packaging.version import parse as parse_version from PIL import Image, ImageDraw, ImageFont, features from .helper import ( - assert_image_similar, + assert_image_similar_tofile, skip_unless_feature, skip_unless_feature_version, ) FONT_SIZE = 20 -FONT_PATH = "Tests/fonts/DejaVuSans.ttf" +FONT_PATH = "Tests/fonts/DejaVuSans/DejaVuSans.ttf" pytestmark = skip_unless_feature("raqm") @@ -31,8 +31,7 @@ def test_complex_text(): draw.text((0, 0), "اهلا عمان", font=ttf, fill=500) target = "Tests/images/test_text.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) def test_y_offset(): @@ -43,8 +42,7 @@ def test_y_offset(): draw.text((0, 0), "العالم العربي", font=ttf, fill=500) target = "Tests/images/test_y_offset.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 1.7) + assert_image_similar_tofile(im, target, 1.7) def test_complex_unicode_text(): @@ -55,8 +53,7 @@ def test_complex_unicode_text(): draw.text((0, 0), "السلام عليكم", font=ttf, fill=500) target = "Tests/images/test_complex_unicode_text.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) ttf = ImageFont.truetype("Tests/fonts/KhmerOSBattambang-Regular.ttf", FONT_SIZE) @@ -65,8 +62,7 @@ def test_complex_unicode_text(): draw.text((0, 0), "លោកុប្បត្តិ", font=ttf, fill=500) target = "Tests/images/test_complex_unicode_text2.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 2.33) + assert_image_similar_tofile(im, target, 2.33) def test_text_direction_rtl(): @@ -77,8 +73,7 @@ def test_text_direction_rtl(): draw.text((0, 0), "English عربي", font=ttf, fill=500, direction="rtl") target = "Tests/images/test_direction_rtl.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) def test_text_direction_ltr(): @@ -89,8 +84,7 @@ def test_text_direction_ltr(): draw.text((0, 0), "سلطنة عمان Oman", font=ttf, fill=500, direction="ltr") target = "Tests/images/test_direction_ltr.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) def test_text_direction_rtl2(): @@ -101,8 +95,7 @@ def test_text_direction_rtl2(): draw.text((0, 0), "Oman سلطنة عمان", font=ttf, fill=500, direction="rtl") target = "Tests/images/test_direction_ltr.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) def test_text_direction_ttb(): @@ -117,8 +110,7 @@ def test_text_direction_ttb(): pytest.skip("libraqm 0.7 or greater not available") target = "Tests/images/test_direction_ttb.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 2.8) + assert_image_similar_tofile(im, target, 2.8) def test_text_direction_ttb_stroke(): @@ -141,8 +133,7 @@ def test_text_direction_ttb_stroke(): pytest.skip("libraqm 0.7 or greater not available") target = "Tests/images/test_direction_ttb_stroke.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 19.4) + assert_image_similar_tofile(im, target, 19.4) def test_ligature_features(): @@ -152,8 +143,7 @@ def test_ligature_features(): draw = ImageDraw.Draw(im) draw.text((0, 0), "filling", font=ttf, fill=500, features=["-liga"]) target = "Tests/images/test_ligature_features.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) liga_size = ttf.getsize("fi", features=["-liga"]) assert liga_size == (13, 19) @@ -167,8 +157,7 @@ def test_kerning_features(): draw.text((0, 0), "TeToAV", font=ttf, fill=500, features=["-kern"]) target = "Tests/images/test_kerning_features.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) def test_arabictext_features(): @@ -185,8 +174,7 @@ def test_arabictext_features(): ) target = "Tests/images/test_arabictext_features.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) def test_x_max_and_y_offset(): @@ -197,8 +185,7 @@ def test_x_max_and_y_offset(): draw.text((0, 0), "لح", font=ttf, fill=500) target = "Tests/images/test_x_max_and_y_offset.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) def test_language(): @@ -209,8 +196,7 @@ def test_language(): draw.text((0, 0), "абвг", font=ttf, fill=500, language="sr") target = "Tests/images/test_language.png" - with Image.open(target) as target_img: - assert_image_similar(im, target_img, 0.5) + assert_image_similar_tofile(im, target, 0.5) @pytest.mark.parametrize("mode", ("L", "1")) @@ -287,8 +273,7 @@ def test_anchor_ttb(anchor): if str(ex) == "libraqm 0.7 or greater required for 'ttb' direction": pytest.skip("libraqm 0.7 or greater not available") - with Image.open(path) as expected: - assert_image_similar(im, expected, 1) # fails at 5 + assert_image_similar_tofile(im, path, 1) # fails at 5 combine_tests = ( @@ -351,8 +336,7 @@ def test_combine(name, text, dir, anchor, epsilon): if str(ex) == "libraqm 0.7 or greater required for 'ttb' direction": pytest.skip("libraqm 0.7 or greater not available") - with Image.open(path) as expected: - assert_image_similar(im, expected, epsilon) + assert_image_similar_tofile(im, path, epsilon) @pytest.mark.parametrize( @@ -384,8 +368,7 @@ def test_combine_multiline(anchor, align): d.rectangle(bbox, outline="red") d.multiline_text((200, 200), text, fill="black", anchor=anchor, font=f, align=align) - with Image.open(path) as expected: - assert_image_similar(im, expected, 0.015) + assert_image_similar_tofile(im, path, 0.015) def test_anchor_invalid_ttb(): diff --git a/Tests/test_imagemorph.py b/Tests/test_imagemorph.py index 087c39e01..368c2bba1 100644 --- a/Tests/test_imagemorph.py +++ b/Tests/test_imagemorph.py @@ -3,7 +3,7 @@ import pytest from PIL import Image, ImageMorph, _imagingmorph -from .helper import assert_image_equal, hopper +from .helper import assert_image_equal_tofile, hopper def string_to_img(image_string): @@ -57,8 +57,7 @@ def assert_img_equal_img_string(A, Bstring): def test_str_to_img(): - with Image.open("Tests/images/morph_a.png") as im: - assert_image_equal(A, im) + assert_image_equal_tofile(A, "Tests/images/morph_a.png") def create_lut(): @@ -236,19 +235,19 @@ def test_negate(): ) -def test_non_binary_images(): +def test_incorrect_mode(): im = hopper("RGB") mop = ImageMorph.MorphOp(op_name="erosion8") - with pytest.raises(Exception) as e: + with pytest.raises(ValueError) as e: mop.apply(im) - assert str(e.value) == "Image must be binary, meaning it must use mode L" - with pytest.raises(Exception) as e: + assert str(e.value) == "Image mode must be L" + with pytest.raises(ValueError) as e: mop.match(im) - assert str(e.value) == "Image must be binary, meaning it must use mode L" - with pytest.raises(Exception) as e: + assert str(e.value) == "Image mode must be L" + with pytest.raises(ValueError) as e: mop.get_on_pixels(im) - assert str(e.value) == "Image must be binary, meaning it must use mode L" + assert str(e.value) == "Image mode must be L" def test_add_patterns(): diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index f17bfdd2f..acd20bb58 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -5,6 +5,7 @@ from PIL import Image, ImageDraw, ImageOps, ImageStat, features from .helper import ( assert_image_equal, assert_image_similar, + assert_image_similar_tofile, assert_tuple_approx_equal, hopper, ) @@ -28,6 +29,7 @@ def test_sanity(): ImageOps.autocontrast(hopper("L"), cutoff=(2, 10)) ImageOps.autocontrast(hopper("L"), ignore=[0, 255]) ImageOps.autocontrast(hopper("L"), mask=hopper("L")) + ImageOps.autocontrast(hopper("L"), preserve_tone=True) ImageOps.colorize(hopper("L"), (0, 0, 0), (255, 255, 255)) ImageOps.colorize(hopper("L"), "black", "white") @@ -35,6 +37,9 @@ def test_sanity(): ImageOps.pad(hopper("L"), (128, 128)) ImageOps.pad(hopper("RGB"), (128, 128)) + ImageOps.contain(hopper("L"), (128, 128)) + ImageOps.contain(hopper("RGB"), (128, 128)) + ImageOps.crop(hopper("L"), 1) ImageOps.crop(hopper("RGB"), 1) @@ -97,6 +102,13 @@ def test_fit_same_ratio(): assert new_im.size == (1000, 755) +@pytest.mark.parametrize("new_size", ((256, 256), (512, 256), (256, 512))) +def test_contain(new_size): + im = hopper() + new_im = ImageOps.contain(im, new_size) + assert new_im.size == (256, 256) + + def test_pad(): # Same ratio im = hopper() @@ -112,10 +124,9 @@ def test_pad(): new_im = ImageOps.pad(im, new_size, color=color, centering=centering) assert new_im.size == new_size - with Image.open( - "Tests/images/imageops_pad_" + label + "_" + str(i) + ".jpg" - ) as target: - assert_image_similar(new_im, target, 6) + assert_image_similar_tofile( + new_im, "Tests/images/imageops_pad_" + label + "_" + str(i) + ".jpg", 6 + ) def test_pil163(): @@ -145,6 +156,19 @@ def test_scale(): assert newimg.size == (25, 25) +def test_expand_palette(): + im = Image.open("Tests/images/p_16.tga") + im_expanded = ImageOps.expand(im, 10, (255, 0, 0)) + + px = im_expanded.convert("RGB").load() + assert px[0, 0] == (255, 0, 0) + + im_cropped = im_expanded.crop( + (10, 10, im_expanded.width - 10, im_expanded.height - 10) + ) + assert_image_equal(im_cropped, im) + + def test_colorize_2color(): # Test the colorizing function with 2-color functionality @@ -291,6 +315,7 @@ def test_exif_transpose(): else: assert transposed_im.info["exif"] != original_exif + assert 0x0112 in im.getexif() assert 0x0112 not in transposed_im.getexif() # Repeat the operation to test that it does not keep transposing @@ -336,7 +361,7 @@ def test_autocontrast_mask_toy_input(): assert ImageStat.Stat(result_nomask).median == [128] -def test_auto_contrast_mask_real_input(): +def test_autocontrast_mask_real_input(): # Test the autocontrast with a rectangular mask with Image.open("Tests/images/iptc.jpg") as img: @@ -362,3 +387,52 @@ def test_auto_contrast_mask_real_input(): threshold=2, msg="autocontrast without mask pixel incorrect", ) + + +def test_autocontrast_preserve_tone(): + def autocontrast(mode, preserve_tone): + im = hopper(mode) + return ImageOps.autocontrast(im, preserve_tone=preserve_tone).histogram() + + assert autocontrast("RGB", True) != autocontrast("RGB", False) + assert autocontrast("L", True) == autocontrast("L", False) + + +def test_autocontrast_preserve_gradient(): + gradient = Image.linear_gradient("L") + + # test with a grayscale gradient that extends to 0,255. + # Should be a noop. + out = ImageOps.autocontrast(gradient, cutoff=0, preserve_tone=True) + + assert_image_equal(gradient, out) + + # cutoff the top and bottom + # autocontrast should make the first and last histogram entries equal + # and, with rounding, should be 10% of the image pixels + out = ImageOps.autocontrast(gradient, cutoff=10, preserve_tone=True) + hist = out.histogram() + assert hist[0] == hist[-1] + assert hist[-1] == 256 * round(256 * 0.10) + + # in rgb + img = gradient.convert("RGB") + out = ImageOps.autocontrast(img, cutoff=0, preserve_tone=True) + assert_image_equal(img, out) + + +@pytest.mark.parametrize( + "color", ((255, 255, 255), (127, 255, 0), (127, 127, 127), (0, 0, 0)) +) +def test_autocontrast_preserve_one_color(color): + img = Image.new("RGB", (10, 10), color) + + # single color images shouldn't change + out = ImageOps.autocontrast(img, cutoff=0, preserve_tone=True) + assert_image_equal(img, out) # single color, no cutoff + + # even if there is a cutoff + out = ImageOps.autocontrast( + img, cutoff=10, preserve_tone=True + ) # single color 10 cutoff + assert_image_equal(img, out) diff --git a/Tests/test_imagepalette.py b/Tests/test_imagepalette.py index a2b0d2b02..ee2cfdf9b 100644 --- a/Tests/test_imagepalette.py +++ b/Tests/test_imagepalette.py @@ -2,27 +2,47 @@ import pytest from PIL import Image, ImagePalette -from .helper import assert_image_equal +from .helper import assert_image_equal, assert_image_equal_tofile def test_sanity(): - ImagePalette.ImagePalette("RGB", list(range(256)) * 3) + palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3) + assert len(palette.colors) == 256 + with pytest.raises(ValueError): - ImagePalette.ImagePalette("RGB", list(range(256)) * 2) + ImagePalette.ImagePalette("RGB", list(range(256)) * 3, 10) + + +def test_reload(): + im = Image.open("Tests/images/hopper.gif") + original = im.copy() + im.palette.dirty = 1 + assert_image_equal(im.convert("RGB"), original.convert("RGB")) def test_getcolor(): palette = ImagePalette.ImagePalette() + assert len(palette.palette) == 0 + assert len(palette.colors) == 0 test_map = {} for i in range(256): test_map[palette.getcolor((i, i, i))] = i - assert len(test_map) == 256 + + # Colors can be converted between RGB and RGBA + rgba_palette = ImagePalette.ImagePalette("RGBA") + assert rgba_palette.getcolor((0, 0, 0)) == rgba_palette.getcolor((0, 0, 0, 255)) + + assert palette.getcolor((0, 0, 0)) == palette.getcolor((0, 0, 0, 255)) + + # An error is raised when the palette is full with pytest.raises(ValueError): palette.getcolor((1, 2, 3)) + # But not if the image is not using one of the palette entries + palette.getcolor((1, 2, 3), image=Image.new("P", (1, 1))) # Test unknown color specifier with pytest.raises(ValueError): @@ -116,7 +136,7 @@ def test_getdata(): mode, data_out = palette.getdata() # Assert - assert mode == "RGB;L" + assert mode == "RGB" def test_rawmode_getdata(): @@ -141,8 +161,7 @@ def test_2bit_palette(tmp_path): img.putpalette(b"\xFF\x00\x00\x00\xFF\x00\x00\x00\xFF") # RGB img.save(outfile, format="PNG") - with Image.open(outfile) as reloaded: - assert_image_equal(img, reloaded) + assert_image_equal_tofile(img, outfile) def test_invalid_palette(): diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py index c39bb0a06..53b1fef7c 100644 --- a/Tests/test_imageqt.py +++ b/Tests/test_imageqt.py @@ -4,38 +4,24 @@ from PIL import ImageQt from .helper import hopper +pytestmark = pytest.mark.skipif( + not ImageQt.qt_is_installed, reason="Qt bindings are not installed" +) + if ImageQt.qt_is_installed: from PIL.ImageQt import qRgba -@pytest.mark.skipif(not ImageQt.qt_is_installed, reason="Qt bindings are not installed") -class PillowQPixmapTestCase: - @classmethod - def setup_class(self): - try: - if ImageQt.qt_version == "5": - from PyQt5.QtGui import QGuiApplication - elif ImageQt.qt_version == "side2": - from PySide2.QtGui import QGuiApplication - except ImportError: - pytest.skip("QGuiApplication not installed") - return - - self.app = QGuiApplication([]) - - @classmethod - def teardown_class(self): - self.app.quit() - self.app = None - - -@pytest.mark.skipif(not ImageQt.qt_is_installed, reason="Qt bindings are not installed") def test_rgb(): # from https://doc.qt.io/archives/qt-4.8/qcolor.html # typedef QRgb # An ARGB quadruplet on the format #AARRGGBB, # equivalent to an unsigned int. - if ImageQt.qt_version == "5": + if ImageQt.qt_version == "6": + from PyQt6.QtGui import qRgb + elif ImageQt.qt_version == "side6": + from PySide6.QtGui import qRgb + elif ImageQt.qt_version == "5": from PyQt5.QtGui import qRgb elif ImageQt.qt_version == "side2": from PySide2.QtGui import qRgb @@ -55,7 +41,13 @@ def test_rgb(): checkrgb(0, 0, 255) -@pytest.mark.skipif(not ImageQt.qt_is_installed, reason="Qt bindings are not installed") def test_image(): for mode in ("1", "RGB", "RGBA", "L", "P"): ImageQt.ImageQt(hopper(mode)) + + +def test_closed_file(): + with pytest.warns(None) as record: + ImageQt.ImageQt("Tests/images/hopper.gif") + + assert not record diff --git a/Tests/test_imageshow.py b/Tests/test_imageshow.py index 78e80f521..5981e22c0 100644 --- a/Tests/test_imageshow.py +++ b/Tests/test_imageshow.py @@ -62,4 +62,20 @@ def test_viewer(): def test_viewers(): for viewer in ImageShow._viewers: - viewer.get_command("test.jpg") + try: + viewer.get_command("test.jpg") + except NotImplementedError: + pass + + +def test_ipythonviewer(): + pytest.importorskip("IPython", reason="IPython not installed") + for viewer in ImageShow._viewers: + if isinstance(viewer, ImageShow.IPythonViewer): + test_viewer = viewer + break + else: + assert False + + im = hopper() + assert test_viewer.show(im) == 1 diff --git a/Tests/test_imagewin_pointers.py b/Tests/test_imagewin_pointers.py index a5cac96e4..c51a66089 100644 --- a/Tests/test_imagewin_pointers.py +++ b/Tests/test_imagewin_pointers.py @@ -110,4 +110,5 @@ if is_win32(): DeleteObject(dib) DeleteDC(hdc) - Image.open(BytesIO(bitmap)).save(opath) + with Image.open(BytesIO(bitmap)) as im: + im.save(opath) diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index 8a1460346..af7eae935 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -320,6 +320,23 @@ class TestLibUnpack: self.assert_unpack("RGB", "G", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) self.assert_unpack("RGB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) + self.assert_unpack("RGB", "R;16B", 2, (1, 0, 0), (3, 0, 0), (5, 0, 0)) + self.assert_unpack("RGB", "G;16B", 2, (0, 1, 0), (0, 3, 0), (0, 5, 0)) + self.assert_unpack("RGB", "B;16B", 2, (0, 0, 1), (0, 0, 3), (0, 0, 5)) + + self.assert_unpack("RGB", "R;16L", 2, (2, 0, 0), (4, 0, 0), (6, 0, 0)) + self.assert_unpack("RGB", "G;16L", 2, (0, 2, 0), (0, 4, 0), (0, 6, 0)) + self.assert_unpack("RGB", "B;16L", 2, (0, 0, 2), (0, 0, 4), (0, 0, 6)) + + if sys.byteorder == "little": + self.assert_unpack("RGB", "R;16N", 2, (2, 0, 0), (4, 0, 0), (6, 0, 0)) + self.assert_unpack("RGB", "G;16N", 2, (0, 2, 0), (0, 4, 0), (0, 6, 0)) + self.assert_unpack("RGB", "B;16N", 2, (0, 0, 2), (0, 0, 4), (0, 0, 6)) + else: + self.assert_unpack("RGB", "R;16N", 2, (1, 0, 0), (3, 0, 0), (5, 0, 0)) + self.assert_unpack("RGB", "G;16N", 2, (0, 1, 0), (0, 3, 0), (0, 5, 0)) + self.assert_unpack("RGB", "B;16N", 2, (0, 0, 1), (0, 0, 3), (0, 0, 5)) + def test_RGBA(self): self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)) self.assert_unpack( @@ -450,6 +467,43 @@ class TestLibUnpack: self.assert_unpack("RGBA", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) self.assert_unpack("RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) + self.assert_unpack("RGBA", "R;16B", 2, (1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0)) + self.assert_unpack("RGBA", "G;16B", 2, (0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0)) + self.assert_unpack("RGBA", "B;16B", 2, (0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0)) + self.assert_unpack("RGBA", "A;16B", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5)) + + self.assert_unpack("RGBA", "R;16L", 2, (2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0)) + self.assert_unpack("RGBA", "G;16L", 2, (0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0)) + self.assert_unpack("RGBA", "B;16L", 2, (0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0)) + self.assert_unpack("RGBA", "A;16L", 2, (0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6)) + + if sys.byteorder == "little": + self.assert_unpack( + "RGBA", "R;16N", 2, (2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0) + ) + self.assert_unpack( + "RGBA", "G;16N", 2, (0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0) + ) + self.assert_unpack( + "RGBA", "B;16N", 2, (0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0) + ) + self.assert_unpack( + "RGBA", "A;16N", 2, (0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6) + ) + else: + self.assert_unpack( + "RGBA", "R;16N", 2, (1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0) + ) + self.assert_unpack( + "RGBA", "G;16N", 2, (0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0) + ) + self.assert_unpack( + "RGBA", "B;16N", 2, (0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0) + ) + self.assert_unpack( + "RGBA", "A;16N", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5) + ) + def test_RGBa(self): self.assert_unpack( "RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) diff --git a/Tests/test_map.py b/Tests/test_map.py index 2b65fb3f9..752c5f268 100644 --- a/Tests/test_map.py +++ b/Tests/test_map.py @@ -4,10 +4,6 @@ import pytest from PIL import Image -from .helper import is_win32 - -pytestmark = pytest.mark.skipif(is_win32(), reason="Win32 does not call map_buffer") - def test_overflow(): # There is the potential to overflow comparisons in map.c @@ -27,6 +23,13 @@ def test_overflow(): Image.MAX_IMAGE_PIXELS = max_pixels +def test_tobytes(): + # Previously raised an access violation on Windows + with Image.open("Tests/images/l2rgb_read.bmp") as im: + with pytest.raises((ValueError, MemoryError, OSError)): + im.tobytes() + + @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="Requires 64-bit system") def test_ysize(): numpy = pytest.importorskip("numpy", reason="NumPy not installed") diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index da367fa46..def7adf3f 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -31,7 +31,7 @@ def test_numpy_to_image(): return i # Check supported 1-bit integer formats - assert_image(to_image(numpy.bool, 1, 1), "1", TEST_IMAGE_SIZE) + assert_image(to_image(bool, 1, 1), "1", TEST_IMAGE_SIZE) assert_image(to_image(numpy.bool8, 1, 1), "1", TEST_IMAGE_SIZE) # Check supported 8-bit integer formats @@ -65,7 +65,7 @@ def test_numpy_to_image(): to_image(numpy.int64) # Check floating-point formats - assert_image(to_image(numpy.float), "F", TEST_IMAGE_SIZE) + assert_image(to_image(float), "F", TEST_IMAGE_SIZE) with pytest.raises(TypeError): to_image(numpy.float16) assert_image(to_image(numpy.float32), "F", TEST_IMAGE_SIZE) @@ -191,7 +191,7 @@ def test_putdata(): def test_roundtrip_eye(): for dtype in ( - numpy.bool, + bool, numpy.bool8, numpy.int8, numpy.int16, @@ -199,7 +199,7 @@ def test_roundtrip_eye(): numpy.uint8, numpy.uint16, numpy.uint32, - numpy.float, + float, numpy.float32, numpy.float64, ): @@ -218,7 +218,7 @@ def test_zero_size(): def test_bool(): # https://github.com/python-pillow/Pillow/issues/2044 - a = numpy.zeros((10, 2), dtype=numpy.bool) + a = numpy.zeros((10, 2), dtype=bool) a[0][0] = True im2 = Image.fromarray(a) @@ -234,4 +234,6 @@ def test_no_resource_warning_for_numpy_array(): with Image.open(test_file) as im: # Act/Assert - pytest.warns(None, lambda: array(im)) + with pytest.warns(None) as record: + array(im) + assert not record diff --git a/Tests/test_psdraw.py b/Tests/test_psdraw.py index 31f0f493b..e74d79828 100644 --- a/Tests/test_psdraw.py +++ b/Tests/test_psdraw.py @@ -1,6 +1,8 @@ import os import sys -from io import StringIO +from io import BytesIO + +import pytest from PIL import Image, PSDraw @@ -44,10 +46,21 @@ def test_draw_postscript(tmp_path): assert os.path.getsize(tempfile) > 0 -def test_stdout(): +@pytest.mark.parametrize("buffer", (True, False)) +def test_stdout(buffer): # Temporarily redirect stdout old_stdout = sys.stdout - sys.stdout = mystdout = StringIO() + + if buffer: + + class MyStdOut: + buffer = BytesIO() + + mystdout = MyStdOut() + else: + mystdout = BytesIO() + + sys.stdout = mystdout ps = PSDraw.PSDraw() _create_document(ps) @@ -55,4 +68,6 @@ def test_stdout(): # Reset stdout sys.stdout = old_stdout - assert mystdout.getvalue() != "" + if buffer: + mystdout = mystdout.buffer + assert mystdout.getvalue() != b"" diff --git a/Tests/test_qt_image_fromqpixmap.py b/Tests/test_qt_image_fromqpixmap.py deleted file mode 100644 index cb1b385ec..000000000 --- a/Tests/test_qt_image_fromqpixmap.py +++ /dev/null @@ -1,15 +0,0 @@ -from PIL import ImageQt - -from .helper import assert_image_equal, hopper -from .test_imageqt import PillowQPixmapTestCase - - -class TestFromQPixmap(PillowQPixmapTestCase): - def roundtrip(self, expected): - result = ImageQt.fromqpixmap(ImageQt.toqpixmap(expected)) - # Qt saves all pixmaps as rgb - assert_image_equal(result, expected.convert("RGB")) - - def test_sanity(self): - for mode in ("1", "RGB", "RGBA", "L", "P"): - self.roundtrip(hopper(mode)) diff --git a/Tests/test_qt_image_qapplication.py b/Tests/test_qt_image_qapplication.py new file mode 100644 index 000000000..dec790c50 --- /dev/null +++ b/Tests/test_qt_image_qapplication.py @@ -0,0 +1,88 @@ +import pytest + +from PIL import ImageQt + +from .helper import assert_image_equal, assert_image_equal_tofile, hopper + +if ImageQt.qt_is_installed: + from PIL.ImageQt import QPixmap + + if ImageQt.qt_version == "6": + from PyQt6.QtCore import QPoint + from PyQt6.QtGui import QImage, QPainter, QRegion + from PyQt6.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget + elif ImageQt.qt_version == "side6": + from PySide6.QtCore import QPoint + from PySide6.QtGui import QImage, QPainter, QRegion + from PySide6.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget + elif ImageQt.qt_version == "5": + from PyQt5.QtCore import QPoint + from PyQt5.QtGui import QImage, QPainter, QRegion + from PyQt5.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget + elif ImageQt.qt_version == "side2": + from PySide2.QtCore import QPoint + from PySide2.QtGui import QImage, QPainter, QRegion + from PySide2.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget + + class Example(QWidget): + def __init__(self): + super().__init__() + + img = hopper().resize((1000, 1000)) + + qimage = ImageQt.ImageQt(img) + + pixmap1 = ImageQt.QPixmap.fromImage(qimage) + + QHBoxLayout(self) # hbox + + lbl = QLabel(self) + # Segfault in the problem + lbl.setPixmap(pixmap1.copy()) + + +def roundtrip(expected): + result = ImageQt.fromqpixmap(ImageQt.toqpixmap(expected)) + # Qt saves all pixmaps as rgb + assert_image_equal(result, expected.convert("RGB")) + + +@pytest.mark.skipif(not ImageQt.qt_is_installed, reason="Qt bindings are not installed") +def test_sanity(tmp_path): + # Segfault test + app = QApplication([]) + ex = Example() + assert app # Silence warning + assert ex # Silence warning + + for mode in ("1", "RGB", "RGBA", "L", "P"): + # to QPixmap + im = hopper(mode) + data = ImageQt.toqpixmap(im) + + assert isinstance(data, QPixmap) + assert not data.isNull() + + # Test saving the file + tempfile = str(tmp_path / f"temp_{mode}.png") + data.save(tempfile) + + # Render the image + qimage = ImageQt.ImageQt(im) + data = QPixmap.fromImage(qimage) + qt_format = QImage.Format if ImageQt.qt_version == "6" else QImage + qimage = QImage(128, 128, qt_format.Format_ARGB32) + painter = QPainter(qimage) + image_label = QLabel() + image_label.setPixmap(data) + image_label.render(painter, QPoint(0, 0), QRegion(0, 0, 128, 128)) + painter.end() + rendered_tempfile = str(tmp_path / f"temp_rendered_{mode}.png") + qimage.save(rendered_tempfile) + assert_image_equal_tofile(im.convert("RGBA"), rendered_tempfile) + + # from QPixmap + roundtrip(hopper(mode)) + + app.quit() + app = None diff --git a/Tests/test_qt_image_toqimage.py b/Tests/test_qt_image_toqimage.py index 8d599f9bf..2a6b29abe 100644 --- a/Tests/test_qt_image_toqimage.py +++ b/Tests/test_qt_image_toqimage.py @@ -1,8 +1,8 @@ import pytest -from PIL import Image, ImageQt +from PIL import ImageQt -from .helper import assert_image_equal, hopper +from .helper import assert_image_equal, assert_image_equal_tofile, hopper pytestmark = pytest.mark.skipif( not ImageQt.qt_is_installed, reason="Qt bindings are not installed" @@ -11,13 +11,6 @@ pytestmark = pytest.mark.skipif( if ImageQt.qt_is_installed: from PIL.ImageQt import QImage - try: - from PyQt5 import QtGui - from PyQt5.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget - except (ImportError, RuntimeError): - from PySide2 import QtGui - from PySide2.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget - def test_sanity(tmp_path): for mode in ("RGB", "RGBA", "L", "P", "1"): @@ -47,31 +40,4 @@ def test_sanity(tmp_path): data.save(tempfile) # Check that it actually worked. - with Image.open(tempfile) as reloaded: - assert_image_equal(reloaded, src) - - -def test_segfault(): - app = QApplication([]) - ex = Example() - assert app # Silence warning - assert ex # Silence warning - - -if ImageQt.qt_is_installed: - - class Example(QWidget): - def __init__(self): - super().__init__() - - img = hopper().resize((1000, 1000)) - - qimage = ImageQt.ImageQt(img) - - pixmap1 = QtGui.QPixmap.fromImage(qimage) - - QHBoxLayout(self) # hbox - - lbl = QLabel(self) - # Segfault in the problem - lbl.setPixmap(pixmap1.copy()) + assert_image_equal_tofile(src, tempfile) diff --git a/Tests/test_qt_image_toqpixmap.py b/Tests/test_qt_image_toqpixmap.py deleted file mode 100644 index f38cc7f13..000000000 --- a/Tests/test_qt_image_toqpixmap.py +++ /dev/null @@ -1,20 +0,0 @@ -from PIL import ImageQt - -from .helper import hopper -from .test_imageqt import PillowQPixmapTestCase - -if ImageQt.qt_is_installed: - from PIL.ImageQt import QPixmap - - -class TestToQPixmap(PillowQPixmapTestCase): - def test_sanity(self, tmp_path): - for mode in ("1", "RGB", "RGBA", "L", "P"): - data = ImageQt.toqpixmap(hopper(mode)) - - assert isinstance(data, QPixmap) - assert not data.isNull() - - # Test saving the file - tempfile = str(tmp_path / f"temp_{mode}.png") - data.save(tempfile) diff --git a/Tests/test_sgi_crash.py b/Tests/test_sgi_crash.py index 2b671244a..f9eaf9b19 100644 --- a/Tests/test_sgi_crash.py +++ b/Tests/test_sgi_crash.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import pytest from PIL import Image @@ -6,7 +5,19 @@ from PIL import Image @pytest.mark.parametrize( "test_file", - ["Tests/images/sgi_overrun_expandrowF04.bin", "Tests/images/sgi_crash.bin"], + [ + "Tests/images/sgi_overrun_expandrowF04.bin", + "Tests/images/sgi_crash.bin", + "Tests/images/crash-6b7f2244da6d0ae297ee0754a424213444e92778.sgi", + "Tests/images/ossfuzz-5730089102868480.sgi", + "Tests/images/crash-754d9c7ec485ffb76a90eeaab191ef69a2a3a3cd.sgi", + "Tests/images/crash-465703f71a0f0094873a3e0e82c9f798161171b8.sgi", + "Tests/images/crash-64834657ee604b8797bf99eac6a194c124a9a8ba.sgi", + "Tests/images/crash-abcf1c97b8fe42a6c68f1fb0b978530c98d57ced.sgi", + "Tests/images/crash-b82e64d4f3f76d7465b6af535283029eda211259.sgi", + "Tests/images/crash-c1b2595b8b0b92cc5f38b6635e98e3a119ade807.sgi", + "Tests/images/crash-db8bfa78b19721225425530c5946217720d7df4e.sgi", + ], ) def test_crashes(test_file): with open(test_file, "rb") as f: diff --git a/Tests/test_tiff_crashes.py b/Tests/test_tiff_crashes.py index 9c293e014..6cdb8e44d 100644 --- a/Tests/test_tiff_crashes.py +++ b/Tests/test_tiff_crashes.py @@ -19,7 +19,24 @@ from .helper import on_ci @pytest.mark.parametrize( - "test_file", ["Tests/images/crash_1.tif", "Tests/images/crash_2.tif"] + "test_file", + [ + "Tests/images/crash_1.tif", + "Tests/images/crash_2.tif", + "Tests/images/crash-2020-10-test.tif", + "Tests/images/crash-0c7e0e8e11ce787078f00b5b0ca409a167f070e0.tif", + "Tests/images/crash-0e16d3bfb83be87356d026d66919deaefca44dac.tif", + "Tests/images/crash-1152ec2d1a1a71395b6f2ce6721c38924d025bf3.tif", + "Tests/images/crash-1185209cf7655b5aed8ae5e77784dfdd18ab59e9.tif", + "Tests/images/crash-338516dbd2f0e83caddb8ce256c22db3bd6dc40f.tif", + "Tests/images/crash-4f085cc12ece8cde18758d42608bed6a2a2cfb1c.tif", + "Tests/images/crash-86214e58da443d2b80820cff9677a38a33dcbbca.tif", + "Tests/images/crash-f46f5b2f43c370fe65706c11449f567ecc345e74.tif", + "Tests/images/crash-63b1dffefc8c075ddc606c0a2f5fdc15ece78863.tif", + "Tests/images/crash-74d2a78403a5a59db1fb0a2b8735ac068a75f6e3.tif", + "Tests/images/crash-81154a65438ba5aaeca73fd502fa4850fbde60f8.tif", + "Tests/images/crash-0da013a13571cc8eb457a39fee8db18f8a3c7127.tif", + ], ) @pytest.mark.filterwarnings("ignore:Possibly corrupt EXIF data") @pytest.mark.filterwarnings("ignore:Metadata warning") diff --git a/Tests/test_tiff_ifdrational.py b/Tests/test_tiff_ifdrational.py index 1697a8d49..12f475df0 100644 --- a/Tests/test_tiff_ifdrational.py +++ b/Tests/test_tiff_ifdrational.py @@ -28,6 +28,8 @@ def test_sanity(): _test_equal(1, 2, Fraction(1, 2)) _test_equal(1, 2, IFDRational(1, 2)) + _test_equal(7, 5, 1.4) + def test_ranges(): for num in range(1, 10): diff --git a/depends/install_imagequant.sh b/depends/install_imagequant.sh index ed438f904..c6c7506a3 100755 --- a/depends/install_imagequant.sh +++ b/depends/install_imagequant.sh @@ -1,7 +1,7 @@ #!/bin/bash # install libimagequant -archive=libimagequant-2.13.1 +archive=libimagequant-2.15.1 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz diff --git a/depends/install_webp.sh b/depends/install_webp.sh index 9b1882c43..568cb2df9 100755 --- a/depends/install_webp.sh +++ b/depends/install_webp.sh @@ -1,7 +1,7 @@ #!/bin/bash # install webp -archive=libwebp-1.1.0 +archive=libwebp-1.2.0 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz diff --git a/docs/COPYING b/docs/COPYING index ec2a5d8cb..f2466d659 100644 --- a/docs/COPYING +++ b/docs/COPYING @@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is Pillow is the friendly PIL fork. It is - Copyright © 2010-2020 by Alex Clark and contributors + Copyright © 2010-2021 by Alex Clark and contributors Like PIL, Pillow is licensed under the open source PIL Software License: diff --git a/docs/Guardfile b/docs/Guardfile index 16f731611..b689b079a 100755 --- a/docs/Guardfile +++ b/docs/Guardfile @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from livereload.compiler import shell from livereload.task import Task diff --git a/docs/conf.py b/docs/conf.py index 4e14a6fd0..9b4eb669b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,11 +29,13 @@ needs_sphinx = "2.4" # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + "sphinx_copybutton", + "sphinx_issues", + "sphinx_removed_in", "sphinx.ext.autodoc", "sphinx.ext.intersphinx", "sphinx.ext.viewcode", - "sphinx_issues", - "sphinx_removed_in", + "sphinxext.opengraph", ] intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} @@ -51,7 +53,7 @@ master_doc = "index" # General information about the project. project = "Pillow (PIL Fork)" -copyright = "1995-2011 Fredrik Lundh, 2010-2020 Alex Clark and Contributors" +copyright = "1995-2011 Fredrik Lundh, 2010-2021 Alex Clark and Contributors" author = "Fredrik Lundh, Alex Clark and Contributors" # The version info for the project you're documenting, acts as replacement for @@ -312,3 +314,14 @@ def setup(app): app.add_js_file("js/script.js") app.add_css_file("css/dark.css") app.add_css_file("css/light.css") + + +# GitHub repo for sphinx-issues +issues_github_path = "python-pillow/Pillow" + +# sphinxext.opengraph +ogp_image = ( + "https://raw.githubusercontent.com/python-pillow/pillow-logo/master/" + "pillow-logo-dark-text-1280x640.png" +) +ogp_image_alt = "Pillow" diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 44aa2a795..ef88afa23 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -25,6 +25,26 @@ vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`). .. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/ +Tk/Tcl 8.4 +~~~~~~~~~~ + +.. deprecated:: 8.2.0 + +Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), +when Tk/Tcl 8.5 will be the minimum supported. + +Categories +~~~~~~~~~~ + +.. deprecated:: 8.2.0 + +``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), +along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and +``Image.CONTAINER`` attributes. + +To determine if an image has multiple frames or not, +``getattr(im, "is_animated", False)`` can be used instead. + Image.show command parameter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/handbook/concepts.rst b/docs/handbook/concepts.rst index c4cdda78d..66eeaf6f8 100644 --- a/docs/handbook/concepts.rst +++ b/docs/handbook/concepts.rst @@ -44,7 +44,7 @@ supports the following standard modes: * ``I`` (32-bit signed integer pixels) * ``F`` (32-bit floating point pixels) -Pillow also provides limited support for a few special modes, including: +Pillow also provides limited support for a few additional modes, including: * ``LA`` (L with alpha) * ``PA`` (P with alpha) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 9c5af7ac9..5d4e83494 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -13,6 +13,14 @@ contents, not their names, but the :py:meth:`~PIL.Image.Image.save` method looks at the name to determine which format to use, unless the format is given explicitly. +When an image is opened from a file, only that instance of the image is considered to +have the format. Copies of the image will contain data loaded from the file, but not +the file itself, meaning that it can no longer be considered to be in the original +format. So if :py:meth:`~PIL.Image.Image.copy` is called on an image, or another method +internally creates a copy of the image, the ``fp`` (file pointer), along with any +methods and attributes specific to a format. The :py:attr:`~PIL.Image.Image.format` +attribute will be ``None``. + Fully supported formats ----------------------- @@ -31,6 +39,13 @@ The :py:meth:`~PIL.Image.open` method sets the following **compression** Set to ``bmp_rle`` if the file is run-length encoded. +DDS +^^^ + +DDS is a popular container texture format used in video games and natively supported +by DirectX. Uncompressed RGB and RGBA can be read, and (since 8.3.0) written. DXT1, +DXT3 (since 3.4.0) and DXT5 pixel formats can be read, only in ``RGBA`` mode. + DIB ^^^ @@ -251,6 +266,12 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum .. versionadded:: 8.1.0 +**bitmap_format** + By default, the image data will be saved in PNG format. With a bitmap format of + "bmp", image data will be saved in BMP format instead. + + .. versionadded:: 8.3.0 + IM ^^ @@ -880,10 +901,10 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum **compression** A string containing the desired compression method for the file. (valid only with libtiff installed) Valid compression - methods are: :data:`None`, ``"tiff_ccitt"``, ``"group3"``, - ``"group4"``, ``"tiff_jpeg"``, ``"tiff_adobe_deflate"``, - ``"tiff_thunderscan"``, ``"tiff_deflate"``, ``"tiff_sgilog"``, - ``"tiff_sgilog24"``, ``"tiff_raw_16"`` + methods are: :data:`None`, ``"group3"``, ``"group4"``, ``"jpeg"``, ``"lzma"``, + ``"packbits"``, ``"tiff_adobe_deflate"``, ``"tiff_ccitt"``, ``"tiff_lzw"``, + ``"tiff_raw_16"``, ``"tiff_sgilog"``, ``"tiff_sgilog24"``, ``"tiff_thunderscan"``, + ``"webp"`, ``"zstd"`` **quality** The image quality for JPEG compression, on a scale from 0 (worst) to 100 @@ -905,6 +926,9 @@ using the general tags available through tiffinfo. **copyright** Strings +**icc_profile** + The ICC Profile to include in the saved file. + **resolution_unit** An integer. 1 for no unit, 2 for inches and 3 for centimeters. @@ -941,7 +965,7 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: files compared to the slowest, but best, 100. **method** - Quality/speed trade-off (0=fast, 6=slower-better). Defaults to 0. + Quality/speed trade-off (0=fast, 6=slower-better). Defaults to 4. **icc_profile** The ICC Profile to include in the saved file. Only supported if @@ -1029,17 +1053,6 @@ is commonly used in fax applications. The DCX decoder can read files containing When the file is opened, only the first image is read. You can use :py:meth:`~PIL.Image.Image.seek` or :py:mod:`~PIL.ImageSequence` to read other images. - -DDS -^^^ - -DDS is a popular container texture format used in video games and natively -supported by DirectX. -Currently, uncompressed RGB data and DXT1, DXT3, and DXT5 pixel formats are -supported, and only in ``RGBA`` mode. - -.. versionadded:: 3.4.0 DXT3 - FLI, FLC ^^^^^^^^ @@ -1243,8 +1256,10 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum .. versionadded:: 3.0.0 **append_images** - A list of images to append as additional pages. Each of the - images in the list can be single or multiframe images. + A list of :py:class:`PIL.Image.Image` objects to append as additional pages. Each + of the images in the list can be single or multiframe images. The ``save_all`` + parameter must be present and set to ``True`` in conjunction with + ``append_images``. .. versionadded:: 4.2.0 diff --git a/docs/handbook/tutorial.rst b/docs/handbook/tutorial.rst index 6b68a0562..cdac0ae2d 100644 --- a/docs/handbook/tutorial.rst +++ b/docs/handbook/tutorial.rst @@ -424,7 +424,7 @@ Drawing PostScript title = "hopper" box = (1*72, 2*72, 7*72, 10*72) # in points - ps = PSDraw.PSDraw() # default is sys.stdout + ps = PSDraw.PSDraw() # default is sys.stdout or sys.stdout.buffer ps.begin_document(title) # draw the image (75 dpi) diff --git a/docs/handbook/writing-your-own-file-decoder.rst b/docs/handbook/writing-your-own-file-decoder.rst index 03b4ca601..9b670dba8 100644 --- a/docs/handbook/writing-your-own-file-decoder.rst +++ b/docs/handbook/writing-your-own-file-decoder.rst @@ -269,7 +269,7 @@ decoder that can be used to read various packed formats into a floating point image memory. To use the bit decoder with the :py:func:`PIL.Image.frombytes` function, use -the following syntax:: +the following syntax: .. code-block:: python diff --git a/docs/index.rst b/docs/index.rst index d2aca4bc4..3348feb89 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,9 +29,13 @@ Pillow for enterprise is available via the Tidelift Subscription. `Learn more = 1.0 no longer supports "import Image". Please use "from PIL import Image" instead. +.. warning:: Pillow >= 1.0 no longer supports ``import Image``. Please use ``from PIL import Image`` instead. -.. warning:: Pillow >= 2.1.0 no longer supports "import _imaging". Please use "from PIL.Image import core as _imaging" instead. +.. warning:: Pillow >= 2.1.0 no longer supports ``import _imaging``. Please use ``from PIL.Image import core as _imaging`` instead. Python Support -------------- @@ -57,8 +57,9 @@ Windows Installation We provide Pillow binaries for Windows compiled for the matrix of supported Pythons in both 32 and 64-bit versions in the wheel format. -These binaries have all of the optional libraries included except -for raqm, libimagequant, and libxcb:: +These binaries include support for all optional libraries except +libimagequant and libxcb. Raqm support requires +FriBiDi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow @@ -71,8 +72,8 @@ macOS Installation We provide binaries for macOS for each of the supported Python versions in the wheel format. These include support for all optional -libraries except libimagequant and libxcb. Raqm support requires -libraqm, fribidi, and harfbuzz to be installed separately:: +libraries except libimagequant. Raqm support requires +FriBiDi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow @@ -83,14 +84,15 @@ Linux Installation We provide binaries for Linux for each of the supported Python versions in the manylinux wheel format. These include support for all optional libraries except libimagequant. Raqm support requires -libraqm, fribidi, and harfbuzz to be installed separately:: +FriBiDi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow -Most major Linux distributions, including Fedora, Debian/Ubuntu and -ArchLinux also include Pillow in packages that previously contained -PIL e.g. ``python-imaging``. +Most major Linux distributions, including Fedora, Ubuntu and ArchLinux +also include Pillow in packages that previously contained PIL e.g. +``python-imaging``. Debian splits it into two packages, ``python3-pil`` +and ``python3-pil.imagetk``. FreeBSD Installation ^^^^^^^^^^^^^^^^^^^^ @@ -152,14 +154,14 @@ Many of Pillow's features require external libraries: * **libtiff** provides compressed TIFF functionality - * Pillow has been tested with libtiff versions **3.x** and **4.0-4.1** + * Pillow has been tested with libtiff versions **3.x** and **4.0-4.3** * **libfreetype** provides type related services * **littlecms** provides color management * Pillow version 2.2.1 and below uses liblcms1, Pillow 2.3.0 and - above uses liblcms2. Tested with **1.19** and **2.7-2.11**. + above uses liblcms2. Tested with **1.19** and **2.7-2.12**. * **libwebp** provides the WebP format. @@ -177,7 +179,7 @@ Many of Pillow's features require external libraries: * **libimagequant** provides improved color quantization - * Pillow has been tested with libimagequant **2.6-2.13.1** + * Pillow has been tested with libimagequant **2.6-2.15.1** * Libimagequant is licensed GPLv3, which is more restrictive than the Pillow license, therefore we will not be distributing binaries with libimagequant support enabled. @@ -190,11 +192,15 @@ Many of Pillow's features require external libraries: * libraqm depends on the following libraries: FreeType, HarfBuzz, FriBiDi, make sure that you install them before installing libraqm if not available as package in your system. - * setting text direction or font features is not supported without - libraqm. - * libraqm is dynamically loaded in Pillow 5.0.0 and above, so support - is available if all the libraries are installed. - * Windows support: Raqm is not included in prebuilt wheels + * Setting text direction or font features is not supported without libraqm. + * Pillow wheels since version 8.2.0 include a modified version of libraqm that + loads libfribidi at runtime if it is installed. + On Windows this requires compiling FriBiDi and installing ``fribidi.dll`` + into a directory listed in the `Dynamic-Link Library Search Order (Microsoft Docs) + `_ + (``fribidi-0.dll`` or ``libfribidi-0.dll`` are also detected). + See `Build Options`_ to see how to build this version. + * Previous versions of Pillow (5.0.0 to 8.1.2) linked libraqm dynamically at runtime. * **libxcb** provides X11 screengrab support. @@ -243,6 +249,12 @@ Build Options an exception if the libraries are not found. Webpmux (WebP metadata) relies on WebP support. Tcl and Tk also must be used together. +* Build flags: ``--vendor-raqm --vendor-fribidi`` + These flags are used to compile a modified version of libraqm and + a shim that dynamically loads libfribidi at runtime. These are + used to compile the standard Pillow wheels. Compiling libraqm requires + a C99-compliant compiler. + * Build flag: ``--disable-platform-guessing``. Skips all of the platform dependent guessing of include and library directories for automated build systems that configure the proper paths in the @@ -366,6 +378,10 @@ In Fedora, the command is:: sudo dnf install python3-devel redhat-rpm-config +In Alpine, the command is:: + + sudo apk add python3-dev py3-setuptools + .. Note:: ``redhat-rpm-config`` is required on Fedora 23, but not earlier versions. Prerequisites for **Ubuntu 16.04 LTS - 20.04 LTS** are installed with:: @@ -385,6 +401,12 @@ Prerequisites are installed on recent **Red Hat**, **CentOS** or **Fedora** with Note that the package manager may be yum or DNF, depending on the exact distribution. +Prerequisites are installed for **Alpine** with:: + + sudo apk add tiff-dev jpeg-dev openjpeg-dev zlib-dev freetype-dev lcms2-dev \ + libwebp-dev tcl-dev tk-dev harfbuzz-dev fribidi-dev libimagequant-dev \ + libxcb-dev libpng-dev + See also the ``Dockerfile``\s in the Test Infrastructure repo (https://github.com/python-pillow/docker-images) for a known working install process for other tested distros. @@ -430,10 +452,10 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | Debian 10 Buster | 3.7 |x86 | +----------------------------------+--------------------------+-----------------------+ -| Fedora 32 | 3.8 |x86-64 | -+----------------------------------+--------------------------+-----------------------+ | Fedora 33 | 3.9 |x86-64 | +----------------------------------+--------------------------+-----------------------+ +| Fedora 34 | 3.9 |x86-64 | ++----------------------------------+--------------------------+-----------------------+ | macOS 10.15 Catalina | 3.6, 3.7, 3.8, 3.9, PyPy3|x86-64 | +----------------------------------+--------------------------+-----------------------+ | Ubuntu Linux 16.04 LTS (Xenial) | 3.6, 3.7, 3.8, 3.9, PyPy3|x86-64 | @@ -465,18 +487,18 @@ These platforms have been reported to work at the versions mentioned. +----------------------------------+------------------------------+--------------------------------+-----------------------+ |**Operating system** |**Tested Python versions** |**Latest tested Pillow version**|**Tested processors** | +----------------------------------+------------------------------+--------------------------------+-----------------------+ -| macOS 11.0 Big Sur | 3.8, 3.9 | 8.0.1 |arm | +| macOS 11.0 Big Sur | 3.7, 3.8, 3.9 | 8.2.0 |arm | | +------------------------------+--------------------------------+-----------------------+ -| | 3.6, 3.7, 3.8, 3.9 | 8.0.1 |x86-64 | +| | 3.6, 3.7, 3.8, 3.9 | 8.2.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | macOS 10.15 Catalina | 3.6, 3.7, 3.8, 3.9 | 8.0.1 |x86-64 | -| +------------------------------+--------------------------------+ + +| +------------------------------+--------------------------------+ | | | 3.5 | 7.2.0 | | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | macOS 10.14 Mojave | 3.5, 3.6, 3.7, 3.8 | 7.2.0 |x86-64 | -| +------------------------------+--------------------------------+ + +| +------------------------------+--------------------------------+ | | | 2.7 | 6.0.0 | | -| +------------------------------+--------------------------------+ + +| +------------------------------+--------------------------------+ | | | 3.4 | 5.4.1 | | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | macOS 10.13 High Sierra | 2.7, 3.4, 3.5, 3.6 | 4.2.1 |x86-64 | @@ -484,7 +506,7 @@ These platforms have been reported to work at the versions mentioned. | macOS 10.12 Sierra | 2.7, 3.4, 3.5, 3.6 | 4.1.1 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | Mac OS X 10.11 El Capitan | 2.7, 3.4, 3.5, 3.6, 3.7 | 5.4.1 |x86-64 | -| +------------------------------+--------------------------------+ + +| +------------------------------+--------------------------------+ | | | 3.3 | 4.1.0 | | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | Mac OS X 10.9 Mavericks | 2.7, 3.2, 3.3, 3.4 | 3.0.0 |x86-64 | @@ -512,6 +534,10 @@ These platforms have been reported to work at the versions mentioned. +----------------------------------+------------------------------+--------------------------------+-----------------------+ | Raspbian Stretch | 2.7, 3.5 | 4.0.0 |arm | +----------------------------------+------------------------------+--------------------------------+-----------------------+ +| Raspberry Pi OS | 3.6, 3.7, 3.8, 3.9 | 8.2.0 |arm | +| +------------------------------+--------------------------------+ | +| | 2.7 | 6.2.2 | | ++----------------------------------+------------------------------+--------------------------------+-----------------------+ | Gentoo Linux | 2.7, 3.2 | 2.1.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | FreeBSD 11.1 | 2.7, 3.4, 3.5, 3.6 | 4.3.0 |x86-64 | diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 8d63c173b..c80b28a98 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -22,8 +22,8 @@ Windows). .. code-block:: python from PIL import Image - im = Image.open("bride.jpg") - im.rotate(45).show() + with Image.open("hopper.jpg") as im: + im.rotate(45).show() Create thumbnails ^^^^^^^^^^^^^^^^^ @@ -40,9 +40,9 @@ current directory preserving aspect ratios with 128x128 max resolution. for infile in glob.glob("*.jpg"): file, ext = os.path.splitext(infile) - im = Image.open(infile) - im.thumbnail(size) - im.save(file + ".thumbnail", "JPEG") + with Image.open(infile) as im: + im.thumbnail(size) + im.save(file + ".thumbnail", "JPEG") Functions --------- @@ -145,22 +145,21 @@ This crops the input image with the provided coordinates: from PIL import Image - im = Image.open("hopper.jpg") + with Image.open("hopper.jpg") as im: - # 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) + # 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)) + # 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.effect_spread .. automethod:: PIL.Image.Image.entropy .. automethod:: PIL.Image.Image.filter -.. automethod:: PIL.Image.Image.frombytes This blurs the input image using a filter from the ``ImageFilter`` module: @@ -168,11 +167,12 @@ This blurs the input image using a filter from the ``ImageFilter`` module: from PIL import Image, ImageFilter - im = Image.open("hopper.jpg") + with Image.open("hopper.jpg") as im: - # Blur the input image using the filter ImageFilter.BLUR - im_blurred = im.filter(filter=ImageFilter.BLUR) + # Blur the input image using the filter ImageFilter.BLUR + im_blurred = im.filter(filter=ImageFilter.BLUR) +.. automethod:: PIL.Image.Image.frombytes .. automethod:: PIL.Image.Image.getbands This helps to get the bands of the input image: @@ -181,8 +181,8 @@ This helps to get the bands of the input image: from PIL import Image - im = Image.open("hopper.jpg") - print(im.getbands()) # Returns ('R', 'G', 'B') + with Image.open("hopper.jpg") as im: + print(im.getbands()) # Returns ('R', 'G', 'B') .. automethod:: PIL.Image.Image.getbbox @@ -192,9 +192,9 @@ This helps to get the bounding box coordinates of the input image: from PIL import Image - im = Image.open("hopper.jpg") - print(im.getbbox()) - # Returns four coordinates in the format (left, upper, right, lower) + with Image.open("hopper.jpg") as im: + print(im.getbbox()) + # Returns four coordinates in the format (left, upper, right, lower) .. automethod:: PIL.Image.Image.getchannel .. automethod:: PIL.Image.Image.getcolors @@ -222,11 +222,11 @@ This resizes the given image from ``(width, height)`` to ``(width/2, height/2)`` from PIL import Image - im = Image.open("hopper.jpg") + with Image.open("hopper.jpg") as im: - # Provide the target width and height of the image - (width, height) = (im.width // 2, im.height // 2) - im_resized = im.resize((width, height)) + # 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.rotate @@ -236,12 +236,12 @@ This rotates the input image by ``theta`` degrees counter clockwise: from PIL import Image - im = Image.open("hopper.jpg") + with Image.open("hopper.jpg") as im: - # Rotate the image by 60 degrees counter clockwise - theta = 60 - # Angle is in degrees counter clockwise - im_rotated = im.rotate(angle=theta) + # 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.seek @@ -260,12 +260,12 @@ This flips the input image by using the :data:`FLIP_LEFT_RIGHT` method. from PIL import Image - im = Image.open("hopper.jpg") + with Image.open("hopper.jpg") as im: - # 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" + # 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 @@ -486,15 +486,16 @@ Used to specify the quantization method to use for the :meth:`~Image.quantize` m .. data:: MEDIANCUT - Median cut + Median cut. Default method, except for RGBA images. This method does not support + RGBA images. .. data:: MAXCOVERAGE - Maximum coverage + Maximum coverage. This method does not support RGBA images. .. data:: FASTOCTREE - Fast octree + Fast octree. Default method for RGBA images. .. data:: LIBIMAGEQUANT @@ -502,10 +503,3 @@ Used to specify the quantization method to use for the :meth:`~Image.quantize` m Check support using :py:func:`PIL.features.check_feature` with ``feature="libimagequant"``. - -.. comment: These are not referenced anywhere? - Categories - ^^^^^^^^^^ - .. data:: NORMAL - .. data:: SEQUENCE - .. data:: CONTAINER diff --git a/docs/reference/ImageColor.rst b/docs/reference/ImageColor.rst index e32a77b54..20237eccf 100644 --- a/docs/reference/ImageColor.rst +++ b/docs/reference/ImageColor.rst @@ -16,8 +16,11 @@ Color Names The ImageColor module supports the following string formats: -* Hexadecimal color specifiers, given as ``#rgb`` or ``#rrggbb``. For example, - ``#ff0000`` specifies pure red. +* Hexadecimal color specifiers, given as ``#rgb``, ``#rgba``, ``#rrggbb`` or + ``#rrggbbaa``, where ``r`` is red, ``g`` is green, ``b`` is blue and ``a`` is + alpha (also called 'opacity'). For example, ``#ff0000`` specifies pure red, + and ``#ff0000cc`` specifies red with 80% opacity (``cc`` is 204 in decimal + form, and 204 / 255 = 0.8). * RGB functions, given as ``rgb(red, green, blue)`` where the color values are integers in the range 0 to 255. Alternatively, the color values can be given diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 57d1c2dda..46e1595c2 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -18,6 +18,7 @@ Example: Draw a gray cross over an image .. code-block:: python + import sys from PIL import Image, ImageDraw with Image.open("hopper.jpg") as im: @@ -81,24 +82,24 @@ Example: Draw Partial Opacity Text from PIL import Image, ImageDraw, ImageFont # get an image - base = Image.open("Pillow/Tests/images/hopper.png").convert("RGBA") + with Image.open("Pillow/Tests/images/hopper.png").convert("RGBA") as base: - # make a blank image for the text, initialized to transparent text color - txt = Image.new("RGBA", base.size, (255,255,255,0)) + # make a blank image for the text, initialized to transparent text color + txt = Image.new("RGBA", base.size, (255,255,255,0)) - # get a font - fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 40) - # get a drawing context - d = ImageDraw.Draw(txt) + # get a font + fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 40) + # get a drawing context + d = ImageDraw.Draw(txt) - # draw text, half opacity - d.text((10,10), "Hello", font=fnt, fill=(255,255,255,128)) - # draw text, full opacity - d.text((10,60), "World", font=fnt, fill=(255,255,255,255)) + # draw text, half opacity + d.text((10,10), "Hello", font=fnt, fill=(255,255,255,128)) + # draw text, full opacity + d.text((10,60), "World", font=fnt, fill=(255,255,255,255)) - out = Image.alpha_composite(base, txt) + out = Image.alpha_composite(base, txt) - out.show() + out.show() Example: Draw Multiline Text ---------------------------- @@ -285,6 +286,20 @@ Methods .. versionadded:: 5.3.0 +.. py:method:: ImageDraw.rounded_rectangle(xy, radius=0, fill=None, outline=None, width=1) + + Draws a rounded rectangle. + + :param xy: Two points to define the bounding box. Sequence of either + ``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``. The second point + is just outside the drawn rectangle. + :param radius: Radius of the corners. + :param outline: Color to use for the outline. + :param fill: Color to use for the fill. + :param width: The line width, in pixels. + + .. versionadded:: 8.2.0 + .. py:method:: ImageDraw.shape(shape, fill=None, outline=None) .. warning:: This method is experimental. @@ -352,7 +367,7 @@ Methods .. versionadded:: 6.2.0 - :param embedded_color: Whether to use font embedded color glyphs (COLR or CBDT). + :param embedded_color: Whether to use font embedded color glyphs (COLR, CBDT, SBIX). .. versionadded:: 8.0.0 @@ -413,7 +428,7 @@ Methods .. versionadded:: 6.2.0 - :param embedded_color: Whether to use font embedded color glyphs (COLR or CBDT). + :param embedded_color: Whether to use font embedded color glyphs (COLR, CBDT, SBIX). .. versionadded:: 8.0.0 @@ -577,7 +592,7 @@ Methods correct substitutions as appropriate, if available. It should be a `BCP 47 language code`_. Requires libraqm. - :param embedded_color: Whether to use font embedded color glyphs (COLR or CBDT). + :param embedded_color: Whether to use font embedded color glyphs (COLR, CBDT, SBIX). .. py:method:: ImageDraw.textbbox(xy, text, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, embedded_color=False) @@ -626,7 +641,7 @@ Methods It should be a `BCP 47 language code`_. Requires libraqm. :param stroke_width: The width of the text stroke. - :param embedded_color: Whether to use font embedded color glyphs (COLR or CBDT). + :param embedded_color: Whether to use font embedded color glyphs (COLR, CBDT, SBIX). .. py:method:: ImageDraw.multiline_textbbox(xy, text, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, embedded_color=False) @@ -669,7 +684,7 @@ Methods It should be a `BCP 47 language code`_. Requires libraqm. :param stroke_width: The width of the text stroke. - :param embedded_color: Whether to use font embedded color glyphs (COLR or CBDT). + :param embedded_color: Whether to use font embedded color glyphs (COLR, CBDT, SBIX). .. py:method:: getdraw(im=None, hints=None) diff --git a/docs/reference/ImageMath.rst b/docs/reference/ImageMath.rst index 821f60cf5..63f88fddd 100644 --- a/docs/reference/ImageMath.rst +++ b/docs/reference/ImageMath.rst @@ -15,11 +15,11 @@ Example: Using the :py:mod:`~PIL.ImageMath` module from PIL import Image, ImageMath - im1 = Image.open("image1.jpg") - im2 = Image.open("image2.jpg") + with Image.open("image1.jpg") as im1: + with Image.open("image2.jpg") as im2: - out = ImageMath.eval("convert(min(a, b), 'L')", a=im1, b=im2) - out.save("result.png") + out = ImageMath.eval("convert(min(a, b), 'L')", a=im1, b=im2) + out.save("result.png") .. py:function:: eval(expression, environment) diff --git a/docs/reference/ImageOps.rst b/docs/reference/ImageOps.rst index 9a16d6625..d1c43cf60 100644 --- a/docs/reference/ImageOps.rst +++ b/docs/reference/ImageOps.rst @@ -12,6 +12,7 @@ only work on L and RGB images. .. autofunction:: autocontrast .. autofunction:: colorize +.. autofunction:: contain .. autofunction:: pad .. autofunction:: crop .. autofunction:: scale diff --git a/docs/reference/ImageQt.rst b/docs/reference/ImageQt.rst index 34d4cef51..66f5880a3 100644 --- a/docs/reference/ImageQt.rst +++ b/docs/reference/ImageQt.rst @@ -4,8 +4,8 @@ :py:mod:`~PIL.ImageQt` Module ============================= -The :py:mod:`~PIL.ImageQt` module contains support for creating PyQt5 or PySide2 QImage -objects from PIL images. +The :py:mod:`~PIL.ImageQt` module contains support for creating PyQt6, PySide6, PyQt5 +or PySide2 QImage objects from PIL images. .. versionadded:: 1.1.6 @@ -14,7 +14,7 @@ objects from PIL images. Creates an :py:class:`~PIL.ImageQt.ImageQt` object from a PIL :py:class:`~PIL.Image.Image` object. This class is a subclass of QtGui.QImage, which means that you can pass the resulting objects directly - to PyQt5/PySide2 API functions and methods. + to PyQt6/PySide6/PyQt5/PySide2 API functions and methods. This operation is currently supported for mode 1, L, P, RGB, and RGBA images. To handle other modes, you need to convert the image first. diff --git a/docs/reference/ImageShow.rst b/docs/reference/ImageShow.rst index a30a6caed..e4d9805ab 100644 --- a/docs/reference/ImageShow.rst +++ b/docs/reference/ImageShow.rst @@ -9,6 +9,7 @@ All default viewers convert the image to be shown to PNG format. .. autofunction:: PIL.ImageShow.show +.. autoclass:: IPythonViewer .. autoclass:: WindowsViewer .. autoclass:: MacViewer @@ -17,6 +18,7 @@ All default viewers convert the image to be shown to PNG format. The following viewers may be registered on Unix-based systems, if the given command is found: .. autoclass:: PIL.ImageShow.DisplayViewer + .. autoclass:: PIL.ImageShow.GmDisplayViewer .. autoclass:: PIL.ImageShow.EogViewer .. autoclass:: PIL.ImageShow.XVViewer diff --git a/docs/reference/c_extension_debugging.rst b/docs/reference/c_extension_debugging.rst new file mode 100644 index 000000000..527b9d7bc --- /dev/null +++ b/docs/reference/c_extension_debugging.rst @@ -0,0 +1,469 @@ +C Extension debugging on Linux, with gbd/valgrind. +================================================== + +Install the tools +----------------- + +You need some basics in addition to the basic tools to build +pillow. These are what's required on Ubuntu, YMMV for other +distributions. + +- ``python3-dbg`` package for the gdb extensions and python symbols +- ``gdb`` and ``valgrind`` +- Potentially debug symbols for libraries. On ubuntu they're shipped + in package-dbgsym packages, from a different repo. + +:: + + deb http://ddebs.ubuntu.com focal main restricted universe multiverse + deb http://ddebs.ubuntu.com focal-updates main restricted universe multiverse + deb http://ddebs.ubuntu.com focal-proposed main restricted universe multiverse + +Then ``sudo apt-get update && sudo apt-get install libtiff5-dbgsym`` + +- There's a bug with the dbg package for at least python 3.8 on ubuntu + 20.04, and you need to add a new link or two to make it autoload when + running python: + +:: + + cd /usr/share/gdb/auto-load/usr/bin + ln -s python3.8m-gdb.py python3.8d-gdb.py + +- In Ubuntu 18.04, it's actually including the path to the virtualenv + in the search for the ``python3.*-gdb.py`` file, but you can + helpfully put in the same directory as the binary. + +- I also find that history is really useful for gdb, so I added this to + my ``~/.gdbinit`` file: + +:: + + set history filename ~/.gdb_history + set history save on + +- If the python stack isn't working in gdb, then + ``set debug auto-load`` can also be helpful in ``.gdbinit``. + +- Make a virtualenv with the debug python and activate it, then install + whatever dependencies are required and build. You want to build with + the debug python so you get symbols for your extension. + +:: + + virtualenv -p python3.8-dbg ~/vpy38-dbg + source ~/vpy38-dbg/bin/activate + cd ~/Pillow && pip install -r requirements.txt && make install + +Test Case +--------- + +Take your test image, and make a really simple harness. + +:: + + from PIL import Image + with Image.open(path) as im: + im.load() + +- Run this through valgrind, but note that python triggers some issues + on its own, so you're looking for items within the Pillow hierarchy + that don't look like they're solely in the python call chain. In this + example, the ones we're interested are after the warnings, and have + ``decode.c`` and ``TiffDecode.c`` in the call stack: + +:: + + (vpy38-dbg) ubuntu@primary:~/Home/tests$ valgrind python test_tiff.py + ==51890== Memcheck, a memory error detector + ==51890== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. + ==51890== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info + ==51890== Command: python test_tiff.py + ==51890== + ==51890== Invalid read of size 4 + ==51890== at 0x472E3D: address_in_range (obmalloc.c:1401) + ==51890== by 0x472EEA: pymalloc_free (obmalloc.c:1677) + ==51890== by 0x474960: _PyObject_Free (obmalloc.c:1896) + ==51890== by 0x473BAC: _PyMem_DebugRawFree (obmalloc.c:2187) + ==51890== by 0x473BD4: _PyMem_DebugFree (obmalloc.c:2318) + ==51890== by 0x474C08: PyObject_Free (obmalloc.c:709) + ==51890== by 0x45DD60: dictresize (dictobject.c:1259) + ==51890== by 0x45DD76: insertion_resize (dictobject.c:1019) + ==51890== by 0x464F30: PyDict_SetDefault (dictobject.c:2924) + ==51890== by 0x4D03BE: PyUnicode_InternInPlace (unicodeobject.c:15289) + ==51890== by 0x4D0700: PyUnicode_InternFromString (unicodeobject.c:15322) + ==51890== by 0x64D2FC: descr_new (descrobject.c:857) + ==51890== Address 0x4c1b020 is 384 bytes inside a block of size 1,160 free'd + ==51890== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==51890== by 0x4735D3: _PyMem_RawFree (obmalloc.c:127) + ==51890== by 0x473BAC: _PyMem_DebugRawFree (obmalloc.c:2187) + ==51890== by 0x474941: PyMem_RawFree (obmalloc.c:595) + ==51890== by 0x47496E: _PyObject_Free (obmalloc.c:1898) + ==51890== by 0x473BAC: _PyMem_DebugRawFree (obmalloc.c:2187) + ==51890== by 0x473BD4: _PyMem_DebugFree (obmalloc.c:2318) + ==51890== by 0x474C08: PyObject_Free (obmalloc.c:709) + ==51890== by 0x45DD60: dictresize (dictobject.c:1259) + ==51890== by 0x45DD76: insertion_resize (dictobject.c:1019) + ==51890== by 0x464F30: PyDict_SetDefault (dictobject.c:2924) + ==51890== by 0x4D03BE: PyUnicode_InternInPlace (unicodeobject.c:15289) + ==51890== Block was alloc'd at + ==51890== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==51890== by 0x473646: _PyMem_RawMalloc (obmalloc.c:99) + ==51890== by 0x473529: _PyMem_DebugRawAlloc (obmalloc.c:2120) + ==51890== by 0x473565: _PyMem_DebugRawMalloc (obmalloc.c:2153) + ==51890== by 0x4748B1: PyMem_RawMalloc (obmalloc.c:572) + ==51890== by 0x475909: _PyObject_Malloc (obmalloc.c:1628) + ==51890== by 0x473529: _PyMem_DebugRawAlloc (obmalloc.c:2120) + ==51890== by 0x473565: _PyMem_DebugRawMalloc (obmalloc.c:2153) + ==51890== by 0x4736B0: _PyMem_DebugMalloc (obmalloc.c:2303) + ==51890== by 0x474B78: PyObject_Malloc (obmalloc.c:685) + ==51890== by 0x45C435: new_keys_object (dictobject.c:558) + ==51890== by 0x45DA95: dictresize (dictobject.c:1202) + ==51890== + ==51890== Invalid read of size 4 + ==51890== at 0x472E3D: address_in_range (obmalloc.c:1401) + ==51890== by 0x47594A: pymalloc_realloc (obmalloc.c:1929) + ==51890== by 0x475A02: _PyObject_Realloc (obmalloc.c:1982) + ==51890== by 0x473DCA: _PyMem_DebugRawRealloc (obmalloc.c:2240) + ==51890== by 0x473FF8: _PyMem_DebugRealloc (obmalloc.c:2326) + ==51890== by 0x4749FB: PyMem_Realloc (obmalloc.c:623) + ==51890== by 0x44A6FC: list_resize (listobject.c:70) + ==51890== by 0x44A872: app1 (listobject.c:340) + ==51890== by 0x44FD65: PyList_Append (listobject.c:352) + ==51890== by 0x514315: r_ref (marshal.c:945) + ==51890== by 0x516034: r_object (marshal.c:1139) + ==51890== by 0x516C70: r_object (marshal.c:1389) + ==51890== Address 0x4c41020 is 32 bytes before a block of size 1,600 in arena "client" + ==51890== + ==51890== Conditional jump or move depends on uninitialised value(s) + ==51890== at 0x472E46: address_in_range (obmalloc.c:1403) + ==51890== by 0x47594A: pymalloc_realloc (obmalloc.c:1929) + ==51890== by 0x475A02: _PyObject_Realloc (obmalloc.c:1982) + ==51890== by 0x473DCA: _PyMem_DebugRawRealloc (obmalloc.c:2240) + ==51890== by 0x473FF8: _PyMem_DebugRealloc (obmalloc.c:2326) + ==51890== by 0x4749FB: PyMem_Realloc (obmalloc.c:623) + ==51890== by 0x44A6FC: list_resize (listobject.c:70) + ==51890== by 0x44A872: app1 (listobject.c:340) + ==51890== by 0x44FD65: PyList_Append (listobject.c:352) + ==51890== by 0x5E3321: _posix_listdir (posixmodule.c:3823) + ==51890== by 0x5E33A8: os_listdir_impl (posixmodule.c:3879) + ==51890== by 0x5E4D77: os_listdir (posixmodule.c.h:1197) + ==51890== + ==51890== Use of uninitialised value of size 8 + ==51890== at 0x472E59: address_in_range (obmalloc.c:1403) + ==51890== by 0x47594A: pymalloc_realloc (obmalloc.c:1929) + ==51890== by 0x475A02: _PyObject_Realloc (obmalloc.c:1982) + ==51890== by 0x473DCA: _PyMem_DebugRawRealloc (obmalloc.c:2240) + ==51890== by 0x473FF8: _PyMem_DebugRealloc (obmalloc.c:2326) + ==51890== by 0x4749FB: PyMem_Realloc (obmalloc.c:623) + ==51890== by 0x44A6FC: list_resize (listobject.c:70) + ==51890== by 0x44A872: app1 (listobject.c:340) + ==51890== by 0x44FD65: PyList_Append (listobject.c:352) + ==51890== by 0x5E3321: _posix_listdir (posixmodule.c:3823) + ==51890== by 0x5E33A8: os_listdir_impl (posixmodule.c:3879) + ==51890== by 0x5E4D77: os_listdir (posixmodule.c.h:1197) + ==51890== + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 16908288 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67895296 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 1572864 bytes but only got 0. Skipping tag 42 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 116647 bytes but only got 4867. Skipping tag 42738 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 3468830728 bytes but only got 4851. Skipping tag 279 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 2198732800 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67239937 bytes but only got 4125. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33947764 bytes but only got 0. Skipping tag 139 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 17170432 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 80478208 bytes but only got 0. Skipping tag 1 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 787460 bytes but only got 4882. Skipping tag 20 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 1075 bytes but only got 0. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 120586240 bytes but only got 0. Skipping tag 194 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 65536 bytes but only got 0. Skipping tag 3 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 198656 bytes but only got 0. Skipping tag 279 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 206848 bytes but only got 0. Skipping tag 64512 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 130968 bytes but only got 4882. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 77848 bytes but only got 4689. Skipping tag 64270 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 262156 bytes but only got 0. Skipping tag 257 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33624064 bytes but only got 0. Skipping tag 49152 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67178752 bytes but only got 4627. Skipping tag 50688 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33632768 bytes but only got 0. Skipping tag 56320 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 134386688 bytes but only got 4115. Skipping tag 2048 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33912832 bytes but only got 0. Skipping tag 7168 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 151966208 bytes but only got 4627. Skipping tag 10240 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 119032832 bytes but only got 3859. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 46535680 bytes but only got 0. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 35651584 bytes but only got 0. Skipping tag 42 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 524288 bytes but only got 0. Skipping tag 0 + warnings.warn( + _TIFFVSetField: tempfile.tif: Null count for "Tag 769" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 42754" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 769" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 42754" (type 1, writecount -3, passcount 1). + ZIPDecode: Decoding error at scanline 0, incorrect header check. + ==51890== Invalid write of size 4 + ==51890== at 0x61C39E6: putcontig8bitYCbCr22tile (tif_getimage.c:2146) + ==51890== by 0x61C5865: gtStripContig (tif_getimage.c:977) + ==51890== by 0x6094317: ReadStrip (TiffDecode.c:269) + ==51890== by 0x6094749: ImagingLibTiffDecode (TiffDecode.c:479) + ==51890== by 0x60615D1: _decode (decode.c:136) + ==51890== by 0x64BF47: method_vectorcall_VARARGS (descrobject.c:300) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x43627B: function_code_fastcall (call.c:283) + ==51890== by 0x436D21: _PyFunction_Vectorcall (call.c:410) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== Address 0x6f456d4 is 0 bytes after a block of size 68 alloc'd + ==51890== at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==51890== by 0x60946D0: ImagingLibTiffDecode (TiffDecode.c:469) + ==51890== by 0x60615D1: _decode (decode.c:136) + ==51890== by 0x64BF47: method_vectorcall_VARARGS (descrobject.c:300) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x43627B: function_code_fastcall (call.c:283) + ==51890== by 0x436D21: _PyFunction_Vectorcall (call.c:410) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x4DFDFB: _PyEval_EvalCodeWithName (ceval.c:4298) + ==51890== by 0x436C40: _PyFunction_Vectorcall (call.c:435) + ==51890== + ==51890== Invalid write of size 4 + ==51890== at 0x61C39B5: putcontig8bitYCbCr22tile (tif_getimage.c:2145) + ==51890== by 0x61C5865: gtStripContig (tif_getimage.c:977) + ==51890== by 0x6094317: ReadStrip (TiffDecode.c:269) + ==51890== by 0x6094749: ImagingLibTiffDecode (TiffDecode.c:479) + ==51890== by 0x60615D1: _decode (decode.c:136) + ==51890== by 0x64BF47: method_vectorcall_VARARGS (descrobject.c:300) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x43627B: function_code_fastcall (call.c:283) + ==51890== by 0x436D21: _PyFunction_Vectorcall (call.c:410) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== Address 0x6f456d8 is 4 bytes after a block of size 68 alloc'd + ==51890== at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) + ==51890== by 0x60946D0: ImagingLibTiffDecode (TiffDecode.c:469) + ==51890== by 0x60615D1: _decode (decode.c:136) + ==51890== by 0x64BF47: method_vectorcall_VARARGS (descrobject.c:300) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x43627B: function_code_fastcall (call.c:283) + ==51890== by 0x436D21: _PyFunction_Vectorcall (call.c:410) + ==51890== by 0x4EB73C: _PyObject_Vectorcall (abstract.h:127) + ==51890== by 0x4EB73C: call_function (ceval.c:4963) + ==51890== by 0x4EB73C: _PyEval_EvalFrameDefault (ceval.c:3486) + ==51890== by 0x4DF2EE: PyEval_EvalFrameEx (ceval.c:741) + ==51890== by 0x4DFDFB: _PyEval_EvalCodeWithName (ceval.c:4298) + ==51890== by 0x436C40: _PyFunction_Vectorcall (call.c:435) + ==51890== + TIFFFillStrip: Invalid strip byte count 0, strip 1. + Traceback (most recent call last): + File "test_tiff.py", line 8, in + im.load() + File "/home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py", line 1087, in load + return self._load_libtiff() + File "/home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py", line 1191, in _load_libtiff + raise OSError(err) + OSError: -2 + sys:1: ResourceWarning: unclosed file <_io.BufferedReader name='crash-2020-10-test.tiff'> + ==51890== + ==51890== HEAP SUMMARY: + ==51890== in use at exit: 748,734 bytes in 444 blocks + ==51890== total heap usage: 6,320 allocs, 5,876 frees, 69,142,969 bytes allocated + ==51890== + ==51890== LEAK SUMMARY: + ==51890== definitely lost: 0 bytes in 0 blocks + ==51890== indirectly lost: 0 bytes in 0 blocks + ==51890== possibly lost: 721,538 bytes in 372 blocks + ==51890== still reachable: 27,196 bytes in 72 blocks + ==51890== suppressed: 0 bytes in 0 blocks + ==51890== Rerun with --leak-check=full to see details of leaked memory + ==51890== + ==51890== Use --track-origins=yes to see where uninitialised values come from + ==51890== For lists of detected and suppressed errors, rerun with: -s + ==51890== ERROR SUMMARY: 2556 errors from 6 contexts (suppressed: 0 from 0) + (vpy38-dbg) ubuntu@primary:~/Home/tests$ + +- Now that we've confirmed that there's something odd/bad going on, + it's time to gdb. +- Start with ``gdb python`` +- Set a break point starting with the valgrind stack trace. + ``b TiffDecode.c:269`` +- Run the script with ``r test_tiff.py`` +- When the break point is hit, explore the state with ``info locals``, + ``bt``, ``py-bt``, or ``p [variable]``. For pointers, + ``p *[variable]`` is useful. + +:: + + (vpy38-dbg) ubuntu@primary:~/Home/tests$ gdb python + GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2 + Copyright (C) 2020 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + Type "show copying" and "show warranty" for details. + This GDB was configured as "x86_64-linux-gnu". + Type "show configuration" for configuration details. + For bug reporting instructions, please see: + . + Find the GDB manual and other documentation resources online at: + . + + For help, type "help". + Type "apropos word" to search for commands related to "word"... + Reading symbols from python... + (gdb) b TiffDecode.c:269 + No source file named TiffDecode.c. + Make breakpoint pending on future shared library load? (y or [n]) y + Breakpoint 1 (TiffDecode.c:269) pending. + (gdb) r test_tiff.py + Starting program: /home/ubuntu/vpy38-dbg/bin/python test_tiff.py + [Thread debugging using libthread_db enabled] + Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 16908288 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67895296 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 1572864 bytes but only got 0. Skipping tag 42 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 116647 bytes but only got 4867. Skipping tag 42738 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 3468830728 bytes but only got 4851. Skipping tag 279 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 2198732800 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67239937 bytes but only got 4125. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33947764 bytes but only got 0. Skipping tag 139 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 17170432 bytes but only got 0. Skipping tag 0 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 80478208 bytes but only got 0. Skipping tag 1 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 787460 bytes but only got 4882. Skipping tag 20 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 1075 bytes but only got 0. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 120586240 bytes but only got 0. Skipping tag 194 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 65536 bytes but only got 0. Skipping tag 3 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 198656 bytes but only got 0. Skipping tag 279 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 206848 bytes but only got 0. Skipping tag 64512 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 130968 bytes but only got 4882. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 77848 bytes but only got 4689. Skipping tag 64270 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 262156 bytes but only got 0. Skipping tag 257 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33624064 bytes but only got 0. Skipping tag 49152 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 67178752 bytes but only got 4627. Skipping tag 50688 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33632768 bytes but only got 0. Skipping tag 56320 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 134386688 bytes but only got 4115. Skipping tag 2048 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 33912832 bytes but only got 0. Skipping tag 7168 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 151966208 bytes but only got 4627. Skipping tag 10240 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 119032832 bytes but only got 3859. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 46535680 bytes but only got 0. Skipping tag 256 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 35651584 bytes but only got 0. Skipping tag 42 + warnings.warn( + /home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py:770: UserWarning: Possibly corrupt EXIF data. Expecting to read 524288 bytes but only got 0. Skipping tag 0 + warnings.warn( + _TIFFVSetField: tempfile.tif: Null count for "Tag 769" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 42754" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 769" (type 1, writecount -3, passcount 1). + _TIFFVSetField: tempfile.tif: Null count for "Tag 42754" (type 1, writecount -3, passcount 1). + + Breakpoint 1, ReadStrip (tiff=tiff@entry=0xae9b90, row=0, buffer=0xac2eb0) at src/libImaging/TiffDecode.c:269 + 269 ok = TIFFRGBAImageGet(&img, buffer, img.width, rows_to_read); + (gdb) p img + $1 = {tif = 0xae9b90, stoponerr = 0, isContig = 1, alpha = 0, width = 20, height = 1536, bitspersample = 8, samplesperpixel = 3, + orientation = 1, req_orientation = 1, photometric = 6, redcmap = 0x0, greencmap = 0x0, bluecmap = 0x0, get = + 0x7ffff71d0710 , put = {any = 0x7ffff71ce550 , + contig = 0x7ffff71ce550 , separate = 0x7ffff71ce550 }, Map = 0x0, + BWmap = 0x0, PALmap = 0x0, ycbcr = 0xaf24b0, cielab = 0x0, UaToAa = 0x0, Bitdepth16To8 = 0x0, row_offset = 0, col_offset = 0} + (gdb) up + #1 0x00007ffff736174a in ImagingLibTiffDecode (im=0xac1f90, state=0x7ffff76767e0, buffer=, bytes=) + at src/libImaging/TiffDecode.c:479 + 479 if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) { + (gdb) p *state + $2 = {count = 0, state = 0, errcode = 0, x = 0, y = 0, ystep = 0, xsize = 17, ysize = 108, xoff = 0, yoff = 0, + shuffle = 0x7ffff735f411 , bits = 32, bytes = 68, buffer = 0xac2eb0 "P\354\336\367\377\177", context = 0xa75440, fd = 0x0} + (gdb) py-bt + Traceback (most recent call first): + File "/home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py", line 1428, in _load_libtiff + + File "/home/ubuntu/vpy38-dbg/lib/python3.8/site-packages/Pillow-8.0.1-py3.8-linux-x86_64.egg/PIL/TiffImagePlugin.py", line 1087, in load + return self._load_libtiff() + File "test_tiff.py", line 8, in + im.load() + +- Poke around till you understand what's going on. In this case, + state->xsize and img.width are different, which led to an out of + bounds write, as the receiving buffer was sized for the smaller of + the two. + +Caveats +------- + +- If your program is running/hung in a docker container and your host + has the appropriate tools, you can run gdb as the superuser in the + host and you may be able to get a trace of where the process is hung. + You probably won't have the capability to do that from within the + docker container, as the trace capacity isn't allowed by default. + +- Variations of this are possible on the mac/windows, but the details + are going to be different. + +- IIRC, Fedora has the gdb bits working by default. Ubuntu has always + been a bit of a battle to make it work. diff --git a/docs/reference/features.rst b/docs/reference/features.rst index dd218fa0e..0a6381098 100644 --- a/docs/reference/features.rst +++ b/docs/reference/features.rst @@ -17,7 +17,7 @@ Modules Support for the following modules can be checked: * ``pil``: The Pillow core module, required for all functionality. -* ``tkinter``: Tkinter support. Version number not available. +* ``tkinter``: Tkinter support. * ``freetype2``: FreeType font support via :py:func:`PIL.ImageFont.truetype`. * ``littlecms2``: LittleCMS 2 support via :py:mod:`PIL.ImageCms`. * ``webp``: WebP image support. diff --git a/docs/reference/internal_design.rst b/docs/reference/internal_design.rst index 5f911db51..2e2d3322f 100644 --- a/docs/reference/internal_design.rst +++ b/docs/reference/internal_design.rst @@ -8,3 +8,4 @@ Internal Reference Docs limits block_allocator internal_modules + c_extension_debugging diff --git a/docs/reference/limits.rst b/docs/reference/limits.rst index 79dc66e67..a71b514b5 100644 --- a/docs/reference/limits.rst +++ b/docs/reference/limits.rst @@ -25,13 +25,6 @@ Internal Limits is smaller than 2GB, as calculated by ``y*stride`` (so 2Gpx for 'L' images, and .5Gpx for 'RGB' -* Any call to internal python size functions for buffers or strings - are currently returned as int32, not py_ssize_t. This limits the - maximum buffer to 2GB for operations like frombytes and frombuffer. - -* This also limits the size of buffers converted using a - decoder. (decode.c:127) - Format Size Limits ================== diff --git a/docs/releasenotes/7.1.0.rst b/docs/releasenotes/7.1.0.rst index fd3627e3c..0024a537d 100644 --- a/docs/releasenotes/7.1.0.rst +++ b/docs/releasenotes/7.1.0.rst @@ -74,7 +74,7 @@ Security This release includes security fixes. -* :cve:`CVE-2020-10177` Fix multiple OOB reads in FLI decoding +* :cve:`CVE-2020-10177` Fix multiple out-of-bounds reads in FLI decoding * :cve:`CVE-2020-10378` Fix bounds overflow in PCX decoding * :cve:`CVE-2020-10379` Fix two buffer overflows in TIFF decoding * :cve:`CVE-2020-10994` Fix bounds overflow in JPEG 2000 decoding diff --git a/docs/releasenotes/8.0.0.rst b/docs/releasenotes/8.0.0.rst index 1bef62e00..2ff9b3799 100644 --- a/docs/releasenotes/8.0.0.rst +++ b/docs/releasenotes/8.0.0.rst @@ -78,7 +78,7 @@ Added a new ``formats`` parameter to :py:func:`.Image.open`: * A list or tuple of formats to attempt to load the file in. This can be used to restrict the set of formats checked. Pass ``None`` to try all supported formats. You can print the set of - available formats by running ``python -m PIL`` or using + available formats by running ``python3 -m PIL`` or using the :py:func:`PIL.features.pilinfo` function. ImageOps.autocontrast: add mask parameter @@ -115,8 +115,9 @@ now support fonts with embedded color data. To render text with embedded color data, use the parameter ``embedded_color=True``. Support for CBDT fonts requires FreeType 2.5 compiled with libpng. +Support for SBIX fonts requires FreeType 2.5.1 compiled with libpng. Support for COLR fonts requires FreeType 2.10. -SBIX and SVG fonts are not yet supported. +SVG fonts are not yet supported. ImageDraw.textlength ^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/releasenotes/8.1.0.rst b/docs/releasenotes/8.1.0.rst index 976fa482a..8ed1d9d85 100644 --- a/docs/releasenotes/8.1.0.rst +++ b/docs/releasenotes/8.1.0.rst @@ -15,13 +15,10 @@ vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`). .. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/ -API Changes -=========== +Makefile +^^^^^^^^ -TODO -^^^^ - -TODO +The ``install-venv`` target has been deprecated. API Additions ============= @@ -39,12 +36,58 @@ already exists for the ICNS format. Security ======== -OpenJPEG in the macOS and Linux wheels has been updated from 2.3.1 to 2.4.0, including security fixes. +This release includes security fixes. + +* An out-of-bounds read when saving TIFFs with custom metadata through LibTIFF +* An out-of-bounds read when saving a GIF of 1px width +* :cve:`CVE-2020-35653` Buffer read overrun in PCX decoding + +The PCX image decoder used the reported image stride to calculate the row buffer, +rather than calculating it from the image size. This issue dates back to the PIL fork. +Thanks to Google's `OSS-Fuzz`_ project for finding this. + +* :cve:`CVE-2020-35654` Fix TIFF out-of-bounds write error + +Out-of-bounds write in ``TiffDecode.c`` when reading corrupt YCbCr files in some +LibTIFF versions (4.1.0/Ubuntu 20.04, but not 4.0.9/Ubuntu 18.04). In some cases +LibTIFF's interpretation of the file is different when reading in RGBA mode, leading to +an out-of-bounds write in ``TiffDecode.c``. This potentially affects Pillow versions +from 6.0.0 to 8.0.1, depending on the version of LibTIFF. This was reported through +`Tidelift`_. + +* :cve:`CVE-2020-35655` Fix for SGI Decode buffer overrun + +4 byte read overflow in ``SgiRleDecode.c``, where the code was not correctly checking the +offsets and length tables. Independently reported through `Tidelift`_ and Google's +`OSS-Fuzz`_. This vulnerability covers Pillow versions 4.3.0->8.0.1. + +.. _Tidelift: https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pillow&utm_medium=referral&utm_campaign=docs +.. _OSS-Fuzz: https://github.com/google/oss-fuzz + +Dependencies +^^^^^^^^^^^^ + +OpenJPEG in the macOS and Linux wheels has been updated from 2.3.1 to 2.4.0, including +security fixes. + +LibTIFF in the macOS and Linux wheels has been updated from 4.1.0 to 4.2.0, including +security fixes discovered by fuzzers. Other Changes ============= +Makefile +^^^^^^^^ + +The ``co`` target has been removed. + PyPy wheels ^^^^^^^^^^^ Wheels have been added for PyPy 3.7. + +PySide6 +^^^^^^^ + +Support has been added for PySide6. If it is installed, it will be used instead of +PyQt5 or PySide2, since it is based on a newer Qt. diff --git a/docs/releasenotes/8.1.1.rst b/docs/releasenotes/8.1.1.rst new file mode 100644 index 000000000..4081c49ca --- /dev/null +++ b/docs/releasenotes/8.1.1.rst @@ -0,0 +1,27 @@ +8.1.1 +----- + +Security +======== + +:cve:`CVE-2021-25289`: The previous fix for :cve:`CVE-2020-35654` was insufficient +due to incorrect error checking in ``TiffDecode.c``. + +:cve:`CVE-2021-25290`: In ``TiffDecode.c``, there is a negative-offset ``memcpy`` +with an invalid size. + +:cve:`CVE-2021-25291`: In ``TiffDecode.c``, invalid tile boundaries could lead to +an out-of-bounds read in ``TIFFReadRGBATile``. + +:cve:`CVE-2021-25292`: The PDF parser has a catastrophic backtracking regex +that could be used as a DOS attack. + +:cve:`CVE-2021-25293`: There is an out-of-bounds read in ``SgiRleDecode.c``, +since Pillow 4.3.0. + + +Other Changes +============= + +A crash with the feature flags for libimagequant, libjpeg-turbo, WebP and XCB on +unreleased Python 3.10 has been fixed (:issue:`5193`). diff --git a/docs/releasenotes/8.1.2.rst b/docs/releasenotes/8.1.2.rst new file mode 100644 index 000000000..50d132f33 --- /dev/null +++ b/docs/releasenotes/8.1.2.rst @@ -0,0 +1,12 @@ +8.1.2 +----- + +Security +======== + +There is an exhaustion of memory DOS in the BLP (:cve:`CVE-2021-27921`), +ICNS (:cve:`CVE-2021-27922`) and ICO (:cve:`CVE-2021-27923`) container formats +where Pillow did not properly check the reported size of the contained image. +These images could cause arbitrarily large memory allocations. This was reported +by Jiayi Lin, Luke Shaffer, Xinran Xie, and Akshay Ajayan of +`Arizona State University `_. diff --git a/docs/releasenotes/8.2.0.rst b/docs/releasenotes/8.2.0.rst new file mode 100644 index 000000000..912af3ad2 --- /dev/null +++ b/docs/releasenotes/8.2.0.rst @@ -0,0 +1,230 @@ +8.2.0 +----- + +Deprecations +============ + +Categories +^^^^^^^^^^ + +``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), +along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and +``Image.CONTAINER`` attributes. + +To determine if an image has multiple frames or not, +``getattr(im, "is_animated", False)`` can be used instead. + +Tk/Tcl 8.4 +^^^^^^^^^^ + +Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), +when Tk/Tcl 8.5 will be the minimum supported. + +API Changes +=========== + +Image.alpha_composite: dest +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When calling :py:meth:`~PIL.Image.Image.alpha_composite`, the ``dest`` argument now +accepts negative co-ordinates, like the upper left corner of the ``box`` argument of +:py:meth:`~PIL.Image.Image.paste` can be negative. Naturally, this has effect of +cropping the overlaid image. + +Image.getexif: EXIF and GPS IFD +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Previously, :py:meth:`~PIL.Image.Image.getexif` flattened the EXIF IFD into the rest of +the data, losing information. This information is now kept separate, moved under +``im.getexif().get_ifd(0x8769)``. + +Direct access to the GPS IFD dictionary was possible through ``im.getexif()[0x8825]``. +This is now consistent with other IFDs, and must be accessed through +``im.getexif().get_ifd(0x8825)``. + +These changes only affect :py:meth:`~PIL.Image.Image.getexif`, introduced in Pillow +6.0. The older ``_getexif()`` methods are unaffected. + +Image._MODEINFO +^^^^^^^^^^^^^^^ + +This internal dictionary had been deprecated by a comment since PIL, and is now +removed. Instead, ``Image.getmodebase()``, ``Image.getmodetype()``, +``Image.getmodebandnames()``, ``Image.getmodebands()`` or ``ImageMode.getmode()`` +can be used. + +API Additions +============= + +getxmp() for JPEG images +^^^^^^^^^^^^^^^^^^^^^^^^ + +A new method has been added to return +`XMP data `_ for JPEG +images. It reads the XML data into a dictionary of names and values. + +For example:: + + >>> from PIL import Image + >>> with Image.open("Tests/images/xmp_test.jpg") as im: + >>> print(im.getxmp()) + {'RDF': {}, 'Description': {'Version': '10.4', 'ProcessVersion': '10.0', ...}, ...} + +ImageDraw.rounded_rectangle +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Added :py:meth:`~PIL.ImageDraw.ImageDraw.rounded_rectangle`. It works the same as +:py:meth:`~PIL.ImageDraw.ImageDraw.rectangle`, except with an additional ``radius`` +argument. ``radius`` is limited to half of the width or the height, so that users can +create a circle, but not any other ellipse. + +.. code-block:: python + + from PIL import Image, ImageDraw + im = Image.new("RGB", (200, 200)) + draw = ImageDraw.Draw(im) + draw.rounded_rectangle(xy=(10, 20, 190, 180), radius=30, fill="red") + +ImageOps.autocontrast: preserve_tone +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The default behaviour of :py:meth:`~PIL.ImageOps.autocontrast` is to normalize +separate histograms for each color channel, changing the tone of the image. The new +``preserve_tone`` argument keeps the tone unchanged by using one luminance histogram +for all channels. + +ImageShow.GmDisplayViewer +^^^^^^^^^^^^^^^^^^^^^^^^^ + +If GraphicsMagick is present, this new :py:class:`PIL.ImageShow.Viewer` subclass will +be registered. It uses GraphicsMagick_, an ImageMagick_ fork, to display images. + +The GraphicsMagick based viewer has a lower priority than its ImageMagick +counterpart. Thus, if both ImageMagick and GraphicsMagick are installed, +``im.show()`` and :py:func:`.ImageShow.show()` prefer the viewer based on +ImageMagick, i.e the behaviour stays the same for Pillow users having +ImageMagick installed. + +ImageShow.IPythonViewer +^^^^^^^^^^^^^^^^^^^^^^^ + +If IPython is present, this new :py:class:`PIL.ImageShow.Viewer` subclass will be +registered. It displays images on all IPython frontends. This will be helpful +to users of Google Colab, allowing ``im.show()`` to display images. + +It is lower in priority than the other default :py:class:`PIL.ImageShow.Viewer` +instances, so it will only be used by ``im.show()`` or :py:func:`.ImageShow.show()` +if none of the other viewers are available. This means that the behaviour of +:py:class:`PIL.ImageShow` will stay the same for most Pillow users. + +Saving TIFF with ICC profile +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As is already possible for JPEG, PNG and WebP, the ICC profile for TIFF files can now +be specified through a keyword argument:: + + im.save("out.tif", icc_profile=...) + + +Security +======== + +These were all found with `OSS-Fuzz`_. + +:cve:`CVE-2021-25287`, :cve:`CVE-2021-25288`: Fix OOB read in Jpeg2KDecode +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* For J2k images with multiple bands, it's legal to have different widths for each band, + e.g. 1 byte for ``L``, 4 bytes for ``A``. +* This dates to Pillow 2.4.0. + +:cve:`CVE-2021-28675`: Fix DOS in PsdImagePlugin +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* :py:class:`.PsdImagePlugin.PsdImageFile` did not sanity check the number of input + layers with regard to the size of the data block, this could lead to a + denial-of-service on :py:meth:`~PIL.Image.open` prior to + :py:meth:`~PIL.Image.Image.load`. +* This dates to the PIL fork. + +:cve:`CVE-2021-28676`: Fix FLI DOS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* ``FliDecode.c`` did not properly check that the block advance was non-zero, + potentially leading to an infinite loop on load. +* This dates to the PIL fork. + +:cve:`CVE-2021-28677`: Fix EPS DOS on _open +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The readline used in EPS has to deal with any combination of ``\r`` and ``\n`` as line + endings. It accidentally used a quadratic method of accumulating lines while looking + for a line ending. +* A malicious EPS file could use this to perform a denial-of-service of Pillow in the + open phase, before an image was accepted for opening. +* This dates to the PIL fork. + +:cve:`CVE-2021-28678`: Fix BLP DOS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* ``BlpImagePlugin`` did not properly check that reads after jumping to file offsets + returned data. This could lead to a denial-of-service where the decoder could be run a + large number of times on empty data. +* This dates to Pillow 5.1.0. + +Fix memory DOS in ImageFont +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* A corrupt or specially crafted TTF font could have font metrics that lead to + unreasonably large sizes when rendering text in font. ``ImageFont.py`` did not check + the image size before allocating memory for it. +* This dates to the PIL fork. + +Other Changes +============= + +GIF writer uses LZW encoding +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +GIF files are now written using LZW encoding, which will generate smaller files, +typically about 70% of the size generated by the older encoder. + +The pixel data is encoded using the format specified in the `CompuServe GIF standard +`_. + +The older encoder used a variant of run-length encoding that was compatible but less +efficient. + +GraphicsMagick +^^^^^^^^^^^^^^ + +The test suite can now be run on systems which have GraphicsMagick_ but not +ImageMagick_ installed. If both are installed, the tests prefer ImageMagick. + +Libraqm and FriBiDi linking +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The way the libraqm dependency for complex text scripts is linked has been changed: + +Source builds will now link against the system version of libraqm at build time +rather than at runtime by default. + +Binary wheels now include a statically linked modified version of libraqm that +links against FriBiDi at runtime instead. This change is intended to address +issues with the previous implementation on some platforms. These are created +by building Pillow with the new build flags ``--vendor-raqm --vendor-fribidi``. + +Windows users will now need to install ``fribidi.dll`` (or ``fribidi-0.dll``) only, +``libraqm.dll`` is no longer used. + +See :doc:`installation documentation<../installation>` for more information. + +PyQt6 +^^^^^ + +Support has been added for PyQt6. If it is installed, it will be used instead of +PySide6, PyQt5 or PySide2. + +.. _GraphicsMagick: http://www.graphicsmagick.org/ +.. _ImageMagick: https://imagemagick.org/ +.. _OSS-Fuzz: https://github.com/google/oss-fuzz diff --git a/docs/releasenotes/8.3.0.rst b/docs/releasenotes/8.3.0.rst new file mode 100644 index 000000000..b8f9f6f50 --- /dev/null +++ b/docs/releasenotes/8.3.0.rst @@ -0,0 +1,73 @@ +8.3.0 +----- + +Deprecations +============ + +TODO +^^^^ + +TODO + +API Changes +=========== + +Changed WebP default "method" value when saving +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Previously, it was 0, for the best speed. The default has now been changed to 4, to +match WebP's default, for higher quality with still some speed optimisation. + +Default resampling filter for special image modes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Pillow 7.0 changed the default resampling filter to ``Image.BICUBIC``. However, as this +is not supported yet for images with a custom number of bits, the default filter for +those modes has been reverted to ``Image.NEAREST``. + +ImageMorph incorrect mode errors +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For ``apply()``, ``match()`` and ``get_on_pixels()``, if the image mode is not L, an +:py:exc:`Exception` was thrown. This has now been changed to a :py:exc:`ValueError`. + +API Additions +============= + +ImageOps.contain +^^^^^^^^^^^^^^^^ + +Returns a resized version of the image, set to the maximum width and height within +``size``, while maintaining the original aspect ratio. + +To compare it to other ImageOps methods: + +- :py:meth:`~PIL.ImageOps.fit` expands an image until is fills ``size``, cropping the + parts of the image that do not fit. +- :py:meth:`~PIL.ImageOps.pad` expands an image to fill ``size``, without cropping, but + instead filling the extra space with ``color``. +- :py:meth:`~PIL.ImageOps.contain` is similar to :py:meth:`~PIL.ImageOps.pad`, but it + does not fill the extra space. Instead, the original aspect ratio is maintained. So + unlike the other two methods, it is not guaranteed to return an image of ``size``. + +ICO saving: bitmap_format argument +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, Pillow saves ICO files in the PNG format. They can now also be saved in BMP +format, through the new ``bitmap_format`` argument:: + + im.save("out.ico", bitmap_format="bmp") + +Security +======== + +TODO + +Other Changes +============= + +Added DDS BC5 reading +^^^^^^^^^^^^^^^^^^^^^ + +Support has been added to read the BC5 format of DDS images, whether UNORM, SNORM or +TYPELESS. diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index cd73de814..3e23e43d3 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -14,6 +14,10 @@ expected to be backported to earlier versions. .. toctree:: :maxdepth: 2 + 8.3.0 + 8.2.0 + 8.1.2 + 8.1.1 8.1.0 8.0.1 8.0.0 diff --git a/docs/releasenotes/versioning.rst b/docs/releasenotes/versioning.rst index 1653bff3c..a8c9fc998 100644 --- a/docs/releasenotes/versioning.rst +++ b/docs/releasenotes/versioning.rst @@ -3,7 +3,7 @@ Versioning ========== -Pillow follows [Semantic Versioning](https://semver.org/): +Pillow follows `Semantic Versioning `_: Given a version number MAJOR.MINOR.PATCH, increment the: diff --git a/docs/resources/css/dark.css b/docs/resources/css/dark.css index cc213d674..8866c07ea 100644 --- a/docs/resources/css/dark.css +++ b/docs/resources/css/dark.css @@ -1275,7 +1275,7 @@ .wy-body-for-nav { background-image: initial; - background-color: rgb(26, 28, 29); + background-color: rgb(24, 26, 27); } .wy-nav-side { @@ -1333,11 +1333,6 @@ color: rgb(152, 143, 129); } - .wy-body-for-nav { - background-image: initial; - background-color: rgb(26, 28, 29); - } - @media screen and (min-width: 1100px) { .wy-nav-content-wrap { background-image: initial; diff --git a/requirements.txt b/requirements.txt index 1ed1356f9..fd2ede5fd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,10 @@ packaging pyroma pytest pytest-cov +pytest-timeout sphinx>=2.4 +sphinx-copybutton sphinx-issues sphinx-removed-in sphinx-rtd-theme +sphinxext-opengraph diff --git a/selftest.py b/selftest.py index a9a02ef71..8d77cc5a9 100755 --- a/selftest.py +++ b/selftest.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # minimal sanity check import sys @@ -147,9 +147,7 @@ def testimage(): ('F', (128, 128)) PIL can do many other things, but I'll leave that for another - day. If you're curious, check the handbook, available from: - - http://www.pythonware.com + day. Cheers /F """ diff --git a/setup.py b/setup.py index cbc2641c5..c3b9eee41 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # > pyroma . # ------------------------------ # Checking . @@ -29,13 +29,15 @@ def get_version(): NAME = "Pillow" PILLOW_VERSION = get_version() FREETYPE_ROOT = None +HARFBUZZ_ROOT = None +FRIBIDI_ROOT = None IMAGEQUANT_ROOT = None JPEG2K_ROOT = None JPEG_ROOT = None LCMS_ROOT = None TIFF_ROOT = None ZLIB_ROOT = None - +FUZZING_BUILD = "LIB_FUZZING_ENGINE" in os.environ if sys.platform == "win32" and sys.version_info >= (3, 10): import atexit @@ -228,6 +230,19 @@ def _find_library_file(self, library): return ret +def _find_include_dir(self, dirname, include): + for directory in self.compiler.include_dirs: + _dbg("Checking for include file %s in %s", (include, directory)) + if os.path.isfile(os.path.join(directory, include)): + _dbg("Found %s in %s", (include, directory)) + return True + subdir = os.path.join(directory, dirname) + _dbg("Checking for include file %s in %s", (include, subdir)) + if os.path.isfile(os.path.join(subdir, include)): + _dbg("Found %s in %s", (include, subdir)) + return subdir + + def _cmd_exists(cmd): return any( os.access(os.path.join(path, cmd), os.X_OK) @@ -267,6 +282,7 @@ class pil_build_ext(build_ext): "jpeg", "tiff", "freetype", + "raqm", "lcms", "webp", "webpmux", @@ -276,6 +292,7 @@ class pil_build_ext(build_ext): ] required = {"jpeg", "zlib"} + vendor = set() def __init__(self): for f in self.features: @@ -287,6 +304,9 @@ class pil_build_ext(build_ext): def want(self, feat): return getattr(self, feat) is None + def want_vendor(self, feat): + return feat in self.vendor + def __iter__(self): yield from self.features @@ -296,6 +316,10 @@ class pil_build_ext(build_ext): build_ext.user_options + [(f"disable-{x}", None, f"Disable support for {x}") for x in feature] + [(f"enable-{x}", None, f"Enable support for {x}") for x in feature] + + [ + (f"vendor-{x}", None, f"Use vendored version of {x}") + for x in ("raqm", "fribidi") + ] + [ ("disable-platform-guessing", None, "Disable platform guessing on Linux"), ("debug", None, "Debug logging"), @@ -310,6 +334,8 @@ class pil_build_ext(build_ext): for x in self.feature: setattr(self, f"disable_{x}", None) setattr(self, f"enable_{x}", None) + for x in ("raqm", "fribidi"): + setattr(self, f"vendor_{x}", None) def finalize_options(self): build_ext.finalize_options(self) @@ -334,18 +360,43 @@ class pil_build_ext(build_ext): raise ValueError( f"Conflicting options: --enable-{x} and --disable-{x}" ) + if x == "freetype": + _dbg("--disable-freetype implies --disable-raqm") + if getattr(self, "enable_raqm"): + raise ValueError( + "Conflicting options: --enable-raqm and --disable-freetype" + ) + setattr(self, "disable_raqm", True) if getattr(self, f"enable_{x}"): _dbg("Requiring %s", x) self.feature.required.add(x) + if x == "raqm": + _dbg("--enable-raqm implies --enable-freetype") + self.feature.required.add("freetype") + for x in ("raqm", "fribidi"): + if getattr(self, f"vendor_{x}"): + if getattr(self, "disable_raqm"): + raise ValueError( + f"Conflicting options: --vendor-{x} and --disable-raqm" + ) + if x == "fribidi" and not getattr(self, "vendor_raqm"): + raise ValueError( + f"Conflicting options: --vendor-{x} and not --vendor-raqm" + ) + _dbg("Using vendored version of %s", x) + self.feature.vendor.add(x) - def _update_extension(self, name, libraries, define_macros=None, include_dirs=None): + def _update_extension(self, name, libraries, define_macros=None, sources=None): for extension in self.extensions: if extension.name == name: extension.libraries += libraries if define_macros is not None: extension.define_macros += define_macros - if include_dirs is not None: - extension.include_dirs += include_dirs + if sources is not None: + extension.sources += sources + if FUZZING_BUILD: + extension.language = "c++" + extension.extra_link_args = ["--stdlib=libc++"] break def _remove_extension(self, name): @@ -371,6 +422,8 @@ class pil_build_ext(build_ext): TIFF_ROOT=("libtiff-5", "libtiff-4"), ZLIB_ROOT="zlib", FREETYPE_ROOT="freetype2", + HARFBUZZ_ROOT="harfbuzz", + FRIBIDI_ROOT="fribidi", LCMS_ROOT="lcms2", IMAGEQUANT_ROOT="libimagequant", ).items(): @@ -656,6 +709,39 @@ class pil_build_ext(build_ext): if subdir: _add_directory(self.compiler.include_dirs, subdir, 0) + if feature.freetype and feature.want("raqm"): + if not feature.want_vendor("raqm"): # want system Raqm + _dbg("Looking for Raqm") + if _find_include_file(self, "raqm.h"): + if _find_library_file(self, "raqm"): + feature.raqm = "raqm" + elif _find_library_file(self, "libraqm"): + feature.raqm = "libraqm" + else: # want to build Raqm from src/thirdparty + _dbg("Looking for HarfBuzz") + feature.harfbuzz = None + hb_dir = _find_include_dir(self, "harfbuzz", "hb.h") + if hb_dir: + if isinstance(hb_dir, str): + _add_directory(self.compiler.include_dirs, hb_dir, 0) + if _find_library_file(self, "harfbuzz"): + feature.harfbuzz = "harfbuzz" + if feature.harfbuzz: + if not feature.want_vendor("fribidi"): # want system FriBiDi + _dbg("Looking for FriBiDi") + feature.fribidi = None + fribidi_dir = _find_include_dir(self, "fribidi", "fribidi.h") + if fribidi_dir: + if isinstance(fribidi_dir, str): + _add_directory( + self.compiler.include_dirs, fribidi_dir, 0 + ) + if _find_library_file(self, "fribidi"): + feature.fribidi = "fribidi" + feature.raqm = True + else: # want to build FriBiDi shim from src/thirdparty + feature.raqm = True + if feature.want("lcms"): _dbg("Looking for lcms") if _find_include_file(self, "lcms2.h"): @@ -724,9 +810,11 @@ class pil_build_ext(build_ext): if feature.tiff: libs.append(feature.tiff) defs.append(("HAVE_LIBTIFF", None)) - # FIXME the following define should be detected automatically - # based on system libtiff, see #4237 - if PLATFORM_MINGW: + if sys.platform == "win32": + # This define needs to be defined if-and-only-if it was defined + # when compiling LibTIFF. LibTIFF doesn't expose it in `tiffconf.h`, + # so we have to guess; by default it is defined in all Windows builds. + # See #4237, #5243, #5359 for more information. defs.append(("USE_WIN32_FILEIO", None)) if feature.xcb: libs.append(feature.xcb) @@ -751,9 +839,25 @@ class pil_build_ext(build_ext): # additional libraries if feature.freetype: + srcs = [] libs = ["freetype"] defs = [] - self._update_extension("PIL._imagingft", libs, defs) + if feature.raqm: + if not feature.want_vendor("raqm"): # using system Raqm + defs.append(("HAVE_RAQM", None)) + defs.append(("HAVE_RAQM_SYSTEM", None)) + libs.append(feature.raqm) + else: # building Raqm from src/thirdparty + defs.append(("HAVE_RAQM", None)) + srcs.append("src/thirdparty/raqm/raqm.c") + libs.append(feature.harfbuzz) + if not feature.want_vendor("fribidi"): # using system FriBiDi + defs.append(("HAVE_FRIBIDI_SYSTEM", None)) + libs.append(feature.fribidi) + else: # building FriBiDi shim from src/thirdparty + srcs.append("src/thirdparty/fribidi-shim/fribidi.c") + self._update_extension("PIL._imagingft", libs, defs, srcs) + else: self._remove_extension("PIL._imagingft") @@ -800,6 +904,12 @@ class pil_build_ext(build_ext): print(f" [{v.strip()}") print("-" * 68) + raqm_extra_info = "" + if feature.want_vendor("raqm"): + raqm_extra_info += "bundled" + if feature.want_vendor("fribidi"): + raqm_extra_info += ", FriBiDi shim" + options = [ (feature.jpeg, "JPEG"), (feature.jpeg2000, "OPENJPEG (JPEG2000)", feature.openjpeg_version), @@ -807,6 +917,7 @@ class pil_build_ext(build_ext): (feature.imagequant, "LIBIMAGEQUANT"), (feature.tiff, "LIBTIFF"), (feature.freetype, "FREETYPE2"), + (feature.raqm, "RAQM (Text shaping)", raqm_extra_info), (feature.lcms, "LITTLECMS2"), (feature.webp, "WEBP"), (feature.webpmux, "WEBPMUX"), @@ -816,10 +927,10 @@ class pil_build_ext(build_ext): all = 1 for option in options: if option[0]: - version = "" + extra_info = "" if len(option) >= 3 and option[2]: - version = f" ({option[2]})" - print(f"--- {option[1]} support available{version}") + extra_info = f" ({option[2]})" + print(f"--- {option[1]} support available{extra_info}") else: print(f"*** {option[1]} support not available") all = 0 @@ -840,7 +951,7 @@ class pil_build_ext(build_ext): def debug_build(): - return hasattr(sys, "gettotalrefcount") + return hasattr(sys, "gettotalrefcount") or FUZZING_BUILD files = ["src/_imaging.c"] diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index d5d7c0e05..7b78597b4 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -286,33 +286,36 @@ class _BLPBaseDecoder(ImageFile.PyDecoder): raise OSError("Truncated Blp file") from e return 0, 0 + def _safe_read(self, length): + return ImageFile._safe_read(self.fd, length) + def _read_palette(self): ret = [] for i in range(256): try: - b, g, r, a = struct.unpack("<4B", self.fd.read(4)) + b, g, r, a = struct.unpack("<4B", self._safe_read(4)) except struct.error: break ret.append((b, g, r, a)) return ret def _read_blp_header(self): - (self._blp_compression,) = struct.unpack("= 52: for idx, mask in enumerate( ["r_mask", "g_mask", "b_mask", "a_mask"] ): - file_info[mask] = i32(header_data[36 + idx * 4 : 40 + idx * 4]) + file_info[mask] = i32(header_data, 36 + idx * 4) else: # 40 byte headers only have the three components in the # bitfields masks, ref: @@ -267,7 +264,7 @@ class BmpImageFile(ImageFile.ImageFile): if not _accept(head_data): raise SyntaxError("Not a BMP file") # read the start position of the BMP image data (u32) - offset = i32(head_data[10:14]) + offset = i32(head_data, 10) # load bitmap information (offset=raster info) self._bitmap(offset=offset) diff --git a/src/PIL/CurImagePlugin.py b/src/PIL/CurImagePlugin.py index 35123f789..42af5cafc 100644 --- a/src/PIL/CurImagePlugin.py +++ b/src/PIL/CurImagePlugin.py @@ -16,7 +16,6 @@ # See the README file for information on usage and redistribution. # from . import BmpImagePlugin, Image -from ._binary import i8 from ._binary import i16le as i16 from ._binary import i32le as i32 @@ -48,17 +47,17 @@ class CurImageFile(BmpImagePlugin.BmpImageFile): # pick the largest cursor in the file m = b"" - for i in range(i16(s[4:])): + for i in range(i16(s, 4)): s = self.fp.read(16) if not m: m = s - elif i8(s[0]) > i8(m[0]) and i8(s[1]) > i8(m[1]): + elif s[0] > m[0] and s[1] > m[1]: m = s if not m: raise TypeError("No cursors were found") # load as bitmap - self._bitmap(i32(m[12:]) + offset) + self._bitmap(i32(m, 12) + offset) # patch up the bitmap height self._size = self.size[0], self.size[1] // 2 diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index df2d0060c..260924fca 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -14,6 +14,7 @@ import struct from io import BytesIO from . import Image, ImageFile +from ._binary import o32le as o32 # Magic ("DDS ") DDS_MAGIC = 0x20534444 @@ -97,6 +98,9 @@ DXT5_FOURCC = 0x35545844 DXGI_FORMAT_R8G8B8A8_TYPELESS = 27 DXGI_FORMAT_R8G8B8A8_UNORM = 28 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29 +DXGI_FORMAT_BC5_TYPELESS = 82 +DXGI_FORMAT_BC5_UNORM = 83 +DXGI_FORMAT_BC5_SNORM = 84 DXGI_FORMAT_BC7_TYPELESS = 97 DXGI_FORMAT_BC7_UNORM = 98 DXGI_FORMAT_BC7_UNORM_SRGB = 99 @@ -127,15 +131,17 @@ class DdsImageFile(ImageFile.ImageFile): fourcc = header.read(4) (bitcount,) = struct.unpack("= 6 and i16(prefix[4:6]) in [0xAF11, 0xAF12] + return len(prefix) >= 6 and i16(prefix, 4) in [0xAF11, 0xAF12] ## @@ -47,22 +46,22 @@ class FliImageFile(ImageFile.ImageFile): s = self.fp.read(128) if not ( _accept(s) - and i16(s[14:16]) in [0, 3] # flags + and i16(s, 14) in [0, 3] # flags and s[20:22] == b"\x00\x00" # reserved ): raise SyntaxError("not an FLI/FLC file") # frames - self.n_frames = i16(s[6:8]) + self.n_frames = i16(s, 6) self.is_animated = self.n_frames > 1 # image characteristics self.mode = "P" - self._size = i16(s[8:10]), i16(s[10:12]) + self._size = i16(s, 8), i16(s, 10) # animation speed - duration = i32(s[16:20]) - magic = i16(s[4:6]) + duration = i32(s, 16) + magic = i16(s, 4) if magic == 0xAF11: duration = (duration * 1000) // 70 self.info["duration"] = duration @@ -74,17 +73,17 @@ class FliImageFile(ImageFile.ImageFile): self.__offset = 128 - if i16(s[4:6]) == 0xF100: + if i16(s, 4) == 0xF100: # prefix chunk; ignore it self.__offset = self.__offset + i32(s) s = self.fp.read(16) - if i16(s[4:6]) == 0xF1FA: + if i16(s, 4) == 0xF1FA: # look for palette chunk s = self.fp.read(6) - if i16(s[4:6]) == 11: + if i16(s, 4) == 11: self._palette(palette, 2) - elif i16(s[4:6]) == 4: + elif i16(s, 4) == 4: self._palette(palette, 0) palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette] @@ -102,15 +101,15 @@ class FliImageFile(ImageFile.ImageFile): i = 0 for e in range(i16(self.fp.read(2))): s = self.fp.read(2) - i = i + i8(s[0]) - n = i8(s[1]) + i = i + s[0] + n = s[1] if n == 0: n = 256 s = self.fp.read(n * 3) for n in range(0, len(s), 3): - r = i8(s[n]) << shift - g = i8(s[n + 1]) << shift - b = i8(s[n + 2]) << shift + r = s[n] << shift + g = s[n + 1] << shift + b = s[n + 2] << shift palette[i] = (r, g, b) i += 1 diff --git a/src/PIL/FpxImagePlugin.py b/src/PIL/FpxImagePlugin.py index 14070eebf..5e385469f 100644 --- a/src/PIL/FpxImagePlugin.py +++ b/src/PIL/FpxImagePlugin.py @@ -17,7 +17,6 @@ import olefile from . import Image, ImageFile -from ._binary import i8 from ._binary import i32le as i32 # we map from colour field tuples to (mode, rawmode) descriptors @@ -181,8 +180,8 @@ class FpxImageFile(ImageFile.ImageFile): elif compression == 2: - internal_color_conversion = i8(s[14]) - jpeg_tables = i8(s[15]) + internal_color_conversion = s[14] + jpeg_tables = s[15] rawmode = self.rawmode if internal_color_conversion: diff --git a/src/PIL/FtexImagePlugin.py b/src/PIL/FtexImagePlugin.py index 900661238..3b169038c 100644 --- a/src/PIL/FtexImagePlugin.py +++ b/src/PIL/FtexImagePlugin.py @@ -98,9 +98,9 @@ class FtexImageFile(ImageFile.ImageFile): pass -def _validate(prefix): +def _accept(prefix): return prefix[:4] == MAGIC -Image.register_open(FtexImageFile.format, FtexImageFile, _validate) +Image.register_open(FtexImageFile.format, FtexImageFile, _accept) Image.register_extensions(FtexImageFile.format, [".ftc", ".ftu"]) diff --git a/src/PIL/GbrImagePlugin.py b/src/PIL/GbrImagePlugin.py index 5e447b411..0f230602d 100644 --- a/src/PIL/GbrImagePlugin.py +++ b/src/PIL/GbrImagePlugin.py @@ -29,7 +29,7 @@ from ._binary import i32be as i32 def _accept(prefix): - return len(prefix) >= 8 and i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1, 2) + return len(prefix) >= 8 and i32(prefix, 0) >= 20 and i32(prefix, 4) in (1, 2) ## diff --git a/src/PIL/GdImageFile.py b/src/PIL/GdImageFile.py index 8561f7b74..9c34adaa6 100644 --- a/src/PIL/GdImageFile.py +++ b/src/PIL/GdImageFile.py @@ -28,7 +28,6 @@ from . import ImageFile, ImagePalette, UnidentifiedImageError -from ._binary import i8 from ._binary import i16be as i16 from ._binary import i32be as i32 @@ -49,17 +48,17 @@ class GdImageFile(ImageFile.ImageFile): # Header s = self.fp.read(1037) - if not i16(s[:2]) in [65534, 65535]: + if not i16(s) in [65534, 65535]: raise SyntaxError("Not a valid GD 2.x .gd file") self.mode = "L" # FIXME: "P" - self._size = i16(s[2:4]), i16(s[4:6]) + self._size = i16(s, 2), i16(s, 4) - trueColor = i8(s[6]) + trueColor = s[6] trueColorOffset = 2 if trueColor else 0 # transparency index - tindex = i32(s[7 + trueColorOffset : 7 + trueColorOffset + 4]) + tindex = i32(s, 7 + trueColorOffset) if tindex < 256: self.info["transparency"] = tindex diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 95e300bd7..5db310809 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -30,7 +30,6 @@ import os import subprocess from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence -from ._binary import i8 from ._binary import i16le as i16 from ._binary import o8 from ._binary import o16le as o16 @@ -58,8 +57,8 @@ class GifImageFile(ImageFile.ImageFile): def data(self): s = self.fp.read(1) - if s and i8(s): - return self.fp.read(i8(s)) + if s and s[0]: + return self.fp.read(s[0]) return None def _open(self): @@ -70,18 +69,18 @@ class GifImageFile(ImageFile.ImageFile): raise SyntaxError("not a GIF file") self.info["version"] = s[:6] - self._size = i16(s[6:]), i16(s[8:]) + self._size = i16(s, 6), i16(s, 8) self.tile = [] - flags = i8(s[10]) + flags = s[10] bits = (flags & 7) + 1 if flags & 128: # get global palette - self.info["background"] = i8(s[11]) + self.info["background"] = s[11] # check if palette contains colour indices p = self.fp.read(3 << bits) for i in range(0, len(p), 3): - if not (i // 3 == i8(p[i]) == i8(p[i + 1]) == i8(p[i + 2])): + if not (i // 3 == p[i] == p[i + 1] == p[i + 2]): p = ImagePalette.raw("RGB", p) self.global_palette = self.palette = p break @@ -146,11 +145,10 @@ class GifImageFile(ImageFile.ImageFile): self.dispose_extent = [0, 0, 0, 0] # x0, y0, x1, y1 self.__frame = -1 self.__fp.seek(self.__rewind) - self._prev_im = None self.disposal_method = 0 else: # ensure that the previous frame was loaded - if not self.im: + if self.tile: self.load() if frame != self.__frame + 1: @@ -175,6 +173,8 @@ class GifImageFile(ImageFile.ImageFile): self.palette = copy(self.global_palette) info = {} + frame_transparency = None + interlace = None while True: s = self.fp.read(1) @@ -187,14 +187,14 @@ class GifImageFile(ImageFile.ImageFile): # s = self.fp.read(1) block = self.data() - if i8(s) == 249: + if s[0] == 249: # # graphic control extension # - flags = i8(block[0]) + flags = block[0] if flags & 1: - info["transparency"] = i8(block[3]) - info["duration"] = i16(block[1:3]) * 10 + frame_transparency = block[3] + info["duration"] = i16(block, 1) * 10 # disposal method - find the value of bits 4 - 6 dispose_bits = 0b00011100 & flags @@ -205,7 +205,7 @@ class GifImageFile(ImageFile.ImageFile): # correct, but it seems to prevent the last # frame from looking odd for some animations self.disposal_method = dispose_bits - elif i8(s) == 254: + elif s[0] == 254: # # comment extension # @@ -216,15 +216,15 @@ class GifImageFile(ImageFile.ImageFile): info["comment"] = block block = self.data() continue - elif i8(s) == 255: + elif s[0] == 255: # # application extension # info["extension"] = block, self.fp.tell() if block[:11] == b"NETSCAPE2.0": block = self.data() - if len(block) >= 3 and i8(block[0]) == 1: - info["loop"] = i16(block[1:3]) + if len(block) >= 3 and block[0] == 1: + info["loop"] = i16(block, 1) while self.data(): pass @@ -235,12 +235,12 @@ class GifImageFile(ImageFile.ImageFile): s = self.fp.read(9) # extent - x0, y0 = i16(s[0:]), i16(s[2:]) - x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:]) + x0, y0 = i16(s, 0), i16(s, 2) + x1, y1 = x0 + i16(s, 4), y0 + i16(s, 6) if x1 > self.size[0] or y1 > self.size[1]: self._size = max(x1, self.size[0]), max(y1, self.size[1]) self.dispose_extent = x0, y0, x1, y1 - flags = i8(s[8]) + flags = s[8] interlace = (flags & 64) != 0 @@ -249,16 +249,13 @@ class GifImageFile(ImageFile.ImageFile): self.palette = ImagePalette.raw("RGB", self.fp.read(3 << bits)) # image data - bits = i8(self.fp.read(1)) + bits = self.fp.read(1)[0] self.__offset = self.fp.tell() - self.tile = [ - ("gif", (x0, y0, x1, y1), self.__offset, (bits, interlace)) - ] break else: pass - # raise OSError, "illegal GIF tag `%x`" % i8(s) + # raise OSError, "illegal GIF tag `%x`" % s[0] try: if self.disposal_method < 2: @@ -266,24 +263,56 @@ class GifImageFile(ImageFile.ImageFile): self.dispose = None elif self.disposal_method == 2: # replace with background colour - Image._decompression_bomb_check(self.size) - self.dispose = Image.core.fill("P", self.size, self.info["background"]) + + # only dispose the extent in this frame + x0, y0, x1, y1 = self.dispose_extent + dispose_size = (x1 - x0, y1 - y0) + + Image._decompression_bomb_check(dispose_size) + + # by convention, attempt to use transparency first + color = ( + frame_transparency + if frame_transparency is not None + else self.info.get("background", 0) + ) + self.dispose = Image.core.fill("P", dispose_size, color) else: # replace with previous contents if self.im: - self.dispose = self.im.copy() + # only dispose the extent in this frame + self.dispose = self._crop(self.im, self.dispose_extent) + elif frame_transparency is not None: + x0, y0, x1, y1 = self.dispose_extent + dispose_size = (x1 - x0, y1 - y0) - # only dispose the extent in this frame - if self.dispose: - self.dispose = self._crop(self.dispose, self.dispose_extent) - except (AttributeError, KeyError): + Image._decompression_bomb_check(dispose_size) + self.dispose = Image.core.fill( + "P", dispose_size, frame_transparency + ) + except AttributeError: pass - if not self.tile: + if interlace is not None: + transparency = -1 + if frame_transparency is not None: + if frame == 0: + self.info["transparency"] = frame_transparency + else: + transparency = frame_transparency + self.tile = [ + ( + "gif", + (x0, y0, x1, y1), + self.__offset, + (bits, interlace, transparency), + ) + ] + else: # self.__fp = None raise EOFError - for k in ["transparency", "duration", "comment", "extension", "loop"]: + for k in ["duration", "comment", "extension", "loop"]: if k in info: self.info[k] = info[k] elif k in self.info: @@ -293,23 +322,15 @@ class GifImageFile(ImageFile.ImageFile): if self.palette: self.mode = "P" + def load_prepare(self): + if not self.im and "transparency" in self.info: + self.im = Image.core.fill(self.mode, self.size, self.info["transparency"]) + + super(GifImageFile, self).load_prepare() + def tell(self): return self.__frame - def load_end(self): - ImageFile.ImageFile.load_end(self) - - # if the disposal method is 'do not dispose', transparent - # pixels should show the content of the previous frame - if self._prev_im and self._prev_disposal_method == 1: - # we do this by pasting the updated area onto the previous - # frame which we then use as the current image content - updated = self._crop(self.im, self.dispose_extent) - self._prev_im.paste(updated, self.dispose_extent, updated.convert("RGBA")) - self.im = self._prev_im - self._prev_im = self.im.copy() - self._prev_disposal_method = self.disposal_method - def _close__fp(self): try: if self.__fp != self.fp: @@ -451,10 +472,10 @@ def _write_multiple_frames(im, fp, palette): previous = im_frames[-1] if encoderinfo.get("disposal") == 2: if background_im is None: - background = _get_background( - im, - im.encoderinfo.get("background", im.info.get("background")), + color = im.encoderinfo.get( + "transparency", im.info.get("transparency", (0, 0, 0)) ) + background = _get_background(im_frame, color) background_im = Image.new("P", im_frame.size, background) background_im.putpalette(im_frames[0]["im"].palette) base_im = background_im @@ -750,7 +771,15 @@ def _get_background(im, infoBackground): # 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) + try: + background = im.palette.getcolor(background, im) + except ValueError as e: + if str(e) == "cannot allocate more than 256 colors": + # If all 256 colors are in use, + # then there is no need for the background color + return 0 + else: + raise return background diff --git a/src/PIL/GribStubImagePlugin.py b/src/PIL/GribStubImagePlugin.py index 515c272f7..b9bdd16e3 100644 --- a/src/PIL/GribStubImagePlugin.py +++ b/src/PIL/GribStubImagePlugin.py @@ -10,7 +10,6 @@ # from . import Image, ImageFile -from ._binary import i8 _handler = None @@ -30,7 +29,7 @@ def register_handler(handler): def _accept(prefix): - return prefix[0:4] == b"GRIB" and i8(prefix[7]) == 1 + return prefix[0:4] == b"GRIB" and prefix[7] == 1 class GribStubImageFile(ImageFile.StubImageFile): diff --git a/src/PIL/IcnsImagePlugin.py b/src/PIL/IcnsImagePlugin.py index 397de44fe..5442f6fc4 100644 --- a/src/PIL/IcnsImagePlugin.py +++ b/src/PIL/IcnsImagePlugin.py @@ -23,7 +23,6 @@ import struct import sys from PIL import Image, ImageFile, PngImagePlugin, features -from PIL._binary import i8 enable_jpeg2k = features.check_codec("jpg_2000") if enable_jpeg2k: @@ -69,7 +68,7 @@ def read_32(fobj, start_length, size): byte = fobj.read(1) if not byte: break - byte = i8(byte) + byte = byte[0] if byte & 0x80: blocksize = byte - 125 byte = fobj.read(1) @@ -105,6 +104,7 @@ def read_png_or_jpeg2000(fobj, start_length, size): if sig[:8] == b"\x89PNG\x0d\x0a\x1a\x0a": fobj.seek(start) im = PngImagePlugin.PngImageFile(fobj) + Image._decompression_bomb_check(im.size) return {"RGBA": im} elif ( sig[:4] == b"\xff\x4f\xff\x51" @@ -121,6 +121,7 @@ def read_png_or_jpeg2000(fobj, start_length, size): jp2kstream = fobj.read(length) f = io.BytesIO(jp2kstream) im = Jpeg2KImagePlugin.Jpeg2KImageFile(f) + Image._decompression_bomb_check(im.size) if im.mode != "RGBA": im = im.convert("RGBA") return {"RGBA": im} @@ -357,7 +358,11 @@ def _save(im, fp, filename): fp.flush() -Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == MAGIC) +def _accept(prefix): + return prefix[:4] == MAGIC + + +Image.register_open(IcnsImageFile.format, IcnsImageFile, _accept) Image.register_extension(IcnsImageFile.format, ".icns") Image.register_save(IcnsImageFile.format, _save) @@ -365,7 +370,7 @@ Image.register_mime(IcnsImageFile.format, "image/icns") if __name__ == "__main__": if len(sys.argv) < 2: - print("Syntax: python IcnsImagePlugin.py [file]") + print("Syntax: python3 IcnsImagePlugin.py [file]") sys.exit() with open(sys.argv[1], "rb") as fp: diff --git a/src/PIL/IcoImagePlugin.py b/src/PIL/IcoImagePlugin.py index 8b456d502..ffb1e873d 100644 --- a/src/PIL/IcoImagePlugin.py +++ b/src/PIL/IcoImagePlugin.py @@ -28,9 +28,9 @@ from io import BytesIO from math import ceil, log from . import BmpImagePlugin, Image, ImageFile, PngImagePlugin -from ._binary import i8 from ._binary import i16le as i16 from ._binary import i32le as i32 +from ._binary import o32le as o32 # # -------------------------------------------------------------------- @@ -54,6 +54,7 @@ def _save(im, fp, filename): sizes = list(sizes) fp.write(struct.pack("=8bpp) - "reserved": i8(s[3]), - "planes": i16(s[4:]), - "bpp": i16(s[6:]), - "size": i32(s[8:]), - "offset": i32(s[12:]), + "width": s[0], + "height": s[1], + "nb_color": s[2], # No. of colors in image (0 if >=8bpp) + "reserved": s[3], + "planes": i16(s, 4), + "bpp": i16(s, 6), + "size": i32(s, 8), + "offset": i32(s, 12), } # See Wikipedia @@ -179,6 +193,7 @@ class IcoFile: if data[:8] == PngImagePlugin._MAGIC: # png frame im = PngImagePlugin.PngImageFile(self.buf) + Image._decompression_bomb_check(im.size) else: # XOR + AND mask bmp frame im = BmpImagePlugin.DibImageFile(self.buf) @@ -190,13 +205,7 @@ class IcoFile: im.tile[0] = d, (0, 0) + im.size, o, a # figure out where AND mask image starts - mode = a[0] - bpp = 8 - for k, v in BmpImagePlugin.BIT2MODE.items(): - if mode == v[1]: - bpp = k - break - + bpp = header["bpp"] if 32 == bpp: # 32-bit color depth icon image allows semitransparent areas # PIL's DIB format ignores transparency bits, recover them. @@ -267,7 +276,8 @@ class IcoImageFile(ImageFile.ImageFile): Handles classic, XP and Vista icon formats. When saving, PNG compression is used. Support for this was only added in - Windows Vista. + Windows Vista. If you are unable to view the icon in Windows, convert the + image to "RGBA" mode before saving. This plugin is a refactored version of Win32IconImagePlugin by Bryan Davis . diff --git a/src/PIL/ImImagePlugin.py b/src/PIL/ImImagePlugin.py index 8ef474171..1dfc808c4 100644 --- a/src/PIL/ImImagePlugin.py +++ b/src/PIL/ImImagePlugin.py @@ -30,7 +30,6 @@ import os import re from . import Image, ImageFile, ImagePalette -from ._binary import i8 # -------------------------------------------------------------------- # Standard tags @@ -223,14 +222,14 @@ class ImImageFile(ImageFile.ImageFile): linear = 1 # linear greyscale palette for i in range(256): if palette[i] == palette[i + 256] == palette[i + 512]: - if i8(palette[i]) != i: + if palette[i] != i: linear = 0 else: greyscale = 0 if self.mode in ["L", "LA", "P", "PA"]: if greyscale: if not linear: - self.lut = [i8(c) for c in palette[:256]] + self.lut = list(palette[:256]) else: if self.mode in ["L", "P"]: self.mode = self.rawmode = "P" @@ -240,7 +239,7 @@ class ImImageFile(ImageFile.ImageFile): self.palette = ImagePalette.raw("RGB;L", palette) elif self.mode == "RGB": if not greyscale or not linear: - self.lut = [i8(c) for c in palette] + self.lut = list(palette) self.frame = 0 diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 1b4efdc4f..a549a5bb0 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -50,7 +50,7 @@ from . import ( _plugins, _raise_version_warning, ) -from ._binary import i8, i32le +from ._binary import i32le from ._util import deferred_error, isPath if sys.version_info >= (3, 7): @@ -59,6 +59,16 @@ if sys.version_info >= (3, 7): if name == "PILLOW_VERSION": _raise_version_warning() return __version__ + else: + categories = {"NORMAL": 0, "SEQUENCE": 1, "CONTAINER": 2} + if name in categories: + warnings.warn( + "Image categories are deprecated and will be removed in Pillow 10 " + "(2023-01-02). Use is_animated instead.", + DeprecationWarning, + stacklevel=2, + ) + return categories[name] raise AttributeError(f"module '{__name__}' has no attribute '{name}'") @@ -69,6 +79,11 @@ else: # Silence warning assert PILLOW_VERSION + # categories + NORMAL = 0 + SEQUENCE = 1 + CONTAINER = 2 + logger = logging.getLogger(__name__) @@ -187,11 +202,6 @@ MAXCOVERAGE = 1 FASTOCTREE = 2 LIBIMAGEQUANT = 3 -# categories -NORMAL = 0 -SEQUENCE = 1 -CONTAINER = 2 - if hasattr(core, "DEFAULT_STRATEGY"): DEFAULT_STRATEGY = core.DEFAULT_STRATEGY FILTERED = core.FILTERED @@ -213,28 +223,7 @@ DECODERS = {} ENCODERS = {} # -------------------------------------------------------------------- -# Modes supported by this version - -_MODEINFO = { - # NOTE: this table will be removed in future versions. use - # getmode* functions or ImageMode descriptors instead. - # official modes - "1": ("L", "L", ("1",)), - "L": ("L", "L", ("L",)), - "I": ("L", "I", ("I",)), - "F": ("L", "F", ("F",)), - "P": ("P", "L", ("P",)), - "RGB": ("RGB", "L", ("R", "G", "B")), - "RGBX": ("RGB", "L", ("R", "G", "B", "X")), - "RGBA": ("RGB", "L", ("R", "G", "B", "A")), - "CMYK": ("RGB", "L", ("C", "M", "Y", "K")), - "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")), - "LAB": ("RGB", "L", ("L", "A", "B")), - "HSV": ("RGB", "L", ("H", "S", "V")), - # Experimental modes include I;16, I;16L, I;16B, RGBa, BGR;15, and - # BGR;24. Use these modes only if you know exactly what you're - # doing... -} +# Modes if sys.byteorder == "little": _ENDIAN = "<" @@ -280,7 +269,7 @@ def _conv_type_shape(im): return (im.size[1], im.size[0], extra), typ -MODES = sorted(_MODEINFO) +MODES = ["1", "CMYK", "F", "HSV", "I", "L", "LAB", "P", "RGB", "RGBA", "RGBX", "YCbCr"] # raw modes that may be memory mapped. NOTE: if you change this, you # may have to modify the stride calculation in map.c too! @@ -535,11 +524,22 @@ class Image: self._size = (0, 0) self.palette = None self.info = {} - self.category = NORMAL + self._category = 0 self.readonly = 0 self.pyaccess = None self._exif = None + def __getattr__(self, name): + if name == "category": + warnings.warn( + "Image categories are deprecated and will be removed in Pillow 10 " + "(2023-01-02). Use is_animated instead.", + DeprecationWarning, + stacklevel=2, + ) + return self._category + raise AttributeError(name) + @property def width(self): return self.size[0] @@ -586,10 +586,10 @@ class Image: This operation will destroy the image core and release its memory. The image data will be unusable afterward. - This function is only required to close images that have not - had their file read and closed by the - :py:meth:`~PIL.Image.Image.load` method. See - :ref:`file-handling` for more information. + This function is required to close images that have multiple frames or + have not had their file read and closed by the + :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for + more information. """ try: if hasattr(self, "_close__fp"): @@ -648,7 +648,7 @@ class Image: and self.mode == other.mode and self.size == other.size and self.info == other.info - and self.category == other.category + and self._category == other._category and self.readonly == other.readonly and self.getpalette() == other.getpalette() and self.tobytes() == other.tobytes() @@ -676,9 +676,10 @@ class Image: raise ValueError("Could not save to PNG for display") from e return b.getvalue() - @property - def __array_interface__(self): + def __array__(self): # numpy array interface support + import numpy as np + new = {} shape, typestr = _conv_type_shape(self) new["shape"] = shape @@ -690,7 +691,11 @@ class Image: new["data"] = self.tobytes("raw", "L") else: new["data"] = self.tobytes() - return new + + class ArrayData: + __array_interface__ = new + + return np.array(ArrayData()) def __getstate__(self): return [self.info, self.mode, self.size, self.getpalette(), self.tobytes()] @@ -825,10 +830,10 @@ class Image: arr = bytes( value for (index, value) in enumerate(arr) if index % 4 != 3 ) - self.im.putpalette(mode, arr) + palette_length = self.im.putpalette(mode, arr) self.palette.dirty = 0 self.palette.rawmode = None - if "transparency" in self.info: + if "transparency" in self.info and mode in ("RGBA", "LA", "PA"): if isinstance(self.info["transparency"], int): self.im.putpalettealpha(self.info["transparency"], 0) else: @@ -836,6 +841,7 @@ class Image: self.palette.mode = "RGBA" else: self.palette.mode = "RGB" + self.palette.palette = self.im.getpalette()[: palette_length * 3] if self.im: if cffi and USE_CFFI_ACCESS: @@ -878,7 +884,7 @@ class Image: The default method of converting a greyscale ("L") or "RGB" image into a bilevel (mode "1") image uses Floyd-Steinberg dither to approximate the original image luminosity levels. If - dither is :data:`NONE`, all values larger than 128 are set to 255 (white), + dither is :data:`NONE`, all values larger than 127 are set to 255 (white), all other values to 0 (black). To use other thresholds, use the :py:meth:`~PIL.Image.Image.point` method. @@ -971,21 +977,28 @@ class Image: if self.mode == "P": trns_im.putpalette(self.palette) if isinstance(t, tuple): + err = "Couldn't allocate a palette color for transparency" try: - t = trns_im.palette.getcolor(t) - except Exception as e: - raise ValueError( - "Couldn't allocate a palette color for transparency" - ) from e - trns_im.putpixel((0, 0), t) - - if mode in ("L", "RGB"): - trns_im = trns_im.convert(mode) + t = trns_im.palette.getcolor(t, self) + except ValueError as e: + if str(e) == "cannot allocate more than 256 colors": + # If all 256 colors are in use, + # then there is no need for transparency + t = None + else: + raise ValueError(err) from e + if t is None: + trns = None else: - # can't just retrieve the palette number, got to do it - # after quantization. - trns_im = trns_im.convert("RGB") - trns = trns_im.getpixel((0, 0)) + trns_im.putpixel((0, 0), t) + + if mode in ("L", "RGB"): + trns_im = trns_im.convert(mode) + else: + # can't just retrieve the palette number, got to do it + # after quantization. + trns_im = trns_im.convert("RGB") + trns = trns_im.getpixel((0, 0)) elif self.mode == "P" and mode == "RGBA": t = self.info["transparency"] @@ -1003,14 +1016,14 @@ class Image: new = self._new(im) from . import ImagePalette - new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB")) + new.palette = ImagePalette.ImagePalette("RGB", new.im.getpalette("RGB")) if delete_trns: # This could possibly happen if we requantize to fewer colors. # The transparency would be totally off in that case. del new.info["transparency"] if trns is not None: try: - new.info["transparency"] = new.palette.getcolor(trns) + new.info["transparency"] = new.palette.getcolor(trns, new) except Exception: # if we can't make a transparent color, don't leave the old # transparency hanging around to mess us up. @@ -1033,16 +1046,25 @@ class Image: raise ValueError("illegal conversion") from e new_im = self._new(im) + if mode == "P" and palette != ADAPTIVE: + from . import ImagePalette + + new_im.palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3) if delete_trns: # crash fail if we leave a bytes transparency in an rgb/l mode. del new_im.info["transparency"] if trns is not None: if new_im.mode == "P": try: - new_im.info["transparency"] = new_im.palette.getcolor(trns) - except Exception: + new_im.info["transparency"] = new_im.palette.getcolor(trns, new_im) + except ValueError as e: del new_im.info["transparency"] - warnings.warn("Couldn't allocate palette entry for transparency") + if str(e) != "cannot allocate more than 256 colors": + # If all 256 colors are in use, + # then there is no need for transparency + warnings.warn( + "Couldn't allocate palette entry for transparency" + ) else: new_im.info["transparency"] = trns return new_im @@ -1059,6 +1081,12 @@ class Image: :data:`LIBIMAGEQUANT` (libimagequant; check support using :py:func:`PIL.features.check_feature` with ``feature="libimagequant"``). + + By default, :data:`MEDIANCUT` will be used. + + The exception to this is RGBA images. :data:`MEDIANCUT` and + :data:`MAXCOVERAGE` do not support RGBA images, so + :data:`FASTOCTREE` is used by default instead. :param kmeans: Integer :param palette: Quantize to the palette of given :py:class:`PIL.Image.Image`. @@ -1074,11 +1102,11 @@ class Image: if method is None: # defaults: - method = 0 + method = MEDIANCUT if self.mode == "RGBA": - method = 2 + method = FASTOCTREE - if self.mode == "RGBA" and method not in (2, 3): + if self.mode == "RGBA" and method not in (FASTOCTREE, LIBIMAGEQUANT): # Caller specified an invalid mode. raise ValueError( "Fast Octree (method == 2) and libimagequant (method == 3) " @@ -1243,6 +1271,10 @@ class Image: """ Returns a list of colors used in this image. + The colors will be in the image's mode. For example, an RGB image will + return a tuple of (red, green, blue) color values, and a P image will + return the index of the color in the palette. + :param maxcolors: Maximum number of colors. If this number is exceeded, this method returns None. The default limit is 256 colors. @@ -1302,30 +1334,62 @@ class Image: return tuple(extrema) return self.im.getextrema() + def _getxmp(self, xmp_tags): + def get_name(tag): + return tag.split("}")[1] + + def get_value(element): + value = {get_name(k): v for k, v in element.attrib.items()} + children = list(element) + if children: + for child in children: + name = get_name(child.tag) + child_value = get_value(child) + if name in value: + if not isinstance(value[name], list): + value[name] = [value[name]] + value[name].append(child_value) + else: + value[name] = child_value + elif value: + if element.text: + value["text"] = element.text + else: + return element.text + return value + + root = xml.etree.ElementTree.fromstring(xmp_tags) + return {get_name(root.tag): get_value(root)} + def getexif(self): if self._exif is None: self._exif = Exif() exif_info = self.info.get("exif") - if exif_info is None and "Raw profile type exif" in self.info: - exif_info = bytes.fromhex( - "".join(self.info["Raw profile type exif"].split("\n")[3:]) - ) - self._exif.load(exif_info) + if exif_info is None: + if "Raw profile type exif" in self.info: + exif_info = bytes.fromhex( + "".join(self.info["Raw profile type exif"].split("\n")[3:]) + ) + elif hasattr(self, "tag_v2"): + self._exif.endian = self.tag_v2._endian + self._exif.load_from_fp(self.fp, self.tag_v2._offset) + if exif_info is not None: + self._exif.load(exif_info) # XMP tags if 0x0112 not in self._exif: xmp_tags = self.info.get("XML:com.adobe.xmp") if xmp_tags: - root = xml.etree.ElementTree.fromstring(xmp_tags) - for elem in root.iter(): - if elem.tag.endswith("}Description"): - orientation = elem.attrib.get( - "{http://ns.adobe.com/tiff/1.0/}Orientation" - ) - if orientation: - self._exif[0x0112] = int(orientation) - break + xmp = self._getxmp(xmp_tags) + if ( + "xmpmeta" in xmp + and "RDF" in xmp["xmpmeta"] + and "Description" in xmp["xmpmeta"]["RDF"] + ): + description = xmp["xmpmeta"]["RDF"]["Description"] + if "Orientation" in description: + self._exif[0x0112] = int(description["Orientation"]) return self._exif @@ -1378,7 +1442,7 @@ class Image: self.load() x, y = self.im.getprojection() - return [i8(c) for c in x], [i8(c) for c in y] + return list(x), list(y) def histogram(self, mask=None, extrema=None): """ @@ -1540,8 +1604,6 @@ class Image: raise ValueError("Destination must be a 2-tuple") if min(source) < 0: raise ValueError("Source must be non-negative") - if min(dest) < 0: - raise ValueError("Destination must be non-negative") if len(source) == 2: source = source + im.size @@ -1686,7 +1748,7 @@ class Image: Attaches a palette to this image. The image must be a "P", "PA", "L" or "LA" image. - The palette sequence must contain either 768 integer values, or 1024 + The palette sequence must contain at most 768 integer values, or 1024 integer values if alpha is included. Each group of values represents the red, green, blue (and alpha if included) values for the corresponding pixel index. Instead of an integer sequence, you can use @@ -1699,7 +1761,6 @@ class Image: if self.mode not in ("L", "LA", "P", "PA"): raise ValueError("illegal image mode") - self.load() if isinstance(data, ImagePalette.ImagePalette): palette = ImagePalette.raw(data.rawmode, data.palette) else: @@ -1746,7 +1807,7 @@ class Image: and len(value) in [3, 4] ): # RGB or RGBA value for a P image - value = self.palette.getcolor(value) + value = self.palette.getcolor(value, self) return self.im.putpixel(xy, value) def remap_palette(self, dest_map, source_palette=None): @@ -1767,6 +1828,7 @@ class Image: if source_palette is None: if self.mode == "P": + self.load() real_source_palette = self.im.getpalette("RGB")[:768] else: # L-mode real_source_palette = bytearray(i // 3 for i in range(768)) @@ -1804,23 +1866,19 @@ class Image: m_im = self.copy() m_im.mode = "P" - m_im.palette = ImagePalette.ImagePalette( - "RGB", palette=mapping_palette * 3, size=768 - ) + m_im.palette = ImagePalette.ImagePalette("RGB", palette=mapping_palette * 3) # possibly set palette dirty, then # m_im.putpalette(mapping_palette, 'L') # converts to 'P' # or just force it. # UNDONE -- this is part of the general issue with palettes - m_im.im.putpalette(*m_im.palette.getdata()) + m_im.im.putpalette("RGB;L", m_im.palette.tobytes()) m_im = m_im.convert("L") # Internally, we require 768 bytes for a palette. new_palette_bytes = palette_bytes + (768 - len(palette_bytes)) * b"\x00" m_im.putpalette(new_palette_bytes) - m_im.palette = ImagePalette.ImagePalette( - "RGB", palette=palette_bytes, size=len(palette_bytes) - ) + m_im.palette = ImagePalette.ImagePalette("RGB", palette=palette_bytes) return m_im @@ -1841,7 +1899,7 @@ class Image: min(self.size[1], math.ceil(box[3] + support_y)), ) - def resize(self, size, resample=BICUBIC, box=None, reducing_gap=None): + def resize(self, size, resample=None, box=None, reducing_gap=None): """ Returns a resized copy of this image. @@ -1851,9 +1909,11 @@ class Image: one of :py:data:`PIL.Image.NEAREST`, :py:data:`PIL.Image.BOX`, :py:data:`PIL.Image.BILINEAR`, :py:data:`PIL.Image.HAMMING`, :py:data:`PIL.Image.BICUBIC` or :py:data:`PIL.Image.LANCZOS`. - Default filter is :py:data:`PIL.Image.BICUBIC`. - If the image has mode "1" or "P", it is - always set to :py:data:`PIL.Image.NEAREST`. + If the image has mode "1" or "P", it is always set to + :py:data:`PIL.Image.NEAREST`. + If the image mode specifies a number of bits, such as "I;16", then the + default filter is :py:data:`PIL.Image.NEAREST`. + Otherwise, the default filter is :py:data:`PIL.Image.BICUBIC`. See: :ref:`concept-filters`. :param box: An optional 4-tuple of floats providing the source image region to be scaled. @@ -1874,7 +1934,10 @@ class Image: :returns: An :py:class:`~PIL.Image.Image` object. """ - if resample not in (NEAREST, BILINEAR, BICUBIC, LANCZOS, BOX, HAMMING): + if resample is None: + type_special = ";" in self.mode + resample = NEAREST if type_special else BICUBIC + elif resample not in (NEAREST, BILINEAR, BICUBIC, LANCZOS, BOX, HAMMING): message = f"Unknown resampling filter ({resample})." filters = [ @@ -1908,7 +1971,7 @@ class Image: if self.mode in ("1", "P"): resample = NEAREST - if self.mode in ["LA", "RGBA"]: + if self.mode in ["LA", "RGBA"] and resample != NEAREST: im = self.convert(self.mode[:-1] + "a") im = im.resize(size, resample, box) return im.convert(self.mode) @@ -2122,6 +2185,11 @@ class Image: elif isinstance(fp, Path): filename = str(fp) open_fp = True + elif fp == sys.stdout: + try: + fp = sys.stdout.buffer + except AttributeError: + pass if not filename and hasattr(fp, "name") and isPath(fp.name): # only set the name for metadata purposes filename = fp.name @@ -2392,14 +2460,14 @@ class Image: :returns: An :py:class:`~PIL.Image.Image` object. """ - if self.mode == "LA": + if self.mode == "LA" and resample != NEAREST: return ( self.convert("La") .transform(size, method, data, resample, fill, fillcolor) .convert("LA") ) - if self.mode == "RGBA": + if self.mode == "RGBA" and resample != NEAREST: return ( self.convert("RGBa") .transform(size, method, data, resample, fill, fillcolor) @@ -2869,7 +2937,7 @@ def open(fp, mode="r", formats=None): :param formats: A list or tuple of formats to attempt to load the file in. This can be used to restrict the set of formats checked. Pass ``None`` to try all supported formats. You can print the set of - available formats by running ``python -m PIL`` or using + available formats by running ``python3 -m PIL`` or using the :py:func:`PIL.features.pilinfo` function. :returns: An :py:class:`~PIL.Image.Image` object. :exception FileNotFoundError: If the file cannot be found. @@ -2918,6 +2986,7 @@ def open(fp, mode="r", formats=None): def _open_core(fp, filename, prefix, formats): for i in formats: + i = i.upper() if i not in OPEN: init() try: @@ -3283,7 +3352,7 @@ atexit.register(core.clear_cache) class Exif(MutableMapping): - endian = "<" + endian = None def __init__(self): self._data = {} @@ -3304,11 +3373,11 @@ class Exif(MutableMapping): # returns a dict with any single item tuples/lists as individual values return {k: self._fixup(v) for k, v in src_dict.items()} - def _get_ifd_dict(self, tag): + def _get_ifd_dict(self, offset): try: # an offset pointer to the location of the nested embedded IFD. # It should be a long, but may be corrupted. - self.fp.seek(self[tag]) + self.fp.seek(offset) except (KeyError, TypeError): pass else: @@ -3318,6 +3387,12 @@ class Exif(MutableMapping): info.load(self.fp) return self._fixup_dict(info) + def _get_head(self): + if self.endian == "<": + return b"II\x2A\x00\x08\x00\x00\x00" + else: + return b"MM\x00\x2A\x00\x00\x00\x08" + def load(self, data): # Extract EXIF information. This is highly experimental, # and is likely to be replaced with something better in a future @@ -3330,8 +3405,8 @@ class Exif(MutableMapping): self._loaded_exif = data self._data.clear() self._ifds.clear() - self._info = None if not data: + self._info = None return if data.startswith(b"Exif\x00\x00"): @@ -3346,106 +3421,150 @@ class Exif(MutableMapping): self.fp.seek(self._info.next) self._info.load(self.fp) + def load_from_fp(self, fp, offset=None): + self._loaded_exif = None + self._data.clear() + self._ifds.clear() + + # process dictionary + from . import TiffImagePlugin + + self.fp = fp + if offset is not None: + self.head = self._get_head() + else: + self.head = self.fp.read(8) + self._info = TiffImagePlugin.ImageFileDirectory_v2(self.head) + if self.endian is None: + self.endian = self._info._endian + if offset is None: + offset = self._info.next + self.fp.seek(offset) + self._info.load(self.fp) + + def _get_merged_dict(self): + merged_dict = dict(self) + # get EXIF extension - ifd = self._get_ifd_dict(0x8769) - if ifd: - self._data.update(ifd) - self._ifds[0x8769] = ifd + if 0x8769 in self: + ifd = self._get_ifd_dict(self[0x8769]) + if ifd: + merged_dict.update(ifd) + + # GPS + if 0x8825 in self: + merged_dict[0x8825] = self._get_ifd_dict(self[0x8825]) + + return merged_dict def tobytes(self, offset=8): from . import TiffImagePlugin - if self.endian == "<": - head = b"II\x2A\x00\x08\x00\x00\x00" - else: - head = b"MM\x00\x2A\x00\x00\x00\x08" + head = self._get_head() ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) for tag, value in self.items(): + if tag in [0x8769, 0x8225, 0x8825] and not isinstance(value, dict): + value = self.get_ifd(tag) + if ( + tag == 0x8769 + and 0xA005 in value + and not isinstance(value[0xA005], dict) + ): + value = value.copy() + value[0xA005] = self.get_ifd(0xA005) ifd[tag] = value return b"Exif\x00\x00" + head + ifd.tobytes(offset) def get_ifd(self, tag): - if tag not in self._ifds and tag in self: - if tag in [0x8825, 0xA005]: - # gpsinfo, interop - self._ifds[tag] = self._get_ifd_dict(tag) - elif tag == 0x927C: # makernote - from .TiffImagePlugin import ImageFileDirectory_v2 + if tag not in self._ifds: + if tag in [0x8769, 0x8825]: + # exif, gpsinfo + if tag in self: + self._ifds[tag] = self._get_ifd_dict(self[tag]) + elif tag in [0xA005, 0x927C]: + # interop, makernote + if 0x8769 not in self._ifds: + self.get_ifd(0x8769) + tag_data = self._ifds[0x8769][tag] + if tag == 0x927C: + # makernote + from .TiffImagePlugin import ImageFileDirectory_v2 - if self[0x927C][:8] == b"FUJIFILM": - exif_data = self[0x927C] - ifd_offset = i32le(exif_data[8:12]) - ifd_data = exif_data[ifd_offset:] + if tag_data[:8] == b"FUJIFILM": + ifd_offset = i32le(tag_data, 8) + ifd_data = tag_data[ifd_offset:] - makernote = {} - for i in range(0, struct.unpack(" 4: - (offset,) = struct.unpack(" 4: + (offset,) = struct.unpack("H", ifd_data[:2])[0]): - ifd_tag, typ, count, data = struct.unpack( - ">HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2] - ) - if ifd_tag == 0x1101: - # CameraInfo - (offset,) = struct.unpack(">L", data) - self.fp.seek(offset) - - camerainfo = {"ModelID": self.fp.read(4)} - - self.fp.read(4) - # Seconds since 2000 - camerainfo["TimeStamp"] = i32le(self.fp.read(12)) - - self.fp.read(4) - camerainfo["InternalSerialNumber"] = self.fp.read(4) - - self.fp.read(12) - parallax = self.fp.read(4) - handler = ImageFileDirectory_v2._load_dispatch[ - TiffTags.FLOAT - ][1] - camerainfo["Parallax"] = handler( - ImageFileDirectory_v2(), parallax, False + makernote[ifd_tag] = handler( + ImageFileDirectory_v2(), data, False ) + self._ifds[tag] = dict(self._fixup_dict(makernote)) + elif self.get(0x010F) == "Nintendo": + makernote = {} + for i in range(0, struct.unpack(">H", tag_data[:2])[0]): + ifd_tag, typ, count, data = struct.unpack( + ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] + ) + if ifd_tag == 0x1101: + # CameraInfo + (offset,) = struct.unpack(">L", data) + self.fp.seek(offset) - self.fp.read(4) - camerainfo["Category"] = self.fp.read(2) + camerainfo = {"ModelID": self.fp.read(4)} - makernote = {0x1101: dict(self._fixup_dict(camerainfo))} - self._ifds[0x927C] = makernote + self.fp.read(4) + # Seconds since 2000 + camerainfo["TimeStamp"] = i32le(self.fp.read(12)) + + self.fp.read(4) + camerainfo["InternalSerialNumber"] = self.fp.read(4) + + self.fp.read(12) + parallax = self.fp.read(4) + handler = ImageFileDirectory_v2._load_dispatch[ + TiffTags.FLOAT + ][1] + camerainfo["Parallax"] = handler( + ImageFileDirectory_v2(), parallax, False + ) + + self.fp.read(4) + camerainfo["Category"] = self.fp.read(2) + + makernote = {0x1101: dict(self._fixup_dict(camerainfo))} + self._ifds[tag] = makernote + else: + # interop + self._ifds[tag] = self._get_ifd_dict(tag_data) return self._ifds.get(tag, {}) def __str__(self): @@ -3465,8 +3584,6 @@ class Exif(MutableMapping): def __getitem__(self, tag): if self._info is not None and tag not in self._data and tag in self._info: self._data[tag] = self._fixup(self._info[tag]) - if tag == 0x8825: - self._data[tag] = self.get_ifd(tag) del self._info[tag] return self._data[tag] diff --git a/src/PIL/ImageColor.py b/src/PIL/ImageColor.py index 909117449..51df44040 100644 --- a/src/PIL/ImageColor.py +++ b/src/PIL/ImageColor.py @@ -24,8 +24,8 @@ from . import Image def getrgb(color): """ - Convert a color string to an RGB tuple. If the string cannot be parsed, - this function raises a :py:exc:`ValueError` exception. + Convert a color string to an RGB or RGBA tuple. If the string cannot be + parsed, this function raises a :py:exc:`ValueError` exception. .. versionadded:: 1.1.4 diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index b823be9a2..aea0cc680 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -33,7 +33,7 @@ import math import numbers -from . import Image, ImageColor +from . import Image, ImageColor, ImageFont """ A simple 2D drawing interface for PIL images. @@ -70,6 +70,7 @@ class ImageDraw: self.palette = im.palette else: self.palette = None + self._image = im self.im = im.im self.draw = Image.core.draw(self.im, blend) self.mode = mode @@ -108,13 +109,13 @@ class ImageDraw: if isinstance(ink, str): ink = ImageColor.getcolor(ink, self.mode) if self.palette and not isinstance(ink, numbers.Number): - ink = self.palette.getcolor(ink) + ink = self.palette.getcolor(ink, self._image) ink = self.draw.draw_ink(ink) if fill is not None: if isinstance(fill, str): fill = ImageColor.getcolor(fill, self.mode) if self.palette and not isinstance(fill, numbers.Number): - fill = self.palette.getcolor(fill) + fill = self.palette.getcolor(fill, self._image) fill = self.draw.draw_ink(fill) return ink, fill @@ -257,6 +258,89 @@ class ImageDraw: if ink is not None and ink != fill and width != 0: self.draw.draw_rectangle(xy, ink, 0, width) + def rounded_rectangle(self, xy, radius=0, fill=None, outline=None, width=1): + """Draw a rounded rectangle.""" + if isinstance(xy[0], (list, tuple)): + (x0, y0), (x1, y1) = xy + else: + x0, y0, x1, y1 = xy + + d = radius * 2 + + full_x = d >= x1 - x0 + if full_x: + # The two left and two right corners are joined + d = x1 - x0 + full_y = d >= y1 - y0 + if full_y: + # The two top and two bottom corners are joined + d = y1 - y0 + if full_x and full_y: + # If all corners are joined, that is a circle + return self.ellipse(xy, fill, outline, width) + + if d == 0: + # If the corners have no curve, that is a rectangle + return self.rectangle(xy, fill, outline, width) + + r = d // 2 + ink, fill = self._getink(outline, fill) + + def draw_corners(pieslice): + if full_x: + # Draw top and bottom halves + parts = ( + ((x0, y0, x0 + d, y0 + d), 180, 360), + ((x0, y1 - d, x0 + d, y1), 0, 180), + ) + elif full_y: + # Draw left and right halves + parts = ( + ((x0, y0, x0 + d, y0 + d), 90, 270), + ((x1 - d, y0, x1, y0 + d), 270, 90), + ) + else: + # Draw four separate corners + parts = ( + ((x1 - d, y0, x1, y0 + d), 270, 360), + ((x1 - d, y1 - d, x1, y1), 0, 90), + ((x0, y1 - d, x0 + d, y1), 90, 180), + ((x0, y0, x0 + d, y0 + d), 180, 270), + ) + for part in parts: + if pieslice: + self.draw.draw_pieslice(*(part + (fill, 1))) + else: + self.draw.draw_arc(*(part + (ink, width))) + + if fill is not None: + draw_corners(True) + + if full_x: + self.draw.draw_rectangle((x0, y0 + r + 1, x1, y1 - r - 1), fill, 1) + else: + self.draw.draw_rectangle((x0 + r + 1, y0, x1 - r - 1, y1), fill, 1) + if not full_x and not full_y: + self.draw.draw_rectangle((x0, y0 + r + 1, x0 + r, y1 - r - 1), fill, 1) + self.draw.draw_rectangle((x1 - r, y0 + r + 1, x1, y1 - r - 1), fill, 1) + if ink is not None and ink != fill and width != 0: + draw_corners(False) + + if not full_x: + self.draw.draw_rectangle( + (x0 + r + 1, y0, x1 - r - 1, y0 + width - 1), ink, 1 + ) + self.draw.draw_rectangle( + (x0 + r + 1, y1 - width + 1, x1 - r - 1, y1), ink, 1 + ) + if not full_y: + self.draw.draw_rectangle( + (x0, y0 + r + 1, x0 + width - 1, y1 - r - 1), ink, 1 + ) + self.draw.draw_rectangle( + (x1 - width + 1, y0 + r + 1, x1, y1 - r - 1), ink, 1 + ) + def _multiline_check(self, text): """Draw text.""" split_character = "\n" if isinstance(text, str) else b"\n" @@ -563,6 +647,8 @@ class ImageDraw: if font is None: font = self.getfont() + if not isinstance(font, ImageFont.FreeTypeFont): + raise ValueError("Only supported for TrueType fonts") mode = "RGBA" if embedded_color else self.fontmode bbox = font.getbbox( text, mode, direction, features, language, stroke_width, anchor diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index f2a55cb54..daf732de1 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -192,24 +192,14 @@ class ImageFile(Image.Image): and args[0] in Image._MAPMODES ): try: - if hasattr(Image.core, "map"): - # use built-in mapper WIN32 only - self.map = Image.core.map(self.filename) - self.map.seek(offset) - self.im = self.map.readimage( - self.mode, self.size, args[1], args[2] - ) - else: - # use mmap, if possible - import mmap + # use mmap, if possible + import mmap - with open(self.filename) as fp: - self.map = mmap.mmap( - fp.fileno(), 0, access=mmap.ACCESS_READ - ) - self.im = Image.core.map_buffer( - self.map, self.size, decoder_name, offset, args - ) + with open(self.filename) as fp: + self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) + self.im = Image.core.map_buffer( + self.map, self.size, decoder_name, offset, args + ) readonly = 1 # After trashing self.im, # we might need to reload the palette data. @@ -503,7 +493,7 @@ def _save(im, fp, tile, bufsize=0): # But, it would need at least the image size in most cases. RawEncode is # a tricky case. bufsize = max(MAXBLOCK, bufsize, im.size[0] * 4) # see RawEncode.c - if fp == sys.stdout: + if fp == sys.stdout or (hasattr(sys.stdout, "buffer") and fp == sys.stdout.buffer): fp.flush() return try: @@ -555,12 +545,18 @@ def _safe_read(fp, size): :param fp: File handle. Must implement a read method. :param size: Number of bytes to read. - :returns: A string containing up to size bytes of data. + :returns: A string containing size bytes of data. + + Raises an OSError if the file is truncated and the read cannot be completed + """ if size <= 0: return b"" if size <= SAFEBLOCK: - return fp.read(size) + data = fp.read(size) + if len(data) < size: + raise OSError("Truncated File Read") + return data data = [] while size > 0: block = fp.read(min(size, SAFEBLOCK)) @@ -568,6 +564,8 @@ def _safe_read(fp, size): break data.append(block) size -= len(block) + if sum(len(d) for d in data) < size: + raise OSError("Truncated File Read") return b"".join(data) diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index 9ca17d9ad..d2ece3752 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -16,11 +16,6 @@ # import functools -try: - import numpy -except ImportError: # pragma: no cover - numpy = None - class Filter: pass @@ -154,9 +149,11 @@ class ModeFilter(Filter): class GaussianBlur(MultibandFilter): - """Gaussian blur filter. + """Blurs the image with a sequence of extended box filters, which + approximates a Gaussian kernel. For details on accuracy see + - :param radius: Blur radius. + :param radius: Standard deviation of the Gaussian kernel. """ name = "GaussianBlur" @@ -369,6 +366,13 @@ class Color3DLUT(MultibandFilter): items = size[0] * size[1] * size[2] wrong_size = False + numpy = None + if hasattr(table, "shape"): + try: + import numpy + except ImportError: # pragma: no cover + pass + if numpy and isinstance(table, numpy.ndarray): if copy_table: table = table.copy() diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index c48d89835..e99ca21b2 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -170,8 +170,10 @@ class FreeTypeFont: except ImportError: pass else: - freetype_version = parse_version(features.version_module("freetype2")) - if freetype_version < parse_version("2.8"): + freetype_version = features.version_module("freetype2") + if freetype_version is not None and parse_version( + freetype_version + ) < parse_version("2.8"): warnings.warn( "Support for FreeType 2.7 is deprecated and will be removed" " in Pillow 9 (2022-01-02). Please upgrade to FreeType 2.8 " @@ -669,6 +671,7 @@ class FreeTypeFont: ) size = size[0] + stroke_width * 2, size[1] + stroke_width * 2 offset = offset[0] - stroke_width, offset[1] - stroke_width + Image._decompression_bomb_check(size) im = fill("RGBA" if mode == "RGBA" else "L", size, 0) self.font.render( text, im.id, mode, direction, features, language, stroke_width, ink diff --git a/src/PIL/ImageMode.py b/src/PIL/ImageMode.py index 988288329..0afcf9fe1 100644 --- a/src/PIL/ImageMode.py +++ b/src/PIL/ImageMode.py @@ -35,18 +35,28 @@ def getmode(mode): global _modes if not _modes: # initialize mode cache - - from . import Image - modes = {} - # core modes - for m, (basemode, basetype, bands) in Image._MODEINFO.items(): + for m, (basemode, basetype, bands) in { + # core modes + "1": ("L", "L", ("1",)), + "L": ("L", "L", ("L",)), + "I": ("L", "I", ("I",)), + "F": ("L", "F", ("F",)), + "P": ("P", "L", ("P",)), + "RGB": ("RGB", "L", ("R", "G", "B")), + "RGBX": ("RGB", "L", ("R", "G", "B", "X")), + "RGBA": ("RGB", "L", ("R", "G", "B", "A")), + "CMYK": ("RGB", "L", ("C", "M", "Y", "K")), + "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")), + "LAB": ("RGB", "L", ("L", "A", "B")), + "HSV": ("RGB", "L", ("H", "S", "V")), + # extra experimental modes + "RGBa": ("RGB", "L", ("R", "G", "B", "a")), + "LA": ("L", "L", ("L", "A")), + "La": ("L", "L", ("L", "a")), + "PA": ("RGB", "L", ("P", "A")), + }.items(): modes[m] = ModeDescriptor(m, bands, basemode, basetype) - # extra experimental modes - modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L") - modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L") - modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L") - modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L") # mapping modes for i16mode in ( "I;16", diff --git a/src/PIL/ImageMorph.py b/src/PIL/ImageMorph.py index b76dfa01f..fe0083754 100644 --- a/src/PIL/ImageMorph.py +++ b/src/PIL/ImageMorph.py @@ -196,7 +196,7 @@ class MorphOp: raise Exception("No operator loaded") if image.mode != "L": - raise Exception("Image must be binary, meaning it must use mode L") + raise ValueError("Image mode must be L") outimage = Image.new(image.mode, image.size, None) count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id) return count, outimage @@ -211,7 +211,7 @@ class MorphOp: raise Exception("No operator loaded") if image.mode != "L": - raise Exception("Image must be binary, meaning it must use mode L") + raise ValueError("Image mode must be L") return _imagingmorph.match(bytes(self.lut), image.im.id) def get_on_pixels(self, image): @@ -221,7 +221,7 @@ class MorphOp: of all matching pixels. See :ref:`coordinate-system`.""" if image.mode != "L": - raise Exception("Image must be binary, meaning it must use mode L") + raise ValueError("Image mode must be L") return _imagingmorph.get_on_pixels(image.im.id) def load_lut(self, filename): diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 14602a5c8..98be4bb91 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -20,7 +20,7 @@ import functools import operator -from . import Image +from . import Image, ImageDraw # # helpers @@ -61,7 +61,7 @@ def _lut(image, lut): # actions -def autocontrast(image, cutoff=0, ignore=None, mask=None): +def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False): """ Maximize (normalize) image contrast. This function calculates a histogram of the input image (or mask region), removes ``cutoff`` percent of the @@ -77,9 +77,17 @@ def autocontrast(image, cutoff=0, ignore=None, mask=None): :param mask: Histogram used in contrast operation is computed using pixels within the mask. If no mask is given the entire image is used for histogram computation. + :param preserve_tone: Preserve image tone in Photoshop-like style autocontrast. + + .. versionadded:: 8.2.0 + :return: An image. """ - histogram = image.histogram(mask) + if preserve_tone: + histogram = image.convert("L").histogram(mask) + else: + histogram = image.histogram(mask) + lut = [] for layer in range(0, len(histogram), 256): h = histogram[layer : layer + 256] @@ -228,15 +236,43 @@ def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoi return _lut(image, red + green + blue) -def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)): +def contain(image, size, method=Image.BICUBIC): """ - Returns a sized and padded version of the image, expanded to fill the - requested aspect ratio and size. + Returns a resized version of the image, set to the maximum width and height + within the requested size, while maintaining the original aspect ratio. - :param image: The image to size and crop. + :param image: The image to resize and crop. :param size: The requested output size in pixels, given as a (width, height) tuple. - :param method: What resampling method to use. Default is + :param method: Resampling method to use. Default is + :py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`. + :return: An image. + """ + + im_ratio = image.width / image.height + dest_ratio = size[0] / size[1] + + if im_ratio != dest_ratio: + if im_ratio > dest_ratio: + new_height = int(image.height / image.width * size[0]) + if new_height != size[1]: + size = (size[0], new_height) + else: + new_width = int(image.width / image.height * size[1]) + if new_width != size[0]: + size = (new_width, size[1]) + return image.resize(size, resample=method) + + +def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)): + """ + Returns a resized and padded version of the image, expanded to fill the + requested aspect ratio and size. + + :param image: The image to resize and crop. + :param size: The requested output size in pixels, given as a + (width, height) tuple. + :param method: Resampling method to use. Default is :py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`. :param color: The background color of the padded image. :param centering: Control the position of the original image within the @@ -249,27 +285,17 @@ def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)): :return: An image. """ - im_ratio = image.width / image.height - dest_ratio = size[0] / size[1] - - if im_ratio == dest_ratio: - out = image.resize(size, resample=method) + resized = contain(image, size, method) + if resized.size == size: + out = resized else: out = Image.new(image.mode, size, color) - if im_ratio > dest_ratio: - new_height = int(image.height / image.width * size[0]) - if new_height != size[1]: - image = image.resize((size[0], new_height), resample=method) - - y = int((size[1] - new_height) * max(0, min(centering[1], 1))) - out.paste(image, (0, y)) + if resized.width != size[0]: + x = int((size[0] - resized.width) * max(0, min(centering[0], 1))) + out.paste(resized, (x, 0)) else: - new_width = int(image.width / image.height * size[1]) - if new_width != size[0]: - image = image.resize((new_width, size[1]), resample=method) - - x = int((size[0] - new_width) * max(0, min(centering[0], 1))) - out.paste(image, (x, 0)) + y = int((size[1] - resized.height) * max(0, min(centering[1], 1))) + out.paste(resized, (0, y)) return out @@ -296,7 +322,7 @@ def scale(image, factor, resample=Image.BICUBIC): :param image: The image to rescale. :param factor: The expansion factor, as a float. - :param resample: What resampling method to use. Default is + :param resample: Resampling method to use. Default is :py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`. :returns: An :py:class:`~PIL.Image.Image` object. """ @@ -366,22 +392,31 @@ def expand(image, border=0, fill=0): left, top, right, bottom = _border(border) width = left + image.size[0] + right height = top + image.size[1] + bottom - out = Image.new(image.mode, (width, height), _color(fill, image.mode)) - out.paste(image, (left, top)) + color = _color(fill, image.mode) + if image.mode == "P" and image.palette: + out = Image.new(image.mode, (width, height)) + out.putpalette(image.palette) + out.paste(image, (left, top)) + + draw = ImageDraw.Draw(out) + draw.rectangle((0, 0, width, height), outline=color, width=border) + else: + out = Image.new(image.mode, (width, height), color) + out.paste(image, (left, top)) return out def fit(image, size, method=Image.BICUBIC, bleed=0.0, centering=(0.5, 0.5)): """ - Returns a sized and cropped version of the image, cropped to the + Returns a resized and cropped version of the image, cropped to the requested aspect ratio and size. This function was contributed by Kevin Cazabon. - :param image: The image to size and crop. + :param image: The image to resize and crop. :param size: The requested output size in pixels, given as a (width, height) tuple. - :param method: What resampling method to use. Default is + :param method: Resampling method to use. Default is :py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`. :param bleed: Remove a border around the outside of the image from all four edges. The value is a decimal percentage (use 0.01 for @@ -552,7 +587,8 @@ def exif_transpose(image): }.get(orientation) if method is not None: transposed_image = image.transpose(method) - del exif[0x0112] - transposed_image.info["exif"] = exif.tobytes() + transposed_exif = transposed_image.getexif() + del transposed_exif[0x0112] + transposed_image.info["exif"] = transposed_exif.tobytes() return transposed_image return image.copy() diff --git a/src/PIL/ImagePalette.py b/src/PIL/ImagePalette.py index d0604112f..76c4c46d5 100644 --- a/src/PIL/ImagePalette.py +++ b/src/PIL/ImagePalette.py @@ -39,14 +39,27 @@ class ImagePalette: def __init__(self, mode="RGB", palette=None, size=0): self.mode = mode self.rawmode = None # if set, palette contains raw data - self.palette = palette or bytearray(range(256)) * len(self.mode) - self.colors = {} + self.palette = palette or bytearray() self.dirty = None - if (size == 0 and len(self.mode) * 256 != len(self.palette)) or ( - size != 0 and size != len(self.palette) - ): + if size != 0 and size != len(self.palette): raise ValueError("wrong palette size") + @property + def palette(self): + return self._palette + + @palette.setter + def palette(self, palette): + self._palette = palette + + mode_len = len(self.mode) + self.colors = {} + for i in range(0, len(self.palette), mode_len): + color = tuple(self.palette[i : i + mode_len]) + if color in self.colors: + continue + self.colors[color] = i // mode_len + def copy(self): new = ImagePalette() @@ -54,7 +67,6 @@ class ImagePalette: new.rawmode = self.rawmode if self.palette is not None: new.palette = self.palette[:] - new.colors = self.colors.copy() new.dirty = self.dirty return new @@ -68,7 +80,7 @@ class ImagePalette: """ if self.rawmode: return self.rawmode, self.palette - return self.mode + ";L", self.tobytes() + return self.mode, self.tobytes() def tobytes(self): """Convert palette to bytes. @@ -80,14 +92,12 @@ class ImagePalette: if isinstance(self.palette, bytes): return self.palette arr = array.array("B", self.palette) - if hasattr(arr, "tobytes"): - return arr.tobytes() - return arr.tostring() + return arr.tobytes() # Declare tostring as an alias for tobytes tostring = tobytes - def getcolor(self, color): + def getcolor(self, color, image=None): """Given an rgb tuple, allocate palette entry. .. warning:: This method is experimental. @@ -95,19 +105,37 @@ class ImagePalette: if self.rawmode: raise ValueError("palette contains raw palette data") if isinstance(color, tuple): + if self.mode == "RGB": + if len(color) == 4 and color[3] == 255: + color = color[:3] + elif self.mode == "RGBA": + if len(color) == 3: + color += (255,) try: return self.colors[color] except KeyError as e: # allocate new color slot - if isinstance(self.palette, bytes): - self.palette = bytearray(self.palette) - index = len(self.colors) + if not isinstance(self.palette, bytearray): + self._palette = bytearray(self.palette) + index = len(self.palette) // 3 if index >= 256: - raise ValueError("cannot allocate more than 256 colors") from e + if image: + # Search for an unused index + for i, count in reversed(list(enumerate(image.histogram()))): + if count == 0: + index = i + break + if index >= 256: + raise ValueError("cannot allocate more than 256 colors") from e self.colors[color] = index - self.palette[index] = color[0] - self.palette[index + 256] = color[1] - self.palette[index + 512] = color[2] + if index * 3 < len(self.palette): + self._palette = ( + self.palette[: index * 3] + + bytes(color) + + self.palette[index * 3 + 3 :] + ) + else: + self._palette += bytes(color) self.dirty = 1 return index else: diff --git a/src/PIL/ImageQt.py b/src/PIL/ImageQt.py index 91be53488..32630f2ca 100644 --- a/src/PIL/ImageQt.py +++ b/src/PIL/ImageQt.py @@ -22,13 +22,24 @@ from io import BytesIO from . import Image from ._util import isPath -qt_versions = [["5", "PyQt5"], ["side2", "PySide2"]] +qt_versions = [ + ["6", "PyQt6"], + ["side6", "PySide6"], + ["5", "PyQt5"], + ["side2", "PySide2"], +] # If a version has already been imported, attempt it first qt_versions.sort(key=lambda qt_version: qt_version[1] in sys.modules, reverse=True) for qt_version, qt_module in qt_versions: try: - if qt_module == "PyQt5": + if qt_module == "PyQt6": + from PyQt6.QtCore import QBuffer, QIODevice + from PyQt6.QtGui import QImage, QPixmap, qRgba + elif qt_module == "PySide6": + from PySide6.QtCore import QBuffer, QIODevice + from PySide6.QtGui import QImage, QPixmap, qRgba + elif qt_module == "PyQt5": from PyQt5.QtCore import QBuffer, QIODevice from PyQt5.QtGui import QImage, QPixmap, qRgba elif qt_module == "PySide2": @@ -52,11 +63,11 @@ def rgb(r, g, b, a=255): def fromqimage(im): """ - :param im: A PIL Image object, or a file name - (given either as Python string or a PyQt string object) + :param im: QImage or PIL ImageQt object """ buffer = QBuffer() - buffer.open(QIODevice.ReadWrite) + qt_openmode = QIODevice.OpenMode if qt_version == "6" else QIODevice + buffer.open(qt_openmode.ReadWrite) # preserve alpha channel with png # otherwise ppm is more friendly with Image.open if im.hasAlphaChannel(): @@ -117,6 +128,7 @@ def align8to32(bytes, width, mode): def _toqclass_helper(im): data = None colortable = None + exclusive_fp = False # handle filename, if given instead of image name if hasattr(im, "toUtf8"): @@ -124,31 +136,41 @@ def _toqclass_helper(im): im = str(im.toUtf8(), "utf-8") if isPath(im): im = Image.open(im) + exclusive_fp = True + qt_format = QImage.Format if qt_version == "6" else QImage if im.mode == "1": - format = QImage.Format_Mono + format = qt_format.Format_Mono elif im.mode == "L": - format = QImage.Format_Indexed8 + format = qt_format.Format_Indexed8 colortable = [] for i in range(256): colortable.append(rgb(i, i, i)) elif im.mode == "P": - format = QImage.Format_Indexed8 + format = qt_format.Format_Indexed8 colortable = [] palette = im.getpalette() for i in range(0, len(palette), 3): colortable.append(rgb(*palette[i : i + 3])) elif im.mode == "RGB": - data = im.tobytes("raw", "BGRX") - format = QImage.Format_RGB32 + # Populate the 4th channel with 255 + im = im.convert("RGBA") + + data = im.tobytes("raw", "BGRA") + format = qt_format.Format_RGB32 elif im.mode == "RGBA": data = im.tobytes("raw", "BGRA") - format = QImage.Format_ARGB32 + format = qt_format.Format_ARGB32 else: + if exclusive_fp: + im.close() raise ValueError(f"unsupported image mode {repr(im.mode)}") - __data = data or align8to32(im.tobytes(), im.size[0], im.mode) - return {"data": __data, "im": im, "format": format, "colortable": colortable} + size = im.size + __data = data or align8to32(im.tobytes(), size[0], im.mode) + if exclusive_fp: + im.close() + return {"data": __data, "size": size, "format": format, "colortable": colortable} if qt_is_installed: @@ -170,8 +192,8 @@ if qt_is_installed: self.__data = im_data["data"] super().__init__( self.__data, - im_data["im"].size[0], - im_data["im"].size[1], + im_data["size"][0], + im_data["size"][1], im_data["format"], ) if im_data["colortable"]: @@ -185,11 +207,7 @@ def toqimage(im): def toqpixmap(im): # # This doesn't work. For now using a dumb approach. # im_data = _toqclass_helper(im) - # result = QPixmap(im_data['im'].size[0], im_data['im'].size[1]) - # result.loadFromData(im_data['data']) - # Fix some strange bug that causes - if im.mode == "RGB": - im = im.convert("RGBA") - + # result = QPixmap(im_data["size"][0], im_data["size"][1]) + # result.loadFromData(im_data["data"]) qimage = toqimage(im) return QPixmap.fromImage(qimage) diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py index 1ada8252c..c3693eb61 100644 --- a/src/PIL/ImageShow.py +++ b/src/PIL/ImageShow.py @@ -69,7 +69,6 @@ class Viewer: Converts the given image to the target format and displays it. """ - # save temporary image to disk if not ( image.mode in ("1", "RGBA") or (self.format == "PNG" and image.mode in ("I;16", "LA")) @@ -195,11 +194,21 @@ class DisplayViewer(UnixViewer): return command, executable +class GmDisplayViewer(UnixViewer): + """The GraphicsMagick ``gm display`` command.""" + + def get_command_ex(self, file, **options): + executable = "gm" + command = "gm display" + return command, executable + + class EogViewer(UnixViewer): """The GNOME Image Viewer ``eog`` command.""" def get_command_ex(self, file, **options): - command = executable = "eog" + executable = "eog" + command = "eog -n" return command, executable @@ -221,15 +230,34 @@ class XVViewer(UnixViewer): if sys.platform not in ("win32", "darwin"): # unixoids if shutil.which("display"): register(DisplayViewer) + if shutil.which("gm"): + register(GmDisplayViewer) if shutil.which("eog"): register(EogViewer) if shutil.which("xv"): register(XVViewer) + +class IPythonViewer(Viewer): + """The viewer for IPython frontends.""" + + def show_image(self, image, **options): + ipython_display(image) + return 1 + + +try: + from IPython.display import display as ipython_display +except ImportError: + pass +else: + register(IPythonViewer) + + if __name__ == "__main__": if len(sys.argv) < 2: - print("Syntax: python ImageShow.py imagefile [title]") + print("Syntax: python3 ImageShow.py imagefile [title]") sys.exit() with Image.open(sys.argv[1]) as im: diff --git a/src/PIL/IptcImagePlugin.py b/src/PIL/IptcImagePlugin.py index f407b7e5f..0bbe50668 100644 --- a/src/PIL/IptcImagePlugin.py +++ b/src/PIL/IptcImagePlugin.py @@ -62,14 +62,14 @@ class IptcImageFile(ImageFile.ImageFile): if not len(s): return None, 0 - tag = i8(s[1]), i8(s[2]) + tag = s[1], s[2] # syntax - if i8(s[0]) != 0x1C or tag[0] < 1 or tag[0] > 9: + if s[0] != 0x1C or tag[0] < 1 or tag[0] > 9: raise SyntaxError("invalid IPTC/NAA file") # field size - size = i8(s[3]) + size = s[3] if size > 132: raise OSError("illegal field length in IPTC/NAA file") elif size == 128: @@ -77,7 +77,7 @@ class IptcImageFile(ImageFile.ImageFile): elif size > 128: size = i(self.fp.read(size - 128)) else: - size = i16(s[3:]) + size = i16(s, 3) return tag, size diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 29bc61aa8..ec4e12f7b 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -33,6 +33,7 @@ # import array import io +import math import os import struct import subprocess @@ -41,7 +42,6 @@ import tempfile import warnings from . import Image, ImageFile, TiffImagePlugin -from ._binary import i8 from ._binary import i16be as i16 from ._binary import i32be as i32 from ._binary import o8 @@ -75,7 +75,7 @@ def APP(self, marker): self.info["jfif_version"] = divmod(version, 256) # extract JFIF properties try: - jfif_unit = i8(s[7]) + jfif_unit = s[7] jfif_density = i16(s, 8), i16(s, 10) except Exception: pass @@ -115,7 +115,7 @@ def APP(self, marker): code = i16(s, offset) offset += 2 # resource name (usually empty) - name_len = i8(s[offset]) + name_len = s[offset] # name = s[offset+1:offset+1+name_len] offset += 1 + name_len offset += offset & 1 # align @@ -125,10 +125,10 @@ def APP(self, marker): data = s[offset : offset + size] if code == 0x03ED: # ResolutionInfo data = { - "XResolution": i32(data[:4]) / 65536, - "DisplayedUnitsX": i16(data[4:8]), - "YResolution": i32(data[8:12]) / 65536, - "DisplayedUnitsY": i16(data[12:]), + "XResolution": i32(data, 0) / 65536, + "DisplayedUnitsX": i16(data, 4), + "YResolution": i32(data, 8) / 65536, + "DisplayedUnitsY": i16(data, 12), } photoshop[code] = data offset += size @@ -140,8 +140,8 @@ def APP(self, marker): self.info["adobe"] = i16(s, 5) # extract Adobe custom properties try: - adobe_transform = i8(s[1]) - except Exception: + adobe_transform = s[11] + except IndexError: pass else: self.info["adobe_transform"] = adobe_transform @@ -162,15 +162,17 @@ def APP(self, marker): dpi = float(x_resolution[0]) / x_resolution[1] except TypeError: dpi = x_resolution + if math.isnan(dpi): + raise ValueError if resolution_unit == 3: # cm # 1 dpcm = 2.54 dpi dpi *= 2.54 - self.info["dpi"] = int(dpi + 0.5), int(dpi + 0.5) + self.info["dpi"] = dpi, dpi except (KeyError, SyntaxError, ValueError, ZeroDivisionError): # SyntaxError for invalid/unreadable EXIF # KeyError for dpi not included # ZeroDivisionError for invalid dpi rational value - # ValueError for x_resolution[0] being an invalid float + # ValueError for dpi being an invalid float self.info["dpi"] = 72, 72 @@ -195,13 +197,13 @@ def SOF(self, marker): n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) - self._size = i16(s[3:]), i16(s[1:]) + self._size = i16(s, 3), i16(s, 1) - self.bits = i8(s[0]) + self.bits = s[0] if self.bits != 8: raise SyntaxError(f"cannot handle {self.bits}-bit layers") - self.layers = i8(s[5]) + self.layers = s[5] if self.layers == 1: self.mode = "L" elif self.layers == 3: @@ -217,7 +219,7 @@ def SOF(self, marker): if self.icclist: # fixup icc profile self.icclist.sort() # sort by sequence number - if i8(self.icclist[0][13]) == len(self.icclist): + if self.icclist[0][13] == len(self.icclist): profile = [] for p in self.icclist: profile.append(p[14:]) @@ -230,7 +232,7 @@ def SOF(self, marker): for i in range(6, len(s), 3): t = s[i : i + 3] # 4-tuples: id, vsamp, hsamp, qtable - self.layer.append((t[0], i8(t[1]) // 16, i8(t[1]) & 15, i8(t[2]))) + self.layer.append((t[0], t[1] // 16, t[1] & 15, t[2])) def DQT(self, marker): @@ -244,7 +246,7 @@ def DQT(self, marker): n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) while len(s): - v = i8(s[0]) + v = s[0] precision = 1 if (v // 16 == 0) else 2 # in bytes qt_length = 1 + precision * 64 if len(s) < qt_length: @@ -362,7 +364,7 @@ class JpegImageFile(ImageFile.ImageFile): while True: - i = i8(s) + i = s[0] if i == 0xFF: s = s + self.fp.read(1) i = i16(s) @@ -475,11 +477,24 @@ class JpegImageFile(ImageFile.ImageFile): def _getmp(self): return _getmp(self) + def getxmp(self): + """ + Returns a dictionary containing the XMP tags. + :returns: XMP tags in a dictionary. + """ + + for segment, content in self.applist: + if segment == "APP1": + marker, xmp_tags = content.rsplit(b"\x00", 1) + if marker == b"http://ns.adobe.com/xap/1.0/": + return self._getxmp(xmp_tags) + return {} + def _getexif(self): if "exif" not in self.info: return None - return dict(self.getexif()) + return self.getexif()._get_merged_dict() def _getmp(self): diff --git a/src/PIL/MicImagePlugin.py b/src/PIL/MicImagePlugin.py index 2aed26030..9248b1b65 100644 --- a/src/PIL/MicImagePlugin.py +++ b/src/PIL/MicImagePlugin.py @@ -68,7 +68,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): self.is_animated = self._n_frames > 1 if len(self.images) > 1: - self.category = Image.CONTAINER + self._category = Image.CONTAINER self.seek(0) diff --git a/src/PIL/MpoImagePlugin.py b/src/PIL/MpoImagePlugin.py index 575cc9c8e..7244aa2a9 100644 --- a/src/PIL/MpoImagePlugin.py +++ b/src/PIL/MpoImagePlugin.py @@ -82,9 +82,11 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile): n = i16(self.fp.read(2)) - 2 self.info["exif"] = ImageFile._safe_read(self.fp, n) - exif = self.getexif() - if 40962 in exif and 40963 in exif: - self._size = (exif[40962], exif[40963]) + mptype = self.mpinfo[0xB002][frame]["Attribute"]["MPType"] + if mptype.startswith("Large Thumbnail"): + exif = self.getexif().get_ifd(0x8769) + if 40962 in exif and 40963 in exif: + self._size = (exif[40962], exif[40963]) elif "exif" in self.info: del self.info["exif"] diff --git a/src/PIL/MspImagePlugin.py b/src/PIL/MspImagePlugin.py index 9dd6e9f32..e1fdc1fdf 100644 --- a/src/PIL/MspImagePlugin.py +++ b/src/PIL/MspImagePlugin.py @@ -27,7 +27,6 @@ import io import struct from . import Image, ImageFile -from ._binary import i8 from ._binary import i16le as i16 from ._binary import o16le as o16 @@ -59,12 +58,12 @@ class MspImageFile(ImageFile.ImageFile): # Header checksum checksum = 0 for i in range(0, 32, 2): - checksum = checksum ^ i16(s[i : i + 2]) + checksum = checksum ^ i16(s, i) if checksum != 0: raise SyntaxError("bad MSP checksum") self.mode = "1" - self._size = i16(s[4:]), i16(s[6:]) + self._size = i16(s, 4), i16(s, 6) if s[:4] == b"DanM": self.tile = [("raw", (0, 0) + self.size, 32, ("1", 0, 1))] @@ -133,7 +132,7 @@ class MspDecoder(ImageFile.PyDecoder): ) idx = 0 while idx < rowlen: - runtype = i8(row[idx]) + runtype = row[idx] idx += 1 if runtype == 0: (runcount, runval) = struct.unpack_from("Bc", row, idx) diff --git a/src/PIL/PSDraw.py b/src/PIL/PSDraw.py index c1bd933d3..743c35f01 100644 --- a/src/PIL/PSDraw.py +++ b/src/PIL/PSDraw.py @@ -26,39 +26,36 @@ from . import EpsImagePlugin class PSDraw: """ Sets up printing to the given file. If ``fp`` is omitted, - :py:data:`sys.stdout` is assumed. + ``sys.stdout.buffer`` or ``sys.stdout`` is assumed. """ def __init__(self, fp=None): if not fp: - fp = sys.stdout + try: + fp = sys.stdout.buffer + except AttributeError: + fp = sys.stdout self.fp = fp - def _fp_write(self, to_write): - if self.fp == sys.stdout: - self.fp.write(to_write) - else: - self.fp.write(bytes(to_write, "UTF-8")) - def begin_document(self, id=None): """Set up printing of a document. (Write PostScript DSC header.)""" # FIXME: incomplete - self._fp_write( - "%!PS-Adobe-3.0\n" - "save\n" - "/showpage { } def\n" - "%%EndComments\n" - "%%BeginDocument\n" + self.fp.write( + b"%!PS-Adobe-3.0\n" + b"save\n" + b"/showpage { } def\n" + b"%%EndComments\n" + b"%%BeginDocument\n" ) - # self._fp_write(ERROR_PS) # debugging! - self._fp_write(EDROFF_PS) - self._fp_write(VDI_PS) - self._fp_write("%%EndProlog\n") + # self.fp.write(ERROR_PS) # debugging! + self.fp.write(EDROFF_PS) + self.fp.write(VDI_PS) + self.fp.write(b"%%EndProlog\n") self.isofont = {} def end_document(self): """Ends printing. (Write PostScript DSC footer.)""" - self._fp_write("%%EndDocument\nrestore showpage\n%%End\n") + self.fp.write(b"%%EndDocument\nrestore showpage\n%%End\n") if hasattr(self.fp, "flush"): self.fp.flush() @@ -69,12 +66,13 @@ class PSDraw: :param font: A PostScript font name :param size: Size in points. """ + font = bytes(font, "UTF-8") if font not in self.isofont: # reencode font - self._fp_write(f"/PSDraw-{font} ISOLatin1Encoding /{font} E\n") + self.fp.write(b"/PSDraw-%s ISOLatin1Encoding /%s E\n" % (font, font)) self.isofont[font] = 1 # rough - self._fp_write(f"/F0 {size} /PSDraw-{font} F\n") + self.fp.write(b"/F0 %d /PSDraw-%s F\n" % (size, font)) def line(self, xy0, xy1): """ @@ -82,7 +80,7 @@ class PSDraw: PostScript point coordinates (72 points per inch, (0, 0) is the lower left corner of the page). """ - self._fp_write("%d %d %d %d Vl\n" % (*xy0, *xy1)) + self.fp.write(b"%d %d %d %d Vl\n" % (*xy0, *xy1)) def rectangle(self, box): """ @@ -97,16 +95,18 @@ class PSDraw: %d %d M %d %d 0 Vr\n """ - self._fp_write("%d %d M %d %d 0 Vr\n" % box) + self.fp.write(b"%d %d M %d %d 0 Vr\n" % box) def text(self, xy, text): """ Draws text at the given position. You must use :py:meth:`~PIL.PSDraw.PSDraw.setfont` before calling this method. """ - text = "\\(".join(text.split("(")) - text = "\\)".join(text.split(")")) - self._fp_write(f"{xy[0]} {xy[1]} M ({text}) S\n") + text = bytes(text, "UTF-8") + text = b"\\(".join(text.split(b"(")) + text = b"\\)".join(text.split(b")")) + xy += (text,) + self.fp.write(b"%d %d M (%s) S\n" % xy) def image(self, box, im, dpi=None): """Draw a PIL image, centered in the given box.""" @@ -130,14 +130,14 @@ class PSDraw: y = ymax dx = (xmax - x) / 2 + box[0] dy = (ymax - y) / 2 + box[1] - self._fp_write(f"gsave\n{dx:f} {dy:f} translate\n") + self.fp.write(b"gsave\n%f %f translate\n" % (dx, dy)) if (x, y) != im.size: # EpsImagePlugin._save prints the image at (0,0,xsize,ysize) sx = x / im.size[0] sy = y / im.size[1] - self._fp_write(f"{sx:f} {sy:f} scale\n") + self.fp.write(b"%f %f scale\n" % (sx, sy)) EpsImagePlugin._save(im, self.fp, None, 0) - self._fp_write("\ngrestore\n") + self.fp.write(b"\ngrestore\n") # -------------------------------------------------------------------- @@ -153,7 +153,7 @@ class PSDraw: # -EDROFF_PS = """\ +EDROFF_PS = b"""\ /S { show } bind def /P { moveto show } bind def /M { moveto } bind def @@ -182,7 +182,7 @@ EDROFF_PS = """\ # Copyright (c) Fredrik Lundh 1994. # -VDI_PS = """\ +VDI_PS = b"""\ /Vm { moveto } bind def /Va { newpath arcn stroke } bind def /Vl { moveto lineto stroke } bind def @@ -207,7 +207,7 @@ VDI_PS = """\ # 89-11-21 fl: created (pslist 1.10) # -ERROR_PS = """\ +ERROR_PS = b"""\ /landscape false def /errorBUF 200 string def /errorNL { currentpoint 10 sub exch pop 72 exch moveto } def diff --git a/src/PIL/PcdImagePlugin.py b/src/PIL/PcdImagePlugin.py index 625f55646..38caf5c63 100644 --- a/src/PIL/PcdImagePlugin.py +++ b/src/PIL/PcdImagePlugin.py @@ -16,7 +16,6 @@ from . import Image, ImageFile -from ._binary import i8 ## # Image plugin for PhotoCD images. This plugin only reads the 768x512 @@ -38,7 +37,7 @@ class PcdImageFile(ImageFile.ImageFile): if s[:4] != b"PCD_": raise SyntaxError("not a PCD file") - orientation = i8(s[1538]) & 3 + orientation = s[1538] & 3 self.tile_post_rotate = None if orientation == 1: self.tile_post_rotate = 90 diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index 767f9945a..d2e166bdd 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -29,7 +29,6 @@ import io import logging from . import Image, ImageFile, ImagePalette -from ._binary import i8 from ._binary import i16le as i16 from ._binary import o8 from ._binary import o16le as o16 @@ -38,7 +37,7 @@ logger = logging.getLogger(__name__) def _accept(prefix): - return i8(prefix[0]) == 10 and i8(prefix[1]) in [0, 2, 3, 5] + return prefix[0] == 10 and prefix[1] in [0, 2, 3, 5] ## @@ -64,16 +63,16 @@ class PcxImageFile(ImageFile.ImageFile): logger.debug("BBox: %s %s %s %s", *bbox) # format - version = i8(s[1]) - bits = i8(s[3]) - planes = i8(s[65]) - stride = i16(s, 66) + version = s[1] + bits = s[3] + planes = s[65] + provided_stride = i16(s, 66) logger.debug( "PCX version %s, bits %s, planes %s, stride %s", version, bits, planes, - stride, + provided_stride, ) self.info["dpi"] = i16(s, 12), i16(s, 14) @@ -91,7 +90,7 @@ class PcxImageFile(ImageFile.ImageFile): # FIXME: hey, this doesn't work with the incremental loader !!! self.fp.seek(-769, io.SEEK_END) s = self.fp.read(769) - if len(s) == 769 and i8(s[0]) == 12: + if len(s) == 769 and s[0] == 12: # check if the palette is linear greyscale for i in range(256): if s[i * 3 + 1 : i * 3 + 4] != o8(i) * 3: @@ -111,6 +110,16 @@ class PcxImageFile(ImageFile.ImageFile): self.mode = mode self._size = bbox[2] - bbox[0], bbox[3] - bbox[1] + # Don't trust the passed in stride. + # Calculate the approximate position for ourselves. + # CVE-2020-35653 + stride = (self._size[0] * bits + 7) // 8 + + # While the specification states that this must be even, + # not all images follow this + if provided_stride != stride: + stride += stride % 2 + bbox = (0, 0) + self.size logger.debug("size: %sx%s", *self.size) diff --git a/src/PIL/PdfImagePlugin.py b/src/PIL/PdfImagePlugin.py index 36c8fb849..49ba077e6 100644 --- a/src/PIL/PdfImagePlugin.py +++ b/src/PIL/PdfImagePlugin.py @@ -124,7 +124,7 @@ def _save(im, fp, filename, save_all=False): decode = None if im.mode == "1": - filter = "ASCIIHexDecode" + filter = "DCTDecode" colorspace = PdfParser.PdfName("DeviceGray") procset = "ImageB" # grayscale bits = 1 @@ -161,12 +161,6 @@ def _save(im, fp, filename, save_all=False): op = io.BytesIO() if filter == "ASCIIHexDecode": - if bits == 1: - # FIXME: the hex encoder doesn't support packed 1-bit - # images; do things the hard way... - data = im.tobytes("raw", "1") - im = Image.new("L", im.size) - im.putdata(data) ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)]) elif filter == "DCTDecode": Image.SAVE["JPEG"](im, op, filename) @@ -208,8 +202,8 @@ def _save(im, fp, filename, save_all=False): MediaBox=[ 0, 0, - int(width * 72.0 / resolution), - int(height * 72.0 / resolution), + width * 72.0 / resolution, + height * 72.0 / resolution, ], Contents=contents_refs[pageNumber], ) @@ -217,9 +211,9 @@ def _save(im, fp, filename, save_all=False): # # page contents - page_contents = b"q %d 0 0 %d 0 0 cm /image Do Q\n" % ( - int(width * 72.0 / resolution), - int(height * 72.0 / resolution), + page_contents = b"q %f 0 0 %f 0 0 cm /image Do Q\n" % ( + width * 72.0 / resolution, + height * 72.0 / resolution, ) existing_pdf.write_obj(contents_refs[pageNumber], stream=page_contents) diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index 975905f96..b5279e0d7 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -330,6 +330,8 @@ def pdf_repr(x): return bytes(x) elif isinstance(x, int): return str(x).encode("us-ascii") + elif isinstance(x, float): + return str(x).encode("us-ascii") elif isinstance(x, time.struct_time): return b"(D:" + time.strftime("%Y%m%d%H%M%SZ", x).encode("us-ascii") + b")" elif isinstance(x, dict): @@ -580,8 +582,9 @@ class PdfParser: whitespace_or_hex = br"[\000\011\012\014\015\0400-9a-fA-F]" whitespace_optional = whitespace + b"*" whitespace_mandatory = whitespace + b"+" + whitespace_optional_no_nl = br"[\000\011\014\015\040]*" # no "\012" aka "\n" newline_only = br"[\r\n]+" - newline = whitespace_optional + newline_only + whitespace_optional + newline = whitespace_optional_no_nl + newline_only + whitespace_optional_no_nl re_trailer_end = re.compile( whitespace_mandatory + br"trailer" diff --git a/src/PIL/PixarImagePlugin.py b/src/PIL/PixarImagePlugin.py index 91f0314b5..c4860b6c4 100644 --- a/src/PIL/PixarImagePlugin.py +++ b/src/PIL/PixarImagePlugin.py @@ -49,10 +49,10 @@ class PixarImageFile(ImageFile.ImageFile): # read rest of header s = s + self.fp.read(508) - self._size = i16(s[418:420]), i16(s[416:418]) + self._size = i16(s, 418), i16(s, 416) # get channel/depth descriptions - mode = i16(s[424:426]), i16(s[426:428]) + mode = i16(s, 424), i16(s, 426) if mode == (14, 2): self.mode = "RGB" diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 6af41af6e..899d91108 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -39,7 +39,6 @@ import warnings import zlib from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence -from ._binary import i8 from ._binary import i16be as i16 from ._binary import i32be as i32 from ._binary import o8 @@ -193,7 +192,7 @@ class ChunkStream: # Skip CRC checks for ancillary chunks if allowed to load truncated # images # 5th byte of first char is 1 [specs, section 5.4] - if ImageFile.LOAD_TRUNCATED_IMAGES and (i8(cid[0]) >> 5 & 1): + if ImageFile.LOAD_TRUNCATED_IMAGES and (cid[0] >> 5 & 1): self.crc_skip(cid, data) return @@ -390,8 +389,8 @@ class PngStream(ChunkStream): # Compressed profile n bytes (zlib with deflate compression) i = s.find(b"\0") logger.debug("iCCP profile name %r", s[:i]) - logger.debug("Compression method %s", i8(s[i])) - comp_method = i8(s[i]) + logger.debug("Compression method %s", s[i]) + comp_method = s[i] if comp_method != 0: raise SyntaxError(f"Unknown compression method {comp_method} in iCCP chunk") try: @@ -410,14 +409,14 @@ class PngStream(ChunkStream): # image header s = ImageFile._safe_read(self.fp, length) - self.im_size = i32(s), i32(s[4:]) + self.im_size = i32(s, 0), i32(s, 4) try: - self.im_mode, self.im_rawmode = _MODES[(i8(s[8]), i8(s[9]))] + self.im_mode, self.im_rawmode = _MODES[(s[8], s[9])] except Exception: pass - if i8(s[12]): + if s[12]: self.im_info["interlace"] = 1 - if i8(s[11]): + if s[11]: raise SyntaxError("unknown filter category") return s @@ -465,7 +464,7 @@ class PngStream(ChunkStream): elif self.im_mode in ("1", "L", "I"): self.im_info["transparency"] = i16(s) elif self.im_mode == "RGB": - self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:]) + self.im_info["transparency"] = i16(s), i16(s, 2), i16(s, 4) return s def chunk_gAMA(self, pos, length): @@ -491,17 +490,17 @@ class PngStream(ChunkStream): # 3 absolute colorimetric s = ImageFile._safe_read(self.fp, length) - self.im_info["srgb"] = i8(s) + self.im_info["srgb"] = s[0] return s def chunk_pHYs(self, pos, length): # pixels per unit s = ImageFile._safe_read(self.fp, length) - px, py = i32(s), i32(s[4:]) - unit = i8(s[8]) + px, py = i32(s, 0), i32(s, 4) + unit = s[8] if unit == 1: # meter - dpi = int(px * 0.0254 + 0.5), int(py * 0.0254 + 0.5) + dpi = px * 0.0254, py * 0.0254 self.im_info["dpi"] = dpi elif unit == 0: self.im_info["aspect"] = px, py @@ -537,7 +536,7 @@ class PngStream(ChunkStream): k = s v = b"" if v: - comp_method = i8(v[0]) + comp_method = v[0] else: comp_method = 0 if comp_method != 0: @@ -571,7 +570,7 @@ class PngStream(ChunkStream): return s if len(r) < 2: return s - cf, cm, r = i8(r[0]), i8(r[1]), r[2:] + cf, cm, r = r[0], r[1], r[2:] try: lang, tk, v = r.split(b"\0", 2) except ValueError: @@ -619,7 +618,7 @@ class PngStream(ChunkStream): warnings.warn("Invalid APNG, will use default PNG image if possible") return s self.im_n_frames = n_frames - self.im_info["loop"] = i32(s[4:]) + self.im_info["loop"] = i32(s, 4) self.im_custom_mimetype = "image/apng" return s @@ -631,18 +630,18 @@ class PngStream(ChunkStream): ): raise SyntaxError("APNG contains frame sequence errors") self._seq_num = seq - width, height = i32(s[4:]), i32(s[8:]) - px, py = i32(s[12:]), i32(s[16:]) + width, height = i32(s, 4), i32(s, 8) + px, py = i32(s, 12), i32(s, 16) im_w, im_h = self.im_size if px + width > im_w or py + height > im_h: raise SyntaxError("APNG contains invalid frames") self.im_info["bbox"] = (px, py, px + width, py + height) - delay_num, delay_den = i16(s[20:]), i16(s[22:]) + delay_num, delay_den = i16(s, 20), i16(s, 22) if delay_den == 0: delay_den = 100 self.im_info["duration"] = float(delay_num) / float(delay_den) * 1000 - self.im_info["disposal"] = i8(s[24]) - self.im_info["blend"] = i8(s[25]) + self.im_info["disposal"] = s[24] + self.im_info["blend"] = s[25] return s def chunk_fdAT(self, pos, length): @@ -803,60 +802,76 @@ class PngImageFile(ImageFile.ImageFile): self.blend_op = self.info.get("blend") self.dispose_extent = self.info.get("bbox") self.__frame = 0 - return else: if frame != self.__frame + 1: raise ValueError(f"cannot seek to frame {frame}") - # ensure previous frame was loaded - self.load() + # ensure previous frame was loaded + self.load() - self.fp = self.__fp + if self.dispose: + self.im.paste(self.dispose, self.dispose_extent) + self._prev_im = self.im.copy() - # advance to the next frame - if self.__prepare_idat: - ImageFile._safe_read(self.fp, self.__prepare_idat) - self.__prepare_idat = 0 - frame_start = False - while True: - self.fp.read(4) # CRC + self.fp = self.__fp - try: - cid, pos, length = self.png.read() - except (struct.error, SyntaxError): - break + # advance to the next frame + if self.__prepare_idat: + ImageFile._safe_read(self.fp, self.__prepare_idat) + self.__prepare_idat = 0 + frame_start = False + while True: + self.fp.read(4) # CRC - if cid == b"IEND": - raise EOFError("No more images in APNG file") - if cid == b"fcTL": - if frame_start: - # there must be at least one fdAT chunk between fcTL chunks - raise SyntaxError("APNG missing frame data") - frame_start = True + try: + cid, pos, length = self.png.read() + except (struct.error, SyntaxError): + break - try: - self.png.call(cid, pos, length) - except UnicodeDecodeError: - break - except EOFError: - if cid == b"fdAT": - length -= 4 + if cid == b"IEND": + raise EOFError("No more images in APNG file") + if cid == b"fcTL": if frame_start: - self.__prepare_idat = length - break - ImageFile._safe_read(self.fp, length) - except AttributeError: - logger.debug("%r %s %s (unknown)", cid, pos, length) - ImageFile._safe_read(self.fp, length) + # there must be at least one fdAT chunk between fcTL chunks + raise SyntaxError("APNG missing frame data") + frame_start = True - self.__frame = frame - self.tile = self.png.im_tile - self.dispose_op = self.info.get("disposal") - self.blend_op = self.info.get("blend") - self.dispose_extent = self.info.get("bbox") + try: + self.png.call(cid, pos, length) + except UnicodeDecodeError: + break + except EOFError: + if cid == b"fdAT": + length -= 4 + if frame_start: + self.__prepare_idat = length + break + ImageFile._safe_read(self.fp, length) + except AttributeError: + logger.debug("%r %s %s (unknown)", cid, pos, length) + ImageFile._safe_read(self.fp, length) - if not self.tile: - raise EOFError + self.__frame = frame + self.tile = self.png.im_tile + self.dispose_op = self.info.get("disposal") + self.blend_op = self.info.get("blend") + self.dispose_extent = self.info.get("bbox") + + if not self.tile: + raise EOFError + + # setup frame disposal (actual disposal done when needed in the next _seek()) + if self._prev_im is None and self.dispose_op == APNG_DISPOSE_OP_PREVIOUS: + self.dispose_op = APNG_DISPOSE_OP_BACKGROUND + + if self.dispose_op == APNG_DISPOSE_OP_PREVIOUS: + self.dispose = self._prev_im.copy() + self.dispose = self._crop(self.dispose, self.dispose_extent) + elif self.dispose_op == APNG_DISPOSE_OP_BACKGROUND: + self.dispose = Image.core.fill(self.mode, self.size) + self.dispose = self._crop(self.dispose, self.dispose_extent) + else: + self.dispose = None def tell(self): return self.__frame @@ -905,6 +920,8 @@ class PngImageFile(ImageFile.ImageFile): def load_end(self): """internal: finished reading image data""" + if self.__idat != 0: + self.fp.read(self.__idat) while True: self.fp.read(4) # CRC @@ -939,19 +956,6 @@ class PngImageFile(ImageFile.ImageFile): self.png.close() self.png = None else: - # setup frame disposal (actual disposal done when needed in _seek()) - if self._prev_im is None and self.dispose_op == APNG_DISPOSE_OP_PREVIOUS: - self.dispose_op = APNG_DISPOSE_OP_BACKGROUND - - if self.dispose_op == APNG_DISPOSE_OP_PREVIOUS: - dispose = self._prev_im.copy() - dispose = self._crop(dispose, self.dispose_extent) - elif self.dispose_op == APNG_DISPOSE_OP_BACKGROUND: - dispose = Image.core.fill(self.im.mode, self.size) - dispose = self._crop(dispose, self.dispose_extent) - else: - dispose = None - if self._prev_im and self.blend_op == APNG_BLEND_OP_OVER: updated = self._crop(self.im, self.dispose_extent) self._prev_im.paste( @@ -960,17 +964,13 @@ class PngImageFile(ImageFile.ImageFile): self.im = self._prev_im if self.pyaccess: self.pyaccess = None - self._prev_im = self.im.copy() - - if dispose: - self._prev_im.paste(dispose, self.dispose_extent) def _getexif(self): if "exif" not in self.info: self.load() if "exif" not in self.info and "Raw profile type exif" not in self.info: return None - return dict(self.getexif()) + return self.getexif()._get_merged_dict() def getexif(self): if "exif" not in self.info: @@ -978,6 +978,17 @@ class PngImageFile(ImageFile.ImageFile): return super().getexif() + def getxmp(self): + """ + Returns a dictionary containing the XMP tags. + :returns: XMP tags in a dictionary. + """ + return ( + self._getxmp(self.info["XML:com.adobe.xmp"]) + if "XML:com.adobe.xmp" in self.info + else {} + ) + def _close__fp(self): try: if self.__fp != self.fp: @@ -1188,23 +1199,21 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): # attempt to minimize storage requirements for palette images if "bits" in im.encoderinfo: # number of bits specified by user - colors = 1 << im.encoderinfo["bits"] + colors = min(1 << im.encoderinfo["bits"], 256) else: # check palette contents if im.palette: - colors = max(min(len(im.palette.getdata()[1]) // 3, 256), 2) + colors = max(min(len(im.palette.getdata()[1]) // 3, 256), 1) else: colors = 256 - if colors <= 2: - bits = 1 - elif colors <= 4: - bits = 2 - elif colors <= 16: - bits = 4 - else: - bits = 8 - if bits != 8: + if colors <= 16: + if colors <= 2: + bits = 1 + elif colors <= 4: + bits = 2 + else: + bits = 4 mode = f"{mode};{bits}" # encoder options @@ -1272,7 +1281,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): chunk(fp, cid, data) if im.mode == "P": - palette_byte_number = (2 ** bits) * 3 + palette_byte_number = colors * 3 palette_bytes = im.im.getpalette("RGB")[:palette_byte_number] while len(palette_bytes) < palette_byte_number: palette_bytes += b"\0" @@ -1283,7 +1292,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): if transparency or transparency == 0: if im.mode == "P": # limit to actual palette size - alpha_bytes = 2 ** bits + alpha_bytes = colors if isinstance(transparency, bytes): chunk(fp, b"tRNS", transparency[:alpha_bytes]) else: @@ -1304,7 +1313,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): else: if im.mode == "P" and im.im.getpalettemode() == "RGBA": alpha = im.im.getpalette("RGBA", "A") - alpha_bytes = 2 ** bits + alpha_bytes = colors chunk(fp, b"tRNS", alpha[:alpha_bytes]) dpi = im.encoderinfo.get("dpi") diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index 8d1dbf2b2..e7b884674 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -63,12 +63,12 @@ class PsdImageFile(ImageFile.ImageFile): # header s = read(26) - if not _accept(s) or i16(s[4:]) != 1: + if not _accept(s) or i16(s, 4) != 1: raise SyntaxError("not a PSD file") - psd_bits = i16(s[22:]) - psd_channels = i16(s[12:]) - psd_mode = i16(s[24:]) + psd_bits = i16(s, 22) + psd_channels = i16(s, 12) + psd_mode = i16(s, 24) mode, channels = MODES[(psd_mode, psd_bits)] @@ -76,7 +76,7 @@ class PsdImageFile(ImageFile.ImageFile): raise OSError("not enough channels") self.mode = mode - self._size = i32(s[18:]), i32(s[14:]) + self._size = i32(s, 18), i32(s, 14) # # color mode data @@ -119,7 +119,8 @@ class PsdImageFile(ImageFile.ImageFile): end = self.fp.tell() + size size = i32(read(4)) if size: - self.layers = _layerinfo(self.fp) + _layer_data = io.BytesIO(ImageFile._safe_read(self.fp, size)) + self.layers = _layerinfo(_layer_data, size) self.fp.seek(end) self.n_frames = len(self.layers) self.is_animated = self.n_frames > 1 @@ -171,11 +172,20 @@ class PsdImageFile(ImageFile.ImageFile): self.__fp = None -def _layerinfo(file): +def _layerinfo(fp, ct_bytes): # read layerinfo block layers = [] - read = file.read - for i in range(abs(i16(read(2)))): + + def read(size): + return ImageFile._safe_read(fp, size) + + ct = i16(read(2)) + + # sanity check + if ct_bytes < (abs(ct) * 20): + raise SyntaxError("Layer block too short for number of layers requested") + + for i in range(abs(ct)): # bounding box y0 = i32(read(4)) @@ -186,7 +196,8 @@ def _layerinfo(file): # image info info = [] mode = [] - types = list(range(i16(read(2)))) + ct_types = i16(read(2)) + types = list(range(ct_types)) if len(types) > 4: continue @@ -219,16 +230,16 @@ def _layerinfo(file): size = i32(read(4)) # length of the extra data field combined = 0 if size: - data_end = file.tell() + size + data_end = fp.tell() + size length = i32(read(4)) if length: - file.seek(length - 16, io.SEEK_CUR) + fp.seek(length - 16, io.SEEK_CUR) combined += length + 4 length = i32(read(4)) if length: - file.seek(length, io.SEEK_CUR) + fp.seek(length, io.SEEK_CUR) combined += length + 4 length = i8(read(1)) @@ -238,7 +249,7 @@ def _layerinfo(file): name = read(length).decode("latin-1", "replace") combined += length + 1 - file.seek(data_end) + fp.seek(data_end) layers.append((name, mode, (x0, y0, x1, y1))) # get tiles @@ -246,7 +257,7 @@ def _layerinfo(file): for name, mode, bbox in layers: tile = [] for m in mode: - t = _maketile(file, m, bbox, 1) + t = _maketile(fp, m, bbox, 1) if t: tile.extend(t) layers[i] = name, mode, bbox, tile @@ -291,7 +302,7 @@ def _maketile(file, mode, bbox, channels): layer += ";I" tile.append(("packbits", bbox, offset, layer)) for y in range(ysize): - offset = offset + i16(bytecount[i : i + 2]) + offset = offset + i16(bytecount, i) i += 2 file.seek(offset) diff --git a/src/PIL/PyAccess.py b/src/PIL/PyAccess.py index 494f5f9f4..5ceaa238a 100644 --- a/src/PIL/PyAccess.py +++ b/src/PIL/PyAccess.py @@ -54,6 +54,7 @@ class PyAccess: self.image32 = ffi.cast("int **", vals["image32"]) self.image = ffi.cast("unsigned char **", vals["image"]) self.xsize, self.ysize = img.im.size + self._img = img # Keep pointer to im object to prevent dereferencing. self._im = img.im @@ -93,7 +94,7 @@ class PyAccess: and len(color) in [3, 4] ): # RGB or RGBA value for a P image - color = self._palette.getcolor(color) + color = self._palette.getcolor(color, self._img) return self.set_pixel(x, y, color) diff --git a/src/PIL/SgiImagePlugin.py b/src/PIL/SgiImagePlugin.py index f878fefa9..d0f7c9993 100644 --- a/src/PIL/SgiImagePlugin.py +++ b/src/PIL/SgiImagePlugin.py @@ -26,7 +26,6 @@ import os import struct from . import Image, ImageFile -from ._binary import i8 from ._binary import i16be as i16 from ._binary import o8 @@ -64,22 +63,22 @@ class SgiImageFile(ImageFile.ImageFile): raise ValueError("Not an SGI image file") # compression : verbatim or RLE - compression = i8(s[2]) + compression = s[2] # bpc : 1 or 2 bytes (8bits or 16bits) - bpc = i8(s[3]) + bpc = s[3] # dimension : 1, 2 or 3 (depending on xsize, ysize and zsize) - dimension = i16(s[4:]) + dimension = i16(s, 4) # xsize : width - xsize = i16(s[6:]) + xsize = i16(s, 6) # ysize : height - ysize = i16(s[8:]) + ysize = i16(s, 8) # zsize : channels count - zsize = i16(s[10:]) + zsize = i16(s, 10) # layout layout = bpc, dimension, zsize diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index 819f2ed0a..062af9f98 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -296,7 +296,7 @@ Image.register_save(SpiderImageFile.format, _save_spider) if __name__ == "__main__": if len(sys.argv) < 2: - print("Syntax: python SpiderImagePlugin.py [infile] [outfile]") + print("Syntax: python3 SpiderImagePlugin.py [infile] [outfile]") sys.exit() filename = sys.argv[1] diff --git a/src/PIL/SunImagePlugin.py b/src/PIL/SunImagePlugin.py index d99884293..c03759a01 100644 --- a/src/PIL/SunImagePlugin.py +++ b/src/PIL/SunImagePlugin.py @@ -58,13 +58,13 @@ class SunImageFile(ImageFile.ImageFile): offset = 32 - self._size = i32(s[4:8]), i32(s[8:12]) + self._size = i32(s, 4), i32(s, 8) - depth = i32(s[12:16]) - # data_length = i32(s[16:20]) # unreliable, ignore. - file_type = i32(s[20:24]) - palette_type = i32(s[24:28]) # 0: None, 1: RGB, 2: Raw/arbitrary - palette_length = i32(s[28:32]) + depth = i32(s, 12) + # data_length = i32(s, 16) # unreliable, ignore. + file_type = i32(s, 20) + palette_type = i32(s, 24) # 0: None, 1: RGB, 2: Raw/arbitrary + palette_length = i32(s, 28) if depth == 1: self.mode, rawmode = "1", "1;I" diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py index 69b3e0678..5e5d52d1a 100644 --- a/src/PIL/TgaImagePlugin.py +++ b/src/PIL/TgaImagePlugin.py @@ -20,7 +20,6 @@ import warnings from . import Image, ImageFile, ImagePalette -from ._binary import i8 from ._binary import i16le as i16 from ._binary import o8 from ._binary import o16le as o16 @@ -56,16 +55,16 @@ class TgaImageFile(ImageFile.ImageFile): # process header s = self.fp.read(18) - id_len = i8(s[0]) + id_len = s[0] - colormaptype = i8(s[1]) - imagetype = i8(s[2]) + colormaptype = s[1] + imagetype = s[2] - depth = i8(s[16]) + depth = s[16] - flags = i8(s[17]) + flags = s[17] - self._size = i16(s[12:]), i16(s[14:]) + self._size = i16(s, 12), i16(s, 14) # validate header fields if ( @@ -111,10 +110,10 @@ class TgaImageFile(ImageFile.ImageFile): if colormaptype: # read palette - start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:]) + start, size, mapdepth = i16(s, 3), i16(s, 5), s[7] if mapdepth == 16: self.palette = ImagePalette.raw( - "BGR;16", b"\0" * 2 * start + self.fp.read(2 * size) + "BGR;15", b"\0" * 2 * start + self.fp.read(2 * size) ) elif mapdepth == 24: self.palette = ImagePalette.raw( diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 5480fcd85..b836e9994 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -49,7 +49,7 @@ from fractions import Fraction from numbers import Number, Rational from . import Image, ImageFile, ImagePalette, TiffTags -from ._binary import i8, o8 +from ._binary import o8 from .TiffTags import TYPES logger = logging.getLogger(__name__) @@ -354,9 +354,22 @@ class IFDRational(Rational): return self._val.__hash__() def __eq__(self, other): + val = self._val if isinstance(other, IFDRational): other = other._val - return self._val == other + if isinstance(other, float): + val = float(val) + return val == other + + def __getstate__(self): + return [self._val, self._numerator, self._denominator] + + def __setstate__(self, state): + IFDRational.__init__(self, 0) + _val, _numerator, _denominator = state + self._val = _val + self._numerator = _numerator + self._denominator = _denominator def _delegate(op): def delegate(self, *args): @@ -446,16 +459,16 @@ class ImageFileDirectory_v2(MutableMapping): Tags will be found in the private attributes self._tagdata, and in self._tags_v2 once decoded. - Self.legacy_api is a value for internal use, and shouldn't be + self.legacy_api is a value for internal use, and shouldn't be changed from outside code. In cooperation with the ImageFileDirectory_v1 class, if legacy_api is true, then decoded - tags will be populated into both _tags_v1 and _tags_v2. _Tags_v2 + tags will be populated into both _tags_v1 and _tags_v2. _tags_v2 will be used if this IFD is used in the TIFF save routine. Tags - should be read from tags_v1 if legacy_api == true. + should be read from _tags_v1 if legacy_api == true. """ - def __init__(self, ifh=b"II\052\0\0\0\0\0", prefix=None): + def __init__(self, ifh=b"II\052\0\0\0\0\0", prefix=None, group=None): """Initialize an ImageFileDirectory. To construct an ImageFileDirectory from a real file, pass the 8-byte @@ -475,6 +488,7 @@ class ImageFileDirectory_v2(MutableMapping): self._endian = "<" else: raise SyntaxError("not a TIFF IFD") + self.group = group self.tagtype = {} """ Dictionary of tag types """ self.reset() @@ -506,7 +520,10 @@ class ImageFileDirectory_v2(MutableMapping): Returns the complete tag dictionary, with named tags where possible. """ - return {TiffTags.lookup(code).name: value for code, value in self.items()} + return { + TiffTags.lookup(code, self.group).name: value + for code, value in self.items() + } def __len__(self): return len(set(self._tagdata) | set(self._tags_v2)) @@ -531,7 +548,7 @@ class ImageFileDirectory_v2(MutableMapping): def _setitem(self, tag, value, legacy_api): basetypes = (Number, bytes, str) - info = TiffTags.lookup(tag) + info = TiffTags.lookup(tag, self.group) values = [value] if isinstance(value, basetypes) else value if tag not in self.tagtype: @@ -565,7 +582,8 @@ class ImageFileDirectory_v2(MutableMapping): if self.tagtype[tag] == TiffTags.UNDEFINED: values = [ - value.encode("ascii", "replace") if isinstance(value, str) else value + v.encode("ascii", "replace") if isinstance(v, str) else v + for v in values ] elif self.tagtype[tag] == TiffTags.RATIONAL: values = [float(v) if isinstance(v, int) else v for v in values] @@ -747,7 +765,7 @@ class ImageFileDirectory_v2(MutableMapping): for i in range(self._unpack("H", self._ensure_read(fp, 2))[0]): tag, typ, count, data = self._unpack("HHL4s", self._ensure_read(fp, 12)) - tagname = TiffTags.lookup(tag).name + tagname = TiffTags.lookup(tag, self.group).name typname = TYPES.get(typ, "unknown") msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})" @@ -814,15 +832,16 @@ class ImageFileDirectory_v2(MutableMapping): ifh = b"II\x2A\x00\x08\x00\x00\x00" else: ifh = b"MM\x00\x2A\x00\x00\x00\x08" - ifd = ImageFileDirectory_v2(ifh) - for ifd_tag, ifd_value in self._tags_v2[tag].items(): + ifd = ImageFileDirectory_v2(ifh, group=tag) + values = self._tags_v2[tag] + for ifd_tag, ifd_value in values.items(): ifd[ifd_tag] = ifd_value data = ifd.tobytes(offset) else: values = value if isinstance(value, tuple) else (value,) data = self._write_dispatch[typ](self, *values) - tagname = TiffTags.lookup(tag).name + tagname = TiffTags.lookup(tag, self.group).name typname = "ifd" if is_ifd else TYPES.get(typ, "unknown") msg = f"save: {tagname} ({tag}) - type: {typname} ({typ})" msg += " - value: " + ( @@ -1052,6 +1071,11 @@ class TiffImageFile(ImageFile.ImageFile): def _seek(self, frame): self.fp = self.__fp + + # reset buffered io handle in case fp + # was passed to libtiff, invalidating the buffer + self.fp.tell() + while len(self._frame_pos) <= frame: if not self.__next: raise EOFError("no more images in TIFF file") @@ -1059,14 +1083,16 @@ class TiffImageFile(ImageFile.ImageFile): f"Seeking to frame {frame}, on frame {self.__frame}, " f"__next {self.__next}, location: {self.fp.tell()}" ) - # reset buffered io handle in case fp - # was passed to libtiff, invalidating the buffer - self.fp.tell() self.fp.seek(self.__next) self._frame_pos.append(self.__next) logger.debug("Loading tags, location: %s" % self.fp.tell()) self.tag_v2.load(self.fp) - self.__next = self.tag_v2.next + if self.tag_v2.next in self._frame_pos: + # This IFD has already been processed + # Declare this to be the end of the image + self.__next = 0 + else: + self.__next = self.tag_v2.next if self.__next == 0: self._n_frames = frame + 1 if len(self._frame_pos) == 1: @@ -1083,6 +1109,13 @@ class TiffImageFile(ImageFile.ImageFile): """Return the current frame number""" return self.__frame + def getxmp(self): + """ + Returns a dictionary containing the XMP tags. + :returns: XMP tags in a dictionary. + """ + return self._getxmp(self.tag_v2[700]) if 700 in self.tag_v2 else {} + def load(self): if self.tile and self.use_load_libtiff: return self._load_libtiff() @@ -1250,6 +1283,13 @@ class TiffImageFile(ImageFile.ImageFile): if bps_count > len(bps_tuple) and len(bps_tuple) == 1: bps_tuple = bps_tuple * bps_count + samplesPerPixel = self.tag_v2.get( + SAMPLESPERPIXEL, + 3 if self._compression == "tiff_jpeg" and photo in (2, 6) else 1, + ) + if len(bps_tuple) != samplesPerPixel: + raise SyntaxError("unknown data organization") + # mode: check photometric interpretation and bits per pixel key = ( self.tag_v2.prefix, @@ -1277,11 +1317,11 @@ class TiffImageFile(ImageFile.ImageFile): if xres and yres: resunit = self.tag_v2.get(RESOLUTION_UNIT) if resunit == 2: # dots per inch - self.info["dpi"] = int(xres + 0.5), int(yres + 0.5) + self.info["dpi"] = (xres, yres) elif resunit == 3: # dots per centimeter. convert to dpi - self.info["dpi"] = int(xres * 2.54 + 0.5), int(yres * 2.54 + 0.5) + self.info["dpi"] = (xres * 2.54, yres * 2.54) elif resunit is None: # used to default to 1, but now 2) - self.info["dpi"] = int(xres + 0.5), int(yres + 0.5) + self.info["dpi"] = (xres, yres) # For backward compatibility, # we also preserve the old behavior self.info["resolution"] = xres, yres @@ -1324,6 +1364,15 @@ class TiffImageFile(ImageFile.ImageFile): if ";16L" in rawmode: rawmode = rawmode.replace(";16L", ";16N") + # YCbCr images with new jpeg compression with pixels in one plane + # unpacked straight into RGB values + if ( + photo == 6 + and self._compression == "jpeg" + and self._planar_configuration == 1 + ): + rawmode = "RGB" + # Offset in the tile tuple is 0, we go from 0,0 to # w,h, and we only do this once -- eds a = (rawmode, self._compression, False, self.tag_v2.offset) @@ -1442,6 +1491,8 @@ def _save(im, fp, filename): elif compression == "tiff_jpeg": # OJPEG is obsolete, so use new-style JPEG compression instead compression = "jpeg" + elif compression == "tiff_deflate": + compression = "tiff_adobe_deflate" libtiff = WRITE_LIBTIFF or compression != "raw" @@ -1481,8 +1532,9 @@ def _save(im, fp, filename): # preserve ICC profile (should also work when saving other formats # which support profiles as TIFF) -- 2008-06-06 Florian Hoech - if "icc_profile" in im.info: - ifd[ICCPROFILE] = im.info["icc_profile"] + icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile")) + if icc: + ifd[ICCPROFILE] = icc for key, name in [ (IMAGEDESCRIPTION, "description"), @@ -1502,8 +1554,8 @@ def _save(im, fp, filename): dpi = im.encoderinfo.get("dpi") if dpi: ifd[RESOLUTION_UNIT] = 2 - ifd[X_RESOLUTION] = int(dpi[0] + 0.5) - ifd[Y_RESOLUTION] = int(dpi[1] + 0.5) + ifd[X_RESOLUTION] = dpi[0] + ifd[Y_RESOLUTION] = dpi[1] if bits != (1,): ifd[BITSPERSAMPLE] = bits @@ -1518,7 +1570,7 @@ def _save(im, fp, filename): if im.mode in ["P", "PA"]: lut = im.im.getpalette("RGB", "RGB;L") - ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut) + ifd[COLORMAP] = tuple(v * 256 for v in lut) # data orientation stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8) ifd[ROWSPERSTRIP] = im.size[1] diff --git a/src/PIL/TiffTags.py b/src/PIL/TiffTags.py index 796ff3479..88856aa92 100644 --- a/src/PIL/TiffTags.py +++ b/src/PIL/TiffTags.py @@ -33,7 +33,7 @@ class TagInfo(namedtuple("_TagInfo", "value name type length enum")): return self.enum.get(value, value) if self.enum else value -def lookup(tag): +def lookup(tag, group=None): """ :param tag: Integer tag number :returns: Taginfo namedtuple, From the TAGS_V2 info if possible, @@ -42,7 +42,11 @@ def lookup(tag): """ - return TAGS_V2.get(tag, TagInfo(tag, TAGS.get(tag, "unknown"))) + if group is not None: + info = TAGS_V2_GROUPS[group].get(tag) if group in TAGS_V2_GROUPS else None + else: + info = TAGS_V2.get(tag) + return info or TagInfo(tag, TAGS.get(tag, "unknown")) ## @@ -178,12 +182,15 @@ TAGS_V2 = { 532: ("ReferenceBlackWhite", RATIONAL, 6), 700: ("XMP", BYTE, 0), 33432: ("Copyright", ASCII, 1), - 33723: ("IptcNaaInfo", UNDEFINED, 0), + 33723: ("IptcNaaInfo", UNDEFINED, 1), 34377: ("PhotoshopInfo", BYTE, 0), # FIXME add more tags here 34665: ("ExifIFD", LONG, 1), 34675: ("ICCProfile", UNDEFINED, 1), 34853: ("GPSInfoIFD", LONG, 1), + 36864: ("ExifVersion", UNDEFINED, 1), + 40965: ("InteroperabilityIFD", LONG, 1), + 41730: ("CFAPattern", UNDEFINED, 1), # MPInfo 45056: ("MPFVersion", UNDEFINED, 1), 45057: ("NumberOfImages", LONG, 1), @@ -204,11 +211,25 @@ TAGS_V2 = { 45579: ("YawAngle", SIGNED_RATIONAL, 1), 45580: ("PitchAngle", SIGNED_RATIONAL, 1), 45581: ("RollAngle", SIGNED_RATIONAL, 1), + 40960: ("FlashPixVersion", UNDEFINED, 1), 50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}), 50780: ("BestQualityScale", RATIONAL, 1), 50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one 50839: ("ImageJMetaData", UNDEFINED, 1), # see Issue #2006 } +TAGS_V2_GROUPS = { + # ExifIFD + 34665: { + 36864: ("ExifVersion", UNDEFINED, 1), + 40960: ("FlashPixVersion", UNDEFINED, 1), + 40965: ("InteroperabilityIFD", LONG, 1), + 41730: ("CFAPattern", UNDEFINED, 1), + }, + # GPSInfoIFD + 34853: {}, + # InteroperabilityIFD + 40965: {1: ("InteropIndex", ASCII, 1), 2: ("InteropVersion", UNDEFINED, 1)}, +} # Legacy Tags structure # these tags aren't included above, but were in the previous versions @@ -367,6 +388,10 @@ def _populate(): TAGS_V2[k] = TagInfo(k, *v) + for group, tags in TAGS_V2_GROUPS.items(): + for k, v in tags.items(): + tags[k] = TagInfo(k, *v) + _populate() ## @@ -484,9 +509,6 @@ LIBTIFF_CORE = { 65537, } -LIBTIFF_CORE.remove(301) # Array of short, crashes -LIBTIFF_CORE.remove(532) # Array of long, crashes - LIBTIFF_CORE.remove(255) # We don't have support for subfiletypes LIBTIFF_CORE.remove(322) # We don't have support for writing tiled images with libtiff LIBTIFF_CORE.remove(323) # Tiled images diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py index 2e9746fa3..b63a07ca8 100644 --- a/src/PIL/WebPImagePlugin.py +++ b/src/PIL/WebPImagePlugin.py @@ -96,7 +96,7 @@ class WebPImageFile(ImageFile.ImageFile): def _getexif(self): if "exif" not in self.info: return None - return dict(self.getexif()) + return self.getexif()._get_merged_dict() def seek(self, frame): if not self._seek_check(frame): @@ -192,7 +192,7 @@ def _save_all(im, fp, filename): r, g, b = palette[background * 3 : (background + 1) * 3] background = (r, g, b, 0) - duration = im.encoderinfo.get("duration", 0) + duration = im.encoderinfo.get("duration", im.info.get("duration")) loop = im.encoderinfo.get("loop", 0) minimize_size = im.encoderinfo.get("minimize_size", False) kmin = im.encoderinfo.get("kmin", None) @@ -314,13 +314,13 @@ def _save(im, fp, filename): if isinstance(exif, Image.Exif): exif = exif.tobytes() xmp = im.encoderinfo.get("xmp", "") - method = im.encoderinfo.get("method", 0) + method = im.encoderinfo.get("method", 4) if im.mode not in _VALID_WEBP_LEGACY_MODES: alpha = ( "A" in im.mode or "a" in im.mode - or (im.mode == "P" and "A" in im.im.getpalettemode()) + or (im.mode == "P" and "transparency" in im.info) ) im = im.convert("RGBA" if alpha else "RGB") diff --git a/src/PIL/WmfImagePlugin.py b/src/PIL/WmfImagePlugin.py index 87847a107..27f5d2f87 100644 --- a/src/PIL/WmfImagePlugin.py +++ b/src/PIL/WmfImagePlugin.py @@ -127,8 +127,8 @@ class WmfStubImageFile(ImageFile.StubImageFile): size = x1 - x0, y1 - y0 # calculate dots per inch from bbox and frame - xdpi = int(2540.0 * (x1 - y0) / (frame[2] - frame[0]) + 0.5) - ydpi = int(2540.0 * (y1 - y0) / (frame[3] - frame[1]) + 0.5) + xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0]) + ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1]) self.info["wmf_bbox"] = x0, y0, x1, y1 @@ -152,7 +152,7 @@ class WmfStubImageFile(ImageFile.StubImageFile): def load(self, dpi=None): if dpi is not None and self._inch is not None: - self.info["dpi"] = int(dpi + 0.5) + self.info["dpi"] = dpi x0, y0, x1, y1 = self.info["wmf_bbox"] self._size = ( (x1 - x0) * self.info["dpi"] // self._inch, diff --git a/src/PIL/XVThumbImagePlugin.py b/src/PIL/XVThumbImagePlugin.py index c0d8db09a..4efedb77e 100644 --- a/src/PIL/XVThumbImagePlugin.py +++ b/src/PIL/XVThumbImagePlugin.py @@ -18,7 +18,7 @@ # from . import Image, ImageFile, ImagePalette -from ._binary import i8, o8 +from ._binary import o8 _MAGIC = b"P7 332" @@ -59,7 +59,7 @@ class XVThumbImageFile(ImageFile.ImageFile): s = self.fp.readline() if not s: raise SyntaxError("Unexpected EOF reading XV thumbnail file") - if i8(s[0]) != 35: # ie. when not a comment: '#' + if s[0] != 35: # ie. when not a comment: '#' break # parse header line (already read) diff --git a/src/PIL/XpmImagePlugin.py b/src/PIL/XpmImagePlugin.py index d8bd00a1b..ebd65ba58 100644 --- a/src/PIL/XpmImagePlugin.py +++ b/src/PIL/XpmImagePlugin.py @@ -18,7 +18,7 @@ import re from . import Image, ImageFile, ImagePalette -from ._binary import i8, o8 +from ._binary import o8 # XPM header xpm_head = re.compile(b'"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)') @@ -72,7 +72,7 @@ class XpmImageFile(ImageFile.ImageFile): elif s[-1:] in b"\r\n": s = s[:-1] - c = i8(s[1]) + c = s[1] s = s[2:-2].split() for i in range(0, len(s), 2): diff --git a/src/PIL/_tkinter_finder.py b/src/PIL/_tkinter_finder.py index 7018a1b79..58aeffbfb 100644 --- a/src/PIL/_tkinter_finder.py +++ b/src/PIL/_tkinter_finder.py @@ -1,9 +1,20 @@ """ Find compiled module linking to Tcl / Tk libraries """ import sys +import tkinter +import warnings from tkinter import _tkinter as tk if hasattr(sys, "pypy_find_executable"): TKINTER_LIB = tk.tklib_cffi.__file__ else: TKINTER_LIB = tk.__file__ + +tk_version = str(tkinter.TkVersion) +if tk_version == "8.4": + warnings.warn( + "Support for Tk/Tcl 8.4 is deprecated and will be removed" + " in Pillow 10 (2023-01-02). Please upgrade to Tk/Tcl 8.5 " + "or newer.", + DeprecationWarning, + ) diff --git a/src/PIL/_version.py b/src/PIL/_version.py index 4fcb50190..8300b60e5 100644 --- a/src/PIL/_version.py +++ b/src/PIL/_version.py @@ -1,2 +1,2 @@ # Master version for Pillow -__version__ = "8.1.0.dev0" +__version__ = "8.3.0.dev0" diff --git a/src/PIL/features.py b/src/PIL/features.py index da0ca557c..3838568f3 100644 --- a/src/PIL/features.py +++ b/src/PIL/features.py @@ -9,7 +9,7 @@ from . import Image modules = { "pil": ("PIL._imaging", "PILLOW_VERSION"), - "tkinter": ("PIL._tkinter_finder", None), + "tkinter": ("PIL._tkinter_finder", "tk_version"), "freetype2": ("PIL._imagingft", "freetype2_version"), "littlecms2": ("PIL._imagingcms", "littlecms_version"), "webp": ("PIL._webp", "webpdecoder_version"), @@ -118,6 +118,8 @@ features = { "webp_mux": ("PIL._webp", "HAVE_WEBPMUX", None), "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY", None), "raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"), + "fribidi": ("PIL._imagingft", "HAVE_FRIBIDI", "fribidi_version"), + "harfbuzz": ("PIL._imagingft", "HAVE_HARFBUZZ", "harfbuzz_version"), "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"), "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"), "xcb": ("PIL._imaging", "HAVE_XCB", None), @@ -216,7 +218,7 @@ def get_supported(): def pilinfo(out=None, supported_formats=True): """ Prints information about this installation of Pillow. - This function can be called with ``python -m PIL``. + This function can be called with ``python3 -m PIL``. :param out: The output stream to print to. Defaults to ``sys.stdout`` if ``None``. @@ -274,6 +276,11 @@ def pilinfo(out=None, supported_formats=True): # this check is also in src/_imagingcms.c:setup_module() version_static = tuple(int(x) for x in v.split(".")) < (2, 7) t = "compiled for" if version_static else "loaded" + if name == "raqm": + for f in ("fribidi", "harfbuzz"): + v2 = version_feature(f) + if v2 is not None: + v += f", {f} {v2}" print("---", feature, "support ok,", t, v, file=out) else: print("---", feature, "support ok", file=out) diff --git a/src/Tk/_tkmini.h b/src/Tk/_tkmini.h index adc470532..b6945eb1a 100644 --- a/src/Tk/_tkmini.h +++ b/src/Tk/_tkmini.h @@ -79,18 +79,20 @@ typedef struct Tcl_Interp Tcl_Interp; typedef struct Tcl_Command_ *Tcl_Command; typedef void *ClientData; -typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp - *interp, int argc, const char *argv[]); -typedef void (Tcl_CmdDeleteProc) (ClientData clientData); +typedef int(Tcl_CmdProc)( + ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]); +typedef void(Tcl_CmdDeleteProc)(ClientData clientData); /* Typedefs derived from function signatures in Tcl header */ /* Tcl_CreateCommand */ -typedef Tcl_Command (*Tcl_CreateCommand_t)(Tcl_Interp *interp, - const char *cmdName, Tcl_CmdProc *proc, - ClientData clientData, - Tcl_CmdDeleteProc *deleteProc); +typedef Tcl_Command (*Tcl_CreateCommand_t)( + Tcl_Interp *interp, + const char *cmdName, + Tcl_CmdProc *proc, + ClientData clientData, + Tcl_CmdDeleteProc *deleteProc); /* Tcl_AppendResult */ -typedef void (*Tcl_AppendResult_t) (Tcl_Interp *interp, ...); +typedef void (*Tcl_AppendResult_t)(Tcl_Interp *interp, ...); /* Tk header excerpts */ @@ -107,8 +109,7 @@ typedef struct Tk_Window_ *Tk_Window; typedef void *Tk_PhotoHandle; -typedef struct Tk_PhotoImageBlock -{ +typedef struct Tk_PhotoImageBlock { unsigned char *pixelPtr; int width; int height; @@ -119,23 +120,30 @@ typedef struct Tk_PhotoImageBlock /* Typedefs derived from function signatures in Tk header */ /* Tk_PhotoPutBlock for Tk <= 8.4 */ -typedef void (*Tk_PhotoPutBlock_84_t) (Tk_PhotoHandle handle, - Tk_PhotoImageBlock *blockPtr, int x, int y, - int width, int height, int compRule); +typedef void (*Tk_PhotoPutBlock_84_t)( + Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, + int x, + int y, + int width, + int height, + int compRule); /* Tk_PhotoPutBlock for Tk >= 8.5 */ -typedef int (*Tk_PhotoPutBlock_85_t) (Tcl_Interp * interp, - Tk_PhotoHandle handle, - Tk_PhotoImageBlock * blockPtr, int x, int y, - int width, int height, int compRule); +typedef int (*Tk_PhotoPutBlock_85_t)( + Tcl_Interp *interp, + Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, + int x, + int y, + int width, + int height, + int compRule); /* Tk_PhotoSetSize for Tk <= 8.4 */ -typedef void (*Tk_PhotoSetSize_84_t) (Tk_PhotoHandle handle, - int width, int height); +typedef void (*Tk_PhotoSetSize_84_t)(Tk_PhotoHandle handle, int width, int height); /* Tk_FindPhoto */ -typedef Tk_PhotoHandle (*Tk_FindPhoto_t) (Tcl_Interp *interp, - const char *imageName); +typedef Tk_PhotoHandle (*Tk_FindPhoto_t)(Tcl_Interp *interp, const char *imageName); /* Tk_PhotoGetImage */ -typedef int (*Tk_PhotoGetImage_t) (Tk_PhotoHandle handle, - Tk_PhotoImageBlock * blockPtr); +typedef int (*Tk_PhotoGetImage_t)(Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr); /* * end block for C++ diff --git a/src/Tk/tkImaging.c b/src/Tk/tkImaging.c index 5df3abb72..1c6c5f34a 100644 --- a/src/Tk/tkImaging.c +++ b/src/Tk/tkImaging.c @@ -58,8 +58,7 @@ static Tk_PhotoSetSize_84_t TK_PHOTO_SET_SIZE_84; static Tk_PhotoPutBlock_85_t TK_PHOTO_PUT_BLOCK_85; static Imaging -ImagingFind(const char* name) -{ +ImagingFind(const char *name) { Py_ssize_t id; /* FIXME: use CObject instead? */ @@ -72,41 +71,37 @@ ImagingFind(const char* name) return NULL; } - return (Imaging) id; + return (Imaging)id; } - static int -PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp, - int argc, const char **argv) -{ +PyImagingPhotoPut( + ClientData clientdata, Tcl_Interp *interp, int argc, const char **argv) { Imaging im; Tk_PhotoHandle photo; Tk_PhotoImageBlock block; if (argc != 3) { - TCL_APPEND_RESULT(interp, "usage: ", argv[0], - " destPhoto srcImage", (char *) NULL); + TCL_APPEND_RESULT( + interp, "usage: ", argv[0], " destPhoto srcImage", (char *)NULL); return TCL_ERROR; } /* get Tcl PhotoImage handle */ photo = TK_FIND_PHOTO(interp, argv[1]); if (photo == NULL) { - TCL_APPEND_RESULT( - interp, "destination photo must exist", (char *) NULL - ); + TCL_APPEND_RESULT(interp, "destination photo must exist", (char *)NULL); return TCL_ERROR; } /* get PIL Image handle */ im = ImagingFind(argv[2]); if (!im) { - TCL_APPEND_RESULT(interp, "bad name", (char*) NULL); + TCL_APPEND_RESULT(interp, "bad name", (char *)NULL); return TCL_ERROR; } if (!im->block) { - TCL_APPEND_RESULT(interp, "bad display memory", (char*) NULL); + TCL_APPEND_RESULT(interp, "bad display memory", (char *)NULL); return TCL_ERROR; } @@ -126,18 +121,18 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp, block.offset[3] = 0; /* no alpha */ } } else { - TCL_APPEND_RESULT(interp, "Bad mode", (char*) NULL); + TCL_APPEND_RESULT(interp, "Bad mode", (char *)NULL); return TCL_ERROR; } block.width = im->xsize; block.height = im->ysize; block.pitch = im->linesize; - block.pixelPtr = (unsigned char*) im->block; + block.pixelPtr = (unsigned char *)im->block; if (TK_LT_85) { /* Tk 8.4 */ - TK_PHOTO_PUT_BLOCK_84(photo, &block, 0, 0, block.width, block.height, - TK_PHOTO_COMPOSITE_SET); + TK_PHOTO_PUT_BLOCK_84( + photo, &block, 0, 0, block.width, block.height, TK_PHOTO_COMPOSITE_SET); if (strcmp(im->mode, "RGBA") == 0) { /* Tk workaround: we need apply ToggleComplexAlphaIfNeeded */ /* (fixed in Tk 8.5a3) */ @@ -145,50 +140,54 @@ PyImagingPhotoPut(ClientData clientdata, Tcl_Interp* interp, } } else { /* Tk >=8.5 */ - TK_PHOTO_PUT_BLOCK_85(interp, photo, &block, 0, 0, block.width, - block.height, TK_PHOTO_COMPOSITE_SET); + TK_PHOTO_PUT_BLOCK_85( + interp, + photo, + &block, + 0, + 0, + block.width, + block.height, + TK_PHOTO_COMPOSITE_SET); } return TCL_OK; } static int -PyImagingPhotoGet(ClientData clientdata, Tcl_Interp* interp, - int argc, const char **argv) -{ +PyImagingPhotoGet( + ClientData clientdata, Tcl_Interp *interp, int argc, const char **argv) { Imaging im; Tk_PhotoHandle photo; Tk_PhotoImageBlock block; int x, y, z; if (argc != 3) { - TCL_APPEND_RESULT(interp, "usage: ", argv[0], - " srcPhoto destImage", (char *) NULL); + TCL_APPEND_RESULT( + interp, "usage: ", argv[0], " srcPhoto destImage", (char *)NULL); return TCL_ERROR; } /* get Tcl PhotoImage handle */ photo = TK_FIND_PHOTO(interp, argv[1]); if (photo == NULL) { - TCL_APPEND_RESULT( - interp, "source photo must exist", (char *) NULL - ); + TCL_APPEND_RESULT(interp, "source photo must exist", (char *)NULL); return TCL_ERROR; } /* get PIL Image handle */ im = ImagingFind(argv[2]); if (!im) { - TCL_APPEND_RESULT(interp, "bad name", (char*) NULL); + TCL_APPEND_RESULT(interp, "bad name", (char *)NULL); return TCL_ERROR; } TK_PHOTO_GET_IMAGE(photo, &block); for (y = 0; y < block.height; y++) { - UINT8* out = (UINT8*)im->image32[y]; + UINT8 *out = (UINT8 *)im->image32[y]; for (x = 0; x < block.pitch; x += block.pixelSize) { - for (z=0; z < block.pixelSize; z++) { + for (z = 0; z < block.pixelSize; z++) { int offset = block.offset[z]; out[x + offset] = block.pixelPtr[y * block.pitch + x + offset]; } @@ -198,14 +197,20 @@ PyImagingPhotoGet(ClientData clientdata, Tcl_Interp* interp, return TCL_OK; } - void -TkImaging_Init(Tcl_Interp* interp) -{ - TCL_CREATE_COMMAND(interp, "PyImagingPhoto", PyImagingPhotoPut, - (ClientData) 0, (Tcl_CmdDeleteProc*) NULL); - TCL_CREATE_COMMAND(interp, "PyImagingPhotoGet", PyImagingPhotoGet, - (ClientData) 0, (Tcl_CmdDeleteProc*) NULL); +TkImaging_Init(Tcl_Interp *interp) { + TCL_CREATE_COMMAND( + interp, + "PyImagingPhoto", + PyImagingPhotoPut, + (ClientData)0, + (Tcl_CmdDeleteProc *)NULL); + TCL_CREATE_COMMAND( + interp, + "PyImagingPhotoGet", + PyImagingPhotoGet, + (ClientData)0, + (Tcl_CmdDeleteProc *)NULL); } /* @@ -230,13 +235,13 @@ TkImaging_Init(Tcl_Interp* interp) #define TKINTER_PKG "tkinter" -FARPROC _dfunc(HMODULE lib_handle, const char *func_name) -{ +FARPROC +_dfunc(HMODULE lib_handle, const char *func_name) { /* * Load function `func_name` from `lib_handle`. * Set Python exception if we can't find `func_name` in `lib_handle`. * Returns function pointer or NULL if not present. - */ + */ char message[100]; @@ -248,24 +253,26 @@ FARPROC _dfunc(HMODULE lib_handle, const char *func_name) return func; } -int get_tcl(HMODULE hMod) -{ +int +get_tcl(HMODULE hMod) { /* * Try to fill Tcl global vars with function pointers. Return 0 for no * functions found, 1 for all functions found, -1 for some but not all * functions found. */ - if ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) - GetProcAddress(hMod, "Tcl_CreateCommand")) == NULL) { + if ((TCL_CREATE_COMMAND = + (Tcl_CreateCommand_t)GetProcAddress(hMod, "Tcl_CreateCommand")) == NULL) { return 0; /* Maybe not Tcl module */ } - return ((TCL_APPEND_RESULT = (Tcl_AppendResult_t) _dfunc(hMod, - "Tcl_AppendResult")) == NULL) ? -1 : 1; + return ((TCL_APPEND_RESULT = + (Tcl_AppendResult_t)_dfunc(hMod, "Tcl_AppendResult")) == NULL) + ? -1 + : 1; } -int get_tk(HMODULE hMod) -{ +int +get_tk(HMODULE hMod) { /* * Try to fill Tk global vars with function pointers. Return 0 for no * functions found, 1 for all functions found, -1 for some but not all @@ -273,26 +280,31 @@ int get_tk(HMODULE hMod) */ FARPROC func = GetProcAddress(hMod, "Tk_PhotoPutBlock"); - if (func == NULL) { /* Maybe not Tk module */ + if (func == NULL) { /* Maybe not Tk module */ return 0; } - if ((TK_PHOTO_GET_IMAGE = (Tk_PhotoGetImage_t) - _dfunc(hMod, "Tk_PhotoGetImage")) == NULL) { return -1; }; - if ((TK_FIND_PHOTO = (Tk_FindPhoto_t) - _dfunc(hMod, "Tk_FindPhoto")) == NULL) { return -1; }; + if ((TK_PHOTO_GET_IMAGE = (Tk_PhotoGetImage_t)_dfunc(hMod, "Tk_PhotoGetImage")) == + NULL) { + return -1; + }; + if ((TK_FIND_PHOTO = (Tk_FindPhoto_t)_dfunc(hMod, "Tk_FindPhoto")) == NULL) { + return -1; + }; TK_LT_85 = GetProcAddress(hMod, "Tk_PhotoPutBlock_Panic") == NULL; /* Tk_PhotoPutBlock_Panic defined as of 8.5.0 */ if (TK_LT_85) { - TK_PHOTO_PUT_BLOCK_84 = (Tk_PhotoPutBlock_84_t) func; - return ((TK_PHOTO_SET_SIZE_84 = (Tk_PhotoSetSize_84_t) - _dfunc(hMod, "Tk_PhotoSetSize")) == NULL) ? -1 : 1; + TK_PHOTO_PUT_BLOCK_84 = (Tk_PhotoPutBlock_84_t)func; + return ((TK_PHOTO_SET_SIZE_84 = + (Tk_PhotoSetSize_84_t)_dfunc(hMod, "Tk_PhotoSetSize")) == NULL) + ? -1 + : 1; } - TK_PHOTO_PUT_BLOCK_85 = (Tk_PhotoPutBlock_85_t) func; + TK_PHOTO_PUT_BLOCK_85 = (Tk_PhotoPutBlock_85_t)func; return 1; } -int load_tkinter_funcs(void) -{ +int +load_tkinter_funcs(void) { /* * Load Tcl and Tk functions by searching all modules in current process. * Return 0 for success, non-zero for failure. @@ -344,7 +356,7 @@ int load_tkinter_funcs(void) return 1; } -#else /* not Windows */ +#else /* not Windows */ /* * On Unix, we can get the Tcl and Tk symbols from the tkinter module, because @@ -353,9 +365,9 @@ int load_tkinter_funcs(void) */ /* From module __file__ attribute to char *string for dlopen. */ -char *fname2char(PyObject *fname) -{ - PyObject* bytes; +char * +fname2char(PyObject *fname) { + PyObject *bytes; bytes = PyUnicode_EncodeFSDefault(fname); if (bytes == NULL) { return NULL; @@ -365,15 +377,15 @@ char *fname2char(PyObject *fname) #include -void *_dfunc(void *lib_handle, const char *func_name) -{ +void * +_dfunc(void *lib_handle, const char *func_name) { /* * Load function `func_name` from `lib_handle`. * Set Python exception if we can't find `func_name` in `lib_handle`. * Returns function pointer or NULL if not present. */ - void* func; + void *func; /* Reset errors. */ dlerror(); func = dlsym(lib_handle, func_name); @@ -384,35 +396,44 @@ void *_dfunc(void *lib_handle, const char *func_name) return func; } -int _func_loader(void *lib) -{ +int +_func_loader(void *lib) { /* * Fill global function pointers from dynamic lib. * Return 1 if any pointer is NULL, 0 otherwise. */ - if ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) - _dfunc(lib, "Tcl_CreateCommand")) == NULL) { return 1; } - if ((TCL_APPEND_RESULT = (Tcl_AppendResult_t) _dfunc(lib, - "Tcl_AppendResult")) == NULL) { return 1; } - if ((TK_PHOTO_GET_IMAGE = (Tk_PhotoGetImage_t) - _dfunc(lib, "Tk_PhotoGetImage")) == NULL) { return 1; } - if ((TK_FIND_PHOTO = (Tk_FindPhoto_t) - _dfunc(lib, "Tk_FindPhoto")) == NULL) { return 1; } + if ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t)_dfunc(lib, "Tcl_CreateCommand")) == + NULL) { + return 1; + } + if ((TCL_APPEND_RESULT = (Tcl_AppendResult_t)_dfunc(lib, "Tcl_AppendResult")) == + NULL) { + return 1; + } + if ((TK_PHOTO_GET_IMAGE = (Tk_PhotoGetImage_t)_dfunc(lib, "Tk_PhotoGetImage")) == + NULL) { + return 1; + } + if ((TK_FIND_PHOTO = (Tk_FindPhoto_t)_dfunc(lib, "Tk_FindPhoto")) == NULL) { + return 1; + } /* Tk_PhotoPutBlock_Panic defined as of 8.5.0 */ TK_LT_85 = (dlsym(lib, "Tk_PhotoPutBlock_Panic") == NULL); if (TK_LT_85) { - return (((TK_PHOTO_PUT_BLOCK_84 = (Tk_PhotoPutBlock_84_t) - _dfunc(lib, "Tk_PhotoPutBlock")) == NULL) || - ((TK_PHOTO_SET_SIZE_84 = (Tk_PhotoSetSize_84_t) - _dfunc(lib, "Tk_PhotoSetSize")) == NULL)); + return ( + ((TK_PHOTO_PUT_BLOCK_84 = + (Tk_PhotoPutBlock_84_t)_dfunc(lib, "Tk_PhotoPutBlock")) == NULL) || + ((TK_PHOTO_SET_SIZE_84 = + (Tk_PhotoSetSize_84_t)_dfunc(lib, "Tk_PhotoSetSize")) == NULL)); } - return ((TK_PHOTO_PUT_BLOCK_85 = (Tk_PhotoPutBlock_85_t) - _dfunc(lib, "Tk_PhotoPutBlock")) == NULL); + return ( + (TK_PHOTO_PUT_BLOCK_85 = + (Tk_PhotoPutBlock_85_t)_dfunc(lib, "Tk_PhotoPutBlock")) == NULL); } -int load_tkinter_funcs(void) -{ +int +load_tkinter_funcs(void) { /* * Load tkinter global funcs from tkinter compiled module. * Return 0 for success, non-zero for failure. @@ -447,8 +468,7 @@ int load_tkinter_funcs(void) } tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); if (tkinter_lib == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Cannot dlopen tkinter module file"); + PyErr_SetString(PyExc_RuntimeError, "Cannot dlopen tkinter module file"); goto exit; } ret = _func_loader(tkinter_lib); diff --git a/src/_imaging.c b/src/_imaging.c index 0f8c9d61f..e2193fec3 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -94,31 +94,30 @@ #include /* Configuration stuff. Feel free to undef things you don't need. */ -#define WITH_IMAGECHOPS /* ImageChops support */ -#define WITH_IMAGEDRAW /* ImageDraw support */ -#define WITH_MAPPING /* use memory mapping to read some file formats */ -#define WITH_IMAGEPATH /* ImagePath stuff */ -#define WITH_ARROW /* arrow graphics stuff (experimental) */ -#define WITH_EFFECTS /* special effects */ -#define WITH_QUANTIZE /* quantization support */ -#define WITH_RANKFILTER /* rank filter */ -#define WITH_MODEFILTER /* mode filter */ -#define WITH_THREADING /* "friendly" threading support */ +#define WITH_IMAGECHOPS /* ImageChops support */ +#define WITH_IMAGEDRAW /* ImageDraw support */ +#define WITH_MAPPING /* use memory mapping to read some file formats */ +#define WITH_IMAGEPATH /* ImagePath stuff */ +#define WITH_ARROW /* arrow graphics stuff (experimental) */ +#define WITH_EFFECTS /* special effects */ +#define WITH_QUANTIZE /* quantization support */ +#define WITH_RANKFILTER /* rank filter */ +#define WITH_MODEFILTER /* mode filter */ +#define WITH_THREADING /* "friendly" threading support */ #define WITH_UNSHARPMASK /* Kevin Cazabon's unsharpmask module */ -#undef VERBOSE +#undef VERBOSE -#define B16(p, i) ((((int)p[(i)]) << 8) + p[(i)+1]) -#define L16(p, i) ((((int)p[(i)+1]) << 8) + p[(i)]) -#define S16(v) ((v) < 32768 ? (v) : ((v) - 65536)) +#define B16(p, i) ((((int)p[(i)]) << 8) + p[(i) + 1]) +#define L16(p, i) ((((int)p[(i) + 1]) << 8) + p[(i)]) +#define S16(v) ((v) < 32768 ? (v) : ((v)-65536)) /* -------------------------------------------------------------------- */ /* OBJECT ADMINISTRATION */ /* -------------------------------------------------------------------- */ typedef struct { - PyObject_HEAD - Imaging image; + PyObject_HEAD Imaging image; ImagingAccess access; } ImagingObject; @@ -126,8 +125,7 @@ static PyTypeObject Imaging_Type; #ifdef WITH_IMAGEDRAW -typedef struct -{ +typedef struct { /* to write a character, cut out sxy from glyph data, place at current position plus dxy, and advance by (dx, dy) */ int dx, dy; @@ -136,8 +134,7 @@ typedef struct } Glyph; typedef struct { - PyObject_HEAD - ImagingObject* ref; + PyObject_HEAD ImagingObject *ref; Imaging bitmap; int ysize; int baseline; @@ -147,8 +144,7 @@ typedef struct { static PyTypeObject ImagingFont_Type; typedef struct { - PyObject_HEAD - ImagingObject* image; + PyObject_HEAD ImagingObject *image; UINT8 ink[4]; int blend; } ImagingDrawObject; @@ -158,17 +154,15 @@ static PyTypeObject ImagingDraw_Type; #endif typedef struct { - PyObject_HEAD - ImagingObject* image; + PyObject_HEAD ImagingObject *image; int readonly; } PixelAccessObject; static PyTypeObject PixelAccess_Type; -PyObject* -PyImagingNew(Imaging imOut) -{ - ImagingObject* imagep; +PyObject * +PyImagingNew(Imaging imOut) { + ImagingObject *imagep; if (!imOut) { return NULL; @@ -187,13 +181,11 @@ PyImagingNew(Imaging imOut) imagep->image = imOut; imagep->access = ImagingAccessNew(imOut); - return (PyObject*) imagep; + return (PyObject *)imagep; } static void -_dealloc(ImagingObject* imagep) -{ - +_dealloc(ImagingObject *imagep) { #ifdef VERBOSE printf("imaging %p deleted\n", imagep); #endif @@ -207,8 +199,8 @@ _dealloc(ImagingObject* imagep) #define PyImaging_Check(op) (Py_TYPE(op) == &Imaging_Type) -Imaging PyImaging_AsImaging(PyObject *op) -{ +Imaging +PyImaging_AsImaging(PyObject *op) { if (!PyImaging_Check(op)) { PyErr_BadInternalCall(); return NULL; @@ -217,22 +209,21 @@ Imaging PyImaging_AsImaging(PyObject *op) return ((ImagingObject *)op)->image; } - /* -------------------------------------------------------------------- */ /* THREAD HANDLING */ /* -------------------------------------------------------------------- */ -void ImagingSectionEnter(ImagingSectionCookie* cookie) -{ +void +ImagingSectionEnter(ImagingSectionCookie *cookie) { #ifdef WITH_THREADING - *cookie = (PyThreadState *) PyEval_SaveThread(); + *cookie = (PyThreadState *)PyEval_SaveThread(); #endif } -void ImagingSectionLeave(ImagingSectionCookie* cookie) -{ +void +ImagingSectionLeave(ImagingSectionCookie *cookie) { #ifdef WITH_THREADING - PyEval_RestoreThread((PyThreadState*) *cookie); + PyEval_RestoreThread((PyThreadState *)*cookie); #endif } @@ -241,13 +232,13 @@ void ImagingSectionLeave(ImagingSectionCookie* cookie) /* -------------------------------------------------------------------- */ /* Python compatibility API */ -int PyImaging_CheckBuffer(PyObject* buffer) -{ +int +PyImaging_CheckBuffer(PyObject *buffer) { return PyObject_CheckBuffer(buffer); } -int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view) -{ +int +PyImaging_GetBuffer(PyObject *buffer, Py_buffer *view) { /* must call check_buffer first! */ return PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE); } @@ -257,58 +248,50 @@ int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view) /* -------------------------------------------------------------------- */ /* error messages */ -static const char* must_be_sequence = "argument must be a sequence"; -static const char* must_be_two_coordinates = - "coordinate list must contain exactly 2 coordinates"; -static const char* wrong_mode = "unrecognized image mode"; -static const char* wrong_raw_mode = "unrecognized raw mode"; -static const char* outside_image = "image index out of range"; -static const char* outside_palette = "palette index out of range"; -static const char* wrong_palette_size = "invalid palette size"; -static const char* no_palette = "image has no palette"; -static const char* readonly = "image is readonly"; +static const char *must_be_sequence = "argument must be a sequence"; +static const char *must_be_two_coordinates = + "coordinate list must contain exactly 2 coordinates"; +static const char *wrong_mode = "unrecognized image mode"; +static const char *wrong_raw_mode = "unrecognized raw mode"; +static const char *outside_image = "image index out of range"; +static const char *outside_palette = "palette index out of range"; +static const char *wrong_palette_size = "invalid palette size"; +static const char *no_palette = "image has no palette"; +static const char *readonly = "image is readonly"; /* static const char* no_content = "image has no content"; */ void * -ImagingError_OSError(void) -{ +ImagingError_OSError(void) { PyErr_SetString(PyExc_OSError, "error when accessing file"); return NULL; } void * -ImagingError_MemoryError(void) -{ +ImagingError_MemoryError(void) { return PyErr_NoMemory(); } void * -ImagingError_Mismatch(void) -{ +ImagingError_Mismatch(void) { PyErr_SetString(PyExc_ValueError, "images do not match"); return NULL; } void * -ImagingError_ModeError(void) -{ +ImagingError_ModeError(void) { PyErr_SetString(PyExc_ValueError, "image has wrong mode"); return NULL; } void * -ImagingError_ValueError(const char *message) -{ +ImagingError_ValueError(const char *message) { PyErr_SetString( - PyExc_ValueError, - (message) ? (char*) message : "unrecognized argument value" - ); + PyExc_ValueError, (message) ? (char *)message : "unrecognized argument value"); return NULL; } void -ImagingError_Clear(void) -{ +ImagingError_Clear(void) { PyErr_Clear(); } @@ -317,8 +300,7 @@ ImagingError_Clear(void) /* -------------------------------------------------------------------- */ static int -getbands(const char* mode) -{ +getbands(const char *mode) { Imaging im; int bands; @@ -335,15 +317,14 @@ getbands(const char* mode) return bands; } -#define TYPE_UINT8 (0x100|sizeof(UINT8)) -#define TYPE_INT32 (0x200|sizeof(INT32)) -#define TYPE_FLOAT16 (0x500|sizeof(FLOAT16)) -#define TYPE_FLOAT32 (0x300|sizeof(FLOAT32)) -#define TYPE_DOUBLE (0x400|sizeof(double)) +#define TYPE_UINT8 (0x100 | sizeof(UINT8)) +#define TYPE_INT32 (0x200 | sizeof(INT32)) +#define TYPE_FLOAT16 (0x500 | sizeof(FLOAT16)) +#define TYPE_FLOAT32 (0x300 | sizeof(FLOAT32)) +#define TYPE_DOUBLE (0x400 | sizeof(double)) -static void* -getlist(PyObject* arg, Py_ssize_t* length, const char* wrong_length, int type) -{ +static void * +getlist(PyObject *arg, Py_ssize_t *length, const char *wrong_length, int type) { /* - allocates and returns a c array of the items in the python sequence arg. - the size of the returned array is in length @@ -358,11 +339,11 @@ getlist(PyObject* arg, Py_ssize_t* length, const char* wrong_length, int type) int itemp; double dtemp; FLOAT32 ftemp; - UINT8* list; - PyObject* seq; - PyObject* op; + UINT8 *list; + PyObject *seq; + PyObject *op; - if ( ! PySequence_Check(arg)) { + if (!PySequence_Check(arg)) { PyErr_SetString(PyExc_TypeError, must_be_sequence); return NULL; } @@ -376,12 +357,12 @@ getlist(PyObject* arg, Py_ssize_t* length, const char* wrong_length, int type) /* malloc check ok, type & ff is just a sizeof(something) calloc checks for overflow */ list = calloc(n, type & 0xff); - if ( ! list) { + if (!list) { return ImagingError_MemoryError(); } seq = PySequence_Fast(arg, must_be_sequence); - if ( ! seq) { + if (!seq) { free(list); return NULL; } @@ -391,22 +372,22 @@ getlist(PyObject* arg, Py_ssize_t* length, const char* wrong_length, int type) // DRY, branch prediction is going to work _really_ well // on this switch. And 3 fewer loops to copy/paste. switch (type) { - case TYPE_UINT8: - itemp = PyLong_AsLong(op); - list[i] = CLIP8(itemp); - break; - case TYPE_INT32: - itemp = PyLong_AsLong(op); - memcpy(list + i * sizeof(INT32), &itemp, sizeof(itemp)); - break; - case TYPE_FLOAT32: - ftemp = (FLOAT32)PyFloat_AsDouble(op); - memcpy(list + i * sizeof(ftemp), &ftemp, sizeof(ftemp)); - break; - case TYPE_DOUBLE: - dtemp = PyFloat_AsDouble(op); - memcpy(list + i * sizeof(dtemp), &dtemp, sizeof(dtemp)); - break; + case TYPE_UINT8: + itemp = PyLong_AsLong(op); + list[i] = CLIP8(itemp); + break; + case TYPE_INT32: + itemp = PyLong_AsLong(op); + memcpy(list + i * sizeof(INT32), &itemp, sizeof(itemp)); + break; + case TYPE_FLOAT32: + ftemp = (FLOAT32)PyFloat_AsDouble(op); + memcpy(list + i * sizeof(ftemp), &ftemp, sizeof(ftemp)); + break; + case TYPE_DOUBLE: + dtemp = PyFloat_AsDouble(op); + memcpy(list + i * sizeof(dtemp), &dtemp, sizeof(dtemp)); + break; } } @@ -431,31 +412,30 @@ float16tofloat32(const FLOAT16 in) { UINT32 t3; FLOAT32 out[1] = {0}; - t1 = in & 0x7fff; // Non-sign bits - t2 = in & 0x8000; // Sign bit - t3 = in & 0x7c00; // Exponent + t1 = in & 0x7fff; // Non-sign bits + t2 = in & 0x8000; // Sign bit + t3 = in & 0x7c00; // Exponent - t1 <<= 13; // Align mantissa on MSB - t2 <<= 16; // Shift sign bit into position + t1 <<= 13; // Align mantissa on MSB + t2 <<= 16; // Shift sign bit into position - t1 += 0x38000000; // Adjust bias + t1 += 0x38000000; // Adjust bias - t1 = (t3 == 0 ? 0 : t1); // Denormals-as-zero + t1 = (t3 == 0 ? 0 : t1); // Denormals-as-zero - t1 |= t2; // Re-insert sign bit + t1 |= t2; // Re-insert sign bit memcpy(out, &t1, 4); return out[0]; } -static inline PyObject* -getpixel(Imaging im, ImagingAccess access, int x, int y) -{ +static inline PyObject * +getpixel(Imaging im, ImagingAccess access, int x, int y) { union { - UINT8 b[4]; - UINT16 h; - INT32 i; - FLOAT32 f; + UINT8 b[4]; + UINT16 h; + INT32 i; + FLOAT32 f; } pixel; if (x < 0) { @@ -473,27 +453,28 @@ getpixel(Imaging im, ImagingAccess access, int x, int y) access->get_pixel(im, x, y, &pixel); switch (im->type) { - case IMAGING_TYPE_UINT8: - switch (im->bands) { - case 1: - return PyLong_FromLong(pixel.b[0]); - case 2: - return Py_BuildValue("BB", pixel.b[0], pixel.b[1]); - case 3: - return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]); - case 4: - return Py_BuildValue("BBBB", pixel.b[0], pixel.b[1], pixel.b[2], pixel.b[3]); - } - break; - case IMAGING_TYPE_INT32: - return PyLong_FromLong(pixel.i); - case IMAGING_TYPE_FLOAT32: - return PyFloat_FromDouble(pixel.f); - case IMAGING_TYPE_SPECIAL: - if (strncmp(im->mode, "I;16", 4) == 0) { - return PyLong_FromLong(pixel.h); - } - break; + case IMAGING_TYPE_UINT8: + switch (im->bands) { + case 1: + return PyLong_FromLong(pixel.b[0]); + case 2: + return Py_BuildValue("BB", pixel.b[0], pixel.b[1]); + case 3: + return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]); + case 4: + return Py_BuildValue( + "BBBB", pixel.b[0], pixel.b[1], pixel.b[2], pixel.b[3]); + } + break; + case IMAGING_TYPE_INT32: + return PyLong_FromLong(pixel.i); + case IMAGING_TYPE_FLOAT32: + return PyFloat_FromDouble(pixel.f); + case IMAGING_TYPE_SPECIAL: + if (strncmp(im->mode, "I;16", 4) == 0) { + return PyLong_FromLong(pixel.h); + } + break; } /* unknown type */ @@ -501,11 +482,10 @@ getpixel(Imaging im, ImagingAccess access, int x, int y) return Py_None; } -static char* -getink(PyObject* color, Imaging im, char* ink) -{ - int g=0, b=0, a=0; - double f=0; +static char * +getink(PyObject *color, Imaging im, char *ink) { + int g = 0, b = 0, a = 0; + double f = 0; /* Windows 64 bit longs are 32 bits, and 0xFFFFFFFF (white) is a python long (not int) that raises an overflow error when trying to return it into a 32 bit C long @@ -518,11 +498,10 @@ getink(PyObject* color, Imaging im, char* ink) be cast to either UINT8 or INT32 */ int rIsInt = 0; - if (PyTuple_Check(color) && PyTuple_Size(color) == 1) { + if (PyTuple_Check(color) && PyTuple_GET_SIZE(color) == 1) { color = PyTuple_GetItem(color, 0); } - if (im->type == IMAGING_TYPE_UINT8 || - im->type == IMAGING_TYPE_INT32 || + if (im->type == IMAGING_TYPE_UINT8 || im->type == IMAGING_TYPE_INT32 || im->type == IMAGING_TYPE_SPECIAL) { if (PyLong_Check(color)) { r = PyLong_AsLongLong(color); @@ -536,70 +515,81 @@ getink(PyObject* color, Imaging im, char* ink) return NULL; } } else { - PyErr_SetString(PyExc_TypeError, "color must be int or single-element tuple"); + PyErr_SetString( + PyExc_TypeError, "color must be int or single-element tuple"); return NULL; } } switch (im->type) { - case IMAGING_TYPE_UINT8: - /* unsigned integer */ - if (im->bands == 1) { - /* unsigned integer, single layer */ - if (rIsInt != 1) { - if (!PyArg_ParseTuple(color, "L", &r)) { - return NULL; + case IMAGING_TYPE_UINT8: + /* unsigned integer */ + if (im->bands == 1) { + /* unsigned integer, single layer */ + if (rIsInt != 1) { + if (PyTuple_GET_SIZE(color) != 1) { + PyErr_SetString(PyExc_TypeError, "color must be int or single-element tuple"); + return NULL; + } else if (!PyArg_ParseTuple(color, "L", &r)) { + return NULL; + } } - } - ink[0] = (char) CLIP8(r); - ink[1] = ink[2] = ink[3] = 0; - } else { - a = 255; - if (rIsInt) { - /* compatibility: ABGR */ - a = (UINT8) (r >> 24); - b = (UINT8) (r >> 16); - g = (UINT8) (r >> 8); - r = (UINT8) r; + ink[0] = (char)CLIP8(r); + ink[1] = ink[2] = ink[3] = 0; } else { - if (im->bands == 2) { - if (!PyArg_ParseTuple(color, "L|i", &r, &a)) { - return NULL; - } - g = b = r; + a = 255; + if (rIsInt) { + /* compatibility: ABGR */ + a = (UINT8)(r >> 24); + b = (UINT8)(r >> 16); + g = (UINT8)(r >> 8); + r = (UINT8)r; } else { - if (!PyArg_ParseTuple(color, "Lii|i", &r, &g, &b, &a)) { - return NULL; + int tupleSize = PyTuple_GET_SIZE(color); + if (im->bands == 2) { + if (tupleSize != 1 && tupleSize != 2) { + PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one or two elements"); + return NULL; + } else if (!PyArg_ParseTuple(color, "L|i", &r, &a)) { + return NULL; + } + g = b = r; + } else { + if (tupleSize != 3 && tupleSize != 4) { + PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one, three or four elements"); + return NULL; + } else if (!PyArg_ParseTuple(color, "Lii|i", &r, &g, &b, &a)) { + return NULL; + } } } + ink[0] = (char)CLIP8(r); + ink[1] = (char)CLIP8(g); + ink[2] = (char)CLIP8(b); + ink[3] = (char)CLIP8(a); } - ink[0] = (char) CLIP8(r); - ink[1] = (char) CLIP8(g); - ink[2] = (char) CLIP8(b); - ink[3] = (char) CLIP8(a); - } - return ink; - case IMAGING_TYPE_INT32: - /* signed integer */ - itmp = r; - memcpy(ink, &itmp, sizeof(itmp)); - return ink; - case IMAGING_TYPE_FLOAT32: - /* floating point */ - f = PyFloat_AsDouble(color); - if (f == -1.0 && PyErr_Occurred()) { - return NULL; - } - ftmp = f; - memcpy(ink, &ftmp, sizeof(ftmp)); - return ink; - case IMAGING_TYPE_SPECIAL: - if (strncmp(im->mode, "I;16", 4) == 0) { - ink[0] = (UINT8) r; - ink[1] = (UINT8) (r >> 8); - ink[2] = ink[3] = 0; return ink; - } + case IMAGING_TYPE_INT32: + /* signed integer */ + itmp = r; + memcpy(ink, &itmp, sizeof(itmp)); + return ink; + case IMAGING_TYPE_FLOAT32: + /* floating point */ + f = PyFloat_AsDouble(color); + if (f == -1.0 && PyErr_Occurred()) { + return NULL; + } + ftmp = f; + memcpy(ink, &ftmp, sizeof(ftmp)); + return ink; + case IMAGING_TYPE_SPECIAL: + if (strncmp(im->mode, "I;16", 4) == 0) { + ink[0] = (UINT8)r; + ink[1] = (UINT8)(r >> 8); + ink[2] = ink[3] = 0; + return ink; + } } PyErr_SetString(PyExc_ValueError, wrong_mode); @@ -610,12 +600,11 @@ getink(PyObject* color, Imaging im, char* ink) /* FACTORIES */ /* -------------------------------------------------------------------- */ -static PyObject* -_fill(PyObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_fill(PyObject *self, PyObject *args) { + char *mode; int xsize, ysize; - PyObject* color; + PyObject *color; char buffer[4]; Imaging im; @@ -639,16 +628,14 @@ _fill(PyObject* self, PyObject* args) } } - - (void) ImagingFill(im, buffer); + (void)ImagingFill(im, buffer); return PyImagingNew(im); } -static PyObject* -_new(PyObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_new(PyObject *self, PyObject *args) { + char *mode; int xsize, ysize; if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) { @@ -658,10 +645,9 @@ _new(PyObject* self, PyObject* args) return PyImagingNew(ImagingNew(mode, xsize, ysize)); } -static PyObject* -_new_block(PyObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_new_block(PyObject *self, PyObject *args) { + char *mode; int xsize, ysize; if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) { @@ -671,10 +657,9 @@ _new_block(PyObject* self, PyObject* args) return PyImagingNew(ImagingNewBlock(mode, xsize, ysize)); } -static PyObject* -_linear_gradient(PyObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_linear_gradient(PyObject *self, PyObject *args) { + char *mode; if (!PyArg_ParseTuple(args, "s", &mode)) { return NULL; @@ -683,10 +668,9 @@ _linear_gradient(PyObject* self, PyObject* args) return PyImagingNew(ImagingFillLinearGradient(mode)); } -static PyObject* -_radial_gradient(PyObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_radial_gradient(PyObject *self, PyObject *args) { + char *mode; if (!PyArg_ParseTuple(args, "s", &mode)) { return NULL; @@ -695,64 +679,57 @@ _radial_gradient(PyObject* self, PyObject* args) return PyImagingNew(ImagingFillRadialGradient(mode)); } -static PyObject* -_alpha_composite(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep1; - ImagingObject* imagep2; +static PyObject * +_alpha_composite(ImagingObject *self, PyObject *args) { + ImagingObject *imagep1; + ImagingObject *imagep2; - if (!PyArg_ParseTuple(args, "O!O!", - &Imaging_Type, &imagep1, - &Imaging_Type, &imagep2)) { + if (!PyArg_ParseTuple( + args, "O!O!", &Imaging_Type, &imagep1, &Imaging_Type, &imagep2)) { return NULL; } return PyImagingNew(ImagingAlphaComposite(imagep1->image, imagep2->image)); } -static PyObject* -_blend(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep1; - ImagingObject* imagep2; +static PyObject * +_blend(ImagingObject *self, PyObject *args) { + ImagingObject *imagep1; + ImagingObject *imagep2; double alpha; alpha = 0.5; - if (!PyArg_ParseTuple(args, "O!O!|d", - &Imaging_Type, &imagep1, - &Imaging_Type, &imagep2, - &alpha)) { + if (!PyArg_ParseTuple( + args, "O!O!|d", &Imaging_Type, &imagep1, &Imaging_Type, &imagep2, &alpha)) { return NULL; } - return PyImagingNew(ImagingBlend(imagep1->image, imagep2->image, - (float) alpha)); + return PyImagingNew(ImagingBlend(imagep1->image, imagep2->image, (float)alpha)); } /* -------------------------------------------------------------------- */ /* METHODS */ /* -------------------------------------------------------------------- */ -static INT16* -_prepare_lut_table(PyObject* table, Py_ssize_t table_size) -{ +static INT16 * +_prepare_lut_table(PyObject *table, Py_ssize_t table_size) { int i; Py_buffer buffer_info; INT32 data_type = TYPE_FLOAT32; float item = 0; - void* table_data = NULL; - int free_table_data = 0; - INT16* prepared; + void *table_data = NULL; + int free_table_data = 0; + INT16 *prepared; - /* NOTE: This value should be the same as in ColorLUT.c */ - #define PRECISION_BITS (16 - 8 - 2) +/* NOTE: This value should be the same as in ColorLUT.c */ +#define PRECISION_BITS (16 - 8 - 2) - const char* wrong_size = ("The table should have table_channels * " - "size1D * size2D * size3D float items."); + const char *wrong_size = + ("The table should have table_channels * " + "size1D * size2D * size3D float items."); if (PyObject_CheckBuffer(table)) { - if ( ! PyObject_GetBuffer(table, &buffer_info, - PyBUF_CONTIG_RO | PyBUF_FORMAT)) { + if (!PyObject_GetBuffer(table, &buffer_info, PyBUF_CONTIG_RO | PyBUF_FORMAT)) { if (buffer_info.ndim == 1 && buffer_info.shape[0] == table_size) { if (strlen(buffer_info.format) == 1) { switch (buffer_info.format[0]) { @@ -775,21 +752,21 @@ _prepare_lut_table(PyObject* table, Py_ssize_t table_size) } } - if ( ! table_data) { + if (!table_data) { free_table_data = 1; table_data = getlist(table, &table_size, wrong_size, TYPE_FLOAT32); - if ( ! table_data) { + if (!table_data) { return NULL; } } /* malloc check ok, max is 2 * 4 * 65**3 = 2197000 */ - prepared = (INT16*) malloc(sizeof(INT16) * table_size); - if ( ! prepared) { + prepared = (INT16 *)malloc(sizeof(INT16) * table_size); + if (!prepared) { if (free_table_data) { free(table_data); } - return (INT16*) ImagingError_MemoryError(); + return (INT16 *)ImagingError_MemoryError(); } for (i = 0; i < table_size; i++) { @@ -797,15 +774,16 @@ _prepare_lut_table(PyObject* table, Py_ssize_t table_size) double dtmp; switch (data_type) { case TYPE_FLOAT16: - memcpy(&htmp, ((char*) table_data) + i * sizeof(htmp), sizeof(htmp)); + memcpy(&htmp, ((char *)table_data) + i * sizeof(htmp), sizeof(htmp)); item = float16tofloat32(htmp); break; case TYPE_FLOAT32: - memcpy(&item, ((char*) table_data) + i * sizeof(FLOAT32), sizeof(FLOAT32)); + memcpy( + &item, ((char *)table_data) + i * sizeof(FLOAT32), sizeof(FLOAT32)); break; case TYPE_DOUBLE: - memcpy(&dtmp, ((char*) table_data) + i * sizeof(dtmp), sizeof(dtmp)); - item = (FLOAT32) dtmp; + memcpy(&dtmp, ((char *)table_data) + i * sizeof(dtmp), sizeof(dtmp)); + item = (FLOAT32)dtmp; break; } /* Max value for INT16 */ @@ -825,69 +803,75 @@ _prepare_lut_table(PyObject* table, Py_ssize_t table_size) } } - #undef PRECISION_BITS +#undef PRECISION_BITS if (free_table_data) { free(table_data); } return prepared; } - -static PyObject* -_color_lut_3d(ImagingObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_color_lut_3d(ImagingObject *self, PyObject *args) { + char *mode; int filter; int table_channels; int size1D, size2D, size3D; - PyObject* table; + PyObject *table; - INT16* prepared_table; + INT16 *prepared_table; Imaging imOut; - if ( ! PyArg_ParseTuple(args, "siiiiiO:color_lut_3d", &mode, &filter, - &table_channels, &size1D, &size2D, &size3D, - &table)) { + if (!PyArg_ParseTuple( + args, + "siiiiiO:color_lut_3d", + &mode, + &filter, + &table_channels, + &size1D, + &size2D, + &size3D, + &table)) { return NULL; } /* actually, it is trilinear */ if (filter != IMAGING_TRANSFORM_BILINEAR) { - PyErr_SetString(PyExc_ValueError, - "Only LINEAR filter is supported."); + PyErr_SetString(PyExc_ValueError, "Only LINEAR filter is supported."); return NULL; } if (1 > table_channels || table_channels > 4) { - PyErr_SetString(PyExc_ValueError, - "table_channels should be from 1 to 4"); + PyErr_SetString(PyExc_ValueError, "table_channels should be from 1 to 4"); return NULL; } - if (2 > size1D || size1D > 65 || - 2 > size2D || size2D > 65 || - 2 > size3D || size3D > 65 - ) { - PyErr_SetString(PyExc_ValueError, - "Table size in any dimension should be from 2 to 65"); + if (2 > size1D || size1D > 65 || 2 > size2D || size2D > 65 || 2 > size3D || + size3D > 65) { + PyErr_SetString( + PyExc_ValueError, "Table size in any dimension should be from 2 to 65"); return NULL; } - prepared_table = _prepare_lut_table( - table, table_channels * size1D * size2D * size3D); - if ( ! prepared_table) { + prepared_table = + _prepare_lut_table(table, table_channels * size1D * size2D * size3D); + if (!prepared_table) { return NULL; } imOut = ImagingNewDirty(mode, self->image->xsize, self->image->ysize); - if ( ! imOut) { + if (!imOut) { free(prepared_table); return NULL; } - if ( ! ImagingColorLUT3D_linear(imOut, self->image, - table_channels, size1D, size2D, size3D, - prepared_table)) { + if (!ImagingColorLUT3D_linear( + imOut, + self->image, + table_channels, + size1D, + size2D, + size3D, + prepared_table)) { free(prepared_table); ImagingDelete(imOut); return NULL; @@ -898,10 +882,9 @@ _color_lut_3d(ImagingObject* self, PyObject* args) return PyImagingNew(imOut); } -static PyObject* -_convert(ImagingObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_convert(ImagingObject *self, PyObject *args) { + char *mode; int dither = 0; ImagingObject *paletteimage = NULL; @@ -911,7 +894,8 @@ _convert(ImagingObject* self, PyObject* args) if (paletteimage != NULL) { if (!PyImaging_Check(paletteimage)) { PyObject_Print((PyObject *)paletteimage, stderr, 0); - PyErr_SetString(PyExc_ValueError, "palette argument must be image with mode 'P'"); + PyErr_SetString( + PyExc_ValueError, "palette argument must be image with mode 'P'"); return NULL; } if (paletteimage->image->palette == NULL) { @@ -920,17 +904,16 @@ _convert(ImagingObject* self, PyObject* args) } } - return PyImagingNew(ImagingConvert(self->image, mode, paletteimage ? paletteimage->image->palette : NULL, dither)); + return PyImagingNew(ImagingConvert( + self->image, mode, paletteimage ? paletteimage->image->palette : NULL, dither)); } -static PyObject* -_convert2(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep1; - ImagingObject* imagep2; - if (!PyArg_ParseTuple(args, "O!O!", - &Imaging_Type, &imagep1, - &Imaging_Type, &imagep2)) { +static PyObject * +_convert2(ImagingObject *self, PyObject *args) { + ImagingObject *imagep1; + ImagingObject *imagep2; + if (!PyArg_ParseTuple( + args, "O!O!", &Imaging_Type, &imagep1, &Imaging_Type, &imagep2)) { return NULL; } @@ -942,17 +925,28 @@ _convert2(ImagingObject* self, PyObject* args) return Py_None; } -static PyObject* -_convert_matrix(ImagingObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_convert_matrix(ImagingObject *self, PyObject *args) { + char *mode; float m[12]; - if (!PyArg_ParseTuple(args, "s(ffff)", &mode, m+0, m+1, m+2, m+3)) { + if (!PyArg_ParseTuple(args, "s(ffff)", &mode, m + 0, m + 1, m + 2, m + 3)) { PyErr_Clear(); - if (!PyArg_ParseTuple(args, "s(ffffffffffff)", &mode, - m+0, m+1, m+2, m+3, - m+4, m+5, m+6, m+7, - m+8, m+9, m+10, m+11)){ + if (!PyArg_ParseTuple( + args, + "s(ffffffffffff)", + &mode, + m + 0, + m + 1, + m + 2, + m + 3, + m + 4, + m + 5, + m + 6, + m + 7, + m + 8, + m + 9, + m + 10, + m + 11)) { return NULL; } } @@ -960,11 +954,10 @@ _convert_matrix(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingConvertMatrix(self->image, mode, m)); } -static PyObject* -_convert_transparent(ImagingObject* self, PyObject* args) -{ - char* mode; - int r,g,b; +static PyObject * +_convert_transparent(ImagingObject *self, PyObject *args) { + char *mode; + int r, g, b; if (PyArg_ParseTuple(args, "s(iii)", &mode, &r, &g, &b)) { return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, g, b)); } @@ -975,9 +968,8 @@ _convert_transparent(ImagingObject* self, PyObject* args) return NULL; } -static PyObject* -_copy(ImagingObject* self, PyObject* args) -{ +static PyObject * +_copy(ImagingObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) { return NULL; } @@ -985,9 +977,8 @@ _copy(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingCopy(self->image)); } -static PyObject* -_crop(ImagingObject* self, PyObject* args) -{ +static PyObject * +_crop(ImagingObject *self, PyObject *args) { int x0, y0, x1, y1; if (!PyArg_ParseTuple(args, "(iiii)", &x0, &y0, &x1, &y1)) { return NULL; @@ -996,9 +987,8 @@ _crop(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingCrop(self->image, x0, y0, x1, y1)); } -static PyObject* -_expand_image(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)) { @@ -1008,18 +998,17 @@ _expand_image(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingExpand(self->image, x, y, mode)); } -static PyObject* -_filter(ImagingObject* self, PyObject* args) -{ - PyObject* imOut; +static PyObject * +_filter(ImagingObject *self, PyObject *args) { + PyObject *imOut; Py_ssize_t kernelsize; - FLOAT32* kerneldata; + FLOAT32 *kerneldata; int xsize, ysize, i; float divisor, offset; - PyObject* kernel = NULL; - if (!PyArg_ParseTuple(args, "(ii)ffO", &xsize, &ysize, - &divisor, &offset, &kernel)) { + PyObject *kernel = NULL; + if (!PyArg_ParseTuple( + args, "(ii)ffO", &xsize, &ysize, &divisor, &offset, &kernel)) { return NULL; } @@ -1028,7 +1017,7 @@ _filter(ImagingObject* self, PyObject* args) if (!kerneldata) { return NULL; } - if (kernelsize != (Py_ssize_t) xsize * (Py_ssize_t) ysize) { + if (kernelsize != (Py_ssize_t)xsize * (Py_ssize_t)ysize) { free(kerneldata); return ImagingError_ValueError("bad kernel size"); } @@ -1037,9 +1026,7 @@ _filter(ImagingObject* self, PyObject* args) kerneldata[i] /= divisor; } - imOut = PyImagingNew( - ImagingFilter(self->image, xsize, ysize, kerneldata, offset) - ); + imOut = PyImagingNew(ImagingFilter(self->image, xsize, ysize, kerneldata, offset)); free(kerneldata); @@ -1047,9 +1034,8 @@ _filter(ImagingObject* self, PyObject* args) } #ifdef WITH_UNSHARPMASK -static PyObject* -_gaussian_blur(ImagingObject* self, PyObject* args) -{ +static PyObject * +_gaussian_blur(ImagingObject *self, PyObject *args) { Imaging imIn; Imaging imOut; @@ -1074,16 +1060,15 @@ _gaussian_blur(ImagingObject* self, PyObject* args) } #endif -static PyObject* -_getpalette(ImagingObject* self, PyObject* args) -{ - PyObject* palette; +static PyObject * +_getpalette(ImagingObject *self, PyObject *args) { + PyObject *palette; int palettesize = 256; int bits; ImagingShuffler pack; - char* mode = "RGB"; - char* rawmode = "RGB"; + char *mode = "RGB"; + char *rawmode = "RGB"; if (!PyArg_ParseTuple(args, "|ss", &mode, &rawmode)) { return NULL; } @@ -1104,27 +1089,25 @@ _getpalette(ImagingObject* self, PyObject* args) return NULL; } - pack((UINT8*) PyBytes_AsString(palette), - self->image->palette->palette, palettesize); + pack( + (UINT8 *)PyBytes_AsString(palette), self->image->palette->palette, palettesize); return palette; } -static PyObject* -_getpalettemode(ImagingObject* self, PyObject* args) -{ +static PyObject * +_getpalettemode(ImagingObject *self) { if (!self->image->palette) { - PyErr_SetString(PyExc_ValueError, no_palette); - return NULL; + PyErr_SetString(PyExc_ValueError, no_palette); + return NULL; } return PyUnicode_FromString(self->image->palette->mode); } static inline int -_getxy(PyObject* xy, int* x, int *y) -{ - PyObject* value; +_getxy(PyObject *xy, int *x, int *y) { + PyObject *value; if (!PyTuple_Check(xy) || PyTuple_GET_SIZE(xy) != 2) { goto badarg; @@ -1134,48 +1117,48 @@ _getxy(PyObject* xy, int* x, int *y) if (PyLong_Check(value)) { *x = PyLong_AS_LONG(value); } else if (PyFloat_Check(value)) { - *x = (int) PyFloat_AS_DOUBLE(value); + *x = (int)PyFloat_AS_DOUBLE(value); } else { - goto badval; + PyObject *int_value = PyObject_CallMethod(value, "__int__", NULL); + if (int_value != NULL && PyLong_Check(int_value)) { + *x = PyLong_AS_LONG(int_value); + } else { + goto badval; + } } value = PyTuple_GET_ITEM(xy, 1); if (PyLong_Check(value)) { *y = PyLong_AS_LONG(value); } else if (PyFloat_Check(value)) { - *y = (int) PyFloat_AS_DOUBLE(value); + *y = (int)PyFloat_AS_DOUBLE(value); } else { - goto badval; + PyObject *int_value = PyObject_CallMethod(value, "__int__", NULL); + if (int_value != NULL && PyLong_Check(int_value)) { + *y = PyLong_AS_LONG(int_value); + } else { + goto badval; + } } return 0; - badarg: - PyErr_SetString( - PyExc_TypeError, - "argument must be sequence of length 2" - ); +badarg: + PyErr_SetString(PyExc_TypeError, "argument must be sequence of length 2"); return -1; - badval: - PyErr_SetString( - PyExc_TypeError, - "an integer is required" - ); +badval: + PyErr_SetString(PyExc_TypeError, "an integer is required"); return -1; } -static PyObject* -_getpixel(ImagingObject* self, PyObject* args) -{ - PyObject* xy; +static PyObject * +_getpixel(ImagingObject *self, PyObject *args) { + PyObject *xy; int x, y; if (PyTuple_GET_SIZE(args) != 1) { - PyErr_SetString( - PyExc_TypeError, - "argument 1 must be sequence of length 2" - ); + PyErr_SetString(PyExc_TypeError, "argument 1 must be sequence of length 2"); return NULL; } @@ -1199,38 +1182,37 @@ union hist_extrema { FLOAT32 f[2]; }; -static union hist_extrema* -parse_histogram_extremap(ImagingObject* self, PyObject* extremap, - union hist_extrema* ep) -{ +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)) { + 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; - } - 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; @@ -1238,17 +1220,16 @@ parse_histogram_extremap(ImagingObject* self, PyObject* extremap, return ep; } -static PyObject* -_histogram(ImagingObject* self, PyObject* args) -{ +static PyObject * +_histogram(ImagingObject *self, PyObject *args) { ImagingHistogram h; - PyObject* list; + PyObject *list; int i; union hist_extrema extrema; - union hist_extrema* ep; + union hist_extrema *ep; - PyObject* extremap = NULL; - ImagingObject* maskp = NULL; + PyObject *extremap = NULL; + ImagingObject *maskp = NULL; if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp)) { return NULL; } @@ -1264,7 +1245,7 @@ _histogram(ImagingObject* self, PyObject* args) /* Build an integer list containing the histogram */ list = PyList_New(h->bands * 256); for (i = 0; i < h->bands * 256; i++) { - PyObject* item; + PyObject *item; item = PyLong_FromLong(h->histogram[i]); if (item == NULL) { Py_DECREF(list); @@ -1280,18 +1261,17 @@ _histogram(ImagingObject* self, PyObject* args) return list; } -static PyObject* -_entropy(ImagingObject* self, PyObject* args) -{ +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; + union hist_extrema *ep; - PyObject* extremap = NULL; - ImagingObject* maskp = NULL; + PyObject *extremap = NULL; + ImagingObject *maskp = NULL; if (!PyArg_ParseTuple(args, "|OO!", &extremap, &Imaging_Type, &maskp)) { return NULL; } @@ -1330,9 +1310,8 @@ _entropy(ImagingObject* self, PyObject* args) } #ifdef WITH_MODEFILTER -static PyObject* -_modefilter(ImagingObject* self, PyObject* args) -{ +static PyObject * +_modefilter(ImagingObject *self, PyObject *args) { int size; if (!PyArg_ParseTuple(args, "i", &size)) { return NULL; @@ -1342,9 +1321,8 @@ _modefilter(ImagingObject* self, PyObject* args) } #endif -static PyObject* -_offset(ImagingObject* self, PyObject* args) -{ +static PyObject * +_offset(ImagingObject *self, PyObject *args) { int xoffset, yoffset; if (!PyArg_ParseTuple(args, "ii", &xoffset, &yoffset)) { return NULL; @@ -1353,38 +1331,35 @@ _offset(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingOffset(self->image, xoffset, yoffset)); } -static PyObject* -_paste(ImagingObject* self, PyObject* args) -{ +static PyObject * +_paste(ImagingObject *self, PyObject *args) { int status; char ink[4]; - PyObject* source; + PyObject *source; int x0, y0, x1, y1; - ImagingObject* maskp = NULL; - if (!PyArg_ParseTuple(args, "O(iiii)|O!", - &source, - &x0, &y0, &x1, &y1, - &Imaging_Type, &maskp)) { + ImagingObject *maskp = NULL; + if (!PyArg_ParseTuple( + args, "O(iiii)|O!", &source, &x0, &y0, &x1, &y1, &Imaging_Type, &maskp)) { return NULL; } if (PyImaging_Check(source)) { status = ImagingPaste( - self->image, PyImaging_AsImaging(source), + self->image, + PyImaging_AsImaging(source), (maskp) ? maskp->image : NULL, - x0, y0, x1, y1 - ); + x0, + y0, + x1, + y1); } else { if (!getink(source, self->image, ink)) { return NULL; } status = ImagingFill2( - self->image, ink, - (maskp) ? maskp->image : NULL, - x0, y0, x1, y1 - ); + self->image, ink, (maskp) ? maskp->image : NULL, x0, y0, x1, y1); } if (status < 0) { @@ -1395,23 +1370,22 @@ _paste(ImagingObject* self, PyObject* args) return Py_None; } -static PyObject* -_point(ImagingObject* self, PyObject* args) -{ - static const char* wrong_number = "wrong number of lut entries"; +static PyObject * +_point(ImagingObject *self, PyObject *args) { + static const char *wrong_number = "wrong number of lut entries"; Py_ssize_t n; int i, bands; Imaging im; - PyObject* list; - char* mode; + PyObject *list; + char *mode; if (!PyArg_ParseTuple(args, "Oz", &list, &mode)) { return NULL; } if (mode && !strcmp(mode, "F")) { - FLOAT32* data; + FLOAT32 *data; /* map from 8-bit data to floating point */ n = 256; @@ -1419,11 +1393,11 @@ _point(ImagingObject* self, PyObject* args) if (!data) { return NULL; } - im = ImagingPoint(self->image, mode, (void*) data); + im = ImagingPoint(self->image, mode, (void *)data); free(data); } else if (!strcmp(self->image->mode, "I") && mode && !strcmp(mode, "L")) { - UINT8* data; + UINT8 *data; /* map from 16-bit subset of 32-bit data to 8-bit */ /* FIXME: support arbitrary number of entries (requires API change) */ @@ -1432,11 +1406,11 @@ _point(ImagingObject* self, PyObject* args) if (!data) { return NULL; } - im = ImagingPoint(self->image, mode, (void*) data); + im = ImagingPoint(self->image, mode, (void *)data); free(data); } else { - INT32* data; + INT32 *data; UINT8 lut[1024]; if (mode) { @@ -1456,23 +1430,23 @@ _point(ImagingObject* self, PyObject* args) } if (mode && !strcmp(mode, "I")) { - im = ImagingPoint(self->image, mode, (void*) data); + im = ImagingPoint(self->image, mode, (void *)data); } else if (mode && bands > 1) { for (i = 0; i < 256; i++) { - lut[i*4] = CLIP8(data[i]); - lut[i*4+1] = CLIP8(data[i+256]); - lut[i*4+2] = CLIP8(data[i+512]); + lut[i * 4] = CLIP8(data[i]); + lut[i * 4 + 1] = CLIP8(data[i + 256]); + lut[i * 4 + 2] = CLIP8(data[i + 512]); if (n > 768) { - lut[i*4+3] = CLIP8(data[i+768]); + lut[i * 4 + 3] = CLIP8(data[i + 768]); } } - im = ImagingPoint(self->image, mode, (void*) lut); + im = ImagingPoint(self->image, mode, (void *)lut); } else { /* map individual bands */ for (i = 0; i < n; i++) { lut[i] = CLIP8(data[i]); } - im = ImagingPoint(self->image, mode, (void*) lut); + im = ImagingPoint(self->image, mode, (void *)lut); } free(data); } @@ -1480,9 +1454,8 @@ _point(ImagingObject* self, PyObject* args) return PyImagingNew(im); } -static PyObject* -_point_transform(ImagingObject* self, PyObject* args) -{ +static PyObject * +_point_transform(ImagingObject *self, PyObject *args) { double scale = 1.0; double offset = 0.0; if (!PyArg_ParseTuple(args, "|dd", &scale, &offset)) { @@ -1492,16 +1465,15 @@ _point_transform(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingPointTransform(self->image, scale, offset)); } -static PyObject* -_putdata(ImagingObject* self, PyObject* args) -{ +static PyObject * +_putdata(ImagingObject *self, PyObject *args) { Imaging image; // i & n are # pixels, require py_ssize_t. x can be as large as n. y, just because. Py_ssize_t n, i, x, y; - PyObject* data; - PyObject* seq = NULL; - PyObject* op; + PyObject *data; + PyObject *seq = NULL; + PyObject *op; double scale = 1.0; double offset = 0.0; @@ -1524,54 +1496,54 @@ _putdata(ImagingObject* self, PyObject* args) if (image->image8) { if (PyBytes_Check(data)) { - unsigned char* p; - p = (unsigned char*) PyBytes_AS_STRING(data); + unsigned char *p; + p = (unsigned char *)PyBytes_AS_STRING(data); if (scale == 1.0 && offset == 0.0) { /* Plain string data */ for (i = y = 0; i < n; i += image->xsize, y++) { x = n - i; - if (x > (int) image->xsize) { + if (x > (int)image->xsize) { x = image->xsize; } - memcpy(image->image8[y], p+i, x); + memcpy(image->image8[y], p + i, x); } } else { /* Scaled and clipped string data */ for (i = x = y = 0; i < n; i++) { - image->image8[y][x] = CLIP8((int) (p[i] * scale + offset)); - if (++x >= (int) image->xsize) { + image->image8[y][x] = CLIP8((int)(p[i] * scale + offset)); + if (++x >= (int)image->xsize) { x = 0, y++; } } } } else { - seq = PySequence_Fast(data, must_be_sequence); - if (!seq) { - PyErr_SetString(PyExc_TypeError, must_be_sequence); - return NULL; - } - if (scale == 1.0 && offset == 0.0) { - /* Clipped data */ - for (i = x = y = 0; i < n; i++) { - op = PySequence_Fast_GET_ITEM(seq, i); - image->image8[y][x] = (UINT8) CLIP8(PyLong_AsLong(op)); - if (++x >= (int) image->xsize){ - x = 0, y++; - } - } + seq = PySequence_Fast(data, must_be_sequence); + if (!seq) { + PyErr_SetString(PyExc_TypeError, must_be_sequence); + return NULL; + } + if (scale == 1.0 && offset == 0.0) { + /* Clipped data */ + for (i = x = y = 0; i < n; i++) { + op = PySequence_Fast_GET_ITEM(seq, i); + image->image8[y][x] = (UINT8)CLIP8(PyLong_AsLong(op)); + if (++x >= (int)image->xsize) { + x = 0, y++; + } + } } else { - /* Scaled and clipped data */ - for (i = x = y = 0; i < n; i++) { - PyObject *op = PySequence_Fast_GET_ITEM(seq, i); - image->image8[y][x] = CLIP8( - (int) (PyFloat_AsDouble(op) * scale + offset)); - if (++x >= (int) image->xsize){ - x = 0, y++; - } - } - } - PyErr_Clear(); /* Avoid weird exceptions */ + /* Scaled and clipped data */ + for (i = x = y = 0; i < n; i++) { + PyObject *op = PySequence_Fast_GET_ITEM(seq, i); + image->image8[y][x] = + CLIP8((int)(PyFloat_AsDouble(op) * scale + offset)); + if (++x >= (int)image->xsize) { + x = 0, y++; + } + } + } + PyErr_Clear(); /* Avoid weird exceptions */ } } else { /* 32-bit images */ @@ -1581,50 +1553,50 @@ _putdata(ImagingObject* self, PyObject* args) return NULL; } switch (image->type) { - case IMAGING_TYPE_INT32: - for (i = x = y = 0; i < n; i++) { - op = PySequence_Fast_GET_ITEM(seq, i); - IMAGING_PIXEL_INT32(image, x, y) = - (INT32) (PyFloat_AsDouble(op) * scale + offset); - if (++x >= (int) image->xsize){ - x = 0, y++; + case IMAGING_TYPE_INT32: + for (i = x = y = 0; i < n; i++) { + op = PySequence_Fast_GET_ITEM(seq, i); + IMAGING_PIXEL_INT32(image, x, y) = + (INT32)(PyFloat_AsDouble(op) * scale + offset); + if (++x >= (int)image->xsize) { + x = 0, y++; + } } - } - PyErr_Clear(); /* Avoid weird exceptions */ - break; - case IMAGING_TYPE_FLOAT32: - for (i = x = y = 0; i < n; i++) { - op = PySequence_Fast_GET_ITEM(seq, i); - IMAGING_PIXEL_FLOAT32(image, x, y) = - (FLOAT32) (PyFloat_AsDouble(op) * scale + offset); - if (++x >= (int) image->xsize){ - x = 0, y++; + PyErr_Clear(); /* Avoid weird exceptions */ + break; + case IMAGING_TYPE_FLOAT32: + for (i = x = y = 0; i < n; i++) { + op = PySequence_Fast_GET_ITEM(seq, i); + IMAGING_PIXEL_FLOAT32(image, x, y) = + (FLOAT32)(PyFloat_AsDouble(op) * scale + offset); + if (++x >= (int)image->xsize) { + x = 0, y++; + } } - } - PyErr_Clear(); /* Avoid weird exceptions */ - break; - default: - for (i = x = y = 0; i < n; i++) { - union { - char ink[4]; - INT32 inkint; - } u; + PyErr_Clear(); /* Avoid weird exceptions */ + break; + default: + for (i = x = y = 0; i < n; i++) { + union { + char ink[4]; + INT32 inkint; + } u; - u.inkint = 0; + u.inkint = 0; - op = PySequence_Fast_GET_ITEM(seq, i); - if (!op || !getink(op, image, u.ink)) { - Py_DECREF(seq); - return NULL; + op = PySequence_Fast_GET_ITEM(seq, i); + if (!op || !getink(op, image, u.ink)) { + Py_DECREF(seq); + return NULL; + } + /* FIXME: what about scale and offset? */ + image->image32[y][x] = u.inkint; + if (++x >= (int)image->xsize) { + x = 0, y++; + } } - /* FIXME: what about scale and offset? */ - image->image32[y][x] = u.inkint; - if (++x >= (int) image->xsize){ - x = 0, y++; - } - } - PyErr_Clear(); /* Avoid weird exceptions */ - break; + PyErr_Clear(); /* Avoid weird exceptions */ + break; } } @@ -1636,9 +1608,8 @@ _putdata(ImagingObject* self, PyObject* args) #ifdef WITH_QUANTIZE -static PyObject* -_quantize(ImagingObject* self, PyObject* args) -{ +static PyObject * +_quantize(ImagingObject *self, PyObject *args) { int colours = 256; int method = 0; int kmeans = 0; @@ -1648,23 +1619,20 @@ _quantize(ImagingObject* self, PyObject* args) if (!self->image->xsize || !self->image->ysize) { /* no content; return an empty image */ - return PyImagingNew( - ImagingNew("P", self->image->xsize, self->image->ysize) - ); + return PyImagingNew(ImagingNew("P", self->image->xsize, self->image->ysize)); } return PyImagingNew(ImagingQuantize(self->image, colours, method, kmeans)); } #endif -static PyObject* -_putpalette(ImagingObject* self, PyObject* args) -{ +static PyObject * +_putpalette(ImagingObject *self, PyObject *args) { ImagingShuffler unpack; int bits; - char* rawmode; - UINT8* palette; + char *rawmode; + UINT8 *palette; Py_ssize_t palettesize; if (!PyArg_ParseTuple(args, "sy#", &rawmode, &palette, &palettesize)) { return NULL; @@ -1682,7 +1650,7 @@ _putpalette(ImagingObject* self, PyObject* args) return NULL; } - if ( palettesize * 8 / bits > 256) { + if (palettesize * 8 / bits > 256) { PyErr_SetString(PyExc_ValueError, wrong_palette_size); return NULL; } @@ -1695,13 +1663,11 @@ _putpalette(ImagingObject* self, PyObject* args) unpack(self->image->palette->palette, palette, palettesize * 8 / bits); - Py_INCREF(Py_None); - return Py_None; + return PyLong_FromLong(palettesize * 8 / bits); } -static PyObject* -_putpalettealpha(ImagingObject* self, PyObject* args) -{ +static PyObject * +_putpalettealpha(ImagingObject *self, PyObject *args) { int index; int alpha = 0; if (!PyArg_ParseTuple(args, "i|i", &index, &alpha)) { @@ -1719,15 +1685,14 @@ _putpalettealpha(ImagingObject* self, PyObject* args) } strcpy(self->image->palette->mode, "RGBA"); - self->image->palette->palette[index*4+3] = (UINT8) alpha; + self->image->palette->palette[index * 4 + 3] = (UINT8)alpha; Py_INCREF(Py_None); return Py_None; } -static PyObject* -_putpalettealphas(ImagingObject* self, PyObject* args) -{ +static PyObject * +_putpalettealphas(ImagingObject *self, PyObject *args) { int i; UINT8 *values; Py_ssize_t length; @@ -1740,28 +1705,27 @@ _putpalettealphas(ImagingObject* self, PyObject* args) return NULL; } - if (length > 256) { + if (length > 256) { PyErr_SetString(PyExc_ValueError, outside_palette); return NULL; } strcpy(self->image->palette->mode, "RGBA"); - for (i=0; iimage->palette->palette[i*4+3] = (UINT8) values[i]; + for (i = 0; i < length; i++) { + self->image->palette->palette[i * 4 + 3] = (UINT8)values[i]; } Py_INCREF(Py_None); return Py_None; } -static PyObject* -_putpixel(ImagingObject* self, PyObject* args) -{ +static PyObject * +_putpixel(ImagingObject *self, PyObject *args) { Imaging im; char ink[4]; int x, y; - PyObject* color; + PyObject *color; if (!PyArg_ParseTuple(args, "(ii)O", &x, &y, &color)) { return NULL; } @@ -1793,9 +1757,8 @@ _putpixel(ImagingObject* self, PyObject* args) } #ifdef WITH_RANKFILTER -static PyObject* -_rankfilter(ImagingObject* self, PyObject* args) -{ +static PyObject * +_rankfilter(ImagingObject *self, PyObject *args) { int size, rank; if (!PyArg_ParseTuple(args, "ii", &size, &rank)) { return NULL; @@ -1805,9 +1768,8 @@ _rankfilter(ImagingObject* self, PyObject* args) } #endif -static PyObject* -_resize(ImagingObject* self, PyObject* args) -{ +static PyObject * +_resize(ImagingObject *self, PyObject *args) { Imaging imIn; Imaging imOut; @@ -1819,8 +1781,16 @@ _resize(ImagingObject* self, PyObject* args) box[2] = imIn->xsize; box[3] = imIn->ysize; - if (!PyArg_ParseTuple(args, "(ii)|i(ffff)", &xsize, &ysize, &filter, - &box[0], &box[1], &box[2], &box[3])) { + if (!PyArg_ParseTuple( + args, + "(ii)|i(ffff)", + &xsize, + &ysize, + &filter, + &box[0], + &box[1], + &box[2], + &box[3])) { return NULL; } @@ -1841,36 +1811,31 @@ _resize(ImagingObject* self, PyObject* args) } // If box's coordinates are int and box size matches requested size - if (box[0] - (int) box[0] == 0 && box[2] - box[0] == xsize - && box[1] - (int) box[1] == 0 && box[3] - box[1] == ysize) { + if (box[0] - (int)box[0] == 0 && box[2] - box[0] == xsize && + box[1] - (int)box[1] == 0 && box[3] - box[1] == ysize) { imOut = ImagingCrop(imIn, box[0], box[1], box[2], box[3]); - } - else if (filter == IMAGING_TRANSFORM_NEAREST) { + } else if (filter == IMAGING_TRANSFORM_NEAREST) { double a[6]; memset(a, 0, sizeof a); - a[0] = (double) (box[2] - box[0]) / xsize; - a[4] = (double) (box[3] - box[1]) / ysize; + a[0] = (double)(box[2] - box[0]) / xsize; + a[4] = (double)(box[3] - box[1]) / ysize; a[2] = box[0]; a[5] = box[1]; imOut = ImagingNewDirty(imIn->mode, xsize, ysize); imOut = ImagingTransform( - imOut, imIn, IMAGING_TRANSFORM_AFFINE, - 0, 0, xsize, ysize, - a, filter, 1); - } - else { + imOut, imIn, IMAGING_TRANSFORM_AFFINE, 0, 0, xsize, ysize, a, filter, 1); + } else { imOut = ImagingResample(imIn, xsize, ysize, filter, box); } return PyImagingNew(imOut); } -static PyObject* -_reduce(ImagingObject* self, PyObject* args) -{ +static PyObject * +_reduce(ImagingObject *self, PyObject *args) { Imaging imIn; Imaging imOut; @@ -1881,8 +1846,15 @@ _reduce(ImagingObject* self, PyObject* args) box[2] = imIn->xsize; box[3] = imIn->ysize; - if (!PyArg_ParseTuple(args, "(ii)|(iiii)", &xscale, &yscale, - &box[0], &box[1], &box[2], &box[3])) { + if (!PyArg_ParseTuple( + args, + "(ii)|(iiii)", + &xscale, + &yscale, + &box[0], + &box[1], + &box[2], + &box[3])) { return NULL; } @@ -1914,18 +1886,16 @@ _reduce(ImagingObject* self, PyObject* args) return PyImagingNew(imOut); } - -#define IS_RGB(mode)\ +#define IS_RGB(mode) \ (!strcmp(mode, "RGB") || !strcmp(mode, "RGBA") || !strcmp(mode, "RGBX")) -static PyObject* -im_setmode(ImagingObject* self, PyObject* args) -{ +static PyObject * +im_setmode(ImagingObject *self, PyObject *args) { /* attempt to modify the mode of an image in place */ Imaging im; - char* mode; + char *mode; Py_ssize_t modelen; if (!PyArg_ParseTuple(args, "s#:setmode", &mode, &modelen)) { return NULL; @@ -1942,7 +1912,7 @@ im_setmode(ImagingObject* self, PyObject* args) strcpy(im->mode, mode); im->bands = modelen; if (!strcmp(mode, "RGBA")) { - (void) ImagingFillBand(im, 3, 255); + (void)ImagingFillBand(im, 3, 255); } } else { /* trying doing an in-place conversion */ @@ -1960,42 +1930,48 @@ im_setmode(ImagingObject* self, PyObject* args) return Py_None; } - -static PyObject* -_transform2(ImagingObject* self, PyObject* args) -{ - static const char* wrong_number = "wrong number of matrix entries"; +static PyObject * +_transform2(ImagingObject *self, PyObject *args) { + static const char *wrong_number = "wrong number of matrix entries"; Imaging imOut; Py_ssize_t n; double *a; - ImagingObject* imagep; + ImagingObject *imagep; int x0, y0, x1, y1; int method; - PyObject* data; + PyObject *data; int filter = IMAGING_TRANSFORM_NEAREST; int fill = 1; - if (!PyArg_ParseTuple(args, "(iiii)O!iO|ii", - &x0, &y0, &x1, &y1, - &Imaging_Type, &imagep, - &method, &data, - &filter, &fill)) { + if (!PyArg_ParseTuple( + args, + "(iiii)O!iO|ii", + &x0, + &y0, + &x1, + &y1, + &Imaging_Type, + &imagep, + &method, + &data, + &filter, + &fill)) { return NULL; } switch (method) { - case IMAGING_TRANSFORM_AFFINE: - n = 6; - break; - case IMAGING_TRANSFORM_PERSPECTIVE: - n = 8; - break; - case IMAGING_TRANSFORM_QUAD: - n = 8; - break; - default: - n = -1; /* force error */ + case IMAGING_TRANSFORM_AFFINE: + n = 6; + break; + case IMAGING_TRANSFORM_PERSPECTIVE: + n = 8; + break; + case IMAGING_TRANSFORM_QUAD: + n = 8; + break; + default: + n = -1; /* force error */ } a = getlist(data, &n, wrong_number, TYPE_DOUBLE); @@ -2004,8 +1980,7 @@ _transform2(ImagingObject* self, PyObject* args) } imOut = ImagingTransform( - self->image, imagep->image, method, - x0, y0, x1, y1, a, filter, fill); + self->image, imagep->image, method, x0, y0, x1, y1, a, filter, fill); free(a); @@ -2017,9 +1992,8 @@ _transform2(ImagingObject* self, PyObject* args) return Py_None; } -static PyObject* -_transpose(ImagingObject* self, PyObject* args) -{ +static PyObject * +_transpose(ImagingObject *self, PyObject *args) { Imaging imIn; Imaging imOut; @@ -2031,45 +2005,45 @@ _transpose(ImagingObject* self, PyObject* args) imIn = self->image; switch (op) { - case 0: /* flip left right */ - case 1: /* flip top bottom */ - case 3: /* rotate 180 */ - imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize); - break; - case 2: /* rotate 90 */ - case 4: /* rotate 270 */ - case 5: /* transpose */ - case 6: /* transverse */ - imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize); - break; - default: - PyErr_SetString(PyExc_ValueError, "No such transpose operation"); - return NULL; + case 0: /* flip left right */ + case 1: /* flip top bottom */ + case 3: /* rotate 180 */ + imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize); + break; + case 2: /* rotate 90 */ + case 4: /* rotate 270 */ + case 5: /* transpose */ + case 6: /* transverse */ + imOut = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize); + break; + default: + PyErr_SetString(PyExc_ValueError, "No such transpose operation"); + return NULL; } if (imOut) { switch (op) { - case 0: - (void) ImagingFlipLeftRight(imOut, imIn); - break; - case 1: - (void) ImagingFlipTopBottom(imOut, imIn); - break; - case 2: - (void) ImagingRotate90(imOut, imIn); - break; - case 3: - (void) ImagingRotate180(imOut, imIn); - break; - case 4: - (void) ImagingRotate270(imOut, imIn); - break; - case 5: - (void) ImagingTranspose(imOut, imIn); - break; - case 6: - (void) ImagingTransverse(imOut, imIn); - break; + case 0: + (void)ImagingFlipLeftRight(imOut, imIn); + break; + case 1: + (void)ImagingFlipTopBottom(imOut, imIn); + break; + case 2: + (void)ImagingRotate90(imOut, imIn); + break; + case 3: + (void)ImagingRotate180(imOut, imIn); + break; + case 4: + (void)ImagingRotate270(imOut, imIn); + break; + case 5: + (void)ImagingTranspose(imOut, imIn); + break; + case 6: + (void)ImagingTransverse(imOut, imIn); + break; } } @@ -2077,9 +2051,8 @@ _transpose(ImagingObject* self, PyObject* args) } #ifdef WITH_UNSHARPMASK -static PyObject* -_unsharp_mask(ImagingObject* self, PyObject* args) -{ +static PyObject * +_unsharp_mask(ImagingObject *self, PyObject *args) { Imaging imIn; Imaging imOut; @@ -2103,9 +2076,8 @@ _unsharp_mask(ImagingObject* self, PyObject* args) } #endif -static PyObject* -_box_blur(ImagingObject* self, PyObject* args) -{ +static PyObject * +_box_blur(ImagingObject *self, PyObject *args) { Imaging imIn; Imaging imOut; @@ -2131,15 +2103,13 @@ _box_blur(ImagingObject* self, PyObject* args) /* -------------------------------------------------------------------- */ -static PyObject* -_isblock(ImagingObject* self, PyObject* args) -{ +static PyObject * +_isblock(ImagingObject *self) { return PyBool_FromLong(self->image->block != NULL); } -static PyObject* -_getbbox(ImagingObject* self, PyObject* args) -{ +static PyObject * +_getbbox(ImagingObject *self) { int bbox[4]; if (!ImagingGetBBox(self->image, bbox)) { Py_INCREF(Py_None); @@ -2149,12 +2119,11 @@ _getbbox(ImagingObject* self, PyObject* args) return Py_BuildValue("iiii", bbox[0], bbox[1], bbox[2], bbox[3]); } -static PyObject* -_getcolors(ImagingObject* self, PyObject* args) -{ - ImagingColorItem* items; +static PyObject * +_getcolors(ImagingObject *self, PyObject *args) { + ImagingColorItem *items; int i, colors; - PyObject* out; + PyObject *out; int maxcolors = 256; if (!PyArg_ParseTuple(args, "i:getcolors", &maxcolors)) { @@ -2172,10 +2141,9 @@ _getcolors(ImagingObject* self, PyObject* args) } else { out = PyList_New(colors); for (i = 0; i < colors; i++) { - ImagingColorItem* v = &items[i]; - PyObject* item = Py_BuildValue( - "iN", v->count, getpixel(self->image, self->access, v->x, v->y) - ); + ImagingColorItem *v = &items[i]; + PyObject *item = Py_BuildValue( + "iN", v->count, getpixel(self->image, self->access, v->x, v->y)); PyList_SetItem(out, i, item); } } @@ -2185,9 +2153,8 @@ _getcolors(ImagingObject* self, PyObject* args) return out; } -static PyObject* -_getextrema(ImagingObject* self, PyObject* args) -{ +static PyObject * +_getextrema(ImagingObject *self) { union { UINT8 u[2]; INT32 i[2]; @@ -2203,16 +2170,16 @@ _getextrema(ImagingObject* self, PyObject* args) if (status) { switch (self->image->type) { - case IMAGING_TYPE_UINT8: - return Py_BuildValue("BB", extrema.u[0], extrema.u[1]); - case IMAGING_TYPE_INT32: - return Py_BuildValue("ii", extrema.i[0], extrema.i[1]); - case IMAGING_TYPE_FLOAT32: - return Py_BuildValue("dd", extrema.f[0], extrema.f[1]); - case IMAGING_TYPE_SPECIAL: - if (strcmp(self->image->mode, "I;16") == 0) { - return Py_BuildValue("HH", extrema.s[0], extrema.s[1]); - } + case IMAGING_TYPE_UINT8: + return Py_BuildValue("BB", extrema.u[0], extrema.u[1]); + case IMAGING_TYPE_INT32: + return Py_BuildValue("ii", extrema.i[0], extrema.i[1]); + case IMAGING_TYPE_FLOAT32: + return Py_BuildValue("dd", extrema.f[0], extrema.f[1]); + case IMAGING_TYPE_SPECIAL: + if (strcmp(self->image->mode, "I;16") == 0) { + return Py_BuildValue("HH", extrema.s[0], extrema.s[1]); + } } } @@ -2220,12 +2187,11 @@ _getextrema(ImagingObject* self, PyObject* args) return Py_None; } -static PyObject* -_getprojection(ImagingObject* self, PyObject* args) -{ - unsigned char* xprofile; - unsigned char* yprofile; - PyObject* result; +static PyObject * +_getprojection(ImagingObject *self) { + unsigned char *xprofile; + unsigned char *yprofile; + PyObject *result; /* malloc check ok */ xprofile = malloc(self->image->xsize); @@ -2237,11 +2203,15 @@ _getprojection(ImagingObject* self, PyObject* args) return ImagingError_MemoryError(); } - ImagingGetProjection(self->image, (unsigned char *)xprofile, (unsigned char *)yprofile); + ImagingGetProjection( + self->image, (unsigned char *)xprofile, (unsigned char *)yprofile); - result = Py_BuildValue("y#y#", - xprofile, (Py_ssize_t)self->image->xsize, - yprofile, (Py_ssize_t)self->image->ysize); + result = Py_BuildValue( + "y#y#", + xprofile, + (Py_ssize_t)self->image->xsize, + yprofile, + (Py_ssize_t)self->image->ysize); free(xprofile); free(yprofile); @@ -2251,9 +2221,8 @@ _getprojection(ImagingObject* self, PyObject* args) /* -------------------------------------------------------------------- */ -static PyObject* -_getband(ImagingObject* self, PyObject* args) -{ +static PyObject * +_getband(ImagingObject *self, PyObject *args) { int band; if (!PyArg_ParseTuple(args, "i", &band)) { @@ -2263,9 +2232,8 @@ _getband(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingGetBand(self->image, band)); } -static PyObject* -_fillband(ImagingObject* self, PyObject* args) -{ +static PyObject * +_fillband(ImagingObject *self, PyObject *args) { int band; int color; @@ -2281,14 +2249,11 @@ _fillband(ImagingObject* self, PyObject* args) return Py_None; } -static PyObject* -_putband(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_putband(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; int band; - if (!PyArg_ParseTuple(args, "O!i", - &Imaging_Type, &imagep, - &band)) { + if (!PyArg_ParseTuple(args, "O!i", &Imaging_Type, &imagep, &band)) { return NULL; } @@ -2300,19 +2265,27 @@ _putband(ImagingObject* self, PyObject* args) return Py_None; } -static PyObject* -_merge(PyObject* self, PyObject* args) -{ - char* mode; +static PyObject * +_merge(PyObject *self, PyObject *args) { + char *mode; ImagingObject *band0 = NULL; ImagingObject *band1 = NULL; ImagingObject *band2 = NULL; ImagingObject *band3 = NULL; Imaging bands[4] = {NULL, NULL, NULL, NULL}; - if (!PyArg_ParseTuple(args, "sO!|O!O!O!", &mode, - &Imaging_Type, &band0, &Imaging_Type, &band1, - &Imaging_Type, &band2, &Imaging_Type, &band3)) { + if (!PyArg_ParseTuple( + args, + "sO!|O!O!O!", + &mode, + &Imaging_Type, + &band0, + &Imaging_Type, + &band1, + &Imaging_Type, + &band2, + &Imaging_Type, + &band3)) { return NULL; } @@ -2332,23 +2305,22 @@ _merge(PyObject* self, PyObject* args) return PyImagingNew(ImagingMerge(mode, bands)); } -static PyObject* -_split(ImagingObject* self, PyObject* args) -{ +static PyObject * +_split(ImagingObject *self) { int fails = 0; Py_ssize_t i; - PyObject* list; - PyObject* imaging_object; + PyObject *list; + PyObject *imaging_object; Imaging bands[4] = {NULL, NULL, NULL, NULL}; - if ( ! ImagingSplit(self->image, bands)) { + if (!ImagingSplit(self->image, bands)) { return NULL; } list = PyTuple_New(self->image->bands); for (i = 0; i < self->image->bands; i++) { imaging_object = PyImagingNew(bands[i]); - if ( ! imaging_object) { + if (!imaging_object) { fails += 1; } PyTuple_SET_ITEM(list, i, imaging_object); @@ -2364,16 +2336,14 @@ _split(ImagingObject* self, PyObject* args) #ifdef WITH_IMAGECHOPS -static PyObject* -_chop_invert(ImagingObject* self, PyObject* args) -{ +static PyObject * +_chop_invert(ImagingObject *self) { return PyImagingNew(ImagingNegative(self->image)); } -static PyObject* -_chop_lighter(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_lighter(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2382,10 +2352,9 @@ _chop_lighter(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopLighter(self->image, imagep->image)); } -static PyObject* -_chop_darker(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_darker(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2394,10 +2363,9 @@ _chop_darker(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopDarker(self->image, imagep->image)); } -static PyObject* -_chop_difference(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_difference(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2406,10 +2374,9 @@ _chop_difference(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopDifference(self->image, imagep->image)); } -static PyObject* -_chop_multiply(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_multiply(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2418,10 +2385,9 @@ _chop_multiply(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopMultiply(self->image, imagep->image)); } -static PyObject* -_chop_screen(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_screen(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2430,48 +2396,41 @@ _chop_screen(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopScreen(self->image, imagep->image)); } -static PyObject* -_chop_add(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_add(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; float scale; int offset; scale = 1.0; offset = 0; - if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep, - &scale, &offset)) { + if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep, &scale, &offset)) { return NULL; } - return PyImagingNew(ImagingChopAdd(self->image, imagep->image, - scale, offset)); + return PyImagingNew(ImagingChopAdd(self->image, imagep->image, scale, offset)); } -static PyObject* -_chop_subtract(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_subtract(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; float scale; int offset; scale = 1.0; offset = 0; - if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep, - &scale, &offset)) { + if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep, &scale, &offset)) { return NULL; } - return PyImagingNew(ImagingChopSubtract(self->image, imagep->image, - scale, offset)); + return PyImagingNew(ImagingChopSubtract(self->image, imagep->image, scale, offset)); } -static PyObject* -_chop_and(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_and(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2480,10 +2439,9 @@ _chop_and(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopAnd(self->image, imagep->image)); } -static PyObject* -_chop_or(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_or(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2492,10 +2450,9 @@ _chop_or(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopOr(self->image, imagep->image)); } -static PyObject* -_chop_xor(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_xor(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2504,10 +2461,9 @@ _chop_xor(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopXor(self->image, imagep->image)); } -static PyObject* -_chop_add_modulo(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_add_modulo(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2516,10 +2472,9 @@ _chop_add_modulo(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopAddModulo(self->image, imagep->image)); } -static PyObject* -_chop_subtract_modulo(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_subtract_modulo(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2528,10 +2483,9 @@ _chop_subtract_modulo(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopSubtractModulo(self->image, imagep->image)); } -static PyObject* -_chop_soft_light(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_soft_light(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2540,10 +2494,9 @@ _chop_soft_light(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopSoftLight(self->image, imagep->image)); } -static PyObject* -_chop_hard_light(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_hard_light(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2552,10 +2505,9 @@ _chop_hard_light(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingChopHardLight(self->image, imagep->image)); } -static PyObject* -_chop_overlay(ImagingObject* self, PyObject* args) -{ - ImagingObject* imagep; +static PyObject * +_chop_overlay(ImagingObject *self, PyObject *args) { + ImagingObject *imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) { return NULL; @@ -2565,24 +2517,21 @@ _chop_overlay(ImagingObject* self, PyObject* args) } #endif - /* -------------------------------------------------------------------- */ #ifdef WITH_IMAGEDRAW -static PyObject* -_font_new(PyObject* self_, PyObject* args) -{ +static PyObject * +_font_new(PyObject *self_, PyObject *args) { ImagingFontObject *self; int i, y0, y1; - static const char* wrong_length = "descriptor table has wrong size"; + static const char *wrong_length = "descriptor table has wrong size"; - ImagingObject* imagep; - unsigned char* glyphdata; + ImagingObject *imagep; + unsigned char *glyphdata; Py_ssize_t glyphdata_length; - if (!PyArg_ParseTuple(args, "O!y#", - &Imaging_Type, &imagep, - &glyphdata, &glyphdata_length)) { + if (!PyArg_ParseTuple( + args, "O!y#", &Imaging_Type, &imagep, &glyphdata, &glyphdata_length)) { return NULL; } @@ -2629,19 +2578,17 @@ _font_new(PyObject* self_, PyObject* args) Py_INCREF(imagep); self->ref = imagep; - return (PyObject*) self; + return (PyObject *)self; } static void -_font_dealloc(ImagingFontObject* self) -{ +_font_dealloc(ImagingFontObject *self) { Py_XDECREF(self->ref); PyObject_Del(self); } static inline int -textwidth(ImagingFontObject* self, const unsigned char* text) -{ +textwidth(ImagingFontObject *self, const unsigned char *text) { int xsize; for (xsize = 0; *text; text++) { @@ -2651,16 +2598,17 @@ textwidth(ImagingFontObject* self, const unsigned char* text) return xsize; } -void _font_text_asBytes(PyObject* encoded_string, unsigned char** text){ +void +_font_text_asBytes(PyObject *encoded_string, unsigned char **text) { /* Allocates *text, returns a 'new reference'. Caller is required to free */ - PyObject* bytes = NULL; + PyObject *bytes = NULL; Py_ssize_t len = 0; char *buffer; *text = NULL; - if (PyUnicode_CheckExact(encoded_string)){ + if (PyUnicode_CheckExact(encoded_string)) { bytes = PyUnicode_AsLatin1String(encoded_string); if (!bytes) { return; @@ -2670,7 +2618,7 @@ void _font_text_asBytes(PyObject* encoded_string, unsigned char** text){ PyBytes_AsStringAndSize(encoded_string, &buffer, &len); } - *text = calloc(len+1,1); + *text = calloc(len + 1, 1); if (*text) { memcpy(*text, buffer, len); } else { @@ -2683,23 +2631,21 @@ void _font_text_asBytes(PyObject* encoded_string, unsigned char** text){ return; } - -static PyObject* -_font_getmask(ImagingFontObject* self, PyObject* args) -{ +static PyObject * +_font_getmask(ImagingFontObject *self, PyObject *args) { Imaging im; Imaging bitmap; int x, b; - int i=0; + int i = 0; int status; - Glyph* glyph; + Glyph *glyph; - PyObject* encoded_string; + PyObject *encoded_string; - unsigned char* text; - char* mode = ""; + unsigned char *text; + char *mode = ""; - if (!PyArg_ParseTuple(args, "O|s:getmask", &encoded_string, &mode)){ + if (!PyArg_ParseTuple(args, "O|s:getmask", &encoded_string, &mode)) { return NULL; } @@ -2715,22 +2661,24 @@ _font_getmask(ImagingFontObject* self, PyObject* args) } b = 0; - (void) ImagingFill(im, &b); + (void)ImagingFill(im, &b); b = self->baseline; for (x = 0; text[i]; i++) { glyph = &self->glyphs[text[i]]; - bitmap = ImagingCrop( - self->bitmap, - glyph->sx0, glyph->sy0, glyph->sx1, glyph->sy1 - ); + bitmap = + ImagingCrop(self->bitmap, glyph->sx0, glyph->sy0, glyph->sx1, glyph->sy1); if (!bitmap) { goto failed; } status = ImagingPaste( - im, bitmap, NULL, - glyph->dx0+x, glyph->dy0+b, glyph->dx1+x, glyph->dy1+b - ); + im, + bitmap, + NULL, + glyph->dx0 + x, + glyph->dy0 + b, + glyph->dx1 + x, + glyph->dy1 + b); ImagingDelete(bitmap); if (status < 0) { goto failed; @@ -2741,18 +2689,17 @@ _font_getmask(ImagingFontObject* self, PyObject* args) free(text); return PyImagingNew(im); - failed: +failed: free(text); ImagingDelete(im); Py_RETURN_NONE; } -static PyObject* -_font_getsize(ImagingFontObject* self, PyObject* args) -{ - unsigned char* text; - PyObject* encoded_string; - PyObject* val; +static PyObject * +_font_getsize(ImagingFontObject *self, PyObject *args) { + unsigned char *text; + PyObject *encoded_string; + PyObject *val; if (!PyArg_ParseTuple(args, "O:getsize", &encoded_string)) { return NULL; @@ -2769,19 +2716,18 @@ _font_getsize(ImagingFontObject* self, PyObject* args) } static struct PyMethodDef _font_methods[] = { - {"getmask", (PyCFunction)_font_getmask, 1}, - {"getsize", (PyCFunction)_font_getsize, 1}, + {"getmask", (PyCFunction)_font_getmask, METH_VARARGS}, + {"getsize", (PyCFunction)_font_getsize, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; /* -------------------------------------------------------------------- */ -static PyObject* -_draw_new(PyObject* self_, PyObject* args) -{ +static PyObject * +_draw_new(PyObject *self_, PyObject *args) { ImagingDrawObject *self; - ImagingObject* imagep; + ImagingObject *imagep; int blend = 0; if (!PyArg_ParseTuple(args, "O!|i", &Imaging_Type, &imagep, &blend)) { return NULL; @@ -2800,41 +2746,39 @@ _draw_new(PyObject* self_, PyObject* args) self->blend = blend; - return (PyObject*) self; + return (PyObject *)self; } static void -_draw_dealloc(ImagingDrawObject* self) -{ +_draw_dealloc(ImagingDrawObject *self) { Py_XDECREF(self->image); PyObject_Del(self); } -extern Py_ssize_t PyPath_Flatten(PyObject* data, double **xy); +extern Py_ssize_t +PyPath_Flatten(PyObject *data, double **xy); -static PyObject* -_draw_ink(ImagingDrawObject* self, PyObject* args) -{ +static PyObject * +_draw_ink(ImagingDrawObject *self, PyObject *args) { INT32 ink = 0; - PyObject* color; + PyObject *color; if (!PyArg_ParseTuple(args, "O", &color)) { return NULL; } - if (!getink(color, self->image->image, (char*) &ink)) { + if (!getink(color, self->image->image, (char *)&ink)) { return NULL; } - return PyLong_FromLong((int) ink); + return PyLong_FromLong((int)ink); } -static PyObject* -_draw_arc(ImagingDrawObject* self, PyObject* args) -{ - double* xy; +static PyObject * +_draw_arc(ImagingDrawObject *self, PyObject *args) { + double *xy; Py_ssize_t n; - PyObject* data; + PyObject *data; int ink; int width = 0; float start, end; @@ -2852,11 +2796,17 @@ _draw_arc(ImagingDrawObject* self, PyObject* args) return NULL; } - n = ImagingDrawArc(self->image->image, - (int) xy[0], (int) xy[1], - (int) xy[2], (int) xy[3], - start, end, &ink, width, self->blend - ); + n = ImagingDrawArc( + self->image->image, + (int)xy[0], + (int)xy[1], + (int)xy[2], + (int)xy[3], + start, + end, + &ink, + width, + self->blend); free(xy); @@ -2868,14 +2818,13 @@ _draw_arc(ImagingDrawObject* self, PyObject* args) return Py_None; } -static PyObject* -_draw_bitmap(ImagingDrawObject* self, PyObject* args) -{ +static PyObject * +_draw_bitmap(ImagingDrawObject *self, PyObject *args) { double *xy; Py_ssize_t n; PyObject *data; - ImagingObject* bitmap; + ImagingObject *bitmap; int ink; if (!PyArg_ParseTuple(args, "OO!i", &data, &Imaging_Type, &bitmap, &ink)) { return NULL; @@ -2886,17 +2835,14 @@ _draw_bitmap(ImagingDrawObject* self, PyObject* args) return NULL; } if (n != 1) { - PyErr_SetString(PyExc_TypeError, - "coordinate list must contain exactly 1 coordinate" - ); + PyErr_SetString( + PyExc_TypeError, "coordinate list must contain exactly 1 coordinate"); free(xy); return NULL; } n = ImagingDrawBitmap( - self->image->image, (int) xy[0], (int) xy[1], bitmap->image, - &ink, self->blend - ); + self->image->image, (int)xy[0], (int)xy[1], bitmap->image, &ink, self->blend); free(xy); @@ -2908,216 +2854,12 @@ _draw_bitmap(ImagingDrawObject* self, PyObject* args) return Py_None; } -static PyObject* -_draw_chord(ImagingDrawObject* self, PyObject* args) -{ - double* xy; - Py_ssize_t n; - - PyObject* data; - int ink, fill; - int width = 0; - float start, end; - if (!PyArg_ParseTuple(args, "Offii|i", - &data, &start, &end, &ink, &fill, &width)) { - return NULL; - } - - n = PyPath_Flatten(data, &xy); - if (n < 0) { - return NULL; - } - if (n != 2) { - PyErr_SetString(PyExc_TypeError, must_be_two_coordinates); - free(xy); - return NULL; - } - - n = ImagingDrawChord(self->image->image, - (int) xy[0], (int) xy[1], - (int) xy[2], (int) xy[3], - start, end, &ink, fill, width, self->blend - ); - - free(xy); - - if (n < 0) { - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject* -_draw_ellipse(ImagingDrawObject* self, PyObject* args) -{ - double* xy; - Py_ssize_t n; - - PyObject* data; - int ink; - int fill = 0; - int width = 0; - if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width)) { - return NULL; - } - - n = PyPath_Flatten(data, &xy); - if (n < 0) { - return NULL; - } - if (n != 2) { - PyErr_SetString(PyExc_TypeError, must_be_two_coordinates); - free(xy); - return NULL; - } - - n = ImagingDrawEllipse(self->image->image, - (int) xy[0], (int) xy[1], - (int) xy[2], (int) xy[3], - &ink, fill, width, self->blend - ); - - free(xy); - - if (n < 0) { - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject* -_draw_lines(ImagingDrawObject* self, PyObject* args) -{ +static PyObject * +_draw_chord(ImagingDrawObject *self, PyObject *args) { double *xy; - Py_ssize_t i, n; + Py_ssize_t n; PyObject *data; - int ink; - int width = 0; - if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &width)) { - return NULL; - } - - n = PyPath_Flatten(data, &xy); - if (n < 0) { - return NULL; - } - - if (width <= 1) { - double *p = NULL; - for (i = 0; i < n-1; i++) { - p = &xy[i+i]; - if (ImagingDrawLine( - self->image->image, - (int) p[0], (int) p[1], (int) p[2], (int) p[3], - &ink, self->blend) < 0) { - free(xy); - return NULL; - } - } - if (p) {/* draw last point */ - ImagingDrawPoint( - self->image->image, - (int) p[2], (int) p[3], - &ink, self->blend - ); - } - } else { - for (i = 0; i < n-1; i++) { - double *p = &xy[i+i]; - if (ImagingDrawWideLine( - self->image->image, - (int) p[0], (int) p[1], (int) p[2], (int) p[3], - &ink, width, self->blend) < 0) { - free(xy); - return NULL; - } - } - } - - free(xy); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject* -_draw_points(ImagingDrawObject* self, PyObject* args) -{ - double *xy; - Py_ssize_t i, n; - - PyObject *data; - int ink; - if (!PyArg_ParseTuple(args, "Oi", &data, &ink)) { - return NULL; - } - - n = PyPath_Flatten(data, &xy); - if (n < 0) { - return NULL; - } - - for (i = 0; i < n; i++) { - double *p = &xy[i+i]; - if (ImagingDrawPoint(self->image->image, (int) p[0], (int) p[1], - &ink, self->blend) < 0) { - free(xy); - return NULL; - } - } - - free(xy); - - Py_INCREF(Py_None); - return Py_None; -} - -#ifdef WITH_ARROW - -/* from outline.c */ -extern ImagingOutline PyOutline_AsOutline(PyObject* outline); - -static PyObject* -_draw_outline(ImagingDrawObject* self, PyObject* args) -{ - ImagingOutline outline; - - PyObject* outline_; - int ink; - int fill = 0; - if (!PyArg_ParseTuple(args, "Oi|i", &outline_, &ink, &fill)) { - return NULL; - } - - outline = PyOutline_AsOutline(outline_); - if (!outline) { - PyErr_SetString(PyExc_TypeError, "expected outline object"); - return NULL; - } - - if (ImagingDrawOutline(self->image->image, outline, - &ink, fill, self->blend) < 0) { - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -#endif - -static PyObject* -_draw_pieslice(ImagingDrawObject* self, PyObject* args) -{ - double* xy; - Py_ssize_t n; - - PyObject* data; int ink, fill; int width = 0; float start, end; @@ -3135,11 +2877,18 @@ _draw_pieslice(ImagingDrawObject* self, PyObject* args) return NULL; } - n = ImagingDrawPieslice(self->image->image, - (int) xy[0], (int) xy[1], - (int) xy[2], (int) xy[3], - start, end, &ink, fill, width, self->blend - ); + n = ImagingDrawChord( + self->image->image, + (int)xy[0], + (int)xy[1], + (int)xy[2], + (int)xy[3], + start, + end, + &ink, + fill, + width, + self->blend); free(xy); @@ -3151,65 +2900,12 @@ _draw_pieslice(ImagingDrawObject* self, PyObject* args) return Py_None; } -static PyObject* -_draw_polygon(ImagingDrawObject* self, PyObject* args) -{ +static PyObject * +_draw_ellipse(ImagingDrawObject *self, PyObject *args) { double *xy; - int *ixy; - Py_ssize_t n, i; - - PyObject* data; - int ink; - int fill = 0; - if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &fill)) { - return NULL; - } - - n = PyPath_Flatten(data, &xy); - if (n < 0) { - return NULL; - } - if (n < 2) { - PyErr_SetString(PyExc_TypeError, - "coordinate list must contain at least 2 coordinates" - ); - free(xy); - return NULL; - } - - /* Copy list of vertices to array */ - ixy = (int*) calloc(n, 2 * sizeof(int)); - if (ixy == NULL) { - free(xy); - return ImagingError_MemoryError(); - } - - for (i = 0; i < n; i++) { - ixy[i+i] = (int) xy[i+i]; - ixy[i+i+1] = (int) xy[i+i+1]; - } - - free(xy); - - if (ImagingDrawPolygon(self->image->image, n, ixy, - &ink, fill, self->blend) < 0) { - free(ixy); - return NULL; - } - - free(ixy); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject* -_draw_rectangle(ImagingDrawObject* self, PyObject* args) -{ - double* xy; Py_ssize_t n; - PyObject* data; + PyObject *data; int ink; int fill = 0; int width = 0; @@ -3227,11 +2923,280 @@ _draw_rectangle(ImagingDrawObject* self, PyObject* args) return NULL; } - n = ImagingDrawRectangle(self->image->image, - (int) xy[0], (int) xy[1], - (int) xy[2], (int) xy[3], - &ink, fill, width, self->blend - ); + n = ImagingDrawEllipse( + self->image->image, + (int)xy[0], + (int)xy[1], + (int)xy[2], + (int)xy[3], + &ink, + fill, + width, + self->blend); + + free(xy); + + if (n < 0) { + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +_draw_lines(ImagingDrawObject *self, PyObject *args) { + double *xy; + Py_ssize_t i, n; + + PyObject *data; + int ink; + int width = 0; + if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &width)) { + return NULL; + } + + n = PyPath_Flatten(data, &xy); + if (n < 0) { + return NULL; + } + + if (width <= 1) { + double *p = NULL; + for (i = 0; i < n - 1; i++) { + p = &xy[i + i]; + if (ImagingDrawLine( + self->image->image, + (int)p[0], + (int)p[1], + (int)p[2], + (int)p[3], + &ink, + self->blend) < 0) { + free(xy); + return NULL; + } + } + if (p) { /* draw last point */ + ImagingDrawPoint( + self->image->image, (int)p[2], (int)p[3], &ink, self->blend); + } + } else { + for (i = 0; i < n - 1; i++) { + double *p = &xy[i + i]; + if (ImagingDrawWideLine( + self->image->image, + (int)p[0], + (int)p[1], + (int)p[2], + (int)p[3], + &ink, + width, + self->blend) < 0) { + free(xy); + return NULL; + } + } + } + + free(xy); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +_draw_points(ImagingDrawObject *self, PyObject *args) { + double *xy; + Py_ssize_t i, n; + + PyObject *data; + int ink; + if (!PyArg_ParseTuple(args, "Oi", &data, &ink)) { + return NULL; + } + + n = PyPath_Flatten(data, &xy); + if (n < 0) { + return NULL; + } + + for (i = 0; i < n; i++) { + double *p = &xy[i + i]; + if (ImagingDrawPoint( + self->image->image, (int)p[0], (int)p[1], &ink, self->blend) < 0) { + free(xy); + return NULL; + } + } + + free(xy); + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef WITH_ARROW + +/* from outline.c */ +extern ImagingOutline +PyOutline_AsOutline(PyObject *outline); + +static PyObject * +_draw_outline(ImagingDrawObject *self, PyObject *args) { + ImagingOutline outline; + + PyObject *outline_; + int ink; + int fill = 0; + if (!PyArg_ParseTuple(args, "Oi|i", &outline_, &ink, &fill)) { + return NULL; + } + + outline = PyOutline_AsOutline(outline_); + if (!outline) { + PyErr_SetString(PyExc_TypeError, "expected outline object"); + return NULL; + } + + if (ImagingDrawOutline(self->image->image, outline, &ink, fill, self->blend) < 0) { + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +#endif + +static PyObject * +_draw_pieslice(ImagingDrawObject *self, PyObject *args) { + double *xy; + Py_ssize_t n; + + PyObject *data; + int ink, fill; + int width = 0; + float start, end; + if (!PyArg_ParseTuple(args, "Offii|i", &data, &start, &end, &ink, &fill, &width)) { + return NULL; + } + + n = PyPath_Flatten(data, &xy); + if (n < 0) { + return NULL; + } + if (n != 2) { + PyErr_SetString(PyExc_TypeError, must_be_two_coordinates); + free(xy); + return NULL; + } + + n = ImagingDrawPieslice( + self->image->image, + (int)xy[0], + (int)xy[1], + (int)xy[2], + (int)xy[3], + start, + end, + &ink, + fill, + width, + self->blend); + + free(xy); + + if (n < 0) { + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +_draw_polygon(ImagingDrawObject *self, PyObject *args) { + double *xy; + int *ixy; + Py_ssize_t n, i; + + PyObject *data; + int ink; + int fill = 0; + if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &fill)) { + return NULL; + } + + n = PyPath_Flatten(data, &xy); + if (n < 0) { + return NULL; + } + if (n < 2) { + PyErr_SetString( + PyExc_TypeError, "coordinate list must contain at least 2 coordinates"); + free(xy); + return NULL; + } + + /* Copy list of vertices to array */ + ixy = (int *)calloc(n, 2 * sizeof(int)); + if (ixy == NULL) { + free(xy); + return ImagingError_MemoryError(); + } + + for (i = 0; i < n; i++) { + ixy[i + i] = (int)xy[i + i]; + ixy[i + i + 1] = (int)xy[i + i + 1]; + } + + free(xy); + + if (ImagingDrawPolygon(self->image->image, n, ixy, &ink, fill, self->blend) < 0) { + free(ixy); + return NULL; + } + + free(ixy); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +_draw_rectangle(ImagingDrawObject *self, PyObject *args) { + double *xy; + Py_ssize_t n; + + PyObject *data; + int ink; + int fill = 0; + int width = 0; + if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width)) { + return NULL; + } + + n = PyPath_Flatten(data, &xy); + if (n < 0) { + return NULL; + } + if (n != 2) { + PyErr_SetString(PyExc_TypeError, must_be_two_coordinates); + free(xy); + return NULL; + } + + n = ImagingDrawRectangle( + self->image->image, + (int)xy[0], + (int)xy[1], + (int)xy[2], + (int)xy[3], + &ink, + fill, + width, + self->blend); free(xy); @@ -3246,29 +3211,27 @@ _draw_rectangle(ImagingDrawObject* self, PyObject* args) static struct PyMethodDef _draw_methods[] = { #ifdef WITH_IMAGEDRAW /* Graphics (ImageDraw) */ - {"draw_lines", (PyCFunction)_draw_lines, 1}, + {"draw_lines", (PyCFunction)_draw_lines, METH_VARARGS}, #ifdef WITH_ARROW - {"draw_outline", (PyCFunction)_draw_outline, 1}, + {"draw_outline", (PyCFunction)_draw_outline, METH_VARARGS}, #endif - {"draw_polygon", (PyCFunction)_draw_polygon, 1}, - {"draw_rectangle", (PyCFunction)_draw_rectangle, 1}, - {"draw_points", (PyCFunction)_draw_points, 1}, - {"draw_arc", (PyCFunction)_draw_arc, 1}, - {"draw_bitmap", (PyCFunction)_draw_bitmap, 1}, - {"draw_chord", (PyCFunction)_draw_chord, 1}, - {"draw_ellipse", (PyCFunction)_draw_ellipse, 1}, - {"draw_pieslice", (PyCFunction)_draw_pieslice, 1}, - {"draw_ink", (PyCFunction)_draw_ink, 1}, + {"draw_polygon", (PyCFunction)_draw_polygon, METH_VARARGS}, + {"draw_rectangle", (PyCFunction)_draw_rectangle, METH_VARARGS}, + {"draw_points", (PyCFunction)_draw_points, METH_VARARGS}, + {"draw_arc", (PyCFunction)_draw_arc, METH_VARARGS}, + {"draw_bitmap", (PyCFunction)_draw_bitmap, METH_VARARGS}, + {"draw_chord", (PyCFunction)_draw_chord, METH_VARARGS}, + {"draw_ellipse", (PyCFunction)_draw_ellipse, METH_VARARGS}, + {"draw_pieslice", (PyCFunction)_draw_pieslice, METH_VARARGS}, + {"draw_ink", (PyCFunction)_draw_ink, METH_VARARGS}, #endif {NULL, NULL} /* sentinel */ }; #endif - -static PyObject* -pixel_access_new(ImagingObject* imagep, PyObject* args) -{ +static PyObject * +pixel_access_new(ImagingObject *imagep, PyObject *args) { PixelAccessObject *self; int readonly = 0; @@ -3287,19 +3250,17 @@ pixel_access_new(ImagingObject* imagep, PyObject* args) self->readonly = readonly; - return (PyObject*) self; + return (PyObject *)self; } static void -pixel_access_dealloc(PixelAccessObject* self) -{ +pixel_access_dealloc(PixelAccessObject *self) { Py_XDECREF(self->image); PyObject_Del(self); } static PyObject * -pixel_access_getitem(PixelAccessObject *self, PyObject *xy) -{ +pixel_access_getitem(PixelAccessObject *self, PyObject *xy) { int x, y; if (_getxy(xy, &x, &y)) { return NULL; @@ -3309,14 +3270,13 @@ pixel_access_getitem(PixelAccessObject *self, PyObject *xy) } static int -pixel_access_setitem(PixelAccessObject *self, PyObject *xy, PyObject *color) -{ +pixel_access_setitem(PixelAccessObject *self, PyObject *xy, PyObject *color) { Imaging im = self->image->image; char ink[4]; int x, y; if (self->readonly) { - (void) ImagingError_ValueError(readonly); + (void)ImagingError_ValueError(readonly); return -1; } @@ -3336,7 +3296,7 @@ pixel_access_setitem(PixelAccessObject *self, PyObject *xy, PyObject *color) return -1; } - if (!color) {/* FIXME: raise exception? */ + if (!color) { /* FIXME: raise exception? */ return 0; } @@ -3355,29 +3315,36 @@ pixel_access_setitem(PixelAccessObject *self, PyObject *xy, PyObject *color) #ifdef WITH_EFFECTS -static PyObject* -_effect_mandelbrot(ImagingObject* self, PyObject* args) -{ +static PyObject * +_effect_mandelbrot(ImagingObject *self, PyObject *args) { int xsize = 512; int ysize = 512; double extent[4]; int quality = 100; - extent[0] = -3; extent[1] = -2.5; - extent[2] = 2; extent[3] = 2.5; + extent[0] = -3; + extent[1] = -2.5; + extent[2] = 2; + extent[3] = 2.5; - if (!PyArg_ParseTuple(args, "|(ii)(dddd)i", &xsize, &ysize, - &extent[0], &extent[1], &extent[2], &extent[3], - &quality)) { + if (!PyArg_ParseTuple( + args, + "|(ii)(dddd)i", + &xsize, + &ysize, + &extent[0], + &extent[1], + &extent[2], + &extent[3], + &quality)) { return NULL; } return PyImagingNew(ImagingEffectMandelbrot(xsize, ysize, extent, quality)); } -static PyObject* -_effect_noise(ImagingObject* self, PyObject* args) -{ +static PyObject * +_effect_noise(ImagingObject *self, PyObject *args) { int xsize, ysize; float sigma = 128; if (!PyArg_ParseTuple(args, "(ii)|f", &xsize, &ysize, &sigma)) { @@ -3387,9 +3354,8 @@ _effect_noise(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingEffectNoise(xsize, ysize, sigma)); } -static PyObject* -_effect_spread(ImagingObject* self, PyObject* args) -{ +static PyObject * +_effect_spread(ImagingObject *self, PyObject *args) { int dist; if (!PyArg_ParseTuple(args, "i", &dist)) { @@ -3405,30 +3371,33 @@ _effect_spread(ImagingObject* self, PyObject* args) /* UTILITIES */ /* -------------------------------------------------------------------- */ - -static PyObject* -_getcodecstatus(PyObject* self, PyObject* args) -{ +static PyObject * +_getcodecstatus(PyObject *self, PyObject *args) { int status; - char* msg; + char *msg; if (!PyArg_ParseTuple(args, "i", &status)) { return NULL; } switch (status) { - case IMAGING_CODEC_OVERRUN: - msg = "buffer overrun"; break; - case IMAGING_CODEC_BROKEN: - msg = "broken data stream"; break; - case IMAGING_CODEC_UNKNOWN: - msg = "unrecognized data stream contents"; break; - case IMAGING_CODEC_CONFIG: - msg = "codec configuration error"; break; - case IMAGING_CODEC_MEMORY: - msg = "out of memory"; break; - default: - Py_RETURN_NONE; + case IMAGING_CODEC_OVERRUN: + msg = "buffer overrun"; + break; + case IMAGING_CODEC_BROKEN: + msg = "broken data stream"; + break; + case IMAGING_CODEC_UNKNOWN: + msg = "unrecognized data stream contents"; + break; + case IMAGING_CODEC_CONFIG: + msg = "codec configuration error"; + break; + case IMAGING_CODEC_MEMORY: + msg = "out of memory"; + break; + default: + Py_RETURN_NONE; } return PyUnicode_FromString(msg); @@ -3438,11 +3407,9 @@ _getcodecstatus(PyObject* self, PyObject* args) /* DEBUGGING HELPERS */ /* -------------------------------------------------------------------- */ - -static PyObject* -_save_ppm(ImagingObject* self, PyObject* args) -{ - char* filename; +static PyObject * +_save_ppm(ImagingObject *self, PyObject *args) { + char *filename; if (!PyArg_ParseTuple(args, "s", &filename)) { return NULL; @@ -3456,7 +3423,6 @@ _save_ppm(ImagingObject* self, PyObject* args) return Py_None; } - /* -------------------------------------------------------------------- */ /* methods */ @@ -3464,171 +3430,163 @@ _save_ppm(ImagingObject* self, PyObject* args) static struct PyMethodDef methods[] = { /* Put commonly used methods first */ - {"getpixel", (PyCFunction)_getpixel, 1}, - {"putpixel", (PyCFunction)_putpixel, 1}, + {"getpixel", (PyCFunction)_getpixel, METH_VARARGS}, + {"putpixel", (PyCFunction)_putpixel, METH_VARARGS}, - {"pixel_access", (PyCFunction)pixel_access_new, 1}, + {"pixel_access", (PyCFunction)pixel_access_new, METH_VARARGS}, /* Standard processing methods (Image) */ - {"color_lut_3d", (PyCFunction)_color_lut_3d, 1}, - {"convert", (PyCFunction)_convert, 1}, - {"convert2", (PyCFunction)_convert2, 1}, - {"convert_matrix", (PyCFunction)_convert_matrix, 1}, - {"convert_transparent", (PyCFunction)_convert_transparent, 1}, - {"copy", (PyCFunction)_copy, 1}, - {"crop", (PyCFunction)_crop, 1}, - {"expand", (PyCFunction)_expand_image, 1}, - {"filter", (PyCFunction)_filter, 1}, - {"histogram", (PyCFunction)_histogram, 1}, - {"entropy", (PyCFunction)_entropy, 1}, + {"color_lut_3d", (PyCFunction)_color_lut_3d, METH_VARARGS}, + {"convert", (PyCFunction)_convert, METH_VARARGS}, + {"convert2", (PyCFunction)_convert2, METH_VARARGS}, + {"convert_matrix", (PyCFunction)_convert_matrix, METH_VARARGS}, + {"convert_transparent", (PyCFunction)_convert_transparent, METH_VARARGS}, + {"copy", (PyCFunction)_copy, METH_VARARGS}, + {"crop", (PyCFunction)_crop, METH_VARARGS}, + {"expand", (PyCFunction)_expand_image, METH_VARARGS}, + {"filter", (PyCFunction)_filter, METH_VARARGS}, + {"histogram", (PyCFunction)_histogram, METH_VARARGS}, + {"entropy", (PyCFunction)_entropy, METH_VARARGS}, #ifdef WITH_MODEFILTER - {"modefilter", (PyCFunction)_modefilter, 1}, + {"modefilter", (PyCFunction)_modefilter, METH_VARARGS}, #endif - {"offset", (PyCFunction)_offset, 1}, - {"paste", (PyCFunction)_paste, 1}, - {"point", (PyCFunction)_point, 1}, - {"point_transform", (PyCFunction)_point_transform, 1}, - {"putdata", (PyCFunction)_putdata, 1}, + {"offset", (PyCFunction)_offset, METH_VARARGS}, + {"paste", (PyCFunction)_paste, METH_VARARGS}, + {"point", (PyCFunction)_point, METH_VARARGS}, + {"point_transform", (PyCFunction)_point_transform, METH_VARARGS}, + {"putdata", (PyCFunction)_putdata, METH_VARARGS}, #ifdef WITH_QUANTIZE - {"quantize", (PyCFunction)_quantize, 1}, + {"quantize", (PyCFunction)_quantize, METH_VARARGS}, #endif #ifdef WITH_RANKFILTER - {"rankfilter", (PyCFunction)_rankfilter, 1}, + {"rankfilter", (PyCFunction)_rankfilter, METH_VARARGS}, #endif - {"resize", (PyCFunction)_resize, 1}, - {"reduce", (PyCFunction)_reduce, 1}, - {"transpose", (PyCFunction)_transpose, 1}, - {"transform2", (PyCFunction)_transform2, 1}, + {"resize", (PyCFunction)_resize, METH_VARARGS}, + {"reduce", (PyCFunction)_reduce, METH_VARARGS}, + {"transpose", (PyCFunction)_transpose, METH_VARARGS}, + {"transform2", (PyCFunction)_transform2, METH_VARARGS}, - {"isblock", (PyCFunction)_isblock, 1}, + {"isblock", (PyCFunction)_isblock, METH_NOARGS}, - {"getbbox", (PyCFunction)_getbbox, 1}, - {"getcolors", (PyCFunction)_getcolors, 1}, - {"getextrema", (PyCFunction)_getextrema, 1}, - {"getprojection", (PyCFunction)_getprojection, 1}, + {"getbbox", (PyCFunction)_getbbox, METH_NOARGS}, + {"getcolors", (PyCFunction)_getcolors, METH_VARARGS}, + {"getextrema", (PyCFunction)_getextrema, METH_NOARGS}, + {"getprojection", (PyCFunction)_getprojection, METH_NOARGS}, - {"getband", (PyCFunction)_getband, 1}, - {"putband", (PyCFunction)_putband, 1}, - {"split", (PyCFunction)_split, 1}, - {"fillband", (PyCFunction)_fillband, 1}, + {"getband", (PyCFunction)_getband, METH_VARARGS}, + {"putband", (PyCFunction)_putband, METH_VARARGS}, + {"split", (PyCFunction)_split, METH_NOARGS}, + {"fillband", (PyCFunction)_fillband, METH_VARARGS}, - {"setmode", (PyCFunction)im_setmode, 1}, + {"setmode", (PyCFunction)im_setmode, METH_VARARGS}, - {"getpalette", (PyCFunction)_getpalette, 1}, - {"getpalettemode", (PyCFunction)_getpalettemode, 1}, - {"putpalette", (PyCFunction)_putpalette, 1}, - {"putpalettealpha", (PyCFunction)_putpalettealpha, 1}, - {"putpalettealphas", (PyCFunction)_putpalettealphas, 1}, + {"getpalette", (PyCFunction)_getpalette, METH_VARARGS}, + {"getpalettemode", (PyCFunction)_getpalettemode, METH_NOARGS}, + {"putpalette", (PyCFunction)_putpalette, METH_VARARGS}, + {"putpalettealpha", (PyCFunction)_putpalettealpha, METH_VARARGS}, + {"putpalettealphas", (PyCFunction)_putpalettealphas, METH_VARARGS}, #ifdef WITH_IMAGECHOPS /* Channel operations (ImageChops) */ - {"chop_invert", (PyCFunction)_chop_invert, 1}, - {"chop_lighter", (PyCFunction)_chop_lighter, 1}, - {"chop_darker", (PyCFunction)_chop_darker, 1}, - {"chop_difference", (PyCFunction)_chop_difference, 1}, - {"chop_multiply", (PyCFunction)_chop_multiply, 1}, - {"chop_screen", (PyCFunction)_chop_screen, 1}, - {"chop_add", (PyCFunction)_chop_add, 1}, - {"chop_subtract", (PyCFunction)_chop_subtract, 1}, - {"chop_add_modulo", (PyCFunction)_chop_add_modulo, 1}, - {"chop_subtract_modulo", (PyCFunction)_chop_subtract_modulo, 1}, - {"chop_and", (PyCFunction)_chop_and, 1}, - {"chop_or", (PyCFunction)_chop_or, 1}, - {"chop_xor", (PyCFunction)_chop_xor, 1}, - {"chop_soft_light", (PyCFunction)_chop_soft_light, 1}, - {"chop_hard_light", (PyCFunction)_chop_hard_light, 1}, - {"chop_overlay", (PyCFunction)_chop_overlay, 1}, + {"chop_invert", (PyCFunction)_chop_invert, METH_NOARGS}, + {"chop_lighter", (PyCFunction)_chop_lighter, METH_VARARGS}, + {"chop_darker", (PyCFunction)_chop_darker, METH_VARARGS}, + {"chop_difference", (PyCFunction)_chop_difference, METH_VARARGS}, + {"chop_multiply", (PyCFunction)_chop_multiply, METH_VARARGS}, + {"chop_screen", (PyCFunction)_chop_screen, METH_VARARGS}, + {"chop_add", (PyCFunction)_chop_add, METH_VARARGS}, + {"chop_subtract", (PyCFunction)_chop_subtract, METH_VARARGS}, + {"chop_add_modulo", (PyCFunction)_chop_add_modulo, METH_VARARGS}, + {"chop_subtract_modulo", (PyCFunction)_chop_subtract_modulo, METH_VARARGS}, + {"chop_and", (PyCFunction)_chop_and, METH_VARARGS}, + {"chop_or", (PyCFunction)_chop_or, METH_VARARGS}, + {"chop_xor", (PyCFunction)_chop_xor, METH_VARARGS}, + {"chop_soft_light", (PyCFunction)_chop_soft_light, METH_VARARGS}, + {"chop_hard_light", (PyCFunction)_chop_hard_light, METH_VARARGS}, + {"chop_overlay", (PyCFunction)_chop_overlay, METH_VARARGS}, #endif #ifdef WITH_UNSHARPMASK /* Kevin Cazabon's unsharpmask extension */ - {"gaussian_blur", (PyCFunction)_gaussian_blur, 1}, - {"unsharp_mask", (PyCFunction)_unsharp_mask, 1}, + {"gaussian_blur", (PyCFunction)_gaussian_blur, METH_VARARGS}, + {"unsharp_mask", (PyCFunction)_unsharp_mask, METH_VARARGS}, #endif - {"box_blur", (PyCFunction)_box_blur, 1}, + {"box_blur", (PyCFunction)_box_blur, METH_VARARGS}, #ifdef WITH_EFFECTS /* Special effects */ - {"effect_spread", (PyCFunction)_effect_spread, 1}, + {"effect_spread", (PyCFunction)_effect_spread, METH_VARARGS}, #endif /* Misc. */ - {"new_block", (PyCFunction)_new_block, 1}, + {"new_block", (PyCFunction)_new_block, METH_VARARGS}, - {"save_ppm", (PyCFunction)_save_ppm, 1}, + {"save_ppm", (PyCFunction)_save_ppm, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; - /* attributes */ -static PyObject* -_getattr_mode(ImagingObject* self, void* closure) -{ +static PyObject * +_getattr_mode(ImagingObject *self, void *closure) { return PyUnicode_FromString(self->image->mode); } -static PyObject* -_getattr_size(ImagingObject* self, void* closure) -{ +static PyObject * +_getattr_size(ImagingObject *self, void *closure) { return Py_BuildValue("ii", self->image->xsize, self->image->ysize); } -static PyObject* -_getattr_bands(ImagingObject* self, void* closure) -{ +static PyObject * +_getattr_bands(ImagingObject *self, void *closure) { return PyLong_FromLong(self->image->bands); } -static PyObject* -_getattr_id(ImagingObject* self, void* closure) -{ - return PyLong_FromSsize_t((Py_ssize_t) self->image); +static PyObject * +_getattr_id(ImagingObject *self, void *closure) { + return PyLong_FromSsize_t((Py_ssize_t)self->image); } -static PyObject* -_getattr_ptr(ImagingObject* self, void* closure) -{ +static PyObject * +_getattr_ptr(ImagingObject *self, void *closure) { return PyCapsule_New(self->image, IMAGING_MAGIC, NULL); } -static PyObject* -_getattr_unsafe_ptrs(ImagingObject* self, void* closure) -{ - return Py_BuildValue("(sn)(sn)(sn)", - "image8", self->image->image8, - "image32", self->image->image32, - "image", self->image->image - ); +static PyObject * +_getattr_unsafe_ptrs(ImagingObject *self, void *closure) { + return Py_BuildValue( + "(sn)(sn)(sn)", + "image8", + self->image->image8, + "image32", + self->image->image32, + "image", + self->image->image); }; - static struct PyGetSetDef getsetters[] = { - { "mode", (getter) _getattr_mode }, - { "size", (getter) _getattr_size }, - { "bands", (getter) _getattr_bands }, - { "id", (getter) _getattr_id }, - { "ptr", (getter) _getattr_ptr }, - { "unsafe_ptrs", (getter) _getattr_unsafe_ptrs }, - { NULL } -}; + {"mode", (getter)_getattr_mode}, + {"size", (getter)_getattr_size}, + {"bands", (getter)_getattr_bands}, + {"id", (getter)_getattr_id}, + {"ptr", (getter)_getattr_ptr}, + {"unsafe_ptrs", (getter)_getattr_unsafe_ptrs}, + {NULL}}; /* basic sequence semantics */ static Py_ssize_t -image_length(ImagingObject *self) -{ +image_length(ImagingObject *self) { Imaging im = self->image; - return (Py_ssize_t) im->xsize * im->ysize; + return (Py_ssize_t)im->xsize * im->ysize; } static PyObject * -image_item(ImagingObject *self, Py_ssize_t i) -{ +image_item(ImagingObject *self, Py_ssize_t i) { int x, y; Imaging im = self->image; @@ -3643,154 +3601,150 @@ image_item(ImagingObject *self, Py_ssize_t i) } static PySequenceMethods image_as_sequence = { - (lenfunc) image_length, /*sq_length*/ - (binaryfunc) NULL, /*sq_concat*/ - (ssizeargfunc) NULL, /*sq_repeat*/ - (ssizeargfunc) image_item, /*sq_item*/ - (ssizessizeargfunc) NULL, /*sq_slice*/ - (ssizeobjargproc) NULL, /*sq_ass_item*/ - (ssizessizeobjargproc) NULL, /*sq_ass_slice*/ + (lenfunc)image_length, /*sq_length*/ + (binaryfunc)NULL, /*sq_concat*/ + (ssizeargfunc)NULL, /*sq_repeat*/ + (ssizeargfunc)image_item, /*sq_item*/ + (ssizessizeargfunc)NULL, /*sq_slice*/ + (ssizeobjargproc)NULL, /*sq_ass_item*/ + (ssizessizeobjargproc)NULL, /*sq_ass_slice*/ }; - /* type description */ static PyTypeObject Imaging_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "ImagingCore", /*tp_name*/ - sizeof(ImagingObject), /*tp_size*/ - 0, /*tp_itemsize*/ + PyVarObject_HEAD_INIT(NULL, 0) "ImagingCore", /*tp_name*/ + sizeof(ImagingObject), /*tp_size*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - &image_as_sequence, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - methods, /*tp_methods*/ - 0, /*tp_members*/ - getsetters, /*tp_getset*/ + (destructor)_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + &image_as_sequence, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + methods, /*tp_methods*/ + 0, /*tp_members*/ + getsetters, /*tp_getset*/ }; #ifdef WITH_IMAGEDRAW static PyTypeObject ImagingFont_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "ImagingFont", /*tp_name*/ - sizeof(ImagingFontObject), /*tp_size*/ - 0, /*tp_itemsize*/ + PyVarObject_HEAD_INIT(NULL, 0) "ImagingFont", /*tp_name*/ + sizeof(ImagingFontObject), /*tp_size*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)_font_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - _font_methods, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ + (destructor)_font_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + _font_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ }; static PyTypeObject ImagingDraw_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "ImagingDraw", /*tp_name*/ - sizeof(ImagingDrawObject), /*tp_size*/ - 0, /*tp_itemsize*/ + PyVarObject_HEAD_INIT(NULL, 0) "ImagingDraw", /*tp_name*/ + sizeof(ImagingDrawObject), /*tp_size*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)_draw_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - _draw_methods, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ + (destructor)_draw_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + _draw_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ }; #endif static PyMappingMethods pixel_access_as_mapping = { - (lenfunc) NULL, /*mp_length*/ - (binaryfunc) pixel_access_getitem, /*mp_subscript*/ - (objobjargproc) pixel_access_setitem, /*mp_ass_subscript*/ + (lenfunc)NULL, /*mp_length*/ + (binaryfunc)pixel_access_getitem, /*mp_subscript*/ + (objobjargproc)pixel_access_setitem, /*mp_ass_subscript*/ }; /* type description */ static PyTypeObject PixelAccess_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "PixelAccess", sizeof(PixelAccessObject), 0, + PyVarObject_HEAD_INIT(NULL, 0) "PixelAccess", + sizeof(PixelAccessObject), + 0, /* methods */ (destructor)pixel_access_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - &pixel_access_as_mapping, /*tp_as_mapping */ - 0 /*tp_hash*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + &pixel_access_as_mapping, /*tp_as_mapping */ + 0 /*tp_hash*/ }; /* -------------------------------------------------------------------- */ -static PyObject* -_get_stats(PyObject* self, PyObject* args) -{ - PyObject* d; +static PyObject * +_get_stats(PyObject *self, PyObject *args) { + PyObject *d; ImagingMemoryArena arena = &ImagingDefaultArena; if (!PyArg_ParseTuple(args, ":get_stats")) { @@ -3798,27 +3752,23 @@ _get_stats(PyObject* self, PyObject* args) } d = PyDict_New(); - if ( ! d) { + if (!d) { return NULL; } - PyDict_SetItemString(d, "new_count", - PyLong_FromLong(arena->stats_new_count)); - PyDict_SetItemString(d, "allocated_blocks", - PyLong_FromLong(arena->stats_allocated_blocks)); - PyDict_SetItemString(d, "reused_blocks", - PyLong_FromLong(arena->stats_reused_blocks)); - PyDict_SetItemString(d, "reallocated_blocks", - PyLong_FromLong(arena->stats_reallocated_blocks)); - PyDict_SetItemString(d, "freed_blocks", - PyLong_FromLong(arena->stats_freed_blocks)); - PyDict_SetItemString(d, "blocks_cached", - PyLong_FromLong(arena->blocks_cached)); + PyDict_SetItemString(d, "new_count", PyLong_FromLong(arena->stats_new_count)); + PyDict_SetItemString( + d, "allocated_blocks", PyLong_FromLong(arena->stats_allocated_blocks)); + PyDict_SetItemString( + d, "reused_blocks", PyLong_FromLong(arena->stats_reused_blocks)); + PyDict_SetItemString( + d, "reallocated_blocks", PyLong_FromLong(arena->stats_reallocated_blocks)); + PyDict_SetItemString(d, "freed_blocks", PyLong_FromLong(arena->stats_freed_blocks)); + PyDict_SetItemString(d, "blocks_cached", PyLong_FromLong(arena->blocks_cached)); return d; } -static PyObject* -_reset_stats(PyObject* self, PyObject* args) -{ +static PyObject * +_reset_stats(PyObject *self, PyObject *args) { ImagingMemoryArena arena = &ImagingDefaultArena; if (!PyArg_ParseTuple(args, ":reset_stats")) { @@ -3835,9 +3785,8 @@ _reset_stats(PyObject* self, PyObject* args) return Py_None; } -static PyObject* -_get_alignment(PyObject* self, PyObject* args) -{ +static PyObject * +_get_alignment(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_alignment")) { return NULL; } @@ -3845,9 +3794,8 @@ _get_alignment(PyObject* self, PyObject* args) return PyLong_FromLong(ImagingDefaultArena.alignment); } -static PyObject* -_get_block_size(PyObject* self, PyObject* args) -{ +static PyObject * +_get_block_size(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_block_size")) { return NULL; } @@ -3855,9 +3803,8 @@ _get_block_size(PyObject* self, PyObject* args) return PyLong_FromLong(ImagingDefaultArena.block_size); } -static PyObject* -_get_blocks_max(PyObject* self, PyObject* args) -{ +static PyObject * +_get_blocks_max(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":get_blocks_max")) { return NULL; } @@ -3865,9 +3812,8 @@ _get_blocks_max(PyObject* self, PyObject* args) return PyLong_FromLong(ImagingDefaultArena.blocks_max); } -static PyObject* -_set_alignment(PyObject* self, PyObject* args) -{ +static PyObject * +_set_alignment(PyObject *self, PyObject *args) { int alignment; if (!PyArg_ParseTuple(args, "i:set_alignment", &alignment)) { return NULL; @@ -3889,23 +3835,20 @@ _set_alignment(PyObject* self, PyObject* args) return Py_None; } -static PyObject* -_set_block_size(PyObject* self, PyObject* args) -{ +static PyObject * +_set_block_size(PyObject *self, PyObject *args) { int block_size; if (!PyArg_ParseTuple(args, "i:set_block_size", &block_size)) { return NULL; } if (block_size <= 0) { - PyErr_SetString(PyExc_ValueError, - "block_size should be greater than 0"); + PyErr_SetString(PyExc_ValueError, "block_size should be greater than 0"); return NULL; } if (block_size & 0xfff) { - PyErr_SetString(PyExc_ValueError, - "block_size should be multiple of 4096"); + PyErr_SetString(PyExc_ValueError, "block_size should be multiple of 4096"); return NULL; } @@ -3915,27 +3858,24 @@ _set_block_size(PyObject* self, PyObject* args) return Py_None; } -static PyObject* -_set_blocks_max(PyObject* self, PyObject* args) -{ +static PyObject * +_set_blocks_max(PyObject *self, PyObject *args) { int blocks_max; if (!PyArg_ParseTuple(args, "i:set_blocks_max", &blocks_max)) { return NULL; } if (blocks_max < 0) { - PyErr_SetString(PyExc_ValueError, - "blocks_max should be greater than 0"); + PyErr_SetString(PyExc_ValueError, "blocks_max should be greater than 0"); return NULL; - } - else if ( (unsigned long)blocks_max > SIZE_MAX/sizeof(ImagingDefaultArena.blocks_pool[0])) { - PyErr_SetString(PyExc_ValueError, - "blocks_max is too large"); + } else if ( + (unsigned long)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)) { return ImagingError_MemoryError(); } @@ -3943,9 +3883,8 @@ _set_blocks_max(PyObject* self, PyObject* args) return Py_None; } -static PyObject* -_clear_cache(PyObject* self, PyObject* args) -{ +static PyObject * +_clear_cache(PyObject *self, PyObject *args) { int i = 0; if (!PyArg_ParseTuple(args, "|i:clear_cache", &i)) { @@ -3964,179 +3903,214 @@ _clear_cache(PyObject* self, PyObject* args) pluggable codecs, but not before PIL 1.2 */ /* Decoders (in decode.c) */ -extern PyObject* PyImaging_BcnDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_BitDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_FliDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_GifDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_HexDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_JpegDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_PackbitsDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_PcdDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_PcxDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_RawDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_SgiRleDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_SunRleDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_TgaRleDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_XbmDecoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_ZipDecoderNew(PyObject* self, PyObject* args); +extern PyObject * +PyImaging_BcnDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_BitDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_FliDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_GifDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_HexDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_JpegDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_Jpeg2KDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_LibTiffDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_PackbitsDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_PcdDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_PcxDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_RawDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_SgiRleDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_SunRleDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_TgaRleDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_XbmDecoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_ZipDecoderNew(PyObject *self, PyObject *args); /* Encoders (in encode.c) */ -extern PyObject* PyImaging_EpsEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_GifEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_JpegEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_Jpeg2KEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_PcxEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_TgaRleEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_XbmEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_ZipEncoderNew(PyObject* self, PyObject* args); -extern PyObject* PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args); +extern PyObject * +PyImaging_EpsEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_GifEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_JpegEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_PcxEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_RawEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_TgaRleEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_XbmEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_ZipEncoderNew(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args); /* Display support etc (in display.c) */ #ifdef _WIN32 -extern PyObject* PyImaging_CreateWindowWin32(PyObject* self, PyObject* args); -extern PyObject* PyImaging_DisplayWin32(PyObject* self, PyObject* args); -extern PyObject* PyImaging_DisplayModeWin32(PyObject* self, PyObject* args); -extern PyObject* PyImaging_GrabScreenWin32(PyObject* self, PyObject* args); -extern PyObject* PyImaging_GrabClipboardWin32(PyObject* self, PyObject* args); -extern PyObject* PyImaging_ListWindowsWin32(PyObject* self, PyObject* args); -extern PyObject* PyImaging_EventLoopWin32(PyObject* self, PyObject* args); -extern PyObject* PyImaging_DrawWmf(PyObject* self, PyObject* args); +extern PyObject * +PyImaging_CreateWindowWin32(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_DisplayWin32(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_DisplayModeWin32(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_GrabScreenWin32(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_GrabClipboardWin32(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_ListWindowsWin32(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_EventLoopWin32(PyObject *self, PyObject *args); +extern PyObject * +PyImaging_DrawWmf(PyObject *self, PyObject *args); #endif #ifdef HAVE_XCB -extern PyObject* PyImaging_GrabScreenX11(PyObject* self, PyObject* args); +extern PyObject * +PyImaging_GrabScreenX11(PyObject *self, PyObject *args); #endif /* Experimental path stuff (in path.c) */ -extern PyObject* PyPath_Create(ImagingObject* self, PyObject* args); +extern PyObject * +PyPath_Create(ImagingObject *self, PyObject *args); /* Experimental outline stuff (in outline.c) */ -extern PyObject* PyOutline_Create(ImagingObject* self, PyObject* args); +extern PyObject * +PyOutline_Create(ImagingObject *self, PyObject *args); -extern PyObject* PyImaging_Mapper(PyObject* self, PyObject* args); -extern PyObject* PyImaging_MapBuffer(PyObject* self, PyObject* args); +extern PyObject * +PyImaging_MapBuffer(PyObject *self, PyObject *args); static PyMethodDef functions[] = { /* Object factories */ - {"alpha_composite", (PyCFunction)_alpha_composite, 1}, - {"blend", (PyCFunction)_blend, 1}, - {"fill", (PyCFunction)_fill, 1}, - {"new", (PyCFunction)_new, 1}, - {"merge", (PyCFunction)_merge, 1}, + {"alpha_composite", (PyCFunction)_alpha_composite, METH_VARARGS}, + {"blend", (PyCFunction)_blend, METH_VARARGS}, + {"fill", (PyCFunction)_fill, METH_VARARGS}, + {"new", (PyCFunction)_new, METH_VARARGS}, + {"merge", (PyCFunction)_merge, METH_VARARGS}, /* Functions */ - {"convert", (PyCFunction)_convert2, 1}, + {"convert", (PyCFunction)_convert2, METH_VARARGS}, /* Codecs */ - {"bcn_decoder", (PyCFunction)PyImaging_BcnDecoderNew, 1}, - {"bit_decoder", (PyCFunction)PyImaging_BitDecoderNew, 1}, - {"eps_encoder", (PyCFunction)PyImaging_EpsEncoderNew, 1}, - {"fli_decoder", (PyCFunction)PyImaging_FliDecoderNew, 1}, - {"gif_decoder", (PyCFunction)PyImaging_GifDecoderNew, 1}, - {"gif_encoder", (PyCFunction)PyImaging_GifEncoderNew, 1}, - {"hex_decoder", (PyCFunction)PyImaging_HexDecoderNew, 1}, - {"hex_encoder", (PyCFunction)PyImaging_EpsEncoderNew, 1}, /* EPS=HEX! */ + {"bcn_decoder", (PyCFunction)PyImaging_BcnDecoderNew, METH_VARARGS}, + {"bit_decoder", (PyCFunction)PyImaging_BitDecoderNew, METH_VARARGS}, + {"eps_encoder", (PyCFunction)PyImaging_EpsEncoderNew, METH_VARARGS}, + {"fli_decoder", (PyCFunction)PyImaging_FliDecoderNew, METH_VARARGS}, + {"gif_decoder", (PyCFunction)PyImaging_GifDecoderNew, METH_VARARGS}, + {"gif_encoder", (PyCFunction)PyImaging_GifEncoderNew, METH_VARARGS}, + {"hex_decoder", (PyCFunction)PyImaging_HexDecoderNew, METH_VARARGS}, + {"hex_encoder", (PyCFunction)PyImaging_EpsEncoderNew, METH_VARARGS}, /* EPS=HEX! */ #ifdef HAVE_LIBJPEG - {"jpeg_decoder", (PyCFunction)PyImaging_JpegDecoderNew, 1}, - {"jpeg_encoder", (PyCFunction)PyImaging_JpegEncoderNew, 1}, + {"jpeg_decoder", (PyCFunction)PyImaging_JpegDecoderNew, METH_VARARGS}, + {"jpeg_encoder", (PyCFunction)PyImaging_JpegEncoderNew, METH_VARARGS}, #endif #ifdef HAVE_OPENJPEG - {"jpeg2k_decoder", (PyCFunction)PyImaging_Jpeg2KDecoderNew, 1}, - {"jpeg2k_encoder", (PyCFunction)PyImaging_Jpeg2KEncoderNew, 1}, + {"jpeg2k_decoder", (PyCFunction)PyImaging_Jpeg2KDecoderNew, METH_VARARGS}, + {"jpeg2k_encoder", (PyCFunction)PyImaging_Jpeg2KEncoderNew, METH_VARARGS}, #endif #ifdef HAVE_LIBTIFF - {"libtiff_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1}, - {"libtiff_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1}, + {"libtiff_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, METH_VARARGS}, + {"libtiff_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, METH_VARARGS}, #endif - {"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, 1}, - {"pcd_decoder", (PyCFunction)PyImaging_PcdDecoderNew, 1}, - {"pcx_decoder", (PyCFunction)PyImaging_PcxDecoderNew, 1}, - {"pcx_encoder", (PyCFunction)PyImaging_PcxEncoderNew, 1}, - {"raw_decoder", (PyCFunction)PyImaging_RawDecoderNew, 1}, - {"raw_encoder", (PyCFunction)PyImaging_RawEncoderNew, 1}, - {"sgi_rle_decoder", (PyCFunction)PyImaging_SgiRleDecoderNew, 1}, - {"sun_rle_decoder", (PyCFunction)PyImaging_SunRleDecoderNew, 1}, - {"tga_rle_decoder", (PyCFunction)PyImaging_TgaRleDecoderNew, 1}, - {"tga_rle_encoder", (PyCFunction)PyImaging_TgaRleEncoderNew, 1}, - {"xbm_decoder", (PyCFunction)PyImaging_XbmDecoderNew, 1}, - {"xbm_encoder", (PyCFunction)PyImaging_XbmEncoderNew, 1}, + {"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, METH_VARARGS}, + {"pcd_decoder", (PyCFunction)PyImaging_PcdDecoderNew, METH_VARARGS}, + {"pcx_decoder", (PyCFunction)PyImaging_PcxDecoderNew, METH_VARARGS}, + {"pcx_encoder", (PyCFunction)PyImaging_PcxEncoderNew, METH_VARARGS}, + {"raw_decoder", (PyCFunction)PyImaging_RawDecoderNew, METH_VARARGS}, + {"raw_encoder", (PyCFunction)PyImaging_RawEncoderNew, METH_VARARGS}, + {"sgi_rle_decoder", (PyCFunction)PyImaging_SgiRleDecoderNew, METH_VARARGS}, + {"sun_rle_decoder", (PyCFunction)PyImaging_SunRleDecoderNew, METH_VARARGS}, + {"tga_rle_decoder", (PyCFunction)PyImaging_TgaRleDecoderNew, METH_VARARGS}, + {"tga_rle_encoder", (PyCFunction)PyImaging_TgaRleEncoderNew, METH_VARARGS}, + {"xbm_decoder", (PyCFunction)PyImaging_XbmDecoderNew, METH_VARARGS}, + {"xbm_encoder", (PyCFunction)PyImaging_XbmEncoderNew, METH_VARARGS}, #ifdef HAVE_LIBZ - {"zip_decoder", (PyCFunction)PyImaging_ZipDecoderNew, 1}, - {"zip_encoder", (PyCFunction)PyImaging_ZipEncoderNew, 1}, + {"zip_decoder", (PyCFunction)PyImaging_ZipDecoderNew, METH_VARARGS}, + {"zip_encoder", (PyCFunction)PyImaging_ZipEncoderNew, METH_VARARGS}, #endif - /* Memory mapping */ +/* Memory mapping */ #ifdef WITH_MAPPING -#ifdef _WIN32 - {"map", (PyCFunction)PyImaging_Mapper, 1}, -#endif - {"map_buffer", (PyCFunction)PyImaging_MapBuffer, 1}, + {"map_buffer", (PyCFunction)PyImaging_MapBuffer, METH_VARARGS}, #endif - /* Display support */ +/* Display support */ #ifdef _WIN32 - {"display", (PyCFunction)PyImaging_DisplayWin32, 1}, - {"display_mode", (PyCFunction)PyImaging_DisplayModeWin32, 1}, - {"grabscreen_win32", (PyCFunction)PyImaging_GrabScreenWin32, 1}, - {"grabclipboard_win32", (PyCFunction)PyImaging_GrabClipboardWin32, 1}, - {"createwindow", (PyCFunction)PyImaging_CreateWindowWin32, 1}, - {"eventloop", (PyCFunction)PyImaging_EventLoopWin32, 1}, - {"listwindows", (PyCFunction)PyImaging_ListWindowsWin32, 1}, - {"drawwmf", (PyCFunction)PyImaging_DrawWmf, 1}, + {"display", (PyCFunction)PyImaging_DisplayWin32, METH_VARARGS}, + {"display_mode", (PyCFunction)PyImaging_DisplayModeWin32, METH_VARARGS}, + {"grabscreen_win32", (PyCFunction)PyImaging_GrabScreenWin32, METH_VARARGS}, + {"grabclipboard_win32", (PyCFunction)PyImaging_GrabClipboardWin32, METH_VARARGS}, + {"createwindow", (PyCFunction)PyImaging_CreateWindowWin32, METH_VARARGS}, + {"eventloop", (PyCFunction)PyImaging_EventLoopWin32, METH_VARARGS}, + {"listwindows", (PyCFunction)PyImaging_ListWindowsWin32, METH_VARARGS}, + {"drawwmf", (PyCFunction)PyImaging_DrawWmf, METH_VARARGS}, #endif #ifdef HAVE_XCB - {"grabscreen_x11", (PyCFunction)PyImaging_GrabScreenX11, 1}, + {"grabscreen_x11", (PyCFunction)PyImaging_GrabScreenX11, METH_VARARGS}, #endif /* Utilities */ - {"getcodecstatus", (PyCFunction)_getcodecstatus, 1}, + {"getcodecstatus", (PyCFunction)_getcodecstatus, METH_VARARGS}, - /* Special effects (experimental) */ +/* Special effects (experimental) */ #ifdef WITH_EFFECTS - {"effect_mandelbrot", (PyCFunction)_effect_mandelbrot, 1}, - {"effect_noise", (PyCFunction)_effect_noise, 1}, - {"linear_gradient", (PyCFunction)_linear_gradient, 1}, - {"radial_gradient", (PyCFunction)_radial_gradient, 1}, - {"wedge", (PyCFunction)_linear_gradient, 1}, /* Compatibility */ + {"effect_mandelbrot", (PyCFunction)_effect_mandelbrot, METH_VARARGS}, + {"effect_noise", (PyCFunction)_effect_noise, METH_VARARGS}, + {"linear_gradient", (PyCFunction)_linear_gradient, METH_VARARGS}, + {"radial_gradient", (PyCFunction)_radial_gradient, METH_VARARGS}, + {"wedge", (PyCFunction)_linear_gradient, METH_VARARGS}, /* Compatibility */ #endif - /* Drawing support stuff */ +/* Drawing support stuff */ #ifdef WITH_IMAGEDRAW - {"font", (PyCFunction)_font_new, 1}, - {"draw", (PyCFunction)_draw_new, 1}, + {"font", (PyCFunction)_font_new, METH_VARARGS}, + {"draw", (PyCFunction)_draw_new, METH_VARARGS}, #endif - /* Experimental path stuff */ +/* Experimental path stuff */ #ifdef WITH_IMAGEPATH - {"path", (PyCFunction)PyPath_Create, 1}, + {"path", (PyCFunction)PyPath_Create, METH_VARARGS}, #endif - /* Experimental arrow graphics stuff */ +/* Experimental arrow graphics stuff */ #ifdef WITH_ARROW - {"outline", (PyCFunction)PyOutline_Create, 1}, + {"outline", (PyCFunction)PyOutline_Create, METH_VARARGS}, #endif /* Resource management */ - {"get_stats", (PyCFunction)_get_stats, 1}, - {"reset_stats", (PyCFunction)_reset_stats, 1}, - {"get_alignment", (PyCFunction)_get_alignment, 1}, - {"get_block_size", (PyCFunction)_get_block_size, 1}, - {"get_blocks_max", (PyCFunction)_get_blocks_max, 1}, - {"set_alignment", (PyCFunction)_set_alignment, 1}, - {"set_block_size", (PyCFunction)_set_block_size, 1}, - {"set_blocks_max", (PyCFunction)_set_blocks_max, 1}, - {"clear_cache", (PyCFunction)_clear_cache, 1}, + {"get_stats", (PyCFunction)_get_stats, METH_VARARGS}, + {"reset_stats", (PyCFunction)_reset_stats, METH_VARARGS}, + {"get_alignment", (PyCFunction)_get_alignment, METH_VARARGS}, + {"get_block_size", (PyCFunction)_get_block_size, METH_VARARGS}, + {"get_blocks_max", (PyCFunction)_get_blocks_max, METH_VARARGS}, + {"set_alignment", (PyCFunction)_set_alignment, METH_VARARGS}, + {"set_block_size", (PyCFunction)_set_block_size, METH_VARARGS}, + {"set_blocks_max", (PyCFunction)_set_blocks_max, METH_VARARGS}, + {"clear_cache", (PyCFunction)_clear_cache, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; static int -setup_module(PyObject* m) { - PyObject* d = PyModule_GetDict(m); - const char* version = (char*)PILLOW_VERSION; +setup_module(PyObject *m) { + PyObject *d = PyModule_GetDict(m); + const char *version = (char *)PILLOW_VERSION; /* Ready object types */ if (PyType_Ready(&Imaging_Type) < 0) { @@ -4159,74 +4133,90 @@ setup_module(PyObject* m) { ImagingAccessInit(); #ifdef HAVE_LIBJPEG - { - extern const char* ImagingJpegVersion(void); - PyDict_SetItemString(d, "jpeglib_version", PyUnicode_FromString(ImagingJpegVersion())); - } + { + extern const char *ImagingJpegVersion(void); + PyDict_SetItemString( + d, "jpeglib_version", PyUnicode_FromString(ImagingJpegVersion())); + } #endif #ifdef HAVE_OPENJPEG - { - extern const char *ImagingJpeg2KVersion(void); - PyDict_SetItemString(d, "jp2klib_version", PyUnicode_FromString(ImagingJpeg2KVersion())); - } -#endif - -#ifdef LIBJPEG_TURBO_VERSION - PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_True); - #define tostr1(a) #a - #define tostr(a) tostr1(a) - PyDict_SetItemString(d, "libjpeg_turbo_version", PyUnicode_FromString(tostr(LIBJPEG_TURBO_VERSION))); - #undef tostr - #undef tostr1 -#else - PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_False); -#endif - -#ifdef HAVE_LIBIMAGEQUANT - PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", Py_True); { - extern const char* ImagingImageQuantVersion(void); - PyDict_SetItemString(d, "imagequant_version", PyUnicode_FromString(ImagingImageQuantVersion())); + extern const char *ImagingJpeg2KVersion(void); + PyDict_SetItemString( + d, "jp2klib_version", PyUnicode_FromString(ImagingJpeg2KVersion())); + } +#endif + + PyObject *have_libjpegturbo; +#ifdef LIBJPEG_TURBO_VERSION + have_libjpegturbo = Py_True; +#define tostr1(a) #a +#define tostr(a) tostr1(a) + PyDict_SetItemString( + d, "libjpeg_turbo_version", PyUnicode_FromString(tostr(LIBJPEG_TURBO_VERSION))); +#undef tostr +#undef tostr1 +#else + have_libjpegturbo = Py_False; +#endif + Py_INCREF(have_libjpegturbo); + PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", have_libjpegturbo); + + PyObject *have_libimagequant; +#ifdef HAVE_LIBIMAGEQUANT + have_libimagequant = Py_True; + { + extern const char *ImagingImageQuantVersion(void); + PyDict_SetItemString( + d, "imagequant_version", PyUnicode_FromString(ImagingImageQuantVersion())); } #else - PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", Py_False); + have_libimagequant = Py_False; #endif + Py_INCREF(have_libimagequant); + PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", have_libimagequant); #ifdef HAVE_LIBZ - /* zip encoding strategies */ - PyModule_AddIntConstant(m, "DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY); - PyModule_AddIntConstant(m, "FILTERED", Z_FILTERED); - PyModule_AddIntConstant(m, "HUFFMAN_ONLY", Z_HUFFMAN_ONLY); - PyModule_AddIntConstant(m, "RLE", Z_RLE); - PyModule_AddIntConstant(m, "FIXED", Z_FIXED); - { - extern const char* ImagingZipVersion(void); - PyDict_SetItemString(d, "zlib_version", PyUnicode_FromString(ImagingZipVersion())); - } + /* zip encoding strategies */ + PyModule_AddIntConstant(m, "DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY); + PyModule_AddIntConstant(m, "FILTERED", Z_FILTERED); + PyModule_AddIntConstant(m, "HUFFMAN_ONLY", Z_HUFFMAN_ONLY); + PyModule_AddIntConstant(m, "RLE", Z_RLE); + PyModule_AddIntConstant(m, "FIXED", Z_FIXED); + { + extern const char *ImagingZipVersion(void); + PyDict_SetItemString( + d, "zlib_version", PyUnicode_FromString(ImagingZipVersion())); + } #endif #ifdef HAVE_LIBTIFF - { - extern const char * ImagingTiffVersion(void); - PyDict_SetItemString(d, "libtiff_version", PyUnicode_FromString(ImagingTiffVersion())); + { + extern const char *ImagingTiffVersion(void); + PyDict_SetItemString( + d, "libtiff_version", PyUnicode_FromString(ImagingTiffVersion())); - // Test for libtiff 4.0 or later, excluding libtiff 3.9.6 and 3.9.7 - PyObject* support_custom_tags; -#if TIFFLIB_VERSION >= 20111221 && TIFFLIB_VERSION != 20120218 && TIFFLIB_VERSION != 20120922 - support_custom_tags = Py_True; + // Test for libtiff 4.0 or later, excluding libtiff 3.9.6 and 3.9.7 + PyObject *support_custom_tags; +#if TIFFLIB_VERSION >= 20111221 && TIFFLIB_VERSION != 20120218 && \ + TIFFLIB_VERSION != 20120922 + support_custom_tags = Py_True; #else - support_custom_tags = Py_False; + support_custom_tags = Py_False; #endif - PyDict_SetItemString(d, "libtiff_support_custom_tags", support_custom_tags); - } + PyDict_SetItemString(d, "libtiff_support_custom_tags", support_custom_tags); + } #endif + PyObject *have_xcb; #ifdef HAVE_XCB - PyModule_AddObject(m, "HAVE_XCB", Py_True); + have_xcb = Py_True; #else - PyModule_AddObject(m, "HAVE_XCB", Py_False); + have_xcb = Py_False; #endif + Py_INCREF(have_xcb); + PyModule_AddObject(m, "HAVE_XCB", have_xcb); PyDict_SetItemString(d, "PILLOW_VERSION", PyUnicode_FromString(version)); @@ -4235,14 +4225,14 @@ setup_module(PyObject* m) { PyMODINIT_FUNC PyInit__imaging(void) { - PyObject* m; + PyObject *m; static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, - "_imaging", /* m_name */ - NULL, /* m_doc */ - -1, /* m_size */ - functions, /* m_methods */ + "_imaging", /* m_name */ + NULL, /* m_doc */ + -1, /* m_size */ + functions, /* m_methods */ }; m = PyModule_Create(&module_def); diff --git a/src/_imagingcms.c b/src/_imagingcms.c index 491866f74..1446bd02b 100644 --- a/src/_imagingcms.c +++ b/src/_imagingcms.c @@ -17,7 +17,8 @@ * March 2009, for distribution under the standard PIL license */ -#define COPYRIGHTINFO "\ +#define COPYRIGHTINFO \ + "\ pyCMS\n\ a Python / PIL interface to the littleCMS ICC Color Management System\n\ Copyright (C) 2002-2003 Kevin Cazabon\n\ @@ -26,7 +27,7 @@ http://www.cazabon.com\n\ " #define PY_SSIZE_T_CLEAN -#include "Python.h" // Include before wchar.h so _GNU_SOURCE is set +#include "Python.h" // Include before wchar.h so _GNU_SOURCE is set #include "wchar.h" #include "datetime.h" @@ -41,10 +42,11 @@ http://www.cazabon.com\n\ 1.0.0 pil Integrating littleCMS2 0.1.0 pil integration & refactoring 0.0.2 alpha: Minor updates, added interfaces to littleCMS features, Jan 6, 2003 - - fixed some memory holes in how transforms/profiles were created and passed back to Python - due to improper destructor setup for PyCObjects + - fixed some memory holes in how transforms/profiles were created and passed back to + Python due to improper destructor setup for PyCObjects - added buildProofTransformFromOpenProfiles() function - - eliminated some code redundancy, centralizing several common tasks with internal functions + - eliminated some code redundancy, centralizing several common tasks with internal + functions 0.0.1 alpha: First public release Dec 26, 2002 @@ -74,18 +76,16 @@ http://www.cazabon.com\n\ /* a profile represents the ICC characteristics for a specific device */ typedef struct { - PyObject_HEAD - cmsHPROFILE profile; + PyObject_HEAD cmsHPROFILE profile; } CmsProfileObject; static PyTypeObject CmsProfile_Type; #define CmsProfile_Check(op) (Py_TYPE(op) == &CmsProfile_Type) -static PyObject* -cms_profile_new(cmsHPROFILE profile) -{ - CmsProfileObject* self; +static PyObject * +cms_profile_new(cmsHPROFILE profile) { + CmsProfileObject *self; self = PyObject_New(CmsProfileObject, &CmsProfile_Type); if (!self) { @@ -94,15 +94,14 @@ cms_profile_new(cmsHPROFILE profile) self->profile = profile; - return (PyObject*) self; + return (PyObject *)self; } -static PyObject* -cms_profile_open(PyObject* self, PyObject* args) -{ +static PyObject * +cms_profile_open(PyObject *self, PyObject *args) { cmsHPROFILE hProfile; - char* sProfile; + char *sProfile; if (!PyArg_ParseTuple(args, "s:profile_open", &sProfile)) { return NULL; } @@ -116,12 +115,11 @@ cms_profile_open(PyObject* self, PyObject* args) return cms_profile_new(hProfile); } -static PyObject* -cms_profile_fromstring(PyObject* self, PyObject* args) -{ +static PyObject * +cms_profile_fromstring(PyObject *self, PyObject *args) { cmsHPROFILE hProfile; - char* pProfile; + char *pProfile; Py_ssize_t nProfile; if (!PyArg_ParseTuple(args, "y#:profile_frombytes", &pProfile, &nProfile)) { return NULL; @@ -136,28 +134,27 @@ cms_profile_fromstring(PyObject* self, PyObject* args) return cms_profile_new(hProfile); } -static PyObject* -cms_profile_tobytes(PyObject* self, PyObject* args) -{ - char *pProfile =NULL; +static PyObject * +cms_profile_tobytes(PyObject *self, PyObject *args) { + char *pProfile = NULL; cmsUInt32Number nProfile; - PyObject* CmsProfile; + PyObject *CmsProfile; cmsHPROFILE *profile; - PyObject* ret; - if (!PyArg_ParseTuple(args, "O", &CmsProfile)){ + PyObject *ret; + if (!PyArg_ParseTuple(args, "O", &CmsProfile)) { return NULL; } - profile = ((CmsProfileObject*)CmsProfile)->profile; + profile = ((CmsProfileObject *)CmsProfile)->profile; if (!cmsSaveProfileToMem(profile, pProfile, &nProfile)) { PyErr_SetString(PyExc_OSError, "Could not determine profile size"); return NULL; } - pProfile = (char*)malloc(nProfile); + pProfile = (char *)malloc(nProfile); if (!pProfile) { PyErr_SetString(PyExc_OSError, "Out of Memory"); return NULL; @@ -176,17 +173,15 @@ cms_profile_tobytes(PyObject* self, PyObject* args) } static void -cms_profile_dealloc(CmsProfileObject* self) -{ - (void) cmsCloseProfile(self->profile); +cms_profile_dealloc(CmsProfileObject *self) { + (void)cmsCloseProfile(self->profile); PyObject_Del(self); } /* a transform represents the mapping between two profiles */ typedef struct { - PyObject_HEAD - char mode_in[8]; + PyObject_HEAD char mode_in[8]; char mode_out[8]; cmsHTRANSFORM transform; } CmsTransformObject; @@ -195,10 +190,9 @@ static PyTypeObject CmsTransform_Type; #define CmsTransform_Check(op) (Py_TYPE(op) == &CmsTransform_Type) -static PyObject* -cms_transform_new(cmsHTRANSFORM transform, char* mode_in, char* mode_out) -{ - CmsTransformObject* self; +static PyObject * +cms_transform_new(cmsHTRANSFORM transform, char *mode_in, char *mode_out) { + CmsTransformObject *self; self = PyObject_New(CmsTransformObject, &CmsTransform_Type); if (!self) { @@ -210,12 +204,11 @@ cms_transform_new(cmsHTRANSFORM transform, char* mode_in, char* mode_out) strcpy(self->mode_in, mode_in); strcpy(self->mode_out, mode_out); - return (PyObject*) self; + return (PyObject *)self; } static void -cms_transform_dealloc(CmsTransformObject* self) -{ +cms_transform_dealloc(CmsTransformObject *self) { cmsDeleteTransform(self->transform); PyObject_Del(self); } @@ -224,41 +217,30 @@ cms_transform_dealloc(CmsTransformObject* self) /* internal functions */ static cmsUInt32Number -findLCMStype(char* PILmode) -{ +findLCMStype(char *PILmode) { if (strcmp(PILmode, "RGB") == 0) { return TYPE_RGBA_8; - } - else if (strcmp(PILmode, "RGBA") == 0) { + } else if (strcmp(PILmode, "RGBA") == 0) { return TYPE_RGBA_8; - } - else if (strcmp(PILmode, "RGBX") == 0) { + } else if (strcmp(PILmode, "RGBX") == 0) { return TYPE_RGBA_8; - } - else if (strcmp(PILmode, "RGBA;16B") == 0) { + } else if (strcmp(PILmode, "RGBA;16B") == 0) { return TYPE_RGBA_16; - } - else if (strcmp(PILmode, "CMYK") == 0) { + } else if (strcmp(PILmode, "CMYK") == 0) { return TYPE_CMYK_8; - } - else if (strcmp(PILmode, "L") == 0) { + } else if (strcmp(PILmode, "L") == 0) { return TYPE_GRAY_8; - } - else if (strcmp(PILmode, "L;16") == 0) { + } else if (strcmp(PILmode, "L;16") == 0) { return TYPE_GRAY_16; - } - else if (strcmp(PILmode, "L;16B") == 0) { + } else if (strcmp(PILmode, "L;16B") == 0) { return TYPE_GRAY_16_SE; - } - else if (strcmp(PILmode, "YCCA") == 0) { + } else if (strcmp(PILmode, "YCCA") == 0) { return TYPE_YCbCr_8; - } - else if (strcmp(PILmode, "YCC") == 0) { + } else if (strcmp(PILmode, "YCC") == 0) { return TYPE_YCbCr_8; - } - else if (strcmp(PILmode, "LAB") == 0) { + } else if (strcmp(PILmode, "LAB") == 0) { // LabX equivalent like ALab, but not reversed -- no #define in lcms2 - return (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)); + return (COLORSPACE_SH(PT_LabV2) | CHANNELS_SH(3) | BYTES_SH(1) | EXTRA_SH(1)); } else { @@ -270,8 +252,7 @@ findLCMStype(char* PILmode) #define Cms_Min(a, b) ((a) < (b) ? (a) : (b)) static int -pyCMSgetAuxChannelChannel (cmsUInt32Number format, int auxChannelNdx) -{ +pyCMSgetAuxChannelChannel(cmsUInt32Number format, int auxChannelNdx) { int numColors = T_CHANNELS(format); int numExtras = T_EXTRA(format); @@ -282,28 +263,24 @@ pyCMSgetAuxChannelChannel (cmsUInt32Number format, int auxChannelNdx) } else { return numExtras - 2 - auxChannelNdx; } - } - else if (T_SWAPFIRST(format)) { + } else if (T_SWAPFIRST(format)) { // in order, after color channels, but last extra is shifted to first if (auxChannelNdx == numExtras - 1) { return 0; } else { return numColors + 1 + auxChannelNdx; } - } - else if (T_DOSWAP(format)) { + } else if (T_DOSWAP(format)) { // reverse order, before anything return numExtras - 1 - auxChannelNdx; - } - else { + } else { // in order, after color channels return numColors + auxChannelNdx; } } static void -pyCMScopyAux (cmsHTRANSFORM hTransform, Imaging imDst, const Imaging imSrc) -{ +pyCMScopyAux(cmsHTRANSFORM hTransform, Imaging imDst, const Imaging imSrc) { cmsUInt32Number dstLCMSFormat; cmsUInt32Number srcLCMSFormat; int numSrcExtras; @@ -331,11 +308,11 @@ pyCMScopyAux (cmsHTRANSFORM hTransform, Imaging imDst, const Imaging imSrc) // copy only if channel format is identical, except OPTIMIZED is ignored as it // does not affect the aux channel - if (T_FLOAT(dstLCMSFormat) != T_FLOAT(srcLCMSFormat) - || T_FLAVOR(dstLCMSFormat) != T_FLAVOR(srcLCMSFormat) - || T_ENDIAN16(dstLCMSFormat) != T_ENDIAN16(srcLCMSFormat) - || T_BYTES(dstLCMSFormat) != T_BYTES(srcLCMSFormat)) { - return; + if (T_FLOAT(dstLCMSFormat) != T_FLOAT(srcLCMSFormat) || + T_FLAVOR(dstLCMSFormat) != T_FLAVOR(srcLCMSFormat) || + T_ENDIAN16(dstLCMSFormat) != T_ENDIAN16(srcLCMSFormat) || + T_BYTES(dstLCMSFormat) != T_BYTES(srcLCMSFormat)) { + return; } numSrcExtras = T_EXTRA(srcLCMSFormat); @@ -354,19 +331,21 @@ pyCMScopyAux (cmsHTRANSFORM hTransform, Imaging imDst, const Imaging imSrc) for (y = 0; y < ySize; y++) { int x; - char* pDstExtras = imDst->image[y] + dstChannel * channelSize; - const char* pSrcExtras = imSrc->image[y] + srcChannel * channelSize; + char *pDstExtras = imDst->image[y] + dstChannel * channelSize; + const char *pSrcExtras = imSrc->image[y] + srcChannel * channelSize; for (x = 0; x < xSize; x++) { - memcpy(pDstExtras + x * dstChunkSize, pSrcExtras + x * srcChunkSize, channelSize); + memcpy( + pDstExtras + x * dstChunkSize, + pSrcExtras + x * srcChunkSize, + channelSize); } } } } static int -pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) -{ +pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) { int i; if (im->xsize > imOut->xsize || im->ysize > imOut->ysize) { @@ -375,8 +354,8 @@ pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) Py_BEGIN_ALLOW_THREADS - // transform color channels only - for (i = 0; i < im->ysize; i++) { + // transform color channels only + for (i = 0; i < im->ysize; i++) { cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize); } @@ -391,26 +370,33 @@ pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) Py_END_ALLOW_THREADS - return 0; + return 0; } static cmsHTRANSFORM -_buildTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, char *sInMode, char *sOutMode, int iRenderingIntent, cmsUInt32Number cmsFLAGS) -{ +_buildTransform( + cmsHPROFILE hInputProfile, + cmsHPROFILE hOutputProfile, + char *sInMode, + char *sOutMode, + int iRenderingIntent, + cmsUInt32Number cmsFLAGS) { cmsHTRANSFORM hTransform; Py_BEGIN_ALLOW_THREADS - /* create the transform */ - hTransform = cmsCreateTransform(hInputProfile, - findLCMStype(sInMode), - hOutputProfile, - findLCMStype(sOutMode), - iRenderingIntent, cmsFLAGS); + /* create the transform */ + hTransform = cmsCreateTransform( + hInputProfile, + findLCMStype(sInMode), + hOutputProfile, + findLCMStype(sOutMode), + iRenderingIntent, + cmsFLAGS); Py_END_ALLOW_THREADS - if (!hTransform) { + if (!hTransform) { PyErr_SetString(PyExc_ValueError, "cannot build transform"); } @@ -418,25 +404,33 @@ _buildTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, char *sIn } static cmsHTRANSFORM -_buildProofTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, cmsHPROFILE hProofProfile, char *sInMode, char *sOutMode, int iRenderingIntent, int iProofIntent, cmsUInt32Number cmsFLAGS) -{ +_buildProofTransform( + cmsHPROFILE hInputProfile, + cmsHPROFILE hOutputProfile, + cmsHPROFILE hProofProfile, + char *sInMode, + char *sOutMode, + int iRenderingIntent, + int iProofIntent, + cmsUInt32Number cmsFLAGS) { cmsHTRANSFORM hTransform; Py_BEGIN_ALLOW_THREADS - /* create the transform */ - hTransform = cmsCreateProofingTransform(hInputProfile, - findLCMStype(sInMode), - hOutputProfile, - findLCMStype(sOutMode), - hProofProfile, - iRenderingIntent, - iProofIntent, - cmsFLAGS); + /* create the transform */ + hTransform = cmsCreateProofingTransform( + hInputProfile, + findLCMStype(sInMode), + hOutputProfile, + findLCMStype(sOutMode), + hProofProfile, + iRenderingIntent, + iProofIntent, + cmsFLAGS); Py_END_ALLOW_THREADS - if (!hTransform) { + if (!hTransform) { PyErr_SetString(PyExc_ValueError, "cannot build proof transform"); } @@ -457,11 +451,27 @@ buildTransform(PyObject *self, PyObject *args) { cmsHTRANSFORM transform = NULL; - if (!PyArg_ParseTuple(args, "O!O!ss|ii:buildTransform", &CmsProfile_Type, &pInputProfile, &CmsProfile_Type, &pOutputProfile, &sInMode, &sOutMode, &iRenderingIntent, &cmsFLAGS)) { + if (!PyArg_ParseTuple( + args, + "O!O!ss|ii:buildTransform", + &CmsProfile_Type, + &pInputProfile, + &CmsProfile_Type, + &pOutputProfile, + &sInMode, + &sOutMode, + &iRenderingIntent, + &cmsFLAGS)) { return NULL; } - transform = _buildTransform(pInputProfile->profile, pOutputProfile->profile, sInMode, sOutMode, iRenderingIntent, cmsFLAGS); + transform = _buildTransform( + pInputProfile->profile, + pOutputProfile->profile, + sInMode, + sOutMode, + iRenderingIntent, + cmsFLAGS); if (!transform) { return NULL; @@ -471,8 +481,7 @@ buildTransform(PyObject *self, PyObject *args) { } static PyObject * -buildProofTransform(PyObject *self, PyObject *args) -{ +buildProofTransform(PyObject *self, PyObject *args) { CmsProfileObject *pInputProfile; CmsProfileObject *pOutputProfile; CmsProfileObject *pProofProfile; @@ -484,23 +493,42 @@ buildProofTransform(PyObject *self, PyObject *args) cmsHTRANSFORM transform = NULL; - if (!PyArg_ParseTuple(args, "O!O!O!ss|iii:buildProofTransform", &CmsProfile_Type, &pInputProfile, &CmsProfile_Type, &pOutputProfile, &CmsProfile_Type, &pProofProfile, &sInMode, &sOutMode, &iRenderingIntent, &iProofIntent, &cmsFLAGS)) { + if (!PyArg_ParseTuple( + args, + "O!O!O!ss|iii:buildProofTransform", + &CmsProfile_Type, + &pInputProfile, + &CmsProfile_Type, + &pOutputProfile, + &CmsProfile_Type, + &pProofProfile, + &sInMode, + &sOutMode, + &iRenderingIntent, + &iProofIntent, + &cmsFLAGS)) { return NULL; } - transform = _buildProofTransform(pInputProfile->profile, pOutputProfile->profile, pProofProfile->profile, sInMode, sOutMode, iRenderingIntent, iProofIntent, cmsFLAGS); + transform = _buildProofTransform( + pInputProfile->profile, + pOutputProfile->profile, + pProofProfile->profile, + sInMode, + sOutMode, + iRenderingIntent, + iProofIntent, + cmsFLAGS); if (!transform) { return NULL; } return cms_transform_new(transform, sInMode, sOutMode); - } static PyObject * -cms_transform_apply(CmsTransformObject *self, PyObject *args) -{ +cms_transform_apply(CmsTransformObject *self, PyObject *args) { Py_ssize_t idIn; Py_ssize_t idOut; Imaging im; @@ -512,8 +540,8 @@ cms_transform_apply(CmsTransformObject *self, PyObject *args) return NULL; } - im = (Imaging) idIn; - imOut = (Imaging) idOut; + im = (Imaging)idIn; + imOut = (Imaging)idOut; result = pyCMSdoTransform(im, imOut, self->transform); @@ -524,8 +552,7 @@ cms_transform_apply(CmsTransformObject *self, PyObject *args) /* Python-Callable On-The-Fly profile creation functions */ static PyObject * -createProfile(PyObject *self, PyObject *args) -{ +createProfile(PyObject *self, PyObject *args) { char *sColorSpace; cmsHPROFILE hProfile; cmsFloat64Number dColorTemp = 0.0; @@ -540,21 +567,21 @@ createProfile(PyObject *self, PyObject *args) if (dColorTemp > 0.0) { result = cmsWhitePointFromTemp(&whitePoint, dColorTemp); if (!result) { - PyErr_SetString(PyExc_ValueError, "ERROR: Could not calculate white point from color temperature provided, must be float in degrees Kelvin"); + PyErr_SetString( + PyExc_ValueError, + "ERROR: Could not calculate white point from color temperature " + "provided, must be float in degrees Kelvin"); return NULL; } hProfile = cmsCreateLab2Profile(&whitePoint); } else { hProfile = cmsCreateLab2Profile(NULL); } - } - else if (strcmp(sColorSpace, "XYZ") == 0) { + } else if (strcmp(sColorSpace, "XYZ") == 0) { hProfile = cmsCreateXYZProfile(); - } - else if (strcmp(sColorSpace, "sRGB") == 0) { + } else if (strcmp(sColorSpace, "sRGB") == 0) { hProfile = cmsCreate_sRGBProfile(); - } - else { + } else { hProfile = NULL; } @@ -570,8 +597,7 @@ createProfile(PyObject *self, PyObject *args) /* profile methods */ static PyObject * -cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args) -{ +cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args) { cmsBool result; int intent; @@ -582,7 +608,8 @@ cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args) result = cmsIsIntentSupported(self->profile, intent, direction); - /* printf("cmsIsIntentSupported(%p, %d, %d) => %d\n", self->profile, intent, direction, result); */ + /* printf("cmsIsIntentSupported(%p, %d, %d) => %d\n", self->profile, intent, + * direction, result); */ return PyLong_FromLong(result != 0); } @@ -596,30 +623,30 @@ cms_profile_is_intent_supported(CmsProfileObject *self, PyObject *args) #endif static PyObject * -cms_get_display_profile_win32(PyObject* self, PyObject* args) -{ +cms_get_display_profile_win32(PyObject *self, PyObject *args) { char filename[MAX_PATH]; cmsUInt32Number filename_size; BOOL ok; HANDLE handle = 0; int is_dc = 0; - if (!PyArg_ParseTuple(args, "|" F_HANDLE "i:get_display_profile", &handle, &is_dc)) { + if (!PyArg_ParseTuple( + args, "|" F_HANDLE "i:get_display_profile", &handle, &is_dc)) { return NULL; } filename_size = sizeof(filename); if (is_dc) { - ok = GetICMProfile((HDC) handle, &filename_size, filename); + ok = GetICMProfile((HDC)handle, &filename_size, filename); } else { - HDC dc = GetDC((HWND) handle); + HDC dc = GetDC((HWND)handle); ok = GetICMProfile(dc, &filename_size, filename); - ReleaseDC((HWND) handle, dc); + ReleaseDC((HWND)handle, dc); } if (ok) { - return PyUnicode_FromStringAndSize(filename, filename_size-1); + return PyUnicode_FromStringAndSize(filename, filename_size - 1); } Py_INCREF(Py_None); @@ -630,9 +657,8 @@ cms_get_display_profile_win32(PyObject* self, PyObject* args) /* -------------------------------------------------------------------- */ /* Helper functions. */ -static PyObject* -_profile_read_mlu(CmsProfileObject* self, cmsTagSignature info) -{ +static PyObject * +_profile_read_mlu(CmsProfileObject *self, cmsTagSignature info) { PyObject *uni; char *lc = "en"; char *cc = cmsNoCountry; @@ -673,26 +699,22 @@ _profile_read_mlu(CmsProfileObject* self, cmsTagSignature info) return uni; } - -static PyObject* -_profile_read_int_as_string(cmsUInt32Number nr) -{ - PyObject* ret; +static PyObject * +_profile_read_int_as_string(cmsUInt32Number nr) { + PyObject *ret; char buf[5]; - buf[0] = (char) ((nr >> 24) & 0xff); - buf[1] = (char) ((nr >> 16) & 0xff); - buf[2] = (char) ((nr >> 8) & 0xff); - buf[3] = (char) (nr & 0xff); + buf[0] = (char)((nr >> 24) & 0xff); + buf[1] = (char)((nr >> 16) & 0xff); + buf[2] = (char)((nr >> 8) & 0xff); + buf[3] = (char)(nr & 0xff); buf[4] = 0; ret = PyUnicode_DecodeASCII(buf, 4, NULL); return ret; } - -static PyObject* -_profile_read_signature(CmsProfileObject* self, cmsTagSignature info) -{ +static PyObject * +_profile_read_signature(CmsProfileObject *self, cmsTagSignature info) { unsigned int *sig; if (!cmsIsTag(self->profile, info)) { @@ -700,7 +722,7 @@ _profile_read_signature(CmsProfileObject* self, cmsTagSignature info) return Py_None; } - sig = (unsigned int *) cmsReadTag(self->profile, info); + sig = (unsigned int *)cmsReadTag(self->profile, info); if (!sig) { Py_INCREF(Py_None); return Py_None; @@ -709,42 +731,53 @@ _profile_read_signature(CmsProfileObject* self, cmsTagSignature info) return _profile_read_int_as_string(*sig); } -static PyObject* -_xyz_py(cmsCIEXYZ* XYZ) -{ +static PyObject * +_xyz_py(cmsCIEXYZ *XYZ) { cmsCIExyY xyY; cmsXYZ2xyY(&xyY, XYZ); - return Py_BuildValue("((d,d,d),(d,d,d))", XYZ->X, XYZ->Y, XYZ->Z, xyY.x, xyY.y, xyY.Y); + return Py_BuildValue( + "((d,d,d),(d,d,d))", XYZ->X, XYZ->Y, XYZ->Z, xyY.x, xyY.y, xyY.Y); } -static PyObject* -_xyz3_py(cmsCIEXYZ* XYZ) -{ +static PyObject * +_xyz3_py(cmsCIEXYZ *XYZ) { cmsCIExyY xyY[3]; cmsXYZ2xyY(&xyY[0], &XYZ[0]); cmsXYZ2xyY(&xyY[1], &XYZ[1]); cmsXYZ2xyY(&xyY[2], &XYZ[2]); - return Py_BuildValue("(((d,d,d),(d,d,d),(d,d,d)),((d,d,d),(d,d,d),(d,d,d)))", - XYZ[0].X, XYZ[0].Y, XYZ[0].Z, - XYZ[1].X, XYZ[1].Y, XYZ[1].Z, - XYZ[2].X, XYZ[2].Y, XYZ[2].Z, - xyY[0].x, xyY[0].y, xyY[0].Y, - xyY[1].x, xyY[1].y, xyY[1].Y, - xyY[2].x, xyY[2].y, xyY[2].Y); + return Py_BuildValue( + "(((d,d,d),(d,d,d),(d,d,d)),((d,d,d),(d,d,d),(d,d,d)))", + XYZ[0].X, + XYZ[0].Y, + XYZ[0].Z, + XYZ[1].X, + XYZ[1].Y, + XYZ[1].Z, + XYZ[2].X, + XYZ[2].Y, + XYZ[2].Z, + xyY[0].x, + xyY[0].y, + xyY[0].Y, + xyY[1].x, + xyY[1].y, + xyY[1].Y, + xyY[2].x, + xyY[2].y, + xyY[2].Y); } -static PyObject* -_profile_read_ciexyz(CmsProfileObject* self, cmsTagSignature info, int multi) -{ - cmsCIEXYZ* XYZ; +static PyObject * +_profile_read_ciexyz(CmsProfileObject *self, cmsTagSignature info, int multi) { + cmsCIEXYZ *XYZ; if (!cmsIsTag(self->profile, info)) { Py_INCREF(Py_None); return Py_None; } - XYZ = (cmsCIEXYZ*) cmsReadTag(self->profile, info); + XYZ = (cmsCIEXYZ *)cmsReadTag(self->profile, info); if (!XYZ) { Py_INCREF(Py_None); return Py_None; @@ -756,17 +789,16 @@ _profile_read_ciexyz(CmsProfileObject* self, cmsTagSignature info, int multi) } } -static PyObject* -_profile_read_ciexyy_triple(CmsProfileObject* self, cmsTagSignature info) -{ - cmsCIExyYTRIPLE* triple; +static PyObject * +_profile_read_ciexyy_triple(CmsProfileObject *self, cmsTagSignature info) { + cmsCIExyYTRIPLE *triple; if (!cmsIsTag(self->profile, info)) { Py_INCREF(Py_None); return Py_None; } - triple = (cmsCIExyYTRIPLE*) cmsReadTag(self->profile, info); + triple = (cmsCIExyYTRIPLE *)cmsReadTag(self->profile, info); if (!triple) { Py_INCREF(Py_None); return Py_None; @@ -774,26 +806,32 @@ _profile_read_ciexyy_triple(CmsProfileObject* self, cmsTagSignature info) /* Note: lcms does all the heavy lifting and error checking (nr of channels == 3). */ - return Py_BuildValue("((d,d,d),(d,d,d),(d,d,d)),", - triple->Red.x, triple->Red.y, triple->Red.Y, - triple->Green.x, triple->Green.y, triple->Green.Y, - triple->Blue.x, triple->Blue.y, triple->Blue.Y); + return Py_BuildValue( + "((d,d,d),(d,d,d),(d,d,d)),", + triple->Red.x, + triple->Red.y, + triple->Red.Y, + triple->Green.x, + triple->Green.y, + triple->Green.Y, + triple->Blue.x, + triple->Blue.y, + triple->Blue.Y); } -static PyObject* -_profile_read_named_color_list(CmsProfileObject* self, cmsTagSignature info) -{ - cmsNAMEDCOLORLIST* ncl; +static PyObject * +_profile_read_named_color_list(CmsProfileObject *self, cmsTagSignature info) { + cmsNAMEDCOLORLIST *ncl; int i, n; char name[cmsMAX_PATH]; - PyObject* result; + PyObject *result; if (!cmsIsTag(self->profile, info)) { Py_INCREF(Py_None); return Py_None; } - ncl = (cmsNAMEDCOLORLIST*) cmsReadTag(self->profile, info); + ncl = (cmsNAMEDCOLORLIST *)cmsReadTag(self->profile, info); if (ncl == NULL) { Py_INCREF(Py_None); return Py_None; @@ -807,7 +845,7 @@ _profile_read_named_color_list(CmsProfileObject* self, cmsTagSignature info) } for (i = 0; i < n; i++) { - PyObject* str; + PyObject *str; cmsNamedColorInfo(ncl, i, name, NULL, NULL, NULL, NULL); str = PyUnicode_FromString(name); if (str == NULL) { @@ -821,9 +859,9 @@ _profile_read_named_color_list(CmsProfileObject* self, cmsTagSignature info) return result; } -static cmsBool _calculate_rgb_primaries(CmsProfileObject* self, cmsCIEXYZTRIPLE* result) -{ - double input[3][3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; +static cmsBool +_calculate_rgb_primaries(CmsProfileObject *self, cmsCIEXYZTRIPLE *result) { + double input[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; cmsHPROFILE hXYZ; cmsHTRANSFORM hTransform; @@ -836,36 +874,41 @@ static cmsBool _calculate_rgb_primaries(CmsProfileObject* self, cmsCIEXYZTRIPLE* } // transform from our profile to XYZ using doubles for highest precision - hTransform = cmsCreateTransform(self->profile, TYPE_RGB_DBL, - hXYZ, TYPE_XYZ_DBL, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE); + hTransform = cmsCreateTransform( + self->profile, + TYPE_RGB_DBL, + hXYZ, + TYPE_XYZ_DBL, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE); cmsCloseProfile(hXYZ); if (hTransform == NULL) { return 0; } - cmsDoTransform(hTransform, (void*) input, result, 3); + cmsDoTransform(hTransform, (void *)input, result, 3); cmsDeleteTransform(hTransform); return 1; } -static cmsBool _check_intent(int clut, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection) -{ +static cmsBool +_check_intent( + int clut, + cmsHPROFILE hProfile, + cmsUInt32Number Intent, + cmsUInt32Number UsedDirection) { if (clut) { return cmsIsCLUT(hProfile, Intent, UsedDirection); - } - else { + } else { return cmsIsIntentSupported(hProfile, Intent, UsedDirection); } } #define INTENTS 200 -static PyObject* -_is_intent_supported(CmsProfileObject* self, int clut) -{ - PyObject* result; +static PyObject * +_is_intent_supported(CmsProfileObject *self, int clut) { + PyObject *result; int n; int i; cmsUInt32Number intent_ids[INTENTS]; @@ -877,26 +920,28 @@ _is_intent_supported(CmsProfileObject* self, int clut) return Py_None; } - - n = cmsGetSupportedIntents(INTENTS, - intent_ids, - intent_descs); + n = cmsGetSupportedIntents(INTENTS, intent_ids, intent_descs); for (i = 0; i < n; i++) { - int intent = (int) intent_ids[i]; - PyObject* id; - PyObject* entry; + int intent = (int)intent_ids[i]; + PyObject *id; + PyObject *entry; - /* Only valid for ICC Intents (otherwise we read invalid memory in lcms cmsio1.c). */ - if (!(intent == INTENT_PERCEPTUAL || intent == INTENT_RELATIVE_COLORIMETRIC - || intent == INTENT_SATURATION || intent == INTENT_ABSOLUTE_COLORIMETRIC)) { + /* Only valid for ICC Intents (otherwise we read invalid memory in lcms + * cmsio1.c). */ + if (!(intent == INTENT_PERCEPTUAL || intent == INTENT_RELATIVE_COLORIMETRIC || + intent == INTENT_SATURATION || intent == INTENT_ABSOLUTE_COLORIMETRIC)) { continue; } - id = PyLong_FromLong((long) intent); - entry = Py_BuildValue("(OOO)", - _check_intent(clut, self->profile, intent, LCMS_USED_AS_INPUT) ? Py_True : Py_False, - _check_intent(clut, self->profile, intent, LCMS_USED_AS_OUTPUT) ? Py_True : Py_False, - _check_intent(clut, self->profile, intent, LCMS_USED_AS_PROOF) ? Py_True : Py_False); + id = PyLong_FromLong((long)intent); + entry = Py_BuildValue( + "(OOO)", + _check_intent(clut, self->profile, intent, LCMS_USED_AS_INPUT) ? Py_True + : Py_False, + _check_intent(clut, self->profile, intent, LCMS_USED_AS_OUTPUT) ? Py_True + : Py_False, + _check_intent(clut, self->profile, intent, LCMS_USED_AS_PROOF) ? Py_True + : Py_False); if (id == NULL || entry == NULL) { Py_XDECREF(id); Py_XDECREF(entry); @@ -914,195 +959,171 @@ _is_intent_supported(CmsProfileObject* self, int clut) static PyMethodDef pyCMSdll_methods[] = { - {"profile_open", cms_profile_open, 1}, - {"profile_frombytes", cms_profile_fromstring, 1}, - {"profile_fromstring", cms_profile_fromstring, 1}, - {"profile_tobytes", cms_profile_tobytes, 1}, + {"profile_open", cms_profile_open, METH_VARARGS}, + {"profile_frombytes", cms_profile_fromstring, METH_VARARGS}, + {"profile_fromstring", cms_profile_fromstring, METH_VARARGS}, + {"profile_tobytes", cms_profile_tobytes, METH_VARARGS}, /* profile and transform functions */ - {"buildTransform", buildTransform, 1}, - {"buildProofTransform", buildProofTransform, 1}, - {"createProfile", createProfile, 1}, + {"buildTransform", buildTransform, METH_VARARGS}, + {"buildProofTransform", buildProofTransform, METH_VARARGS}, + {"createProfile", createProfile, METH_VARARGS}, - /* platform specific tools */ +/* platform specific tools */ #ifdef _WIN32 - {"get_display_profile_win32", cms_get_display_profile_win32, 1}, + {"get_display_profile_win32", cms_get_display_profile_win32, METH_VARARGS}, #endif - {NULL, NULL} -}; + {NULL, NULL}}; static struct PyMethodDef cms_profile_methods[] = { - {"is_intent_supported", (PyCFunction) cms_profile_is_intent_supported, 1}, + {"is_intent_supported", (PyCFunction)cms_profile_is_intent_supported, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; -static PyObject* -cms_profile_getattr_rendering_intent(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_rendering_intent(CmsProfileObject *self, void *closure) { return PyLong_FromLong(cmsGetHeaderRenderingIntent(self->profile)); } /* New-style unicode interfaces. */ -static PyObject* -cms_profile_getattr_copyright(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_copyright(CmsProfileObject *self, void *closure) { return _profile_read_mlu(self, cmsSigCopyrightTag); } -static PyObject* -cms_profile_getattr_target(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_target(CmsProfileObject *self, void *closure) { return _profile_read_mlu(self, cmsSigCharTargetTag); } -static PyObject* -cms_profile_getattr_manufacturer(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_manufacturer(CmsProfileObject *self, void *closure) { return _profile_read_mlu(self, cmsSigDeviceMfgDescTag); } -static PyObject* -cms_profile_getattr_model(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_model(CmsProfileObject *self, void *closure) { return _profile_read_mlu(self, cmsSigDeviceModelDescTag); } -static PyObject* -cms_profile_getattr_profile_description(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_profile_description(CmsProfileObject *self, void *closure) { return _profile_read_mlu(self, cmsSigProfileDescriptionTag); } -static PyObject* -cms_profile_getattr_screening_description(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_screening_description(CmsProfileObject *self, void *closure) { return _profile_read_mlu(self, cmsSigScreeningDescTag); } -static PyObject* -cms_profile_getattr_viewing_condition(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_viewing_condition(CmsProfileObject *self, void *closure) { return _profile_read_mlu(self, cmsSigViewingCondDescTag); } -static PyObject* -cms_profile_getattr_creation_date(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_creation_date(CmsProfileObject *self, void *closure) { cmsBool result; struct tm ct; result = cmsGetHeaderCreationDateTime(self->profile, &ct); - if (! result) { + if (!result) { Py_INCREF(Py_None); return Py_None; } - return PyDateTime_FromDateAndTime(1900 + ct.tm_year, ct.tm_mon, ct.tm_mday, - ct.tm_hour, ct.tm_min, ct.tm_sec, 0); + return PyDateTime_FromDateAndTime( + 1900 + ct.tm_year, ct.tm_mon, ct.tm_mday, ct.tm_hour, ct.tm_min, ct.tm_sec, 0); } -static PyObject* -cms_profile_getattr_version(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_version(CmsProfileObject *self, void *closure) { cmsFloat64Number version = cmsGetProfileVersion(self->profile); return PyFloat_FromDouble(version); } -static PyObject* -cms_profile_getattr_icc_version(CmsProfileObject* self, void* closure) -{ - return PyLong_FromLong((long) cmsGetEncodedICCversion(self->profile)); +static PyObject * +cms_profile_getattr_icc_version(CmsProfileObject *self, void *closure) { + return PyLong_FromLong((long)cmsGetEncodedICCversion(self->profile)); } -static PyObject* -cms_profile_getattr_attributes(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_attributes(CmsProfileObject *self, void *closure) { cmsUInt64Number attr; cmsGetHeaderAttributes(self->profile, &attr); /* This works just as well on Windows (LLP64), 32-bit Linux (ILP32) and 64-bit Linux (LP64) systems. */ - return PyLong_FromUnsignedLongLong((unsigned long long) attr); + return PyLong_FromUnsignedLongLong((unsigned long long)attr); } -static PyObject* -cms_profile_getattr_header_flags(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_header_flags(CmsProfileObject *self, void *closure) { cmsUInt32Number flags = cmsGetHeaderFlags(self->profile); return PyLong_FromLong(flags); } -static PyObject* -cms_profile_getattr_header_manufacturer(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_header_manufacturer(CmsProfileObject *self, void *closure) { return _profile_read_int_as_string(cmsGetHeaderManufacturer(self->profile)); } -static PyObject* -cms_profile_getattr_header_model(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_header_model(CmsProfileObject *self, void *closure) { return _profile_read_int_as_string(cmsGetHeaderModel(self->profile)); } -static PyObject* -cms_profile_getattr_device_class(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_device_class(CmsProfileObject *self, void *closure) { return _profile_read_int_as_string(cmsGetDeviceClass(self->profile)); } -static PyObject* -cms_profile_getattr_connection_space(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_connection_space(CmsProfileObject *self, void *closure) { return _profile_read_int_as_string(cmsGetPCS(self->profile)); } -static PyObject* -cms_profile_getattr_xcolor_space(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_xcolor_space(CmsProfileObject *self, void *closure) { return _profile_read_int_as_string(cmsGetColorSpace(self->profile)); } -static PyObject* -cms_profile_getattr_profile_id(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_profile_id(CmsProfileObject *self, void *closure) { cmsUInt8Number id[16]; cmsGetHeaderProfileID(self->profile, id); - return PyBytes_FromStringAndSize((char *) id, 16); + return PyBytes_FromStringAndSize((char *)id, 16); } -static PyObject* -cms_profile_getattr_is_matrix_shaper(CmsProfileObject* self, void* closure) -{ - return PyBool_FromLong((long) cmsIsMatrixShaper(self->profile)); +static PyObject * +cms_profile_getattr_is_matrix_shaper(CmsProfileObject *self, void *closure) { + return PyBool_FromLong((long)cmsIsMatrixShaper(self->profile)); } -static PyObject* -cms_profile_getattr_technology(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_technology(CmsProfileObject *self, void *closure) { return _profile_read_signature(self, cmsSigTechnologyTag); } -static PyObject* -cms_profile_getattr_colorimetric_intent(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_colorimetric_intent(CmsProfileObject *self, void *closure) { return _profile_read_signature(self, cmsSigColorimetricIntentImageStateTag); } -static PyObject* -cms_profile_getattr_perceptual_rendering_intent_gamut(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_perceptual_rendering_intent_gamut( + CmsProfileObject *self, void *closure) { return _profile_read_signature(self, cmsSigPerceptualRenderingIntentGamutTag); } -static PyObject* -cms_profile_getattr_saturation_rendering_intent_gamut(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_saturation_rendering_intent_gamut( + CmsProfileObject *self, void *closure) { return _profile_read_signature(self, cmsSigSaturationRenderingIntentGamutTag); } -static PyObject* -cms_profile_getattr_red_colorant(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_red_colorant(CmsProfileObject *self, void *closure) { if (!cmsIsMatrixShaper(self->profile)) { Py_INCREF(Py_None); return Py_None; @@ -1110,10 +1131,8 @@ cms_profile_getattr_red_colorant(CmsProfileObject* self, void* closure) return _profile_read_ciexyz(self, cmsSigRedColorantTag, 0); } - -static PyObject* -cms_profile_getattr_green_colorant(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_green_colorant(CmsProfileObject *self, void *closure) { if (!cmsIsMatrixShaper(self->profile)) { Py_INCREF(Py_None); return Py_None; @@ -1121,10 +1140,8 @@ cms_profile_getattr_green_colorant(CmsProfileObject* self, void* closure) return _profile_read_ciexyz(self, cmsSigGreenColorantTag, 0); } - -static PyObject* -cms_profile_getattr_blue_colorant(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_blue_colorant(CmsProfileObject *self, void *closure) { if (!cmsIsMatrixShaper(self->profile)) { Py_INCREF(Py_None); return Py_None; @@ -1132,10 +1149,10 @@ cms_profile_getattr_blue_colorant(CmsProfileObject* self, void* closure) return _profile_read_ciexyz(self, cmsSigBlueColorantTag, 0); } -static PyObject* -cms_profile_getattr_media_white_point_temperature(CmsProfileObject *self, void* closure) -{ - cmsCIEXYZ* XYZ; +static PyObject * +cms_profile_getattr_media_white_point_temperature( + CmsProfileObject *self, void *closure) { + cmsCIEXYZ *XYZ; cmsCIExyY xyY; cmsFloat64Number tempK; cmsTagSignature info = cmsSigMediaWhitePointTag; @@ -1146,7 +1163,7 @@ cms_profile_getattr_media_white_point_temperature(CmsProfileObject *self, void* return Py_None; } - XYZ = (cmsCIEXYZ*) cmsReadTag(self->profile, info); + XYZ = (cmsCIEXYZ *)cmsReadTag(self->profile, info); if (XYZ == NULL || XYZ->X == 0) { Py_INCREF(Py_None); return Py_None; @@ -1161,47 +1178,40 @@ cms_profile_getattr_media_white_point_temperature(CmsProfileObject *self, void* return PyFloat_FromDouble(tempK); } -static PyObject* -cms_profile_getattr_media_white_point(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_media_white_point(CmsProfileObject *self, void *closure) { return _profile_read_ciexyz(self, cmsSigMediaWhitePointTag, 0); } - -static PyObject* -cms_profile_getattr_media_black_point(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_media_black_point(CmsProfileObject *self, void *closure) { return _profile_read_ciexyz(self, cmsSigMediaBlackPointTag, 0); } -static PyObject* -cms_profile_getattr_luminance(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_luminance(CmsProfileObject *self, void *closure) { return _profile_read_ciexyz(self, cmsSigLuminanceTag, 0); } -static PyObject* -cms_profile_getattr_chromatic_adaptation(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_chromatic_adaptation(CmsProfileObject *self, void *closure) { return _profile_read_ciexyz(self, cmsSigChromaticAdaptationTag, 1); } -static PyObject* -cms_profile_getattr_chromaticity(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_chromaticity(CmsProfileObject *self, void *closure) { return _profile_read_ciexyy_triple(self, cmsSigChromaticityTag); } -static PyObject* -cms_profile_getattr_red_primary(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_red_primary(CmsProfileObject *self, void *closure) { cmsBool result = 0; cmsCIEXYZTRIPLE primaries; if (cmsIsMatrixShaper(self->profile)) { result = _calculate_rgb_primaries(self, &primaries); } - if (! result) { + if (!result) { Py_INCREF(Py_None); return Py_None; } @@ -1209,16 +1219,15 @@ cms_profile_getattr_red_primary(CmsProfileObject* self, void* closure) return _xyz_py(&primaries.Red); } -static PyObject* -cms_profile_getattr_green_primary(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_green_primary(CmsProfileObject *self, void *closure) { cmsBool result = 0; cmsCIEXYZTRIPLE primaries; if (cmsIsMatrixShaper(self->profile)) { result = _calculate_rgb_primaries(self, &primaries); } - if (! result) { + if (!result) { Py_INCREF(Py_None); return Py_None; } @@ -1226,16 +1235,15 @@ cms_profile_getattr_green_primary(CmsProfileObject* self, void* closure) return _xyz_py(&primaries.Green); } -static PyObject* -cms_profile_getattr_blue_primary(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_blue_primary(CmsProfileObject *self, void *closure) { cmsBool result = 0; cmsCIEXYZTRIPLE primaries; if (cmsIsMatrixShaper(self->profile)) { result = _calculate_rgb_primaries(self, &primaries); } - if (! result) { + if (!result) { Py_INCREF(Py_None); return Py_None; } @@ -1243,61 +1251,55 @@ cms_profile_getattr_blue_primary(CmsProfileObject* self, void* closure) return _xyz_py(&primaries.Blue); } -static PyObject* -cms_profile_getattr_colorant_table(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_colorant_table(CmsProfileObject *self, void *closure) { return _profile_read_named_color_list(self, cmsSigColorantTableTag); } -static PyObject* -cms_profile_getattr_colorant_table_out(CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_colorant_table_out(CmsProfileObject *self, void *closure) { return _profile_read_named_color_list(self, cmsSigColorantTableOutTag); } -static PyObject* -cms_profile_getattr_is_intent_supported (CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_is_intent_supported(CmsProfileObject *self, void *closure) { return _is_intent_supported(self, 0); } -static PyObject* -cms_profile_getattr_is_clut (CmsProfileObject* self, void* closure) -{ +static PyObject * +cms_profile_getattr_is_clut(CmsProfileObject *self, void *closure) { return _is_intent_supported(self, 1); } -static const char* -_illu_map(int i) -{ - switch(i) { - case 0: - return "unknown"; - case 1: - return "D50"; - case 2: - return "D65"; - case 3: - return "D93"; - case 4: - return "F2"; - case 5: - return "D55"; - case 6: - return "A"; - case 7: - return "E"; - case 8: - return "F8"; - default: - return NULL; +static const char * +_illu_map(int i) { + switch (i) { + case 0: + return "unknown"; + case 1: + return "D50"; + case 2: + return "D65"; + case 3: + return "D93"; + case 4: + return "F2"; + case 5: + return "D55"; + case 6: + return "A"; + case 7: + return "E"; + case 8: + return "F8"; + default: + return NULL; } } -static PyObject* -cms_profile_getattr_icc_measurement_condition (CmsProfileObject* self, void* closure) -{ - cmsICCMeasurementConditions* mc; +static PyObject * +cms_profile_getattr_icc_measurement_condition(CmsProfileObject *self, void *closure) { + cmsICCMeasurementConditions *mc; cmsTagSignature info = cmsSigMeasurementTag; const char *geo; @@ -1306,7 +1308,7 @@ cms_profile_getattr_icc_measurement_condition (CmsProfileObject* self, void* clo return Py_None; } - mc = (cmsICCMeasurementConditions*) cmsReadTag(self->profile, info); + mc = (cmsICCMeasurementConditions *)cmsReadTag(self->profile, info); if (!mc) { Py_INCREF(Py_None); return Py_None; @@ -1320,18 +1322,25 @@ cms_profile_getattr_icc_measurement_condition (CmsProfileObject* self, void* clo geo = "unknown"; } - return Py_BuildValue("{s:i,s:(ddd),s:s,s:d,s:s}", - "observer", mc->Observer, - "backing", mc->Backing.X, mc->Backing.Y, mc->Backing.Z, - "geo", geo, - "flare", mc->Flare, - "illuminant_type", _illu_map(mc->IlluminantType)); + return Py_BuildValue( + "{s:i,s:(ddd),s:s,s:d,s:s}", + "observer", + mc->Observer, + "backing", + mc->Backing.X, + mc->Backing.Y, + mc->Backing.Z, + "geo", + geo, + "flare", + mc->Flare, + "illuminant_type", + _illu_map(mc->IlluminantType)); } -static PyObject* -cms_profile_getattr_icc_viewing_condition (CmsProfileObject* self, void* closure) -{ - cmsICCViewingConditions* vc; +static PyObject * +cms_profile_getattr_icc_viewing_condition(CmsProfileObject *self, void *closure) { + cmsICCViewingConditions *vc; cmsTagSignature info = cmsSigViewingConditionsTag; if (!cmsIsTag(self->profile, info)) { @@ -1339,158 +1348,164 @@ cms_profile_getattr_icc_viewing_condition (CmsProfileObject* self, void* closure return Py_None; } - vc = (cmsICCViewingConditions*) cmsReadTag(self->profile, info); + vc = (cmsICCViewingConditions *)cmsReadTag(self->profile, info); if (!vc) { Py_INCREF(Py_None); return Py_None; } - return Py_BuildValue("{s:(ddd),s:(ddd),s:s}", - "illuminant", vc->IlluminantXYZ.X, vc->IlluminantXYZ.Y, vc->IlluminantXYZ.Z, - "surround", vc->SurroundXYZ.X, vc->SurroundXYZ.Y, vc->SurroundXYZ.Z, - "illuminant_type", _illu_map(vc->IlluminantType)); + return Py_BuildValue( + "{s:(ddd),s:(ddd),s:s}", + "illuminant", + vc->IlluminantXYZ.X, + vc->IlluminantXYZ.Y, + vc->IlluminantXYZ.Z, + "surround", + vc->SurroundXYZ.X, + vc->SurroundXYZ.Y, + vc->SurroundXYZ.Z, + "illuminant_type", + _illu_map(vc->IlluminantType)); } - static struct PyGetSetDef cms_profile_getsetters[] = { /* New style interfaces. */ - { "rendering_intent", (getter) cms_profile_getattr_rendering_intent }, - { "creation_date", (getter) cms_profile_getattr_creation_date }, - { "copyright", (getter) cms_profile_getattr_copyright }, - { "target", (getter) cms_profile_getattr_target }, - { "manufacturer", (getter) cms_profile_getattr_manufacturer }, - { "model", (getter) cms_profile_getattr_model }, - { "profile_description", (getter) cms_profile_getattr_profile_description }, - { "screening_description", (getter) cms_profile_getattr_screening_description }, - { "viewing_condition", (getter) cms_profile_getattr_viewing_condition }, - { "version", (getter) cms_profile_getattr_version }, - { "icc_version", (getter) cms_profile_getattr_icc_version }, - { "attributes", (getter) cms_profile_getattr_attributes }, - { "header_flags", (getter) cms_profile_getattr_header_flags }, - { "header_manufacturer", (getter) cms_profile_getattr_header_manufacturer }, - { "header_model", (getter) cms_profile_getattr_header_model }, - { "device_class", (getter) cms_profile_getattr_device_class }, - { "connection_space", (getter) cms_profile_getattr_connection_space }, - { "xcolor_space", (getter) cms_profile_getattr_xcolor_space }, - { "profile_id", (getter) cms_profile_getattr_profile_id }, - { "is_matrix_shaper", (getter) cms_profile_getattr_is_matrix_shaper }, - { "technology", (getter) cms_profile_getattr_technology }, - { "colorimetric_intent", (getter) cms_profile_getattr_colorimetric_intent }, - { "perceptual_rendering_intent_gamut", (getter) cms_profile_getattr_perceptual_rendering_intent_gamut }, - { "saturation_rendering_intent_gamut", (getter) cms_profile_getattr_saturation_rendering_intent_gamut }, - { "red_colorant", (getter) cms_profile_getattr_red_colorant }, - { "green_colorant", (getter) cms_profile_getattr_green_colorant }, - { "blue_colorant", (getter) cms_profile_getattr_blue_colorant }, - { "red_primary", (getter) cms_profile_getattr_red_primary }, - { "green_primary", (getter) cms_profile_getattr_green_primary }, - { "blue_primary", (getter) cms_profile_getattr_blue_primary }, - { "media_white_point_temperature", (getter) cms_profile_getattr_media_white_point_temperature }, - { "media_white_point", (getter) cms_profile_getattr_media_white_point }, - { "media_black_point", (getter) cms_profile_getattr_media_black_point }, - { "luminance", (getter) cms_profile_getattr_luminance }, - { "chromatic_adaptation", (getter) cms_profile_getattr_chromatic_adaptation }, - { "chromaticity", (getter) cms_profile_getattr_chromaticity }, - { "colorant_table", (getter) cms_profile_getattr_colorant_table }, - { "colorant_table_out", (getter) cms_profile_getattr_colorant_table_out }, - { "intent_supported", (getter) cms_profile_getattr_is_intent_supported }, - { "clut", (getter) cms_profile_getattr_is_clut }, - { "icc_measurement_condition", (getter) cms_profile_getattr_icc_measurement_condition }, - { "icc_viewing_condition", (getter) cms_profile_getattr_icc_viewing_condition }, - - { NULL } -}; + {"rendering_intent", (getter)cms_profile_getattr_rendering_intent}, + {"creation_date", (getter)cms_profile_getattr_creation_date}, + {"copyright", (getter)cms_profile_getattr_copyright}, + {"target", (getter)cms_profile_getattr_target}, + {"manufacturer", (getter)cms_profile_getattr_manufacturer}, + {"model", (getter)cms_profile_getattr_model}, + {"profile_description", (getter)cms_profile_getattr_profile_description}, + {"screening_description", (getter)cms_profile_getattr_screening_description}, + {"viewing_condition", (getter)cms_profile_getattr_viewing_condition}, + {"version", (getter)cms_profile_getattr_version}, + {"icc_version", (getter)cms_profile_getattr_icc_version}, + {"attributes", (getter)cms_profile_getattr_attributes}, + {"header_flags", (getter)cms_profile_getattr_header_flags}, + {"header_manufacturer", (getter)cms_profile_getattr_header_manufacturer}, + {"header_model", (getter)cms_profile_getattr_header_model}, + {"device_class", (getter)cms_profile_getattr_device_class}, + {"connection_space", (getter)cms_profile_getattr_connection_space}, + {"xcolor_space", (getter)cms_profile_getattr_xcolor_space}, + {"profile_id", (getter)cms_profile_getattr_profile_id}, + {"is_matrix_shaper", (getter)cms_profile_getattr_is_matrix_shaper}, + {"technology", (getter)cms_profile_getattr_technology}, + {"colorimetric_intent", (getter)cms_profile_getattr_colorimetric_intent}, + {"perceptual_rendering_intent_gamut", + (getter)cms_profile_getattr_perceptual_rendering_intent_gamut}, + {"saturation_rendering_intent_gamut", + (getter)cms_profile_getattr_saturation_rendering_intent_gamut}, + {"red_colorant", (getter)cms_profile_getattr_red_colorant}, + {"green_colorant", (getter)cms_profile_getattr_green_colorant}, + {"blue_colorant", (getter)cms_profile_getattr_blue_colorant}, + {"red_primary", (getter)cms_profile_getattr_red_primary}, + {"green_primary", (getter)cms_profile_getattr_green_primary}, + {"blue_primary", (getter)cms_profile_getattr_blue_primary}, + {"media_white_point_temperature", + (getter)cms_profile_getattr_media_white_point_temperature}, + {"media_white_point", (getter)cms_profile_getattr_media_white_point}, + {"media_black_point", (getter)cms_profile_getattr_media_black_point}, + {"luminance", (getter)cms_profile_getattr_luminance}, + {"chromatic_adaptation", (getter)cms_profile_getattr_chromatic_adaptation}, + {"chromaticity", (getter)cms_profile_getattr_chromaticity}, + {"colorant_table", (getter)cms_profile_getattr_colorant_table}, + {"colorant_table_out", (getter)cms_profile_getattr_colorant_table_out}, + {"intent_supported", (getter)cms_profile_getattr_is_intent_supported}, + {"clut", (getter)cms_profile_getattr_is_clut}, + {"icc_measurement_condition", + (getter)cms_profile_getattr_icc_measurement_condition}, + {"icc_viewing_condition", (getter)cms_profile_getattr_icc_viewing_condition}, + {NULL}}; static PyTypeObject CmsProfile_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "PIL._imagingcms.CmsProfile", /*tp_name */ - sizeof(CmsProfileObject), 0,/*tp_basicsize, tp_itemsize */ + PyVarObject_HEAD_INIT(NULL, 0) "PIL._imagingcms.CmsProfile", /*tp_name */ + sizeof(CmsProfileObject), + 0, /*tp_basicsize, tp_itemsize */ /* methods */ - (destructor) cms_profile_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - cms_profile_methods, /*tp_methods*/ - 0, /*tp_members*/ - cms_profile_getsetters, /*tp_getset*/ + (destructor)cms_profile_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + cms_profile_methods, /*tp_methods*/ + 0, /*tp_members*/ + cms_profile_getsetters, /*tp_getset*/ }; static struct PyMethodDef cms_transform_methods[] = { - {"apply", (PyCFunction) cms_transform_apply, 1}, - {NULL, NULL} /* sentinel */ + {"apply", (PyCFunction)cms_transform_apply, 1}, {NULL, NULL} /* sentinel */ }; -static PyObject* -cms_transform_getattr_inputMode(CmsTransformObject* self, void* closure) -{ +static PyObject * +cms_transform_getattr_inputMode(CmsTransformObject *self, void *closure) { return PyUnicode_FromString(self->mode_in); } -static PyObject* -cms_transform_getattr_outputMode(CmsTransformObject* self, void* closure) -{ +static PyObject * +cms_transform_getattr_outputMode(CmsTransformObject *self, void *closure) { return PyUnicode_FromString(self->mode_out); } static struct PyGetSetDef cms_transform_getsetters[] = { - { "inputMode", (getter) cms_transform_getattr_inputMode }, - { "outputMode", (getter) cms_transform_getattr_outputMode }, - { NULL } -}; + {"inputMode", (getter)cms_transform_getattr_inputMode}, + {"outputMode", (getter)cms_transform_getattr_outputMode}, + {NULL}}; static PyTypeObject CmsTransform_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "CmsTransform", sizeof(CmsTransformObject), 0, + PyVarObject_HEAD_INIT(NULL, 0) "CmsTransform", + sizeof(CmsTransformObject), + 0, /* methods */ - (destructor) cms_transform_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - cms_transform_methods, /*tp_methods*/ - 0, /*tp_members*/ - cms_transform_getsetters, /*tp_getset*/ + (destructor)cms_transform_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + cms_transform_methods, /*tp_methods*/ + 0, /*tp_members*/ + cms_transform_getsetters, /*tp_getset*/ }; static int -setup_module(PyObject* m) { +setup_module(PyObject *m) { PyObject *d; PyObject *v; int vn; @@ -1524,14 +1539,14 @@ setup_module(PyObject* m) { PyMODINIT_FUNC PyInit__imagingcms(void) { - PyObject* m; + PyObject *m; static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, - "_imagingcms", /* m_name */ - NULL, /* m_doc */ - -1, /* m_size */ - pyCMSdll_methods, /* m_methods */ + "_imagingcms", /* m_name */ + NULL, /* m_doc */ + -1, /* m_size */ + pyCMSdll_methods, /* m_methods */ }; m = PyModule_Create(&module_def); diff --git a/src/_imagingft.c b/src/_imagingft.c index 5566ee3da..2427bc685 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -35,12 +35,8 @@ #define KEEP_PY_UNICODE -#ifndef _WIN32 -#include -#endif - #if !defined(FT_LOAD_TARGET_MONO) -#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME +#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME #endif /* -------------------------------------------------------------------- */ @@ -49,98 +45,62 @@ #undef FTERRORS_H #undef __FTERRORS_H__ -#define FT_ERRORDEF( e, v, s ) { e, s }, -#define FT_ERROR_START_LIST { -#define FT_ERROR_END_LIST { 0, 0 } }; +#define FT_ERRORDEF(e, v, s) {e, s}, +#define FT_ERROR_START_LIST { +#define FT_ERROR_END_LIST \ + { 0, 0 } \ + } \ + ; -#include "libImaging/raqm.h" +#ifdef HAVE_RAQM +# ifdef HAVE_RAQM_SYSTEM +# include +# else +# include "thirdparty/raqm/raqm.h" +# ifdef HAVE_FRIBIDI_SYSTEM +# include +# else +# include "thirdparty/fribidi-shim/fribidi.h" +# include +# endif +# endif +#endif + +static int have_raqm = 0; #define LAYOUT_FALLBACK 0 #define LAYOUT_RAQM 1 -typedef struct -{ - int index, x_offset, x_advance, y_offset, y_advance; - unsigned int cluster; +typedef struct { + int index, x_offset, x_advance, y_offset, y_advance; + unsigned int cluster; } GlyphInfo; struct { int code; - const char* message; + const char *message; } ft_errors[] = #include FT_ERRORS_H -/* -------------------------------------------------------------------- */ -/* font objects */ + /* -------------------------------------------------------------------- */ + /* font objects */ -static FT_Library library; + static FT_Library library; typedef struct { - PyObject_HEAD - FT_Face face; + PyObject_HEAD FT_Face face; unsigned char *font_bytes; int layout_engine; } FontObject; static PyTypeObject Font_Type; -typedef const char* (*t_raqm_version_string) (void); -typedef bool (*t_raqm_version_atleast)(unsigned int major, - unsigned int minor, - unsigned int micro); -typedef raqm_t* (*t_raqm_create)(void); -typedef int (*t_raqm_set_text)(raqm_t *rq, - const uint32_t *text, - size_t len); -typedef bool (*t_raqm_set_text_utf8) (raqm_t *rq, - const char *text, - size_t len); -typedef bool (*t_raqm_set_par_direction) (raqm_t *rq, - raqm_direction_t dir); -typedef bool (*t_raqm_set_language) (raqm_t *rq, - const char *lang, - size_t start, - size_t len); -typedef bool (*t_raqm_add_font_feature) (raqm_t *rq, - const char *feature, - int len); -typedef bool (*t_raqm_set_freetype_face) (raqm_t *rq, - FT_Face face); -typedef bool (*t_raqm_layout) (raqm_t *rq); -typedef raqm_glyph_t* (*t_raqm_get_glyphs) (raqm_t *rq, - size_t *length); -typedef raqm_glyph_t_01* (*t_raqm_get_glyphs_01) (raqm_t *rq, - size_t *length); -typedef void (*t_raqm_destroy) (raqm_t *rq); - -typedef struct { - void* raqm; - int version; - t_raqm_version_string version_string; - t_raqm_version_atleast version_atleast; - t_raqm_create create; - t_raqm_set_text set_text; - t_raqm_set_text_utf8 set_text_utf8; - t_raqm_set_par_direction set_par_direction; - t_raqm_set_language set_language; - t_raqm_add_font_feature add_font_feature; - t_raqm_set_freetype_face set_freetype_face; - t_raqm_layout layout; - t_raqm_get_glyphs get_glyphs; - t_raqm_get_glyphs_01 get_glyphs_01; - t_raqm_destroy destroy; -} p_raqm_func; - -static p_raqm_func p_raqm; - - /* round a 26.6 pixel coordinate to the nearest integer */ -#define PIXEL(x) ((((x)+32) & -64)>>6) +#define PIXEL(x) ((((x) + 32) & -64) >> 6) -static PyObject* -geterror(int code) -{ +static PyObject * +geterror(int code) { int i; for (i = 0; ft_errors[i].message; i++) { @@ -154,134 +114,41 @@ geterror(int code) return NULL; } -static int -setraqm(void) -{ - /* set the static function pointers for dynamic raqm linking */ - p_raqm.raqm = NULL; - - /* Microsoft needs a totally different system */ -#ifndef _WIN32 - p_raqm.raqm = dlopen("libraqm.so.0", RTLD_LAZY); - if (!p_raqm.raqm) { - p_raqm.raqm = dlopen("libraqm.dylib", RTLD_LAZY); - } -#else - p_raqm.raqm = LoadLibrary("libraqm"); - /* MSYS */ - if (!p_raqm.raqm) { - p_raqm.raqm = LoadLibrary("libraqm-0"); - } -#endif - - if (!p_raqm.raqm) { - return 1; - } - -#ifndef _WIN32 - p_raqm.version_string = (t_raqm_version_string)dlsym(p_raqm.raqm, "raqm_version_string"); - p_raqm.version_atleast = (t_raqm_version_atleast)dlsym(p_raqm.raqm, "raqm_version_atleast"); - p_raqm.create = (t_raqm_create)dlsym(p_raqm.raqm, "raqm_create"); - p_raqm.set_text = (t_raqm_set_text)dlsym(p_raqm.raqm, "raqm_set_text"); - p_raqm.set_text_utf8 = (t_raqm_set_text_utf8)dlsym(p_raqm.raqm, "raqm_set_text_utf8"); - p_raqm.set_par_direction = (t_raqm_set_par_direction)dlsym(p_raqm.raqm, "raqm_set_par_direction"); - p_raqm.set_language = (t_raqm_set_language)dlsym(p_raqm.raqm, "raqm_set_language"); - p_raqm.add_font_feature = (t_raqm_add_font_feature)dlsym(p_raqm.raqm, "raqm_add_font_feature"); - p_raqm.set_freetype_face = (t_raqm_set_freetype_face)dlsym(p_raqm.raqm, "raqm_set_freetype_face"); - p_raqm.layout = (t_raqm_layout)dlsym(p_raqm.raqm, "raqm_layout"); - p_raqm.destroy = (t_raqm_destroy)dlsym(p_raqm.raqm, "raqm_destroy"); - if(dlsym(p_raqm.raqm, "raqm_index_to_position")) { - p_raqm.get_glyphs = (t_raqm_get_glyphs)dlsym(p_raqm.raqm, "raqm_get_glyphs"); - p_raqm.version = 2; - } else { - p_raqm.version = 1; - p_raqm.get_glyphs_01 = (t_raqm_get_glyphs_01)dlsym(p_raqm.raqm, "raqm_get_glyphs"); - } - if (dlerror() || - !(p_raqm.create && - p_raqm.set_text && - p_raqm.set_text_utf8 && - p_raqm.set_par_direction && - p_raqm.set_language && - p_raqm.add_font_feature && - p_raqm.set_freetype_face && - p_raqm.layout && - (p_raqm.get_glyphs || p_raqm.get_glyphs_01) && - p_raqm.destroy)) { - dlclose(p_raqm.raqm); - p_raqm.raqm = NULL; - return 2; - } -#else - p_raqm.version_string = (t_raqm_version_string)GetProcAddress(p_raqm.raqm, "raqm_version_string"); - p_raqm.version_atleast = (t_raqm_version_atleast)GetProcAddress(p_raqm.raqm, "raqm_version_atleast"); - p_raqm.create = (t_raqm_create)GetProcAddress(p_raqm.raqm, "raqm_create"); - p_raqm.set_text = (t_raqm_set_text)GetProcAddress(p_raqm.raqm, "raqm_set_text"); - p_raqm.set_text_utf8 = (t_raqm_set_text_utf8)GetProcAddress(p_raqm.raqm, "raqm_set_text_utf8"); - p_raqm.set_par_direction = (t_raqm_set_par_direction)GetProcAddress(p_raqm.raqm, "raqm_set_par_direction"); - p_raqm.set_language = (t_raqm_set_language)GetProcAddress(p_raqm.raqm, "raqm_set_language"); - p_raqm.add_font_feature = (t_raqm_add_font_feature)GetProcAddress(p_raqm.raqm, "raqm_add_font_feature"); - p_raqm.set_freetype_face = (t_raqm_set_freetype_face)GetProcAddress(p_raqm.raqm, "raqm_set_freetype_face"); - p_raqm.layout = (t_raqm_layout)GetProcAddress(p_raqm.raqm, "raqm_layout"); - p_raqm.destroy = (t_raqm_destroy)GetProcAddress(p_raqm.raqm, "raqm_destroy"); - if(GetProcAddress(p_raqm.raqm, "raqm_index_to_position")) { - p_raqm.get_glyphs = (t_raqm_get_glyphs)GetProcAddress(p_raqm.raqm, "raqm_get_glyphs"); - p_raqm.version = 2; - } else { - p_raqm.version = 1; - p_raqm.get_glyphs_01 = (t_raqm_get_glyphs_01)GetProcAddress(p_raqm.raqm, "raqm_get_glyphs"); - } - if (!(p_raqm.create && - p_raqm.set_text && - p_raqm.set_text_utf8 && - p_raqm.set_par_direction && - p_raqm.set_language && - p_raqm.add_font_feature && - p_raqm.set_freetype_face && - p_raqm.layout && - (p_raqm.get_glyphs || p_raqm.get_glyphs_01) && - p_raqm.destroy)) { - FreeLibrary(p_raqm.raqm); - p_raqm.raqm = NULL; - return 2; - } -#endif - - return 0; -} - -static PyObject* -getfont(PyObject* self_, PyObject* args, PyObject* kw) -{ +static PyObject * +getfont(PyObject *self_, PyObject *args, PyObject *kw) { /* create a font object from a file name and a size (in pixels) */ - FontObject* self; + FontObject *self; int error = 0; - char* filename = NULL; + char *filename = NULL; Py_ssize_t size; Py_ssize_t index = 0; Py_ssize_t layout_engine = 0; - unsigned char* encoding; - unsigned char* font_bytes; + unsigned char *encoding; + unsigned char *font_bytes; Py_ssize_t font_bytes_size = 0; - static char* kwlist[] = { - "filename", "size", "index", "encoding", "font_bytes", - "layout_engine", NULL - }; + static char *kwlist[] = { + "filename", "size", "index", "encoding", "font_bytes", "layout_engine", NULL}; if (!library) { - PyErr_SetString( - PyExc_OSError, - "failed to initialize FreeType library" - ); + PyErr_SetString(PyExc_OSError, "failed to initialize FreeType library"); return NULL; } - if (!PyArg_ParseTupleAndKeywords(args, kw, "etn|nsy#n", kwlist, - Py_FileSystemDefaultEncoding, &filename, - &size, &index, &encoding, &font_bytes, - &font_bytes_size, &layout_engine)) { + if (!PyArg_ParseTupleAndKeywords( + args, + kw, + "etn|nsy#n", + kwlist, + Py_FileSystemDefaultEncoding, + &filename, + &size, + &index, + &encoding, + &font_bytes, + &font_bytes_size, + &layout_engine)) { return NULL; } @@ -304,12 +171,16 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw) /* Don't free this before FT_Done_Face */ self->font_bytes = PyMem_Malloc(font_bytes_size); if (!self->font_bytes) { - error = 65; // Out of Memory in Freetype. + error = 65; // Out of Memory in Freetype. } if (!error) { memcpy(self->font_bytes, font_bytes, (size_t)font_bytes_size); - error = FT_New_Memory_Face(library, (FT_Byte*)self->font_bytes, - font_bytes_size, index, &self->face); + error = FT_New_Memory_Face( + library, + (FT_Byte *)self->font_bytes, + font_bytes_size, + index, + &self->face); } } @@ -317,14 +188,13 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw) error = FT_Set_Pixel_Sizes(self->face, 0, size); } - if (!error && encoding && strlen((char*) encoding) == 4) { - FT_Encoding encoding_tag = FT_MAKE_TAG( - encoding[0], encoding[1], encoding[2], encoding[3] - ); + if (!error && encoding && strlen((char *)encoding) == 4) { + FT_Encoding encoding_tag = + FT_MAKE_TAG(encoding[0], encoding[1], encoding[2], encoding[3]); error = FT_Select_Charmap(self->face, encoding_tag); } if (filename) { - PyMem_Free(filename); + PyMem_Free(filename); } if (error) { @@ -336,12 +206,11 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw) return geterror(error); } - return (PyObject*) self; + return (PyObject *)self; } static int -font_getchar(PyObject* string, int index, FT_ULong* char_out) -{ +font_getchar(PyObject *string, int index, FT_ULong *char_out) { if (PyUnicode_Check(string)) { if (index >= PyUnicode_GET_LENGTH(string)) { return 0; @@ -352,17 +221,24 @@ font_getchar(PyObject* string, int index, FT_ULong* char_out) return 0; } +#ifdef HAVE_RAQM + static size_t -text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *features, - const char* lang, GlyphInfo **glyph_info, int mask, int color) -{ +text_layout_raqm( + PyObject *string, + FontObject *self, + const char *dir, + PyObject *features, + const char *lang, + GlyphInfo **glyph_info, + int mask, + int color) { size_t i = 0, count = 0, start = 0; raqm_t *rq; raqm_glyph_t *glyphs = NULL; - raqm_glyph_t_01 *glyphs_01 = NULL; raqm_direction_t direction; - rq = (*p_raqm.create)(); + rq = raqm_create(); if (rq == NULL) { PyErr_SetString(PyExc_ValueError, "raqm_create() failed."); goto failed; @@ -376,20 +252,19 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject * and raqm fails with empty strings */ goto failed; } - int set_text = (*p_raqm.set_text)(rq, text, size); + int set_text = raqm_set_text(rq, text, size); PyMem_Free(text); if (!set_text) { PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed"); goto failed; } if (lang) { - if (!(*p_raqm.set_language)(rq, lang, start, size)) { + if (!raqm_set_language(rq, lang, start, size)) { PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed"); goto failed; } } - } - else { + } else { PyErr_SetString(PyExc_TypeError, "expected string"); goto failed; } @@ -402,17 +277,21 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject * direction = RAQM_DIRECTION_LTR; } else if (strcmp(dir, "ttb") == 0) { direction = RAQM_DIRECTION_TTB; - if (p_raqm.version_atleast == NULL || !(*p_raqm.version_atleast)(0, 7, 0)) { - PyErr_SetString(PyExc_ValueError, "libraqm 0.7 or greater required for 'ttb' direction"); - goto failed; - } +#if !defined(RAQM_VERSION_ATLEAST) + /* RAQM_VERSION_ATLEAST was added in Raqm 0.7.0 */ + PyErr_SetString( + PyExc_ValueError, + "libraqm 0.7 or greater required for 'ttb' direction"); + goto failed; +#endif } else { - PyErr_SetString(PyExc_ValueError, "direction must be either 'rtl', 'ltr' or 'ttb'"); + PyErr_SetString( + PyExc_ValueError, "direction must be either 'rtl', 'ltr' or 'ttb'"); goto failed; } } - if (!(*p_raqm.set_par_direction)(rq, direction)) { + if (!raqm_set_par_direction(rq, direction)) { PyErr_SetString(PyExc_ValueError, "raqm_set_par_direction() failed"); goto failed; } @@ -444,37 +323,28 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject * feature = PyBytes_AS_STRING(bytes); size = PyBytes_GET_SIZE(bytes); } - if (!(*p_raqm.add_font_feature)(rq, feature, size)) { + if (!raqm_add_font_feature(rq, feature, size)) { PyErr_SetString(PyExc_ValueError, "raqm_add_font_feature() failed"); goto failed; } } } - if (!(*p_raqm.set_freetype_face)(rq, self->face)) { + if (!raqm_set_freetype_face(rq, self->face)) { PyErr_SetString(PyExc_RuntimeError, "raqm_set_freetype_face() failed."); goto failed; } - if (!(*p_raqm.layout)(rq)) { + if (!raqm_layout(rq)) { PyErr_SetString(PyExc_RuntimeError, "raqm_layout() failed."); goto failed; } - if (p_raqm.version == 1) { - glyphs_01 = (*p_raqm.get_glyphs_01)(rq, &count); - if (glyphs_01 == NULL) { - PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); - count = 0; - goto failed; - } - } else { /* version == 2 */ - glyphs = (*p_raqm.get_glyphs)(rq, &count); - if (glyphs == NULL) { - PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); - count = 0; - goto failed; - } + glyphs = raqm_get_glyphs(rq, &count); + if (glyphs == NULL) { + PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); + count = 0; + goto failed; } (*glyph_info) = PyMem_New(GlyphInfo, count); @@ -484,35 +354,32 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject * goto failed; } - if (p_raqm.version == 1) { - for (i = 0; i < count; i++) { - (*glyph_info)[i].index = glyphs_01[i].index; - (*glyph_info)[i].x_offset = glyphs_01[i].x_offset; - (*glyph_info)[i].x_advance = glyphs_01[i].x_advance; - (*glyph_info)[i].y_offset = glyphs_01[i].y_offset; - (*glyph_info)[i].y_advance = glyphs_01[i].y_advance; - (*glyph_info)[i].cluster = glyphs_01[i].cluster; - } - } else { - for (i = 0; i < count; i++) { - (*glyph_info)[i].index = glyphs[i].index; - (*glyph_info)[i].x_offset = glyphs[i].x_offset; - (*glyph_info)[i].x_advance = glyphs[i].x_advance; - (*glyph_info)[i].y_offset = glyphs[i].y_offset; - (*glyph_info)[i].y_advance = glyphs[i].y_advance; - (*glyph_info)[i].cluster = glyphs[i].cluster; - } + for (i = 0; i < count; i++) { + (*glyph_info)[i].index = glyphs[i].index; + (*glyph_info)[i].x_offset = glyphs[i].x_offset; + (*glyph_info)[i].x_advance = glyphs[i].x_advance; + (*glyph_info)[i].y_offset = glyphs[i].y_offset; + (*glyph_info)[i].y_advance = glyphs[i].y_advance; + (*glyph_info)[i].cluster = glyphs[i].cluster; } failed: - (*p_raqm.destroy)(rq); + raqm_destroy(rq); return count; } +#endif + static size_t -text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObject *features, - const char* lang, GlyphInfo **glyph_info, int mask, int color) -{ +text_layout_fallback( + PyObject *string, + FontObject *self, + const char *dir, + PyObject *features, + const char *lang, + GlyphInfo **glyph_info, + int mask, + int color) { int error, load_flags; FT_ULong ch; Py_ssize_t count; @@ -522,7 +389,10 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObje int i; if (features != Py_None || dir != NULL || lang != NULL) { - PyErr_SetString(PyExc_KeyError, "setting text direction, language or font features is not supported without libraqm"); + PyErr_SetString( + PyExc_KeyError, + "setting text direction, language or font features is not supported " + "without libraqm"); } if (!PyUnicode_Check(string)) { PyErr_SetString(PyExc_TypeError, "expected string"); @@ -531,7 +401,7 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObje count = 0; while (font_getchar(string, count, &ch)) { - count++; + count++; } if (count == 0) { return 0; @@ -560,14 +430,18 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObje return 0; } glyph = self->face->glyph; - (*glyph_info)[i].x_offset=0; - (*glyph_info)[i].y_offset=0; + (*glyph_info)[i].x_offset = 0; + (*glyph_info)[i].y_offset = 0; if (kerning && last_index && (*glyph_info)[i].index) { FT_Vector delta; - if (FT_Get_Kerning(self->face, last_index, (*glyph_info)[i].index, - ft_kerning_default,&delta) == 0) { - (*glyph_info)[i-1].x_advance += PIXEL(delta.x); - (*glyph_info)[i-1].y_advance += PIXEL(delta.y); + if (FT_Get_Kerning( + self->face, + last_index, + (*glyph_info)[i].index, + ft_kerning_default, + &delta) == 0) { + (*glyph_info)[i - 1].x_advance += PIXEL(delta.x); + (*glyph_info)[i - 1].y_advance += PIXEL(delta.y); } } @@ -581,28 +455,37 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObje } static size_t -text_layout(PyObject* string, FontObject* self, const char* dir, PyObject *features, - const char* lang, GlyphInfo **glyph_info, int mask, int color) -{ +text_layout( + PyObject *string, + FontObject *self, + const char *dir, + PyObject *features, + const char *lang, + GlyphInfo **glyph_info, + int mask, + int color) { size_t count; - - if (p_raqm.raqm && self->layout_engine == LAYOUT_RAQM) { - count = text_layout_raqm(string, self, dir, features, lang, glyph_info, mask, color); - } else { - count = text_layout_fallback(string, self, dir, features, lang, glyph_info, mask, color); +#ifdef HAVE_RAQM + if (have_raqm && self->layout_engine == LAYOUT_RAQM) { + count = text_layout_raqm( + string, self, dir, features, lang, glyph_info, mask, color); + } else +#endif + { + count = text_layout_fallback( + string, self, dir, features, lang, glyph_info, mask, color); } return count; } -static PyObject* -font_getlength(FontObject* self, PyObject* args) -{ - int length; /* length along primary axis, in 26.6 precision */ +static PyObject * +font_getlength(FontObject *self, PyObject *args) { + int length; /* length along primary axis, in 26.6 precision */ 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? */ + 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; @@ -611,7 +494,8 @@ font_getlength(FontObject* self, PyObject* args) /* calculate size and bearing for a given string */ - if (!PyArg_ParseTuple(args, "O|zzOz:getlength", &string, &mode, &dir, &features, &lang)) { + if (!PyArg_ParseTuple( + args, "O|zzOz:getlength", &string, &mode, &dir, &features, &lang)) { return NULL; } @@ -642,24 +526,23 @@ font_getlength(FontObject* self, PyObject* args) return PyLong_FromLong(length); } -static PyObject* -font_getsize(FontObject* self, PyObject* args) -{ +static PyObject * +font_getsize(FontObject *self, PyObject *args) { 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 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 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 */ + 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? */ + 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; @@ -669,7 +552,8 @@ font_getsize(FontObject* self, PyObject* args) /* calculate size and bearing for a given string */ - if (!PyArg_ParseTuple(args, "O|zzOzz:getsize", &string, &mode, &dir, &features, &lang, &anchor)) { + if (!PyArg_ParseTuple( + args, "O|zzOzz:getsize", &string, &mode, &dir, &features, &lang, &anchor)) { return NULL; } @@ -771,95 +655,98 @@ font_getsize(FontObject* self, PyObject* args) if (face) { if (horizontal_dir) { switch (anchor[0]) { - case 'l': // left - x_anchor = 0; - break; - case 'm': // middle (left + right) / 2 - x_anchor = PIXEL(position / 2); - break; - case 'r': // right - x_anchor = PIXEL(position); - break; - case 's': // vertical baseline - default: - goto bad_anchor; + case 'l': // left + x_anchor = 0; + break; + case 'm': // middle (left + right) / 2 + x_anchor = PIXEL(position / 2); + break; + case 'r': // right + x_anchor = PIXEL(position); + break; + case 's': // vertical baseline + default: + goto bad_anchor; } switch (anchor[1]) { - case 'a': // ascender - y_anchor = PIXEL(self->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) / 2); - break; - case 's': // horizontal baseline - y_anchor = 0; - break; - case 'b': // bottom - y_anchor = y_min; - break; - case 'd': // descender - y_anchor = PIXEL(self->face->size->metrics.descender); - break; - default: - goto bad_anchor; + case 'a': // ascender + y_anchor = PIXEL(self->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) / + 2); + break; + case 's': // horizontal baseline + y_anchor = 0; + break; + case 'b': // bottom + y_anchor = y_min; + break; + case 'd': // descender + y_anchor = PIXEL(self->face->size->metrics.descender); + break; + default: + goto bad_anchor; } } else { switch (anchor[0]) { - case 'l': // left - x_anchor = x_min; - break; - case 'm': // middle (left + right) / 2 - x_anchor = (x_min + x_max) / 2; - break; - case 'r': // right - x_anchor = x_max; - break; - case 's': // vertical baseline - x_anchor = 0; - break; - default: - goto bad_anchor; + case 'l': // left + x_anchor = x_min; + break; + case 'm': // middle (left + right) / 2 + x_anchor = (x_min + x_max) / 2; + break; + case 'r': // right + x_anchor = x_max; + break; + case 's': // vertical baseline + x_anchor = 0; + break; + default: + goto bad_anchor; } switch (anchor[1]) { - case 't': // top - y_anchor = 0; - break; - case 'm': // middle (top + bottom) / 2 - y_anchor = PIXEL(position / 2); - break; - case 'b': // bottom - y_anchor = PIXEL(position); - break; - case 'a': // ascender - case 's': // horizontal baseline - case 'd': // descender - default: - goto bad_anchor; + case 't': // top + y_anchor = 0; + break; + case 'm': // middle (top + bottom) / 2 + y_anchor = PIXEL(position / 2); + break; + case 'b': // bottom + y_anchor = PIXEL(position); + break; + case 'a': // ascender + case 's': // horizontal baseline + case 'd': // descender + default: + goto bad_anchor; } } } return Py_BuildValue( "(ii)(ii)", - (x_max - x_min), (y_max - y_min), - (-x_anchor + x_min), -(-y_anchor + y_max) - ); + (x_max - x_min), + (y_max - y_min), + (-x_anchor + x_min), + -(-y_anchor + y_max)); bad_anchor: PyErr_Format(PyExc_ValueError, "bad anchor specified: %s", anchor); return NULL; } -static PyObject* -font_render(FontObject* self, PyObject* args) -{ - int x, y; /* pen position, in 26.6 precision */ - int px, py; /* position of current glyph, in pixels */ +static PyObject * +font_render(FontObject *self, PyObject *args) { + int x, y; /* pen position, in 26.6 precision */ + int px, py; /* position of current glyph, in pixels */ int x_min, y_max; /* text offset in 26.6 precision */ - int load_flags; /* FreeType load_flags parameter */ + int load_flags; /* FreeType load_flags parameter */ int error; FT_Glyph glyph; FT_GlyphSlot glyph_slot; @@ -868,16 +755,16 @@ font_render(FontObject* self, PyObject* args) FT_BitmapGlyph bitmap_glyph; FT_Stroker stroker = NULL; int bitmap_converted_ready = 0; /* has bitmap_converted been initialized */ - GlyphInfo *glyph_info = NULL; /* computed text layout */ - size_t i, count; /* glyph_info index and length */ - int xx, yy; /* pixel offset of current glyph bitmap */ - int x0, x1; /* horizontal bounds of glyph bitmap to copy */ - 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 */ + GlyphInfo *glyph_info = NULL; /* computed text layout */ + size_t i, count; /* glyph_info index and length */ + int xx, yy; /* pixel offset of current glyph bitmap */ + int x0, x1; /* horizontal bounds of glyph bitmap to copy */ + 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 */ Imaging im; Py_ssize_t id; - int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */ + int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */ int color = 0; /* is FT_LOAD_COLOR enabled? */ int stroke_width = 0; PY_LONG_LONG foreground_ink_long = 0; @@ -886,13 +773,22 @@ font_render(FontObject* self, PyObject* args) const char *dir = NULL; const char *lang = NULL; PyObject *features = Py_None; - PyObject* string; + PyObject *string; /* render string into given buffer (the buffer *must* have the right size, or this will crash) */ - if (!PyArg_ParseTuple(args, "On|zzOziL:render", &string, &id, &mode, &dir, &features, &lang, - &stroke_width, &foreground_ink_long)) { + if (!PyArg_ParseTuple( + args, + "On|zzOziL:render", + &string, + &id, + &mode, + &dir, + &features, + &lang, + &stroke_width, + &foreground_ink_long)) { return NULL; } @@ -904,11 +800,12 @@ font_render(FontObject* self, PyObject* args) #ifdef FT_COLOR_H if (color) { FT_Color foreground_color; - FT_Byte* ink = (FT_Byte*)&foreground_ink; + FT_Byte *ink = (FT_Byte *)&foreground_ink; foreground_color.red = ink[0]; foreground_color.green = ink[1]; foreground_color.blue = ink[2]; - foreground_color.alpha = (FT_Byte) 255; /* ink alpha is handled in ImageDraw.text */ + foreground_color.alpha = + (FT_Byte)255; /* ink alpha is handled in ImageDraw.text */ FT_Palette_Set_Foreground_Color(self->face, foreground_color); } #endif @@ -927,10 +824,15 @@ font_render(FontObject* self, PyObject* args) return geterror(error); } - FT_Stroker_Set(stroker, (FT_Fixed)stroke_width*64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); + FT_Stroker_Set( + stroker, + (FT_Fixed)stroke_width * 64, + FT_STROKER_LINECAP_ROUND, + FT_STROKER_LINEJOIN_ROUND, + 0); } - im = (Imaging) id; + im = (Imaging)id; load_flags = FT_LOAD_DEFAULT; if (mask) { load_flags |= FT_LOAD_TARGET_MONO; @@ -950,7 +852,8 @@ font_render(FontObject* self, PyObject* args) px = PIXEL(x + glyph_info[i].x_offset); py = PIXEL(y + glyph_info[i].y_offset); - error = FT_Load_Glyph(self->face, glyph_info[i].index, load_flags | FT_LOAD_RENDER); + error = + FT_Load_Glyph(self->face, glyph_info[i].index, load_flags | FT_LOAD_RENDER); if (error) { return geterror(error); } @@ -1030,9 +933,7 @@ font_render(FontObject* self, PyObject* args) case FT_PIXEL_MODE_GRAY2: case FT_PIXEL_MODE_GRAY4: if (!bitmap_converted_ready) { - -#if FREETYPE_MAJOR > 2 ||\ - (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 6) +#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 6) FT_Bitmap_Init(&bitmap_converted); #else FT_Bitmap_New(&bitmap_converted); @@ -1070,18 +971,18 @@ font_render(FontObject* self, PyObject* args) x1 = im->xsize - xx; } - source = (unsigned char*) bitmap.buffer; + source = (unsigned char *)bitmap.buffer; for (bitmap_y = 0; bitmap_y < bitmap.rows; bitmap_y++, yy++) { /* clip glyph bitmap height to target image bounds */ if (yy >= 0 && yy < im->ysize) { /* blend this glyph into the buffer */ int k; unsigned char v; - unsigned char* target; + unsigned char *target; if (color) { /* target[RGB] returns the color, target[A] returns the mask */ /* target bands get split again in ImageDraw.text */ - target = (unsigned char*)im->image[yy] + xx * 4; + target = (unsigned char *)im->image[yy] + xx * 4; } else { target = im->image8[yy] + xx; } @@ -1091,17 +992,20 @@ font_render(FontObject* self, PyObject* args) for (k = x0; k < x1; k++) { if (target[k * 4 + 3] < source[k * 4 + 3]) { /* unpremultiply BGRa to RGBA */ - target[k * 4 + 0] = CLIP8((255 * (int)source[k * 4 + 2]) / source[k * 4 + 3]); - target[k * 4 + 1] = CLIP8((255 * (int)source[k * 4 + 1]) / source[k * 4 + 3]); - target[k * 4 + 2] = CLIP8((255 * (int)source[k * 4 + 0]) / source[k * 4 + 3]); + target[k * 4 + 0] = CLIP8( + (255 * (int)source[k * 4 + 2]) / source[k * 4 + 3]); + target[k * 4 + 1] = CLIP8( + (255 * (int)source[k * 4 + 1]) / source[k * 4 + 3]); + target[k * 4 + 2] = CLIP8( + (255 * (int)source[k * 4 + 0]) / source[k * 4 + 3]); target[k * 4 + 3] = source[k * 4 + 3]; } } } else #endif - if (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { + if (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { if (color) { - unsigned char* ink = (unsigned char*)&foreground_ink; + unsigned char *ink = (unsigned char *)&foreground_ink; for (k = x0; k < x1; k++) { v = source[k] * convert_scale; if (target[k * 4 + 3] < v) { @@ -1152,173 +1056,166 @@ glyph_error: return NULL; } -#if FREETYPE_MAJOR > 2 ||\ - (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) ||\ +#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) || \ (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 9 && FREETYPE_PATCH == 1) - static PyObject* - font_getvarnames(FontObject* self) - { - int error; - FT_UInt i, j, num_namedstyles, name_count; - FT_MM_Var *master; - FT_SfntName name; - PyObject *list_names, *list_name; +static PyObject * +font_getvarnames(FontObject *self) { + int error; + FT_UInt i, j, num_namedstyles, name_count; + FT_MM_Var *master; + FT_SfntName name; + PyObject *list_names, *list_name; - error = FT_Get_MM_Var(self->face, &master); + error = FT_Get_MM_Var(self->face, &master); + if (error) { + return geterror(error); + } + + num_namedstyles = master->num_namedstyles; + list_names = PyList_New(num_namedstyles); + + name_count = FT_Get_Sfnt_Name_Count(self->face); + for (i = 0; i < name_count; i++) { + error = FT_Get_Sfnt_Name(self->face, i, &name); if (error) { return geterror(error); } - num_namedstyles = master->num_namedstyles; - list_names = PyList_New(num_namedstyles); + for (j = 0; j < num_namedstyles; j++) { + if (PyList_GetItem(list_names, j) != NULL) { + continue; + } - name_count = FT_Get_Sfnt_Name_Count(self->face); - for (i = 0; i < name_count; i++) { - error = FT_Get_Sfnt_Name(self->face, i, &name); + if (master->namedstyle[j].strid == name.name_id) { + list_name = Py_BuildValue("y#", name.string, name.string_len); + PyList_SetItem(list_names, j, list_name); + break; + } + } + } + + FT_Done_MM_Var(library, master); + + return list_names; +} + +static PyObject * +font_getvaraxes(FontObject *self) { + int error; + FT_UInt i, j, num_axis, name_count; + FT_MM_Var *master; + FT_Var_Axis axis; + FT_SfntName name; + PyObject *list_axes, *list_axis, *axis_name; + error = FT_Get_MM_Var(self->face, &master); + if (error) { + return geterror(error); + } + + num_axis = master->num_axis; + name_count = FT_Get_Sfnt_Name_Count(self->face); + + list_axes = PyList_New(num_axis); + for (i = 0; i < num_axis; i++) { + axis = master->axis[i]; + + list_axis = PyDict_New(); + PyDict_SetItemString( + list_axis, "minimum", PyLong_FromLong(axis.minimum / 65536)); + PyDict_SetItemString(list_axis, "default", PyLong_FromLong(axis.def / 65536)); + PyDict_SetItemString( + list_axis, "maximum", PyLong_FromLong(axis.maximum / 65536)); + + for (j = 0; j < name_count; j++) { + error = FT_Get_Sfnt_Name(self->face, j, &name); if (error) { return geterror(error); } - for (j = 0; j < num_namedstyles; j++) { - if (PyList_GetItem(list_names, j) != NULL) { - continue; - } - - if (master->namedstyle[j].strid == name.name_id) { - list_name = Py_BuildValue("y#", name.string, name.string_len); - PyList_SetItem(list_names, j, list_name); - break; - } + if (name.name_id == axis.strid) { + axis_name = Py_BuildValue("y#", name.string, name.string_len); + PyDict_SetItemString(list_axis, "name", axis_name); + break; } } - FT_Done_MM_Var(library, master); - - return list_names; + PyList_SetItem(list_axes, i, list_axis); } - static PyObject* - font_getvaraxes(FontObject* self) - { - int error; - FT_UInt i, j, num_axis, name_count; - FT_MM_Var* master; - FT_Var_Axis axis; - FT_SfntName name; - PyObject *list_axes, *list_axis, *axis_name; - error = FT_Get_MM_Var(self->face, &master); - if (error) { - return geterror(error); - } + FT_Done_MM_Var(library, master); - num_axis = master->num_axis; - name_count = FT_Get_Sfnt_Name_Count(self->face); + return list_axes; +} - list_axes = PyList_New(num_axis); - for (i = 0; i < num_axis; i++) { - axis = master->axis[i]; +static PyObject * +font_setvarname(FontObject *self, PyObject *args) { + int error; - list_axis = PyDict_New(); - PyDict_SetItemString(list_axis, "minimum", - PyLong_FromLong(axis.minimum / 65536)); - PyDict_SetItemString(list_axis, "default", - PyLong_FromLong(axis.def / 65536)); - PyDict_SetItemString(list_axis, "maximum", - PyLong_FromLong(axis.maximum / 65536)); - - for (j = 0; j < name_count; j++) { - error = FT_Get_Sfnt_Name(self->face, j, &name); - if (error) { - return geterror(error); - } - - if (name.name_id == axis.strid) { - axis_name = Py_BuildValue("y#", name.string, name.string_len); - PyDict_SetItemString(list_axis, "name", axis_name); - break; - } - } - - PyList_SetItem(list_axes, i, list_axis); - } - - FT_Done_MM_Var(library, master); - - return list_axes; + int instance_index; + if (!PyArg_ParseTuple(args, "i", &instance_index)) { + return NULL; } - static PyObject* - font_setvarname(FontObject* self, PyObject* args) - { - int error; + error = FT_Set_Named_Instance(self->face, instance_index); + if (error) { + return geterror(error); + } - int instance_index; - if (!PyArg_ParseTuple(args, "i", &instance_index)) { + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +font_setvaraxes(FontObject *self, PyObject *args) { + int error; + + PyObject *axes, *item; + Py_ssize_t i, num_coords; + FT_Fixed *coords; + FT_Fixed coord; + if (!PyArg_ParseTuple(args, "O", &axes)) { + return NULL; + } + + if (!PyList_Check(axes)) { + PyErr_SetString(PyExc_TypeError, "argument must be a list"); + return NULL; + } + + num_coords = PyObject_Length(axes); + coords = malloc(2 * sizeof(coords)); + if (coords == NULL) { + return PyErr_NoMemory(); + } + for (i = 0; i < num_coords; i++) { + item = PyList_GET_ITEM(axes, i); + if (PyFloat_Check(item)) { + coord = PyFloat_AS_DOUBLE(item); + } else if (PyLong_Check(item)) { + coord = (float)PyLong_AS_LONG(item); + } else if (PyNumber_Check(item)) { + coord = PyFloat_AsDouble(item); + } else { + free(coords); + PyErr_SetString(PyExc_TypeError, "list must contain numbers"); return NULL; } - - error = FT_Set_Named_Instance(self->face, instance_index); - if (error) { - return geterror(error); - } - - Py_INCREF(Py_None); - return Py_None; + coords[i] = coord * 65536; } - static PyObject* - font_setvaraxes(FontObject* self, PyObject* args) - { - int error; - - PyObject *axes, *item; - Py_ssize_t i, num_coords; - FT_Fixed *coords; - FT_Fixed coord; - if (!PyArg_ParseTuple(args, "O", &axes)) { - return NULL; - } - - if (!PyList_Check(axes)) { - PyErr_SetString(PyExc_TypeError, "argument must be a list"); - return NULL; - } - - num_coords = PyObject_Length(axes); - coords = malloc(2 * sizeof(coords)); - if (coords == NULL) { - return PyErr_NoMemory(); - } - for (i = 0; i < num_coords; i++) { - item = PyList_GET_ITEM(axes, i); - if (PyFloat_Check(item)) { - coord = PyFloat_AS_DOUBLE(item); - } else if (PyLong_Check(item)) { - coord = (float) PyLong_AS_LONG(item); - } else if (PyNumber_Check(item)) { - coord = PyFloat_AsDouble(item); - } else { - free(coords); - PyErr_SetString(PyExc_TypeError, "list must contain numbers"); - return NULL; - } - coords[i] = coord * 65536; - } - - error = FT_Set_Var_Design_Coordinates(self->face, num_coords, coords); - free(coords); - if (error) { - return geterror(error); - } - - Py_INCREF(Py_None); - return Py_None; + error = FT_Set_Var_Design_Coordinates(self->face, num_coords, coords); + free(coords); + if (error) { + return geterror(error); } + + Py_INCREF(Py_None); + return Py_None; +} #endif static void -font_dealloc(FontObject* self) -{ +font_dealloc(FontObject *self) { if (self->face) { FT_Done_Face(self->face); } @@ -1329,128 +1226,115 @@ font_dealloc(FontObject* self) } static PyMethodDef font_methods[] = { - {"render", (PyCFunction) font_render, METH_VARARGS}, - {"getsize", (PyCFunction) font_getsize, METH_VARARGS}, - {"getlength", (PyCFunction) font_getlength, METH_VARARGS}, -#if FREETYPE_MAJOR > 2 ||\ - (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) ||\ + {"render", (PyCFunction)font_render, METH_VARARGS}, + {"getsize", (PyCFunction)font_getsize, METH_VARARGS}, + {"getlength", (PyCFunction)font_getlength, METH_VARARGS}, +#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 9) || \ (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 9 && FREETYPE_PATCH == 1) - {"getvarnames", (PyCFunction) font_getvarnames, METH_NOARGS }, - {"getvaraxes", (PyCFunction) font_getvaraxes, METH_NOARGS }, - {"setvarname", (PyCFunction) font_setvarname, METH_VARARGS}, - {"setvaraxes", (PyCFunction) font_setvaraxes, METH_VARARGS}, + {"getvarnames", (PyCFunction)font_getvarnames, METH_NOARGS}, + {"getvaraxes", (PyCFunction)font_getvaraxes, METH_NOARGS}, + {"setvarname", (PyCFunction)font_setvarname, METH_VARARGS}, + {"setvaraxes", (PyCFunction)font_setvaraxes, METH_VARARGS}, #endif - {NULL, NULL} -}; + {NULL, NULL}}; -static PyObject* -font_getattr_family(FontObject* self, void* closure) -{ +static PyObject * +font_getattr_family(FontObject *self, void *closure) { if (self->face->family_name) { return PyUnicode_FromString(self->face->family_name); } Py_RETURN_NONE; } -static PyObject* -font_getattr_style(FontObject* self, void* closure) -{ +static PyObject * +font_getattr_style(FontObject *self, void *closure) { if (self->face->style_name) { return PyUnicode_FromString(self->face->style_name); } Py_RETURN_NONE; } -static PyObject* -font_getattr_ascent(FontObject* self, void* closure) -{ +static PyObject * +font_getattr_ascent(FontObject *self, void *closure) { return PyLong_FromLong(PIXEL(self->face->size->metrics.ascender)); } -static PyObject* -font_getattr_descent(FontObject* self, void* closure) -{ +static PyObject * +font_getattr_descent(FontObject *self, void *closure) { return PyLong_FromLong(-PIXEL(self->face->size->metrics.descender)); } -static PyObject* -font_getattr_height(FontObject* self, void* closure) -{ +static PyObject * +font_getattr_height(FontObject *self, void *closure) { return PyLong_FromLong(PIXEL(self->face->size->metrics.height)); } -static PyObject* -font_getattr_x_ppem(FontObject* self, void* closure) -{ +static PyObject * +font_getattr_x_ppem(FontObject *self, void *closure) { return PyLong_FromLong(self->face->size->metrics.x_ppem); } -static PyObject* -font_getattr_y_ppem(FontObject* self, void* closure) -{ +static PyObject * +font_getattr_y_ppem(FontObject *self, void *closure) { return PyLong_FromLong(self->face->size->metrics.y_ppem); } - -static PyObject* -font_getattr_glyphs(FontObject* self, void* closure) -{ +static PyObject * +font_getattr_glyphs(FontObject *self, void *closure) { return PyLong_FromLong(self->face->num_glyphs); } static struct PyGetSetDef font_getsetters[] = { - { "family", (getter) font_getattr_family }, - { "style", (getter) font_getattr_style }, - { "ascent", (getter) font_getattr_ascent }, - { "descent", (getter) font_getattr_descent }, - { "height", (getter) font_getattr_height }, - { "x_ppem", (getter) font_getattr_x_ppem }, - { "y_ppem", (getter) font_getattr_y_ppem }, - { "glyphs", (getter) font_getattr_glyphs }, - { NULL } -}; + {"family", (getter)font_getattr_family}, + {"style", (getter)font_getattr_style}, + {"ascent", (getter)font_getattr_ascent}, + {"descent", (getter)font_getattr_descent}, + {"height", (getter)font_getattr_height}, + {"x_ppem", (getter)font_getattr_x_ppem}, + {"y_ppem", (getter)font_getattr_y_ppem}, + {"glyphs", (getter)font_getattr_glyphs}, + {NULL}}; static PyTypeObject Font_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "Font", sizeof(FontObject), 0, + PyVarObject_HEAD_INIT(NULL, 0) "Font", + sizeof(FontObject), + 0, /* methods */ (destructor)font_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - font_methods, /*tp_methods*/ - 0, /*tp_members*/ - font_getsetters, /*tp_getset*/ + 0, /* tp_print */ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + font_methods, /*tp_methods*/ + 0, /*tp_members*/ + font_getsetters, /*tp_getset*/ }; static PyMethodDef _functions[] = { - {"getfont", (PyCFunction) getfont, METH_VARARGS|METH_KEYWORDS}, - {NULL, NULL} -}; + {"getfont", (PyCFunction)getfont, METH_VARARGS | METH_KEYWORDS}, {NULL, NULL}}; static int -setup_module(PyObject* m) { - PyObject* d; - PyObject* v; +setup_module(PyObject *m) { + PyObject *d; + PyObject *v; int major, minor, patch; d = PyModule_GetDict(m); @@ -1467,12 +1351,51 @@ setup_module(PyObject* m) { v = PyUnicode_FromFormat("%d.%d.%d", major, minor, patch); PyDict_SetItemString(d, "freetype2_version", v); +#ifdef HAVE_RAQM +#if defined(HAVE_RAQM_SYSTEM) || defined(HAVE_FRIBIDI_SYSTEM) + have_raqm = 1; +#else + load_fribidi(); + have_raqm = !!p_fribidi; +#endif +#else + have_raqm = 0; +#endif - setraqm(); - v = PyBool_FromLong(!!p_raqm.raqm); + /* if we have Raqm, we have all three (but possibly no version info) */ + v = PyBool_FromLong(have_raqm); PyDict_SetItemString(d, "HAVE_RAQM", v); - if (p_raqm.version_string) { - PyDict_SetItemString(d, "raqm_version", PyUnicode_FromString(p_raqm.version_string())); + PyDict_SetItemString(d, "HAVE_FRIBIDI", v); + PyDict_SetItemString(d, "HAVE_HARFBUZZ", v); + if (have_raqm) { +#ifdef RAQM_VERSION_MAJOR + v = PyUnicode_FromString(raqm_version_string()); +#else + v = Py_None; +#endif + PyDict_SetItemString(d, "raqm_version", v); + +#ifdef FRIBIDI_MAJOR_VERSION + { + const char *a = strchr(fribidi_version_info, ')'); + const char *b = strchr(fribidi_version_info, '\n'); + if (a && b && a + 2 < b) { + v = PyUnicode_FromStringAndSize(a + 2, b - (a + 2)); + } else { + v = Py_None; + } + } +#else + v = Py_None; +#endif + PyDict_SetItemString(d, "fribidi_version", v); + +#ifdef HB_VERSION_STRING + v = PyUnicode_FromString(hb_version_string()); +#else + v = Py_None; +#endif + PyDict_SetItemString(d, "harfbuzz_version", v); } return 0; @@ -1480,14 +1403,14 @@ setup_module(PyObject* m) { PyMODINIT_FUNC PyInit__imagingft(void) { - PyObject* m; + PyObject *m; static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, - "_imagingft", /* m_name */ - NULL, /* m_doc */ - -1, /* m_size */ - _functions, /* m_methods */ + "_imagingft", /* m_name */ + NULL, /* m_doc */ + -1, /* m_size */ + _functions, /* m_methods */ }; m = PyModule_Create(&module_def); diff --git a/src/_imagingmath.c b/src/_imagingmath.c index b99356d14..067c165b2 100644 --- a/src/_imagingmath.c +++ b/src/_imagingmath.c @@ -23,50 +23,51 @@ #define MAX_INT32 2147483647.0 #define MIN_INT32 -2147483648.0 -#define UNOP(name, op, type)\ -void name(Imaging out, Imaging im1)\ -{\ - int x, y;\ - for (y = 0; y < out->ysize; y++) {\ - type* p0 = (type*) out->image[y];\ - type* p1 = (type*) im1->image[y];\ - for (x = 0; x < out->xsize; x++) {\ - *p0 = op(type, *p1);\ - p0++; p1++;\ - }\ - }\ -} +#define UNOP(name, op, type) \ + void name(Imaging out, Imaging im1) { \ + int x, y; \ + for (y = 0; y < out->ysize; y++) { \ + type *p0 = (type *)out->image[y]; \ + type *p1 = (type *)im1->image[y]; \ + for (x = 0; x < out->xsize; x++) { \ + *p0 = op(type, *p1); \ + p0++; \ + p1++; \ + } \ + } \ + } -#define BINOP(name, op, type)\ -void name(Imaging out, Imaging im1, Imaging im2)\ -{\ - int x, y;\ - for (y = 0; y < out->ysize; y++) {\ - type* p0 = (type*) out->image[y];\ - type* p1 = (type*) im1->image[y];\ - type* p2 = (type*) im2->image[y];\ - for (x = 0; x < out->xsize; x++) {\ - *p0 = op(type, *p1, *p2);\ - p0++; p1++; p2++;\ - }\ - }\ -} +#define BINOP(name, op, type) \ + void name(Imaging out, Imaging im1, Imaging im2) { \ + int x, y; \ + for (y = 0; y < out->ysize; y++) { \ + type *p0 = (type *)out->image[y]; \ + type *p1 = (type *)im1->image[y]; \ + type *p2 = (type *)im2->image[y]; \ + for (x = 0; x < out->xsize; x++) { \ + *p0 = op(type, *p1, *p2); \ + p0++; \ + p1++; \ + p2++; \ + } \ + } \ + } #define NEG(type, v1) -(v1) #define INVERT(type, v1) ~(v1) -#define ADD(type, v1, v2) (v1)+(v2) -#define SUB(type, v1, v2) (v1)-(v2) -#define MUL(type, v1, v2) (v1)*(v2) +#define ADD(type, v1, v2) (v1) + (v2) +#define SUB(type, v1, v2) (v1) - (v2) +#define MUL(type, v1, v2) (v1) * (v2) -#define MIN(type, v1, v2) ((v1)<(v2))?(v1):(v2) -#define MAX(type, v1, v2) ((v1)>(v2))?(v1):(v2) +#define MIN(type, v1, v2) ((v1) < (v2)) ? (v1) : (v2) +#define MAX(type, v1, v2) ((v1) > (v2)) ? (v1) : (v2) -#define AND(type, v1, v2) (v1)&(v2) -#define OR(type, v1, v2) (v1)|(v2) -#define XOR(type, v1, v2) (v1)^(v2) -#define LSHIFT(type, v1, v2) (v1)<<(v2) -#define RSHIFT(type, v1, v2) (v1)>>(v2) +#define AND(type, v1, v2) (v1) & (v2) +#define OR(type, v1, v2) (v1) | (v2) +#define XOR(type, v1, v2) (v1) ^ (v2) +#define LSHIFT(type, v1, v2) (v1) << (v2) +#define RSHIFT(type, v1, v2) (v1) >> (v2) #define ABS_I(type, v1) abs((v1)) #define ABS_F(type, v1) fabs((v1)) @@ -79,14 +80,14 @@ void name(Imaging out, Imaging im1, Imaging im2)\ * PyFPE_END_PROTECT(result) */ -#define DIV_I(type, v1, v2) ((v2)!=0)?(v1)/(v2):0 -#define DIV_F(type, v1, v2) ((v2)!=0.0F)?(v1)/(v2):0.0F +#define DIV_I(type, v1, v2) ((v2) != 0) ? (v1) / (v2) : 0 +#define DIV_F(type, v1, v2) ((v2) != 0.0F) ? (v1) / (v2) : 0.0F -#define MOD_I(type, v1, v2) ((v2)!=0)?(v1)%(v2):0 -#define MOD_F(type, v1, v2) ((v2)!=0.0F)?fmod((v1),(v2)):0.0F +#define MOD_I(type, v1, v2) ((v2) != 0) ? (v1) % (v2) : 0 +#define MOD_F(type, v1, v2) ((v2) != 0.0F) ? fmod((v1), (v2)) : 0.0F -static int powi(int x, int y) -{ +static int +powi(int x, int y) { double v = pow(x, y) + 0.5; if (errno == EDOM) { return 0; @@ -96,21 +97,21 @@ static int powi(int x, int y) } else if (v > MAX_INT32) { v = MAX_INT32; } - return (int) v; + return (int)v; } #define POW_I(type, v1, v2) powi(v1, v2) #define POW_F(type, v1, v2) powf(v1, v2) /* FIXME: EDOM handling */ -#define DIFF_I(type, v1, v2) abs((v1)-(v2)) -#define DIFF_F(type, v1, v2) fabs((v1)-(v2)) +#define DIFF_I(type, v1, v2) abs((v1) - (v2)) +#define DIFF_F(type, v1, v2) fabs((v1) - (v2)) -#define EQ(type, v1, v2) (v1)==(v2) -#define NE(type, v1, v2) (v1)!=(v2) -#define LT(type, v1, v2) (v1)<(v2) -#define LE(type, v1, v2) (v1)<=(v2) -#define GT(type, v1, v2) (v1)>(v2) -#define GE(type, v1, v2) (v1)>=(v2) +#define EQ(type, v1, v2) (v1) == (v2) +#define NE(type, v1, v2) (v1) != (v2) +#define LT(type, v1, v2) (v1) < (v2) +#define LE(type, v1, v2) (v1) <= (v2) +#define GT(type, v1, v2) (v1) > (v2) +#define GE(type, v1, v2) (v1) >= (v2) UNOP(abs_I, ABS_I, INT32) UNOP(neg_I, NEG, INT32) @@ -162,8 +163,7 @@ BINOP(gt_F, GT, FLOAT32) BINOP(ge_F, GE, FLOAT32) static PyObject * -_unop(PyObject* self, PyObject* args) -{ +_unop(PyObject *self, PyObject *args) { Imaging out; Imaging im1; void (*unop)(Imaging, Imaging); @@ -173,10 +173,10 @@ _unop(PyObject* self, PyObject* args) return NULL; } - out = (Imaging) i0; - im1 = (Imaging) i1; + out = (Imaging)i0; + im1 = (Imaging)i1; - unop = (void*) op; + unop = (void *)op; unop(out, im1); @@ -185,8 +185,7 @@ _unop(PyObject* self, PyObject* args) } static PyObject * -_binop(PyObject* self, PyObject* args) -{ +_binop(PyObject *self, PyObject *args) { Imaging out; Imaging im1; Imaging im2; @@ -197,11 +196,11 @@ _binop(PyObject* self, PyObject* args) return NULL; } - out = (Imaging) i0; - im1 = (Imaging) i1; - im2 = (Imaging) i2; + out = (Imaging)i0; + im1 = (Imaging)i1; + im2 = (Imaging)i2; - binop = (void*) op; + binop = (void *)op; binop(out, im1, im2); @@ -210,15 +209,11 @@ _binop(PyObject* self, PyObject* args) } static PyMethodDef _functions[] = { - {"unop", _unop, 1}, - {"binop", _binop, 1}, - {NULL, NULL} -}; + {"unop", _unop, 1}, {"binop", _binop, 1}, {NULL, NULL}}; static void -install(PyObject *d, char* name, void* value) -{ - PyObject *v = PyLong_FromSsize_t((Py_ssize_t) value); +install(PyObject *d, char *name, void *value) { + PyObject *v = PyLong_FromSsize_t((Py_ssize_t)value); if (!v || PyDict_SetItemString(d, name, v)) { PyErr_Clear(); } @@ -226,8 +221,8 @@ install(PyObject *d, char* name, void* value) } static int -setup_module(PyObject* m) { - PyObject* d = PyModule_GetDict(m); +setup_module(PyObject *m) { + PyObject *d = PyModule_GetDict(m); install(d, "abs_I", abs_I); install(d, "neg_I", neg_I); @@ -279,14 +274,14 @@ setup_module(PyObject* m) { PyMODINIT_FUNC PyInit__imagingmath(void) { - PyObject* m; + PyObject *m; static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, - "_imagingmath", /* m_name */ - NULL, /* m_doc */ - -1, /* m_size */ - _functions, /* m_methods */ + "_imagingmath", /* m_name */ + NULL, /* m_doc */ + -1, /* m_size */ + _functions, /* m_methods */ }; m = PyModule_Create(&module_def); diff --git a/src/_imagingmorph.c b/src/_imagingmorph.c index 0fe54ab77..c0644b616 100644 --- a/src/_imagingmorph.c +++ b/src/_imagingmorph.c @@ -14,7 +14,7 @@ #include "Python.h" #include "libImaging/Imaging.h" -#define LUT_SIZE (1<<9) +#define LUT_SIZE (1 << 9) /* Apply a morphologic LUT to a binary image. Outputs a a new binary image. @@ -27,9 +27,8 @@ Returns number of changed pixels. */ -static PyObject* -apply(PyObject *self, PyObject* args) -{ +static PyObject * +apply(PyObject *self, PyObject *args) { const char *lut; PyObject *py_lut; Py_ssize_t lut_len, i0, i1; @@ -58,18 +57,16 @@ apply(PyObject *self, PyObject* args) lut = PyBytes_AsString(py_lut); - imgin = (Imaging) i0; - imgout = (Imaging) i1; + imgin = (Imaging)i0; + imgout = (Imaging)i1; width = imgin->xsize; height = imgin->ysize; - if (imgin->type != IMAGING_TYPE_UINT8 || - imgin->bands != 1) { + if (imgin->type != IMAGING_TYPE_UINT8 || imgin->bands != 1) { PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); return NULL; } - if (imgout->type != IMAGING_TYPE_UINT8 || - imgout->bands != 1) { + if (imgout->type != IMAGING_TYPE_UINT8 || imgout->bands != 1) { PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); return NULL; } @@ -77,52 +74,46 @@ apply(PyObject *self, PyObject* args) inrows = imgin->image8; outrows = imgout->image8; - for (row_idx=0; row_idx < height; row_idx++) { + for (row_idx = 0; row_idx < height; row_idx++) { UINT8 *outrow = outrows[row_idx]; UINT8 *inrow = inrows[row_idx]; UINT8 *prow, *nrow; /* Previous and next row */ /* zero boundary conditions. TBD support other modes */ - outrow[0] = outrow[width-1] = 0; - if (row_idx==0 || row_idx == height-1) { - for(col_idx=0; col_idxtype != IMAGING_TYPE_UINT8 || - imgin->bands != 1) { + if (imgin->type != IMAGING_TYPE_UINT8 || imgin->bands != 1) { PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); return NULL; } @@ -177,39 +166,33 @@ match(PyObject *self, PyObject* args) width = imgin->xsize; height = imgin->ysize; - for (row_idx=1; row_idx < height-1; row_idx++) { + for (row_idx = 1; row_idx < height - 1; row_idx++) { UINT8 *inrow = inrows[row_idx]; UINT8 *prow, *nrow; - prow = inrows[row_idx-1]; - nrow = inrows[row_idx+1]; + prow = inrows[row_idx - 1]; + nrow = inrows[row_idx + 1]; - for (col_idx=1; col_idximage8; width = img->xsize; height = img->ysize; - for (row_idx=0; row_idx < height; row_idx++) { + for (row_idx = 0; row_idx < height; row_idx++) { UINT8 *row = rows[row_idx]; - for (col_idx=0; col_idxinterp; } @@ -69,10 +68,10 @@ PyMODINIT_FUNC PyInit__imagingtk(void) { static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, - "_imagingtk", /* m_name */ - NULL, /* m_doc */ - -1, /* m_size */ - functions, /* m_methods */ + "_imagingtk", /* m_name */ + NULL, /* m_doc */ + -1, /* m_size */ + functions, /* m_methods */ }; PyObject *m; m = PyModule_Create(&module_def); diff --git a/src/_webp.c b/src/_webp.c index 6c6ca2aa6..6c357dbb0 100644 --- a/src/_webp.c +++ b/src/_webp.c @@ -21,12 +21,14 @@ #endif -void ImagingSectionEnter(ImagingSectionCookie* cookie) { - *cookie = (PyThreadState *) PyEval_SaveThread(); +void +ImagingSectionEnter(ImagingSectionCookie *cookie) { + *cookie = (PyThreadState *)PyEval_SaveThread(); } -void ImagingSectionLeave(ImagingSectionCookie* cookie) { - PyEval_RestoreThread((PyThreadState*) *cookie); +void +ImagingSectionLeave(ImagingSectionCookie *cookie) { + PyEval_RestoreThread((PyThreadState *)*cookie); } /* -------------------------------------------------------------------- */ @@ -35,12 +37,15 @@ void ImagingSectionLeave(ImagingSectionCookie* cookie) { #ifdef HAVE_WEBPMUX -static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { - "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA", - "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" -}; +static const char *const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { + "WEBP_MUX_NOT_FOUND", + "WEBP_MUX_INVALID_ARGUMENT", + "WEBP_MUX_BAD_DATA", + "WEBP_MUX_MEMORY_ERROR", + "WEBP_MUX_NOT_ENOUGH_DATA"}; -PyObject* HandleMuxError(WebPMuxError err, char* chunk) { +PyObject * +HandleMuxError(WebPMuxError err, char *chunk) { char message[100]; int message_len; assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); @@ -52,9 +57,11 @@ PyObject* HandleMuxError(WebPMuxError err, char* chunk) { // Create the error message if (chunk == NULL) { - message_len = sprintf(message, "could not assemble chunks: %s", kErrorMessages[-err]); + message_len = + sprintf(message, "could not assemble chunks: %s", kErrorMessages[-err]); } else { - message_len = sprintf(message, "could not set %.4s chunk: %s", chunk, kErrorMessages[-err]); + message_len = sprintf( + message, "could not set %.4s chunk: %s", chunk, kErrorMessages[-err]); } if (message_len < 0) { PyErr_SetString(PyExc_RuntimeError, "failed to construct error message"); @@ -90,8 +97,7 @@ PyObject* HandleMuxError(WebPMuxError err, char* chunk) { // Encoder type typedef struct { - PyObject_HEAD - WebPAnimEncoder* enc; + PyObject_HEAD WebPAnimEncoder *enc; WebPPicture frame; } WebPAnimEncoderObject; @@ -99,18 +105,17 @@ static PyTypeObject WebPAnimEncoder_Type; // Decoder type typedef struct { - PyObject_HEAD - WebPAnimDecoder* dec; + PyObject_HEAD WebPAnimDecoder *dec; WebPAnimInfo info; WebPData data; - char* mode; + char *mode; } WebPAnimDecoderObject; static PyTypeObject WebPAnimDecoder_Type; // Encoder functions -PyObject* _anim_encoder_new(PyObject* self, PyObject* args) -{ +PyObject * +_anim_encoder_new(PyObject *self, PyObject *args) { int width, height; uint32_t bgcolor; int loop_count; @@ -119,12 +124,21 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) int allow_mixed; int verbose; WebPAnimEncoderOptions enc_options; - WebPAnimEncoderObject* encp = NULL; - WebPAnimEncoder* enc = NULL; + WebPAnimEncoderObject *encp = NULL; + WebPAnimEncoder *enc = NULL; - if (!PyArg_ParseTuple(args, "iiIiiiiii", - &width, &height, &bgcolor, &loop_count, &minimize_size, - &kmin, &kmax, &allow_mixed, &verbose)) { + if (!PyArg_ParseTuple( + args, + "iiIiiiiii", + &width, + &height, + &bgcolor, + &loop_count, + &minimize_size, + &kmin, + &kmax, + &allow_mixed, + &verbose)) { return NULL; } @@ -154,7 +168,7 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) enc = WebPAnimEncoderNew(width, height, &enc_options); if (enc) { encp->enc = enc; - return (PyObject*) encp; + return (PyObject *)encp; } WebPPictureFree(&(encp->frame)); } @@ -164,33 +178,42 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) return NULL; } -PyObject* _anim_encoder_dealloc(PyObject* self) -{ - WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self; +PyObject * +_anim_encoder_dealloc(PyObject *self) { + WebPAnimEncoderObject *encp = (WebPAnimEncoderObject *)self; WebPPictureFree(&(encp->frame)); WebPAnimEncoderDelete(encp->enc); Py_RETURN_NONE; } -PyObject* _anim_encoder_add(PyObject* self, PyObject* args) -{ - uint8_t* rgb; +PyObject * +_anim_encoder_add(PyObject *self, PyObject *args) { + uint8_t *rgb; Py_ssize_t size; int timestamp; int width; int height; - char* mode; + char *mode; int lossless; float quality_factor; int method; WebPConfig config; - WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self; - WebPAnimEncoder* enc = encp->enc; - WebPPicture* frame = &(encp->frame); + WebPAnimEncoderObject *encp = (WebPAnimEncoderObject *)self; + WebPAnimEncoder *enc = encp->enc; + WebPPicture *frame = &(encp->frame); - if (!PyArg_ParseTuple(args, "z#iiisifi", - (char**)&rgb, &size, ×tamp, &width, &height, &mode, - &lossless, &quality_factor, &method)) { + if (!PyArg_ParseTuple( + args, + "z#iiisifi", + (char **)&rgb, + &size, + ×tamp, + &width, + &height, + &mode, + &lossless, + &quality_factor, + &method)) { return NULL; } @@ -218,10 +241,10 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) // Populate the frame with raw bytes passed to us frame->width = width; frame->height = height; - frame->use_argb = 1; // Don't convert RGB pixels to YUV - if (strcmp(mode, "RGBA")==0) { + frame->use_argb = 1; // Don't convert RGB pixels to YUV + if (strcmp(mode, "RGBA") == 0) { WebPPictureImportRGBA(frame, rgb, 4 * width); - } else if (strcmp(mode, "RGBX")==0) { + } else if (strcmp(mode, "RGBX") == 0) { WebPPictureImportRGBX(frame, rgb, 4 * width); } else { WebPPictureImportRGB(frame, rgb, 3 * width); @@ -236,22 +259,29 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) Py_RETURN_NONE; } -PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) -{ - uint8_t* icc_bytes; - uint8_t* exif_bytes; - uint8_t* xmp_bytes; +PyObject * +_anim_encoder_assemble(PyObject *self, PyObject *args) { + uint8_t *icc_bytes; + uint8_t *exif_bytes; + uint8_t *xmp_bytes; Py_ssize_t icc_size; Py_ssize_t exif_size; Py_ssize_t xmp_size; WebPData webp_data; - WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self; - WebPAnimEncoder* enc = encp->enc; - WebPMux* mux = NULL; - PyObject* ret = NULL; + WebPAnimEncoderObject *encp = (WebPAnimEncoderObject *)self; + WebPAnimEncoder *enc = encp->enc; + WebPMux *mux = NULL; + PyObject *ret = NULL; - if (!PyArg_ParseTuple(args, "s#s#s#", - &icc_bytes, &icc_size, &exif_bytes, &exif_size, &xmp_bytes, &xmp_size)) { + if (!PyArg_ParseTuple( + args, + "s#s#s#", + &icc_bytes, + &icc_size, + &exif_bytes, + &exif_size, + &xmp_bytes, + &xmp_size)) { return NULL; } @@ -270,9 +300,9 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) int i_icc_size = (int)icc_size; int i_exif_size = (int)exif_size; int i_xmp_size = (int)xmp_size; - WebPData icc_profile = { icc_bytes, i_icc_size }; - WebPData exif = { exif_bytes, i_exif_size }; - WebPData xmp = { xmp_bytes, i_xmp_size }; + WebPData icc_profile = {icc_bytes, i_icc_size}; + WebPData exif = {exif_bytes, i_exif_size}; + WebPData xmp = {xmp_bytes, i_xmp_size}; mux = WebPMuxCreate(&webp_data, 1); if (mux == NULL) { @@ -312,7 +342,7 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) } // Convert to Python bytes - ret = PyBytes_FromStringAndSize((char*)webp_data.bytes, webp_data.size); + ret = PyBytes_FromStringAndSize((char *)webp_data.bytes, webp_data.size); WebPDataClear(&webp_data); // If we had to re-mux, we should free it now that we're done with it @@ -324,21 +354,21 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) } // Decoder functions -PyObject* _anim_decoder_new(PyObject* self, PyObject* args) -{ +PyObject * +_anim_decoder_new(PyObject *self, PyObject *args) { PyBytesObject *webp_string; const uint8_t *webp; Py_ssize_t size; WebPData webp_src; - char* mode; + char *mode; WebPDecoderConfig config; - WebPAnimDecoderObject* decp = NULL; - WebPAnimDecoder* dec = NULL; + WebPAnimDecoderObject *decp = NULL; + WebPAnimDecoder *dec = NULL; if (!PyArg_ParseTuple(args, "S", &webp_string)) { return NULL; } - PyBytes_AsStringAndSize((PyObject *)webp_string, (char**)&webp, &size); + PyBytes_AsStringAndSize((PyObject *)webp_string, (char **)&webp, &size); webp_src.bytes = webp; webp_src.size = size; @@ -359,7 +389,7 @@ PyObject* _anim_decoder_new(PyObject* self, PyObject* args) if (dec) { if (WebPAnimDecoderGetInfo(dec, &(decp->info))) { decp->dec = dec; - return (PyObject*)decp; + return (PyObject *)decp; } } } @@ -369,33 +399,34 @@ PyObject* _anim_decoder_new(PyObject* self, PyObject* args) return NULL; } -PyObject* _anim_decoder_dealloc(PyObject* self) -{ - WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; +PyObject * +_anim_decoder_dealloc(PyObject *self) { + WebPAnimDecoderObject *decp = (WebPAnimDecoderObject *)self; WebPDataClear(&(decp->data)); WebPAnimDecoderDelete(decp->dec); Py_RETURN_NONE; } -PyObject* _anim_decoder_get_info(PyObject* self) -{ - WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; - WebPAnimInfo* info = &(decp->info); +PyObject * +_anim_decoder_get_info(PyObject *self) { + WebPAnimDecoderObject *decp = (WebPAnimDecoderObject *)self; + WebPAnimInfo *info = &(decp->info); - return Py_BuildValue("IIIIIs", - info->canvas_width, info->canvas_height, + return Py_BuildValue( + "IIIIIs", + info->canvas_width, + info->canvas_height, info->loop_count, info->bgcolor, info->frame_count, - decp->mode - ); + decp->mode); } -PyObject* _anim_decoder_get_chunk(PyObject* self, PyObject* args) -{ - char* mode; - WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; - const WebPDemuxer* demux; +PyObject * +_anim_decoder_get_chunk(PyObject *self, PyObject *args) { + char *mode; + WebPAnimDecoderObject *decp = (WebPAnimDecoderObject *)self; + const WebPDemuxer *demux; WebPChunkIterator iter; PyObject *ret; @@ -408,27 +439,27 @@ PyObject* _anim_decoder_get_chunk(PyObject* self, PyObject* args) Py_RETURN_NONE; } - ret = PyBytes_FromStringAndSize((const char*)iter.chunk.bytes, iter.chunk.size); + ret = PyBytes_FromStringAndSize((const char *)iter.chunk.bytes, iter.chunk.size); WebPDemuxReleaseChunkIterator(&iter); return ret; } -PyObject* _anim_decoder_get_next(PyObject* self) -{ - uint8_t* buf; +PyObject * +_anim_decoder_get_next(PyObject *self) { + uint8_t *buf; int timestamp; - PyObject* bytes; - PyObject* ret; - WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self; + PyObject *bytes; + PyObject *ret; + WebPAnimDecoderObject *decp = (WebPAnimDecoderObject *)self; if (!WebPAnimDecoderGetNext(decp->dec, &buf, ×tamp)) { PyErr_SetString(PyExc_OSError, "failed to read next frame"); return NULL; } - bytes = PyBytes_FromStringAndSize((char *)buf, - decp->info.canvas_width * 4 * decp->info.canvas_height); + bytes = PyBytes_FromStringAndSize( + (char *)buf, decp->info.canvas_width * 4 * decp->info.canvas_height); ret = Py_BuildValue("Si", bytes, timestamp); @@ -436,9 +467,9 @@ PyObject* _anim_decoder_get_next(PyObject* self) return ret; } -PyObject* _anim_decoder_reset(PyObject* self) -{ - WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; +PyObject * +_anim_decoder_reset(PyObject *self) { + WebPAnimDecoderObject *decp = (WebPAnimDecoderObject *)self; WebPAnimDecoderReset(decp->dec); Py_RETURN_NONE; } @@ -456,37 +487,36 @@ static struct PyMethodDef _anim_encoder_methods[] = { // WebPAnimDecoder type definition static PyTypeObject WebPAnimEncoder_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "WebPAnimEncoder", /*tp_name */ - sizeof(WebPAnimEncoderObject), /*tp_size */ - 0, /*tp_itemsize */ + PyVarObject_HEAD_INIT(NULL, 0) "WebPAnimEncoder", /*tp_name */ + sizeof(WebPAnimEncoderObject), /*tp_size */ + 0, /*tp_itemsize */ /* methods */ (destructor)_anim_encoder_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - _anim_encoder_methods, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + _anim_encoder_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ }; // WebPAnimDecoder methods @@ -500,37 +530,36 @@ static struct PyMethodDef _anim_decoder_methods[] = { // WebPAnimDecoder type definition static PyTypeObject WebPAnimDecoder_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "WebPAnimDecoder", /*tp_name */ - sizeof(WebPAnimDecoderObject), /*tp_size */ - 0, /*tp_itemsize */ + PyVarObject_HEAD_INIT(NULL, 0) "WebPAnimDecoder", /*tp_name */ + sizeof(WebPAnimDecoderObject), /*tp_size */ + 0, /*tp_itemsize */ /* methods */ (destructor)_anim_decoder_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - _anim_decoder_methods, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + _anim_decoder_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ }; #endif @@ -539,19 +568,19 @@ static PyTypeObject WebPAnimDecoder_Type = { /* Legacy WebP Support */ /* -------------------------------------------------------------------- */ -PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) -{ +PyObject * +WebPEncode_wrapper(PyObject *self, PyObject *args) { int width; int height; int lossless; float quality_factor; int method; - uint8_t* rgb; - uint8_t* icc_bytes; - uint8_t* exif_bytes; - uint8_t* xmp_bytes; - uint8_t* output; - char* mode; + uint8_t *rgb; + uint8_t *icc_bytes; + uint8_t *exif_bytes; + uint8_t *xmp_bytes; + uint8_t *output; + char *mode; Py_ssize_t size; Py_ssize_t icc_size; Py_ssize_t exif_size; @@ -565,9 +594,23 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) WebPMemoryWriter writer; WebPPicture pic; - if (!PyArg_ParseTuple(args, "y#iiifss#is#s#", - (char**)&rgb, &size, &width, &height, &lossless, &quality_factor, &mode, - &icc_bytes, &icc_size, &method, &exif_bytes, &exif_size, &xmp_bytes, &xmp_size)) { + if (!PyArg_ParseTuple( + args, + "y#iiifss#is#s#", + (char **)&rgb, + &size, + &width, + &height, + &lossless, + &quality_factor, + &mode, + &icc_bytes, + &icc_size, + &method, + &exif_bytes, + &exif_size, + &xmp_bytes, + &xmp_size)) { return NULL; } @@ -602,7 +645,7 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) } pic.width = width; pic.height = height; - pic.use_argb = 1; // Don't convert RGB pixels to YUV + pic.use_argb = 1; // Don't convert RGB pixels to YUV if (rgba_mode) { WebPPictureImportRGBA(&pic, rgb, channels * width); @@ -620,7 +663,7 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) WebPPictureFree(&pic); if (!ok) { - PyErr_SetString(PyExc_ValueError, "encoding error"); + PyErr_Format(PyExc_ValueError, "encoding error %d", (&pic)->error_code); return NULL; } output = writer.mem; @@ -628,98 +671,100 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) #ifndef HAVE_WEBPMUX if (ret_size > 0) { - PyObject *ret = PyBytes_FromStringAndSize((char*)output, ret_size); + PyObject *ret = PyBytes_FromStringAndSize((char *)output, ret_size); free(output); return ret; } #else { - /* I want to truncate the *_size items that get passed into WebP - data. Pypy2.1.0 had some issues where the Py_ssize_t items had - data in the upper byte. (Not sure why, it shouldn't have been there) - */ - int i_icc_size = (int)icc_size; - int i_exif_size = (int)exif_size; - int i_xmp_size = (int)xmp_size; - WebPData output_data = {0}; - WebPData image = { output, ret_size }; - WebPData icc_profile = { icc_bytes, i_icc_size }; - WebPData exif = { exif_bytes, i_exif_size }; - WebPData xmp = { xmp_bytes, i_xmp_size }; - WebPMuxError err; - int dbg = 0; + /* I want to truncate the *_size items that get passed into WebP + data. Pypy2.1.0 had some issues where the Py_ssize_t items had + data in the upper byte. (Not sure why, it shouldn't have been there) + */ + int i_icc_size = (int)icc_size; + int i_exif_size = (int)exif_size; + int i_xmp_size = (int)xmp_size; + WebPData output_data = {0}; + WebPData image = {output, ret_size}; + WebPData icc_profile = {icc_bytes, i_icc_size}; + WebPData exif = {exif_bytes, i_exif_size}; + WebPData xmp = {xmp_bytes, i_xmp_size}; + WebPMuxError err; + int dbg = 0; - int copy_data = 0; // value 1 indicates given data WILL be copied to the mux - // and value 0 indicates data will NOT be copied. + int copy_data = 0; // value 1 indicates given data WILL be copied to the mux + // and value 0 indicates data will NOT be copied. - WebPMux* mux = WebPMuxNew(); - WebPMuxSetImage(mux, &image, copy_data); + WebPMux *mux = WebPMuxNew(); + WebPMuxSetImage(mux, &image, copy_data); - if (dbg) { - /* was getting %ld icc_size == 0, icc_size>0 was true */ - fprintf(stderr, "icc size %d, %d \n", i_icc_size, i_icc_size > 0); - } - - if (i_icc_size > 0) { if (dbg) { - fprintf(stderr, "Adding ICC Profile\n"); + /* was getting %ld icc_size == 0, icc_size>0 was true */ + fprintf(stderr, "icc size %d, %d \n", i_icc_size, i_icc_size > 0); + } + + if (i_icc_size > 0) { + if (dbg) { + fprintf(stderr, "Adding ICC Profile\n"); + } + err = WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); + if (err != WEBP_MUX_OK) { + return HandleMuxError(err, "ICCP"); + } } - err = WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); - if (err != WEBP_MUX_OK) { - return HandleMuxError(err, "ICCP"); - } - } - if (dbg) { - fprintf(stderr, "exif size %d \n", i_exif_size); - } - if (i_exif_size > 0) { if (dbg) { - fprintf(stderr, "Adding Exif Data\n"); + fprintf(stderr, "exif size %d \n", i_exif_size); } - err = WebPMuxSetChunk(mux, "EXIF", &exif, copy_data); - if (err != WEBP_MUX_OK) { - return HandleMuxError(err, "EXIF"); + if (i_exif_size > 0) { + if (dbg) { + fprintf(stderr, "Adding Exif Data\n"); + } + err = WebPMuxSetChunk(mux, "EXIF", &exif, copy_data); + if (err != WEBP_MUX_OK) { + return HandleMuxError(err, "EXIF"); + } } - } - if (dbg) { - fprintf(stderr, "xmp size %d \n", i_xmp_size); - } - if (i_xmp_size > 0) { - if (dbg){ - fprintf(stderr, "Adding XMP Data\n"); + if (dbg) { + fprintf(stderr, "xmp size %d \n", i_xmp_size); } - err = WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data); - if (err != WEBP_MUX_OK) { - return HandleMuxError(err, "XMP "); + if (i_xmp_size > 0) { + if (dbg) { + fprintf(stderr, "Adding XMP Data\n"); + } + err = WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data); + if (err != WEBP_MUX_OK) { + return HandleMuxError(err, "XMP "); + } } - } - WebPMuxAssemble(mux, &output_data); - WebPMuxDelete(mux); - free(output); + WebPMuxAssemble(mux, &output_data); + WebPMuxDelete(mux); + free(output); - ret_size = output_data.size; - if (ret_size > 0) { - PyObject *ret = PyBytes_FromStringAndSize((char*)output_data.bytes, ret_size); - WebPDataClear(&output_data); - return ret; - } + ret_size = output_data.size; + if (ret_size > 0) { + PyObject *ret = + PyBytes_FromStringAndSize((char *)output_data.bytes, ret_size); + WebPDataClear(&output_data); + return ret; + } } #endif Py_RETURN_NONE; } -PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) -{ - PyBytesObject* webp_string; - const uint8_t* webp; +PyObject * +WebPDecode_wrapper(PyObject *self, PyObject *args) { + PyBytesObject *webp_string; + const uint8_t *webp; Py_ssize_t size; - PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL, *icc_profile = NULL, *exif = NULL; + PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL, *icc_profile = NULL, + *exif = NULL; WebPDecoderConfig config; VP8StatusCode vp8_status_code = VP8_STATUS_OK; - char* mode = "RGB"; + char *mode = "RGB"; if (!PyArg_ParseTuple(args, "S", &webp_string)) { return NULL; @@ -729,7 +774,7 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) Py_RETURN_NONE; } - PyBytes_AsStringAndSize((PyObject*) webp_string, (char**)&webp, &size); + PyBytes_AsStringAndSize((PyObject *)webp_string, (char **)&webp, &size); vp8_status_code = WebPGetFeatures(webp, size, &config.input); if (vp8_status_code == VP8_STATUS_OK) { @@ -743,39 +788,40 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) #ifndef HAVE_WEBPMUX vp8_status_code = WebPDecode(webp, size, &config); #else - { - int copy_data = 0; - WebPData data = { webp, size }; - WebPMuxFrameInfo image; - WebPData icc_profile_data = {0}; - WebPData exif_data = {0}; - - WebPMux* mux = WebPMuxCreate(&data, copy_data); - if (NULL == mux) { - goto end; - } - - if (WEBP_MUX_OK != WebPMuxGetFrame(mux, 1, &image)) { + int copy_data = 0; + WebPData data = {webp, size}; + WebPMuxFrameInfo image; + WebPData icc_profile_data = {0}; + WebPData exif_data = {0}; + + WebPMux *mux = WebPMuxCreate(&data, copy_data); + if (NULL == mux) { + goto end; + } + + if (WEBP_MUX_OK != WebPMuxGetFrame(mux, 1, &image)) { + WebPMuxDelete(mux); + goto end; + } + + webp = image.bitstream.bytes; + size = image.bitstream.size; + + vp8_status_code = WebPDecode(webp, size, &config); + + if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "ICCP", &icc_profile_data)) { + icc_profile = PyBytes_FromStringAndSize( + (const char *)icc_profile_data.bytes, icc_profile_data.size); + } + + if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "EXIF", &exif_data)) { + exif = PyBytes_FromStringAndSize( + (const char *)exif_data.bytes, exif_data.size); + } + + WebPDataClear(&image.bitstream); WebPMuxDelete(mux); - goto end; - } - - webp = image.bitstream.bytes; - size = image.bitstream.size; - - vp8_status_code = WebPDecode(webp, size, &config); - - if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "ICCP", &icc_profile_data)) { - icc_profile = PyBytes_FromStringAndSize((const char*)icc_profile_data.bytes, icc_profile_data.size); - } - - if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "EXIF", &exif_data)) { - exif = PyBytes_FromStringAndSize((const char*)exif_data.bytes, exif_data.size); - } - - WebPDataClear(&image.bitstream); - WebPMuxDelete(mux); } #endif } @@ -785,20 +831,24 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) } if (config.output.colorspace < MODE_YUV) { - bytes = PyBytes_FromStringAndSize((char*)config.output.u.RGBA.rgba, - config.output.u.RGBA.size); + bytes = PyBytes_FromStringAndSize( + (char *)config.output.u.RGBA.rgba, config.output.u.RGBA.size); } else { // Skipping YUV for now. Need Test Images. // UNDONE -- unclear if we'll ever get here if we set mode_rgb* - bytes = PyBytes_FromStringAndSize((char*)config.output.u.YUVA.y, - config.output.u.YUVA.y_size); + bytes = PyBytes_FromStringAndSize( + (char *)config.output.u.YUVA.y, config.output.u.YUVA.y_size); } pymode = PyUnicode_FromString(mode); - ret = Py_BuildValue("SiiSSS", bytes, config.output.width, - config.output.height, pymode, - NULL == icc_profile ? Py_None : icc_profile, - NULL == exif ? Py_None : exif); + ret = Py_BuildValue( + "SiiSSS", + bytes, + config.output.width, + config.output.height, + pymode, + NULL == icc_profile ? Py_None : icc_profile, + NULL == exif ? Py_None : exif); end: WebPFreeDecBuffer(&config.output); @@ -817,17 +867,22 @@ end: // Return the decoder's version number, packed in hexadecimal using 8bits for // each of major/minor/revision. E.g: v2.5.7 is 0x020507. -PyObject* WebPDecoderVersion_wrapper() { +PyObject * +WebPDecoderVersion_wrapper() { return Py_BuildValue("i", WebPGetDecoderVersion()); } // Version as string -const char* -WebPDecoderVersion_str(void) -{ +const char * +WebPDecoderVersion_str(void) { static char version[20]; int version_number = WebPGetDecoderVersion(); - sprintf(version, "%d.%d.%d", version_number >> 16, (version_number >> 8) % 0x100, version_number % 0x100); + sprintf( + version, + "%d.%d.%d", + version_number >> 16, + (version_number >> 8) % 0x100, + version_number % 0x100); return version; } @@ -835,11 +890,13 @@ WebPDecoderVersion_str(void) * The version of webp that ships with (0.1.3) Ubuntu 12.04 doesn't handle alpha well. * Files that are valid with 0.3 are reported as being invalid. */ -int WebPDecoderBuggyAlpha(void) { - return WebPGetDecoderVersion()==0x0103; +int +WebPDecoderBuggyAlpha(void) { + return WebPGetDecoderVersion() == 0x0103; } -PyObject* WebPDecoderBuggyAlpha_wrapper() { +PyObject * +WebPDecoderBuggyAlpha_wrapper() { return Py_BuildValue("i", WebPDecoderBuggyAlpha()); } @@ -847,8 +904,7 @@ PyObject* WebPDecoderBuggyAlpha_wrapper() { /* Module Setup */ /* -------------------------------------------------------------------- */ -static PyMethodDef webpMethods[] = -{ +static PyMethodDef webpMethods[] = { #ifdef HAVE_WEBPANIM {"WebPAnimDecoder", _anim_decoder_new, METH_VARARGS, "WebPAnimDecoder"}, {"WebPAnimEncoder", _anim_encoder_new, METH_VARARGS, "WebPAnimEncoder"}, @@ -856,38 +912,51 @@ static PyMethodDef webpMethods[] = {"WebPEncode", WebPEncode_wrapper, METH_VARARGS, "WebPEncode"}, {"WebPDecode", WebPDecode_wrapper, METH_VARARGS, "WebPDecode"}, {"WebPDecoderVersion", WebPDecoderVersion_wrapper, METH_NOARGS, "WebPVersion"}, - {"WebPDecoderBuggyAlpha", WebPDecoderBuggyAlpha_wrapper, METH_NOARGS, "WebPDecoderBuggyAlpha"}, - {NULL, NULL} -}; + {"WebPDecoderBuggyAlpha", + WebPDecoderBuggyAlpha_wrapper, + METH_NOARGS, + "WebPDecoderBuggyAlpha"}, + {NULL, NULL}}; -void addMuxFlagToModule(PyObject* m) { +void +addMuxFlagToModule(PyObject *m) { + PyObject *have_webpmux; #ifdef HAVE_WEBPMUX - PyModule_AddObject(m, "HAVE_WEBPMUX", Py_True); + have_webpmux = Py_True; #else - PyModule_AddObject(m, "HAVE_WEBPMUX", Py_False); + have_webpmux = Py_False; #endif + Py_INCREF(have_webpmux); + PyModule_AddObject(m, "HAVE_WEBPMUX", have_webpmux); } -void addAnimFlagToModule(PyObject* m) { +void +addAnimFlagToModule(PyObject *m) { + PyObject *have_webpanim; #ifdef HAVE_WEBPANIM - PyModule_AddObject(m, "HAVE_WEBPANIM", Py_True); + have_webpanim = Py_True; #else - PyModule_AddObject(m, "HAVE_WEBPANIM", Py_False); + have_webpanim = Py_False; #endif + Py_INCREF(have_webpanim); + PyModule_AddObject(m, "HAVE_WEBPANIM", have_webpanim); } -void addTransparencyFlagToModule(PyObject* m) { - PyModule_AddObject(m, "HAVE_TRANSPARENCY", - PyBool_FromLong(!WebPDecoderBuggyAlpha())); +void +addTransparencyFlagToModule(PyObject *m) { + PyModule_AddObject( + m, "HAVE_TRANSPARENCY", PyBool_FromLong(!WebPDecoderBuggyAlpha())); } -static int setup_module(PyObject* m) { - PyObject* d = PyModule_GetDict(m); +static int +setup_module(PyObject *m) { + PyObject *d = PyModule_GetDict(m); addMuxFlagToModule(m); addAnimFlagToModule(m); addTransparencyFlagToModule(m); - PyDict_SetItemString(d, "webpdecoder_version", PyUnicode_FromString(WebPDecoderVersion_str())); + PyDict_SetItemString( + d, "webpdecoder_version", PyUnicode_FromString(WebPDecoderVersion_str())); #ifdef HAVE_WEBPANIM /* Ready object types */ @@ -901,14 +970,14 @@ static int setup_module(PyObject* m) { PyMODINIT_FUNC PyInit__webp(void) { - PyObject* m; + PyObject *m; static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, - "_webp", /* m_name */ - NULL, /* m_doc */ - -1, /* m_size */ - webpMethods, /* m_methods */ + "_webp", /* m_name */ + NULL, /* m_doc */ + -1, /* m_size */ + webpMethods, /* m_methods */ }; m = PyModule_Create(&module_def); diff --git a/src/decode.c b/src/decode.c index 5c57fea5d..91bfabf34 100644 --- a/src/decode.c +++ b/src/decode.c @@ -34,36 +34,34 @@ #include "libImaging/Imaging.h" +#include "libImaging/Bit.h" +#include "libImaging/Bcn.h" #include "libImaging/Gif.h" #include "libImaging/Raw.h" -#include "libImaging/Bit.h" #include "libImaging/Sgi.h" - /* -------------------------------------------------------------------- */ /* Common */ /* -------------------------------------------------------------------- */ typedef struct { - PyObject_HEAD - int (*decode)(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); + PyObject_HEAD int (*decode)( + Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); int (*cleanup)(ImagingCodecState state); struct ImagingCodecStateInstance state; Imaging im; - PyObject* lock; + PyObject *lock; int pulls_fd; } ImagingDecoderObject; static PyTypeObject ImagingDecoderType; -static ImagingDecoderObject* -PyImaging_DecoderNew(int contextsize) -{ +static ImagingDecoderObject * +PyImaging_DecoderNew(int contextsize) { ImagingDecoderObject *decoder; void *context; - if(PyType_Ready(&ImagingDecoderType) < 0) { + if (PyType_Ready(&ImagingDecoderType) < 0) { return NULL; } @@ -77,10 +75,10 @@ PyImaging_DecoderNew(int contextsize) /* Allocate decoder context */ if (contextsize > 0) { - context = (void*) calloc(1, contextsize); + context = (void *)calloc(1, contextsize); if (!context) { Py_DECREF(decoder); - (void) ImagingError_MemoryError(); + (void)ImagingError_MemoryError(); return NULL; } } else { @@ -105,8 +103,7 @@ PyImaging_DecoderNew(int contextsize) } static void -_dealloc(ImagingDecoderObject* decoder) -{ +_dealloc(ImagingDecoderObject *decoder) { if (decoder->cleanup) { decoder->cleanup(&decoder->state); } @@ -117,10 +114,9 @@ _dealloc(ImagingDecoderObject* decoder) PyObject_Del(decoder); } -static PyObject* -_decode(ImagingDecoderObject* decoder, PyObject* args) -{ - UINT8* buffer; +static PyObject * +_decode(ImagingDecoderObject *decoder, PyObject *args) { + UINT8 *buffer; Py_ssize_t bufsize; int status; ImagingSectionCookie cookie; @@ -142,26 +138,23 @@ _decode(ImagingDecoderObject* decoder, PyObject* args) return Py_BuildValue("ii", status, decoder->state.errcode); } -static PyObject* -_decode_cleanup(ImagingDecoderObject* decoder, PyObject* args) -{ +static PyObject * +_decode_cleanup(ImagingDecoderObject *decoder, PyObject *args) { int status = 0; - if (decoder->cleanup){ + if (decoder->cleanup) { status = decoder->cleanup(&decoder->state); } return Py_BuildValue("i", status); } +extern Imaging +PyImaging_AsImaging(PyObject *op); - -extern Imaging PyImaging_AsImaging(PyObject *op); - -static PyObject* -_setimage(ImagingDecoderObject* decoder, PyObject* args) -{ - PyObject* op; +static PyObject * +_setimage(ImagingDecoderObject *decoder, PyObject *args) { + PyObject *op; Imaging im; ImagingCodecState state; int x0, y0, x1, y1; @@ -192,10 +185,8 @@ _setimage(ImagingDecoderObject* decoder, PyObject* args) state->ysize = y1 - y0; } - if (state->xsize <= 0 || - state->xsize + state->xoff > (int) im->xsize || - state->ysize <= 0 || - state->ysize + state->yoff > (int) im->ysize) { + if (state->xsize <= 0 || state->xsize + state->xoff > (int)im->xsize || + state->ysize <= 0 || state->ysize + state->yoff > (int)im->ysize) { PyErr_SetString(PyExc_ValueError, "tile cannot extend outside image"); return NULL; } @@ -203,13 +194,13 @@ _setimage(ImagingDecoderObject* decoder, PyObject* args) /* Allocate memory buffer (if bits field is set) */ if (state->bits > 0) { if (!state->bytes) { - if (state->xsize > ((INT_MAX / state->bits)-7)){ + if (state->xsize > ((INT_MAX / state->bits) - 7)) { return ImagingError_MemoryError(); } - state->bytes = (state->bits * state->xsize+7)/8; + state->bytes = (state->bits * state->xsize + 7) / 8; } /* malloc check ok, overflow checked above */ - state->buffer = (UINT8*) malloc(state->bytes); + state->buffer = (UINT8 *)calloc(1, state->bytes); if (!state->buffer) { return ImagingError_MemoryError(); } @@ -225,10 +216,9 @@ _setimage(ImagingDecoderObject* decoder, PyObject* args) return Py_None; } -static PyObject* -_setfd(ImagingDecoderObject* decoder, PyObject* args) -{ - PyObject* fd; +static PyObject * +_setfd(ImagingDecoderObject *decoder, PyObject *args) { + PyObject *fd; ImagingCodecState state; if (!PyArg_ParseTuple(args, "O", &fd)) { @@ -244,75 +234,72 @@ _setfd(ImagingDecoderObject* decoder, PyObject* args) return Py_None; } - static PyObject * -_get_pulls_fd(ImagingDecoderObject *decoder) -{ +_get_pulls_fd(ImagingDecoderObject *decoder) { return PyBool_FromLong(decoder->pulls_fd); } static struct PyMethodDef methods[] = { - {"decode", (PyCFunction)_decode, 1}, - {"cleanup", (PyCFunction)_decode_cleanup, 1}, - {"setimage", (PyCFunction)_setimage, 1}, - {"setfd", (PyCFunction)_setfd, 1}, + {"decode", (PyCFunction)_decode, METH_VARARGS}, + {"cleanup", (PyCFunction)_decode_cleanup, METH_VARARGS}, + {"setimage", (PyCFunction)_setimage, METH_VARARGS}, + {"setfd", (PyCFunction)_setfd, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; static struct PyGetSetDef getseters[] = { - {"pulls_fd", (getter)_get_pulls_fd, NULL, + {"pulls_fd", + (getter)_get_pulls_fd, + NULL, "True if this decoder expects to pull from self.fd itself.", NULL}, {NULL, NULL, NULL, NULL, NULL} /* sentinel */ }; static PyTypeObject ImagingDecoderType = { - PyVarObject_HEAD_INIT(NULL, 0) - "ImagingDecoder", /*tp_name*/ - sizeof(ImagingDecoderObject), /*tp_size*/ - 0, /*tp_itemsize*/ + PyVarObject_HEAD_INIT(NULL, 0) "ImagingDecoder", /*tp_name*/ + sizeof(ImagingDecoderObject), /*tp_size*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - methods, /*tp_methods*/ - 0, /*tp_members*/ - getseters, /*tp_getset*/ + (destructor)_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + methods, /*tp_methods*/ + 0, /*tp_members*/ + getseters, /*tp_getset*/ }; /* -------------------------------------------------------------------- */ int -get_unpacker(ImagingDecoderObject* decoder, const char* mode, - const char* rawmode) -{ +get_unpacker(ImagingDecoderObject *decoder, const char *mode, const char *rawmode) { int bits; ImagingShuffler unpack; unpack = ImagingFindUnpacker(mode, rawmode, &bits); if (!unpack) { Py_DECREF(decoder); - PyErr_SetString(PyExc_ValueError, "unknown raw mode"); + PyErr_SetString(PyExc_ValueError, "unknown raw mode for given image mode"); return -1; } @@ -322,24 +309,21 @@ get_unpacker(ImagingDecoderObject* decoder, const char* mode, return 0; } - /* -------------------------------------------------------------------- */ /* BIT (packed fields) */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_BitDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_BitDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - int bits = 8; - int pad = 8; - int fill = 0; - int sign = 0; + char *mode; + int bits = 8; + int pad = 8; + int fill = 0; + int sign = 0; int ystep = 1; - if (!PyArg_ParseTuple(args, "s|iiiii", &mode, &bits, &pad, &fill, - &sign, &ystep)) { + if (!PyArg_ParseTuple(args, "s|iiiii", &mode, &bits, &pad, &fill, &sign, &ystep)) { return NULL; } @@ -357,47 +341,50 @@ PyImaging_BitDecoderNew(PyObject* self, PyObject* args) decoder->state.ystep = ystep; - ((BITSTATE*)decoder->state.context)->bits = bits; - ((BITSTATE*)decoder->state.context)->pad = pad; - ((BITSTATE*)decoder->state.context)->fill = fill; - ((BITSTATE*)decoder->state.context)->sign = sign; + ((BITSTATE *)decoder->state.context)->bits = bits; + ((BITSTATE *)decoder->state.context)->pad = pad; + ((BITSTATE *)decoder->state.context)->fill = fill; + ((BITSTATE *)decoder->state.context)->sign = sign; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* BCn: GPU block-compressed texture formats */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_BcnDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_BcnDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* actual; + char *mode; + char *actual; int n = 0; - int ystep = 1; - if (!PyArg_ParseTuple(args, "s|ii", &mode, &n, &ystep)) { + char *pixel_format = ""; + if (!PyArg_ParseTuple(args, "si|s", &mode, &n, &pixel_format)) { return NULL; } switch (n) { - case 1: /* BC1: 565 color, 1-bit alpha */ - case 2: /* BC2: 565 color, 4-bit alpha */ - case 3: /* BC3: 565 color, 2-endpoint 8-bit interpolated alpha */ - case 5: /* BC5: 2-channel 8-bit via 2 BC3 alpha blocks */ - case 7: /* BC7: 4-channel 8-bit via everything */ - actual = "RGBA"; break; - case 4: /* BC4: 1-channel 8-bit via 1 BC3 alpha block */ - actual = "L"; break; - case 6: /* BC6: 3-channel 16-bit float */ - /* TODO: support 4-channel floating point images */ - actual = "RGBAF"; break; - default: - PyErr_SetString(PyExc_ValueError, "block compression type unknown"); - return NULL; + case 1: /* BC1: 565 color, 1-bit alpha */ + case 2: /* BC2: 565 color, 4-bit alpha */ + case 3: /* BC3: 565 color, 2-endpoint 8-bit interpolated alpha */ + case 7: /* BC7: 4-channel 8-bit via everything */ + actual = "RGBA"; + break; + case 4: /* BC4: 1-channel 8-bit via 1 BC3 alpha block */ + actual = "L"; + break; + case 5: /* BC5: 2-channel 8-bit via 2 BC3 alpha blocks */ + actual = "RGB"; + break; + case 6: /* BC6: 3-channel 16-bit float */ + /* TODO: support 4-channel floating point images */ + actual = "RGBAF"; + break; + default: + PyErr_SetString(PyExc_ValueError, "block compression type unknown"); + return NULL; } if (strcmp(mode, actual) != 0) { @@ -405,27 +392,25 @@ PyImaging_BcnDecoderNew(PyObject* self, PyObject* args) return NULL; } - decoder = PyImaging_DecoderNew(0); + decoder = PyImaging_DecoderNew(sizeof(char *)); if (decoder == NULL) { return NULL; } decoder->decode = ImagingBcnDecode; decoder->state.state = n; - decoder->state.ystep = ystep; + ((BCNSTATE *)decoder->state.context)->pixel_format = pixel_format; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* FLI */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_FliDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_FliDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; decoder = PyImaging_DecoderNew(0); if (decoder == NULL) { @@ -434,23 +419,22 @@ PyImaging_FliDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingFliDecode; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* GIF */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_GifDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_GifDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; + char *mode; int bits = 8; int interlace = 0; - if (!PyArg_ParseTuple(args, "s|ii", &mode, &bits, &interlace)) { + int transparency = -1; + if (!PyArg_ParseTuple(args, "s|iii", &mode, &bits, &interlace, &transparency)) { return NULL; } @@ -466,24 +450,23 @@ PyImaging_GifDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingGifDecode; - ((GIFDECODERSTATE*)decoder->state.context)->bits = bits; - ((GIFDECODERSTATE*)decoder->state.context)->interlace = interlace; + ((GIFDECODERSTATE *)decoder->state.context)->bits = bits; + ((GIFDECODERSTATE *)decoder->state.context)->interlace = interlace; + ((GIFDECODERSTATE *)decoder->state.context)->transparency = transparency; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* HEX */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_HexDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_HexDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; if (!PyArg_ParseTuple(args, "ss", &mode, &rawmode)) { return NULL; } @@ -499,10 +482,9 @@ PyImaging_HexDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingHexDecode; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* LibTiff */ /* -------------------------------------------------------------------- */ @@ -513,17 +495,16 @@ PyImaging_HexDecoderNew(PyObject* self, PyObject* args) #include -PyObject* -PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; - char* mode; - char* rawmode; - char* compname; +PyObject * +PyImaging_LibTiffDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; + char *mode; + char *rawmode; + char *compname; int fp; - uint32 ifdoffset; + uint32_t ifdoffset; - if (! PyArg_ParseTuple(args, "sssiI", &mode, &rawmode, &compname, &fp, &ifdoffset)) { + if (!PyArg_ParseTuple(args, "sssiI", &mode, &rawmode, &compname, &fp, &ifdoffset)) { return NULL; } @@ -538,31 +519,29 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args) return NULL; } - if (! ImagingLibTiffInit(&decoder->state, fp, ifdoffset)) { + if (!ImagingLibTiffInit(&decoder->state, fp, ifdoffset)) { Py_DECREF(decoder); PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed"); return NULL; } - decoder->decode = ImagingLibTiffDecode; + decoder->decode = ImagingLibTiffDecode; - return (PyObject*) decoder; + return (PyObject *)decoder; } #endif - /* -------------------------------------------------------------------- */ /* PackBits */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_PackbitsDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_PackbitsDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; if (!PyArg_ParseTuple(args, "ss", &mode, &rawmode)) { return NULL; } @@ -578,18 +557,16 @@ PyImaging_PackbitsDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingPackbitsDecode; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* PCD */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_PcdDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_PcdDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; decoder = PyImaging_DecoderNew(0); if (decoder == NULL) { @@ -603,21 +580,19 @@ PyImaging_PcdDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingPcdDecode; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* PCX */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_PcxDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_PcxDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; int stride; if (!PyArg_ParseTuple(args, "ssi", &mode, &rawmode, &stride)) { return NULL; @@ -636,23 +611,21 @@ PyImaging_PcxDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingPcxDecode; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* RAW */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_RawDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_RawDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; int stride = 0; - int ystep = 1; + int ystep = 1; if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &stride, &ystep)) { return NULL; } @@ -670,23 +643,21 @@ PyImaging_RawDecoderNew(PyObject* self, PyObject* args) decoder->state.ystep = ystep; - ((RAWSTATE*)decoder->state.context)->stride = stride; + ((RAWSTATE *)decoder->state.context)->stride = stride; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* SGI RLE */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_SgiRleDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_SgiRleDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; int ystep = 1; int bpc = 1; if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &ystep, &bpc)) { @@ -706,23 +677,21 @@ PyImaging_SgiRleDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingSgiRleDecode; decoder->state.ystep = ystep; - ((SGISTATE*)decoder->state.context)->bpc = bpc; + ((SGISTATE *)decoder->state.context)->bpc = bpc; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* SUN RLE */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_SunRleDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_SunRleDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; if (!PyArg_ParseTuple(args, "ss", &mode, &rawmode)) { return NULL; } @@ -738,21 +707,19 @@ PyImaging_SunRleDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingSunRleDecode; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* TGA RLE */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_TgaRleDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_TgaRleDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; int ystep = 1; int depth = 8; if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &ystep, &depth)) { @@ -773,18 +740,16 @@ PyImaging_TgaRleDecoderNew(PyObject* self, PyObject* args) decoder->state.ystep = ystep; decoder->state.count = depth / 8; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* XBM */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_XbmDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_XbmDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; decoder = PyImaging_DecoderNew(0); if (decoder == NULL) { @@ -797,10 +762,9 @@ PyImaging_XbmDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingXbmDecode; - return (PyObject*) decoder; + return (PyObject *)decoder; } - /* -------------------------------------------------------------------- */ /* ZIP */ /* -------------------------------------------------------------------- */ @@ -809,13 +773,12 @@ PyImaging_XbmDecoderNew(PyObject* self, PyObject* args) #include "libImaging/ZipCodecs.h" -PyObject* -PyImaging_ZipDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_ZipDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; int interlaced = 0; if (!PyArg_ParseTuple(args, "ss|i", &mode, &rawmode, &interlaced)) { return NULL; @@ -833,13 +796,12 @@ PyImaging_ZipDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingZipDecode; decoder->cleanup = ImagingZipDecodeCleanup; - ((ZIPSTATE*)decoder->state.context)->interlaced = interlaced; + ((ZIPSTATE *)decoder->state.context)->interlaced = interlaced; - return (PyObject*) decoder; + return (PyObject *)decoder; } #endif - /* -------------------------------------------------------------------- */ /* JPEG */ /* -------------------------------------------------------------------- */ @@ -849,31 +811,29 @@ PyImaging_ZipDecoderNew(PyObject* self, PyObject* args) /* We better define this decoder last in this file, so the following undef's won't mess things up for the Imaging library proper. */ -#undef HAVE_PROTOTYPES -#undef HAVE_STDDEF_H -#undef HAVE_STDLIB_H -#undef UINT8 -#undef UINT16 -#undef UINT32 -#undef INT8 -#undef INT16 -#undef INT32 +#undef HAVE_PROTOTYPES +#undef HAVE_STDDEF_H +#undef HAVE_STDLIB_H +#undef UINT8 +#undef UINT16 +#undef UINT32 +#undef INT8 +#undef INT16 +#undef INT32 #include "libImaging/Jpeg.h" -PyObject* -PyImaging_JpegDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_JpegDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; - char* mode; - char* rawmode; /* what we want from the decoder */ - char* jpegmode; /* what's in the file */ + char *mode; + char *rawmode; /* what we want from the decoder */ + char *jpegmode; /* what's in the file */ int scale = 1; int draft = 0; - if (!PyArg_ParseTuple(args, "ssz|ii", &mode, &rawmode, &jpegmode, - &scale, &draft)) { + if (!PyArg_ParseTuple(args, "ssz|ii", &mode, &rawmode, &jpegmode, &scale, &draft)) { return NULL; } @@ -900,13 +860,13 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args) decoder->decode = ImagingJpegDecode; decoder->cleanup = ImagingJpegDecodeCleanup; - strncpy(((JPEGSTATE*)decoder->state.context)->rawmode, rawmode, 8); - strncpy(((JPEGSTATE*)decoder->state.context)->jpegmode, jpegmode, 8); + strncpy(((JPEGSTATE *)decoder->state.context)->rawmode, rawmode, 8); + strncpy(((JPEGSTATE *)decoder->state.context)->jpegmode, jpegmode, 8); - ((JPEGSTATE*)decoder->state.context)->scale = scale; - ((JPEGSTATE*)decoder->state.context)->draft = draft; + ((JPEGSTATE *)decoder->state.context)->scale = scale; + ((JPEGSTATE *)decoder->state.context)->draft = draft; - return (PyObject*) decoder; + return (PyObject *)decoder; } #endif @@ -918,22 +878,21 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args) #include "libImaging/Jpeg2K.h" -PyObject* -PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args) -{ - ImagingDecoderObject* decoder; +PyObject * +PyImaging_Jpeg2KDecoderNew(PyObject *self, PyObject *args) { + ImagingDecoderObject *decoder; JPEG2KDECODESTATE *context; - char* mode; - char* format; + char *mode; + char *format; OPJ_CODEC_FORMAT codec_format; int reduce = 0; int layers = 0; int fd = -1; PY_LONG_LONG length = -1; - if (!PyArg_ParseTuple(args, "ss|iiiL", &mode, &format, - &reduce, &layers, &fd, &length)) { + if (!PyArg_ParseTuple( + args, "ss|iiiL", &mode, &format, &reduce, &layers, &fd, &length)) { return NULL; } @@ -964,7 +923,6 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args) context->reduce = reduce; context->layers = layers; - return (PyObject*) decoder; + return (PyObject *)decoder; } #endif /* HAVE_OPENJPEG */ - diff --git a/src/display.c b/src/display.c index b8190db8c..0ce10e249 100644 --- a/src/display.c +++ b/src/display.c @@ -41,15 +41,13 @@ #endif typedef struct { - PyObject_HEAD - ImagingDIB dib; + PyObject_HEAD ImagingDIB dib; } ImagingDisplayObject; static PyTypeObject ImagingDisplayType; -static ImagingDisplayObject* -_new(const char* mode, int xsize, int ysize) -{ +static ImagingDisplayObject * +_new(const char *mode, int xsize, int ysize) { ImagingDisplayObject *display; if (PyType_Ready(&ImagingDisplayType) < 0) { @@ -71,17 +69,15 @@ _new(const char* mode, int xsize, int ysize) } static void -_delete(ImagingDisplayObject* display) -{ +_delete(ImagingDisplayObject *display) { if (display->dib) { ImagingDeleteDIB(display->dib); } PyObject_Del(display); } -static PyObject* -_expose(ImagingDisplayObject* display, PyObject* args) -{ +static PyObject * +_expose(ImagingDisplayObject *display, PyObject *args) { HDC hdc; if (!PyArg_ParseTuple(args, F_HANDLE, &hdc)) { return NULL; @@ -93,15 +89,23 @@ _expose(ImagingDisplayObject* display, PyObject* args) return Py_None; } -static PyObject* -_draw(ImagingDisplayObject* display, PyObject* args) -{ +static PyObject * +_draw(ImagingDisplayObject *display, PyObject *args) { HDC hdc; int dst[4]; int src[4]; - if (!PyArg_ParseTuple(args, F_HANDLE "(iiii)(iiii)", &hdc, - dst+0, dst+1, dst+2, dst+3, - src+0, src+1, src+2, src+3)) { + if (!PyArg_ParseTuple( + args, + F_HANDLE "(iiii)(iiii)", + &hdc, + dst + 0, + dst + 1, + dst + 2, + dst + 3, + src + 0, + src + 1, + src + 2, + src + 3)) { return NULL; } @@ -111,17 +115,17 @@ _draw(ImagingDisplayObject* display, PyObject* args) return Py_None; } -extern Imaging PyImaging_AsImaging(PyObject *op); +extern Imaging +PyImaging_AsImaging(PyObject *op); -static PyObject* -_paste(ImagingDisplayObject* display, PyObject* args) -{ +static PyObject * +_paste(ImagingDisplayObject *display, PyObject *args) { Imaging im; - PyObject* op; + PyObject *op; int xy[4]; xy[0] = xy[1] = xy[2] = xy[3] = 0; - if (!PyArg_ParseTuple(args, "O|(iiii)", &op, xy+0, xy+1, xy+2, xy+3)) { + if (!PyArg_ParseTuple(args, "O|(iiii)", &op, xy + 0, xy + 1, xy + 2, xy + 3)) { return NULL; } im = PyImaging_AsImaging(op); @@ -142,9 +146,8 @@ _paste(ImagingDisplayObject* display, PyObject* args) return Py_None; } -static PyObject* -_query_palette(ImagingDisplayObject* display, PyObject* args) -{ +static PyObject * +_query_palette(ImagingDisplayObject *display, PyObject *args) { HDC hdc; int status; @@ -157,9 +160,8 @@ _query_palette(ImagingDisplayObject* display, PyObject* args) return Py_BuildValue("i", status); } -static PyObject* -_getdc(ImagingDisplayObject* display, PyObject* args) -{ +static PyObject * +_getdc(ImagingDisplayObject *display, PyObject *args) { HWND window; HDC dc; @@ -176,9 +178,8 @@ _getdc(ImagingDisplayObject* display, PyObject* args) return Py_BuildValue(F_HANDLE, dc); } -static PyObject* -_releasedc(ImagingDisplayObject* display, PyObject* args) -{ +static PyObject * +_releasedc(ImagingDisplayObject *display, PyObject *args) { HWND window; HDC dc; @@ -192,10 +193,9 @@ _releasedc(ImagingDisplayObject* display, PyObject* args) return Py_None; } -static PyObject* -_frombytes(ImagingDisplayObject* display, PyObject* args) -{ - char* ptr; +static PyObject * +_frombytes(ImagingDisplayObject *display, PyObject *args) { + char *ptr; Py_ssize_t bytes; if (!PyArg_ParseTuple(args, "y#:frombytes", &ptr, &bytes)) { @@ -213,86 +213,77 @@ _frombytes(ImagingDisplayObject* display, PyObject* args) return Py_None; } -static PyObject* -_tobytes(ImagingDisplayObject* display, PyObject* args) -{ +static PyObject * +_tobytes(ImagingDisplayObject *display, PyObject *args) { if (!PyArg_ParseTuple(args, ":tobytes")) { return NULL; } return PyBytes_FromStringAndSize( - display->dib->bits, display->dib->ysize * display->dib->linesize - ); + display->dib->bits, display->dib->ysize * display->dib->linesize); } static struct PyMethodDef methods[] = { - {"draw", (PyCFunction)_draw, 1}, - {"expose", (PyCFunction)_expose, 1}, - {"paste", (PyCFunction)_paste, 1}, - {"query_palette", (PyCFunction)_query_palette, 1}, - {"getdc", (PyCFunction)_getdc, 1}, - {"releasedc", (PyCFunction)_releasedc, 1}, - {"frombytes", (PyCFunction)_frombytes, 1}, - {"tobytes", (PyCFunction)_tobytes, 1}, + {"draw", (PyCFunction)_draw, METH_VARARGS}, + {"expose", (PyCFunction)_expose, METH_VARARGS}, + {"paste", (PyCFunction)_paste, METH_VARARGS}, + {"query_palette", (PyCFunction)_query_palette, METH_VARARGS}, + {"getdc", (PyCFunction)_getdc, METH_VARARGS}, + {"releasedc", (PyCFunction)_releasedc, METH_VARARGS}, + {"frombytes", (PyCFunction)_frombytes, METH_VARARGS}, + {"tobytes", (PyCFunction)_tobytes, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; -static PyObject* -_getattr_mode(ImagingDisplayObject* self, void* closure) -{ +static PyObject * +_getattr_mode(ImagingDisplayObject *self, void *closure) { return Py_BuildValue("s", self->dib->mode); } -static PyObject* -_getattr_size(ImagingDisplayObject* self, void* closure) -{ +static PyObject * +_getattr_size(ImagingDisplayObject *self, void *closure) { return Py_BuildValue("ii", self->dib->xsize, self->dib->ysize); } static struct PyGetSetDef getsetters[] = { - { "mode", (getter) _getattr_mode }, - { "size", (getter) _getattr_size }, - { NULL } -}; + {"mode", (getter)_getattr_mode}, {"size", (getter)_getattr_size}, {NULL}}; static PyTypeObject ImagingDisplayType = { - PyVarObject_HEAD_INIT(NULL, 0) - "ImagingDisplay", /*tp_name*/ - sizeof(ImagingDisplayObject),/*tp_size*/ - 0, /*tp_itemsize*/ + PyVarObject_HEAD_INIT(NULL, 0) "ImagingDisplay", /*tp_name*/ + sizeof(ImagingDisplayObject), /*tp_size*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)_delete, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - methods, /*tp_methods*/ - 0, /*tp_members*/ - getsetters, /*tp_getset*/ + (destructor)_delete, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + methods, /*tp_methods*/ + 0, /*tp_members*/ + getsetters, /*tp_getset*/ }; -PyObject* -PyImaging_DisplayWin32(PyObject* self, PyObject* args) -{ - ImagingDisplayObject* display; +PyObject * +PyImaging_DisplayWin32(PyObject *self, PyObject *args) { + ImagingDisplayObject *display; char *mode; int xsize, ysize; @@ -305,12 +296,11 @@ PyImaging_DisplayWin32(PyObject* self, PyObject* args) return NULL; } - return (PyObject*) display; + return (PyObject *)display; } -PyObject* -PyImaging_DisplayModeWin32(PyObject* self, PyObject* args) -{ +PyObject * +PyImaging_DisplayModeWin32(PyObject *self, PyObject *args) { char *mode; int size[2]; @@ -322,18 +312,17 @@ PyImaging_DisplayModeWin32(PyObject* self, PyObject* args) /* -------------------------------------------------------------------- */ /* Windows screen grabber */ -typedef HANDLE(__stdcall* Func_SetThreadDpiAwarenessContext)(HANDLE); +typedef HANDLE(__stdcall *Func_SetThreadDpiAwarenessContext)(HANDLE); -PyObject* -PyImaging_GrabScreenWin32(PyObject* self, PyObject* args) -{ +PyObject * +PyImaging_GrabScreenWin32(PyObject *self, PyObject *args) { int x = 0, y = 0, width, height; int includeLayeredWindows = 0, all_screens = 0; HBITMAP bitmap; BITMAPCOREHEADER core; HDC screen, screen_copy; DWORD rop; - PyObject* buffer; + PyObject *buffer; HANDLE dpiAwareness; HMODULE user32; Func_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContext_function; @@ -352,11 +341,11 @@ PyImaging_GrabScreenWin32(PyObject* self, PyObject* args) // loaded dynamically to avoid link errors user32 = LoadLibraryA("User32.dll"); SetThreadDpiAwarenessContext_function = - (Func_SetThreadDpiAwarenessContext) - GetProcAddress(user32, "SetThreadDpiAwarenessContext"); + (Func_SetThreadDpiAwarenessContext)GetProcAddress( + user32, "SetThreadDpiAwarenessContext"); if (SetThreadDpiAwarenessContext_function != NULL) { // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ((DPI_CONTEXT_HANDLE)-3) - dpiAwareness = SetThreadDpiAwarenessContext_function((HANDLE) -3); + dpiAwareness = SetThreadDpiAwarenessContext_function((HANDLE)-3); } if (all_screens) { @@ -396,7 +385,7 @@ PyImaging_GrabScreenWin32(PyObject* self, PyObject* args) /* step 3: extract bits from bitmap */ - buffer = PyBytes_FromStringAndSize(NULL, height * ((width*3 + 3) & -4)); + buffer = PyBytes_FromStringAndSize(NULL, height * ((width * 3 + 3) & -4)); if (!buffer) { return NULL; } @@ -406,8 +395,14 @@ PyImaging_GrabScreenWin32(PyObject* self, PyObject* args) core.bcHeight = height; core.bcPlanes = 1; core.bcBitCount = 24; - if (!GetDIBits(screen_copy, bitmap, 0, height, PyBytes_AS_STRING(buffer), - (BITMAPINFO*) &core, DIB_RGB_COLORS)) { + if (!GetDIBits( + screen_copy, + bitmap, + 0, + height, + PyBytes_AS_STRING(buffer), + (BITMAPINFO *)&core, + DIB_RGB_COLORS)) { goto error; } @@ -426,11 +421,11 @@ error: return NULL; } -static BOOL CALLBACK list_windows_callback(HWND hwnd, LPARAM lParam) -{ - PyObject* window_list = (PyObject*) lParam; - PyObject* item; - PyObject* title; +static BOOL CALLBACK +list_windows_callback(HWND hwnd, LPARAM lParam) { + PyObject *window_list = (PyObject *)lParam; + PyObject *item; + PyObject *title; RECT inner, outer; int title_size; int status; @@ -440,7 +435,7 @@ static BOOL CALLBACK list_windows_callback(HWND hwnd, LPARAM lParam) if (title_size > 0) { title = PyUnicode_FromStringAndSize(NULL, title_size); if (title) { - GetWindowTextW(hwnd, PyUnicode_AS_UNICODE(title), title_size+1); + GetWindowTextW(hwnd, PyUnicode_AS_UNICODE(title), title_size + 1); } } else { title = PyUnicode_FromString(""); @@ -454,10 +449,17 @@ static BOOL CALLBACK list_windows_callback(HWND hwnd, LPARAM lParam) GetWindowRect(hwnd, &outer); item = Py_BuildValue( - F_HANDLE "N(iiii)(iiii)", hwnd, title, - inner.left, inner.top, inner.right, inner.bottom, - outer.left, outer.top, outer.right, outer.bottom - ); + F_HANDLE "N(iiii)(iiii)", + hwnd, + title, + inner.left, + inner.top, + inner.right, + inner.bottom, + outer.left, + outer.top, + outer.right, + outer.bottom); if (!item) { return 0; } @@ -473,17 +475,16 @@ static BOOL CALLBACK list_windows_callback(HWND hwnd, LPARAM lParam) return 1; } -PyObject* -PyImaging_ListWindowsWin32(PyObject* self, PyObject* args) -{ - PyObject* window_list; +PyObject * +PyImaging_ListWindowsWin32(PyObject *self, PyObject *args) { + PyObject *window_list; window_list = PyList_New(0); if (!window_list) { return NULL; } - EnumWindows(list_windows_callback, (LPARAM) window_list); + EnumWindows(list_windows_callback, (LPARAM)window_list); if (PyErr_Occurred()) { Py_DECREF(window_list); @@ -496,17 +497,16 @@ PyImaging_ListWindowsWin32(PyObject* self, PyObject* args) /* -------------------------------------------------------------------- */ /* Windows clipboard grabber */ -PyObject* -PyImaging_GrabClipboardWin32(PyObject* self, PyObject* args) -{ +PyObject * +PyImaging_GrabClipboardWin32(PyObject *self, PyObject *args) { int clip; HANDLE handle = NULL; int size; - void* data; - PyObject* result; + void *data; + PyObject *result; UINT format; - UINT formats[] = { CF_DIB, CF_DIBV5, CF_HDROP, RegisterClipboardFormatA("PNG"), 0 }; - LPCSTR format_names[] = { "DIB", "DIB", "file", "png", NULL }; + UINT formats[] = {CF_DIB, CF_DIBV5, CF_HDROP, RegisterClipboardFormatA("PNG"), 0}; + LPCSTR format_names[] = {"DIB", "DIB", "file", "png", NULL}; if (!OpenClipboard(NULL)) { PyErr_SetString(PyExc_OSError, "failed to open clipboard"); @@ -551,15 +551,14 @@ PyImaging_GrabClipboardWin32(PyObject* self, PyObject* args) static int mainloop = 0; static void -callback_error(const char* handler) -{ - PyObject* sys_stderr; +callback_error(const char *handler) { + PyObject *sys_stderr; sys_stderr = PySys_GetObject("stderr"); if (sys_stderr) { PyFile_WriteString("*** ImageWin: error in ", sys_stderr); - PyFile_WriteString((char*) handler, sys_stderr); + PyFile_WriteString((char *)handler, sys_stderr); PyFile_WriteString(":\n", sys_stderr); } @@ -568,109 +567,119 @@ callback_error(const char* handler) } static LRESULT CALLBACK -windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) -{ +windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; - PyObject* callback = NULL; - PyObject* result; - PyThreadState* threadstate; - PyThreadState* current_threadstate; + PyObject *callback = NULL; + PyObject *result; + PyThreadState *threadstate; + PyThreadState *current_threadstate; HDC dc; RECT rect; LRESULT status = 0; /* set up threadstate for messages that calls back into python */ switch (message) { - case WM_CREATE: - mainloop++; - break; - case WM_DESTROY: - mainloop--; - /* fall through... */ - case WM_PAINT: - case WM_SIZE: - callback = (PyObject*) GetWindowLongPtr(wnd, 0); - if (callback) { - threadstate = (PyThreadState*) - GetWindowLongPtr(wnd, sizeof(PyObject*)); - current_threadstate = PyThreadState_Swap(NULL); - PyEval_RestoreThread(threadstate); - } else { - return DefWindowProc(wnd, message, wParam, lParam); - } + case WM_CREATE: + mainloop++; + break; + case WM_DESTROY: + mainloop--; + /* fall through... */ + case WM_PAINT: + case WM_SIZE: + callback = (PyObject *)GetWindowLongPtr(wnd, 0); + if (callback) { + threadstate = + (PyThreadState *)GetWindowLongPtr(wnd, sizeof(PyObject *)); + current_threadstate = PyThreadState_Swap(NULL); + PyEval_RestoreThread(threadstate); + } else { + return DefWindowProc(wnd, message, wParam, lParam); + } } /* process message */ switch (message) { + case WM_PAINT: + /* redraw (part of) window. this generates a WCK-style + damage/clear/repair cascade */ + BeginPaint(wnd, &ps); + dc = GetDC(wnd); + GetWindowRect(wnd, &rect); /* in screen coordinates */ - case WM_PAINT: - /* redraw (part of) window. this generates a WCK-style - damage/clear/repair cascade */ - BeginPaint(wnd, &ps); - dc = GetDC(wnd); - GetWindowRect(wnd, &rect); /* in screen coordinates */ + result = PyObject_CallFunction( + callback, + "siiii", + "damage", + ps.rcPaint.left, + ps.rcPaint.top, + ps.rcPaint.right, + ps.rcPaint.bottom); + if (result) { + Py_DECREF(result); + } else { + callback_error("window damage callback"); + } - result = PyObject_CallFunction( - callback, "siiii", "damage", - ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right, ps.rcPaint.bottom - ); - if (result) { - Py_DECREF(result); - } else { - callback_error("window damage callback"); - } + result = PyObject_CallFunction( + callback, + "s" F_HANDLE "iiii", + "clear", + dc, + 0, + 0, + rect.right - rect.left, + rect.bottom - rect.top); + if (result) { + Py_DECREF(result); + } else { + callback_error("window clear callback"); + } - result = PyObject_CallFunction( - callback, "s" F_HANDLE "iiii", "clear", dc, - 0, 0, rect.right-rect.left, rect.bottom-rect.top - ); - if (result) { - Py_DECREF(result); - } else { - callback_error("window clear callback"); - } + result = PyObject_CallFunction( + callback, + "s" F_HANDLE "iiii", + "repair", + dc, + 0, + 0, + rect.right - rect.left, + rect.bottom - rect.top); + if (result) { + Py_DECREF(result); + } else { + callback_error("window repair callback"); + } - result = PyObject_CallFunction( - callback, "s" F_HANDLE "iiii", "repair", dc, - 0, 0, rect.right-rect.left, rect.bottom-rect.top - ); - if (result) { - Py_DECREF(result); - } else { - callback_error("window repair callback"); - } + ReleaseDC(wnd, dc); + EndPaint(wnd, &ps); + break; - ReleaseDC(wnd, dc); - EndPaint(wnd, &ps); - break; + case WM_SIZE: + /* resize window */ + result = PyObject_CallFunction( + callback, "sii", "resize", LOWORD(lParam), HIWORD(lParam)); + if (result) { + InvalidateRect(wnd, NULL, 1); + Py_DECREF(result); + } else { + callback_error("window resize callback"); + } + break; - case WM_SIZE: - /* resize window */ - result = PyObject_CallFunction( - callback, "sii", "resize", LOWORD(lParam), HIWORD(lParam) - ); - if (result) { - InvalidateRect(wnd, NULL, 1); - Py_DECREF(result); - } else { - callback_error("window resize callback"); - } - break; + case WM_DESTROY: + /* destroy window */ + result = PyObject_CallFunction(callback, "s", "destroy"); + if (result) { + Py_DECREF(result); + } else { + callback_error("window destroy callback"); + } + Py_DECREF(callback); + break; - case WM_DESTROY: - /* destroy window */ - result = PyObject_CallFunction(callback, "s", "destroy"); - if (result) { - Py_DECREF(result); - } else { - callback_error("window destroy callback"); - } - Py_DECREF(callback); - break; - - default: - status = DefWindowProc(wnd, message, wParam, lParam); + default: + status = DefWindowProc(wnd, message, wParam, lParam); } if (callback) { @@ -682,14 +691,13 @@ windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) return status; } -PyObject* -PyImaging_CreateWindowWin32(PyObject* self, PyObject* args) -{ +PyObject * +PyImaging_CreateWindowWin32(PyObject *self, PyObject *args) { HWND wnd; WNDCLASS windowClass; - char* title; - PyObject* callback; + char *title; + PyObject *callback; int width = 0, height = 0; if (!PyArg_ParseTuple(args, "sO|ii", &title, &callback, &width, &height)) { return NULL; @@ -705,7 +713,7 @@ PyImaging_CreateWindowWin32(PyObject* self, PyObject* args) /* register toplevel window class */ windowClass.style = CS_CLASSDC; windowClass.cbClsExtra = 0; - windowClass.cbWndExtra = sizeof(PyObject*) + sizeof(PyThreadState*); + windowClass.cbWndExtra = sizeof(PyObject *) + sizeof(PyThreadState *); windowClass.hInstance = GetModuleHandle(NULL); /* windowClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); */ windowClass.hbrBackground = NULL; @@ -718,11 +726,18 @@ PyImaging_CreateWindowWin32(PyObject* self, PyObject* args) RegisterClass(&windowClass); /* FIXME: check return status */ wnd = CreateWindowEx( - 0, windowClass.lpszClassName, title, + 0, + windowClass.lpszClassName, + title, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, width, height, - HWND_DESKTOP, NULL, NULL, NULL - ); + CW_USEDEFAULT, + CW_USEDEFAULT, + width, + height, + HWND_DESKTOP, + NULL, + NULL, + NULL); if (!wnd) { PyErr_SetString(PyExc_OSError, "failed to create window"); @@ -731,76 +746,76 @@ PyImaging_CreateWindowWin32(PyObject* self, PyObject* args) /* register window callback */ Py_INCREF(callback); - SetWindowLongPtr(wnd, 0, (LONG_PTR) callback); - SetWindowLongPtr(wnd, sizeof(callback), (LONG_PTR) PyThreadState_Get()); + SetWindowLongPtr(wnd, 0, (LONG_PTR)callback); + SetWindowLongPtr(wnd, sizeof(callback), (LONG_PTR)PyThreadState_Get()); - Py_BEGIN_ALLOW_THREADS - ShowWindow(wnd, SW_SHOWNORMAL); + Py_BEGIN_ALLOW_THREADS ShowWindow(wnd, SW_SHOWNORMAL); SetForegroundWindow(wnd); /* to make sure it's visible */ Py_END_ALLOW_THREADS - return Py_BuildValue(F_HANDLE, wnd); + return Py_BuildValue(F_HANDLE, wnd); } -PyObject* -PyImaging_EventLoopWin32(PyObject* self, PyObject* args) -{ +PyObject * +PyImaging_EventLoopWin32(PyObject *self, PyObject *args) { MSG msg; - Py_BEGIN_ALLOW_THREADS - while (mainloop && GetMessage(&msg, NULL, 0, 0)) { + Py_BEGIN_ALLOW_THREADS while (mainloop && GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } Py_END_ALLOW_THREADS - Py_INCREF(Py_None); + Py_INCREF(Py_None); return Py_None; } /* -------------------------------------------------------------------- */ /* windows WMF renderer */ -#define GET32(p,o) ((DWORD*)(p+o))[0] +#define GET32(p, o) ((DWORD *)(p + o))[0] PyObject * -PyImaging_DrawWmf(PyObject* self, PyObject* args) -{ +PyImaging_DrawWmf(PyObject *self, PyObject *args) { HBITMAP bitmap; HENHMETAFILE meta; BITMAPCOREHEADER core; HDC dc; RECT rect; - PyObject* buffer = NULL; - char* ptr; + PyObject *buffer = NULL; + char *ptr; - char* data; + char *data; Py_ssize_t datasize; int width, height; int x0, y0, x1, y1; - if (!PyArg_ParseTuple(args, "y#(ii)(iiii):_load", &data, &datasize, - &width, &height, &x0, &x1, &y0, &y1)) { + if (!PyArg_ParseTuple( + args, + "y#(ii)(iiii):_load", + &data, + &datasize, + &width, + &height, + &x0, + &x1, + &y0, + &y1)) { return NULL; } /* step 1: copy metafile contents into METAFILE object */ if (datasize > 22 && GET32(data, 0) == 0x9ac6cdd7) { - /* placeable windows metafile (22-byte aldus header) */ - meta = SetWinMetaFileBits(datasize-22, data+22, NULL, NULL); - - } else if (datasize > 80 && GET32(data, 0) == 1 && - GET32(data, 40) == 0x464d4520) { + meta = SetWinMetaFileBits(datasize - 22, data + 22, NULL, NULL); + } else if (datasize > 80 && GET32(data, 0) == 1 && GET32(data, 40) == 0x464d4520) { /* enhanced metafile */ meta = SetEnhMetaFileBits(datasize, data); } else { - /* unknown meta format */ meta = NULL; - } if (!meta) { @@ -818,9 +833,7 @@ PyImaging_DrawWmf(PyObject* self, PyObject* args) dc = CreateCompatibleDC(NULL); - bitmap = CreateDIBSection( - dc, (BITMAPINFO*) &core, DIB_RGB_COLORS, &ptr, NULL, 0 - ); + bitmap = CreateDIBSection(dc, (BITMAPINFO *)&core, DIB_RGB_COLORS, &ptr, NULL, 0); if (!bitmap) { PyErr_SetString(PyExc_OSError, "cannot create bitmap"); @@ -850,7 +863,7 @@ PyImaging_DrawWmf(PyObject* self, PyObject* args) GdiFlush(); - buffer = PyBytes_FromStringAndSize(ptr, height * ((width*3 + 3) & -4)); + buffer = PyBytes_FromStringAndSize(ptr, height * ((width * 3 + 3) & -4)); error: DeleteEnhMetaFile(meta); @@ -875,18 +888,17 @@ error: /* -------------------------------------------------------------------- */ /* X11 screen grabber */ -PyObject* -PyImaging_GrabScreenX11(PyObject* self, PyObject* args) -{ +PyObject * +PyImaging_GrabScreenX11(PyObject *self, PyObject *args) { int width, height; - char* display_name; - xcb_connection_t* connection; + char *display_name; + xcb_connection_t *connection; int screen_number; xcb_screen_iterator_t iter; - xcb_screen_t* screen = NULL; - xcb_get_image_reply_t* reply; - xcb_generic_error_t* error; - PyObject* buffer = NULL; + xcb_screen_t *screen = NULL; + xcb_get_image_reply_t *reply; + xcb_generic_error_t *error; + PyObject *buffer = NULL; if (!PyArg_ParseTuple(args, "|z", &display_name)) { return NULL; @@ -896,7 +908,10 @@ PyImaging_GrabScreenX11(PyObject* self, PyObject* args) connection = xcb_connect(display_name, &screen_number); if (xcb_connection_has_error(connection)) { - PyErr_Format(PyExc_OSError, "X connection failed: error %i", xcb_connection_has_error(connection)); + PyErr_Format( + PyExc_OSError, + "X connection failed: error %i", + xcb_connection_has_error(connection)); xcb_disconnect(connection); return NULL; } @@ -920,13 +935,26 @@ PyImaging_GrabScreenX11(PyObject* self, PyObject* args) /* get image data */ - reply = xcb_get_image_reply(connection, - xcb_get_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, screen->root, - 0, 0, width, height, 0x00ffffff), - &error); + reply = xcb_get_image_reply( + connection, + xcb_get_image( + connection, + XCB_IMAGE_FORMAT_Z_PIXMAP, + screen->root, + 0, + 0, + width, + height, + 0x00ffffff), + &error); if (reply == NULL) { - PyErr_Format(PyExc_OSError, "X get_image failed: error %i (%i, %i, %i)", - error->error_code, error->major_code, error->minor_code, error->resource_id); + PyErr_Format( + PyExc_OSError, + "X get_image failed: error %i (%i, %i, %i)", + error->error_code, + error->major_code, + error->minor_code, + error->resource_id); free(error); xcb_disconnect(connection); return NULL; @@ -935,8 +963,8 @@ PyImaging_GrabScreenX11(PyObject* self, PyObject* args) /* store data in Python buffer */ if (reply->depth == 24) { - buffer = PyBytes_FromStringAndSize((char*)xcb_get_image_data(reply), - xcb_get_image_data_length(reply)); + buffer = PyBytes_FromStringAndSize( + (char *)xcb_get_image_data(reply), xcb_get_image_data_length(reply)); } else { PyErr_Format(PyExc_OSError, "unsupported bit depth: %i", reply->depth); } diff --git a/src/encode.c b/src/encode.c index 57ce42734..daa806ff4 100644 --- a/src/encode.c +++ b/src/encode.c @@ -37,25 +37,23 @@ /* -------------------------------------------------------------------- */ typedef struct { - PyObject_HEAD - int (*encode)(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); + PyObject_HEAD int (*encode)( + Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); int (*cleanup)(ImagingCodecState state); struct ImagingCodecStateInstance state; Imaging im; - PyObject* lock; + PyObject *lock; int pushes_fd; } ImagingEncoderObject; static PyTypeObject ImagingEncoderType; -static ImagingEncoderObject* -PyImaging_EncoderNew(int contextsize) -{ +static ImagingEncoderObject * +PyImaging_EncoderNew(int contextsize) { ImagingEncoderObject *encoder; void *context; - if(PyType_Ready(&ImagingEncoderType) < 0) { + if (PyType_Ready(&ImagingEncoderType) < 0) { return NULL; } @@ -69,10 +67,10 @@ PyImaging_EncoderNew(int contextsize) /* Allocate encoder context */ if (contextsize > 0) { - context = (void*) calloc(1, contextsize); + context = (void *)calloc(1, contextsize); if (!context) { Py_DECREF(encoder); - (void) ImagingError_MemoryError(); + (void)ImagingError_MemoryError(); return NULL; } } else { @@ -94,8 +92,7 @@ PyImaging_EncoderNew(int contextsize) } static void -_dealloc(ImagingEncoderObject* encoder) -{ +_dealloc(ImagingEncoderObject *encoder) { if (encoder->cleanup) { encoder->cleanup(&encoder->state); } @@ -106,23 +103,21 @@ _dealloc(ImagingEncoderObject* encoder) PyObject_Del(encoder); } -static PyObject* -_encode_cleanup(ImagingEncoderObject* encoder, PyObject* args) -{ +static PyObject * +_encode_cleanup(ImagingEncoderObject *encoder, PyObject *args) { int status = 0; - if (encoder->cleanup){ + if (encoder->cleanup) { status = encoder->cleanup(&encoder->state); } return Py_BuildValue("i", status); } -static PyObject* -_encode(ImagingEncoderObject* encoder, PyObject* args) -{ - PyObject* buf; - PyObject* result; +static PyObject * +_encode(ImagingEncoderObject *encoder, PyObject *args) { + PyObject *buf; + PyObject *result; int status; /* Encode to a Python string (allocated by this method) */ @@ -138,8 +133,8 @@ _encode(ImagingEncoderObject* encoder, PyObject* args) return NULL; } - status = encoder->encode(encoder->im, &encoder->state, - (UINT8*) PyBytes_AsString(buf), bufsize); + status = encoder->encode( + encoder->im, &encoder->state, (UINT8 *)PyBytes_AsString(buf), bufsize); /* adjust string length to avoid slicing in encoder */ if (_PyBytes_Resize(&buf, (status > 0) ? status : 0) < 0) { @@ -153,31 +148,28 @@ _encode(ImagingEncoderObject* encoder, PyObject* args) return result; } -static PyObject* -_encode_to_pyfd(ImagingEncoderObject* encoder, PyObject* args) -{ - +static PyObject * +_encode_to_pyfd(ImagingEncoderObject *encoder, PyObject *args) { PyObject *result; int status; if (!encoder->pushes_fd) { // UNDONE, appropriate errcode??? - result = Py_BuildValue("ii", 0, IMAGING_CODEC_CONFIG);; + result = Py_BuildValue("ii", 0, IMAGING_CODEC_CONFIG); + ; return result; } - status = encoder->encode(encoder->im, &encoder->state, - (UINT8*) NULL, 0); + status = encoder->encode(encoder->im, &encoder->state, (UINT8 *)NULL, 0); result = Py_BuildValue("ii", status, encoder->state.errcode); return result; } -static PyObject* -_encode_to_file(ImagingEncoderObject* encoder, PyObject* args) -{ - UINT8* buf; +static PyObject * +_encode_to_file(ImagingEncoderObject *encoder, PyObject *args) { + UINT8 *buf; int status; ImagingSectionCookie cookie; @@ -192,7 +184,7 @@ _encode_to_file(ImagingEncoderObject* encoder, PyObject* args) /* Allocate an encoder buffer */ /* malloc check ok, either constant int, or checked by PyArg_ParseTuple */ - buf = (UINT8*) malloc(bufsize); + buf = (UINT8 *)malloc(bufsize); if (!buf) { return ImagingError_MemoryError(); } @@ -200,7 +192,6 @@ _encode_to_file(ImagingEncoderObject* encoder, PyObject* args) ImagingSectionEnter(&cookie); do { - /* This replaces the inner loop in the ImageFile _save function. */ @@ -223,12 +214,12 @@ _encode_to_file(ImagingEncoderObject* encoder, PyObject* args) return Py_BuildValue("i", encoder->state.errcode); } -extern Imaging PyImaging_AsImaging(PyObject *op); +extern Imaging +PyImaging_AsImaging(PyObject *op); -static PyObject* -_setimage(ImagingEncoderObject* encoder, PyObject* args) -{ - PyObject* op; +static PyObject * +_setimage(ImagingEncoderObject *encoder, PyObject *args) { + PyObject *op; Imaging im; ImagingCodecState state; Py_ssize_t x0, y0, x1, y1; @@ -260,22 +251,20 @@ _setimage(ImagingEncoderObject* encoder, PyObject* args) state->ysize = y1 - y0; } - if (state->xsize <= 0 || - state->xsize + state->xoff > im->xsize || - state->ysize <= 0 || - state->ysize + state->yoff > im->ysize) { + if (state->xsize <= 0 || state->xsize + state->xoff > im->xsize || + state->ysize <= 0 || state->ysize + state->yoff > im->ysize) { PyErr_SetString(PyExc_SystemError, "tile cannot extend outside image"); return NULL; } /* Allocate memory buffer (if bits field is set) */ if (state->bits > 0) { - if (state->xsize > ((INT_MAX / state->bits)-7)) { + if (state->xsize > ((INT_MAX / state->bits) - 7)) { return ImagingError_MemoryError(); } - state->bytes = (state->bits * state->xsize+7)/8; + state->bytes = (state->bits * state->xsize + 7) / 8; /* malloc check ok, overflow checked above */ - state->buffer = (UINT8*) malloc(state->bytes); + state->buffer = (UINT8 *)calloc(1, state->bytes); if (!state->buffer) { return ImagingError_MemoryError(); } @@ -291,10 +280,9 @@ _setimage(ImagingEncoderObject* encoder, PyObject* args) return Py_None; } -static PyObject* -_setfd(ImagingEncoderObject* encoder, PyObject* args) -{ - PyObject* fd; +static PyObject * +_setfd(ImagingEncoderObject *encoder, PyObject *args) { + PyObject *fd; ImagingCodecState state; if (!PyArg_ParseTuple(args, "O", &fd)) { @@ -311,68 +299,66 @@ _setfd(ImagingEncoderObject* encoder, PyObject* args) } static PyObject * -_get_pushes_fd(ImagingEncoderObject *encoder) -{ +_get_pushes_fd(ImagingEncoderObject *encoder) { return PyBool_FromLong(encoder->pushes_fd); } static struct PyMethodDef methods[] = { - {"encode", (PyCFunction)_encode, 1}, - {"cleanup", (PyCFunction)_encode_cleanup, 1}, - {"encode_to_file", (PyCFunction)_encode_to_file, 1}, - {"encode_to_pyfd", (PyCFunction)_encode_to_pyfd, 1}, - {"setimage", (PyCFunction)_setimage, 1}, - {"setfd", (PyCFunction)_setfd, 1}, + {"encode", (PyCFunction)_encode, METH_VARARGS}, + {"cleanup", (PyCFunction)_encode_cleanup, METH_VARARGS}, + {"encode_to_file", (PyCFunction)_encode_to_file, METH_VARARGS}, + {"encode_to_pyfd", (PyCFunction)_encode_to_pyfd, METH_VARARGS}, + {"setimage", (PyCFunction)_setimage, METH_VARARGS}, + {"setfd", (PyCFunction)_setfd, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; static struct PyGetSetDef getseters[] = { - {"pushes_fd", (getter)_get_pushes_fd, NULL, + {"pushes_fd", + (getter)_get_pushes_fd, + NULL, "True if this decoder expects to push directly to self.fd", NULL}, {NULL, NULL, NULL, NULL, NULL} /* sentinel */ }; static PyTypeObject ImagingEncoderType = { - PyVarObject_HEAD_INIT(NULL, 0) - "ImagingEncoder", /*tp_name*/ - sizeof(ImagingEncoderObject), /*tp_size*/ - 0, /*tp_itemsize*/ + PyVarObject_HEAD_INIT(NULL, 0) "ImagingEncoder", /*tp_name*/ + sizeof(ImagingEncoderObject), /*tp_size*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - methods, /*tp_methods*/ - 0, /*tp_members*/ - getseters, /*tp_getset*/ + (destructor)_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + methods, /*tp_methods*/ + 0, /*tp_members*/ + getseters, /*tp_getset*/ }; /* -------------------------------------------------------------------- */ int -get_packer(ImagingEncoderObject* encoder, const char* mode, - const char* rawmode) -{ +get_packer(ImagingEncoderObject *encoder, const char *mode, const char *rawmode) { int bits; ImagingShuffler pack; @@ -389,15 +375,13 @@ get_packer(ImagingEncoderObject* encoder, const char* mode, return 0; } - /* -------------------------------------------------------------------- */ /* EPS */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_EpsEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_EpsEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; encoder = PyImaging_EncoderNew(0); if (encoder == NULL) { @@ -406,18 +390,16 @@ PyImaging_EpsEncoderNew(PyObject* self, PyObject* args) encoder->encode = ImagingEpsEncode; - return (PyObject*) encoder; + return (PyObject *)encoder; } - /* -------------------------------------------------------------------- */ /* GIF */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_GifEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_GifEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; char *mode; char *rawmode; @@ -438,21 +420,19 @@ PyImaging_GifEncoderNew(PyObject* self, PyObject* args) encoder->encode = ImagingGifEncode; - ((GIFENCODERSTATE*)encoder->state.context)->bits = bits; - ((GIFENCODERSTATE*)encoder->state.context)->interlace = interlace; + ((GIFENCODERSTATE *)encoder->state.context)->bits = bits; + ((GIFENCODERSTATE *)encoder->state.context)->interlace = interlace; - return (PyObject*) encoder; + return (PyObject *)encoder; } - /* -------------------------------------------------------------------- */ /* PCX */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_PcxEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_PcxEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; char *mode; char *rawmode; @@ -473,18 +453,16 @@ PyImaging_PcxEncoderNew(PyObject* self, PyObject* args) encoder->encode = ImagingPcxEncode; - return (PyObject*) encoder; + return (PyObject *)encoder; } - /* -------------------------------------------------------------------- */ /* RAW */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_RawEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_RawEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; char *mode; char *rawmode; @@ -509,18 +487,16 @@ PyImaging_RawEncoderNew(PyObject* self, PyObject* args) encoder->state.ystep = ystep; encoder->state.count = stride; - return (PyObject*) encoder; + return (PyObject *)encoder; } - /* -------------------------------------------------------------------- */ /* TGA */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_TgaRleEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_TgaRleEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; char *mode; char *rawmode; @@ -543,19 +519,16 @@ PyImaging_TgaRleEncoderNew(PyObject* self, PyObject* args) encoder->state.ystep = ystep; - return (PyObject*) encoder; + return (PyObject *)encoder; } - - /* -------------------------------------------------------------------- */ /* XBM */ /* -------------------------------------------------------------------- */ -PyObject* -PyImaging_XbmEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_XbmEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; encoder = PyImaging_EncoderNew(0); if (encoder == NULL) { @@ -568,10 +541,9 @@ PyImaging_XbmEncoderNew(PyObject* self, PyObject* args) encoder->encode = ImagingXbmEncode; - return (PyObject*) encoder; + return (PyObject *)encoder; } - /* -------------------------------------------------------------------- */ /* ZIP */ /* -------------------------------------------------------------------- */ @@ -580,29 +552,34 @@ PyImaging_XbmEncoderNew(PyObject* self, PyObject* args) #include "libImaging/ZipCodecs.h" -PyObject* -PyImaging_ZipEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_ZipEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; - char* mode; - char* rawmode; + char *mode; + char *rawmode; Py_ssize_t optimize = 0; Py_ssize_t compress_level = -1; Py_ssize_t compress_type = -1; - char* dictionary = NULL; + char *dictionary = NULL; Py_ssize_t dictionary_size = 0; - if (!PyArg_ParseTuple(args, "ss|nnny#", &mode, &rawmode, - &optimize, - &compress_level, &compress_type, - &dictionary, &dictionary_size)) { + if (!PyArg_ParseTuple( + args, + "ss|nnny#", + &mode, + &rawmode, + &optimize, + &compress_level, + &compress_type, + &dictionary, + &dictionary_size)) { return NULL; } /* Copy to avoid referencing Python's memory */ if (dictionary && dictionary_size > 0) { /* malloc check ok, size comes from PyArg_ParseTuple */ - char* p = malloc(dictionary_size); + char *p = malloc(dictionary_size); if (!p) { return ImagingError_MemoryError(); } @@ -628,20 +605,19 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args) if (rawmode[0] == 'P') { /* disable filtering */ - ((ZIPSTATE*)encoder->state.context)->mode = ZIP_PNG_PALETTE; + ((ZIPSTATE *)encoder->state.context)->mode = ZIP_PNG_PALETTE; } - ((ZIPSTATE*)encoder->state.context)->optimize = optimize; - ((ZIPSTATE*)encoder->state.context)->compress_level = compress_level; - ((ZIPSTATE*)encoder->state.context)->compress_type = compress_type; - ((ZIPSTATE*)encoder->state.context)->dictionary = dictionary; - ((ZIPSTATE*)encoder->state.context)->dictionary_size = dictionary_size; + ((ZIPSTATE *)encoder->state.context)->optimize = optimize; + ((ZIPSTATE *)encoder->state.context)->compress_level = compress_level; + ((ZIPSTATE *)encoder->state.context)->compress_type = compress_type; + ((ZIPSTATE *)encoder->state.context)->dictionary = dictionary; + ((ZIPSTATE *)encoder->state.context)->dictionary_size = dictionary_size; - return (PyObject*) encoder; + return (PyObject *)encoder; } #endif - /* -------------------------------------------------------------------- */ /* LibTiff */ /* -------------------------------------------------------------------- */ @@ -652,15 +628,14 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args) #include -PyObject* -PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; - char* mode; - char* rawmode; - char* compname; - char* filename; + char *mode; + char *rawmode; + char *compname; + char *filename; Py_ssize_t fp; PyObject *tags, *types; @@ -669,16 +644,24 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) int key_int, status, is_core_tag, is_var_length, num_core_tags, i; TIFFDataType type = TIFF_NOTYPE; // This list also exists in TiffTags.py - const int core_tags[] = { - 256, 257, 258, 259, 262, 263, 266, 269, 274, 277, 278, 280, 281, 340, - 341, 282, 283, 284, 286, 287, 296, 297, 320, 321, 338, 32995, 32998, 32996, - 339, 32997, 330, 531, 530, 65537 - }; + const int core_tags[] = {256, 257, 258, 259, 262, 263, 266, 269, 274, + 277, 278, 280, 281, 340, 341, 282, 283, 284, + 286, 287, 296, 297, 320, 321, 338, 32995, 32998, + 32996, 339, 32997, 330, 531, 530, 65537, 301, 532}; Py_ssize_t tags_size; PyObject *item; - if (! PyArg_ParseTuple(args, "sssnsOO", &mode, &rawmode, &compname, &fp, &filename, &tags, &types)) { + if (!PyArg_ParseTuple( + args, + "sssnsOO", + &mode, + &rawmode, + &compname, + &fp, + &filename, + &tags, + &types)) { return NULL; } @@ -688,11 +671,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) } else { tags_size = PyList_Size(tags); TRACE(("tags size: %d\n", (int)tags_size)); - for (pos=0;posstate, filename, fp)) { + if (!ImagingLibTiffEncodeInit(&encoder->state, filename, fp)) { Py_DECREF(encoder); PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed"); return NULL; @@ -731,7 +714,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) is_var_length = 0; type = TIFF_NOTYPE; - for (i=0; istate, type, key_int, is_var_length)) { + if (ImagingLibTiffMergeFieldInfo( + &encoder->state, type, key_int, is_var_length)) { continue; } } if (type == TIFF_BYTE || type == TIFF_UNDEFINED) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - PyBytes_Size(value), PyBytes_AsString(value)); + status = ImagingLibTiffSetField( + &encoder->state, + (ttag_t)key_int, + PyBytes_Size(value), + PyBytes_AsString(value)); } else if (is_var_length) { - Py_ssize_t len,i; + Py_ssize_t len, i; TRACE(("Setting from Tuple: %d \n", key_int)); len = PyTuple_Size(value); if (key_int == TIFFTAG_COLORMAP) { int stride = 256; if (len != 768) { - PyErr_SetString(PyExc_ValueError, "Requiring 768 items for for Colormap"); + PyErr_SetString( + PyExc_ValueError, "Requiring 768 items for Colormap"); return NULL; } UINT16 *av; /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(UINT16)); if (av) { - for (i=0;istate, (ttag_t) key_int, - av, - av + stride, - av + stride * 2); + status = ImagingLibTiffSetField( + &encoder->state, + (ttag_t)key_int, + av, + av + stride, + av + stride * 2); free(av); } } else if (type == TIFF_SHORT) { @@ -825,10 +813,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(UINT16)); if (av) { - for (i=0;istate, (ttag_t) key_int, len, av); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, len, av); free(av); } } else if (type == TIFF_LONG) { @@ -836,10 +825,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(UINT32)); if (av) { - for (i=0;istate, (ttag_t) key_int, len, av); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, len, av); free(av); } } else if (type == TIFF_SBYTE) { @@ -847,10 +837,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(INT8)); if (av) { - for (i=0;istate, (ttag_t) key_int, len, av); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, len, av); free(av); } } else if (type == TIFF_SSHORT) { @@ -858,10 +849,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(INT16)); if (av) { - for (i=0;istate, (ttag_t) key_int, len, av); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, len, av); free(av); } } else if (type == TIFF_SLONG) { @@ -869,10 +861,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(INT32)); if (av) { - for (i=0;istate, (ttag_t) key_int, len, av); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, len, av); free(av); } } else if (type == TIFF_FLOAT) { @@ -880,10 +873,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(FLOAT32)); if (av) { - for (i=0;istate, (ttag_t) key_int, len, av); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, len, av); free(av); } } else if (type == TIFF_DOUBLE) { @@ -891,54 +885,47 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(FLOAT64)); if (av) { - for (i=0;istate, (ttag_t) key_int, len, av); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, len, av); free(av); } } } else { if (type == TIFF_SHORT) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - (UINT16)PyLong_AsLong(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, (UINT16)PyLong_AsLong(value)); } else if (type == TIFF_LONG) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - (UINT32)PyLong_AsLong(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, (UINT32)PyLong_AsLong(value)); } else if (type == TIFF_SSHORT) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - (INT16)PyLong_AsLong(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, (INT16)PyLong_AsLong(value)); } else if (type == TIFF_SLONG) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - (INT32)PyLong_AsLong(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, (INT32)PyLong_AsLong(value)); } else if (type == TIFF_FLOAT) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - (FLOAT32)PyFloat_AsDouble(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, (FLOAT32)PyFloat_AsDouble(value)); } else if (type == TIFF_DOUBLE) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - (FLOAT64)PyFloat_AsDouble(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, (FLOAT64)PyFloat_AsDouble(value)); } else if (type == TIFF_SBYTE) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - (INT8)PyLong_AsLong(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, (INT8)PyLong_AsLong(value)); } else if (type == TIFF_ASCII) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - PyBytes_AsString(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, PyBytes_AsString(value)); } else if (type == TIFF_RATIONAL) { - status = ImagingLibTiffSetField(&encoder->state, - (ttag_t) key_int, - (FLOAT64)PyFloat_AsDouble(value)); + status = ImagingLibTiffSetField( + &encoder->state, (ttag_t)key_int, (FLOAT64)PyFloat_AsDouble(value)); } else { - TRACE(("Unhandled type for key %d : %s \n", - key_int, - PyBytes_AsString(PyObject_Str(value)))); + TRACE( + ("Unhandled type for key %d : %s \n", + key_int, + PyBytes_AsString(PyObject_Str(value)))); } } if (!status) { @@ -949,9 +936,9 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) } } - encoder->encode = ImagingLibTiffEncode; + encoder->encode = ImagingLibTiffEncode; - return (PyObject*) encoder; + return (PyObject *)encoder; } #endif @@ -965,26 +952,27 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) /* We better define this encoder last in this file, so the following undef's won't mess things up for the Imaging library proper. */ -#undef HAVE_PROTOTYPES -#undef HAVE_STDDEF_H -#undef HAVE_STDLIB_H -#undef UINT8 -#undef UINT16 -#undef UINT32 -#undef INT8 -#undef INT16 -#undef INT32 +#undef HAVE_PROTOTYPES +#undef HAVE_STDDEF_H +#undef HAVE_STDLIB_H +#undef UINT8 +#undef UINT16 +#undef UINT32 +#undef INT8 +#undef INT16 +#undef INT32 #include "libImaging/Jpeg.h" -static unsigned int* get_qtables_arrays(PyObject* qtables, int* qtablesLen) { - PyObject* tables; - PyObject* table; - PyObject* table_data; +static unsigned int * +get_qtables_arrays(PyObject *qtables, int *qtablesLen) { + PyObject *tables; + PyObject *table; + PyObject *table_data; int i, j, num_tables; unsigned int *qarrays; - if ((qtables == NULL) || (qtables == Py_None)) { + if ((qtables == NULL) || (qtables == Py_None)) { return NULL; } @@ -996,13 +984,14 @@ static unsigned int* get_qtables_arrays(PyObject* qtables, int* qtablesLen) { tables = PySequence_Fast(qtables, "expected a sequence"); num_tables = PySequence_Size(qtables); if (num_tables < 1 || num_tables > NUM_QUANT_TBLS) { - PyErr_SetString(PyExc_ValueError, + PyErr_SetString( + PyExc_ValueError, "Not a valid number of quantization tables. Should be between 1 and 4."); Py_DECREF(tables); return NULL; } /* malloc check ok, num_tables <4, DCTSIZE2 == 64 from jpeglib.h */ - qarrays = (unsigned int*) malloc(num_tables * DCTSIZE2 * sizeof(unsigned int)); + qarrays = (unsigned int *)malloc(num_tables * DCTSIZE2 * sizeof(unsigned int)); if (!qarrays) { Py_DECREF(tables); return ImagingError_MemoryError(); @@ -1019,7 +1008,8 @@ static unsigned int* get_qtables_arrays(PyObject* qtables, int* qtablesLen) { } table_data = PySequence_Fast(table, "expected a sequence"); for (j = 0; j < DCTSIZE2; j++) { - qarrays[i * DCTSIZE2 + j] = PyLong_AS_LONG(PySequence_Fast_GET_ITEM(table_data, j)); + qarrays[i * DCTSIZE2 + j] = + PyLong_AS_LONG(PySequence_Fast_GET_ITEM(table_data, j)); } Py_DECREF(table_data); } @@ -1037,10 +1027,9 @@ JPEG_QTABLES_ERR: return qarrays; } -PyObject* -PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) -{ - ImagingEncoderObject* encoder; +PyObject * +PyImaging_JpegEncoderNew(PyObject *self, PyObject *args) { + ImagingEncoderObject *encoder; char *mode; char *rawmode; @@ -1051,19 +1040,32 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) Py_ssize_t streamtype = 0; /* 0=interchange, 1=tables only, 2=image only */ Py_ssize_t xdpi = 0, ydpi = 0; Py_ssize_t subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */ - PyObject* qtables=NULL; + PyObject *qtables = NULL; unsigned int *qarrays = NULL; int qtablesLen = 0; - char* extra = NULL; + char *extra = NULL; Py_ssize_t extra_size; - char* rawExif = NULL; + char *rawExif = NULL; Py_ssize_t rawExifLen = 0; - if (!PyArg_ParseTuple(args, "ss|nnnnnnnnOy#y#", - &mode, &rawmode, &quality, - &progressive, &smooth, &optimize, &streamtype, - &xdpi, &ydpi, &subsampling, &qtables, &extra, &extra_size, - &rawExif, &rawExifLen)) { + if (!PyArg_ParseTuple( + args, + "ss|nnnnnnnnOy#y#", + &mode, + &rawmode, + &quality, + &progressive, + &smooth, + &optimize, + &streamtype, + &xdpi, + &ydpi, + &subsampling, + &qtables, + &extra, + &extra_size, + &rawExif, + &rawExifLen)) { return NULL; } @@ -1088,7 +1090,7 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) if (extra && extra_size > 0) { /* malloc check ok, length is from python parsearg */ - char* p = malloc(extra_size); // Freed in JpegEncode, Case 5 + char *p = malloc(extra_size); // Freed in JpegEncode, Case 5 if (!p) { return ImagingError_MemoryError(); } @@ -1100,7 +1102,7 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) if (rawExif && rawExifLen > 0) { /* malloc check ok, length is from python parsearg */ - char* pp = malloc(rawExifLen); // Freed in JpegEncode, Case 5 + char *pp = malloc(rawExifLen); // Freed in JpegEncode, Case 5 if (!pp) { if (extra) { free(extra); @@ -1115,29 +1117,28 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) encoder->encode = ImagingJpegEncode; - strncpy(((JPEGENCODERSTATE*)encoder->state.context)->rawmode, rawmode, 8); + strncpy(((JPEGENCODERSTATE *)encoder->state.context)->rawmode, rawmode, 8); - ((JPEGENCODERSTATE*)encoder->state.context)->quality = quality; - ((JPEGENCODERSTATE*)encoder->state.context)->qtables = qarrays; - ((JPEGENCODERSTATE*)encoder->state.context)->qtablesLen = qtablesLen; - ((JPEGENCODERSTATE*)encoder->state.context)->subsampling = subsampling; - ((JPEGENCODERSTATE*)encoder->state.context)->progressive = progressive; - ((JPEGENCODERSTATE*)encoder->state.context)->smooth = smooth; - ((JPEGENCODERSTATE*)encoder->state.context)->optimize = optimize; - ((JPEGENCODERSTATE*)encoder->state.context)->streamtype = streamtype; - ((JPEGENCODERSTATE*)encoder->state.context)->xdpi = xdpi; - ((JPEGENCODERSTATE*)encoder->state.context)->ydpi = ydpi; - ((JPEGENCODERSTATE*)encoder->state.context)->extra = extra; - ((JPEGENCODERSTATE*)encoder->state.context)->extra_size = extra_size; - ((JPEGENCODERSTATE*)encoder->state.context)->rawExif = rawExif; - ((JPEGENCODERSTATE*)encoder->state.context)->rawExifLen = rawExifLen; + ((JPEGENCODERSTATE *)encoder->state.context)->quality = quality; + ((JPEGENCODERSTATE *)encoder->state.context)->qtables = qarrays; + ((JPEGENCODERSTATE *)encoder->state.context)->qtablesLen = qtablesLen; + ((JPEGENCODERSTATE *)encoder->state.context)->subsampling = subsampling; + ((JPEGENCODERSTATE *)encoder->state.context)->progressive = progressive; + ((JPEGENCODERSTATE *)encoder->state.context)->smooth = smooth; + ((JPEGENCODERSTATE *)encoder->state.context)->optimize = optimize; + ((JPEGENCODERSTATE *)encoder->state.context)->streamtype = streamtype; + ((JPEGENCODERSTATE *)encoder->state.context)->xdpi = xdpi; + ((JPEGENCODERSTATE *)encoder->state.context)->ydpi = ydpi; + ((JPEGENCODERSTATE *)encoder->state.context)->extra = extra; + ((JPEGENCODERSTATE *)encoder->state.context)->extra_size = extra_size; + ((JPEGENCODERSTATE *)encoder->state.context)->rawExif = rawExif; + ((JPEGENCODERSTATE *)encoder->state.context)->rawExifLen = rawExifLen; - return (PyObject*) encoder; + return (PyObject *)encoder; } #endif - /* -------------------------------------------------------------------- */ /* JPEG 2000 */ /* -------------------------------------------------------------------- */ @@ -1147,8 +1148,7 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) #include "libImaging/Jpeg2K.h" static void -j2k_decode_coord_tuple(PyObject *tuple, int *x, int *y) -{ +j2k_decode_coord_tuple(PyObject *tuple, int *x, int *y) { *x = *y = 0; if (tuple && PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2) { @@ -1164,9 +1164,8 @@ j2k_decode_coord_tuple(PyObject *tuple, int *x, int *y) } } -PyObject* -PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) -{ +PyObject * +PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) { ImagingEncoderObject *encoder; JPEG2KENCODESTATE *context; @@ -1185,20 +1184,31 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) OPJ_CINEMA_MODE cine_mode; Py_ssize_t fd = -1; - if (!PyArg_ParseTuple(args, "ss|OOOsOnOOOssn", &mode, &format, - &offset, &tile_offset, &tile_size, - &quality_mode, &quality_layers, &num_resolutions, - &cblk_size, &precinct_size, - &irreversible, &progression, &cinema_mode, - &fd)) { + if (!PyArg_ParseTuple( + args, + "ss|OOOsOnOOOssn", + &mode, + &format, + &offset, + &tile_offset, + &tile_size, + &quality_mode, + &quality_layers, + &num_resolutions, + &cblk_size, + &precinct_size, + &irreversible, + &progression, + &cinema_mode, + &fd)) { return NULL; } - if (strcmp (format, "j2k") == 0) { + if (strcmp(format, "j2k") == 0) { codec_format = OPJ_CODEC_J2K; - } else if (strcmp (format, "jpt") == 0) { + } else if (strcmp(format, "jpt") == 0) { codec_format = OPJ_CODEC_JPT; - } else if (strcmp (format, "jp2") == 0) { + } else if (strcmp(format, "jp2") == 0) { codec_format = OPJ_CODEC_JP2; } else { return NULL; @@ -1245,49 +1255,44 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) context->format = codec_format; context->offset_x = context->offset_y = 0; - j2k_decode_coord_tuple(offset, &context->offset_x, &context->offset_y); - j2k_decode_coord_tuple(tile_offset, - &context->tile_offset_x, - &context->tile_offset_y); - j2k_decode_coord_tuple(tile_size, - &context->tile_size_x, - &context->tile_size_y); + j2k_decode_coord_tuple( + tile_offset, &context->tile_offset_x, &context->tile_offset_y); + j2k_decode_coord_tuple(tile_size, &context->tile_size_x, &context->tile_size_y); /* Error on illegal tile offsets */ if (context->tile_size_x && context->tile_size_y) { - if (context->tile_offset_x <= context->offset_x - context->tile_size_x - || context->tile_offset_y <= context->offset_y - context->tile_size_y) { - PyErr_SetString(PyExc_ValueError, - "JPEG 2000 tile offset too small; top left tile must " - "intersect image area"); + if (context->tile_offset_x <= context->offset_x - context->tile_size_x || + context->tile_offset_y <= context->offset_y - context->tile_size_y) { + PyErr_SetString( + PyExc_ValueError, + "JPEG 2000 tile offset too small; top left tile must " + "intersect image area"); Py_DECREF(encoder); return NULL; } - if (context->tile_offset_x > context->offset_x - || context->tile_offset_y > context->offset_y) { - PyErr_SetString(PyExc_ValueError, - "JPEG 2000 tile offset too large to cover image area"); + if (context->tile_offset_x > context->offset_x || + context->tile_offset_y > context->offset_y) { + PyErr_SetString( + PyExc_ValueError, + "JPEG 2000 tile offset too large to cover image area"); Py_DECREF(encoder); return NULL; } } if (quality_layers && PySequence_Check(quality_layers)) { - context->quality_is_in_db = strcmp (quality_mode, "dB") == 0; + context->quality_is_in_db = strcmp(quality_mode, "dB") == 0; context->quality_layers = quality_layers; Py_INCREF(quality_layers); } context->num_resolutions = num_resolutions; - j2k_decode_coord_tuple(cblk_size, - &context->cblk_width, - &context->cblk_height); - j2k_decode_coord_tuple(precinct_size, - &context->precinct_width, - &context->precinct_height); + j2k_decode_coord_tuple(cblk_size, &context->cblk_width, &context->cblk_height); + j2k_decode_coord_tuple( + precinct_size, &context->precinct_width, &context->precinct_height); context->irreversible = PyObject_IsTrue(irreversible); context->progression = prog_order; diff --git a/src/libImaging/Access.c b/src/libImaging/Access.c index 755e2639a..6bb16fe3a 100644 --- a/src/libImaging/Access.c +++ b/src/libImaging/Access.c @@ -9,7 +9,6 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" /* use Tests/make_hash.py to calculate these values */ @@ -19,23 +18,25 @@ static struct ImagingAccessInstance access_table[ACCESS_TABLE_SIZE]; static inline UINT32 -hash(const char* mode) -{ +hash(const char *mode) { UINT32 i = ACCESS_TABLE_HASH; while (*mode) { - i = ((i<<5) + i) ^ (UINT8) *mode++; + i = ((i << 5) + i) ^ (UINT8)*mode++; } return i % ACCESS_TABLE_SIZE; } static ImagingAccess -add_item(const char* mode) -{ +add_item(const char *mode) { UINT32 i = hash(mode); /* printf("hash %s => %d\n", mode, i); */ if (access_table[i].mode && strcmp(access_table[i].mode, mode) != 0) { - fprintf(stderr, "AccessInit: hash collision: %d for both %s and %s\n", - i, mode, access_table[i].mode); + fprintf( + stderr, + "AccessInit: hash collision: %d for both %s and %s\n", + i, + mode, + access_table[i].mode); exit(1); } access_table[i].mode = mode; @@ -44,37 +45,33 @@ add_item(const char* mode) /* fetch pointer to pixel line */ -static void* -line_8(Imaging im, int x, int y) -{ +static void * +line_8(Imaging im, int x, int y) { return &im->image8[y][x]; } -static void* -line_16(Imaging im, int x, int y) -{ - return &im->image8[y][x+x]; +static void * +line_16(Imaging im, int x, int y) { + return &im->image8[y][x + x]; } -static void* -line_32(Imaging im, int x, int y) -{ +static void * +line_32(Imaging im, int x, int y) { return &im->image32[y][x]; } /* fetch individual pixel */ static void -get_pixel(Imaging im, int x, int y, void* color) -{ - char* out = color; +get_pixel(Imaging im, int x, int y, void *color) { + char *out = color; /* generic pixel access*/ if (im->image8) { out[0] = im->image8[y][x]; } else { - UINT8* p = (UINT8*) &im->image32[y][x]; + UINT8 *p = (UINT8 *)&im->image32[y][x]; if (im->type == IMAGING_TYPE_UINT8 && im->bands == 2) { out[0] = p[0]; out[1] = p[3]; @@ -85,18 +82,16 @@ get_pixel(Imaging im, int x, int y, void* color) } static void -get_pixel_8(Imaging im, int x, int y, void* color) -{ - char* out = color; +get_pixel_8(Imaging im, int x, int y, void *color) { + char *out = color; out[0] = im->image8[y][x]; } static void -get_pixel_16L(Imaging im, int x, int y, void* color) -{ - UINT8* in = (UINT8*) &im->image[y][x+x]; +get_pixel_16L(Imaging im, int x, int y, void *color) { + UINT8 *in = (UINT8 *)&im->image[y][x + x]; #ifdef WORDS_BIGENDIAN - UINT16 out = in[0] + (in[1]<<8); + UINT16 out = in[0] + (in[1] << 8); memcpy(color, &out, sizeof(out)); #else memcpy(color, in, sizeof(UINT16)); @@ -104,29 +99,26 @@ get_pixel_16L(Imaging im, int x, int y, void* color) } static void -get_pixel_16B(Imaging im, int x, int y, void* color) -{ - UINT8* in = (UINT8*) &im->image[y][x+x]; +get_pixel_16B(Imaging im, int x, int y, void *color) { + UINT8 *in = (UINT8 *)&im->image[y][x + x]; #ifdef WORDS_BIGENDIAN memcpy(color, in, sizeof(UINT16)); #else - UINT16 out = in[1] + (in[0]<<8); + UINT16 out = in[1] + (in[0] << 8); memcpy(color, &out, sizeof(out)); #endif } static void -get_pixel_32(Imaging im, int x, int y, void* color) -{ +get_pixel_32(Imaging im, int x, int y, void *color) { memcpy(color, &im->image32[y][x], sizeof(INT32)); } static void -get_pixel_32L(Imaging im, int x, int y, void* color) -{ - UINT8* in = (UINT8*) &im->image[y][x*4]; +get_pixel_32L(Imaging im, int x, int y, void *color) { + UINT8 *in = (UINT8 *)&im->image[y][x * 4]; #ifdef WORDS_BIGENDIAN - INT32 out = in[0] + (in[1]<<8) + (in[2]<<16) + (in[3]<<24); + INT32 out = in[0] + (in[1] << 8) + (in[2] << 16) + (in[3] << 24); memcpy(color, &out, sizeof(out)); #else memcpy(color, in, sizeof(INT32)); @@ -134,13 +126,12 @@ get_pixel_32L(Imaging im, int x, int y, void* color) } static void -get_pixel_32B(Imaging im, int x, int y, void* color) -{ - UINT8* in = (UINT8*) &im->image[y][x*4]; +get_pixel_32B(Imaging im, int x, int y, void *color) { + UINT8 *in = (UINT8 *)&im->image[y][x * 4]; #ifdef WORDS_BIGENDIAN memcpy(color, in, sizeof(INT32)); #else - INT32 out = in[3] + (in[2]<<8) + (in[1]<<16) + (in[0]<<24); + INT32 out = in[3] + (in[2] << 8) + (in[1] << 16) + (in[0] << 24); memcpy(color, &out, sizeof(out)); #endif } @@ -148,47 +139,41 @@ get_pixel_32B(Imaging im, int x, int y, void* color) /* store individual pixel */ static void -put_pixel(Imaging im, int x, int y, const void* color) -{ +put_pixel(Imaging im, int x, int y, const void *color) { if (im->image8) { - im->image8[y][x] = *((UINT8*) color); + im->image8[y][x] = *((UINT8 *)color); } else { memcpy(&im->image32[y][x], color, sizeof(INT32)); } } static void -put_pixel_8(Imaging im, int x, int y, const void* color) -{ - im->image8[y][x] = *((UINT8*) color); +put_pixel_8(Imaging im, int x, int y, const void *color) { + im->image8[y][x] = *((UINT8 *)color); } static void -put_pixel_16L(Imaging im, int x, int y, const void* color) -{ - memcpy(&im->image8[y][x+x], color, 2); +put_pixel_16L(Imaging im, int x, int y, const void *color) { + memcpy(&im->image8[y][x + x], color, 2); } static void -put_pixel_16B(Imaging im, int x, int y, const void* color) -{ - const char* in = color; - UINT8* out = (UINT8*) &im->image8[y][x+x]; +put_pixel_16B(Imaging im, int x, int y, const void *color) { + const char *in = color; + UINT8 *out = (UINT8 *)&im->image8[y][x + x]; out[0] = in[1]; out[1] = in[0]; } static void -put_pixel_32L(Imaging im, int x, int y, const void* color) -{ - memcpy(&im->image8[y][x*4], color, 4); +put_pixel_32L(Imaging im, int x, int y, const void *color) { + memcpy(&im->image8[y][x * 4], color, 4); } static void -put_pixel_32B(Imaging im, int x, int y, const void* color) -{ - const char* in = color; - UINT8* out = (UINT8*) &im->image8[y][x*4]; +put_pixel_32B(Imaging im, int x, int y, const void *color) { + const char *in = color; + UINT8 *out = (UINT8 *)&im->image8[y][x * 4]; out[0] = in[3]; out[1] = in[2]; out[2] = in[1]; @@ -196,19 +181,18 @@ put_pixel_32B(Imaging im, int x, int y, const void* color) } static void -put_pixel_32(Imaging im, int x, int y, const void* color) -{ +put_pixel_32(Imaging im, int x, int y, const void *color) { memcpy(&im->image32[y][x], color, sizeof(INT32)); } void -ImagingAccessInit() -{ -#define ADD(mode_, line_, get_pixel_, put_pixel_) \ - { ImagingAccess access = add_item(mode_); \ - access->line = line_; \ - access->get_pixel = get_pixel_; \ - access->put_pixel = put_pixel_; \ +ImagingAccessInit() { +#define ADD(mode_, line_, get_pixel_, put_pixel_) \ + { \ + ImagingAccess access = add_item(mode_); \ + access->line = line_; \ + access->get_pixel = get_pixel_; \ + access->put_pixel = put_pixel_; \ } /* populate access table */ @@ -236,8 +220,7 @@ ImagingAccessInit() } ImagingAccess -ImagingAccessNew(Imaging im) -{ +ImagingAccessNew(Imaging im) { ImagingAccess access = &access_table[hash(im->mode)]; if (im->mode[0] != access->mode[0] || strcmp(im->mode, access->mode) != 0) { return NULL; @@ -246,7 +229,4 @@ ImagingAccessNew(Imaging im) } void -_ImagingAccessDelete(Imaging im, ImagingAccess access) -{ - -} +_ImagingAccessDelete(Imaging im, ImagingAccess access) {} diff --git a/src/libImaging/AlphaComposite.c b/src/libImaging/AlphaComposite.c index 20b1df9e5..6d728f908 100644 --- a/src/libImaging/AlphaComposite.c +++ b/src/libImaging/AlphaComposite.c @@ -8,39 +8,30 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" #define PRECISION_BITS 7 -typedef struct -{ +typedef struct { UINT8 r; UINT8 g; UINT8 b; UINT8 a; } rgba8; - - Imaging -ImagingAlphaComposite(Imaging imDst, Imaging imSrc) -{ +ImagingAlphaComposite(Imaging imDst, Imaging imSrc) { Imaging imOut; int x, y; /* Check arguments */ - if (!imDst || !imSrc || - strcmp(imDst->mode, "RGBA") || - imDst->type != IMAGING_TYPE_UINT8 || - imDst->bands != 4) { + if (!imDst || !imSrc || strcmp(imDst->mode, "RGBA") || + imDst->type != IMAGING_TYPE_UINT8 || imDst->bands != 4) { return ImagingError_ModeError(); } - if (strcmp(imDst->mode, imSrc->mode) || - imDst->type != imSrc->type || - imDst->bands != imSrc->bands || - imDst->xsize != imSrc->xsize || + if (strcmp(imDst->mode, imSrc->mode) || imDst->type != imSrc->type || + imDst->bands != imSrc->bands || imDst->xsize != imSrc->xsize || imDst->ysize != imSrc->ysize) { return ImagingError_Mismatch(); } @@ -51,11 +42,11 @@ ImagingAlphaComposite(Imaging imDst, Imaging imSrc) } for (y = 0; y < imDst->ysize; y++) { - rgba8* dst = (rgba8*) imDst->image[y]; - rgba8* src = (rgba8*) imSrc->image[y]; - rgba8* out = (rgba8*) imOut->image[y]; + rgba8 *dst = (rgba8 *)imDst->image[y]; + rgba8 *src = (rgba8 *)imSrc->image[y]; + rgba8 *out = (rgba8 *)imOut->image[y]; - for (x = 0; x < imDst->xsize; x ++) { + for (x = 0; x < imDst->xsize; x++) { if (src->a == 0) { // Copy 4 bytes at once. *out = *dst; @@ -69,21 +60,25 @@ ImagingAlphaComposite(Imaging imDst, Imaging imSrc) UINT32 outa255 = src->a * 255 + blend; // There we use 7 bits for precision. // We could use more, but we go beyond 32 bits. - UINT32 coef1 = src->a * 255 * 255 * (1<a * 255 * 255 * (1 << PRECISION_BITS) / outa255; + UINT32 coef2 = 255 * (1 << PRECISION_BITS) - coef1; tmpr = src->r * coef1 + dst->r * coef2; tmpg = src->g * coef1 + dst->g * coef2; tmpb = src->b * coef1 + dst->b * coef2; - out->r = SHIFTFORDIV255(tmpr + (0x80<> PRECISION_BITS; - out->g = SHIFTFORDIV255(tmpg + (0x80<> PRECISION_BITS; - out->b = SHIFTFORDIV255(tmpb + (0x80<> PRECISION_BITS; + out->r = + SHIFTFORDIV255(tmpr + (0x80 << PRECISION_BITS)) >> PRECISION_BITS; + out->g = + SHIFTFORDIV255(tmpg + (0x80 << PRECISION_BITS)) >> PRECISION_BITS; + out->b = + SHIFTFORDIV255(tmpb + (0x80 << PRECISION_BITS)) >> PRECISION_BITS; out->a = SHIFTFORDIV255(outa255 + 0x80); } - dst++; src++; out++; + dst++; + src++; + out++; } - } return imOut; diff --git a/src/libImaging/Bands.c b/src/libImaging/Bands.c index 39ce5c49c..e1b16b34a 100644 --- a/src/libImaging/Bands.c +++ b/src/libImaging/Bands.c @@ -15,23 +15,20 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" - Imaging -ImagingGetBand(Imaging imIn, int band) -{ +ImagingGetBand(Imaging imIn, int band) { Imaging imOut; int x, y; /* Check arguments */ if (!imIn || imIn->type != IMAGING_TYPE_UINT8) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (band < 0 || band >= imIn->bands) { - return (Imaging) ImagingError_ValueError("band index out of range"); + return (Imaging)ImagingError_ValueError("band index out of range"); } /* Shortcuts */ @@ -51,8 +48,8 @@ ImagingGetBand(Imaging imIn, int band) /* Extract band from image */ for (y = 0; y < imIn->ysize; y++) { - UINT8* in = (UINT8*) imIn->image[y] + band; - UINT8* out = imOut->image8[y]; + UINT8 *in = (UINT8 *)imIn->image[y] + band; + UINT8 *out = imOut->image8[y]; x = 0; for (; x < imIn->xsize - 3; x += 4) { UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]); @@ -68,15 +65,13 @@ ImagingGetBand(Imaging imIn, int band) return imOut; } - int -ImagingSplit(Imaging imIn, Imaging bands[4]) -{ +ImagingSplit(Imaging imIn, Imaging bands[4]) { int i, j, x, y; /* Check arguments */ if (!imIn || imIn->type != IMAGING_TYPE_UINT8) { - (void) ImagingError_ModeError(); + (void)ImagingError_ModeError(); return 0; } @@ -88,7 +83,7 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) for (i = 0; i < imIn->bands; i++) { bands[i] = ImagingNewDirty("L", imIn->xsize, imIn->ysize); - if ( ! bands[i]) { + if (!bands[i]) { for (j = 0; j < i; ++j) { ImagingDelete(bands[j]); } @@ -99,14 +94,14 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) /* Extract bands from image */ if (imIn->bands == 2) { for (y = 0; y < imIn->ysize; y++) { - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out0 = bands[0]->image8[y]; - UINT8* out1 = bands[1]->image8[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out0 = bands[0]->image8[y]; + UINT8 *out1 = bands[1]->image8[y]; x = 0; for (; x < imIn->xsize - 3; x += 4) { UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]); memcpy(out0 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0+3], in[4+3], in[8+3], in[12+3]); + v = MAKE_UINT32(in[0 + 3], in[4 + 3], in[8 + 3], in[12 + 3]); memcpy(out1 + x, &v, sizeof(v)); in += 16; } @@ -118,17 +113,17 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) } } else if (imIn->bands == 3) { for (y = 0; y < imIn->ysize; y++) { - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out0 = bands[0]->image8[y]; - UINT8* out1 = bands[1]->image8[y]; - UINT8* out2 = bands[2]->image8[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out0 = bands[0]->image8[y]; + UINT8 *out1 = bands[1]->image8[y]; + UINT8 *out2 = bands[2]->image8[y]; x = 0; for (; x < imIn->xsize - 3; x += 4) { UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]); memcpy(out0 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0+1], in[4+1], in[8+1], in[12+1]); + v = MAKE_UINT32(in[0 + 1], in[4 + 1], in[8 + 1], in[12 + 1]); memcpy(out1 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0+2], in[4+2], in[8+2], in[12+2]); + v = MAKE_UINT32(in[0 + 2], in[4 + 2], in[8 + 2], in[12 + 2]); memcpy(out2 + x, &v, sizeof(v)); in += 16; } @@ -141,20 +136,20 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) } } else { for (y = 0; y < imIn->ysize; y++) { - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out0 = bands[0]->image8[y]; - UINT8* out1 = bands[1]->image8[y]; - UINT8* out2 = bands[2]->image8[y]; - UINT8* out3 = bands[3]->image8[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out0 = bands[0]->image8[y]; + UINT8 *out1 = bands[1]->image8[y]; + UINT8 *out2 = bands[2]->image8[y]; + UINT8 *out3 = bands[3]->image8[y]; x = 0; for (; x < imIn->xsize - 3; x += 4) { UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]); memcpy(out0 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0+1], in[4+1], in[8+1], in[12+1]); + v = MAKE_UINT32(in[0 + 1], in[4 + 1], in[8 + 1], in[12 + 1]); memcpy(out1 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0+2], in[4+2], in[8+2], in[12+2]); + v = MAKE_UINT32(in[0 + 2], in[4 + 2], in[8 + 2], in[12 + 2]); memcpy(out2 + x, &v, sizeof(v)); - v = MAKE_UINT32(in[0+3], in[4+3], in[8+3], in[12+3]); + v = MAKE_UINT32(in[0 + 3], in[4 + 3], in[8 + 3], in[12 + 3]); memcpy(out3 + x, &v, sizeof(v)); in += 16; } @@ -171,25 +166,22 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) return imIn->bands; } - Imaging -ImagingPutBand(Imaging imOut, Imaging imIn, int band) -{ +ImagingPutBand(Imaging imOut, Imaging imIn, int band) { int x, y; /* Check arguments */ if (!imIn || imIn->bands != 1 || !imOut) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (band < 0 || band >= imOut->bands) { - return (Imaging) ImagingError_ValueError("band index out of range"); + return (Imaging)ImagingError_ValueError("band index out of range"); } - if (imIn->type != imOut->type || - imIn->xsize != imOut->xsize || + if (imIn->type != imOut->type || imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return (Imaging) ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch(); } /* Shortcuts */ @@ -204,8 +196,8 @@ ImagingPutBand(Imaging imOut, Imaging imIn, int band) /* Insert band into image */ for (y = 0; y < imIn->ysize; y++) { - UINT8* in = imIn->image8[y]; - UINT8* out = (UINT8*) imOut->image[y] + band; + UINT8 *in = imIn->image8[y]; + UINT8 *out = (UINT8 *)imOut->image[y] + band; for (x = 0; x < imIn->xsize; x++) { *out = in[x]; out += 4; @@ -216,17 +208,16 @@ ImagingPutBand(Imaging imOut, Imaging imIn, int band) } Imaging -ImagingFillBand(Imaging imOut, int band, int color) -{ +ImagingFillBand(Imaging imOut, int band, int color) { int x, y; /* Check arguments */ if (!imOut || imOut->type != IMAGING_TYPE_UINT8) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (band < 0 || band >= imOut->bands) { - return (Imaging) ImagingError_ValueError("band index out of range"); + return (Imaging)ImagingError_ValueError("band index out of range"); } /* Special case for LXXA etc */ @@ -238,9 +229,9 @@ ImagingFillBand(Imaging imOut, int band, int color) /* Insert color into image */ for (y = 0; y < imOut->ysize; y++) { - UINT8* out = (UINT8*) imOut->image[y] + band; + UINT8 *out = (UINT8 *)imOut->image[y] + band; for (x = 0; x < imOut->xsize; x++) { - *out = (UINT8) color; + *out = (UINT8)color; out += 4; } } @@ -249,40 +240,39 @@ ImagingFillBand(Imaging imOut, int band, int color) } Imaging -ImagingMerge(const char* mode, Imaging bands[4]) -{ +ImagingMerge(const char *mode, Imaging bands[4]) { int i, x, y; int bandsCount = 0; Imaging imOut; Imaging firstBand; firstBand = bands[0]; - if ( ! firstBand) { - return (Imaging) ImagingError_ValueError("wrong number of bands"); + if (!firstBand) { + return (Imaging)ImagingError_ValueError("wrong number of bands"); } for (i = 0; i < 4; ++i) { - if ( ! bands[i]) { + if (!bands[i]) { break; } if (bands[i]->bands != 1) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } - if (bands[i]->xsize != firstBand->xsize - || bands[i]->ysize != firstBand->ysize) { - return (Imaging) ImagingError_Mismatch(); + if (bands[i]->xsize != firstBand->xsize || + bands[i]->ysize != firstBand->ysize) { + return (Imaging)ImagingError_Mismatch(); } } bandsCount = i; imOut = ImagingNewDirty(mode, firstBand->xsize, firstBand->ysize); - if ( ! imOut) { + if (!imOut) { return NULL; } if (imOut->bands != bandsCount) { ImagingDelete(imOut); - return (Imaging) ImagingError_ValueError("wrong number of bands"); + return (Imaging)ImagingError_ValueError("wrong number of bands"); } if (imOut->bands == 1) { @@ -291,30 +281,30 @@ ImagingMerge(const char* mode, Imaging bands[4]) if (imOut->bands == 2) { for (y = 0; y < imOut->ysize; y++) { - UINT8* in0 = bands[0]->image8[y]; - UINT8* in1 = bands[1]->image8[y]; - UINT32* out = (UINT32*) imOut->image32[y]; + UINT8 *in0 = bands[0]->image8[y]; + UINT8 *in1 = bands[1]->image8[y]; + UINT32 *out = (UINT32 *)imOut->image32[y]; for (x = 0; x < imOut->xsize; x++) { out[x] = MAKE_UINT32(in0[x], 0, 0, in1[x]); } } } else if (imOut->bands == 3) { for (y = 0; y < imOut->ysize; y++) { - UINT8* in0 = bands[0]->image8[y]; - UINT8* in1 = bands[1]->image8[y]; - UINT8* in2 = bands[2]->image8[y]; - UINT32* out = (UINT32*) imOut->image32[y]; + UINT8 *in0 = bands[0]->image8[y]; + UINT8 *in1 = bands[1]->image8[y]; + UINT8 *in2 = bands[2]->image8[y]; + UINT32 *out = (UINT32 *)imOut->image32[y]; for (x = 0; x < imOut->xsize; x++) { out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], 0); } } } else if (imOut->bands == 4) { for (y = 0; y < imOut->ysize; y++) { - UINT8* in0 = bands[0]->image8[y]; - UINT8* in1 = bands[1]->image8[y]; - UINT8* in2 = bands[2]->image8[y]; - UINT8* in3 = bands[3]->image8[y]; - UINT32* out = (UINT32*) imOut->image32[y]; + UINT8 *in0 = bands[0]->image8[y]; + UINT8 *in1 = bands[1]->image8[y]; + UINT8 *in2 = bands[2]->image8[y]; + UINT8 *in3 = bands[3]->image8[y]; + UINT32 *out = (UINT32 *)imOut->image32[y]; for (x = 0; x < imOut->xsize; x++) { out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], in3[x]); } diff --git a/src/libImaging/Bcn.h b/src/libImaging/Bcn.h new file mode 100644 index 000000000..1a6fbee45 --- /dev/null +++ b/src/libImaging/Bcn.h @@ -0,0 +1,3 @@ +typedef struct { + char *pixel_format; +} BCNSTATE; diff --git a/src/libImaging/BcnDecode.c b/src/libImaging/BcnDecode.c index f908a03ad..22b36eb7a 100644 --- a/src/libImaging/BcnDecode.c +++ b/src/libImaging/BcnDecode.c @@ -11,9 +11,9 @@ * https://creativecommons.org/publicdomain/zero/1.0/ */ - #include "Imaging.h" +#include "Bcn.h" typedef struct { UINT8 r, g, b, a; @@ -37,23 +37,24 @@ typedef struct { UINT8 lut[6]; } bc3_alpha; -#define LOAD16(p) \ - (p)[0] | ((p)[1] << 8) +typedef struct { + INT8 a0, a1; + UINT8 lut[6]; +} bc5s_alpha; -#define LOAD32(p) \ - (p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24) +#define LOAD16(p) (p)[0] | ((p)[1] << 8) -static void bc1_color_load(bc1_color *dst, const UINT8 *src) { +#define LOAD32(p) (p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24) + +static void +bc1_color_load(bc1_color *dst, const UINT8 *src) { dst->c0 = LOAD16(src); dst->c1 = LOAD16(src + 2); dst->lut = LOAD32(src + 4); } -static void bc3_alpha_load(bc3_alpha *dst, const UINT8 *src) { - memcpy(dst, src, sizeof(bc3_alpha)); -} - -static rgba decode_565(UINT16 x) { +static rgba +decode_565(UINT16 x) { rgba c; int r, g, b; r = (x & 0xf800) >> 8; @@ -69,7 +70,8 @@ static rgba decode_565(UINT16 x) { return c; } -static void decode_bc1_color(rgba *dst, const UINT8 *src) { +static void +decode_bc1_color(rgba *dst, const UINT8 *src, int separate_alpha) { bc1_color col; rgba p[4]; int n, cw; @@ -84,14 +86,17 @@ static void decode_bc1_color(rgba *dst, const UINT8 *src) { r1 = p[1].r; g1 = p[1].g; b1 = p[1].b; - if (col.c0 > col.c1) { - p[2].r = (2*r0 + 1*r1) / 3; - p[2].g = (2*g0 + 1*g1) / 3; - p[2].b = (2*b0 + 1*b1) / 3; + + + /* NOTE: BC2 and BC3 reuse BC1 color blocks but always act like c0 > c1 */ + if (col.c0 > col.c1 || separate_alpha) { + p[2].r = (2 * r0 + 1 * r1) / 3; + p[2].g = (2 * g0 + 1 * g1) / 3; + p[2].b = (2 * b0 + 1 * b1) / 3; p[2].a = 0xff; - p[3].r = (1*r0 + 2*r1) / 3; - p[3].g = (1*g0 + 2*g1) / 3; - p[3].b = (1*b0 + 2*b1) / 3; + p[3].r = (1 * r0 + 2 * r1) / 3; + p[3].g = (1 * g0 + 2 * g1) / 3; + p[3].b = (1 * b0 + 2 * b1) / 3; p[3].a = 0xff; } else { p[2].r = (r0 + r1) / 2; @@ -109,51 +114,63 @@ static void decode_bc1_color(rgba *dst, const UINT8 *src) { } } -static void decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o) { - bc3_alpha b; +static void +decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o, int sign) { UINT16 a0, a1; UINT8 a[8]; - int n, lut, aw; - bc3_alpha_load(&b, src); + int n, lut1, lut2, aw; + if (sign == 1) { + bc5s_alpha b; + memcpy(&b, src, sizeof(bc5s_alpha)); + a0 = (b.a0 + 255) / 2; + a1 = (b.a1 + 255) / 2; + lut1 = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16); + lut2 = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16); + } else { + bc3_alpha b; + memcpy(&b, src, sizeof(bc3_alpha)); + a0 = b.a0; + a1 = b.a1; + lut1 = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16); + lut2 = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16); + } - a0 = b.a0; - a1 = b.a1; a[0] = (UINT8)a0; a[1] = (UINT8)a1; if (a0 > a1) { - a[2] = (6*a0 + 1*a1) / 7; - a[3] = (5*a0 + 2*a1) / 7; - a[4] = (4*a0 + 3*a1) / 7; - a[5] = (3*a0 + 4*a1) / 7; - a[6] = (2*a0 + 5*a1) / 7; - a[7] = (1*a0 + 6*a1) / 7; + a[2] = (6 * a0 + 1 * a1) / 7; + a[3] = (5 * a0 + 2 * a1) / 7; + a[4] = (4 * a0 + 3 * a1) / 7; + a[5] = (3 * a0 + 4 * a1) / 7; + a[6] = (2 * a0 + 5 * a1) / 7; + a[7] = (1 * a0 + 6 * a1) / 7; } else { - a[2] = (4*a0 + 1*a1) / 5; - a[3] = (3*a0 + 2*a1) / 5; - a[4] = (2*a0 + 3*a1) / 5; - a[5] = (1*a0 + 4*a1) / 5; + a[2] = (4 * a0 + 1 * a1) / 5; + a[3] = (3 * a0 + 2 * a1) / 5; + a[4] = (2 * a0 + 3 * a1) / 5; + a[5] = (1 * a0 + 4 * a1) / 5; a[6] = 0; a[7] = 0xff; } - lut = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16); for (n = 0; n < 8; n++) { - aw = 7 & (lut >> (3 * n)); + aw = 7 & (lut1 >> (3 * n)); dst[stride * n + o] = a[aw]; } - lut = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16); for (n = 0; n < 8; n++) { - aw = 7 & (lut >> (3 * n)); - dst[stride * (8+n) + o] = a[aw]; + aw = 7 & (lut2 >> (3 * n)); + dst[stride * (8 + n) + o] = a[aw]; } } -static void decode_bc1_block(rgba *col, const UINT8* src) { - decode_bc1_color(col, src); +static void +decode_bc1_block(rgba *col, const UINT8 *src) { + decode_bc1_color(col, src, 0); } -static void decode_bc2_block(rgba *col, const UINT8* src) { +static void +decode_bc2_block(rgba *col, const UINT8 *src) { int n, bitI, byI, av; - decode_bc1_color(col, src + 8); + decode_bc1_color(col, src + 8, 1); for (n = 0; n < 16; n++) { bitI = n * 4; byI = bitI >> 3; @@ -163,30 +180,36 @@ static void decode_bc2_block(rgba *col, const UINT8* src) { } } -static void decode_bc3_block(rgba *col, const UINT8* src) { - decode_bc1_color(col, src + 8); - decode_bc3_alpha((char *)col, src, sizeof(col[0]), 3); +static void +decode_bc3_block(rgba *col, const UINT8 *src) { + decode_bc1_color(col, src + 8, 1); + decode_bc3_alpha((char *)col, src, sizeof(col[0]), 3, 0); } -static void decode_bc4_block(lum *col, const UINT8* src) { - decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0); +static void +decode_bc4_block(lum *col, const UINT8 *src) { + decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0, 0); } -static void decode_bc5_block(rgba *col, const UINT8* src) { - decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0); - decode_bc3_alpha((char *)col, src + 8, sizeof(col[0]), 1); +static void +decode_bc5_block(rgba *col, const UINT8 *src, int sign) { + decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0, sign); + decode_bc3_alpha((char *)col, src + 8, sizeof(col[0]), 1, sign); } /* BC6 and BC7 are described here: - https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt */ + https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt + */ -static UINT8 get_bit(const UINT8* src, int bit) { +static UINT8 +get_bit(const UINT8 *src, int bit) { int by = bit >> 3; bit &= 7; return (src[by] >> bit) & 1; } -static UINT8 get_bits(const UINT8* src, int bit, int count) { +static UINT8 +get_bits(const UINT8 *src, int bit, int count) { UINT8 v; int x; int by = bit >> 3; @@ -197,7 +220,7 @@ static UINT8 get_bits(const UINT8* src, int bit, int count) { if (bit + count <= 8) { v = (src[by] >> bit) & ((1 << count) - 1); } else { - x = src[by] | (src[by+1] << 8); + x = src[by] | (src[by + 1] << 8); v = (x >> bit) & ((1 << count) - 1); } return v; @@ -225,73 +248,51 @@ static const bc7_mode_info bc7_modes[] = { {1, 0, 2, 1, 5, 6, 0, 0, 2, 3}, {1, 0, 2, 0, 7, 8, 0, 0, 2, 2}, {1, 0, 0, 0, 7, 7, 1, 0, 4, 0}, - {2, 6, 0, 0, 5, 5, 1, 0, 2, 0} -}; + {2, 6, 0, 0, 5, 5, 1, 0, 2, 0}}; /* Subset indices: Table.P2, 1 bit per index */ static const UINT16 bc7_si2[] = { - 0xcccc, 0x8888, 0xeeee, 0xecc8, 0xc880, 0xfeec, 0xfec8, 0xec80, - 0xc800, 0xffec, 0xfe80, 0xe800, 0xffe8, 0xff00, 0xfff0, 0xf000, - 0xf710, 0x008e, 0x7100, 0x08ce, 0x008c, 0x7310, 0x3100, 0x8cce, - 0x088c, 0x3110, 0x6666, 0x366c, 0x17e8, 0x0ff0, 0x718e, 0x399c, - 0xaaaa, 0xf0f0, 0x5a5a, 0x33cc, 0x3c3c, 0x55aa, 0x9696, 0xa55a, - 0x73ce, 0x13c8, 0x324c, 0x3bdc, 0x6996, 0xc33c, 0x9966, 0x0660, - 0x0272, 0x04e4, 0x4e40, 0x2720, 0xc936, 0x936c, 0x39c6, 0x639c, - 0x9336, 0x9cc6, 0x817e, 0xe718, 0xccf0, 0x0fcc, 0x7744, 0xee22}; + 0xcccc, 0x8888, 0xeeee, 0xecc8, 0xc880, 0xfeec, 0xfec8, 0xec80, 0xc800, 0xffec, + 0xfe80, 0xe800, 0xffe8, 0xff00, 0xfff0, 0xf000, 0xf710, 0x008e, 0x7100, 0x08ce, + 0x008c, 0x7310, 0x3100, 0x8cce, 0x088c, 0x3110, 0x6666, 0x366c, 0x17e8, 0x0ff0, + 0x718e, 0x399c, 0xaaaa, 0xf0f0, 0x5a5a, 0x33cc, 0x3c3c, 0x55aa, 0x9696, 0xa55a, + 0x73ce, 0x13c8, 0x324c, 0x3bdc, 0x6996, 0xc33c, 0x9966, 0x0660, 0x0272, 0x04e4, + 0x4e40, 0x2720, 0xc936, 0x936c, 0x39c6, 0x639c, 0x9336, 0x9cc6, 0x817e, 0xe718, + 0xccf0, 0x0fcc, 0x7744, 0xee22}; /* Table.P3, 2 bits per index */ static const UINT32 bc7_si3[] = { - 0xaa685050, 0x6a5a5040, 0x5a5a4200, 0x5450a0a8, - 0xa5a50000, 0xa0a05050, 0x5555a0a0, 0x5a5a5050, - 0xaa550000, 0xaa555500, 0xaaaa5500, 0x90909090, - 0x94949494, 0xa4a4a4a4, 0xa9a59450, 0x2a0a4250, - 0xa5945040, 0x0a425054, 0xa5a5a500, 0x55a0a0a0, - 0xa8a85454, 0x6a6a4040, 0xa4a45000, 0x1a1a0500, - 0x0050a4a4, 0xaaa59090, 0x14696914, 0x69691400, - 0xa08585a0, 0xaa821414, 0x50a4a450, 0x6a5a0200, - 0xa9a58000, 0x5090a0a8, 0xa8a09050, 0x24242424, - 0x00aa5500, 0x24924924, 0x24499224, 0x50a50a50, - 0x500aa550, 0xaaaa4444, 0x66660000, 0xa5a0a5a0, - 0x50a050a0, 0x69286928, 0x44aaaa44, 0x66666600, - 0xaa444444, 0x54a854a8, 0x95809580, 0x96969600, - 0xa85454a8, 0x80959580, 0xaa141414, 0x96960000, - 0xaaaa1414, 0xa05050a0, 0xa0a5a5a0, 0x96000000, - 0x40804080, 0xa9a8a9a8, 0xaaaaaa44, 0x2a4a5254}; + 0xaa685050, 0x6a5a5040, 0x5a5a4200, 0x5450a0a8, 0xa5a50000, 0xa0a05050, 0x5555a0a0, + 0x5a5a5050, 0xaa550000, 0xaa555500, 0xaaaa5500, 0x90909090, 0x94949494, 0xa4a4a4a4, + 0xa9a59450, 0x2a0a4250, 0xa5945040, 0x0a425054, 0xa5a5a500, 0x55a0a0a0, 0xa8a85454, + 0x6a6a4040, 0xa4a45000, 0x1a1a0500, 0x0050a4a4, 0xaaa59090, 0x14696914, 0x69691400, + 0xa08585a0, 0xaa821414, 0x50a4a450, 0x6a5a0200, 0xa9a58000, 0x5090a0a8, 0xa8a09050, + 0x24242424, 0x00aa5500, 0x24924924, 0x24499224, 0x50a50a50, 0x500aa550, 0xaaaa4444, + 0x66660000, 0xa5a0a5a0, 0x50a050a0, 0x69286928, 0x44aaaa44, 0x66666600, 0xaa444444, + 0x54a854a8, 0x95809580, 0x96969600, 0xa85454a8, 0x80959580, 0xaa141414, 0x96960000, + 0xaaaa1414, 0xa05050a0, 0xa0a5a5a0, 0x96000000, 0x40804080, 0xa9a8a9a8, 0xaaaaaa44, + 0x2a4a5254}; /* Anchor indices: Table.A2 */ static const char bc7_ai0[] = { - 15,15,15,15,15,15,15,15, - 15,15,15,15,15,15,15,15, - 15, 2, 8, 2, 2, 8, 8,15, - 2, 8, 2, 2, 8, 8, 2, 2, - 15,15, 6, 8, 2, 8,15,15, - 2, 8, 2, 2, 2,15,15, 6, - 6, 2, 6, 8,15,15, 2, 2, - 15,15,15,15,15, 2, 2,15}; + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 8, 2, 2, 8, + 8, 15, 2, 8, 2, 2, 8, 8, 2, 2, 15, 15, 6, 8, 2, 8, 15, 15, 2, 8, 2, 2, + 2, 15, 15, 6, 6, 2, 6, 8, 15, 15, 2, 2, 15, 15, 15, 15, 15, 2, 2, 15}; /* Table.A3a */ static const char bc7_ai1[] = { - 3, 3,15,15, 8, 3,15,15, - 8, 8, 6, 6, 6, 5, 3, 3, - 3, 3, 8,15, 3, 3, 6,10, - 5, 8, 8, 6, 8, 5,15,15, - 8,15, 3, 5, 6,10, 8,15, - 15, 3,15, 5,15,15,15,15, - 3,15, 5, 5, 5, 8, 5,10, - 5,10, 8,13,15,12, 3, 3}; + 3, 3, 15, 15, 8, 3, 15, 15, 8, 8, 6, 6, 6, 5, 3, 3, 3, 3, 8, 15, 3, 3, + 6, 10, 5, 8, 8, 6, 8, 5, 15, 15, 8, 15, 3, 5, 6, 10, 8, 15, 15, 3, 15, 5, + 15, 15, 15, 15, 3, 15, 5, 5, 5, 8, 5, 10, 5, 10, 8, 13, 15, 12, 3, 3}; /* Table.A3b */ -static const char bc7_ai2[] = { - 15, 8, 8, 3,15,15, 3, 8, - 15,15,15,15,15,15,15, 8, - 15, 8,15, 3,15, 8,15, 8, - 3,15, 6,10,15,15,10, 8, - 15, 3,15,10,10, 8, 9,10, - 6,15, 8,15, 3, 6, 6, 8, - 15, 3,15,15,15,15,15,15, - 15,15,15,15, 3,15,15, 8}; +static const char bc7_ai2[] = {15, 8, 8, 3, 15, 15, 3, 8, 15, 15, 15, 15, 15, + 15, 15, 8, 15, 8, 15, 3, 15, 8, 15, 8, 3, 15, + 6, 10, 15, 15, 10, 8, 15, 3, 15, 10, 10, 8, 9, + 10, 6, 15, 8, 15, 3, 6, 6, 8, 15, 3, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 3, 15, 15, 8}; /* Interpolation weights */ static const char bc7_weights2[] = {0, 21, 43, 64}; @@ -299,7 +300,8 @@ static const char bc7_weights3[] = {0, 9, 18, 27, 37, 46, 55, 64}; static const char bc7_weights4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64}; -static const char *bc7_get_weights(int n) { +static const char * +bc7_get_weights(int n) { if (n == 2) { return bc7_weights2; } @@ -309,7 +311,8 @@ static const char *bc7_get_weights(int n) { return bc7_weights4; } -static int bc7_get_subset(int ns, int partition, int n) { +static int +bc7_get_subset(int ns, int partition, int n) { if (ns == 2) { return 1 & (bc7_si2[partition] >> n); } @@ -319,12 +322,14 @@ static int bc7_get_subset(int ns, int partition, int n) { return 0; } -static UINT8 expand_quantized(UINT8 v, int bits) { +static UINT8 +expand_quantized(UINT8 v, int bits) { v = v << (8 - bits); return v | (v >> bits); } -static void bc7_lerp(rgba *dst, const rgba *e, int s0, int s1) { +static void +bc7_lerp(rgba *dst, const rgba *e, int s0, int s1) { int t0 = 64 - s0; int t1 = 64 - s1; dst->r = (UINT8)((t0 * e[0].r + s0 * e[1].r + 32) >> 6); @@ -333,7 +338,8 @@ static void bc7_lerp(rgba *dst, const rgba *e, int s0, int s1) { dst->a = (UINT8)((t1 * e[0].a + s1 * e[1].a + 32) >> 6); } -static void decode_bc7_block(rgba *col, const UINT8* src) { +static void +decode_bc7_block(rgba *col, const UINT8 *src) { rgba endpoints[6]; int bit = 0, cibit, aibit; int mode = src[0]; @@ -352,7 +358,8 @@ static void decode_bc7_block(rgba *col, const UINT8* src) { } return; } - while (!(mode & (1 << bit++))) ; + while (!(mode & (1 << bit++))) + ; mode = bit - 1; info = &bc7_modes[mode]; /* color selection bits: {subset}{endpoint} */ @@ -361,7 +368,7 @@ static void decode_bc7_block(rgba *col, const UINT8* src) { cw = bc7_get_weights(info->ib); aw = bc7_get_weights((ab && info->ib2) ? info->ib2 : info->ib); -#define LOAD(DST, N) \ +#define LOAD(DST, N) \ DST = get_bits(src, bit, N); \ bit += N; LOAD(partition, info->pb); @@ -421,14 +428,14 @@ static void decode_bc7_block(rgba *col, const UINT8* src) { if (ab) { ab++; } - for (i = 0; i < numep; i+=2) { + for (i = 0; i < numep; i += 2) { LOAD(val, 1); for (j = 0; j < 2; j++) { - ASSIGN_P(endpoints[i+j].r); - ASSIGN_P(endpoints[i+j].g); - ASSIGN_P(endpoints[i+j].b); + ASSIGN_P(endpoints[i + j].r); + ASSIGN_P(endpoints[i + j].g); + ASSIGN_P(endpoints[i + j].b); if (ab) { - ASSIGN_P(endpoints[i+j].a); + ASSIGN_P(endpoints[i + j].a); } } } @@ -482,9 +489,9 @@ static void decode_bc7_block(rgba *col, const UINT8* src) { bc7_lerp(&col[i], &endpoints[s], cw[i0], cw[i0]); } #define ROTATE(x, y) \ - val = x; \ - x = y; \ - y = val + val = x; \ + x = y; \ + y = val if (rotation == 1) { ROTATE(col[i].r, col[i].a); } else if (rotation == 2) { @@ -498,106 +505,102 @@ static void decode_bc7_block(rgba *col, const UINT8* src) { /* BC6 */ typedef struct { - char ns; /* number of subsets (also called regions) */ - char tr; /* whether endpoints are delta-compressed */ - char pb; /* partition bits */ + char ns; /* number of subsets (also called regions) */ + char tr; /* whether endpoints are delta-compressed */ + char pb; /* partition bits */ char epb; /* endpoint bits */ - char rb; /* red bits (delta) */ - char gb; /* green bits (delta) */ - char bb; /* blue bits (delta) */ + char rb; /* red bits (delta) */ + char gb; /* green bits (delta) */ + char bb; /* blue bits (delta) */ } bc6_mode_info; static const bc6_mode_info bc6_modes[] = { // 00 {2, 1, 5, 10, 5, 5, 5}, // 01 - {2, 1, 5, 7, 6, 6, 6}, + {2, 1, 5, 7, 6, 6, 6}, // 10 {2, 1, 5, 11, 5, 4, 4}, {2, 1, 5, 11, 4, 5, 4}, {2, 1, 5, 11, 4, 4, 5}, - {2, 1, 5, 9, 5, 5, 5}, - {2, 1, 5, 8, 6, 5, 5}, - {2, 1, 5, 8, 5, 6, 5}, - {2, 1, 5, 8, 5, 5, 6}, - {2, 0, 5, 6, 6, 6, 6}, + {2, 1, 5, 9, 5, 5, 5}, + {2, 1, 5, 8, 6, 5, 5}, + {2, 1, 5, 8, 5, 6, 5}, + {2, 1, 5, 8, 5, 5, 6}, + {2, 0, 5, 6, 6, 6, 6}, // 11 {1, 0, 0, 10, 10, 10, 10}, - {1, 1, 0, 11, 9, 9, 9}, - {1, 1, 0, 12, 8, 8, 8}, - {1, 1, 0, 16, 4, 4, 4} -}; + {1, 1, 0, 11, 9, 9, 9}, + {1, 1, 0, 12, 8, 8, 8}, + {1, 1, 0, 16, 4, 4, 4}}; /* Table.F, encoded as a sequence of bit indices */ static const UINT8 bc6_bit_packings[][75] = { - {116, 132, 176, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, - 164, 112, 113, 114, 115, 64, 65, 66, 67, 68, 172, 160, 161, 162, 163, 80, - 81, 82, 83, 84, 173, 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, - 145, 146, 147, 148, 175}, - {117, 164, 165, 0, 1, 2, 3, 4, 5, 6, 172, 173, 132, 16, 17, 18, 19, 20, 21, - 22, 133, 174, 116, 32, 33, 34, 35, 36, 37, 38, 175, 177, 176, 48, 49, 50, - 51, 52, 53, 112, 113, 114, 115, 64, 65, 66, 67, 68, 69, 160, 161, 162, 163, - 80, 81, 82, 83, 84, 85, 128, 129, 130, 131, 96, 97, 98, 99, 100, 101, 144, - 145, 146, 147, 148, 149}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 10, 112, 113, 114, - 115, 64, 65, 66, 67, 26, 172, 160, 161, 162, 163, 80, 81, 82, 83, 42, 173, - 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, - 175}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 10, 164, 112, 113, 114, - 115, 64, 65, 66, 67, 68, 26, 160, 161, 162, 163, 80, 81, 82, 83, 42, 173, - 128, 129, 130, 131, 96, 97, 98, 99, 172, 174, 144, 145, 146, 147, 116, - 175}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 10, 132, 112, 113, 114, - 115, 64, 65, 66, 67, 26, 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 42, - 128, 129, 130, 131, 96, 97, 98, 99, 173, 174, 144, 145, 146, 147, 176, - 175}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 132, 16, 17, 18, 19, 20, 21, 22, 23, 24, 116, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 176, 48, 49, 50, 51, 52, 164, 112, 113, - 114, 115, 64, 65, 66, 67, 68, 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, - 173, 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, - 175}, - {0, 1, 2, 3, 4, 5, 6, 7, 164, 132, 16, 17, 18, 19, 20, 21, 22, 23, 174, 116, - 32, 33, 34, 35, 36, 37, 38, 39, 175, 176, 48, 49, 50, 51, 52, 53, 112, 113, - 114, 115, 64, 65, 66, 67, 68, 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, - 173, 128, 129, 130, 131, 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, - 149}, - {0, 1, 2, 3, 4, 5, 6, 7, 172, 132, 16, 17, 18, 19, 20, 21, 22, 23, 117, 116, - 32, 33, 34, 35, 36, 37, 38, 39, 165, 176, 48, 49, 50, 51, 52, 164, 112, - 113, 114, 115, 64, 65, 66, 67, 68, 69, 160, 161, 162, 163, 80, 81, 82, 83, - 84, 173, 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, - 148, 175}, - {0, 1, 2, 3, 4, 5, 6, 7, 173, 132, 16, 17, 18, 19, 20, 21, 22, 23, 133, 116, - 32, 33, 34, 35, 36, 37, 38, 39, 177, 176, 48, 49, 50, 51, 52, 164, 112, - 113, 114, 115, 64, 65, 66, 67, 68, 172, 160, 161, 162, 163, 80, 81, 82, 83, - 84, 85, 128, 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, - 148, 175}, - {0, 1, 2, 3, 4, 5, 164, 172, 173, 132, 16, 17, 18, 19, 20, 21, 117, 133, - 174, 116, 32, 33, 34, 35, 36, 37, 165, 175, 177, 176, 48, 49, 50, 51, 52, - 53, 112, 113, 114, 115, 64, 65, 66, 67, 68, 69, 160, 161, 162, 163, 80, 81, - 82, 83, 84, 85, 128, 129, 130, 131, 96, 97, 98, 99, 100, 101, 144, 145, - 146, 147, 148, 149}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 10, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 26, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 42}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 11, 10, - 64, 65, 66, 67, 68, 69, 70, 71, 27, 26, 80, 81, 82, 83, 84, 85, 86, 87, 43, - 42}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 15, 14, 13, 12, 11, 10, - 64, 65, 66, 67, 31, 30, 29, 28, 27, 26, 80, 81, 82, 83, 47, 46, 45, 44, 43, - 42}}; + {116, 132, 176, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, + 66, 67, 68, 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 173, 128, + 129, 130, 131, 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175}, + {117, 164, 165, 0, 1, 2, 3, 4, 5, 6, 172, 173, 132, 16, 17, + 18, 19, 20, 21, 22, 133, 174, 116, 32, 33, 34, 35, 36, 37, 38, + 175, 177, 176, 48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65, + 66, 67, 68, 69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128, + 129, 130, 131, 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 48, 49, 50, 51, 52, 10, 112, 113, 114, 115, 64, 65, 66, 67, 26, + 172, 160, 161, 162, 163, 80, 81, 82, 83, 42, 173, 128, 129, 130, 131, + 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 48, 49, 50, 51, 10, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68, + 26, 160, 161, 162, 163, 80, 81, 82, 83, 42, 173, 128, 129, 130, 131, + 96, 97, 98, 99, 172, 174, 144, 145, 146, 147, 116, 175}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 48, 49, 50, 51, 10, 132, 112, 113, 114, 115, 64, 65, 66, 67, 26, + 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 42, 128, 129, 130, 131, + 96, 97, 98, 99, 173, 174, 144, 145, 146, 147, 176, 175}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 132, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 116, 32, 33, 34, 35, 36, 37, 38, 39, 40, 176, + 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68, + 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 173, 128, 129, 130, 131, + 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175}, + {0, 1, 2, 3, 4, 5, 6, 7, 164, 132, 16, 17, 18, 19, 20, + 21, 22, 23, 174, 116, 32, 33, 34, 35, 36, 37, 38, 39, 175, 176, + 48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65, 66, 67, 68, + 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 173, 128, 129, 130, 131, + 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149}, + {0, 1, 2, 3, 4, 5, 6, 7, 172, 132, 16, 17, 18, 19, 20, + 21, 22, 23, 117, 116, 32, 33, 34, 35, 36, 37, 38, 39, 165, 176, + 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68, + 69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 173, 128, 129, 130, 131, + 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175}, + {0, 1, 2, 3, 4, 5, 6, 7, 173, 132, 16, 17, 18, 19, 20, + 21, 22, 23, 133, 116, 32, 33, 34, 35, 36, 37, 38, 39, 177, 176, + 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68, + 172, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128, 129, 130, 131, + 96, 97, 98, 99, 100, 174, 144, 145, 146, 147, 148, 175}, + {0, 1, 2, 3, 4, 5, 164, 172, 173, 132, 16, 17, 18, 19, 20, + 21, 117, 133, 174, 116, 32, 33, 34, 35, 36, 37, 165, 175, 177, 176, + 48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65, 66, 67, 68, + 69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128, 129, 130, 131, + 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 10, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 26, 80, 81, 82, 83, 84, 85, 86, 87, 88, 42}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 11, 10, + 64, 65, 66, 67, 68, 69, 70, 71, 27, 26, 80, 81, 82, 83, 84, 85, 86, 87, 43, 42}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 15, 14, 13, 12, 11, 10, + 64, 65, 66, 67, 31, 30, 29, 28, 27, 26, 80, 81, 82, 83, 47, 46, 45, 44, 43, 42}}; -static void bc6_sign_extend(UINT16 *v, int prec) { +static void +bc6_sign_extend(UINT16 *v, int prec) { int x = *v; if (x & (1 << (prec - 1))) { x |= -1 << prec; @@ -605,7 +608,8 @@ static void bc6_sign_extend(UINT16 *v, int prec) { *v = (UINT16)x; } -static int bc6_unquantize(UINT16 v, int prec, int sign) { +static int +bc6_unquantize(UINT16 v, int prec, int sign) { int s = 0; int x; if (!sign) { @@ -645,7 +649,8 @@ static int bc6_unquantize(UINT16 v, int prec, int sign) { } } -static float half_to_float(UINT16 h) { +static float +half_to_float(UINT16 h) { /* https://gist.github.com/rygorous/2144712 */ union { UINT32 u; @@ -662,7 +667,8 @@ static float half_to_float(UINT16 h) { return o.f; } -static float bc6_finalize(int v, int sign) { +static float +bc6_finalize(int v, int sign) { if (sign) { if (v < 0) { v = ((-v) * 31) / 32; @@ -675,7 +681,8 @@ static float bc6_finalize(int v, int sign) { } } -static void bc6_lerp(rgb32f *col, int *e0, int *e1, int s, int sign) { +static void +bc6_lerp(rgb32f *col, int *e0, int *e1, int s, int sign) { int r, g, b; int t = 64 - s; r = (e0[0] * t + e1[0] * s) >> 6; @@ -686,7 +693,8 @@ static void bc6_lerp(rgb32f *col, int *e0, int *e1, int s, int sign) { col->b = bc6_finalize(b, sign); } -static void decode_bc6_block(rgb32f *col, const UINT8* src, int sign) { +static void +decode_bc6_block(rgb32f *col, const UINT8 *src, int sign) { UINT16 endpoints[12]; /* storage for r0, g0, b0, r1, ... */ int ueps[12]; int i, i0, ib2, di, dw, mask, numep, s; @@ -736,9 +744,9 @@ static void decode_bc6_block(rgb32f *col, const UINT8* src, int sign) { } if (sign || info->tr) { /* sign-extend e1,2,3 if signed or deltas */ for (i = 3; i < numep; i += 3) { - bc6_sign_extend(&endpoints[i+0], info->rb); - bc6_sign_extend(&endpoints[i+1], info->gb); - bc6_sign_extend(&endpoints[i+2], info->bb); + bc6_sign_extend(&endpoints[i + 0], info->rb); + bc6_sign_extend(&endpoints[i + 1], info->gb); + bc6_sign_extend(&endpoints[i + 2], info->bb); } } if (info->tr) { /* apply deltas */ @@ -747,9 +755,9 @@ static void decode_bc6_block(rgb32f *col, const UINT8* src, int sign) { } if (sign) { for (i = 3; i < numep; i += 3) { - bc6_sign_extend(&endpoints[i+0], info->rb); - bc6_sign_extend(&endpoints[i+1], info->gb); - bc6_sign_extend(&endpoints[i+2], info->bb); + bc6_sign_extend(&endpoints[i + 0], info->rb); + bc6_sign_extend(&endpoints[i + 1], info->gb); + bc6_sign_extend(&endpoints[i + 2], info->bb); } } } @@ -769,11 +777,12 @@ static void decode_bc6_block(rgb32f *col, const UINT8* src, int sign) { i0 = get_bits(src, bit, ib2); bit += ib2; - bc6_lerp(&col[i], &ueps[s], &ueps[s+3], cw[i0], sign); + bc6_lerp(&col[i], &ueps[s], &ueps[s + 3], cw[i0], sign); } } -static void put_block(Imaging im, ImagingCodecState state, const char *col, int sz, int C) { +static void +put_block(Imaging im, ImagingCodecState state, const char *col, int sz, int C) { int width = state->xsize; int height = state->ysize; int xmax = width + state->xoff; @@ -795,15 +804,15 @@ static void put_block(Imaging im, ImagingCodecState state, const char *col, int if (x >= width) { continue; } - memcpy(dst + sz*x, col + sz*(j*4 + i), sz); + memcpy(dst + sz * x, col + sz * (j * 4 + i), sz); } } else { if (state->ystep < 0) { y = state->yoff + ymax - y - 1; } x = state->x; - dst = im->image[y] + sz*x; - memcpy(dst, col + sz*(j*4), 4 * sz); + dst = im->image[y] + sz * x; + memcpy(dst, col + sz * (j * 4), 4 * sz); } } state->x += 4; @@ -813,30 +822,44 @@ static void put_block(Imaging im, ImagingCodecState state, const char *col, int } } -static int decode_bcn(Imaging im, ImagingCodecState state, const UINT8* src, int bytes, int N, int C) { +static int +decode_bcn( + Imaging im, ImagingCodecState state, const UINT8 *src, int bytes, int N, int C, char *pixel_format) { int ymax = state->ysize + state->yoff; const UINT8 *ptr = src; switch (N) { -#define DECODE_LOOP(NN, SZ, TY, ...) \ - case NN: \ - while (bytes >= SZ) { \ - TY col[16]; \ - memset(col, 0, 16 * sizeof(col[0])); \ - decode_bc##NN##_block(col, ptr); \ +#define DECODE_LOOP(NN, SZ, TY, ...) \ + case NN: \ + while (bytes >= SZ) { \ + TY col[16]; \ + memset(col, 0, 16 * sizeof(col[0])); \ + decode_bc##NN##_block(col, ptr); \ put_block(im, state, (const char *)col, sizeof(col[0]), C); \ - ptr += SZ; \ - bytes -= SZ; \ - if (state->y >= ymax) {\ - return -1; \ - }\ - } \ + ptr += SZ; \ + bytes -= SZ; \ + if (state->y >= ymax) { \ + return -1; \ + } \ + } \ break DECODE_LOOP(1, 8, rgba); DECODE_LOOP(2, 16, rgba); DECODE_LOOP(3, 16, rgba); DECODE_LOOP(4, 8, lum); - DECODE_LOOP(5, 16, rgba); + case 5: + while (bytes >= 16) { + rgba col[16]; + memset(col, 0, 16 * sizeof(col[0])); + decode_bc5_block(col, ptr, strcmp(pixel_format, "BC5S") == 0 ? 1 : 0); + put_block(im, state, (const char *)col, sizeof(col[0]), C); + ptr += 16; + bytes -= 16; + if (state->y >= ymax) { + return -1; + } + } + break; case 6: while (bytes >= 16) { rgb32f col[16]; @@ -844,9 +867,9 @@ static int decode_bcn(Imaging im, ImagingCodecState state, const UINT8* src, int put_block(im, state, (const char *)col, sizeof(col[0]), C); ptr += 16; bytes -= 16; - if (state->y >= ymax) {\ - return -1; \ - }\ + if (state->y >= ymax) { + return -1; + } } break; DECODE_LOOP(7, 16, rgba); @@ -855,13 +878,12 @@ static int decode_bcn(Imaging im, ImagingCodecState state, const UINT8* src, int return (int)(ptr - src); } -int ImagingBcnDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) { +int +ImagingBcnDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { int N = state->state & 0xf; int width = state->xsize; int height = state->ysize; - if ((width & 3) | (height & 3)) { - return decode_bcn(im, state, buf, bytes, N, 1); - } else { - return decode_bcn(im, state, buf, bytes, N, 0); - } + int C = (width & 3) | (height & 3) ? 1 : 0; + char *pixel_format = ((BCNSTATE *)state->context)->pixel_format; + return decode_bcn(im, state, buf, bytes, N, C, pixel_format); } diff --git a/src/libImaging/Bit.h b/src/libImaging/Bit.h index 56e3a17d2..f64bfb469 100644 --- a/src/libImaging/Bit.h +++ b/src/libImaging/Bit.h @@ -1,7 +1,6 @@ /* Bit.h */ typedef struct { - /* CONFIGURATION */ /* Number of bits per pixel */ @@ -19,7 +18,7 @@ typedef struct { /* Lookup table (not implemented) */ unsigned long lutsize; - FLOAT32* lut; + FLOAT32 *lut; /* INTERNAL */ unsigned long mask; diff --git a/src/libImaging/BitDecode.c b/src/libImaging/BitDecode.c index 92edd746f..28baa8b7e 100644 --- a/src/libImaging/BitDecode.c +++ b/src/libImaging/BitDecode.c @@ -13,20 +13,16 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #include "Bit.h" - int -ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ - BITSTATE* bitstate = state->context; - UINT8* ptr; +ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { + BITSTATE *bitstate = state->context; + UINT8 *ptr; if (state->state == 0) { - /* Initialize context variables */ /* this decoder only works for float32 image buffers */ @@ -41,37 +37,35 @@ ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt return -1; } - bitstate->mask = (1<bits)-1; + bitstate->mask = (1 << bitstate->bits) - 1; if (bitstate->sign) { - bitstate->signmask = (1<<(bitstate->bits-1)); + bitstate->signmask = (1 << (bitstate->bits - 1)); } /* check image orientation */ if (state->ystep < 0) { - state->y = state->ysize-1; + state->y = state->ysize - 1; state->ystep = -1; } else { state->ystep = 1; } state->state = 1; - } ptr = buf; while (bytes > 0) { - UINT8 byte = *ptr; ptr++; bytes--; /* get a byte from the input stream and insert in the bit buffer */ - if (bitstate->fill&1) { + if (bitstate->fill & 1) { /* fill MSB first */ - bitstate->bitbuffer |= (unsigned long) byte << bitstate->bitcount; + bitstate->bitbuffer |= (unsigned long)byte << bitstate->bitcount; } else { /* fill LSB first */ bitstate->bitbuffer = (bitstate->bitbuffer << 8) | byte; @@ -80,26 +74,24 @@ ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt bitstate->bitcount += 8; while (bitstate->bitcount >= bitstate->bits) { - /* get a pixel from the bit buffer */ unsigned long data; FLOAT32 pixel; - if (bitstate->fill&2) { + if (bitstate->fill & 2) { /* store LSB first */ data = bitstate->bitbuffer & bitstate->mask; if (bitstate->bitcount > 32) { /* bitbuffer overflow; restore it from last input byte */ - bitstate->bitbuffer = byte >> (8 - (bitstate->bitcount - - bitstate->bits)); + bitstate->bitbuffer = + byte >> (8 - (bitstate->bitcount - bitstate->bits)); } else { bitstate->bitbuffer >>= bitstate->bits; } } else { /* store MSB first */ - data = (bitstate->bitbuffer >> (bitstate->bitcount - - bitstate->bits)) - & bitstate->mask; + data = (bitstate->bitbuffer >> (bitstate->bitcount - bitstate->bits)) & + bitstate->mask; } bitstate->bitcount -= bitstate->bits; @@ -109,7 +101,7 @@ ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt if (data <= 0) { pixel = bitstate->lut[0]; } else if (data >= bitstate->lutsize) { - pixel = bitstate->lut[bitstate->lutsize-1]; + pixel = bitstate->lut[bitstate->lutsize - 1]; } else { pixel = bitstate->lut[data]; } @@ -117,13 +109,13 @@ ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt /* convert */ if (data & bitstate->signmask) { /* image memory contains signed data */ - pixel = (FLOAT32) (INT32) (data | ~bitstate->mask); + pixel = (FLOAT32)(INT32)(data | ~bitstate->mask); } else { - pixel = (FLOAT32) data; + pixel = (FLOAT32)data; } } - *(FLOAT32*)(&im->image32[state->y][state->x]) = pixel; + *(FLOAT32 *)(&im->image32[state->y][state->x]) = pixel; /* step forward */ if (++state->x >= state->xsize) { diff --git a/src/libImaging/Blend.c b/src/libImaging/Blend.c index 0bac4cda9..a53ae0fad 100644 --- a/src/libImaging/Blend.c +++ b/src/libImaging/Blend.c @@ -15,27 +15,22 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" - Imaging -ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha) -{ +ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha) { Imaging imOut; int x, y; /* Check arguments */ - if (!imIn1 || !imIn2 || imIn1->type != IMAGING_TYPE_UINT8 - || imIn1->palette || strcmp(imIn1->mode, "1") == 0 - || imIn2->palette || strcmp(imIn2->mode, "1") == 0) { + if (!imIn1 || !imIn2 || imIn1->type != IMAGING_TYPE_UINT8 || imIn1->palette || + strcmp(imIn1->mode, "1") == 0 || imIn2->palette || + strcmp(imIn2->mode, "1") == 0) { return ImagingError_ModeError(); } - if (imIn1->type != imIn2->type || - imIn1->bands != imIn2->bands || - imIn1->xsize != imIn2->xsize || - imIn1->ysize != imIn2->ysize) { + if (imIn1->type != imIn2->type || imIn1->bands != imIn2->bands || + imIn1->xsize != imIn2->xsize || imIn1->ysize != imIn2->ysize) { return ImagingError_Mismatch(); } @@ -54,29 +49,27 @@ ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha) if (alpha >= 0 && alpha <= 1.0) { /* Interpolate between bands */ for (y = 0; y < imIn1->ysize; y++) { - UINT8* in1 = (UINT8*) imIn1->image[y]; - UINT8* in2 = (UINT8*) imIn2->image[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT8 *in1 = (UINT8 *)imIn1->image[y]; + UINT8 *in2 = (UINT8 *)imIn2->image[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn1->linesize; x++) { - out[x] = (UINT8) - ((int) in1[x] + alpha * ((int) in2[x] - (int) in1[x])); + out[x] = (UINT8)((int)in1[x] + alpha * ((int)in2[x] - (int)in1[x])); } } } else { /* Extrapolation; must make sure to clip resulting values */ for (y = 0; y < imIn1->ysize; y++) { - UINT8* in1 = (UINT8*) imIn1->image[y]; - UINT8* in2 = (UINT8*) imIn2->image[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT8 *in1 = (UINT8 *)imIn1->image[y]; + UINT8 *in2 = (UINT8 *)imIn2->image[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn1->linesize; x++) { - float temp = (float) - ((int) in1[x] + alpha * ((int) in2[x] - (int) in1[x])); + float temp = (float)((int)in1[x] + alpha * ((int)in2[x] - (int)in1[x])); if (temp <= 0.0) { out[x] = 0; } else if (temp >= 255.0) { out[x] = 255; } else { - out[x] = (UINT8) temp; + out[x] = (UINT8)temp; } } } diff --git a/src/libImaging/BoxBlur.c b/src/libImaging/BoxBlur.c index dcdc52cbc..2e45a3358 100644 --- a/src/libImaging/BoxBlur.c +++ b/src/libImaging/BoxBlur.c @@ -1,37 +1,40 @@ #include "Imaging.h" - #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) - typedef UINT8 pixel[4]; -void static inline -ImagingLineBoxBlur32(pixel *lineOut, pixel *lineIn, int lastx, int radius, int edgeA, - int edgeB, UINT32 ww, UINT32 fw) -{ +void static inline ImagingLineBoxBlur32( + pixel *lineOut, + pixel *lineIn, + int lastx, + int radius, + int edgeA, + int edgeB, + UINT32 ww, + UINT32 fw) { int x; UINT32 acc[4]; UINT32 bulk[4]; - #define MOVE_ACC(acc, subtract, add) \ - acc[0] += lineIn[add][0] - lineIn[subtract][0]; \ - acc[1] += lineIn[add][1] - lineIn[subtract][1]; \ - acc[2] += lineIn[add][2] - lineIn[subtract][2]; \ - acc[3] += lineIn[add][3] - lineIn[subtract][3]; +#define MOVE_ACC(acc, subtract, add) \ + acc[0] += lineIn[add][0] - lineIn[subtract][0]; \ + acc[1] += lineIn[add][1] - lineIn[subtract][1]; \ + acc[2] += lineIn[add][2] - lineIn[subtract][2]; \ + acc[3] += lineIn[add][3] - lineIn[subtract][3]; - #define ADD_FAR(bulk, acc, left, right) \ - bulk[0] = (acc[0] * ww) + (lineIn[left][0] + lineIn[right][0]) * fw; \ - bulk[1] = (acc[1] * ww) + (lineIn[left][1] + lineIn[right][1]) * fw; \ - bulk[2] = (acc[2] * ww) + (lineIn[left][2] + lineIn[right][2]) * fw; \ - bulk[3] = (acc[3] * ww) + (lineIn[left][3] + lineIn[right][3]) * fw; +#define ADD_FAR(bulk, acc, left, right) \ + bulk[0] = (acc[0] * ww) + (lineIn[left][0] + lineIn[right][0]) * fw; \ + bulk[1] = (acc[1] * ww) + (lineIn[left][1] + lineIn[right][1]) * fw; \ + bulk[2] = (acc[2] * ww) + (lineIn[left][2] + lineIn[right][2]) * fw; \ + bulk[3] = (acc[3] * ww) + (lineIn[left][3] + lineIn[right][3]) * fw; - #define SAVE(x, bulk) \ - lineOut[x][0] = (UINT8)((bulk[0] + (1 << 23)) >> 24); \ - lineOut[x][1] = (UINT8)((bulk[1] + (1 << 23)) >> 24); \ - lineOut[x][2] = (UINT8)((bulk[2] + (1 << 23)) >> 24); \ - lineOut[x][3] = (UINT8)((bulk[3] + (1 << 23)) >> 24); +#define SAVE(x, bulk) \ + lineOut[x][0] = (UINT8)((bulk[0] + (1 << 23)) >> 24); \ + lineOut[x][1] = (UINT8)((bulk[1] + (1 << 23)) >> 24); \ + lineOut[x][2] = (UINT8)((bulk[2] + (1 << 23)) >> 24); \ + lineOut[x][3] = (UINT8)((bulk[3] + (1 << 23)) >> 24); /* Compute acc for -1 pixel (outside of image): From "-radius-1" to "-1" get first pixel, @@ -53,8 +56,7 @@ ImagingLineBoxBlur32(pixel *lineOut, pixel *lineIn, int lastx, int radius, int e acc[2] += lineIn[lastx][2] * (radius - edgeA + 1); acc[3] += lineIn[lastx][3] * (radius - edgeA + 1); - if (edgeA <= edgeB) - { + if (edgeA <= edgeB) { /* Subtract pixel from left ("0"). Add pixels from radius. */ for (x = 0; x < edgeA; x++) { @@ -76,9 +78,7 @@ ImagingLineBoxBlur32(pixel *lineOut, pixel *lineIn, int lastx, int radius, int e ADD_FAR(bulk, acc, x - radius - 1, lastx); SAVE(x, bulk); } - } - else - { + } else { for (x = 0; x < edgeB; x++) { MOVE_ACC(acc, 0, x + radius); ADD_FAR(bulk, acc, 0, x + radius + 1); @@ -96,28 +96,30 @@ ImagingLineBoxBlur32(pixel *lineOut, pixel *lineIn, int lastx, int radius, int e } } - #undef MOVE_ACC - #undef ADD_FAR - #undef SAVE +#undef MOVE_ACC +#undef ADD_FAR +#undef SAVE } - -void static inline -ImagingLineBoxBlur8(UINT8 *lineOut, UINT8 *lineIn, int lastx, int radius, int edgeA, - int edgeB, UINT32 ww, UINT32 fw) -{ +void static inline ImagingLineBoxBlur8( + UINT8 *lineOut, + UINT8 *lineIn, + int lastx, + int radius, + int edgeA, + int edgeB, + UINT32 ww, + UINT32 fw) { int x; UINT32 acc; UINT32 bulk; - #define MOVE_ACC(acc, subtract, add) \ - acc += lineIn[add] - lineIn[subtract]; +#define MOVE_ACC(acc, subtract, add) acc += lineIn[add] - lineIn[subtract]; - #define ADD_FAR(bulk, acc, left, right) \ - bulk = (acc * ww) + (lineIn[left] + lineIn[right]) * fw; +#define ADD_FAR(bulk, acc, left, right) \ + bulk = (acc * ww) + (lineIn[left] + lineIn[right]) * fw; - #define SAVE(x, bulk) \ - lineOut[x] = (UINT8)((bulk + (1 << 23)) >> 24) +#define SAVE(x, bulk) lineOut[x] = (UINT8)((bulk + (1 << 23)) >> 24) acc = lineIn[0] * (radius + 1); for (x = 0; x < edgeA - 1; x++) { @@ -125,8 +127,7 @@ ImagingLineBoxBlur8(UINT8 *lineOut, UINT8 *lineIn, int lastx, int radius, int ed } acc += lineIn[lastx] * (radius - edgeA + 1); - if (edgeA <= edgeB) - { + if (edgeA <= edgeB) { for (x = 0; x < edgeA; x++) { MOVE_ACC(acc, 0, x + radius); ADD_FAR(bulk, acc, 0, x + radius + 1); @@ -142,9 +143,7 @@ ImagingLineBoxBlur8(UINT8 *lineOut, UINT8 *lineIn, int lastx, int radius, int ed ADD_FAR(bulk, acc, x - radius - 1, lastx); SAVE(x, bulk); } - } - else - { + } else { for (x = 0; x < edgeB; x++) { MOVE_ACC(acc, 0, x + radius); ADD_FAR(bulk, acc, 0, x + radius + 1); @@ -162,22 +161,19 @@ ImagingLineBoxBlur8(UINT8 *lineOut, UINT8 *lineIn, int lastx, int radius, int ed } } - #undef MOVE_ACC - #undef ADD_FAR - #undef SAVE +#undef MOVE_ACC +#undef ADD_FAR +#undef SAVE } - - Imaging -ImagingHorizontalBoxBlur(Imaging imOut, Imaging imIn, float floatRadius) -{ +ImagingHorizontalBoxBlur(Imaging imOut, Imaging imIn, float floatRadius) { ImagingSectionCookie cookie; int y; - int radius = (int) floatRadius; - UINT32 ww = (UINT32) (1 << 24) / (floatRadius * 2 + 1); + int radius = (int)floatRadius; + UINT32 ww = (UINT32)(1 << 24) / (floatRadius * 2 + 1); UINT32 fw = ((1 << 24) - (radius * 2 + 1) * ww) / 2; int edgeA = MIN(radius + 1, imIn->xsize); @@ -192,32 +188,33 @@ ImagingHorizontalBoxBlur(Imaging imOut, Imaging imIn, float floatRadius) ImagingSectionEnter(&cookie); - if (imIn->image8) - { + if (imIn->image8) { for (y = 0; y < imIn->ysize; y++) { ImagingLineBoxBlur8( - (imIn == imOut ? (UINT8 *) lineOut : imOut->image8[y]), + (imIn == imOut ? (UINT8 *)lineOut : imOut->image8[y]), imIn->image8[y], imIn->xsize - 1, - radius, edgeA, edgeB, - ww, fw - ); + radius, + edgeA, + edgeB, + ww, + fw); if (imIn == imOut) { // Commit. memcpy(imOut->image8[y], lineOut, imIn->xsize); } } - } - else - { + } else { for (y = 0; y < imIn->ysize; y++) { ImagingLineBoxBlur32( - imIn == imOut ? (pixel *) lineOut : (pixel *) imOut->image32[y], - (pixel *) imIn->image32[y], + imIn == imOut ? (pixel *)lineOut : (pixel *)imOut->image32[y], + (pixel *)imIn->image32[y], imIn->xsize - 1, - radius, edgeA, edgeB, - ww, fw - ); + radius, + edgeA, + edgeB, + ww, + fw); if (imIn == imOut) { // Commit. memcpy(imOut->image32[y], lineOut, imIn->xsize * 4); @@ -232,23 +229,17 @@ ImagingHorizontalBoxBlur(Imaging imOut, Imaging imIn, float floatRadius) return imOut; } - Imaging -ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n) -{ +ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n) { int i; Imaging imTransposed; if (n < 1) { - return ImagingError_ValueError( - "number of passes must be greater than zero" - ); + return ImagingError_ValueError("number of passes must be greater than zero"); } - if (strcmp(imIn->mode, imOut->mode) || - imIn->type != imOut->type || - imIn->bands != imOut->bands || - imIn->xsize != imOut->xsize || + if (strcmp(imIn->mode, imOut->mode) || imIn->type != imOut->type || + imIn->bands != imOut->bands || imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { return ImagingError_Mismatch(); } @@ -257,14 +248,10 @@ ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n) return ImagingError_ModeError(); } - if (!(strcmp(imIn->mode, "RGB") == 0 || - strcmp(imIn->mode, "RGBA") == 0 || - strcmp(imIn->mode, "RGBa") == 0 || - strcmp(imIn->mode, "RGBX") == 0 || - strcmp(imIn->mode, "CMYK") == 0 || - strcmp(imIn->mode, "L") == 0 || - strcmp(imIn->mode, "LA") == 0 || - strcmp(imIn->mode, "La") == 0)) { + if (!(strcmp(imIn->mode, "RGB") == 0 || strcmp(imIn->mode, "RGBA") == 0 || + strcmp(imIn->mode, "RGBa") == 0 || strcmp(imIn->mode, "RGBX") == 0 || + strcmp(imIn->mode, "CMYK") == 0 || strcmp(imIn->mode, "L") == 0 || + strcmp(imIn->mode, "LA") == 0 || strcmp(imIn->mode, "La") == 0)) { return ImagingError_ModeError(); } @@ -277,14 +264,14 @@ ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n) Use imOut as a destination at first pass, then use imOut as a source too. */ ImagingHorizontalBoxBlur(imOut, imIn, radius); - for (i = 1; i < n; i ++) { + for (i = 1; i < n; i++) { ImagingHorizontalBoxBlur(imOut, imOut, radius); } /* Transpose result for blur in another direction. */ ImagingTranspose(imTransposed, imOut); /* Reuse imTransposed as a source and destination there. */ - for (i = 0; i < n; i ++) { + for (i = 0; i < n; i++) { ImagingHorizontalBoxBlur(imTransposed, imTransposed, radius); } /* Restore original orientation. */ @@ -295,14 +282,12 @@ ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n) return imOut; } - -Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius, - int passes) -{ +Imaging +ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius, int passes) { float sigma2, L, l, a; sigma2 = radius * radius / passes; - // from http://www.mia.uni-saarland.de/Publications/gwosdek-ssvm11.pdf + // from https://www.mia.uni-saarland.de/Publications/gwosdek-ssvm11.pdf // [7] Box length. L = sqrt(12.0 * sigma2 + 1.0); // [11] Integer part of box radius. diff --git a/src/libImaging/Chops.c b/src/libImaging/Chops.c index a0a70abd9..f9c005efe 100644 --- a/src/libImaging/Chops.c +++ b/src/libImaging/Chops.c @@ -16,62 +16,59 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" -#define CHOP(operation)\ - int x, y;\ - Imaging imOut;\ - imOut = create(imIn1, imIn2, NULL);\ - if (!imOut) {\ - return NULL;\ - }\ - for (y = 0; y < imOut->ysize; y++) {\ - UINT8* out = (UINT8*) imOut->image[y];\ - UINT8* in1 = (UINT8*) imIn1->image[y];\ - UINT8* in2 = (UINT8*) imIn2->image[y];\ - for (x = 0; x < imOut->linesize; x++) {\ - int temp = operation;\ - if (temp <= 0) {\ - out[x] = 0;\ - } else if (temp >= 255) {\ - out[x] = 255;\ - } else {\ - out[x] = temp;\ - }\ - }\ - }\ +#define CHOP(operation) \ + int x, y; \ + Imaging imOut; \ + imOut = create(imIn1, imIn2, NULL); \ + if (!imOut) { \ + return NULL; \ + } \ + for (y = 0; y < imOut->ysize; y++) { \ + UINT8 *out = (UINT8 *)imOut->image[y]; \ + UINT8 *in1 = (UINT8 *)imIn1->image[y]; \ + UINT8 *in2 = (UINT8 *)imIn2->image[y]; \ + for (x = 0; x < imOut->linesize; x++) { \ + int temp = operation; \ + if (temp <= 0) { \ + out[x] = 0; \ + } else if (temp >= 255) { \ + out[x] = 255; \ + } else { \ + out[x] = temp; \ + } \ + } \ + } \ return imOut; -#define CHOP2(operation, mode)\ - int x, y;\ - Imaging imOut;\ - imOut = create(imIn1, imIn2, mode);\ - if (!imOut) {\ - return NULL;\ - }\ - for (y = 0; y < imOut->ysize; y++) {\ - UINT8* out = (UINT8*) imOut->image[y];\ - UINT8* in1 = (UINT8*) imIn1->image[y];\ - UINT8* in2 = (UINT8*) imIn2->image[y];\ - for (x = 0; x < imOut->linesize; x++) {\ - out[x] = operation;\ - }\ - }\ +#define CHOP2(operation, mode) \ + int x, y; \ + Imaging imOut; \ + imOut = create(imIn1, imIn2, mode); \ + if (!imOut) { \ + return NULL; \ + } \ + for (y = 0; y < imOut->ysize; y++) { \ + UINT8 *out = (UINT8 *)imOut->image[y]; \ + UINT8 *in1 = (UINT8 *)imIn1->image[y]; \ + UINT8 *in2 = (UINT8 *)imIn2->image[y]; \ + for (x = 0; x < imOut->linesize; x++) { \ + out[x] = operation; \ + } \ + } \ return imOut; static Imaging -create(Imaging im1, Imaging im2, char* mode) -{ +create(Imaging im1, Imaging im2, char *mode) { int xsize, ysize; if (!im1 || !im2 || im1->type != IMAGING_TYPE_UINT8 || (mode != NULL && (strcmp(im1->mode, "1") || strcmp(im2->mode, "1")))) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } - if (im1->type != im2->type || - im1->bands != im2->bands) { - return (Imaging) ImagingError_Mismatch(); + if (im1->type != im2->type || im1->bands != im2->bands) { + return (Imaging)ImagingError_Mismatch(); } xsize = (im1->xsize < im2->xsize) ? im1->xsize : im2->xsize; @@ -81,97 +78,85 @@ create(Imaging im1, Imaging im2, char* mode) } Imaging -ImagingChopLighter(Imaging imIn1, Imaging imIn2) -{ +ImagingChopLighter(Imaging imIn1, Imaging imIn2) { CHOP((in1[x] > in2[x]) ? in1[x] : in2[x]); } Imaging -ImagingChopDarker(Imaging imIn1, Imaging imIn2) -{ +ImagingChopDarker(Imaging imIn1, Imaging imIn2) { CHOP((in1[x] < in2[x]) ? in1[x] : in2[x]); } Imaging -ImagingChopDifference(Imaging imIn1, Imaging imIn2) -{ - CHOP(abs((int) in1[x] - (int) in2[x])); +ImagingChopDifference(Imaging imIn1, Imaging imIn2) { + CHOP(abs((int)in1[x] - (int)in2[x])); } Imaging -ImagingChopMultiply(Imaging imIn1, Imaging imIn2) -{ - CHOP((int) in1[x] * (int) in2[x] / 255); +ImagingChopMultiply(Imaging imIn1, Imaging imIn2) { + CHOP((int)in1[x] * (int)in2[x] / 255); } Imaging -ImagingChopScreen(Imaging imIn1, Imaging imIn2) -{ - CHOP(255 - ((int) (255 - in1[x]) * (int) (255 - in2[x])) / 255); +ImagingChopScreen(Imaging imIn1, Imaging imIn2) { + CHOP(255 - ((int)(255 - in1[x]) * (int)(255 - in2[x])) / 255); } Imaging -ImagingChopAdd(Imaging imIn1, Imaging imIn2, float scale, int offset) -{ - CHOP(((int) in1[x] + (int) in2[x]) / scale + offset); +ImagingChopAdd(Imaging imIn1, Imaging imIn2, float scale, int offset) { + CHOP(((int)in1[x] + (int)in2[x]) / scale + offset); } Imaging -ImagingChopSubtract(Imaging imIn1, Imaging imIn2, float scale, int offset) -{ - CHOP(((int) in1[x] - (int) in2[x]) / scale + offset); +ImagingChopSubtract(Imaging imIn1, Imaging imIn2, float scale, int offset) { + CHOP(((int)in1[x] - (int)in2[x]) / scale + offset); } Imaging -ImagingChopAnd(Imaging imIn1, Imaging imIn2) -{ +ImagingChopAnd(Imaging imIn1, Imaging imIn2) { CHOP2((in1[x] && in2[x]) ? 255 : 0, "1"); } Imaging -ImagingChopOr(Imaging imIn1, Imaging imIn2) -{ +ImagingChopOr(Imaging imIn1, Imaging imIn2) { CHOP2((in1[x] || in2[x]) ? 255 : 0, "1"); } Imaging -ImagingChopXor(Imaging imIn1, Imaging imIn2) -{ +ImagingChopXor(Imaging imIn1, Imaging imIn2) { CHOP2(((in1[x] != 0) ^ (in2[x] != 0)) ? 255 : 0, "1"); } Imaging -ImagingChopAddModulo(Imaging imIn1, Imaging imIn2) -{ +ImagingChopAddModulo(Imaging imIn1, Imaging imIn2) { CHOP2(in1[x] + in2[x], NULL); } Imaging -ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2) -{ +ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2) { CHOP2(in1[x] - in2[x], NULL); } Imaging -ImagingChopSoftLight(Imaging imIn1, Imaging imIn2) -{ - CHOP2( (((255-in1[x]) * (in1[x]*in2[x]) ) / 65536) + - (in1[x] * ( 255 - ( (255 - in1[x]) * (255 - in2[x] ) / 255) )) / 255 - , NULL ); +ImagingChopSoftLight(Imaging imIn1, Imaging imIn2) { + CHOP2( + (((255 - in1[x]) * (in1[x] * in2[x])) / 65536) + + (in1[x] * (255 - ((255 - in1[x]) * (255 - in2[x]) / 255))) / 255, + NULL); } Imaging -ImagingChopHardLight(Imaging imIn1, Imaging imIn2) -{ - CHOP2( (in2[x]<128) ? ( (in1[x]*in2[x])/127) - : 255 - ( ((255-in2[x]) * (255-in1[x])) / 127) - , NULL); +ImagingChopHardLight(Imaging imIn1, Imaging imIn2) { + CHOP2( + (in2[x] < 128) ? ((in1[x] * in2[x]) / 127) + : 255 - (((255 - in2[x]) * (255 - in1[x])) / 127), + NULL); } Imaging -ImagingOverlay(Imaging imIn1, Imaging imIn2) -{ - CHOP2( (in1[x]<128) ? ( (in1[x]*in2[x])/127) - : 255 - ( ((255-in1[x]) * (255-in2[x])) / 127) - , NULL); +ImagingOverlay(Imaging imIn1, Imaging imIn2) { + CHOP2( + (in1[x] < 128) ? ((in1[x] * in2[x]) / 127) + : 255 - (((255 - in1[x]) * (255 - in2[x])) / 127), + NULL); } diff --git a/src/libImaging/ColorLUT.c b/src/libImaging/ColorLUT.c index f01d38993..fd6e268b5 100644 --- a/src/libImaging/ColorLUT.c +++ b/src/libImaging/ColorLUT.c @@ -1,52 +1,45 @@ #include "Imaging.h" #include - /* 8 bits for result. Table can overflow [0, 1.0] range, so we need extra bits for overflow and negative values. NOTE: This value should be the same as in _imaging/_prepare_lut_table() */ #define PRECISION_BITS (16 - 8 - 2) -#define PRECISION_ROUNDING (1<<(PRECISION_BITS-1)) +#define PRECISION_ROUNDING (1 << (PRECISION_BITS - 1)) /* 8 — scales are multiplied on byte. 6 — max index in the table (max size is 65, but index 64 is not reachable) */ #define SCALE_BITS (32 - 8 - 6) -#define SCALE_MASK ((1<> PRECISION_BITS]; } static inline void -interpolate3(INT16 out[3], const INT16 a[3], const INT16 b[3], INT16 shift) -{ - out[0] = (a[0] * ((1<> SHIFT_BITS; - out[1] = (a[1] * ((1<> SHIFT_BITS; - out[2] = (a[2] * ((1<> SHIFT_BITS; +interpolate3(INT16 out[3], const INT16 a[3], const INT16 b[3], INT16 shift) { + out[0] = (a[0] * ((1 << SHIFT_BITS) - shift) + b[0] * shift) >> SHIFT_BITS; + out[1] = (a[1] * ((1 << SHIFT_BITS) - shift) + b[1] * shift) >> SHIFT_BITS; + out[2] = (a[2] * ((1 << SHIFT_BITS) - shift) + b[2] * shift) >> SHIFT_BITS; } static inline void -interpolate4(INT16 out[4], const INT16 a[4], const INT16 b[4], INT16 shift) -{ - out[0] = (a[0] * ((1<> SHIFT_BITS; - out[1] = (a[1] * ((1<> SHIFT_BITS; - out[2] = (a[2] * ((1<> SHIFT_BITS; - out[3] = (a[3] * ((1<> SHIFT_BITS; +interpolate4(INT16 out[4], const INT16 a[4], const INT16 b[4], INT16 shift) { + out[0] = (a[0] * ((1 << SHIFT_BITS) - shift) + b[0] * shift) >> SHIFT_BITS; + out[1] = (a[1] * ((1 << SHIFT_BITS) - shift) + b[1] * shift) >> SHIFT_BITS; + out[2] = (a[2] * ((1 << SHIFT_BITS) - shift) + b[2] * shift) >> SHIFT_BITS; + out[3] = (a[3] * ((1 << SHIFT_BITS) - shift) + b[3] * shift) >> SHIFT_BITS; } static inline int -table_index3D(int index1D, int index2D, int index3D, - int size1D, int size1D_2D) -{ +table_index3D(int index1D, int index2D, int index3D, int size1D, int size1D_2D) { return index1D + index2D * size1D + index3D * size1D_2D; } - /* Transforms colors of imIn using provided 3D lookup table and puts the result in imOut. Returns imOut on success or 0 on error. @@ -63,10 +56,14 @@ table_index3D(int index1D, int index2D, int index3D, and 255 << PRECISION_BITS (16320) is highest value. */ Imaging -ImagingColorLUT3D_linear(Imaging imOut, Imaging imIn, int table_channels, - int size1D, int size2D, int size3D, - INT16* table) -{ +ImagingColorLUT3D_linear( + Imaging imOut, + Imaging imIn, + int table_channels, + int size1D, + int size2D, + int size3D, + INT16 *table) { /* This float to int conversion doesn't have rounding error compensation (+0.5) for two reasons: 1. As we don't hit the highest value, @@ -77,9 +74,9 @@ ImagingColorLUT3D_linear(Imaging imOut, Imaging imIn, int table_channels, +1 cells will be outside of the table. With this compensation we never hit the upper cells but this also doesn't introduce any noticeable difference. */ - UINT32 scale1D = (size1D - 1) / 255.0 * (1<type != IMAGING_TYPE_UINT8 || - imOut->type != IMAGING_TYPE_UINT8 || - imIn->bands < 3 || - imOut->bands < table_channels - ) { - return (Imaging) ImagingError_ModeError(); + if (imIn->type != IMAGING_TYPE_UINT8 || imOut->type != IMAGING_TYPE_UINT8 || + imIn->bands < 3 || imOut->bands < table_channels) { + return (Imaging)ImagingError_ModeError(); } /* In case we have one extra band in imOut and don't have in imIn.*/ if (imOut->bands > table_channels && imOut->bands > imIn->bands) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } ImagingSectionEnter(&cookie); for (y = 0; y < imOut->ysize; y++) { - UINT8* rowIn = (UINT8 *)imIn->image[y]; - char* rowOut = (char *)imOut->image[y]; + UINT8 *rowIn = (UINT8 *)imIn->image[y]; + char *rowOut = (char *)imOut->image[y]; for (x = 0; x < imOut->xsize; x++) { - UINT32 index1D = rowIn[x*4 + 0] * scale1D; - UINT32 index2D = rowIn[x*4 + 1] * scale2D; - UINT32 index3D = rowIn[x*4 + 2] * scale3D; + UINT32 index1D = rowIn[x * 4 + 0] * scale1D; + UINT32 index2D = rowIn[x * 4 + 1] * scale2D; + UINT32 index3D = rowIn[x * 4 + 2] * scale3D; INT16 shift1D = (SCALE_MASK & index1D) >> (SCALE_BITS - SHIFT_BITS); INT16 shift2D = (SCALE_MASK & index2D) >> (SCALE_BITS - SHIFT_BITS); INT16 shift3D = (SCALE_MASK & index3D) >> (SCALE_BITS - SHIFT_BITS); int idx = table_channels * table_index3D( - index1D >> SCALE_BITS, index2D >> SCALE_BITS, - index3D >> SCALE_BITS, size1D, size1D_2D); + index1D >> SCALE_BITS, + index2D >> SCALE_BITS, + index3D >> SCALE_BITS, + size1D, + size1D_2D); INT16 result[4], left[4], right[4]; INT16 leftleft[4], leftright[4], rightleft[4], rightright[4]; if (table_channels == 3) { UINT32 v; interpolate3(leftleft, &table[idx + 0], &table[idx + 3], shift1D); - interpolate3(leftright, &table[idx + size1D*3], - &table[idx + size1D*3 + 3], shift1D); + interpolate3( + leftright, + &table[idx + size1D * 3], + &table[idx + size1D * 3 + 3], + shift1D); interpolate3(left, leftleft, leftright, shift2D); - interpolate3(rightleft, &table[idx + size1D_2D*3], - &table[idx + size1D_2D*3 + 3], shift1D); - interpolate3(rightright, &table[idx + size1D_2D*3 + size1D*3], - &table[idx + size1D_2D*3 + size1D*3 + 3], shift1D); + interpolate3( + rightleft, + &table[idx + size1D_2D * 3], + &table[idx + size1D_2D * 3 + 3], + shift1D); + interpolate3( + rightright, + &table[idx + size1D_2D * 3 + size1D * 3], + &table[idx + size1D_2D * 3 + size1D * 3 + 3], + shift1D); interpolate3(right, rightleft, rightright, shift2D); interpolate3(result, left, right, shift3D); v = MAKE_UINT32( - clip8(result[0]), clip8(result[1]), - clip8(result[2]), rowIn[x*4 + 3]); + clip8(result[0]), + clip8(result[1]), + clip8(result[2]), + rowIn[x * 4 + 3]); memcpy(rowOut + x * sizeof(v), &v, sizeof(v)); } if (table_channels == 4) { UINT32 v; interpolate4(leftleft, &table[idx + 0], &table[idx + 4], shift1D); - interpolate4(leftright, &table[idx + size1D*4], - &table[idx + size1D*4 + 4], shift1D); + interpolate4( + leftright, + &table[idx + size1D * 4], + &table[idx + size1D * 4 + 4], + shift1D); interpolate4(left, leftleft, leftright, shift2D); - interpolate4(rightleft, &table[idx + size1D_2D*4], - &table[idx + size1D_2D*4 + 4], shift1D); - interpolate4(rightright, &table[idx + size1D_2D*4 + size1D*4], - &table[idx + size1D_2D*4 + size1D*4 + 4], shift1D); + interpolate4( + rightleft, + &table[idx + size1D_2D * 4], + &table[idx + size1D_2D * 4 + 4], + shift1D); + interpolate4( + rightright, + &table[idx + size1D_2D * 4 + size1D * 4], + &table[idx + size1D_2D * 4 + size1D * 4 + 4], + shift1D); interpolate4(right, rightleft, rightright, shift2D); interpolate4(result, left, right, shift3D); v = MAKE_UINT32( - clip8(result[0]), clip8(result[1]), - clip8(result[2]), clip8(result[3])); + clip8(result[0]), + clip8(result[1]), + clip8(result[2]), + clip8(result[3])); memcpy(rowOut + x * sizeof(v), &v, sizeof(v)); } } diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index b0b794d72..8c7be36a2 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -32,24 +32,21 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" -#define MAX(a, b) (a)>(b) ? (a) : (b) -#define MIN(a, b) (a)<(b) ? (a) : (b) +#define MAX(a, b) (a) > (b) ? (a) : (b) +#define MIN(a, b) (a) < (b) ? (a) : (b) #define CLIP16(v) ((v) <= -32768 ? -32768 : (v) >= 32767 ? 32767 : (v)) /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */ -#define L(rgb)\ - ((INT32) (rgb)[0]*299 + (INT32) (rgb)[1]*587 + (INT32) (rgb)[2]*114) -#define L24(rgb)\ - ((rgb)[0]*19595 + (rgb)[1]*38470 + (rgb)[2]*7471 + 0x8000) - +#define L(rgb) ((INT32)(rgb)[0] * 299 + (INT32)(rgb)[1] * 587 + (INT32)(rgb)[2] * 114) +#define L24(rgb) ((rgb)[0] * 19595 + (rgb)[1] * 38470 + (rgb)[2] * 7471 + 0x8000) #ifndef round -double round(double x) { - return floor(x+0.5); +double +round(double x) { + return floor(x + 0.5); } #endif @@ -58,16 +55,13 @@ double round(double x) { /* ------------------- */ static void -bit2l(UINT8* out, const UINT8* in, int xsize) -{ +bit2l(UINT8 *out, const UINT8 *in, int xsize) { int x; - for (x = 0; x < xsize; x++) - *out++ = (*in++ != 0) ? 255 : 0; + for (x = 0; x < xsize; x++) *out++ = (*in++ != 0) ? 255 : 0; } static void -bit2rgb(UINT8* out, const UINT8* in, int xsize) -{ +bit2rgb(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { UINT8 v = (*in++ != 0) ? 255 : 0; @@ -79,8 +73,7 @@ bit2rgb(UINT8* out, const UINT8* in, int xsize) } static void -bit2cmyk(UINT8* out, const UINT8* in, int xsize) -{ +bit2cmyk(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { *out++ = 0; @@ -91,8 +84,7 @@ bit2cmyk(UINT8* out, const UINT8* in, int xsize) } static void -bit2ycbcr(UINT8* out, const UINT8* in, int xsize) -{ +bit2ycbcr(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { *out++ = (*in++ != 0) ? 255 : 0; @@ -103,8 +95,7 @@ bit2ycbcr(UINT8* out, const UINT8* in, int xsize) } static void -bit2hsv(UINT8* out, const UINT8* in, int xsize) -{ +bit2hsv(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, out += 4) { UINT8 v = (*in++ != 0) ? 255 : 0; @@ -120,8 +111,7 @@ bit2hsv(UINT8* out, const UINT8* in, int xsize) /* ----------------- */ static void -l2bit(UINT8* out, const UINT8* in, int xsize) -{ +l2bit(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { *out++ = (*in++ >= 128) ? 255 : 0; @@ -129,44 +119,41 @@ l2bit(UINT8* out, const UINT8* in, int xsize) } static void -lA2la(UINT8* out, const UINT8* in, int xsize) -{ +lA2la(UINT8 *out, const UINT8 *in, int xsize) { int x; unsigned int alpha, pixel, tmp; for (x = 0; x < xsize; x++, in += 4) { alpha = in[3]; pixel = MULDIV255(in[0], alpha, tmp); - *out++ = (UINT8) pixel; - *out++ = (UINT8) pixel; - *out++ = (UINT8) pixel; - *out++ = (UINT8) alpha; + *out++ = (UINT8)pixel; + *out++ = (UINT8)pixel; + *out++ = (UINT8)pixel; + *out++ = (UINT8)alpha; } } /* RGBa -> RGBA conversion to remove premultiplication Needed for correct transforms/resizing on RGBA images */ static void -la2lA(UINT8* out, const UINT8* in, int xsize) -{ +la2lA(UINT8 *out, const UINT8 *in, int xsize) { int x; unsigned int alpha, pixel; - for (x = 0; x < xsize; x++, in+=4) { + for (x = 0; x < xsize; x++, in += 4) { alpha = in[3]; if (alpha == 255 || alpha == 0) { pixel = in[0]; } else { pixel = CLIP8((255 * in[0]) / alpha); } - *out++ = (UINT8) pixel; - *out++ = (UINT8) pixel; - *out++ = (UINT8) pixel; - *out++ = (UINT8) alpha; + *out++ = (UINT8)pixel; + *out++ = (UINT8)pixel; + *out++ = (UINT8)pixel; + *out++ = (UINT8)alpha; } } static void -l2la(UINT8* out, const UINT8* in, int xsize) -{ +l2la(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { UINT8 v = *in++; @@ -178,8 +165,7 @@ l2la(UINT8* out, const UINT8* in, int xsize) } static void -l2rgb(UINT8* out, const UINT8* in, int xsize) -{ +l2rgb(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { UINT8 v = *in++; @@ -191,8 +177,7 @@ l2rgb(UINT8* out, const UINT8* in, int xsize) } static void -l2hsv(UINT8* out, const UINT8* in, int xsize) -{ +l2hsv(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, out += 4) { UINT8 v = *in++; @@ -204,8 +189,7 @@ l2hsv(UINT8* out, const UINT8* in, int xsize) } static void -la2l(UINT8* out, const UINT8* in, int xsize) -{ +la2l(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4) { *out++ = in[0]; @@ -213,8 +197,7 @@ la2l(UINT8* out, const UINT8* in, int xsize) } static void -la2rgb(UINT8* out, const UINT8* in, int xsize) -{ +la2rgb(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4) { UINT8 v = in[0]; @@ -226,8 +209,7 @@ la2rgb(UINT8* out, const UINT8* in, int xsize) } static void -la2hsv(UINT8* out, const UINT8* in, int xsize) -{ +la2hsv(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out += 4) { UINT8 v = in[0]; @@ -239,8 +221,7 @@ la2hsv(UINT8* out, const UINT8* in, int xsize) } static void -rgb2bit(UINT8* out, const UINT8* in, int xsize) -{ +rgb2bit(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4) { /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */ @@ -249,8 +230,7 @@ rgb2bit(UINT8* out, const UINT8* in, int xsize) } static void -rgb2l(UINT8* out, const UINT8* in, int xsize) -{ +rgb2l(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4) { /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */ @@ -259,8 +239,7 @@ rgb2l(UINT8* out, const UINT8* in, int xsize) } static void -rgb2la(UINT8* out, const UINT8* in, int xsize) -{ +rgb2la(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out += 4) { /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */ @@ -270,8 +249,7 @@ rgb2la(UINT8* out, const UINT8* in, int xsize) } static void -rgb2i(UINT8* out_, const UINT8* in, int xsize) -{ +rgb2i(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out_ += 4) { INT32 v = L24(in) >> 16; @@ -280,44 +258,38 @@ rgb2i(UINT8* out_, const UINT8* in, int xsize) } static void -rgb2f(UINT8* out_, const UINT8* in, int xsize) -{ +rgb2f(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out_ += 4) { - FLOAT32 v = (float) L(in) / 1000.0F; + FLOAT32 v = (float)L(in) / 1000.0F; memcpy(out_, &v, sizeof(v)); } } static void -rgb2bgr15(UINT8* out_, const UINT8* in, int xsize) -{ +rgb2bgr15(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out_ += 2) { - UINT16 v = - ((((UINT16)in[0])<<7)&0x7c00) + - ((((UINT16)in[1])<<2)&0x03e0) + - ((((UINT16)in[2])>>3)&0x001f); + UINT16 v = ((((UINT16)in[0]) << 7) & 0x7c00) + + ((((UINT16)in[1]) << 2) & 0x03e0) + + ((((UINT16)in[2]) >> 3) & 0x001f); memcpy(out_, &v, sizeof(v)); } } static void -rgb2bgr16(UINT8* out_, const UINT8* in, int xsize) -{ +rgb2bgr16(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out_ += 2) { - UINT16 v = - ((((UINT16)in[0])<<8)&0xf800) + - ((((UINT16)in[1])<<3)&0x07e0) + - ((((UINT16)in[2])>>3)&0x001f); + UINT16 v = ((((UINT16)in[0]) << 8) & 0xf800) + + ((((UINT16)in[1]) << 3) & 0x07e0) + + ((((UINT16)in[2]) >> 3) & 0x001f); memcpy(out_, &v, sizeof(v)); } } static void -rgb2bgr24(UINT8* out, const UINT8* in, int xsize) -{ +rgb2bgr24(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4) { *out++ = in[2]; @@ -327,40 +299,39 @@ rgb2bgr24(UINT8* out, const UINT8* in, int xsize) } static void -rgb2hsv_row(UINT8* out, const UINT8* in) -{ // following colorsys.py - float h,s,rc,gc,bc,cr; - UINT8 maxc,minc; +rgb2hsv_row(UINT8 *out, const UINT8 *in) { // following colorsys.py + float h, s, rc, gc, bc, cr; + UINT8 maxc, minc; UINT8 r, g, b; - UINT8 uh,us,uv; + UINT8 uh, us, uv; r = in[0]; g = in[1]; b = in[2]; - maxc = MAX(r,MAX(g,b)); - minc = MIN(r,MIN(g,b)); + maxc = MAX(r, MAX(g, b)); + minc = MIN(r, MIN(g, b)); uv = maxc; - if (minc == maxc){ + if (minc == maxc) { uh = 0; us = 0; } else { - cr = (float)(maxc-minc); - s = cr/(float)maxc; - rc = ((float)(maxc-r))/cr; - gc = ((float)(maxc-g))/cr; - bc = ((float)(maxc-b))/cr; + cr = (float)(maxc - minc); + s = cr / (float)maxc; + rc = ((float)(maxc - r)) / cr; + gc = ((float)(maxc - g)) / cr; + bc = ((float)(maxc - b)) / cr; if (r == maxc) { - h = bc-gc; + h = bc - gc; } else if (g == maxc) { - h = 2.0 + rc-bc; + h = 2.0 + rc - bc; } else { - h = 4.0 + gc-rc; + h = 4.0 + gc - rc; } // incorrect hue happens if h/6 is negative. - h = fmod((h/6.0 + 1.0), 1.0); + h = fmod((h / 6.0 + 1.0), 1.0); - uh = (UINT8)CLIP8((int)(h*255.0)); - us = (UINT8)CLIP8((int)(s*255.0)); + uh = (UINT8)CLIP8((int)(h * 255.0)); + us = (UINT8)CLIP8((int)(s * 255.0)); } out[0] = uh; out[1] = us; @@ -368,8 +339,7 @@ rgb2hsv_row(UINT8* out, const UINT8* in) } static void -rgb2hsv(UINT8* out, const UINT8* in, int xsize) -{ +rgb2hsv(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out += 4) { rgb2hsv_row(out, in); @@ -377,98 +347,91 @@ rgb2hsv(UINT8* out, const UINT8* in, int xsize) } } - - static void -hsv2rgb(UINT8* out, const UINT8* in, int xsize) -{ // following colorsys.py +hsv2rgb(UINT8 *out, const UINT8 *in, int xsize) { // following colorsys.py - int p,q,t; - UINT8 up,uq,ut; + int p, q, t; + UINT8 up, uq, ut; int i, x; float f, fs; - UINT8 h,s,v; + UINT8 h, s, v; for (x = 0; x < xsize; x++, in += 4) { h = in[0]; s = in[1]; v = in[2]; - if (s==0){ + if (s == 0) { *out++ = v; *out++ = v; *out++ = v; } else { - i = floor((float)h * 6.0 / 255.0); // 0 - 6 - f = (float)h * 6.0 / 255.0 - (float)i; // 0-1 : remainder. - fs = ((float)s)/255.0; + i = floor((float)h * 6.0 / 255.0); // 0 - 6 + f = (float)h * 6.0 / 255.0 - (float)i; // 0-1 : remainder. + fs = ((float)s) / 255.0; - p = round((float)v * (1.0-fs)); - q = round((float)v * (1.0-fs*f)); - t = round((float)v * (1.0-fs*(1.0-f))); + p = round((float)v * (1.0 - fs)); + q = round((float)v * (1.0 - fs * f)); + t = round((float)v * (1.0 - fs * (1.0 - f))); up = (UINT8)CLIP8(p); uq = (UINT8)CLIP8(q); ut = (UINT8)CLIP8(t); - switch (i%6) { - case 0: - *out++ = v; - *out++ = ut; - *out++ = up; - break; - case 1: - *out++ = uq; - *out++ = v; - *out++ = up; - break; - case 2: - *out++ = up; - *out++ = v; - *out++ = ut; - break; - case 3: - *out++ = up; - *out++ = uq; - *out++ = v; - break; - case 4: - *out++ = ut; - *out++ = up; - *out++ = v; - break; - case 5: - *out++ = v; - *out++ = up; - *out++ = uq; - break; - + switch (i % 6) { + case 0: + *out++ = v; + *out++ = ut; + *out++ = up; + break; + case 1: + *out++ = uq; + *out++ = v; + *out++ = up; + break; + case 2: + *out++ = up; + *out++ = v; + *out++ = ut; + break; + case 3: + *out++ = up; + *out++ = uq; + *out++ = v; + break; + case 4: + *out++ = ut; + *out++ = up; + *out++ = v; + break; + case 5: + *out++ = v; + *out++ = up; + *out++ = uq; + break; } } *out++ = in[3]; } } - - /* ---------------- */ /* RGBA conversions */ /* ---------------- */ static void -rgb2rgba(UINT8* out, const UINT8* in, int xsize) -{ +rgb2rgba(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { *out++ = *in++; *out++ = *in++; *out++ = *in++; - *out++ = 255; in++; + *out++ = 255; + in++; } } static void -rgba2la(UINT8* out, const UINT8* in, int xsize) -{ +rgba2la(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out += 4) { /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */ @@ -478,20 +441,19 @@ rgba2la(UINT8* out, const UINT8* in, int xsize) } static void -rgba2rgb(UINT8* out, const UINT8* in, int xsize) -{ +rgba2rgb(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { *out++ = *in++; *out++ = *in++; *out++ = *in++; - *out++ = 255; in++; + *out++ = 255; + in++; } } static void -rgbA2rgba(UINT8* out, const UINT8* in, int xsize) -{ +rgbA2rgba(UINT8 *out, const UINT8 *in, int xsize) { int x; unsigned int alpha, tmp; for (x = 0; x < xsize; x++) { @@ -506,11 +468,10 @@ rgbA2rgba(UINT8* out, const UINT8* in, int xsize) /* RGBa -> RGBA conversion to remove premultiplication Needed for correct transforms/resizing on RGBA images */ static void -rgba2rgbA(UINT8* out, const UINT8* in, int xsize) -{ +rgba2rgbA(UINT8 *out, const UINT8 *in, int xsize) { int x; unsigned int alpha; - for (x = 0; x < xsize; x++, in+=4) { + for (x = 0; x < xsize; x++, in += 4) { alpha = in[3]; if (alpha == 255 || alpha == 0) { *out++ = in[0]; @@ -532,35 +493,32 @@ rgba2rgbA(UINT8* out, const UINT8* in, int xsize) */ static void -rgbT2rgba(UINT8* out, int xsize, int r, int g, int b) -{ +rgbT2rgba(UINT8 *out, int xsize, int r, int g, int b) { #ifdef WORDS_BIGENDIAN - UINT32 trns = ((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | 0xff; + UINT32 trns = ((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8) | 0xff; UINT32 repl = trns & 0xffffff00; #else - UINT32 trns = (0xff <<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff); + UINT32 trns = (0xff << 24) | ((b & 0xff) << 16) | ((g & 0xff) << 8) | (r & 0xff); UINT32 repl = trns & 0x00ffffff; #endif int i; - for (i=0; i < xsize; i++ ,out += sizeof(trns)) { + for (i = 0; i < xsize; i++, out += sizeof(trns)) { UINT32 v; memcpy(&v, out, sizeof(v)); - if (v==trns) { + if (v == trns) { memcpy(out, &repl, sizeof(repl)); } } } - /* ---------------- */ /* CMYK conversions */ /* ---------------- */ static void -l2cmyk(UINT8* out, const UINT8* in, int xsize) -{ +l2cmyk(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { *out++ = 0; @@ -571,8 +529,7 @@ l2cmyk(UINT8* out, const UINT8* in, int xsize) } static void -la2cmyk(UINT8* out, const UINT8* in, int xsize) -{ +la2cmyk(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4) { *out++ = 0; @@ -583,21 +540,20 @@ la2cmyk(UINT8* out, const UINT8* in, int xsize) } static void -rgb2cmyk(UINT8* out, const UINT8* in, int xsize) -{ +rgb2cmyk(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { /* Note: no undercolour removal */ *out++ = ~(*in++); *out++ = ~(*in++); *out++ = ~(*in++); - *out++ = 0; in++; + *out++ = 0; + in++; } } static void -cmyk2rgb(UINT8* out, const UINT8* in, int xsize) -{ +cmyk2rgb(UINT8 *out, const UINT8 *in, int xsize) { int x, nk, tmp; for (x = 0; x < xsize; x++) { nk = 255 - in[3]; @@ -611,8 +567,7 @@ cmyk2rgb(UINT8* out, const UINT8* in, int xsize) } static void -cmyk2hsv(UINT8* out, const UINT8* in, int xsize) -{ +cmyk2hsv(UINT8 *out, const UINT8 *in, int xsize) { int x, nk, tmp; for (x = 0; x < xsize; x++) { nk = 255 - in[3]; @@ -631,8 +586,7 @@ cmyk2hsv(UINT8* out, const UINT8* in, int xsize) /* ------------- */ static void -bit2i(UINT8* out_, const UINT8* in, int xsize) -{ +bit2i(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, out_ += 4) { INT32 v = (*in++ != 0) ? 255 : 0; @@ -641,8 +595,7 @@ bit2i(UINT8* out_, const UINT8* in, int xsize) } static void -l2i(UINT8* out_, const UINT8* in, int xsize) -{ +l2i(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, out_ += 4) { INT32 v = *in++; @@ -651,8 +604,7 @@ l2i(UINT8* out_, const UINT8* in, int xsize) } static void -i2l(UINT8* out, const UINT8* in_, int xsize) -{ +i2l(UINT8 *out, const UINT8 *in_, int xsize) { int x; for (x = 0; x < xsize; x++, out++, in_ += 4) { INT32 v; @@ -662,14 +614,13 @@ i2l(UINT8* out, const UINT8* in_, int xsize) } else if (v >= 255) { *out = 255; } else { - *out = (UINT8) v; + *out = (UINT8)v; } } } static void -i2f(UINT8* out_, const UINT8* in_, int xsize) -{ +i2f(UINT8 *out_, const UINT8 *in_, int xsize) { int x; for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) { INT32 i; @@ -681,28 +632,26 @@ i2f(UINT8* out_, const UINT8* in_, int xsize) } static void -i2rgb(UINT8* out, const UINT8* in_, int xsize) -{ +i2rgb(UINT8 *out, const UINT8 *in_, int xsize) { int x; - INT32* in = (INT32*) in_; - for (x = 0; x < xsize; x++, in++, out+=4) { + INT32 *in = (INT32 *)in_; + for (x = 0; x < xsize; x++, in++, out += 4) { if (*in <= 0) { out[0] = out[1] = out[2] = 0; } else if (*in >= 255) { out[0] = out[1] = out[2] = 255; } else { - out[0] = out[1] = out[2] = (UINT8) *in; + out[0] = out[1] = out[2] = (UINT8)*in; } out[3] = 255; } } static void -i2hsv(UINT8* out, const UINT8* in_, int xsize) -{ +i2hsv(UINT8 *out, const UINT8 *in_, int xsize) { int x; - INT32* in = (INT32*) in_; - for (x = 0; x < xsize; x++, in++, out+=4) { + INT32 *in = (INT32 *)in_; + for (x = 0; x < xsize; x++, in++, out += 4) { out[0] = 0; out[1] = 0; if (*in <= 0) { @@ -710,7 +659,7 @@ i2hsv(UINT8* out, const UINT8* in_, int xsize) } else if (*in >= 255) { out[2] = 255; } else { - out[2] = (UINT8) *in; + out[2] = (UINT8)*in; } out[3] = 255; } @@ -721,8 +670,7 @@ i2hsv(UINT8* out, const UINT8* in_, int xsize) /* ------------- */ static void -bit2f(UINT8* out_, const UINT8* in, int xsize) -{ +bit2f(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, out_ += 4) { FLOAT32 f = (*in++ != 0) ? 255.0F : 0.0F; @@ -731,18 +679,16 @@ bit2f(UINT8* out_, const UINT8* in, int xsize) } static void -l2f(UINT8* out_, const UINT8* in, int xsize) -{ +l2f(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, out_ += 4) { - FLOAT32 f = (FLOAT32) *in++; + FLOAT32 f = (FLOAT32)*in++; memcpy(out_, &f, sizeof(f)); } } static void -f2l(UINT8* out, const UINT8* in_, int xsize) -{ +f2l(UINT8 *out, const UINT8 *in_, int xsize) { int x; for (x = 0; x < xsize; x++, out++, in_ += 4) { FLOAT32 v; @@ -752,14 +698,13 @@ f2l(UINT8* out, const UINT8* in_, int xsize) } else if (v >= 255.0) { *out = 255; } else { - *out = (UINT8) v; + *out = (UINT8)v; } } } static void -f2i(UINT8* out_, const UINT8* in_, int xsize) -{ +f2i(UINT8 *out_, const UINT8 *in_, int xsize) { int x; for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) { FLOAT32 f; @@ -777,8 +722,7 @@ f2i(UINT8* out_, const UINT8* in_, int xsize) /* See ConvertYCbCr.c for RGB/YCbCr tables */ static void -l2ycbcr(UINT8* out, const UINT8* in, int xsize) -{ +l2ycbcr(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++) { *out++ = *in++; @@ -789,8 +733,7 @@ l2ycbcr(UINT8* out, const UINT8* in, int xsize) } static void -la2ycbcr(UINT8* out, const UINT8* in, int xsize) -{ +la2ycbcr(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4) { *out++ = in[0]; @@ -801,8 +744,7 @@ la2ycbcr(UINT8* out, const UINT8* in, int xsize) } static void -ycbcr2l(UINT8* out, const UINT8* in, int xsize) -{ +ycbcr2l(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4) { *out++ = in[0]; @@ -810,8 +752,7 @@ ycbcr2l(UINT8* out, const UINT8* in, int xsize) } static void -ycbcr2la(UINT8* out, const UINT8* in, int xsize) -{ +ycbcr2la(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 4, out += 4) { out[0] = out[1] = out[2] = in[0]; @@ -824,77 +765,67 @@ ycbcr2la(UINT8* out, const UINT8* in, int xsize) /* ------------------------- */ static void -I_I16L(UINT8* out, const UINT8* in_, int xsize) -{ +I_I16L(UINT8 *out, const UINT8 *in_, int xsize) { int x, v; for (x = 0; x < xsize; x++, in_ += 4) { INT32 i; memcpy(&i, in_, sizeof(i)); v = CLIP16(i); - *out++ = (UINT8) v; - *out++ = (UINT8) (v >> 8); + *out++ = (UINT8)v; + *out++ = (UINT8)(v >> 8); } } static void -I_I16B(UINT8* out, const UINT8* in_, int xsize) -{ +I_I16B(UINT8 *out, const UINT8 *in_, int xsize) { int x, v; for (x = 0; x < xsize; x++, in_ += 4) { INT32 i; memcpy(&i, in_, sizeof(i)); v = CLIP16(i); - *out++ = (UINT8) (v >> 8); - *out++ = (UINT8) v; + *out++ = (UINT8)(v >> 8); + *out++ = (UINT8)v; } } - static void -I16L_I(UINT8* out_, const UINT8* in, int xsize) -{ +I16L_I(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 2, out_ += 4) { - INT32 v = in[0] + ((int) in[1] << 8); - memcpy(out_, &v, sizeof(v)); - } -} - - -static void -I16B_I(UINT8* out_, const UINT8* in, int xsize) -{ - int x; - for (x = 0; x < xsize; x++, in += 2, out_ += 4) { - INT32 v = in[1] + ((int) in[0] << 8); + INT32 v = in[0] + ((int)in[1] << 8); memcpy(out_, &v, sizeof(v)); } } static void -I16L_F(UINT8* out_, const UINT8* in, int xsize) -{ +I16B_I(UINT8 *out_, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 2, out_ += 4) { - FLOAT32 v = in[0] + ((int) in[1] << 8); - memcpy(out_, &v, sizeof(v)); - } -} - - -static void -I16B_F(UINT8* out_, const UINT8* in, int xsize) -{ - int x; - for (x = 0; x < xsize; x++, in += 2, out_ += 4) { - FLOAT32 v = in[1] + ((int) in[0] << 8); + INT32 v = in[1] + ((int)in[0] << 8); memcpy(out_, &v, sizeof(v)); } } static void -L_I16L(UINT8* out, const UINT8* in, int xsize) -{ +I16L_F(UINT8 *out_, const UINT8 *in, int xsize) { + int x; + for (x = 0; x < xsize; x++, in += 2, out_ += 4) { + FLOAT32 v = in[0] + ((int)in[1] << 8); + memcpy(out_, &v, sizeof(v)); + } +} + +static void +I16B_F(UINT8 *out_, const UINT8 *in, int xsize) { + int x; + for (x = 0; x < xsize; x++, in += 2, out_ += 4) { + FLOAT32 v = in[1] + ((int)in[0] << 8); + memcpy(out_, &v, sizeof(v)); + } +} + +static void +L_I16L(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in++) { *out++ = *in; @@ -903,8 +834,7 @@ L_I16L(UINT8* out, const UINT8* in, int xsize) } static void -L_I16B(UINT8* out, const UINT8* in, int xsize) -{ +L_I16B(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in++) { *out++ = 0; @@ -913,8 +843,7 @@ L_I16B(UINT8* out, const UINT8* in, int xsize) } static void -I16L_L(UINT8* out, const UINT8* in, int xsize) -{ +I16L_L(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 2) { if (in[1] != 0) { @@ -926,8 +855,7 @@ I16L_L(UINT8* out, const UINT8* in, int xsize) } static void -I16B_L(UINT8* out, const UINT8* in, int xsize) -{ +I16B_L(UINT8 *out, const UINT8 *in, int xsize) { int x; for (x = 0; x < xsize; x++, in += 2) { if (in[0] != 0) { @@ -939,123 +867,122 @@ I16B_L(UINT8* out, const UINT8* in, int xsize) } static struct { - const char* from; - const char* to; + const char *from; + const char *to; ImagingShuffler convert; } converters[] = { - { "1", "L", bit2l }, - { "1", "I", bit2i }, - { "1", "F", bit2f }, - { "1", "RGB", bit2rgb }, - { "1", "RGBA", bit2rgb }, - { "1", "RGBX", bit2rgb }, - { "1", "CMYK", bit2cmyk }, - { "1", "YCbCr", bit2ycbcr }, - { "1", "HSV", bit2hsv }, + {"1", "L", bit2l}, + {"1", "I", bit2i}, + {"1", "F", bit2f}, + {"1", "RGB", bit2rgb}, + {"1", "RGBA", bit2rgb}, + {"1", "RGBX", bit2rgb}, + {"1", "CMYK", bit2cmyk}, + {"1", "YCbCr", bit2ycbcr}, + {"1", "HSV", bit2hsv}, - { "L", "1", l2bit }, - { "L", "LA", l2la }, - { "L", "I", l2i }, - { "L", "F", l2f }, - { "L", "RGB", l2rgb }, - { "L", "RGBA", l2rgb }, - { "L", "RGBX", l2rgb }, - { "L", "CMYK", l2cmyk }, - { "L", "YCbCr", l2ycbcr }, - { "L", "HSV", l2hsv }, + {"L", "1", l2bit}, + {"L", "LA", l2la}, + {"L", "I", l2i}, + {"L", "F", l2f}, + {"L", "RGB", l2rgb}, + {"L", "RGBA", l2rgb}, + {"L", "RGBX", l2rgb}, + {"L", "CMYK", l2cmyk}, + {"L", "YCbCr", l2ycbcr}, + {"L", "HSV", l2hsv}, - { "LA", "L", la2l }, - { "LA", "La", lA2la }, - { "LA", "RGB", la2rgb }, - { "LA", "RGBA", la2rgb }, - { "LA", "RGBX", la2rgb }, - { "LA", "CMYK", la2cmyk }, - { "LA", "YCbCr", la2ycbcr }, - { "LA", "HSV", la2hsv }, + {"LA", "L", la2l}, + {"LA", "La", lA2la}, + {"LA", "RGB", la2rgb}, + {"LA", "RGBA", la2rgb}, + {"LA", "RGBX", la2rgb}, + {"LA", "CMYK", la2cmyk}, + {"LA", "YCbCr", la2ycbcr}, + {"LA", "HSV", la2hsv}, - { "La", "LA", la2lA }, + {"La", "LA", la2lA}, - { "I", "L", i2l }, - { "I", "F", i2f }, - { "I", "RGB", i2rgb }, - { "I", "RGBA", i2rgb }, - { "I", "RGBX", i2rgb }, - { "I", "HSV", i2hsv }, + {"I", "L", i2l}, + {"I", "F", i2f}, + {"I", "RGB", i2rgb}, + {"I", "RGBA", i2rgb}, + {"I", "RGBX", i2rgb}, + {"I", "HSV", i2hsv}, - { "F", "L", f2l }, - { "F", "I", f2i }, + {"F", "L", f2l}, + {"F", "I", f2i}, - { "RGB", "1", rgb2bit }, - { "RGB", "L", rgb2l }, - { "RGB", "LA", rgb2la }, - { "RGB", "I", rgb2i }, - { "RGB", "F", rgb2f }, - { "RGB", "BGR;15", rgb2bgr15 }, - { "RGB", "BGR;16", rgb2bgr16 }, - { "RGB", "BGR;24", rgb2bgr24 }, - { "RGB", "RGBA", rgb2rgba }, - { "RGB", "RGBX", rgb2rgba }, - { "RGB", "CMYK", rgb2cmyk }, - { "RGB", "YCbCr", ImagingConvertRGB2YCbCr }, - { "RGB", "HSV", rgb2hsv }, + {"RGB", "1", rgb2bit}, + {"RGB", "L", rgb2l}, + {"RGB", "LA", rgb2la}, + {"RGB", "I", rgb2i}, + {"RGB", "F", rgb2f}, + {"RGB", "BGR;15", rgb2bgr15}, + {"RGB", "BGR;16", rgb2bgr16}, + {"RGB", "BGR;24", rgb2bgr24}, + {"RGB", "RGBA", rgb2rgba}, + {"RGB", "RGBX", rgb2rgba}, + {"RGB", "CMYK", rgb2cmyk}, + {"RGB", "YCbCr", ImagingConvertRGB2YCbCr}, + {"RGB", "HSV", rgb2hsv}, - { "RGBA", "1", rgb2bit }, - { "RGBA", "L", rgb2l }, - { "RGBA", "LA", rgba2la }, - { "RGBA", "I", rgb2i }, - { "RGBA", "F", rgb2f }, - { "RGBA", "RGB", rgba2rgb }, - { "RGBA", "RGBa", rgbA2rgba }, - { "RGBA", "RGBX", rgb2rgba }, - { "RGBA", "CMYK", rgb2cmyk }, - { "RGBA", "YCbCr", ImagingConvertRGB2YCbCr }, - { "RGBA", "HSV", rgb2hsv }, + {"RGBA", "1", rgb2bit}, + {"RGBA", "L", rgb2l}, + {"RGBA", "LA", rgba2la}, + {"RGBA", "I", rgb2i}, + {"RGBA", "F", rgb2f}, + {"RGBA", "RGB", rgba2rgb}, + {"RGBA", "RGBa", rgbA2rgba}, + {"RGBA", "RGBX", rgb2rgba}, + {"RGBA", "CMYK", rgb2cmyk}, + {"RGBA", "YCbCr", ImagingConvertRGB2YCbCr}, + {"RGBA", "HSV", rgb2hsv}, - { "RGBa", "RGBA", rgba2rgbA }, + {"RGBa", "RGBA", rgba2rgbA}, - { "RGBX", "1", rgb2bit }, - { "RGBX", "L", rgb2l }, - { "RGBX", "LA", rgb2la }, - { "RGBX", "I", rgb2i }, - { "RGBX", "F", rgb2f }, - { "RGBX", "RGB", rgba2rgb }, - { "RGBX", "CMYK", rgb2cmyk }, - { "RGBX", "YCbCr", ImagingConvertRGB2YCbCr }, - { "RGBX", "HSV", rgb2hsv }, + {"RGBX", "1", rgb2bit}, + {"RGBX", "L", rgb2l}, + {"RGBX", "LA", rgb2la}, + {"RGBX", "I", rgb2i}, + {"RGBX", "F", rgb2f}, + {"RGBX", "RGB", rgba2rgb}, + {"RGBX", "CMYK", rgb2cmyk}, + {"RGBX", "YCbCr", ImagingConvertRGB2YCbCr}, + {"RGBX", "HSV", rgb2hsv}, - { "CMYK", "RGB", cmyk2rgb }, - { "CMYK", "RGBA", cmyk2rgb }, - { "CMYK", "RGBX", cmyk2rgb }, - { "CMYK", "HSV", cmyk2hsv }, + {"CMYK", "RGB", cmyk2rgb}, + {"CMYK", "RGBA", cmyk2rgb}, + {"CMYK", "RGBX", cmyk2rgb}, + {"CMYK", "HSV", cmyk2hsv}, - { "YCbCr", "L", ycbcr2l }, - { "YCbCr", "LA", ycbcr2la }, - { "YCbCr", "RGB", ImagingConvertYCbCr2RGB }, + {"YCbCr", "L", ycbcr2l}, + {"YCbCr", "LA", ycbcr2la}, + {"YCbCr", "RGB", ImagingConvertYCbCr2RGB}, - { "HSV", "RGB", hsv2rgb }, + {"HSV", "RGB", hsv2rgb}, - { "I", "I;16", I_I16L }, - { "I;16", "I", I16L_I }, - { "L", "I;16", L_I16L }, - { "I;16", "L", I16L_L }, + {"I", "I;16", I_I16L}, + {"I;16", "I", I16L_I}, + {"L", "I;16", L_I16L}, + {"I;16", "L", I16L_L}, - { "I", "I;16L", I_I16L }, - { "I;16L", "I", I16L_I }, - { "I", "I;16B", I_I16B }, - { "I;16B", "I", I16B_I }, + {"I", "I;16L", I_I16L}, + {"I;16L", "I", I16L_I}, + {"I", "I;16B", I_I16B}, + {"I;16B", "I", I16B_I}, - { "L", "I;16L", L_I16L }, - { "I;16L", "L", I16L_L }, - { "L", "I;16B", L_I16B }, - { "I;16B", "L", I16B_L }, + {"L", "I;16L", L_I16L}, + {"I;16L", "L", I16L_L}, + {"L", "I;16B", L_I16B}, + {"I;16B", "L", I16B_L}, - { "I;16", "F", I16L_F }, - { "I;16L", "F", I16L_F }, - { "I;16B", "F", I16B_F }, + {"I;16", "F", I16L_F}, + {"I;16L", "F", I16L_F}, + {"I;16B", "F", I16B_F}, - { NULL } -}; + {NULL}}; /* FIXME: translate indexed versions to pointer versions below this line */ @@ -1064,51 +991,46 @@ static struct { /* ------------------- */ static void -p2bit(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2bit(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; /* FIXME: precalculate greyscale palette? */ for (x = 0; x < xsize; x++) { - *out++ = (L(&palette[in[x]*4]) >= 128000) ? 255 : 0; + *out++ = (L(&palette[in[x] * 4]) >= 128000) ? 255 : 0; } } static void -pa2bit(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2bit(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; /* FIXME: precalculate greyscale palette? */ for (x = 0; x < xsize; x++, in += 4) { - *out++ = (L(&palette[in[0]*4]) >= 128000) ? 255 : 0; + *out++ = (L(&palette[in[0] * 4]) >= 128000) ? 255 : 0; } } static void -p2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2l(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; /* FIXME: precalculate greyscale palette? */ for (x = 0; x < xsize; x++) { - *out++ = L(&palette[in[x]*4]) / 1000; + *out++ = L(&palette[in[x] * 4]) / 1000; } } static void -pa2l(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2l(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; /* FIXME: precalculate greyscale palette? */ for (x = 0; x < xsize; x++, in += 4) { - *out++ = L(&palette[in[0]*4]) / 1000; + *out++ = L(&palette[in[0] * 4]) / 1000; } } static void -p2pa(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2pa(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++, in++) { - const UINT8* rgba = &palette[in[0]]; + const UINT8 *rgba = &palette[in[0]]; *out++ = in[0]; *out++ = in[0]; *out++ = in[0]; @@ -1117,74 +1039,67 @@ p2pa(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) } static void -p2la(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2la(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; /* FIXME: precalculate greyscale palette? */ - for (x = 0; x < xsize; x++, out+=4) { - const UINT8* rgba = &palette[*in++ * 4]; + for (x = 0; x < xsize; x++, out += 4) { + const UINT8 *rgba = &palette[*in++ * 4]; out[0] = out[1] = out[2] = L(rgba) / 1000; out[3] = rgba[3]; } } static void -pa2la(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2la(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; /* FIXME: precalculate greyscale palette? */ for (x = 0; x < xsize; x++, in += 4, out += 4) { - out[0] = out[1] = out[2] = L(&palette[in[0]*4]) / 1000; + out[0] = out[1] = out[2] = L(&palette[in[0] * 4]) / 1000; out[3] = in[3]; } } static void -p2i(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette) -{ +p2i(UINT8 *out_, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++, out_ += 4) { - INT32 v = L(&palette[in[x]*4]) / 1000; + INT32 v = L(&palette[in[x] * 4]) / 1000; memcpy(out_, &v, sizeof(v)); } } static void -pa2i(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2i(UINT8 *out_, const UINT8 *in, int xsize, const UINT8 *palette) { int x; - INT32* out = (INT32*) out_; + INT32 *out = (INT32 *)out_; for (x = 0; x < xsize; x++, in += 4) { - *out++ = L(&palette[in[0]*4]) / 1000; + *out++ = L(&palette[in[0] * 4]) / 1000; } } static void -p2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette) -{ +p2f(UINT8 *out_, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++, out_ += 4) { - FLOAT32 v = L(&palette[in[x]*4]) / 1000.0F; + FLOAT32 v = L(&palette[in[x] * 4]) / 1000.0F; memcpy(out_, &v, sizeof(v)); } } static void -pa2f(UINT8* out_, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2f(UINT8 *out_, const UINT8 *in, int xsize, const UINT8 *palette) { int x; - FLOAT32* out = (FLOAT32*) out_; + FLOAT32 *out = (FLOAT32 *)out_; for (x = 0; x < xsize; x++, in += 4) { - *out++ = (float) L(&palette[in[0]*4]) / 1000.0F; + *out++ = (float)L(&palette[in[0] * 4]) / 1000.0F; } } static void -p2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2rgb(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++) { - const UINT8* rgb = &palette[*in++ * 4]; + const UINT8 *rgb = &palette[*in++ * 4]; *out++ = rgb[0]; *out++ = rgb[1]; *out++ = rgb[2]; @@ -1193,11 +1108,10 @@ p2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) } static void -pa2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2rgb(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++, in += 4) { - const UINT8* rgb = &palette[in[0] * 4]; + const UINT8 *rgb = &palette[in[0] * 4]; *out++ = rgb[0]; *out++ = rgb[1]; *out++ = rgb[2]; @@ -1206,33 +1120,30 @@ pa2rgb(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) } static void -p2hsv(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2hsv(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++, out += 4) { - const UINT8* rgb = &palette[*in++ * 4]; + const UINT8 *rgb = &palette[*in++ * 4]; rgb2hsv_row(out, rgb); out[3] = 255; } } static void -pa2hsv(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2hsv(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++, in += 4, out += 4) { - const UINT8* rgb = &palette[in[0] * 4]; + const UINT8 *rgb = &palette[in[0] * 4]; rgb2hsv_row(out, rgb); out[3] = 255; } } static void -p2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2rgba(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++) { - const UINT8* rgba = &palette[*in++ * 4]; + const UINT8 *rgba = &palette[*in++ * 4]; *out++ = rgba[0]; *out++ = rgba[1]; *out++ = rgba[2]; @@ -1241,11 +1152,10 @@ p2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) } static void -pa2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2rgba(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { int x; for (x = 0; x < xsize; x++, in += 4) { - const UINT8* rgb = &palette[in[0] * 4]; + const UINT8 *rgb = &palette[in[0] * 4]; *out++ = rgb[0]; *out++ = rgb[1]; *out++ = rgb[2]; @@ -1254,45 +1164,40 @@ pa2rgba(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) } static void -p2cmyk(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2cmyk(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { p2rgb(out, in, xsize, palette); rgb2cmyk(out, out, xsize); } static void -pa2cmyk(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2cmyk(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { pa2rgb(out, in, xsize, palette); rgb2cmyk(out, out, xsize); } static void -p2ycbcr(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +p2ycbcr(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { p2rgb(out, in, xsize, palette); ImagingConvertRGB2YCbCr(out, out, xsize); } static void -pa2ycbcr(UINT8* out, const UINT8* in, int xsize, const UINT8* palette) -{ +pa2ycbcr(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) { pa2rgb(out, in, xsize, palette); ImagingConvertRGB2YCbCr(out, out, xsize); } static Imaging -frompalette(Imaging imOut, Imaging imIn, const char *mode) -{ +frompalette(Imaging imOut, Imaging imIn, const char *mode) { ImagingSectionCookie cookie; int alpha; int y; - void (*convert)(UINT8*, const UINT8*, int, const UINT8*); + void (*convert)(UINT8 *, const UINT8 *, int, const UINT8 *); /* Map palette image to L, RGB, RGBA, or CMYK */ if (!imIn->palette) { - return (Imaging) ImagingError_ValueError("no palette"); + return (Imaging)ImagingError_ValueError("no palette"); } alpha = !strcmp(imIn->mode, "PA"); @@ -1322,7 +1227,7 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode) } else if (strcmp(mode, "HSV") == 0) { convert = alpha ? pa2hsv : p2hsv; } else { - return (Imaging) ImagingError_ValueError("conversion not supported"); + return (Imaging)ImagingError_ValueError("conversion not supported"); } imOut = ImagingNew2Dirty(mode, imOut, imIn); @@ -1332,8 +1237,11 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode) ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { - (*convert)((UINT8*) imOut->image[y], (UINT8*) imIn->image[y], - imIn->xsize, imIn->palette->palette); + (*convert)( + (UINT8 *)imOut->image[y], + (UINT8 *)imIn->image[y], + imIn->xsize, + imIn->palette->palette); } ImagingSectionLeave(&cookie); @@ -1344,39 +1252,44 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode) #pragma optimize("", off) #endif static Imaging -topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalette, int dither) -{ +topalette( + Imaging imOut, + Imaging imIn, + const char *mode, + ImagingPalette inpalette, + int dither) { ImagingSectionCookie cookie; int alpha; int x, y; - ImagingPalette palette = inpalette;; + ImagingPalette palette = inpalette; + ; /* Map L or RGB/RGBX/RGBA to palette image */ if (strcmp(imIn->mode, "L") != 0 && strncmp(imIn->mode, "RGB", 3) != 0) { - return (Imaging) ImagingError_ValueError("conversion not supported"); + return (Imaging)ImagingError_ValueError("conversion not supported"); } alpha = !strcmp(mode, "PA"); if (palette == NULL) { - /* FIXME: make user configurable */ - if (imIn->bands == 1) { - palette = ImagingPaletteNew("RGB"); /* Initialised to grey ramp */ - } else { - palette = ImagingPaletteNewBrowser(); /* Standard colour cube */ - } + /* FIXME: make user configurable */ + if (imIn->bands == 1) { + palette = ImagingPaletteNew("RGB"); /* Initialised to grey ramp */ + } else { + palette = ImagingPaletteNewBrowser(); /* Standard colour cube */ + } } if (!palette) { - return (Imaging) ImagingError_ValueError("no palette"); + return (Imaging)ImagingError_ValueError("no palette"); } imOut = ImagingNew2Dirty(mode, imOut, imIn); if (!imOut) { - if (palette != inpalette) { - ImagingPaletteDelete(palette); - } - return NULL; + if (palette != inpalette) { + ImagingPaletteDelete(palette); + } + return NULL; } ImagingPaletteDelete(imOut->palette); @@ -1389,7 +1302,7 @@ topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalett ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { if (alpha) { - l2la((UINT8*) imOut->image[y], (UINT8*) imIn->image[y], imIn->xsize); + l2la((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize); } else { memcpy(imOut->image[y], imIn->image[y], imIn->linesize); } @@ -1403,7 +1316,7 @@ topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalett if (ImagingPaletteCachePrepare(palette) < 0) { ImagingDelete(imOut); if (palette != inpalette) { - ImagingPaletteDelete(palette); + ImagingPaletteDelete(palette); } return NULL; } @@ -1411,7 +1324,7 @@ topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalett if (dither) { /* floyd-steinberg dither */ - int* errors; + int *errors; errors = calloc(imIn->xsize + 1, sizeof(int) * 3); if (!errors) { ImagingDelete(imOut); @@ -1424,9 +1337,9 @@ topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalett int r, r0, r1, r2; int g, g0, g1, g2; int b, b0, b1, b2; - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out = alpha ? (UINT8*) imOut->image32[y] : imOut->image8[y]; - int* e = errors; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y]; + int *e = errors; r = r0 = r1 = 0; g = g0 = g1 = 0; @@ -1434,11 +1347,11 @@ topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalett for (x = 0; x < imIn->xsize; x++, in += 4) { int d2; - INT16* cache; + INT16 *cache; - r = CLIP8(in[0] + (r + e[3+0])/16); - g = CLIP8(in[1] + (g + e[3+1])/16); - b = CLIP8(in[2] + (b + e[3+2])/16); + r = CLIP8(in[0] + (r + e[3 + 0]) / 16); + g = CLIP8(in[1] + (g + e[3 + 1]) / 16); + b = CLIP8(in[2] + (b + e[3 + 2]) / 16); /* get closest colour */ cache = &ImagingPaletteCache(palette, r, g, b); @@ -1446,49 +1359,66 @@ topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalett ImagingPaletteCacheUpdate(palette, r, g, b); } if (alpha) { - out[x*4] = out[x*4+1] = out[x*4+2] = (UINT8) cache[0]; - out[x*4+3] = 255; + out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0]; + out[x * 4 + 3] = 255; } else { - out[x] = (UINT8) cache[0]; + out[x] = (UINT8)cache[0]; } - r -= (int) palette->palette[cache[0]*4]; - g -= (int) palette->palette[cache[0]*4+1]; - b -= (int) palette->palette[cache[0]*4+2]; + r -= (int)palette->palette[cache[0] * 4]; + g -= (int)palette->palette[cache[0] * 4 + 1]; + b -= (int)palette->palette[cache[0] * 4 + 2]; /* propagate errors (don't ask ;-) */ - r2 = r; d2 = r + r; r += d2; e[0] = r + r0; - r += d2; r0 = r + r1; r1 = r2; r += d2; - g2 = g; d2 = g + g; g += d2; e[1] = g + g0; - g += d2; g0 = g + g1; g1 = g2; g += d2; - b2 = b; d2 = b + b; b += d2; e[2] = b + b0; - b += d2; b0 = b + b1; b1 = b2; b += d2; + r2 = r; + d2 = r + r; + r += d2; + e[0] = r + r0; + r += d2; + r0 = r + r1; + r1 = r2; + r += d2; + g2 = g; + d2 = g + g; + g += d2; + e[1] = g + g0; + g += d2; + g0 = g + g1; + g1 = g2; + g += d2; + b2 = b; + d2 = b + b; + b += d2; + e[2] = b + b0; + b += d2; + b0 = b + b1; + b1 = b2; + b += d2; e += 3; - } e[0] = b0; e[1] = b1; e[2] = b2; - } ImagingSectionLeave(&cookie); free(errors); } else { - /* closest colour */ ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { int r, g, b; - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out = alpha ? (UINT8*) imOut->image32[y] : imOut->image8[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y]; for (x = 0; x < imIn->xsize; x++, in += 4) { - INT16* cache; + INT16 *cache; - r = in[0]; g = in[1]; b = in[2]; + r = in[0]; + g = in[1]; + b = in[2]; /* get closest colour */ cache = &ImagingPaletteCache(palette, r, g, b); @@ -1496,38 +1426,36 @@ topalette(Imaging imOut, Imaging imIn, const char *mode, ImagingPalette inpalett ImagingPaletteCacheUpdate(palette, r, g, b); } if (alpha) { - out[x*4] = out[x*4+1] = out[x*4+2] = (UINT8) cache[0]; - out[x*4+3] = 255; + out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0]; + out[x * 4 + 3] = 255; } else { - out[x] = (UINT8) cache[0]; + out[x] = (UINT8)cache[0]; } } } ImagingSectionLeave(&cookie); - } if (inpalette != palette) { - ImagingPaletteCacheDelete(palette); + ImagingPaletteCacheDelete(palette); } } if (inpalette != palette) { - ImagingPaletteDelete(palette); + ImagingPaletteDelete(palette); } return imOut; } static Imaging -tobilevel(Imaging imOut, Imaging imIn, int dither) -{ +tobilevel(Imaging imOut, Imaging imIn, int dither) { ImagingSectionCookie cookie; int x, y; - int* errors; + int *errors; /* Map L or RGB to dithered 1 image */ if (strcmp(imIn->mode, "L") != 0 && strcmp(imIn->mode, "RGB") != 0) { - return (Imaging) ImagingError_ValueError("conversion not supported"); + return (Imaging)ImagingError_ValueError("conversion not supported"); } imOut = ImagingNew2Dirty("1", imOut, imIn); @@ -1542,59 +1470,64 @@ tobilevel(Imaging imOut, Imaging imIn, int dither) } if (imIn->bands == 1) { - /* map each pixel to black or white, using error diffusion */ ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { int l, l0, l1, l2, d2; - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out = imOut->image8[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out = imOut->image8[y]; l = l0 = l1 = 0; for (x = 0; x < imIn->xsize; x++) { - /* pick closest colour */ - l = CLIP8(in[x] + (l + errors[x+1])/16); + l = CLIP8(in[x] + (l + errors[x + 1]) / 16); out[x] = (l > 128) ? 255 : 0; /* propagate errors */ - l -= (int) out[x]; - l2 = l; d2 = l + l; l += d2; errors[x] = l + l0; - l += d2; l0 = l + l1; l1 = l2; l += d2; + l -= (int)out[x]; + l2 = l; + d2 = l + l; + l += d2; + errors[x] = l + l0; + l += d2; + l0 = l + l1; + l1 = l2; + l += d2; } errors[x] = l0; - } ImagingSectionLeave(&cookie); } else { - /* map each pixel to black or white, using error diffusion */ ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { int l, l0, l1, l2, d2; - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out = imOut->image8[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out = imOut->image8[y]; l = l0 = l1 = 0; for (x = 0; x < imIn->xsize; x++, in += 4) { - /* pick closest colour */ - l = CLIP8(L(in)/1000 + (l + errors[x+1])/16); + l = CLIP8(L(in) / 1000 + (l + errors[x + 1]) / 16); out[x] = (l > 128) ? 255 : 0; /* propagate errors */ - l -= (int) out[x]; - l2 = l; d2 = l + l; l += d2; errors[x] = l + l0; - l += d2; l0 = l + l1; l1 = l2; l += d2; - + l -= (int)out[x]; + l2 = l; + d2 = l + l; + l += d2; + errors[x] = l + l0; + l += d2; + l0 = l + l1; + l1 = l2; + l += d2; } errors[x] = l0; - } ImagingSectionLeave(&cookie); } @@ -1608,21 +1541,20 @@ tobilevel(Imaging imOut, Imaging imIn, int dither) #endif static Imaging -convert(Imaging imOut, Imaging imIn, const char *mode, - ImagingPalette palette, int dither) -{ +convert( + Imaging imOut, Imaging imIn, const char *mode, ImagingPalette palette, int dither) { ImagingSectionCookie cookie; ImagingShuffler convert; int y; if (!imIn) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (!mode) { /* Map palette image to full depth */ if (!imIn->palette) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } mode = imIn->palette->mode; } else { @@ -1632,7 +1564,6 @@ convert(Imaging imOut, Imaging imIn, const char *mode, } } - /* test for special conversions */ if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "PA") == 0) { @@ -1647,7 +1578,6 @@ convert(Imaging imOut, Imaging imIn, const char *mode, return tobilevel(imOut, imIn, dither); } - /* standard conversion machinery */ convert = NULL; @@ -1662,12 +1592,12 @@ convert(Imaging imOut, Imaging imIn, const char *mode, if (!convert) { #ifdef notdef - return (Imaging) ImagingError_ValueError("conversion not supported"); + return (Imaging)ImagingError_ValueError("conversion not supported"); #else static char buf[256]; /* FIXME: may overflow if mode is too large */ sprintf(buf, "conversion from %s to %s not supported", imIn->mode, mode); - return (Imaging) ImagingError_ValueError(buf); + return (Imaging)ImagingError_ValueError(buf); #endif } @@ -1678,8 +1608,7 @@ convert(Imaging imOut, Imaging imIn, const char *mode, ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { - (*convert)((UINT8*) imOut->image[y], (UINT8*) imIn->image[y], - imIn->xsize); + (*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize); } ImagingSectionLeave(&cookie); @@ -1687,47 +1616,43 @@ convert(Imaging imOut, Imaging imIn, const char *mode, } Imaging -ImagingConvert(Imaging imIn, const char *mode, - ImagingPalette palette, int dither) -{ +ImagingConvert(Imaging imIn, const char *mode, ImagingPalette palette, int dither) { return convert(NULL, imIn, mode, palette, dither); } Imaging -ImagingConvert2(Imaging imOut, Imaging imIn) -{ +ImagingConvert2(Imaging imOut, Imaging imIn) { return convert(imOut, imIn, imOut->mode, NULL, 0); } - Imaging -ImagingConvertTransparent(Imaging imIn, const char *mode, - int r, int g, int b) -{ +ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) { ImagingSectionCookie cookie; ImagingShuffler convert; Imaging imOut = NULL; int y; - if (!imIn){ - return (Imaging) ImagingError_ModeError(); + if (!imIn) { + return (Imaging)ImagingError_ModeError(); } - if (!((strcmp(imIn->mode, "RGB") == 0 || - strcmp(imIn->mode, "1") == 0 || - strcmp(imIn->mode, "I") == 0 || - strcmp(imIn->mode, "L") == 0) - && strcmp(mode, "RGBA") == 0)) + if (!((strcmp(imIn->mode, "RGB") == 0 || strcmp(imIn->mode, "1") == 0 || + strcmp(imIn->mode, "I") == 0 || strcmp(imIn->mode, "L") == 0) && + strcmp(mode, "RGBA") == 0)) #ifdef notdef { - return (Imaging) ImagingError_ValueError("conversion not supported"); + return (Imaging)ImagingError_ValueError("conversion not supported"); } #else { - static char buf[256]; - /* FIXME: may overflow if mode is too large */ - sprintf(buf, "conversion from %s to %s not supported in convert_transparent", imIn->mode, mode); - return (Imaging) ImagingError_ValueError(buf); + static char buf[256]; + /* FIXME: may overflow if mode is too large */ + sprintf( + buf, + "conversion from %s to %s not supported in convert_transparent", + imIn->mode, + mode); + return (Imaging)ImagingError_ValueError(buf); } #endif @@ -1745,25 +1670,22 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, } imOut = ImagingNew2Dirty(mode, imOut, imIn); - if (!imOut){ + if (!imOut) { return NULL; } ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { - (*convert)((UINT8*) imOut->image[y], (UINT8*) imIn->image[y], - imIn->xsize); - rgbT2rgba((UINT8*) imOut->image[y], imIn->xsize, r, g, b); + (*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize); + rgbT2rgba((UINT8 *)imOut->image[y], imIn->xsize, r, g, b); } ImagingSectionLeave(&cookie); return imOut; - } Imaging -ImagingConvertInPlace(Imaging imIn, const char* mode) -{ +ImagingConvertInPlace(Imaging imIn, const char *mode) { ImagingSectionCookie cookie; ImagingShuffler convert; int y; @@ -1779,8 +1701,7 @@ ImagingConvertInPlace(Imaging imIn, const char* mode) ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { - (*convert)((UINT8*) imIn->image[y], (UINT8*) imIn->image[y], - imIn->xsize); + (*convert)((UINT8 *)imIn->image[y], (UINT8 *)imIn->image[y], imIn->xsize); } ImagingSectionLeave(&cookie); diff --git a/src/libImaging/ConvertYCbCr.c b/src/libImaging/ConvertYCbCr.c index 47de4ff71..142f065e5 100644 --- a/src/libImaging/ConvertYCbCr.c +++ b/src/libImaging/ConvertYCbCr.c @@ -28,356 +28,332 @@ #define SCALE 6 /* bits */ -static INT16 Y_R[] = { 0, 19, 38, 57, 77, 96, 115, 134, 153, 172, 191, -210, 230, 249, 268, 287, 306, 325, 344, 364, 383, 402, 421, 440, 459, -478, 498, 517, 536, 555, 574, 593, 612, 631, 651, 670, 689, 708, 727, -746, 765, 785, 804, 823, 842, 861, 880, 899, 919, 938, 957, 976, 995, -1014, 1033, 1052, 1072, 1091, 1110, 1129, 1148, 1167, 1186, 1206, -1225, 1244, 1263, 1282, 1301, 1320, 1340, 1359, 1378, 1397, 1416, -1435, 1454, 1473, 1493, 1512, 1531, 1550, 1569, 1588, 1607, 1627, -1646, 1665, 1684, 1703, 1722, 1741, 1761, 1780, 1799, 1818, 1837, -1856, 1875, 1894, 1914, 1933, 1952, 1971, 1990, 2009, 2028, 2048, -2067, 2086, 2105, 2124, 2143, 2162, 2182, 2201, 2220, 2239, 2258, -2277, 2296, 2315, 2335, 2354, 2373, 2392, 2411, 2430, 2449, 2469, -2488, 2507, 2526, 2545, 2564, 2583, 2602, 2622, 2641, 2660, 2679, -2698, 2717, 2736, 2756, 2775, 2794, 2813, 2832, 2851, 2870, 2890, -2909, 2928, 2947, 2966, 2985, 3004, 3023, 3043, 3062, 3081, 3100, -3119, 3138, 3157, 3177, 3196, 3215, 3234, 3253, 3272, 3291, 3311, -3330, 3349, 3368, 3387, 3406, 3425, 3444, 3464, 3483, 3502, 3521, -3540, 3559, 3578, 3598, 3617, 3636, 3655, 3674, 3693, 3712, 3732, -3751, 3770, 3789, 3808, 3827, 3846, 3865, 3885, 3904, 3923, 3942, -3961, 3980, 3999, 4019, 4038, 4057, 4076, 4095, 4114, 4133, 4153, -4172, 4191, 4210, 4229, 4248, 4267, 4286, 4306, 4325, 4344, 4363, -4382, 4401, 4420, 4440, 4459, 4478, 4497, 4516, 4535, 4554, 4574, -4593, 4612, 4631, 4650, 4669, 4688, 4707, 4727, 4746, 4765, 4784, -4803, 4822, 4841, 4861, 4880 }; +static INT16 Y_R[] = { + 0, 19, 38, 57, 77, 96, 115, 134, 153, 172, 191, 210, 230, 249, + 268, 287, 306, 325, 344, 364, 383, 402, 421, 440, 459, 478, 498, 517, + 536, 555, 574, 593, 612, 631, 651, 670, 689, 708, 727, 746, 765, 785, + 804, 823, 842, 861, 880, 899, 919, 938, 957, 976, 995, 1014, 1033, 1052, + 1072, 1091, 1110, 1129, 1148, 1167, 1186, 1206, 1225, 1244, 1263, 1282, 1301, 1320, + 1340, 1359, 1378, 1397, 1416, 1435, 1454, 1473, 1493, 1512, 1531, 1550, 1569, 1588, + 1607, 1627, 1646, 1665, 1684, 1703, 1722, 1741, 1761, 1780, 1799, 1818, 1837, 1856, + 1875, 1894, 1914, 1933, 1952, 1971, 1990, 2009, 2028, 2048, 2067, 2086, 2105, 2124, + 2143, 2162, 2182, 2201, 2220, 2239, 2258, 2277, 2296, 2315, 2335, 2354, 2373, 2392, + 2411, 2430, 2449, 2469, 2488, 2507, 2526, 2545, 2564, 2583, 2602, 2622, 2641, 2660, + 2679, 2698, 2717, 2736, 2756, 2775, 2794, 2813, 2832, 2851, 2870, 2890, 2909, 2928, + 2947, 2966, 2985, 3004, 3023, 3043, 3062, 3081, 3100, 3119, 3138, 3157, 3177, 3196, + 3215, 3234, 3253, 3272, 3291, 3311, 3330, 3349, 3368, 3387, 3406, 3425, 3444, 3464, + 3483, 3502, 3521, 3540, 3559, 3578, 3598, 3617, 3636, 3655, 3674, 3693, 3712, 3732, + 3751, 3770, 3789, 3808, 3827, 3846, 3865, 3885, 3904, 3923, 3942, 3961, 3980, 3999, + 4019, 4038, 4057, 4076, 4095, 4114, 4133, 4153, 4172, 4191, 4210, 4229, 4248, 4267, + 4286, 4306, 4325, 4344, 4363, 4382, 4401, 4420, 4440, 4459, 4478, 4497, 4516, 4535, + 4554, 4574, 4593, 4612, 4631, 4650, 4669, 4688, 4707, 4727, 4746, 4765, 4784, 4803, + 4822, 4841, 4861, 4880}; -static INT16 Y_G[] = { 0, 38, 75, 113, 150, 188, 225, 263, 301, 338, -376, 413, 451, 488, 526, 564, 601, 639, 676, 714, 751, 789, 826, 864, -902, 939, 977, 1014, 1052, 1089, 1127, 1165, 1202, 1240, 1277, 1315, -1352, 1390, 1428, 1465, 1503, 1540, 1578, 1615, 1653, 1691, 1728, -1766, 1803, 1841, 1878, 1916, 1954, 1991, 2029, 2066, 2104, 2141, -2179, 2217, 2254, 2292, 2329, 2367, 2404, 2442, 2479, 2517, 2555, -2592, 2630, 2667, 2705, 2742, 2780, 2818, 2855, 2893, 2930, 2968, -3005, 3043, 3081, 3118, 3156, 3193, 3231, 3268, 3306, 3344, 3381, -3419, 3456, 3494, 3531, 3569, 3607, 3644, 3682, 3719, 3757, 3794, -3832, 3870, 3907, 3945, 3982, 4020, 4057, 4095, 4132, 4170, 4208, -4245, 4283, 4320, 4358, 4395, 4433, 4471, 4508, 4546, 4583, 4621, -4658, 4696, 4734, 4771, 4809, 4846, 4884, 4921, 4959, 4997, 5034, -5072, 5109, 5147, 5184, 5222, 5260, 5297, 5335, 5372, 5410, 5447, -5485, 5522, 5560, 5598, 5635, 5673, 5710, 5748, 5785, 5823, 5861, -5898, 5936, 5973, 6011, 6048, 6086, 6124, 6161, 6199, 6236, 6274, -6311, 6349, 6387, 6424, 6462, 6499, 6537, 6574, 6612, 6650, 6687, -6725, 6762, 6800, 6837, 6875, 6913, 6950, 6988, 7025, 7063, 7100, -7138, 7175, 7213, 7251, 7288, 7326, 7363, 7401, 7438, 7476, 7514, -7551, 7589, 7626, 7664, 7701, 7739, 7777, 7814, 7852, 7889, 7927, -7964, 8002, 8040, 8077, 8115, 8152, 8190, 8227, 8265, 8303, 8340, -8378, 8415, 8453, 8490, 8528, 8566, 8603, 8641, 8678, 8716, 8753, -8791, 8828, 8866, 8904, 8941, 8979, 9016, 9054, 9091, 9129, 9167, -9204, 9242, 9279, 9317, 9354, 9392, 9430, 9467, 9505, 9542, 9580 }; +static INT16 Y_G[] = { + 0, 38, 75, 113, 150, 188, 225, 263, 301, 338, 376, 413, 451, 488, + 526, 564, 601, 639, 676, 714, 751, 789, 826, 864, 902, 939, 977, 1014, + 1052, 1089, 1127, 1165, 1202, 1240, 1277, 1315, 1352, 1390, 1428, 1465, 1503, 1540, + 1578, 1615, 1653, 1691, 1728, 1766, 1803, 1841, 1878, 1916, 1954, 1991, 2029, 2066, + 2104, 2141, 2179, 2217, 2254, 2292, 2329, 2367, 2404, 2442, 2479, 2517, 2555, 2592, + 2630, 2667, 2705, 2742, 2780, 2818, 2855, 2893, 2930, 2968, 3005, 3043, 3081, 3118, + 3156, 3193, 3231, 3268, 3306, 3344, 3381, 3419, 3456, 3494, 3531, 3569, 3607, 3644, + 3682, 3719, 3757, 3794, 3832, 3870, 3907, 3945, 3982, 4020, 4057, 4095, 4132, 4170, + 4208, 4245, 4283, 4320, 4358, 4395, 4433, 4471, 4508, 4546, 4583, 4621, 4658, 4696, + 4734, 4771, 4809, 4846, 4884, 4921, 4959, 4997, 5034, 5072, 5109, 5147, 5184, 5222, + 5260, 5297, 5335, 5372, 5410, 5447, 5485, 5522, 5560, 5598, 5635, 5673, 5710, 5748, + 5785, 5823, 5861, 5898, 5936, 5973, 6011, 6048, 6086, 6124, 6161, 6199, 6236, 6274, + 6311, 6349, 6387, 6424, 6462, 6499, 6537, 6574, 6612, 6650, 6687, 6725, 6762, 6800, + 6837, 6875, 6913, 6950, 6988, 7025, 7063, 7100, 7138, 7175, 7213, 7251, 7288, 7326, + 7363, 7401, 7438, 7476, 7514, 7551, 7589, 7626, 7664, 7701, 7739, 7777, 7814, 7852, + 7889, 7927, 7964, 8002, 8040, 8077, 8115, 8152, 8190, 8227, 8265, 8303, 8340, 8378, + 8415, 8453, 8490, 8528, 8566, 8603, 8641, 8678, 8716, 8753, 8791, 8828, 8866, 8904, + 8941, 8979, 9016, 9054, 9091, 9129, 9167, 9204, 9242, 9279, 9317, 9354, 9392, 9430, + 9467, 9505, 9542, 9580}; -static INT16 Y_B[] = { 0, 7, 15, 22, 29, 36, 44, 51, 58, 66, 73, 80, -88, 95, 102, 109, 117, 124, 131, 139, 146, 153, 161, 168, 175, 182, -190, 197, 204, 212, 219, 226, 233, 241, 248, 255, 263, 270, 277, 285, -292, 299, 306, 314, 321, 328, 336, 343, 350, 358, 365, 372, 379, 387, -394, 401, 409, 416, 423, 430, 438, 445, 452, 460, 467, 474, 482, 489, -496, 503, 511, 518, 525, 533, 540, 547, 554, 562, 569, 576, 584, 591, -598, 606, 613, 620, 627, 635, 642, 649, 657, 664, 671, 679, 686, 693, -700, 708, 715, 722, 730, 737, 744, 751, 759, 766, 773, 781, 788, 795, -803, 810, 817, 824, 832, 839, 846, 854, 861, 868, 876, 883, 890, 897, -905, 912, 919, 927, 934, 941, 948, 956, 963, 970, 978, 985, 992, 1000, -1007, 1014, 1021, 1029, 1036, 1043, 1051, 1058, 1065, 1073, 1080, -1087, 1094, 1102, 1109, 1116, 1124, 1131, 1138, 1145, 1153, 1160, -1167, 1175, 1182, 1189, 1197, 1204, 1211, 1218, 1226, 1233, 1240, -1248, 1255, 1262, 1270, 1277, 1284, 1291, 1299, 1306, 1313, 1321, -1328, 1335, 1342, 1350, 1357, 1364, 1372, 1379, 1386, 1394, 1401, -1408, 1415, 1423, 1430, 1437, 1445, 1452, 1459, 1466, 1474, 1481, -1488, 1496, 1503, 1510, 1518, 1525, 1532, 1539, 1547, 1554, 1561, -1569, 1576, 1583, 1591, 1598, 1605, 1612, 1620, 1627, 1634, 1642, -1649, 1656, 1663, 1671, 1678, 1685, 1693, 1700, 1707, 1715, 1722, -1729, 1736, 1744, 1751, 1758, 1766, 1773, 1780, 1788, 1795, 1802, -1809, 1817, 1824, 1831, 1839, 1846, 1853, 1860 }; +static INT16 Y_B[] = { + 0, 7, 15, 22, 29, 36, 44, 51, 58, 66, 73, 80, 88, 95, + 102, 109, 117, 124, 131, 139, 146, 153, 161, 168, 175, 182, 190, 197, + 204, 212, 219, 226, 233, 241, 248, 255, 263, 270, 277, 285, 292, 299, + 306, 314, 321, 328, 336, 343, 350, 358, 365, 372, 379, 387, 394, 401, + 409, 416, 423, 430, 438, 445, 452, 460, 467, 474, 482, 489, 496, 503, + 511, 518, 525, 533, 540, 547, 554, 562, 569, 576, 584, 591, 598, 606, + 613, 620, 627, 635, 642, 649, 657, 664, 671, 679, 686, 693, 700, 708, + 715, 722, 730, 737, 744, 751, 759, 766, 773, 781, 788, 795, 803, 810, + 817, 824, 832, 839, 846, 854, 861, 868, 876, 883, 890, 897, 905, 912, + 919, 927, 934, 941, 948, 956, 963, 970, 978, 985, 992, 1000, 1007, 1014, + 1021, 1029, 1036, 1043, 1051, 1058, 1065, 1073, 1080, 1087, 1094, 1102, 1109, 1116, + 1124, 1131, 1138, 1145, 1153, 1160, 1167, 1175, 1182, 1189, 1197, 1204, 1211, 1218, + 1226, 1233, 1240, 1248, 1255, 1262, 1270, 1277, 1284, 1291, 1299, 1306, 1313, 1321, + 1328, 1335, 1342, 1350, 1357, 1364, 1372, 1379, 1386, 1394, 1401, 1408, 1415, 1423, + 1430, 1437, 1445, 1452, 1459, 1466, 1474, 1481, 1488, 1496, 1503, 1510, 1518, 1525, + 1532, 1539, 1547, 1554, 1561, 1569, 1576, 1583, 1591, 1598, 1605, 1612, 1620, 1627, + 1634, 1642, 1649, 1656, 1663, 1671, 1678, 1685, 1693, 1700, 1707, 1715, 1722, 1729, + 1736, 1744, 1751, 1758, 1766, 1773, 1780, 1788, 1795, 1802, 1809, 1817, 1824, 1831, + 1839, 1846, 1853, 1860}; -static INT16 Cb_R[] = { 0, -10, -21, -31, -42, -53, -64, -75, -85, --96, -107, -118, -129, -139, -150, -161, -172, -183, -193, -204, -215, --226, -237, -247, -258, -269, -280, -291, -301, -312, -323, -334, --345, -355, -366, -377, -388, -399, -409, -420, -431, -442, -453, --463, -474, -485, -496, -507, -517, -528, -539, -550, -561, -571, --582, -593, -604, -615, -625, -636, -647, -658, -669, -679, -690, --701, -712, -723, -733, -744, -755, -766, -777, -787, -798, -809, --820, -831, -841, -852, -863, -874, -885, -895, -906, -917, -928, --939, -949, -960, -971, -982, -993, -1003, -1014, -1025, -1036, -1047, --1057, -1068, -1079, -1090, -1101, -1111, -1122, -1133, -1144, -1155, --1165, -1176, -1187, -1198, -1209, -1219, -1230, -1241, -1252, -1263, --1273, -1284, -1295, -1306, -1317, -1327, -1338, -1349, -1360, -1371, --1381, -1392, -1403, -1414, -1425, -1435, -1446, -1457, -1468, -1479, --1489, -1500, -1511, -1522, -1533, -1543, -1554, -1565, -1576, -1587, --1597, -1608, -1619, -1630, -1641, -1651, -1662, -1673, -1684, -1694, --1705, -1716, -1727, -1738, -1748, -1759, -1770, -1781, -1792, -1802, --1813, -1824, -1835, -1846, -1856, -1867, -1878, -1889, -1900, -1910, --1921, -1932, -1943, -1954, -1964, -1975, -1986, -1997, -2008, -2018, --2029, -2040, -2051, -2062, -2072, -2083, -2094, -2105, -2116, -2126, --2137, -2148, -2159, -2170, -2180, -2191, -2202, -2213, -2224, -2234, --2245, -2256, -2267, -2278, -2288, -2299, -2310, -2321, -2332, -2342, --2353, -2364, -2375, -2386, -2396, -2407, -2418, -2429, -2440, -2450, --2461, -2472, -2483, -2494, -2504, -2515, -2526, -2537, -2548, -2558, --2569, -2580, -2591, -2602, -2612, -2623, -2634, -2645, -2656, -2666, --2677, -2688, -2699, -2710, -2720, -2731, -2742, -2753 }; +static INT16 Cb_R[] = { + 0, -10, -21, -31, -42, -53, -64, -75, -85, -96, -107, -118, + -129, -139, -150, -161, -172, -183, -193, -204, -215, -226, -237, -247, + -258, -269, -280, -291, -301, -312, -323, -334, -345, -355, -366, -377, + -388, -399, -409, -420, -431, -442, -453, -463, -474, -485, -496, -507, + -517, -528, -539, -550, -561, -571, -582, -593, -604, -615, -625, -636, + -647, -658, -669, -679, -690, -701, -712, -723, -733, -744, -755, -766, + -777, -787, -798, -809, -820, -831, -841, -852, -863, -874, -885, -895, + -906, -917, -928, -939, -949, -960, -971, -982, -993, -1003, -1014, -1025, + -1036, -1047, -1057, -1068, -1079, -1090, -1101, -1111, -1122, -1133, -1144, -1155, + -1165, -1176, -1187, -1198, -1209, -1219, -1230, -1241, -1252, -1263, -1273, -1284, + -1295, -1306, -1317, -1327, -1338, -1349, -1360, -1371, -1381, -1392, -1403, -1414, + -1425, -1435, -1446, -1457, -1468, -1479, -1489, -1500, -1511, -1522, -1533, -1543, + -1554, -1565, -1576, -1587, -1597, -1608, -1619, -1630, -1641, -1651, -1662, -1673, + -1684, -1694, -1705, -1716, -1727, -1738, -1748, -1759, -1770, -1781, -1792, -1802, + -1813, -1824, -1835, -1846, -1856, -1867, -1878, -1889, -1900, -1910, -1921, -1932, + -1943, -1954, -1964, -1975, -1986, -1997, -2008, -2018, -2029, -2040, -2051, -2062, + -2072, -2083, -2094, -2105, -2116, -2126, -2137, -2148, -2159, -2170, -2180, -2191, + -2202, -2213, -2224, -2234, -2245, -2256, -2267, -2278, -2288, -2299, -2310, -2321, + -2332, -2342, -2353, -2364, -2375, -2386, -2396, -2407, -2418, -2429, -2440, -2450, + -2461, -2472, -2483, -2494, -2504, -2515, -2526, -2537, -2548, -2558, -2569, -2580, + -2591, -2602, -2612, -2623, -2634, -2645, -2656, -2666, -2677, -2688, -2699, -2710, + -2720, -2731, -2742, -2753}; -static INT16 Cb_G[] = { 0, -20, -41, -63, -84, -105, -126, -147, -169, --190, -211, -232, -253, -275, -296, -317, -338, -359, -381, -402, --423, -444, -465, -487, -508, -529, -550, -571, -593, -614, -635, --656, -677, -699, -720, -741, -762, -783, -805, -826, -847, -868, --889, -911, -932, -953, -974, -995, -1017, -1038, -1059, -1080, -1101, --1123, -1144, -1165, -1186, -1207, -1229, -1250, -1271, -1292, -1313, --1335, -1356, -1377, -1398, -1419, -1441, -1462, -1483, -1504, -1525, --1547, -1568, -1589, -1610, -1631, -1653, -1674, -1695, -1716, -1737, --1759, -1780, -1801, -1822, -1843, -1865, -1886, -1907, -1928, -1949, --1971, -1992, -2013, -2034, -2055, -2077, -2098, -2119, -2140, -2161, --2183, -2204, -2225, -2246, -2267, -2289, -2310, -2331, -2352, -2373, --2395, -2416, -2437, -2458, -2479, -2501, -2522, -2543, -2564, -2585, --2607, -2628, -2649, -2670, -2691, -2713, -2734, -2755, -2776, -2797, --2819, -2840, -2861, -2882, -2903, -2925, -2946, -2967, -2988, -3009, --3031, -3052, -3073, -3094, -3115, -3137, -3158, -3179, -3200, -3221, --3243, -3264, -3285, -3306, -3328, -3349, -3370, -3391, -3412, -3434, --3455, -3476, -3497, -3518, -3540, -3561, -3582, -3603, -3624, -3646, --3667, -3688, -3709, -3730, -3752, -3773, -3794, -3815, -3836, -3858, --3879, -3900, -3921, -3942, -3964, -3985, -4006, -4027, -4048, -4070, --4091, -4112, -4133, -4154, -4176, -4197, -4218, -4239, -4260, -4282, --4303, -4324, -4345, -4366, -4388, -4409, -4430, -4451, -4472, -4494, --4515, -4536, -4557, -4578, -4600, -4621, -4642, -4663, -4684, -4706, --4727, -4748, -4769, -4790, -4812, -4833, -4854, -4875, -4896, -4918, --4939, -4960, -4981, -5002, -5024, -5045, -5066, -5087, -5108, -5130, --5151, -5172, -5193, -5214, -5236, -5257, -5278, -5299, -5320, -5342, --5363, -5384, -5405 }; +static INT16 Cb_G[] = { + 0, -20, -41, -63, -84, -105, -126, -147, -169, -190, -211, -232, + -253, -275, -296, -317, -338, -359, -381, -402, -423, -444, -465, -487, + -508, -529, -550, -571, -593, -614, -635, -656, -677, -699, -720, -741, + -762, -783, -805, -826, -847, -868, -889, -911, -932, -953, -974, -995, + -1017, -1038, -1059, -1080, -1101, -1123, -1144, -1165, -1186, -1207, -1229, -1250, + -1271, -1292, -1313, -1335, -1356, -1377, -1398, -1419, -1441, -1462, -1483, -1504, + -1525, -1547, -1568, -1589, -1610, -1631, -1653, -1674, -1695, -1716, -1737, -1759, + -1780, -1801, -1822, -1843, -1865, -1886, -1907, -1928, -1949, -1971, -1992, -2013, + -2034, -2055, -2077, -2098, -2119, -2140, -2161, -2183, -2204, -2225, -2246, -2267, + -2289, -2310, -2331, -2352, -2373, -2395, -2416, -2437, -2458, -2479, -2501, -2522, + -2543, -2564, -2585, -2607, -2628, -2649, -2670, -2691, -2713, -2734, -2755, -2776, + -2797, -2819, -2840, -2861, -2882, -2903, -2925, -2946, -2967, -2988, -3009, -3031, + -3052, -3073, -3094, -3115, -3137, -3158, -3179, -3200, -3221, -3243, -3264, -3285, + -3306, -3328, -3349, -3370, -3391, -3412, -3434, -3455, -3476, -3497, -3518, -3540, + -3561, -3582, -3603, -3624, -3646, -3667, -3688, -3709, -3730, -3752, -3773, -3794, + -3815, -3836, -3858, -3879, -3900, -3921, -3942, -3964, -3985, -4006, -4027, -4048, + -4070, -4091, -4112, -4133, -4154, -4176, -4197, -4218, -4239, -4260, -4282, -4303, + -4324, -4345, -4366, -4388, -4409, -4430, -4451, -4472, -4494, -4515, -4536, -4557, + -4578, -4600, -4621, -4642, -4663, -4684, -4706, -4727, -4748, -4769, -4790, -4812, + -4833, -4854, -4875, -4896, -4918, -4939, -4960, -4981, -5002, -5024, -5045, -5066, + -5087, -5108, -5130, -5151, -5172, -5193, -5214, -5236, -5257, -5278, -5299, -5320, + -5342, -5363, -5384, -5405}; -static INT16 Cb_B[] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, -320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, 736, -768, 800, 832, 864, 896, 928, 960, 992, 1024, 1056, 1088, 1120, 1152, -1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472, 1504, -1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856, -1888, 1920, 1952, 1984, 2016, 2048, 2080, 2112, 2144, 2176, 2208, -2240, 2272, 2304, 2336, 2368, 2400, 2432, 2464, 2496, 2528, 2560, -2592, 2624, 2656, 2688, 2720, 2752, 2784, 2816, 2848, 2880, 2912, -2944, 2976, 3008, 3040, 3072, 3104, 3136, 3168, 3200, 3232, 3264, -3296, 3328, 3360, 3392, 3424, 3456, 3488, 3520, 3552, 3584, 3616, -3648, 3680, 3712, 3744, 3776, 3808, 3840, 3872, 3904, 3936, 3968, -4000, 4032, 4064, 4096, 4128, 4160, 4192, 4224, 4256, 4288, 4320, -4352, 4384, 4416, 4448, 4480, 4512, 4544, 4576, 4608, 4640, 4672, -4704, 4736, 4768, 4800, 4832, 4864, 4896, 4928, 4960, 4992, 5024, -5056, 5088, 5120, 5152, 5184, 5216, 5248, 5280, 5312, 5344, 5376, -5408, 5440, 5472, 5504, 5536, 5568, 5600, 5632, 5664, 5696, 5728, -5760, 5792, 5824, 5856, 5888, 5920, 5952, 5984, 6016, 6048, 6080, -6112, 6144, 6176, 6208, 6240, 6272, 6304, 6336, 6368, 6400, 6432, -6464, 6496, 6528, 6560, 6592, 6624, 6656, 6688, 6720, 6752, 6784, -6816, 6848, 6880, 6912, 6944, 6976, 7008, 7040, 7072, 7104, 7136, -7168, 7200, 7232, 7264, 7296, 7328, 7360, 7392, 7424, 7456, 7488, -7520, 7552, 7584, 7616, 7648, 7680, 7712, 7744, 7776, 7808, 7840, -7872, 7904, 7936, 7968, 8000, 8032, 8064, 8096, 8128, 8160 }; +static INT16 Cb_B[] = { + 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, + 448, 480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, + 896, 928, 960, 992, 1024, 1056, 1088, 1120, 1152, 1184, 1216, 1248, 1280, 1312, + 1344, 1376, 1408, 1440, 1472, 1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, + 1792, 1824, 1856, 1888, 1920, 1952, 1984, 2016, 2048, 2080, 2112, 2144, 2176, 2208, + 2240, 2272, 2304, 2336, 2368, 2400, 2432, 2464, 2496, 2528, 2560, 2592, 2624, 2656, + 2688, 2720, 2752, 2784, 2816, 2848, 2880, 2912, 2944, 2976, 3008, 3040, 3072, 3104, + 3136, 3168, 3200, 3232, 3264, 3296, 3328, 3360, 3392, 3424, 3456, 3488, 3520, 3552, + 3584, 3616, 3648, 3680, 3712, 3744, 3776, 3808, 3840, 3872, 3904, 3936, 3968, 4000, + 4032, 4064, 4096, 4128, 4160, 4192, 4224, 4256, 4288, 4320, 4352, 4384, 4416, 4448, + 4480, 4512, 4544, 4576, 4608, 4640, 4672, 4704, 4736, 4768, 4800, 4832, 4864, 4896, + 4928, 4960, 4992, 5024, 5056, 5088, 5120, 5152, 5184, 5216, 5248, 5280, 5312, 5344, + 5376, 5408, 5440, 5472, 5504, 5536, 5568, 5600, 5632, 5664, 5696, 5728, 5760, 5792, + 5824, 5856, 5888, 5920, 5952, 5984, 6016, 6048, 6080, 6112, 6144, 6176, 6208, 6240, + 6272, 6304, 6336, 6368, 6400, 6432, 6464, 6496, 6528, 6560, 6592, 6624, 6656, 6688, + 6720, 6752, 6784, 6816, 6848, 6880, 6912, 6944, 6976, 7008, 7040, 7072, 7104, 7136, + 7168, 7200, 7232, 7264, 7296, 7328, 7360, 7392, 7424, 7456, 7488, 7520, 7552, 7584, + 7616, 7648, 7680, 7712, 7744, 7776, 7808, 7840, 7872, 7904, 7936, 7968, 8000, 8032, + 8064, 8096, 8128, 8160}; #define Cr_R Cb_B -static INT16 Cr_G[] = { 0, -26, -53, -79, -106, -133, -160, -187, --213, -240, -267, -294, -321, -347, -374, -401, -428, -455, -481, --508, -535, -562, -589, -615, -642, -669, -696, -722, -749, -776, --803, -830, -856, -883, -910, -937, -964, -990, -1017, -1044, -1071, --1098, -1124, -1151, -1178, -1205, -1232, -1258, -1285, -1312, -1339, --1366, -1392, -1419, -1446, -1473, -1500, -1526, -1553, -1580, -1607, --1634, -1660, -1687, -1714, -1741, -1768, -1794, -1821, -1848, -1875, --1902, -1928, -1955, -1982, -2009, -2036, -2062, -2089, -2116, -2143, --2169, -2196, -2223, -2250, -2277, -2303, -2330, -2357, -2384, -2411, --2437, -2464, -2491, -2518, -2545, -2571, -2598, -2625, -2652, -2679, --2705, -2732, -2759, -2786, -2813, -2839, -2866, -2893, -2920, -2947, --2973, -3000, -3027, -3054, -3081, -3107, -3134, -3161, -3188, -3215, --3241, -3268, -3295, -3322, -3349, -3375, -3402, -3429, -3456, -3483, --3509, -3536, -3563, -3590, -3616, -3643, -3670, -3697, -3724, -3750, --3777, -3804, -3831, -3858, -3884, -3911, -3938, -3965, -3992, -4018, --4045, -4072, -4099, -4126, -4152, -4179, -4206, -4233, -4260, -4286, --4313, -4340, -4367, -4394, -4420, -4447, -4474, -4501, -4528, -4554, --4581, -4608, -4635, -4662, -4688, -4715, -4742, -4769, -4796, -4822, --4849, -4876, -4903, -4929, -4956, -4983, -5010, -5037, -5063, -5090, --5117, -5144, -5171, -5197, -5224, -5251, -5278, -5305, -5331, -5358, --5385, -5412, -5439, -5465, -5492, -5519, -5546, -5573, -5599, -5626, --5653, -5680, -5707, -5733, -5760, -5787, -5814, -5841, -5867, -5894, --5921, -5948, -5975, -6001, -6028, -6055, -6082, -6109, -6135, -6162, --6189, -6216, -6243, -6269, -6296, -6323, -6350, -6376, -6403, -6430, --6457, -6484, -6510, -6537, -6564, -6591, -6618, -6644, -6671, -6698, --6725, -6752, -6778, -6805, -6832 }; +static INT16 Cr_G[] = { + 0, -26, -53, -79, -106, -133, -160, -187, -213, -240, -267, -294, + -321, -347, -374, -401, -428, -455, -481, -508, -535, -562, -589, -615, + -642, -669, -696, -722, -749, -776, -803, -830, -856, -883, -910, -937, + -964, -990, -1017, -1044, -1071, -1098, -1124, -1151, -1178, -1205, -1232, -1258, + -1285, -1312, -1339, -1366, -1392, -1419, -1446, -1473, -1500, -1526, -1553, -1580, + -1607, -1634, -1660, -1687, -1714, -1741, -1768, -1794, -1821, -1848, -1875, -1902, + -1928, -1955, -1982, -2009, -2036, -2062, -2089, -2116, -2143, -2169, -2196, -2223, + -2250, -2277, -2303, -2330, -2357, -2384, -2411, -2437, -2464, -2491, -2518, -2545, + -2571, -2598, -2625, -2652, -2679, -2705, -2732, -2759, -2786, -2813, -2839, -2866, + -2893, -2920, -2947, -2973, -3000, -3027, -3054, -3081, -3107, -3134, -3161, -3188, + -3215, -3241, -3268, -3295, -3322, -3349, -3375, -3402, -3429, -3456, -3483, -3509, + -3536, -3563, -3590, -3616, -3643, -3670, -3697, -3724, -3750, -3777, -3804, -3831, + -3858, -3884, -3911, -3938, -3965, -3992, -4018, -4045, -4072, -4099, -4126, -4152, + -4179, -4206, -4233, -4260, -4286, -4313, -4340, -4367, -4394, -4420, -4447, -4474, + -4501, -4528, -4554, -4581, -4608, -4635, -4662, -4688, -4715, -4742, -4769, -4796, + -4822, -4849, -4876, -4903, -4929, -4956, -4983, -5010, -5037, -5063, -5090, -5117, + -5144, -5171, -5197, -5224, -5251, -5278, -5305, -5331, -5358, -5385, -5412, -5439, + -5465, -5492, -5519, -5546, -5573, -5599, -5626, -5653, -5680, -5707, -5733, -5760, + -5787, -5814, -5841, -5867, -5894, -5921, -5948, -5975, -6001, -6028, -6055, -6082, + -6109, -6135, -6162, -6189, -6216, -6243, -6269, -6296, -6323, -6350, -6376, -6403, + -6430, -6457, -6484, -6510, -6537, -6564, -6591, -6618, -6644, -6671, -6698, -6725, + -6752, -6778, -6805, -6832}; -static INT16 Cr_B[] = { 0, -4, -9, -15, -20, -25, -30, -35, -41, -46, --51, -56, -61, -67, -72, -77, -82, -87, -93, -98, -103, -108, -113, --119, -124, -129, -134, -140, -145, -150, -155, -160, -166, -171, --176, -181, -186, -192, -197, -202, -207, -212, -218, -223, -228, --233, -238, -244, -249, -254, -259, -264, -270, -275, -280, -285, --290, -296, -301, -306, -311, -316, -322, -327, -332, -337, -342, --348, -353, -358, -363, -368, -374, -379, -384, -389, -394, -400, --405, -410, -415, -421, -426, -431, -436, -441, -447, -452, -457, --462, -467, -473, -478, -483, -488, -493, -499, -504, -509, -514, --519, -525, -530, -535, -540, -545, -551, -556, -561, -566, -571, --577, -582, -587, -592, -597, -603, -608, -613, -618, -623, -629, --634, -639, -644, -649, -655, -660, -665, -670, -675, -681, -686, --691, -696, -702, -707, -712, -717, -722, -728, -733, -738, -743, --748, -754, -759, -764, -769, -774, -780, -785, -790, -795, -800, --806, -811, -816, -821, -826, -832, -837, -842, -847, -852, -858, --863, -868, -873, -878, -884, -889, -894, -899, -904, -910, -915, --920, -925, -930, -936, -941, -946, -951, -957, -962, -967, -972, --977, -983, -988, -993, -998, -1003, -1009, -1014, -1019, -1024, --1029, -1035, -1040, -1045, -1050, -1055, -1061, -1066, -1071, -1076, --1081, -1087, -1092, -1097, -1102, -1107, -1113, -1118, -1123, -1128, --1133, -1139, -1144, -1149, -1154, -1159, -1165, -1170, -1175, -1180, --1185, -1191, -1196, -1201, -1206, -1211, -1217, -1222, -1227, -1232, --1238, -1243, -1248, -1253, -1258, -1264, -1269, -1274, -1279, -1284, --1290, -1295, -1300, -1305, -1310, -1316, -1321, -1326 }; +static INT16 Cr_B[] = { + 0, -4, -9, -15, -20, -25, -30, -35, -41, -46, -51, -56, + -61, -67, -72, -77, -82, -87, -93, -98, -103, -108, -113, -119, + -124, -129, -134, -140, -145, -150, -155, -160, -166, -171, -176, -181, + -186, -192, -197, -202, -207, -212, -218, -223, -228, -233, -238, -244, + -249, -254, -259, -264, -270, -275, -280, -285, -290, -296, -301, -306, + -311, -316, -322, -327, -332, -337, -342, -348, -353, -358, -363, -368, + -374, -379, -384, -389, -394, -400, -405, -410, -415, -421, -426, -431, + -436, -441, -447, -452, -457, -462, -467, -473, -478, -483, -488, -493, + -499, -504, -509, -514, -519, -525, -530, -535, -540, -545, -551, -556, + -561, -566, -571, -577, -582, -587, -592, -597, -603, -608, -613, -618, + -623, -629, -634, -639, -644, -649, -655, -660, -665, -670, -675, -681, + -686, -691, -696, -702, -707, -712, -717, -722, -728, -733, -738, -743, + -748, -754, -759, -764, -769, -774, -780, -785, -790, -795, -800, -806, + -811, -816, -821, -826, -832, -837, -842, -847, -852, -858, -863, -868, + -873, -878, -884, -889, -894, -899, -904, -910, -915, -920, -925, -930, + -936, -941, -946, -951, -957, -962, -967, -972, -977, -983, -988, -993, + -998, -1003, -1009, -1014, -1019, -1024, -1029, -1035, -1040, -1045, -1050, -1055, + -1061, -1066, -1071, -1076, -1081, -1087, -1092, -1097, -1102, -1107, -1113, -1118, + -1123, -1128, -1133, -1139, -1144, -1149, -1154, -1159, -1165, -1170, -1175, -1180, + -1185, -1191, -1196, -1201, -1206, -1211, -1217, -1222, -1227, -1232, -1238, -1243, + -1248, -1253, -1258, -1264, -1269, -1274, -1279, -1284, -1290, -1295, -1300, -1305, + -1310, -1316, -1321, -1326}; -static INT16 R_Cr[] = { -11484, -11394, -11305, -11215, -11125, --11036, -10946, -10856, -10766, -10677, -10587, -10497, -10407, --10318, -10228, -10138, -10049, -9959, -9869, -9779, -9690, -9600, --9510, -9420, -9331, -9241, -9151, -9062, -8972, -8882, -8792, -8703, --8613, -8523, -8433, -8344, -8254, -8164, -8075, -7985, -7895, -7805, --7716, -7626, -7536, -7446, -7357, -7267, -7177, -7088, -6998, -6908, --6818, -6729, -6639, -6549, -6459, -6370, -6280, -6190, -6101, -6011, --5921, -5831, -5742, -5652, -5562, -5472, -5383, -5293, -5203, -5113, --5024, -4934, -4844, -4755, -4665, -4575, -4485, -4396, -4306, -4216, --4126, -4037, -3947, -3857, -3768, -3678, -3588, -3498, -3409, -3319, --3229, -3139, -3050, -2960, -2870, -2781, -2691, -2601, -2511, -2422, --2332, -2242, -2152, -2063, -1973, -1883, -1794, -1704, -1614, -1524, --1435, -1345, -1255, -1165, -1076, -986, -896, -807, -717, -627, -537, --448, -358, -268, -178, -89, 0, 90, 179, 269, 359, 449, 538, 628, 718, -808, 897, 987, 1077, 1166, 1256, 1346, 1436, 1525, 1615, 1705, 1795, -1884, 1974, 2064, 2153, 2243, 2333, 2423, 2512, 2602, 2692, 2782, -2871, 2961, 3051, 3140, 3230, 3320, 3410, 3499, 3589, 3679, 3769, -3858, 3948, 4038, 4127, 4217, 4307, 4397, 4486, 4576, 4666, 4756, -4845, 4935, 5025, 5114, 5204, 5294, 5384, 5473, 5563, 5653, 5743, -5832, 5922, 6012, 6102, 6191, 6281, 6371, 6460, 6550, 6640, 6730, -6819, 6909, 6999, 7089, 7178, 7268, 7358, 7447, 7537, 7627, 7717, -7806, 7896, 7986, 8076, 8165, 8255, 8345, 8434, 8524, 8614, 8704, -8793, 8883, 8973, 9063, 9152, 9242, 9332, 9421, 9511, 9601, 9691, -9780, 9870, 9960, 10050, 10139, 10229, 10319, 10408, 10498, 10588, -10678, 10767, 10857, 10947, 11037, 11126, 11216, 11306, 11395 }; +static INT16 R_Cr[] = { + -11484, -11394, -11305, -11215, -11125, -11036, -10946, -10856, -10766, -10677, + -10587, -10497, -10407, -10318, -10228, -10138, -10049, -9959, -9869, -9779, + -9690, -9600, -9510, -9420, -9331, -9241, -9151, -9062, -8972, -8882, + -8792, -8703, -8613, -8523, -8433, -8344, -8254, -8164, -8075, -7985, + -7895, -7805, -7716, -7626, -7536, -7446, -7357, -7267, -7177, -7088, + -6998, -6908, -6818, -6729, -6639, -6549, -6459, -6370, -6280, -6190, + -6101, -6011, -5921, -5831, -5742, -5652, -5562, -5472, -5383, -5293, + -5203, -5113, -5024, -4934, -4844, -4755, -4665, -4575, -4485, -4396, + -4306, -4216, -4126, -4037, -3947, -3857, -3768, -3678, -3588, -3498, + -3409, -3319, -3229, -3139, -3050, -2960, -2870, -2781, -2691, -2601, + -2511, -2422, -2332, -2242, -2152, -2063, -1973, -1883, -1794, -1704, + -1614, -1524, -1435, -1345, -1255, -1165, -1076, -986, -896, -807, + -717, -627, -537, -448, -358, -268, -178, -89, 0, 90, + 179, 269, 359, 449, 538, 628, 718, 808, 897, 987, + 1077, 1166, 1256, 1346, 1436, 1525, 1615, 1705, 1795, 1884, + 1974, 2064, 2153, 2243, 2333, 2423, 2512, 2602, 2692, 2782, + 2871, 2961, 3051, 3140, 3230, 3320, 3410, 3499, 3589, 3679, + 3769, 3858, 3948, 4038, 4127, 4217, 4307, 4397, 4486, 4576, + 4666, 4756, 4845, 4935, 5025, 5114, 5204, 5294, 5384, 5473, + 5563, 5653, 5743, 5832, 5922, 6012, 6102, 6191, 6281, 6371, + 6460, 6550, 6640, 6730, 6819, 6909, 6999, 7089, 7178, 7268, + 7358, 7447, 7537, 7627, 7717, 7806, 7896, 7986, 8076, 8165, + 8255, 8345, 8434, 8524, 8614, 8704, 8793, 8883, 8973, 9063, + 9152, 9242, 9332, 9421, 9511, 9601, 9691, 9780, 9870, 9960, + 10050, 10139, 10229, 10319, 10408, 10498, 10588, 10678, 10767, 10857, + 10947, 11037, 11126, 11216, 11306, 11395}; -static INT16 G_Cb[] = { 2819, 2797, 2775, 2753, 2731, 2709, 2687, -2665, 2643, 2621, 2599, 2577, 2555, 2533, 2511, 2489, 2467, 2445, -2423, 2401, 2379, 2357, 2335, 2313, 2291, 2269, 2247, 2225, 2202, -2180, 2158, 2136, 2114, 2092, 2070, 2048, 2026, 2004, 1982, 1960, -1938, 1916, 1894, 1872, 1850, 1828, 1806, 1784, 1762, 1740, 1718, -1696, 1674, 1652, 1630, 1608, 1586, 1564, 1542, 1520, 1498, 1476, -1454, 1432, 1410, 1388, 1366, 1344, 1321, 1299, 1277, 1255, 1233, -1211, 1189, 1167, 1145, 1123, 1101, 1079, 1057, 1035, 1013, 991, 969, -947, 925, 903, 881, 859, 837, 815, 793, 771, 749, 727, 705, 683, 661, -639, 617, 595, 573, 551, 529, 507, 485, 463, 440, 418, 396, 374, 352, -330, 308, 286, 264, 242, 220, 198, 176, 154, 132, 110, 88, 66, 44, 22, -0, -21, -43, -65, -87, -109, -131, -153, -175, -197, -219, -241, -263, --285, -307, -329, -351, -373, -395, -417, -439, -462, -484, -506, --528, -550, -572, -594, -616, -638, -660, -682, -704, -726, -748, --770, -792, -814, -836, -858, -880, -902, -924, -946, -968, -990, --1012, -1034, -1056, -1078, -1100, -1122, -1144, -1166, -1188, -1210, --1232, -1254, -1276, -1298, -1320, -1343, -1365, -1387, -1409, -1431, --1453, -1475, -1497, -1519, -1541, -1563, -1585, -1607, -1629, -1651, --1673, -1695, -1717, -1739, -1761, -1783, -1805, -1827, -1849, -1871, --1893, -1915, -1937, -1959, -1981, -2003, -2025, -2047, -2069, -2091, --2113, -2135, -2157, -2179, -2201, -2224, -2246, -2268, -2290, -2312, --2334, -2356, -2378, -2400, -2422, -2444, -2466, -2488, -2510, -2532, --2554, -2576, -2598, -2620, -2642, -2664, -2686, -2708, -2730, -2752, --2774, -2796 }; +static INT16 G_Cb[] = { + 2819, 2797, 2775, 2753, 2731, 2709, 2687, 2665, 2643, 2621, 2599, 2577, + 2555, 2533, 2511, 2489, 2467, 2445, 2423, 2401, 2379, 2357, 2335, 2313, + 2291, 2269, 2247, 2225, 2202, 2180, 2158, 2136, 2114, 2092, 2070, 2048, + 2026, 2004, 1982, 1960, 1938, 1916, 1894, 1872, 1850, 1828, 1806, 1784, + 1762, 1740, 1718, 1696, 1674, 1652, 1630, 1608, 1586, 1564, 1542, 1520, + 1498, 1476, 1454, 1432, 1410, 1388, 1366, 1344, 1321, 1299, 1277, 1255, + 1233, 1211, 1189, 1167, 1145, 1123, 1101, 1079, 1057, 1035, 1013, 991, + 969, 947, 925, 903, 881, 859, 837, 815, 793, 771, 749, 727, + 705, 683, 661, 639, 617, 595, 573, 551, 529, 507, 485, 463, + 440, 418, 396, 374, 352, 330, 308, 286, 264, 242, 220, 198, + 176, 154, 132, 110, 88, 66, 44, 22, 0, -21, -43, -65, + -87, -109, -131, -153, -175, -197, -219, -241, -263, -285, -307, -329, + -351, -373, -395, -417, -439, -462, -484, -506, -528, -550, -572, -594, + -616, -638, -660, -682, -704, -726, -748, -770, -792, -814, -836, -858, + -880, -902, -924, -946, -968, -990, -1012, -1034, -1056, -1078, -1100, -1122, + -1144, -1166, -1188, -1210, -1232, -1254, -1276, -1298, -1320, -1343, -1365, -1387, + -1409, -1431, -1453, -1475, -1497, -1519, -1541, -1563, -1585, -1607, -1629, -1651, + -1673, -1695, -1717, -1739, -1761, -1783, -1805, -1827, -1849, -1871, -1893, -1915, + -1937, -1959, -1981, -2003, -2025, -2047, -2069, -2091, -2113, -2135, -2157, -2179, + -2201, -2224, -2246, -2268, -2290, -2312, -2334, -2356, -2378, -2400, -2422, -2444, + -2466, -2488, -2510, -2532, -2554, -2576, -2598, -2620, -2642, -2664, -2686, -2708, + -2730, -2752, -2774, -2796}; -static INT16 G_Cr[] = { 5850, 5805, 5759, 5713, 5667, 5622, 5576, -5530, 5485, 5439, 5393, 5347, 5302, 5256, 5210, 5165, 5119, 5073, -5028, 4982, 4936, 4890, 4845, 4799, 4753, 4708, 4662, 4616, 4570, -4525, 4479, 4433, 4388, 4342, 4296, 4251, 4205, 4159, 4113, 4068, -4022, 3976, 3931, 3885, 3839, 3794, 3748, 3702, 3656, 3611, 3565, -3519, 3474, 3428, 3382, 3336, 3291, 3245, 3199, 3154, 3108, 3062, -3017, 2971, 2925, 2879, 2834, 2788, 2742, 2697, 2651, 2605, 2559, -2514, 2468, 2422, 2377, 2331, 2285, 2240, 2194, 2148, 2102, 2057, -2011, 1965, 1920, 1874, 1828, 1782, 1737, 1691, 1645, 1600, 1554, -1508, 1463, 1417, 1371, 1325, 1280, 1234, 1188, 1143, 1097, 1051, -1006, 960, 914, 868, 823, 777, 731, 686, 640, 594, 548, 503, 457, 411, -366, 320, 274, 229, 183, 137, 91, 46, 0, -45, -90, -136, -182, -228, --273, -319, -365, -410, -456, -502, -547, -593, -639, -685, -730, --776, -822, -867, -913, -959, -1005, -1050, -1096, -1142, -1187, --1233, -1279, -1324, -1370, -1416, -1462, -1507, -1553, -1599, -1644, --1690, -1736, -1781, -1827, -1873, -1919, -1964, -2010, -2056, -2101, --2147, -2193, -2239, -2284, -2330, -2376, -2421, -2467, -2513, -2558, --2604, -2650, -2696, -2741, -2787, -2833, -2878, -2924, -2970, -3016, --3061, -3107, -3153, -3198, -3244, -3290, -3335, -3381, -3427, -3473, --3518, -3564, -3610, -3655, -3701, -3747, -3793, -3838, -3884, -3930, --3975, -4021, -4067, -4112, -4158, -4204, -4250, -4295, -4341, -4387, --4432, -4478, -4524, -4569, -4615, -4661, -4707, -4752, -4798, -4844, --4889, -4935, -4981, -5027, -5072, -5118, -5164, -5209, -5255, -5301, --5346, -5392, -5438, -5484, -5529, -5575, -5621, -5666, -5712, -5758, --5804 }; - -static INT16 B_Cb[] = { -14515, -14402, -14288, -14175, -14062, --13948, -13835, -13721, -13608, -13495, -13381, -13268, -13154, --13041, -12928, -12814, -12701, -12587, -12474, -12360, -12247, --12134, -12020, -11907, -11793, -11680, -11567, -11453, -11340, --11226, -11113, -11000, -10886, -10773, -10659, -10546, -10433, --10319, -10206, -10092, -9979, -9865, -9752, -9639, -9525, -9412, --9298, -9185, -9072, -8958, -8845, -8731, -8618, -8505, -8391, -8278, --8164, -8051, -7938, -7824, -7711, -7597, -7484, -7371, -7257, -7144, --7030, -6917, -6803, -6690, -6577, -6463, -6350, -6236, -6123, -6010, --5896, -5783, -5669, -5556, -5443, -5329, -5216, -5102, -4989, -4876, --4762, -4649, -4535, -4422, -4309, -4195, -4082, -3968, -3855, -3741, --3628, -3515, -3401, -3288, -3174, -3061, -2948, -2834, -2721, -2607, --2494, -2381, -2267, -2154, -2040, -1927, -1814, -1700, -1587, -1473, --1360, -1246, -1133, -1020, -906, -793, -679, -566, -453, -339, -226, --112, 0, 113, 227, 340, 454, 567, 680, 794, 907, 1021, 1134, 1247, -1361, 1474, 1588, 1701, 1815, 1928, 2041, 2155, 2268, 2382, 2495, -2608, 2722, 2835, 2949, 3062, 3175, 3289, 3402, 3516, 3629, 3742, -3856, 3969, 4083, 4196, 4310, 4423, 4536, 4650, 4763, 4877, 4990, -5103, 5217, 5330, 5444, 5557, 5670, 5784, 5897, 6011, 6124, 6237, -6351, 6464, 6578, 6691, 6804, 6918, 7031, 7145, 7258, 7372, 7485, -7598, 7712, 7825, 7939, 8052, 8165, 8279, 8392, 8506, 8619, 8732, -8846, 8959, 9073, 9186, 9299, 9413, 9526, 9640, 9753, 9866, 9980, -10093, 10207, 10320, 10434, 10547, 10660, 10774, 10887, 11001, 11114, -11227, 11341, 11454, 11568, 11681, 11794, 11908, 12021, 12135, 12248, -12361, 12475, 12588, 12702, 12815, 12929, 13042, 13155, 13269, 13382, -13496, 13609, 13722, 13836, 13949, 14063, 14176, 14289, 14403 }; +static INT16 G_Cr[] = { + 5850, 5805, 5759, 5713, 5667, 5622, 5576, 5530, 5485, 5439, 5393, 5347, + 5302, 5256, 5210, 5165, 5119, 5073, 5028, 4982, 4936, 4890, 4845, 4799, + 4753, 4708, 4662, 4616, 4570, 4525, 4479, 4433, 4388, 4342, 4296, 4251, + 4205, 4159, 4113, 4068, 4022, 3976, 3931, 3885, 3839, 3794, 3748, 3702, + 3656, 3611, 3565, 3519, 3474, 3428, 3382, 3336, 3291, 3245, 3199, 3154, + 3108, 3062, 3017, 2971, 2925, 2879, 2834, 2788, 2742, 2697, 2651, 2605, + 2559, 2514, 2468, 2422, 2377, 2331, 2285, 2240, 2194, 2148, 2102, 2057, + 2011, 1965, 1920, 1874, 1828, 1782, 1737, 1691, 1645, 1600, 1554, 1508, + 1463, 1417, 1371, 1325, 1280, 1234, 1188, 1143, 1097, 1051, 1006, 960, + 914, 868, 823, 777, 731, 686, 640, 594, 548, 503, 457, 411, + 366, 320, 274, 229, 183, 137, 91, 46, 0, -45, -90, -136, + -182, -228, -273, -319, -365, -410, -456, -502, -547, -593, -639, -685, + -730, -776, -822, -867, -913, -959, -1005, -1050, -1096, -1142, -1187, -1233, + -1279, -1324, -1370, -1416, -1462, -1507, -1553, -1599, -1644, -1690, -1736, -1781, + -1827, -1873, -1919, -1964, -2010, -2056, -2101, -2147, -2193, -2239, -2284, -2330, + -2376, -2421, -2467, -2513, -2558, -2604, -2650, -2696, -2741, -2787, -2833, -2878, + -2924, -2970, -3016, -3061, -3107, -3153, -3198, -3244, -3290, -3335, -3381, -3427, + -3473, -3518, -3564, -3610, -3655, -3701, -3747, -3793, -3838, -3884, -3930, -3975, + -4021, -4067, -4112, -4158, -4204, -4250, -4295, -4341, -4387, -4432, -4478, -4524, + -4569, -4615, -4661, -4707, -4752, -4798, -4844, -4889, -4935, -4981, -5027, -5072, + -5118, -5164, -5209, -5255, -5301, -5346, -5392, -5438, -5484, -5529, -5575, -5621, + -5666, -5712, -5758, -5804}; +static INT16 B_Cb[] = { + -14515, -14402, -14288, -14175, -14062, -13948, -13835, -13721, -13608, -13495, + -13381, -13268, -13154, -13041, -12928, -12814, -12701, -12587, -12474, -12360, + -12247, -12134, -12020, -11907, -11793, -11680, -11567, -11453, -11340, -11226, + -11113, -11000, -10886, -10773, -10659, -10546, -10433, -10319, -10206, -10092, + -9979, -9865, -9752, -9639, -9525, -9412, -9298, -9185, -9072, -8958, + -8845, -8731, -8618, -8505, -8391, -8278, -8164, -8051, -7938, -7824, + -7711, -7597, -7484, -7371, -7257, -7144, -7030, -6917, -6803, -6690, + -6577, -6463, -6350, -6236, -6123, -6010, -5896, -5783, -5669, -5556, + -5443, -5329, -5216, -5102, -4989, -4876, -4762, -4649, -4535, -4422, + -4309, -4195, -4082, -3968, -3855, -3741, -3628, -3515, -3401, -3288, + -3174, -3061, -2948, -2834, -2721, -2607, -2494, -2381, -2267, -2154, + -2040, -1927, -1814, -1700, -1587, -1473, -1360, -1246, -1133, -1020, + -906, -793, -679, -566, -453, -339, -226, -112, 0, 113, + 227, 340, 454, 567, 680, 794, 907, 1021, 1134, 1247, + 1361, 1474, 1588, 1701, 1815, 1928, 2041, 2155, 2268, 2382, + 2495, 2608, 2722, 2835, 2949, 3062, 3175, 3289, 3402, 3516, + 3629, 3742, 3856, 3969, 4083, 4196, 4310, 4423, 4536, 4650, + 4763, 4877, 4990, 5103, 5217, 5330, 5444, 5557, 5670, 5784, + 5897, 6011, 6124, 6237, 6351, 6464, 6578, 6691, 6804, 6918, + 7031, 7145, 7258, 7372, 7485, 7598, 7712, 7825, 7939, 8052, + 8165, 8279, 8392, 8506, 8619, 8732, 8846, 8959, 9073, 9186, + 9299, 9413, 9526, 9640, 9753, 9866, 9980, 10093, 10207, 10320, + 10434, 10547, 10660, 10774, 10887, 11001, 11114, 11227, 11341, 11454, + 11568, 11681, 11794, 11908, 12021, 12135, 12248, 12361, 12475, 12588, + 12702, 12815, 12929, 13042, 13155, 13269, 13382, 13496, 13609, 13722, + 13836, 13949, 14063, 14176, 14289, 14403}; void -ImagingConvertRGB2YCbCr(UINT8* out, const UINT8* in, int pixels) -{ - int x; - UINT8 a; - int r, g, b; - int y, cr, cb; - - for (x = 0; x < pixels; x++, in +=4, out += 4) { - - r = in[0]; - g = in[1]; - b = in[2]; - a = in[3]; - - y = (Y_R[r] + Y_G[g] + Y_B[b]) >> SCALE; - cb = ((Cb_R[r] + Cb_G[g] + Cb_B[b]) >> SCALE) + 128; - cr = ((Cr_R[r] + Cr_G[g] + Cr_B[b]) >> SCALE) + 128; - - out[0] = (UINT8) y; - out[1] = (UINT8) cb; - out[2] = (UINT8) cr; - out[3] = a; - } -} - -void -ImagingConvertYCbCr2RGB(UINT8* out, const UINT8* in, int pixels) -{ +ImagingConvertRGB2YCbCr(UINT8 *out, const UINT8 *in, int pixels) { int x; UINT8 a; int r, g, b; int y, cr, cb; for (x = 0; x < pixels; x++, in += 4, out += 4) { + r = in[0]; + g = in[1]; + b = in[2]; + a = in[3]; + y = (Y_R[r] + Y_G[g] + Y_B[b]) >> SCALE; + cb = ((Cb_R[r] + Cb_G[g] + Cb_B[b]) >> SCALE) + 128; + cr = ((Cr_R[r] + Cr_G[g] + Cr_B[b]) >> SCALE) + 128; + + out[0] = (UINT8)y; + out[1] = (UINT8)cb; + out[2] = (UINT8)cr; + out[3] = a; + } +} + +void +ImagingConvertYCbCr2RGB(UINT8 *out, const UINT8 *in, int pixels) { + int x; + UINT8 a; + int r, g, b; + int y, cr, cb; + + for (x = 0; x < pixels; x++, in += 4, out += 4) { y = in[0]; cb = in[1]; cr = in[2]; a = in[3]; - r = y + (( R_Cr[cr]) >> SCALE); + r = y + ((R_Cr[cr]) >> SCALE); g = y + ((G_Cb[cb] + G_Cr[cr]) >> SCALE); - b = y + ((B_Cb[cb] ) >> SCALE); + b = y + ((B_Cb[cb]) >> SCALE); out[0] = (r <= 0) ? 0 : (r >= 255) ? 255 : r; out[1] = (g <= 0) ? 0 : (g >= 255) ? 255 : g; diff --git a/src/libImaging/Copy.c b/src/libImaging/Copy.c index 5b4899f39..571133e14 100644 --- a/src/libImaging/Copy.c +++ b/src/libImaging/Copy.c @@ -15,18 +15,15 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" - static Imaging -_copy(Imaging imOut, Imaging imIn) -{ +_copy(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int y; if (!imIn) { - return (Imaging) ImagingError_ValueError(NULL); + return (Imaging)ImagingError_ValueError(NULL); } imOut = ImagingNew2Dirty(imIn->mode, imOut, imIn); @@ -50,13 +47,11 @@ _copy(Imaging imOut, Imaging imIn) } Imaging -ImagingCopy(Imaging imIn) -{ +ImagingCopy(Imaging imIn) { return _copy(NULL, imIn); } Imaging -ImagingCopy2(Imaging imOut, Imaging imIn) -{ +ImagingCopy2(Imaging imOut, Imaging imIn) { return _copy(imOut, imIn); } diff --git a/src/libImaging/Crop.c b/src/libImaging/Crop.c index d136edbfc..2425b4cd5 100644 --- a/src/libImaging/Crop.c +++ b/src/libImaging/Crop.c @@ -15,20 +15,17 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - Imaging -ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1) -{ +ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1) { Imaging imOut; int xsize, ysize; int dx0, dy0, dx1, dy1; INT32 zero = 0; if (!imIn) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } xsize = sx1 - sx0; @@ -48,7 +45,7 @@ ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1) ImagingCopyPalette(imOut, imIn); if (sx0 < 0 || sy0 < 0 || sx1 > imIn->xsize || sy1 > imIn->ysize) { - (void) ImagingFill(imOut, &zero); + (void)ImagingFill(imOut, &zero); } dx0 = -sx0; diff --git a/src/libImaging/Dib.c b/src/libImaging/Dib.c index 202b0c9fa..f8a2901b8 100644 --- a/src/libImaging/Dib.c +++ b/src/libImaging/Dib.c @@ -19,21 +19,18 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #ifdef _WIN32 #include "ImDib.h" - -char* -ImagingGetModeDIB(int size_out[2]) -{ +char * +ImagingGetModeDIB(int size_out[2]) { /* Get device characteristics */ HDC dc; - char* mode; + char *mode; dc = CreateCompatibleDC(NULL); @@ -55,10 +52,8 @@ ImagingGetModeDIB(int size_out[2]) return mode; } - ImagingDIB -ImagingNewDIB(const char *mode, int xsize, int ysize) -{ +ImagingNewDIB(const char *mode, int xsize, int ysize) { /* Create a Windows bitmap */ ImagingDIB dib; @@ -66,23 +61,21 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) int i; /* Check mode */ - if (strcmp(mode, "1") != 0 && strcmp(mode, "L") != 0 && - strcmp(mode, "RGB") != 0) { - return (ImagingDIB) ImagingError_ModeError(); + if (strcmp(mode, "1") != 0 && strcmp(mode, "L") != 0 && strcmp(mode, "RGB") != 0) { + return (ImagingDIB)ImagingError_ModeError(); } /* Create DIB context and info header */ /* malloc check ok, small constant allocation */ - dib = (ImagingDIB) malloc(sizeof(*dib)); + dib = (ImagingDIB)malloc(sizeof(*dib)); if (!dib) { - return (ImagingDIB) ImagingError_MemoryError(); + return (ImagingDIB)ImagingError_MemoryError(); } /* malloc check ok, small constant allocation */ - dib->info = (BITMAPINFO*) malloc(sizeof(BITMAPINFOHEADER) + - 256 * sizeof(RGBQUAD)); + dib->info = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); if (!dib->info) { free(dib); - return (ImagingDIB) ImagingError_MemoryError(); + return (ImagingDIB)ImagingError_MemoryError(); } memset(dib->info, 0, sizeof(BITMAPINFOHEADER)); @@ -90,7 +83,7 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) dib->info->bmiHeader.biWidth = xsize; dib->info->bmiHeader.biHeight = ysize; dib->info->bmiHeader.biPlanes = 1; - dib->info->bmiHeader.biBitCount = strlen(mode)*8; + dib->info->bmiHeader.biBitCount = strlen(mode) * 8; dib->info->bmiHeader.biCompression = BI_RGB; /* Create DIB */ @@ -98,15 +91,15 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) if (!dib->dc) { free(dib->info); free(dib); - return (ImagingDIB) ImagingError_MemoryError(); + return (ImagingDIB)ImagingError_MemoryError(); } - dib->bitmap = CreateDIBSection(dib->dc, dib->info, DIB_RGB_COLORS, - &dib->bits, NULL, 0); + dib->bitmap = + CreateDIBSection(dib->dc, dib->info, DIB_RGB_COLORS, &dib->bits, NULL, 0); if (!dib->bitmap) { free(dib->info); free(dib); - return (ImagingDIB) ImagingError_MemoryError(); + return (ImagingDIB)ImagingError_MemoryError(); } strcpy(dib->mode, mode); @@ -117,7 +110,7 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) dib->linesize = (xsize * dib->pixelsize + 3) & -4; if (dib->pixelsize == 1) { - dib->pack = dib->unpack = (ImagingShuffler) memcpy; + dib->pack = dib->unpack = (ImagingShuffler)memcpy; } else { dib->pack = ImagingPackBGR; dib->unpack = ImagingPackBGR; @@ -131,9 +124,7 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) /* Bind a palette to it as well (only required for 8-bit DIBs) */ if (dib->pixelsize == 1) { for (i = 0; i < 256; i++) { - palette[i].rgbRed = - palette[i].rgbGreen = - palette[i].rgbBlue = i; + palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = i; palette[i].rgbReserved = 0; } SetDIBColorTable(dib->dc, 0, 256, palette); @@ -141,9 +132,8 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) /* Create an associated palette (for 8-bit displays only) */ if (strcmp(ImagingGetModeDIB(NULL), "P") == 0) { - - char palbuf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)]; - LPLOGPALETTE pal = (LPLOGPALETTE) palbuf; + char palbuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)]; + LPLOGPALETTE pal = (LPLOGPALETTE)palbuf; int i, r, g, b; /* Load system palette */ @@ -152,7 +142,6 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) GetSystemPaletteEntries(dib->dc, 0, 256, pal->palPalEntry); if (strcmp(mode, "L") == 0) { - /* Greyscale DIB. Fill all 236 slots with a greyscale ramp * (this is usually overkill on Windows since VGA only offers * 6 bits greyscale resolution). Ignore the slots already @@ -160,16 +149,14 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) i = 10; for (r = 0; r < 236; r++) { - pal->palPalEntry[i].peRed = - pal->palPalEntry[i].peGreen = - pal->palPalEntry[i].peBlue = i; + pal->palPalEntry[i].peRed = pal->palPalEntry[i].peGreen = + pal->palPalEntry[i].peBlue = i; i++; } dib->palette = CreatePalette(pal); } else if (strcmp(mode, "RGB") == 0) { - #ifdef CUBE216 /* Colour DIB. Create a 6x6x6 colour cube (216 entries) and @@ -187,11 +174,10 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) } } } - for (r = 1; r < 22-1; r++) { + for (r = 1; r < 22 - 1; r++) { /* Black and white are already provided by the cube. */ - pal->palPalEntry[i].peRed = - pal->palPalEntry[i].peGreen = - pal->palPalEntry[i].peBlue = r * 255 / (22-1); + pal->palPalEntry[i].peRed = pal->palPalEntry[i].peGreen = + pal->palPalEntry[i].peBlue = r * 255 / (22 - 1); i++; } @@ -214,76 +200,91 @@ ImagingNewDIB(const char *mode, int xsize, int ysize) #endif dib->palette = CreatePalette(pal); - } - } return dib; } void -ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]) -{ +ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]) { /* Paste image data into a bitmap */ /* FIXME: check size! */ int y; for (y = 0; y < im->ysize; y++) { - dib->pack(dib->bits + dib->linesize*(dib->ysize-(xy[1]+y)-1) + - xy[0]*dib->pixelsize, im->image[y], im->xsize); + dib->pack( + dib->bits + dib->linesize * (dib->ysize - (xy[1] + y) - 1) + + xy[0] * dib->pixelsize, + im->image[y], + im->xsize); } - } void -ImagingExposeDIB(ImagingDIB dib, void *dc) -{ +ImagingExposeDIB(ImagingDIB dib, void *dc) { /* Copy bitmap to display */ if (dib->palette != 0) { - SelectPalette((HDC) dc, dib->palette, FALSE); + SelectPalette((HDC)dc, dib->palette, FALSE); } - BitBlt((HDC) dc, 0, 0, dib->xsize, dib->ysize, dib->dc, 0, 0, SRCCOPY); + BitBlt((HDC)dc, 0, 0, dib->xsize, dib->ysize, dib->dc, 0, 0, SRCCOPY); } void -ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]) -{ +ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]) { /* Copy bitmap to printer/display */ - if (GetDeviceCaps((HDC) dc, RASTERCAPS) & RC_STRETCHDIB) { + if (GetDeviceCaps((HDC)dc, RASTERCAPS) & RC_STRETCHDIB) { /* stretchdib (printers) */ - StretchDIBits((HDC) dc, dst[0], dst[1], dst[2]-dst[0], dst[3]-dst[1], - src[0], src[1], src[2]-src[0], src[3]-src[1], dib->bits, - dib->info, DIB_RGB_COLORS, SRCCOPY); + StretchDIBits( + (HDC)dc, + dst[0], + dst[1], + dst[2] - dst[0], + dst[3] - dst[1], + src[0], + src[1], + src[2] - src[0], + src[3] - src[1], + dib->bits, + dib->info, + DIB_RGB_COLORS, + SRCCOPY); } else { /* stretchblt (displays) */ if (dib->palette != 0) { - SelectPalette((HDC) dc, dib->palette, FALSE); + SelectPalette((HDC)dc, dib->palette, FALSE); } - StretchBlt((HDC) dc, dst[0], dst[1], dst[2]-dst[0], dst[3]-dst[1], - dib->dc, src[0], src[1], src[2]-src[0], src[3]-src[1], - SRCCOPY); + StretchBlt( + (HDC)dc, + dst[0], + dst[1], + dst[2] - dst[0], + dst[3] - dst[1], + dib->dc, + src[0], + src[1], + src[2] - src[0], + src[3] - src[1], + SRCCOPY); } } int -ImagingQueryPaletteDIB(ImagingDIB dib, void *dc) -{ +ImagingQueryPaletteDIB(ImagingDIB dib, void *dc) { /* Install bitmap palette */ int n; if (dib->palette != 0) { - /* Realize associated palette */ - HPALETTE now = SelectPalette((HDC) dc, dib->palette, FALSE); - n = RealizePalette((HDC) dc); + HPALETTE now = SelectPalette((HDC)dc, dib->palette, FALSE); + n = RealizePalette((HDC)dc); /* Restore palette */ - SelectPalette((HDC) dc, now, FALSE); + SelectPalette((HDC)dc, now, FALSE); } else { n = 0; @@ -293,8 +294,7 @@ ImagingQueryPaletteDIB(ImagingDIB dib, void *dc) } void -ImagingDeleteDIB(ImagingDIB dib) -{ +ImagingDeleteDIB(ImagingDIB dib) { /* Clean up */ if (dib->palette) { diff --git a/src/libImaging/Draw.c b/src/libImaging/Draw.c index 339e1cd35..161895dc6 100644 --- a/src/libImaging/Draw.c +++ b/src/libImaging/Draw.c @@ -37,17 +37,17 @@ #include #include -#define CEIL(v) (int) ceil(v) -#define FLOOR(v) ((v) >= 0.0 ? (int) (v) : (int) floor(v)) +#define CEIL(v) (int)ceil(v) +#define FLOOR(v) ((v) >= 0.0 ? (int)(v) : (int)floor(v)) -#define INK8(ink) (*(UINT8*)ink) +#define INK8(ink) (*(UINT8 *)ink) /* * Rounds around zero (up=away from zero, down=towards zero) * This guarantees that ROUND_UP|DOWN(f) == -ROUND_UP|DOWN(-f) */ -#define ROUND_UP(f) ((int) ((f) >= 0.0 ? floor((f) + 0.5F) : -floor(fabs(f) + 0.5F))) -#define ROUND_DOWN(f) ((int) ((f) >= 0.0 ? ceil((f) - 0.5F) : -ceil(fabs(f) - 0.5F))) +#define ROUND_UP(f) ((int)((f) >= 0.0 ? floor((f) + 0.5F) : -floor(fabs(f) + 0.5F))) +#define ROUND_DOWN(f) ((int)((f) >= 0.0 ? ceil((f)-0.5F) : -ceil(fabs(f) - 0.5F))) /* -------------------------------------------------------------------- */ /* Primitives */ @@ -65,34 +65,31 @@ typedef struct { typedef void (*hline_handler)(Imaging, int, int, int, int); static inline void -point8(Imaging im, int x, int y, int ink) -{ +point8(Imaging im, int x, int y, int ink) { if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) { if (strncmp(im->mode, "I;16", 4) == 0) { - im->image8[y][x*2] = (UINT8) ink; - im->image8[y][x*2+1] = (UINT8) ink; + im->image8[y][x * 2] = (UINT8)ink; + im->image8[y][x * 2 + 1] = (UINT8)ink; } else { - im->image8[y][x] = (UINT8) ink; + im->image8[y][x] = (UINT8)ink; } } } static inline void -point32(Imaging im, int x, int y, int ink) -{ +point32(Imaging im, int x, int y, int ink) { if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) { im->image32[y][x] = ink; } } static inline void -point32rgba(Imaging im, int x, int y, int ink) -{ +point32rgba(Imaging im, int x, int y, int ink) { unsigned int tmp1; if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) { - UINT8* out = (UINT8*) im->image[y]+x*4; - UINT8* in = (UINT8*) &ink; + UINT8 *out = (UINT8 *)im->image[y] + x * 4; + UINT8 *in = (UINT8 *)&ink; out[0] = BLEND(in[3], out[0], in[0], tmp1); out[1] = BLEND(in[3], out[1], in[1], tmp1); out[2] = BLEND(in[3], out[2], in[2], tmp1); @@ -100,8 +97,7 @@ point32rgba(Imaging im, int x, int y, int ink) } static inline void -hline8(Imaging im, int x0, int y0, int x1, int ink) -{ +hline8(Imaging im, int x0, int y0, int x1, int ink) { int tmp, pixelwidth; if (y0 >= 0 && y0 < im->ysize) { @@ -116,21 +112,22 @@ hline8(Imaging im, int x0, int y0, int x1, int ink) if (x1 < 0) { return; } else if (x1 >= im->xsize) { - x1 = im->xsize-1; + x1 = im->xsize - 1; } if (x0 <= x1) { pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1; - memset(im->image8[y0] + x0 * pixelwidth, (UINT8) ink, - (x1 - x0 + 1) * pixelwidth); + memset( + im->image8[y0] + x0 * pixelwidth, + (UINT8)ink, + (x1 - x0 + 1) * pixelwidth); } } } static inline void -hline32(Imaging im, int x0, int y0, int x1, int ink) -{ +hline32(Imaging im, int x0, int y0, int x1, int ink) { int tmp; - INT32* p; + INT32 *p; if (y0 >= 0 && y0 < im->ysize) { if (x0 > x1) { @@ -144,7 +141,7 @@ hline32(Imaging im, int x0, int y0, int x1, int ink) if (x1 < 0) { return; } else if (x1 >= im->xsize) { - x1 = im->xsize-1; + x1 = im->xsize - 1; } p = im->image32[y0]; while (x0 <= x1) { @@ -154,8 +151,7 @@ hline32(Imaging im, int x0, int y0, int x1, int ink) } static inline void -hline32rgba(Imaging im, int x0, int y0, int x1, int ink) -{ +hline32rgba(Imaging im, int x0, int y0, int x1, int ink) { int tmp; unsigned int tmp1; @@ -171,36 +167,36 @@ hline32rgba(Imaging im, int x0, int y0, int x1, int ink) if (x1 < 0) { return; } else if (x1 >= im->xsize) { - x1 = im->xsize-1; + x1 = im->xsize - 1; } if (x0 <= x1) { - UINT8* out = (UINT8*) im->image[y0]+x0*4; - UINT8* in = (UINT8*) &ink; + UINT8 *out = (UINT8 *)im->image[y0] + x0 * 4; + UINT8 *in = (UINT8 *)&ink; while (x0 <= x1) { out[0] = BLEND(in[3], out[0], in[0], tmp1); out[1] = BLEND(in[3], out[1], in[1], tmp1); out[2] = BLEND(in[3], out[2], in[2], tmp1); - x0++; out += 4; + x0++; + out += 4; } } } } static inline void -line8(Imaging im, int x0, int y0, int x1, int y1, int ink) -{ +line8(Imaging im, int x0, int y0, int x1, int y1, int ink) { int i, n, e; int dx, dy; int xs, ys; /* normalize coordinates */ - dx = x1-x0; + dx = x1 - x0; if (dx < 0) { dx = -dx, xs = -1; } else { xs = 1; } - dy = y1-y0; + dy = y1 - y0; if (dy < 0) { dy = -dy, ys = -1; } else { @@ -210,7 +206,6 @@ line8(Imaging im, int x0, int y0, int x1, int y1, int ink) n = (dx > dy) ? dx : dy; if (dx == 0) { - /* vertical */ for (i = 0; i < dy; i++) { point8(im, x0, y0, ink); @@ -218,7 +213,6 @@ line8(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else if (dy == 0) { - /* horizontal */ for (i = 0; i < dx; i++) { point8(im, x0, y0, ink); @@ -226,7 +220,6 @@ line8(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else if (dx > dy) { - /* bresenham, horizontal slope */ n = dx; dy += dy; @@ -244,7 +237,6 @@ line8(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else { - /* bresenham, vertical slope */ n = dy; dx += dx; @@ -260,25 +252,23 @@ line8(Imaging im, int x0, int y0, int x1, int y1, int ink) e += dx; y0 += ys; } - } } static inline void -line32(Imaging im, int x0, int y0, int x1, int y1, int ink) -{ +line32(Imaging im, int x0, int y0, int x1, int y1, int ink) { int i, n, e; int dx, dy; int xs, ys; /* normalize coordinates */ - dx = x1-x0; + dx = x1 - x0; if (dx < 0) { dx = -dx, xs = -1; } else { xs = 1; } - dy = y1-y0; + dy = y1 - y0; if (dy < 0) { dy = -dy, ys = -1; } else { @@ -288,7 +278,6 @@ line32(Imaging im, int x0, int y0, int x1, int y1, int ink) n = (dx > dy) ? dx : dy; if (dx == 0) { - /* vertical */ for (i = 0; i < dy; i++) { point32(im, x0, y0, ink); @@ -296,7 +285,6 @@ line32(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else if (dy == 0) { - /* horizontal */ for (i = 0; i < dx; i++) { point32(im, x0, y0, ink); @@ -304,7 +292,6 @@ line32(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else if (dx > dy) { - /* bresenham, horizontal slope */ n = dx; dy += dy; @@ -322,7 +309,6 @@ line32(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else { - /* bresenham, vertical slope */ n = dy; dx += dx; @@ -338,25 +324,23 @@ line32(Imaging im, int x0, int y0, int x1, int y1, int ink) e += dx; y0 += ys; } - } } static inline void -line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink) -{ +line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink) { int i, n, e; int dx, dy; int xs, ys; /* normalize coordinates */ - dx = x1-x0; + dx = x1 - x0; if (dx < 0) { dx = -dx, xs = -1; } else { xs = 1; } - dy = y1-y0; + dy = y1 - y0; if (dy < 0) { dy = -dy, ys = -1; } else { @@ -366,7 +350,6 @@ line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink) n = (dx > dy) ? dx : dy; if (dx == 0) { - /* vertical */ for (i = 0; i < dy; i++) { point32rgba(im, x0, y0, ink); @@ -374,7 +357,6 @@ line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else if (dy == 0) { - /* horizontal */ for (i = 0; i < dx; i++) { point32rgba(im, x0, y0, ink); @@ -382,7 +364,6 @@ line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else if (dx > dy) { - /* bresenham, horizontal slope */ n = dx; dy += dy; @@ -400,7 +381,6 @@ line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink) } } else { - /* bresenham, vertical slope */ n = dy; dx += dx; @@ -416,14 +396,12 @@ line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink) e += dx; y0 += ys; } - } } static int -x_cmp(const void *x0, const void *x1) -{ - float diff = *((float*)x0) - *((float*)x1); +x_cmp(const void *x0, const void *x1) { + float diff = *((float *)x0) - *((float *)x1); if (diff < 0) { return -1; } else if (diff > 0) { @@ -433,10 +411,9 @@ x_cmp(const void *x0, const void *x1) } } - static void -draw_horizontal_lines(Imaging im, int n, Edge *e, int ink, int *x_pos, int y, hline_handler hline) -{ +draw_horizontal_lines( + Imaging im, int n, Edge *e, int ink, int *x_pos, int y, hline_handler hline) { int i; for (i = 0; i < n; i++) { if (e[i].ymin == y && e[i].ymin == e[i].ymax) { @@ -458,7 +435,7 @@ draw_horizontal_lines(Imaging im, int n, Edge *e, int ink, int *x_pos, int y, hl } (*hline)(im, xmin, e[i].ymin, xmax, ink); - *x_pos = xmax+1; + *x_pos = xmax + 1; } } } @@ -467,12 +444,9 @@ draw_horizontal_lines(Imaging im, int n, Edge *e, int ink, int *x_pos, int y, hl * Filled polygon draw function using scan line algorithm. */ static inline int -polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, - hline_handler hline) -{ - - Edge** edge_table; - float* xx; +polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler hline) { + Edge **edge_table; + float *xx; int edge_count = 0; int ymin = im->ysize - 1; int ymax = 0; @@ -484,7 +458,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, /* Initialize the edge table and find polygon boundaries */ /* malloc check ok, using calloc */ - edge_table = calloc(n, sizeof(Edge*)); + edge_table = calloc(n, sizeof(Edge *)); if (!edge_table) { return -1; } @@ -519,7 +493,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, int j = 0; int x_pos = 0; for (i = 0; i < edge_count; i++) { - Edge* current = edge_table[i]; + Edge *current = edge_table[i]; if (ymin >= current->ymin && ymin <= current->ymax) { xx[j++] = (ymin - current->y0) * current->dx + current->x0; } @@ -542,7 +516,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, continue; } - int x_start = ROUND_UP(xx[i-1]); + int x_start = ROUND_UP(xx[i - 1]); if (x_pos > x_start) { // Line would be partway through x_pos, so increase the starting point x_start = x_pos; @@ -552,7 +526,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, } } (*hline)(im, x_start, ymin, x_end, ink); - x_pos = x_end+1; + x_pos = x_end + 1; } draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline); } @@ -563,26 +537,22 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, } static inline int -polygon8(Imaging im, int n, Edge *e, int ink, int eofill) -{ +polygon8(Imaging im, int n, Edge *e, int ink, int eofill) { return polygon_generic(im, n, e, ink, eofill, hline8); } static inline int -polygon32(Imaging im, int n, Edge *e, int ink, int eofill) -{ +polygon32(Imaging im, int n, Edge *e, int ink, int eofill) { return polygon_generic(im, n, e, ink, eofill, hline32); } static inline int -polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill) -{ +polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill) { return polygon_generic(im, n, e, ink, eofill, hline32rgba); } static inline void -add_edge(Edge *e, int x0, int y0, int x1, int y1) -{ +add_edge(Edge *e, int x0, int y0, int x1, int y1) { /* printf("edge %d %d %d %d\n", x0, y0, x1, y1); */ if (x0 <= x1) { @@ -601,7 +571,7 @@ add_edge(Edge *e, int x0, int y0, int x1, int y1) e->d = 0; e->dx = 0.0; } else { - e->dx = ((float)(x1-x0)) / (y1-y0); + e->dx = ((float)(x1 - x0)) / (y1 - y0); if (y0 == e->ymin) { e->d = 1; } else { @@ -620,27 +590,26 @@ typedef struct { int (*polygon)(Imaging im, int n, Edge *e, int ink, int eofill); } DRAW; -DRAW draw8 = { point8, hline8, line8, polygon8 }; -DRAW draw32 = { point32, hline32, line32, polygon32 }; -DRAW draw32rgba = { point32rgba, hline32rgba, line32rgba, polygon32rgba }; +DRAW draw8 = {point8, hline8, line8, polygon8}; +DRAW draw32 = {point32, hline32, line32, polygon32}; +DRAW draw32rgba = {point32rgba, hline32rgba, line32rgba, polygon32rgba}; /* -------------------------------------------------------------------- */ /* Interface */ /* -------------------------------------------------------------------- */ -#define DRAWINIT()\ - if (im->image8) {\ - draw = &draw8;\ - ink = INK8(ink_);\ - } else {\ - draw = (op) ? &draw32rgba : &draw32; \ - memcpy(&ink, ink_, sizeof(ink)); \ +#define DRAWINIT() \ + if (im->image8) { \ + draw = &draw8; \ + ink = INK8(ink_); \ + } else { \ + draw = (op) ? &draw32rgba : &draw32; \ + memcpy(&ink, ink_, sizeof(ink)); \ } int -ImagingDrawPoint(Imaging im, int x0, int y0, const void* ink_, int op) -{ - DRAW* draw; +ImagingDrawPoint(Imaging im, int x0, int y0, const void *ink_, int op) { + DRAW *draw; INT32 ink; DRAWINIT(); @@ -651,10 +620,8 @@ ImagingDrawPoint(Imaging im, int x0, int y0, const void* ink_, int op) } int -ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void* ink_, - int op) -{ - DRAW* draw; +ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink_, int op) { + DRAW *draw; INT32 ink; DRAWINIT(); @@ -665,10 +632,9 @@ ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void* ink_, } int -ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, - const void* ink_, int width, int op) -{ - DRAW* draw; +ImagingDrawWideLine( + Imaging im, int x0, int y0, int x1, int y1, const void *ink_, int width, int op) { + DRAW *draw; INT32 ink; int dx, dy; double big_hypotenuse, small_hypotenuse, ratio_max, ratio_min; @@ -677,8 +643,8 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, DRAWINIT(); - dx = x1-x0; - dy = y1-y0; + dx = x1 - x0; + dy = y1 - y0; if (dx == 0 && dy == 0) { draw->point(im, x0, y0, ink); return 0; @@ -698,13 +664,12 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, {x0 - dxmin, y0 + dymax}, {x1 - dxmin, y1 + dymax}, {x1 + dxmax, y1 - dymin}, - {x0 + dxmax, y0 - dymin} - }; + {x0 + dxmax, y0 - dymin}}; - add_edge(e+0, vertices[0][0], vertices[0][1], vertices[1][0], vertices[1][1]); - add_edge(e+1, vertices[1][0], vertices[1][1], vertices[2][0], vertices[2][1]); - add_edge(e+2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]); - add_edge(e+3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]); + add_edge(e + 0, vertices[0][0], vertices[0][1], vertices[1][0], vertices[1][1]); + add_edge(e + 1, vertices[1][0], vertices[1][1], vertices[2][0], vertices[2][1]); + add_edge(e + 2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]); + add_edge(e + 3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]); draw->polygon(im, 4, e, ink, 0); } @@ -712,13 +677,20 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, } int -ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, - const void* ink_, int fill, int width, int op) -{ +ImagingDrawRectangle( + Imaging im, + int x0, + int y0, + int x1, + int y1, + const void *ink_, + int fill, + int width, + int op) { int i; int y; int tmp; - DRAW* draw; + DRAW *draw; INT32 ink; DRAWINIT(); @@ -728,7 +700,6 @@ ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, } if (fill) { - if (y0 < 0) { y0 = 0; } else if (y0 >= im->ysize) { @@ -751,10 +722,10 @@ ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, width = 1; } for (i = 0; i < width; i++) { - draw->hline(im, x0, y0+i, x1, ink); - draw->hline(im, x0, y1-i, x1, ink); - draw->line(im, x1-i, y0, x1-i, y1, ink); - draw->line(im, x0+i, y1, x0+i, y0, ink); + draw->hline(im, x0, y0 + i, x1, ink); + draw->hline(im, x0, y1 - i, x1, ink); + draw->line(im, x1 - i, y0 + width, x1 - i, y1 - width + 1, ink); + draw->line(im, x0 + i, y0 + width, x0 + i, y1 - width + 1, ink); } } @@ -762,11 +733,9 @@ ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, } int -ImagingDrawPolygon(Imaging im, int count, int* xy, const void* ink_, - int fill, int op) -{ - int i, n; - DRAW* draw; +ImagingDrawPolygon(Imaging im, int count, int *xy, const void *ink_, int fill, int op) { + int i, n, x0, y0, x1, y1; + DRAW *draw; INT32 ink; if (count <= 0) { @@ -776,44 +745,55 @@ ImagingDrawPolygon(Imaging im, int count, int* xy, const void* ink_, DRAWINIT(); if (fill) { - /* Build edge list */ /* malloc check ok, using calloc */ - Edge* e = calloc(count, sizeof(Edge)); + Edge *e = calloc(count, sizeof(Edge)); if (!e) { - (void) ImagingError_MemoryError(); + (void)ImagingError_MemoryError(); return -1; } - for (i = n = 0; i < count-1; i++) { - add_edge(&e[n++], xy[i+i], xy[i+i+1], xy[i+i+2], xy[i+i+3]); + for (i = n = 0; i < count - 1; i++) { + x0 = xy[i * 2]; + y0 = xy[i * 2 + 1]; + x1 = xy[i * 2 + 2]; + y1 = xy[i * 2 + 3]; + if (y0 == y1 && i != 0 && y0 == xy[i * 2 - 1]) { + // This is a horizontal line, + // that immediately follows another horizontal line + Edge *last_e = &e[n-1]; + if (x1 > x0 && x0 > xy[i * 2 - 2]) { + // They are both increasing in x + last_e->xmax = x1; + continue; + } else if (x1 < x0 && x0 < xy[i * 2 - 2]) { + // They are both decreasing in x + last_e->xmin = x1; + continue; + } + } + add_edge(&e[n++], x0, y0, x1, y1); } - if (xy[i+i] != xy[0] || xy[i+i+1] != xy[1]) { - add_edge(&e[n++], xy[i+i], xy[i+i+1], xy[0], xy[1]); + if (xy[i * 2] != xy[0] || xy[i * 2 + 1] != xy[1]) { + add_edge(&e[n++], xy[i * 2], xy[i * 2 + 1], xy[0], xy[1]); } draw->polygon(im, n, e, ink, 0); free(e); } else { - /* Outline */ - for (i = 0; i < count-1; i++) { - draw->line(im, xy[i+i], xy[i+i+1], xy[i+i+2], xy[i+i+3], ink); + for (i = 0; i < count - 1; i++) { + draw->line(im, xy[i * 2], xy[i * 2 + 1], xy[i * 2 + 2], xy[i * 2 + 3], ink); } - draw->line(im, xy[i+i], xy[i+i+1], xy[0], xy[1], ink); - + draw->line(im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink); } return 0; } int -ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, const void* ink, - int op) -{ +ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, const void *ink, int op) { return ImagingFill2( - im, ink, bitmap, - x0, y0, x0 + bitmap->xsize, y0 + bitmap->ysize - ); + im, ink, bitmap, x0, y0, x0 + bitmap->xsize, y0 + bitmap->ysize); } /* -------------------------------------------------------------------- */ @@ -830,7 +810,8 @@ typedef struct { int8_t finished; } quarter_state; -void quarter_init(quarter_state* s, int32_t a, int32_t b) { +void +quarter_init(quarter_state *s, int32_t a, int32_t b) { if (a < 0 || b < 0) { s->finished = 1; } else { @@ -849,11 +830,13 @@ void quarter_init(quarter_state* s, int32_t a, int32_t b) { // deviation of the point from ellipse curve, basically a substitution // of the point into the ellipse equation -int64_t quarter_delta(quarter_state* s, int64_t x, int64_t y) { +int64_t +quarter_delta(quarter_state *s, int64_t x, int64_t y) { return llabs(s->a2 * y * y + s->b2 * x * x - s->a2b2); } -int8_t quarter_next(quarter_state* s, int32_t* ret_x, int32_t* ret_y) { +int8_t +quarter_next(quarter_state *s, int32_t *ret_x, int32_t *ret_y) { if (s->finished) { return -1; } @@ -903,7 +886,8 @@ typedef struct { int8_t leftmost; } ellipse_state; -void ellipse_init(ellipse_state* s, int32_t a, int32_t b, int32_t w) { +void +ellipse_init(ellipse_state *s, int32_t a, int32_t b, int32_t w) { s->bufcnt = 0; s->leftmost = a % 2; quarter_init(&s->st_o, a, b); @@ -916,7 +900,8 @@ void ellipse_init(ellipse_state* s, int32_t a, int32_t b, int32_t w) { } } -int8_t ellipse_next(ellipse_state* s, int32_t* ret_x0, int32_t* ret_y, int32_t* ret_x1) { +int8_t +ellipse_next(ellipse_state *s, int32_t *ret_x0, int32_t *ret_y, int32_t *ret_x1) { if (s->bufcnt == 0) { if (s->finished) { return -1; @@ -974,470 +959,519 @@ int8_t ellipse_next(ellipse_state* s, int32_t* ret_x0, int32_t* ret_y, int32_t* // of resulting disjoint clipped segments organized into a sorted linked list // of their end points. typedef enum { - CT_AND, // intersection - CT_OR, // union - CT_CLIP // half-plane clipping + CT_AND, // intersection + CT_OR, // union + CT_CLIP // half-plane clipping } clip_type; typedef struct clip_node { - clip_type type; - double a, b, c; // half-plane coeffs, only used in clipping nodes - struct clip_node* l; // child pointers, are only non-NULL in combining nodes - struct clip_node* r; + clip_type type; + double a, b, c; // half-plane coeffs, only used in clipping nodes + struct clip_node *l; // child pointers, are only non-NULL in combining nodes + struct clip_node *r; } clip_node; // Linked list for the ends of the clipped horizontal segments. // Since the segment is always horizontal, we don't need to store Y coordinate. typedef struct event_list { - int32_t x; - int8_t type; // used internally, 1 for the left end (smaller X), -1 for the - // right end; pointless in output since the output segments - // are disjoint, therefore the types would always come in pairs - // and interchange (1 -1 1 -1 ...) - struct event_list* next; + int32_t x; + int8_t type; // used internally, 1 for the left end (smaller X), -1 for the + // right end; pointless in output since the output segments + // are disjoint, therefore the types would always come in pairs + // and interchange (1 -1 1 -1 ...) + struct event_list *next; } event_list; // Mirrors all the clipping nodes of the tree relative to the y = x line. -void clip_tree_transpose(clip_node* root) { - if (root != NULL) { - if (root->type == CT_CLIP) { - double t = root->a; - root->a = root->b; - root->b = t; +void +clip_tree_transpose(clip_node *root) { + if (root != NULL) { + if (root->type == CT_CLIP) { + double t = root->a; + root->a = root->b; + root->b = t; + } + clip_tree_transpose(root->l); + clip_tree_transpose(root->r); } - clip_tree_transpose(root->l); - clip_tree_transpose(root->r); - } } // Outputs a sequence of open-close events (types -1 and 1) for // non-intersecting segments sorted by X coordinate. // Combining nodes (AND, OR) may also accept sequences for intersecting // segments, i.e. something like correct bracket sequences. -int clip_tree_do_clip(clip_node* root, int32_t x0, int32_t y, int32_t x1, event_list** ret) { - if (root == NULL) { - event_list* start = malloc(sizeof(event_list)); - if (!start) { - ImagingError_MemoryError(); - return -1; +int +clip_tree_do_clip( + clip_node *root, int32_t x0, int32_t y, int32_t x1, event_list **ret) { + if (root == NULL) { + event_list *start = malloc(sizeof(event_list)); + if (!start) { + ImagingError_MemoryError(); + return -1; + } + event_list *end = malloc(sizeof(event_list)); + if (!end) { + free(start); + ImagingError_MemoryError(); + return -1; + } + start->x = x0; + start->type = 1; + start->next = end; + end->x = x1; + end->type = -1; + end->next = NULL; + *ret = start; + return 0; } - event_list* end = malloc(sizeof(event_list)); - if (!end) { - free(start); - ImagingError_MemoryError(); - return -1; + if (root->type == CT_CLIP) { + double eps = 1e-9; + double A = root->a; + double B = root->b; + double C = root->c; + if (fabs(A) < eps) { + if (B * y + C < -eps) { + x0 = 1; + x1 = 0; + } + } else { + // X of intersection + double ix = -(B * y + C) / A; + if (A * x0 + B * y + C < eps) { + x0 = lround(fmax(x0, ix)); + } + if (A * x1 + B * y + C < eps) { + x1 = lround(fmin(x1, ix)); + } + } + if (x0 <= x1) { + event_list *start = malloc(sizeof(event_list)); + if (!start) { + ImagingError_MemoryError(); + return -1; + } + event_list *end = malloc(sizeof(event_list)); + if (!end) { + free(start); + ImagingError_MemoryError(); + return -1; + } + start->x = x0; + start->type = 1; + start->next = end; + end->x = x1; + end->type = -1; + end->next = NULL; + *ret = start; + } else { + *ret = NULL; + } + return 0; } - start->x = x0; - start->type = 1; - start->next = end; - end->x = x1; - end->type = -1; - end->next = NULL; - *ret = start; - return 0; - } - if (root->type == CT_CLIP) { - double eps = 1e-9; - double A = root->a; - double B = root->b; - double C = root->c; - if (fabs(A) < eps) { - if (B * y + C < -eps) { - x0 = 1; - x1 = 0; - } - } else { - // X of intersection - double ix = - (B * y + C) / A; - if (A * x0 + B * y + C < eps) { - x0 = lround(fmax(x0, ix)); - } - if (A * x1 + B * y + C < eps) { - x1 = lround(fmin(x1, ix)); - } - } - if (x0 <= x1) { - event_list* start = malloc(sizeof(event_list)); - if (!start) { - ImagingError_MemoryError(); - return -1; - } - event_list* end = malloc(sizeof(event_list)); - if (!end) { - free(start); - ImagingError_MemoryError(); - return -1; - } - start->x = x0; - start->type = 1; - start->next = end; - end->x = x1; - end->type = -1; - end->next = NULL; - *ret = start; - } else { - *ret = NULL; - } - return 0; - } - if (root->type == CT_OR || root->type == CT_AND) { - event_list* l1; - event_list* l2; - if (clip_tree_do_clip(root->l, x0, y, x1, &l1) < 0) { - return -1; - } - if (clip_tree_do_clip(root->r, x0, y, x1, &l2) < 0) { - while (l1) { - l2 = l1->next; - free(l1); - l1 = l2; - } - return -1; + if (root->type == CT_OR || root->type == CT_AND) { + event_list *l1; + event_list *l2; + if (clip_tree_do_clip(root->l, x0, y, x1, &l1) < 0) { + return -1; + } + if (clip_tree_do_clip(root->r, x0, y, x1, &l2) < 0) { + while (l1) { + l2 = l1->next; + free(l1); + l1 = l2; + } + return -1; + } + *ret = NULL; + event_list *tail = NULL; + int32_t k1 = 0; + int32_t k2 = 0; + while (l1 != NULL || l2 != NULL) { + event_list *t; + if (l2 == NULL || + (l1 != NULL && + (l1->x < l2->x || (l1->x == l2->x && l1->type > l2->type)))) { + t = l1; + k1 += t->type; + assert(k1 >= 0); + l1 = l1->next; + } else { + t = l2; + k2 += t->type; + assert(k2 >= 0); + l2 = l2->next; + } + t->next = NULL; + if ((root->type == CT_OR && + ((t->type == 1 && (tail == NULL || tail->type == -1)) || + (t->type == -1 && k1 == 0 && k2 == 0))) || + (root->type == CT_AND && + ((t->type == 1 && (tail == NULL || tail->type == -1) && k1 > 0 && + k2 > 0) || + (t->type == -1 && tail != NULL && tail->type == 1 && + (k1 == 0 || k2 == 0))))) { + if (tail == NULL) { + *ret = t; + } else { + tail->next = t; + } + tail = t; + } else { + free(t); + } + } + return 0; } *ret = NULL; - event_list* tail = NULL; - int32_t k1 = 0; - int32_t k2 = 0; - while (l1 != NULL || l2 != NULL) { - event_list* t; - if (l2 == NULL || (l1 != NULL && (l1->x < l2->x || (l1->x == l2->x && l1->type > l2->type)))) { - t = l1; - k1 += t->type; - assert(k1 >= 0); - l1 = l1->next; - } else { - t = l2; - k2 += t->type; - assert(k2 >= 0); - l2 = l2->next; - } - t->next = NULL; - if ((root->type == CT_OR && ( - (t->type == 1 && (tail == NULL || tail->type == -1)) || - (t->type == -1 && k1 == 0 && k2 == 0) - )) || - (root->type == CT_AND && ( - (t->type == 1 && (tail == NULL || tail->type == -1) && k1 > 0 && k2 > 0) || - (t->type == -1 && tail != NULL && tail->type == 1 && (k1 == 0 || k2 == 0)) - ))) { - if (tail == NULL) { - *ret = t; - } else { - tail->next = t; - } - tail = t; - } else { - free(t); - } - } return 0; - } - *ret = NULL; - return 0; } // One more layer of processing on top of the regular ellipse. // Uses the clipping tree. // Used for producing ellipse derivatives such as arc, chord, pie, etc. typedef struct { - ellipse_state st; - clip_node* root; - clip_node nodes[7]; - int32_t node_count; - event_list* head; - int32_t y; + ellipse_state st; + clip_node *root; + clip_node nodes[7]; + int32_t node_count; + event_list *head; + int32_t y; } clip_ellipse_state; -typedef void (*clip_ellipse_init)(clip_ellipse_state*, int32_t, int32_t, int32_t, float, float); +typedef void (*clip_ellipse_init)( + clip_ellipse_state *, int32_t, int32_t, int32_t, float, float); -void debug_clip_tree(clip_node* root, int space) { - if (root == NULL) { - return; - } - if (root->type == CT_CLIP) { - int t = space; - while (t--) { - fputc(' ', stderr); +void +debug_clip_tree(clip_node *root, int space) { + if (root == NULL) { + return; } - fprintf(stderr, "clip %+fx%+fy%+f > 0\n", root->a, root->b, root->c); - } else { - debug_clip_tree(root->l, space + 2); - int t = space; - while (t--) { - fputc(' ', stderr); + if (root->type == CT_CLIP) { + int t = space; + while (t--) { + fputc(' ', stderr); + } + fprintf(stderr, "clip %+fx%+fy%+f > 0\n", root->a, root->b, root->c); + } else { + debug_clip_tree(root->l, space + 2); + int t = space; + while (t--) { + fputc(' ', stderr); + } + fprintf(stderr, "%s\n", root->type == CT_AND ? "and" : "or"); + debug_clip_tree(root->r, space + 2); + } + if (space == 0) { + fputc('\n', stderr); } - fprintf(stderr, "%s\n", root->type == CT_AND ? "and" : "or"); - debug_clip_tree(root->r, space + 2); - } - if (space == 0) { - fputc('\n', stderr); - } } // Resulting angles will satisfy 0 <= al < 360, al <= ar <= al + 360 -void normalize_angles(float* al, float* ar) { - if (*ar - *al >= 360) { - *al = 0; - *ar = 360; - } else { - *al = fmod(*al < 0 ? 360 - (fmod(-*al, 360)) : *al, 360); - *ar = *al + fmod(*ar < *al ? 360 - fmod(*al - *ar, 360) : *ar - *al, 360); - } +void +normalize_angles(float *al, float *ar) { + if (*ar - *al >= 360) { + *al = 0; + *ar = 360; + } else { + *al = fmod(*al < 0 ? 360 - (fmod(-*al, 360)) : *al, 360); + *ar = *al + fmod(*ar < *al ? 360 - fmod(*al - *ar, 360) : *ar - *al, 360); + } } // An arc with caps orthogonal to the ellipse curve. -void arc_init(clip_ellipse_state* s, int32_t a, int32_t b, int32_t w, float al, float ar) { - if (a < b) { - // transpose the coordinate system - arc_init(s, b, a, w, 90 - ar, 90 - al); - ellipse_init(&s->st, a, b, w); - clip_tree_transpose(s->root); - } else { - // a >= b, based on "wide" ellipse +void +arc_init(clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float ar) { + if (a < b) { + // transpose the coordinate system + arc_init(s, b, a, w, 90 - ar, 90 - al); + ellipse_init(&s->st, a, b, w); + clip_tree_transpose(s->root); + } else { + // a >= b, based on "wide" ellipse + ellipse_init(&s->st, a, b, w); + + s->head = NULL; + s->node_count = 0; + normalize_angles(&al, &ar); + + // building clipping tree, a lot of different cases + if (ar == al + 360) { + s->root = NULL; + } else { + clip_node *lc = s->nodes + s->node_count++; + clip_node *rc = s->nodes + s->node_count++; + lc->l = lc->r = rc->l = rc->r = NULL; + lc->type = rc->type = CT_CLIP; + lc->a = -a * sin(al * M_PI / 180.0); + lc->b = b * cos(al * M_PI / 180.0); + lc->c = (a * a - b * b) * sin(al * M_PI / 90.0) / 2.0; + rc->a = a * sin(ar * M_PI / 180.0); + rc->b = -b * cos(ar * M_PI / 180.0); + rc->c = (b * b - a * a) * sin(ar * M_PI / 90.0) / 2.0; + if (fmod(al, 180) == 0 || fmod(ar, 180) == 0) { + s->root = s->nodes + s->node_count++; + s->root->l = lc; + s->root->r = rc; + s->root->type = ar - al < 180 ? CT_AND : CT_OR; + } else if (((int)(al / 180) + (int)(ar / 180)) % 2 == 1) { + s->root = s->nodes + s->node_count++; + s->root->l = s->nodes + s->node_count++; + s->root->l->l = s->nodes + s->node_count++; + s->root->l->r = lc; + s->root->r = s->nodes + s->node_count++; + s->root->r->l = s->nodes + s->node_count++; + s->root->r->r = rc; + s->root->type = CT_OR; + s->root->l->type = CT_AND; + s->root->r->type = CT_AND; + s->root->l->l->type = CT_CLIP; + s->root->r->l->type = CT_CLIP; + s->root->l->l->l = s->root->l->l->r = NULL; + s->root->r->l->l = s->root->r->l->r = NULL; + s->root->l->l->a = s->root->l->l->c = 0; + s->root->r->l->a = s->root->r->l->c = 0; + s->root->l->l->b = (int)(al / 180) % 2 == 0 ? 1 : -1; + s->root->r->l->b = (int)(ar / 180) % 2 == 0 ? 1 : -1; + } else { + s->root = s->nodes + s->node_count++; + s->root->l = s->nodes + s->node_count++; + s->root->r = s->nodes + s->node_count++; + s->root->type = s->root->l->type = ar - al < 180 ? CT_AND : CT_OR; + s->root->l->l = lc; + s->root->l->r = rc; + s->root->r->type = CT_CLIP; + s->root->r->l = s->root->r->r = NULL; + s->root->r->a = s->root->r->c = 0; + s->root->r->b = ar < 180 || ar > 540 ? 1 : -1; + } + } + } +} + +// A chord line. +void +chord_line_init( + clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float ar) { + ellipse_init(&s->st, a, b, a + b + 1); + + s->head = NULL; + s->node_count = 0; + + // line equation for chord + double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0); + double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0); + s->root = s->nodes + s->node_count++; + s->root->l = s->nodes + s->node_count++; + s->root->r = s->nodes + s->node_count++; + s->root->type = CT_AND; + s->root->l->type = s->root->r->type = CT_CLIP; + s->root->l->l = s->root->l->r = s->root->r->l = s->root->r->r = NULL; + s->root->l->a = yr - yl; + s->root->l->b = xl - xr; + s->root->l->c = -(s->root->l->a * xl + s->root->l->b * yl); + s->root->r->a = -s->root->l->a; + s->root->r->b = -s->root->l->b; + s->root->r->c = + 2 * w * sqrt(pow(s->root->l->a, 2.0) + pow(s->root->l->b, 2.0)) - s->root->l->c; +} + +// Pie side. +void +pie_side_init( + clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float _) { + ellipse_init(&s->st, a, b, a + b + 1); + + s->head = NULL; + s->node_count = 0; + + double xl = a * cos(al * M_PI / 180.0); + double yl = b * sin(al * M_PI / 180.0); + double a1 = -yl; + double b1 = xl; + double c1 = w * sqrt(a1 * a1 + b1 * b1); + + s->root = s->nodes + s->node_count++; + s->root->type = CT_AND; + s->root->l = s->nodes + s->node_count++; + s->root->l->type = CT_AND; + + clip_node *cnode; + cnode = s->nodes + s->node_count++; + cnode->l = cnode->r = NULL; + cnode->type = CT_CLIP; + cnode->a = a1; + cnode->b = b1; + cnode->c = c1; + s->root->l->l = cnode; + cnode = s->nodes + s->node_count++; + cnode->l = cnode->r = NULL; + cnode->type = CT_CLIP; + cnode->a = -a1; + cnode->b = -b1; + cnode->c = c1; + s->root->l->r = cnode; + cnode = s->nodes + s->node_count++; + cnode->l = cnode->r = NULL; + cnode->type = CT_CLIP; + cnode->a = b1; + cnode->b = -a1; + cnode->c = 0; + s->root->r = cnode; +} + +// A chord. +void +chord_init(clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float ar) { ellipse_init(&s->st, a, b, w); s->head = NULL; s->node_count = 0; - normalize_angles(&al, &ar); - // building clipping tree, a lot of different cases - if (ar == al + 360) { - s->root = NULL; - } else { - clip_node* lc = s->nodes + s->node_count++; - clip_node* rc = s->nodes + s->node_count++; - lc->l = lc->r = rc->l = rc->r = NULL; - lc->type = rc->type = CT_CLIP; - lc->a = -a * sin(al * M_PI / 180.0); - lc->b = b * cos(al * M_PI / 180.0); - lc->c = (a * a - b * b) * sin(al * M_PI / 90.0) / 2.0; - rc->a = a * sin(ar * M_PI / 180.0); - rc->b = -b * cos(ar * M_PI / 180.0); - rc->c = (b * b - a * a) * sin(ar * M_PI / 90.0) / 2.0; - if (fmod(al, 180) == 0 || fmod(ar, 180) == 0) { - s->root = s->nodes + s->node_count++; - s->root->l = lc; - s->root->r = rc; - s->root->type = ar - al < 180 ? CT_AND : CT_OR; - } else if (((int)(al / 180) + (int)(ar / 180)) % 2 == 1) { - s->root = s->nodes + s->node_count++; - s->root->l = s->nodes + s->node_count++; - s->root->l->l = s->nodes + s->node_count++; - s->root->l->r = lc; - s->root->r = s->nodes + s->node_count++; - s->root->r->l = s->nodes + s->node_count++; - s->root->r->r = rc; - s->root->type = CT_OR; - s->root->l->type = CT_AND; - s->root->r->type = CT_AND; - s->root->l->l->type = CT_CLIP; - s->root->r->l->type = CT_CLIP; - s->root->l->l->l = s->root->l->l->r = NULL; - s->root->r->l->l = s->root->r->l->r = NULL; - s->root->l->l->a = s->root->l->l->c = 0; - s->root->r->l->a = s->root->r->l->c = 0; - s->root->l->l->b = (int)(al / 180) % 2 == 0 ? 1 : -1; - s->root->r->l->b = (int)(ar / 180) % 2 == 0 ? 1 : -1; - } else { - s->root = s->nodes + s->node_count++; - s->root->l = s->nodes + s->node_count++; - s->root->r = s->nodes + s->node_count++; - s->root->type = s->root->l->type = ar - al < 180 ? CT_AND : CT_OR; - s->root->l->l = lc; - s->root->l->r = rc; - s->root->r->type = CT_CLIP; - s->root->r->l = s->root->r->r = NULL; - s->root->r->a = s->root->r->c = 0; - s->root->r->b = ar < 180 || ar > 540 ? 1 : -1; - } - } - } -} - -// A chord line. -void chord_line_init(clip_ellipse_state* s, int32_t a, int32_t b, int32_t w, float al, float ar) { - ellipse_init(&s->st, a, b, a + b + 1); - - s->head = NULL; - s->node_count = 0; - - // line equation for chord - double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0); - double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0); - s->root = s->nodes + s->node_count++; - s->root->l = s->nodes + s->node_count++; - s->root->r = s->nodes + s->node_count++; - s->root->type = CT_AND; - s->root->l->type = s->root->r->type = CT_CLIP; - s->root->l->l = s->root->l->r = s->root->r->l = s->root->r->r = NULL; - s->root->l->a = yr - yl; - s->root->l->b = xl - xr; - s->root->l->c = -(s->root->l->a * xl + s->root->l->b * yl); - s->root->r->a = -s->root->l->a; - s->root->r->b = -s->root->l->b; - s->root->r->c = 2 * w * sqrt(pow(s->root->l->a, 2.0) + pow(s->root->l->b, 2.0)) - s->root->l->c; -} - -// Pie side. -void pie_side_init(clip_ellipse_state* s, int32_t a, int32_t b, int32_t w, float al, float _) { - ellipse_init(&s->st, a, b, a + b + 1); - - s->head = NULL; - s->node_count = 0; - - double xl = a * cos(al * M_PI / 180.0); - double yl = b * sin(al * M_PI / 180.0); - double a1 = -yl; - double b1 = xl; - double c1 = w * sqrt(a1 * a1 + b1 * b1); - - s->root = s->nodes + s->node_count++; - s->root->type = CT_AND; - s->root->l = s->nodes + s->node_count++; - s->root->l->type = CT_AND; - - clip_node* cnode; - cnode = s->nodes + s->node_count++; - cnode->l = cnode->r = NULL; - cnode->type = CT_CLIP; - cnode->a = a1; - cnode->b = b1; - cnode->c = c1; - s->root->l->l = cnode; - cnode = s->nodes + s->node_count++; - cnode->l = cnode->r = NULL; - cnode->type = CT_CLIP; - cnode->a = -a1; - cnode->b = -b1; - cnode->c = c1; - s->root->l->r = cnode; - cnode = s->nodes + s->node_count++; - cnode->l = cnode->r = NULL; - cnode->type = CT_CLIP; - cnode->a = b1; - cnode->b = -a1; - cnode->c = 0; - s->root->r = cnode; -} - -// A chord. -void chord_init(clip_ellipse_state* s, int32_t a, int32_t b, int32_t w, float al, float ar) { - ellipse_init(&s->st, a, b, w); - - s->head = NULL; - s->node_count = 0; - - // line equation for chord - double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0); - double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0); - s->root = s->nodes + s->node_count++; - s->root->l = s->root->r = NULL; - s->root->type = CT_CLIP; - s->root->a = yr - yl; - s->root->b = xl - xr; - s->root->c = -(s->root->a * xl + s->root->b * yl); + // line equation for chord + double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0); + double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0); + s->root = s->nodes + s->node_count++; + s->root->l = s->root->r = NULL; + s->root->type = CT_CLIP; + s->root->a = yr - yl; + s->root->b = xl - xr; + s->root->c = -(s->root->a * xl + s->root->b * yl); } // A pie. Can also be used to draw an arc with ugly sharp caps. -void pie_init(clip_ellipse_state* s, int32_t a, int32_t b, int32_t w, float al, float ar) { - ellipse_init(&s->st, a, b, w); +void +pie_init(clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float ar) { + ellipse_init(&s->st, a, b, w); - s->head = NULL; - s->node_count = 0; + s->head = NULL; + s->node_count = 0; - // line equations for pie sides - double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0); - double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0); + // line equations for pie sides + double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0); + double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0); - clip_node* lc = s->nodes + s->node_count++; - clip_node* rc = s->nodes + s->node_count++; - lc->l = lc->r = rc->l = rc->r = NULL; - lc->type = rc->type = CT_CLIP; - lc->a = -yl; - lc->b = xl; - lc->c = 0; - rc->a = yr; - rc->b = -xr; - rc->c = 0; + clip_node *lc = s->nodes + s->node_count++; + clip_node *rc = s->nodes + s->node_count++; + lc->l = lc->r = rc->l = rc->r = NULL; + lc->type = rc->type = CT_CLIP; + lc->a = -yl; + lc->b = xl; + lc->c = 0; + rc->a = yr; + rc->b = -xr; + rc->c = 0; - s->root = s->nodes + s->node_count++; - s->root->l = lc; - s->root->r = rc; - s->root->type = ar - al < 180 ? CT_AND : CT_OR; -} + s->root = s->nodes + s->node_count++; + s->root->l = lc; + s->root->r = rc; + s->root->type = ar - al < 180 ? CT_AND : CT_OR; -void clip_ellipse_free(clip_ellipse_state* s) { - while (s->head != NULL) { - event_list* t = s->head; - s->head = s->head->next; - free(t); - } -} + // add one more semiplane to avoid spikes + if (ar - al < 90) { + clip_node *old_root = s->root; + clip_node *spike_clipper = s->nodes + s->node_count++; + s->root = s->nodes + s->node_count++; + s->root->l = old_root; + s->root->r = spike_clipper; + s->root->type = CT_AND; -int8_t clip_ellipse_next(clip_ellipse_state* s, int32_t* ret_x0, int32_t* ret_y, int32_t* ret_x1) { - int32_t x0, y, x1; - while (s->head == NULL && ellipse_next(&s->st, &x0, &y, &x1) >= 0) { - if (clip_tree_do_clip(s->root, x0, y, x1, &s->head) < 0) { - return -2; + spike_clipper->l = spike_clipper->r = NULL; + spike_clipper->type = CT_CLIP; + spike_clipper->a = (xl + xr) / 2.0; + spike_clipper->b = (yl + yr) / 2.0; + spike_clipper->c = 0; } - s->y = y; - } - if (s->head != NULL) { - *ret_y = s->y; - event_list* t = s->head; - s->head = s->head->next; - *ret_x0 = t->x; - free(t); - t = s->head; - assert(t != NULL); - s->head = s->head->next; - *ret_x1 = t->x; - free(t); - return 0; - } - return -1; +} + +void +clip_ellipse_free(clip_ellipse_state *s) { + while (s->head != NULL) { + event_list *t = s->head; + s->head = s->head->next; + free(t); + } +} + +int8_t +clip_ellipse_next( + clip_ellipse_state *s, int32_t *ret_x0, int32_t *ret_y, int32_t *ret_x1) { + int32_t x0, y, x1; + while (s->head == NULL && ellipse_next(&s->st, &x0, &y, &x1) >= 0) { + if (clip_tree_do_clip(s->root, x0, y, x1, &s->head) < 0) { + return -2; + } + s->y = y; + } + if (s->head != NULL) { + *ret_y = s->y; + event_list *t = s->head; + s->head = s->head->next; + *ret_x0 = t->x; + free(t); + t = s->head; + assert(t != NULL); + s->head = s->head->next; + *ret_x1 = t->x; + free(t); + return 0; + } + return -1; } static int -ellipseNew(Imaging im, int x0, int y0, int x1, int y1, - const void* ink_, int fill, - int width, int op) -{ - DRAW* draw; +ellipseNew( + Imaging im, + int x0, + int y0, + int x1, + int y1, + const void *ink_, + int fill, + int width, + int op) { + DRAW *draw; INT32 ink; DRAWINIT(); int a = x1 - x0; int b = y1 - y0; if (a < 0 || b < 0) { - return 0; + return 0; } if (fill) { - width = a + b; + width = a + b; } ellipse_state st; ellipse_init(&st, a, b, width); int32_t X0, Y, X1; while (ellipse_next(&st, &X0, &Y, &X1) != -1) { - draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink); + draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink); } return 0; } static int -clipEllipseNew(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, - const void* ink_, int width, int op, clip_ellipse_init init) -{ - DRAW* draw; +clipEllipseNew( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink_, + int width, + int op, + clip_ellipse_init init) { + DRAW *draw; INT32 ink; DRAWINIT(); int a = x1 - x0; int b = y1 - y0; if (a < 0 || b < 0) { - return 0; + return 0; } clip_ellipse_state st; @@ -1446,124 +1480,187 @@ clipEllipseNew(Imaging im, int x0, int y0, int x1, int y1, int32_t X0, Y, X1; int next_code; while ((next_code = clip_ellipse_next(&st, &X0, &Y, &X1)) >= 0) { - draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink); + draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink); } clip_ellipse_free(&st); return next_code == -1 ? 0 : -1; } static int -arcNew(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, - const void* ink_, int width, int op) -{ - return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, arc_init); +arcNew( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink_, + int width, + int op) { + return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, arc_init); } static int -chordNew(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, - const void* ink_, int width, int op) -{ - return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, chord_init); +chordNew( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink_, + int width, + int op) { + return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, chord_init); } static int -chordLineNew(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, - const void* ink_, int width, int op) -{ - return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, chord_line_init); +chordLineNew( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink_, + int width, + int op) { + return clipEllipseNew( + im, x0, y0, x1, y1, start, end, ink_, width, op, chord_line_init); } static int -pieNew(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, - const void* ink_, int width, int op) -{ - return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, pie_init); +pieNew( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink_, + int width, + int op) { + return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, pie_init); } static int -pieSideNew(Imaging im, int x0, int y0, int x1, int y1, - float start, - const void* ink_, int width, int op) -{ - return clipEllipseNew(im, x0, y0, x1, y1, start, 0, ink_, width, op, pie_side_init); +pieSideNew( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + const void *ink_, + int width, + int op) { + return clipEllipseNew(im, x0, y0, x1, y1, start, 0, ink_, width, op, pie_side_init); } int -ImagingDrawEllipse(Imaging im, int x0, int y0, int x1, int y1, - const void* ink, int fill, int width, int op) -{ +ImagingDrawEllipse( + Imaging im, + int x0, + int y0, + int x1, + int y1, + const void *ink, + int fill, + int width, + int op) { return ellipseNew(im, x0, y0, x1, y1, ink, fill, width, op); } int -ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, const void* ink, int width, int op) -{ +ImagingDrawArc( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink, + int width, + int op) { normalize_angles(&start, &end); if (start + 360 == end) { - return ImagingDrawEllipse(im, x0, y0, x1, y1, ink, 0, width, op); + return ImagingDrawEllipse(im, x0, y0, x1, y1, ink, 0, width, op); } if (start == end) { - return 0; + return 0; } return arcNew(im, x0, y0, x1, y1, start, end, ink, width, op); } - int -ImagingDrawChord(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, const void* ink, int fill, - int width, int op) -{ +ImagingDrawChord( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink, + int fill, + int width, + int op) { normalize_angles(&start, &end); if (start + 360 == end) { - return ImagingDrawEllipse(im, x0, y0, x1, y1, ink, fill, width, op); + return ImagingDrawEllipse(im, x0, y0, x1, y1, ink, fill, width, op); } if (start == end) { - return 0; + return 0; } if (fill) { - return chordNew(im, x0, y0, x1, y1, start, end, ink, x1 - x0 + y1 - y0 + 1, op); + return chordNew(im, x0, y0, x1, y1, start, end, ink, x1 - x0 + y1 - y0 + 1, op); } else { - if (chordLineNew(im, x0, y0, x1, y1, start, end, ink, width, op)) { - return -1; - } - return chordNew(im, x0, y0, x1, y1, start, end, ink, width, op); + if (chordLineNew(im, x0, y0, x1, y1, start, end, ink, width, op)) { + return -1; + } + return chordNew(im, x0, y0, x1, y1, start, end, ink, width, op); } } - int -ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, const void* ink, int fill, - int width, int op) -{ +ImagingDrawPieslice( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink, + int fill, + int width, + int op) { normalize_angles(&start, &end); if (start + 360 == end) { - return ellipseNew(im, x0, y0, x1, y1, ink, fill, width, op); + return ellipseNew(im, x0, y0, x1, y1, ink, fill, width, op); } if (start == end) { - return 0; + return 0; } if (fill) { - return pieNew(im, x0, y0, x1, y1, start, end, ink, x1 + y1 - x0 - y0, op); + return pieNew(im, x0, y0, x1, y1, start, end, ink, x1 + y1 - x0 - y0, op); } else { - if (pieSideNew(im, x0, y0, x1, y1, start, ink, width, op)) { - return -1; - } - if (pieSideNew(im, x0, y0, x1, y1, end, ink, width, op)) { - return -1; - } - int xc = lround((x0 + x1 - width) / 2.0), yc = lround((y0 + y1 - width) / 2.0); - ellipseNew(im, xc, yc, xc + width - 1, yc + width - 1, ink, 1, 0, op); - return pieNew(im, x0, y0, x1, y1, start, end, ink, width, op); + if (pieSideNew(im, x0, y0, x1, y1, start, ink, width, op)) { + return -1; + } + if (pieSideNew(im, x0, y0, x1, y1, end, ink, width, op)) { + return -1; + } + int xc = lround((x0 + x1 - width) / 2.0), yc = lround((y0 + y1 - width) / 2.0); + ellipseNew(im, xc, yc, xc + width - 1, yc + width - 1, ink, 1, 0, op); + return pieNew(im, x0, y0, x1, y1, start, end, ink, width, op); } } - /* -------------------------------------------------------------------- */ /* experimental level 2 ("arrow") graphics stuff. this implements @@ -1572,7 +1669,6 @@ ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1, itself */ struct ImagingOutlineInstance { - float x0, y0; float x, y; @@ -1581,18 +1677,15 @@ struct ImagingOutlineInstance { Edge *edges; int size; - }; - ImagingOutline -ImagingOutlineNew(void) -{ +ImagingOutlineNew(void) { ImagingOutline outline; outline = calloc(1, sizeof(struct ImagingOutlineInstance)); if (!outline) { - return (ImagingOutline) ImagingError_MemoryError(); + return (ImagingOutline)ImagingError_MemoryError(); } outline->edges = NULL; @@ -1604,8 +1697,7 @@ ImagingOutlineNew(void) } void -ImagingOutlineDelete(ImagingOutline outline) -{ +ImagingOutlineDelete(ImagingOutline outline) { if (!outline) { return; } @@ -1617,11 +1709,9 @@ ImagingOutlineDelete(ImagingOutline outline) free(outline); } - -static Edge* -allocate(ImagingOutline outline, int extra) -{ - Edge* e; +static Edge * +allocate(ImagingOutline outline, int extra) { + Edge *e; if (outline->count + extra > outline->size) { /* expand outline buffer */ @@ -1650,8 +1740,7 @@ allocate(ImagingOutline outline, int extra) } int -ImagingOutlineMove(ImagingOutline outline, float x0, float y0) -{ +ImagingOutlineMove(ImagingOutline outline, float x0, float y0) { outline->x = outline->x0 = x0; outline->y = outline->y0 = y0; @@ -1659,16 +1748,15 @@ ImagingOutlineMove(ImagingOutline outline, float x0, float y0) } int -ImagingOutlineLine(ImagingOutline outline, float x1, float y1) -{ - Edge* e; +ImagingOutlineLine(ImagingOutline outline, float x1, float y1) { + Edge *e; e = allocate(outline, 1); if (!e) { return -1; /* out of memory */ } - add_edge(e, (int) outline->x, (int) outline->y, (int) x1, (int) y1); + add_edge(e, (int)outline->x, (int)outline->y, (int)x1, (int)y1); outline->x = x1; outline->y = y1; @@ -1677,10 +1765,15 @@ ImagingOutlineLine(ImagingOutline outline, float x1, float y1) } int -ImagingOutlineCurve(ImagingOutline outline, float x1, float y1, - float x2, float y2, float x3, float y3) -{ - Edge* e; +ImagingOutlineCurve( + ImagingOutline outline, + float x1, + float y1, + float x2, + float y2, + float x3, + float y3) { + Edge *e; int i; float xo, yo; @@ -1697,22 +1790,20 @@ ImagingOutlineCurve(ImagingOutline outline, float x1, float y1, /* flatten the bezier segment */ for (i = 1; i <= STEPS; i++) { - - float t = ((float) i) / STEPS; - float t2 = t*t; - float t3 = t2*t; + float t = ((float)i) / STEPS; + float t2 = t * t; + float t3 = t2 * t; float u = 1.0F - t; - float u2 = u*u; - float u3 = u2*u; + float u2 = u * u; + float u3 = u2 * u; - float x = outline->x*u3 + 3*(x1*t*u2 + x2*t2*u) + x3*t3 + 0.5; - float y = outline->y*u3 + 3*(y1*t*u2 + y2*t2*u) + y3*t3 + 0.5; + float x = outline->x * u3 + 3 * (x1 * t * u2 + x2 * t2 * u) + x3 * t3 + 0.5; + float y = outline->y * u3 + 3 * (y1 * t * u2 + y2 * t2 * u) + y3 * t3 + 0.5; - add_edge(e++, xo, yo, (int) x, (int) y); + add_edge(e++, xo, yo, (int)x, (int)y); xo = x, yo = y; - } outline->x = xo; @@ -1722,8 +1813,7 @@ ImagingOutlineCurve(ImagingOutline outline, float x1, float y1, } int -ImagingOutlineClose(ImagingOutline outline) -{ +ImagingOutlineClose(ImagingOutline outline) { if (outline->x == outline->x0 && outline->y == outline->y0) { return 0; } @@ -1731,16 +1821,19 @@ ImagingOutlineClose(ImagingOutline outline) } int -ImagingOutlineTransform(ImagingOutline outline, double a[6]) -{ +ImagingOutlineTransform(ImagingOutline outline, double a[6]) { Edge *eIn; Edge *eOut; int i, n; int x0, y0, x1, y1; int X0, Y0, X1, Y1; - double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; - double a3 = a[3]; double a4 = a[4]; double a5 = a[5]; + double a0 = a[0]; + double a1 = a[1]; + double a2 = a[2]; + double a3 = a[3]; + double a4 = a[4]; + double a5 = a[5]; eIn = outline->edges; n = outline->count; @@ -1758,7 +1851,6 @@ ImagingOutlineTransform(ImagingOutline outline, double a[6]) } for (i = 0; i < n; i++) { - x0 = eIn->x0; y0 = eIn->y0; @@ -1778,16 +1870,15 @@ ImagingOutlineTransform(ImagingOutline outline, double a[6]) upgrade your compiler (make sure you have the right service pack) */ - X0 = (int) (a0*x0 + a1*y0 + a2); - Y0 = (int) (a3*x0 + a4*y0 + a5); - X1 = (int) (a0*x1 + a1*y1 + a2); - Y1 = (int) (a3*x1 + a4*y1 + a5); + X0 = (int)(a0 * x0 + a1 * y0 + a2); + Y0 = (int)(a3 * x0 + a4 * y0 + a5); + X1 = (int)(a0 * x1 + a1 * y1 + a2); + Y1 = (int)(a3 * x1 + a4 * y1 + a5); add_edge(eOut, X0, Y0, X1, Y1); eIn++; eOut++; - } free(eIn); @@ -1796,10 +1887,9 @@ ImagingOutlineTransform(ImagingOutline outline, double a[6]) } int -ImagingDrawOutline(Imaging im, ImagingOutline outline, const void* ink_, - int fill, int op) -{ - DRAW* draw; +ImagingDrawOutline( + Imaging im, ImagingOutline outline, const void *ink_, int fill, int op) { + DRAW *draw; INT32 ink; DRAWINIT(); diff --git a/src/libImaging/Effects.c b/src/libImaging/Effects.c index e0f1d0339..93e7af0bc 100644 --- a/src/libImaging/Effects.c +++ b/src/libImaging/Effects.c @@ -15,14 +15,12 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #include Imaging -ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) -{ +ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) { /* Generate a Mandelbrot set covering the given extent */ Imaging im; @@ -32,10 +30,10 @@ ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) double dr, di; /* Check arguments */ - width = extent[2] - extent[0]; + width = extent[2] - extent[0]; height = extent[3] - extent[1]; if (width < 0.0 || height < 0.0 || quality < 2) { - return (Imaging) ImagingError_ValueError(NULL); + return (Imaging)ImagingError_ValueError(NULL); } im = ImagingNewDirty("L", xsize, ysize); @@ -43,24 +41,24 @@ ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) return NULL; } - dr = width/(xsize-1); - di = height/(ysize-1); + dr = width / (xsize - 1); + di = height / (ysize - 1); radius = 100.0; for (y = 0; y < ysize; y++) { - UINT8* buf = im->image8[y]; + UINT8 *buf = im->image8[y]; for (x = 0; x < xsize; x++) { x1 = y1 = xi2 = yi2 = 0.0; - cr = x*dr + extent[0]; - ci = y*di + extent[1]; + cr = x * dr + extent[0]; + ci = y * di + extent[1]; for (k = 1;; k++) { - y1 = 2*x1*y1 + ci; + y1 = 2 * x1 * y1 + ci; x1 = xi2 - yi2 + cr; - xi2 = x1*x1; - yi2 = y1*y1; + xi2 = x1 * x1; + yi2 = y1 * y1; if ((xi2 + yi2) > radius) { - buf[x] = k*255/quality; + buf[x] = k * 255 / quality; break; } if (k > quality) { @@ -74,8 +72,7 @@ ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) } Imaging -ImagingEffectNoise(int xsize, int ysize, float sigma) -{ +ImagingEffectNoise(int xsize, int ysize, float sigma) { /* Generate Gaussian noise centered around 128 */ Imaging imOut; @@ -92,7 +89,7 @@ ImagingEffectNoise(int xsize, int ysize, float sigma) nextok = 0; for (y = 0; y < imOut->ysize; y++) { - UINT8* out = imOut->image8[y]; + UINT8 *out = imOut->image8[y]; for (x = 0; x < imOut->xsize; x++) { if (nextok) { this = next; @@ -101,11 +98,11 @@ ImagingEffectNoise(int xsize, int ysize, float sigma) /* after numerical recipes */ double v1, v2, radius, factor; do { - v1 = rand()*(2.0/RAND_MAX) - 1.0; - v2 = rand()*(2.0/RAND_MAX) - 1.0; - radius= v1*v1 + v2*v2; + v1 = rand() * (2.0 / RAND_MAX) - 1.0; + v2 = rand() * (2.0 / RAND_MAX) - 1.0; + radius = v1 * v1 + v2 * v2; } while (radius >= 1.0); - factor = sqrt(-2.0*log(radius)/radius); + factor = sqrt(-2.0 * log(radius) / radius); this = factor * v1; next = factor * v2; } @@ -117,8 +114,7 @@ ImagingEffectNoise(int xsize, int ysize, float sigma) } Imaging -ImagingEffectSpread(Imaging imIn, int distance) -{ +ImagingEffectSpread(Imaging imIn, int distance) { /* Randomly spread pixels in an image */ Imaging imOut; @@ -130,26 +126,26 @@ ImagingEffectSpread(Imaging imIn, int distance) return NULL; } -#define SPREAD(type, image)\ - if (distance == 0) {\ - for (y = 0; y < imOut->ysize; y++) {\ - for (x = 0; x < imOut->xsize; x++) {\ - imOut->image[y][x] = imIn->image[y][x];\ - }\ - }\ - } else {\ - for (y = 0; y < imOut->ysize; y++) {\ - for (x = 0; x < imOut->xsize; x++) {\ - int xx = x + (rand() % distance) - distance/2;\ - int yy = y + (rand() % distance) - distance/2;\ - if (xx >= 0 && xx < imIn->xsize && yy >= 0 && yy < imIn->ysize) {\ - imOut->image[yy][xx] = imIn->image[y][x];\ - imOut->image[y][x] = imIn->image[yy][xx];\ - } else {\ - imOut->image[y][x] = imIn->image[y][x];\ - }\ - }\ - }\ +#define SPREAD(type, image) \ + if (distance == 0) { \ + for (y = 0; y < imOut->ysize; y++) { \ + for (x = 0; x < imOut->xsize; x++) { \ + imOut->image[y][x] = imIn->image[y][x]; \ + } \ + } \ + } else { \ + for (y = 0; y < imOut->ysize; y++) { \ + for (x = 0; x < imOut->xsize; x++) { \ + int xx = x + (rand() % distance) - distance / 2; \ + int yy = y + (rand() % distance) - distance / 2; \ + if (xx >= 0 && xx < imIn->xsize && yy >= 0 && yy < imIn->ysize) { \ + imOut->image[yy][xx] = imIn->image[y][x]; \ + imOut->image[y][x] = imIn->image[yy][xx]; \ + } else { \ + imOut->image[y][x] = imIn->image[y][x]; \ + } \ + } \ + } \ } if (imIn->image8) { diff --git a/src/libImaging/EpsEncode.c b/src/libImaging/EpsEncode.c index ac8a4059c..3f2cb33b2 100644 --- a/src/libImaging/EpsEncode.c +++ b/src/libImaging/EpsEncode.c @@ -17,28 +17,24 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - int -ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) -{ - enum { HEXBYTE=1, NEWLINE }; +ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { + enum { HEXBYTE = 1, NEWLINE }; const char *hex = "0123456789abcdef"; - UINT8* ptr = buf; - UINT8* in, i; + UINT8 *ptr = buf; + UINT8 *in, i; if (!state->state) { state->state = HEXBYTE; state->xsize *= im->pixelsize; /* Hack! */ } - in = (UINT8*) im->image[state->y]; + in = (UINT8 *)im->image[state->y]; for (;;) { - if (state->state == NEWLINE) { if (bytes < 1) { break; @@ -53,8 +49,8 @@ ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) } i = in[state->x++]; - *ptr++ = hex[(i>>4)&15]; - *ptr++ = hex[i&15]; + *ptr++ = hex[(i >> 4) & 15]; + *ptr++ = hex[i & 15]; bytes -= 2; /* Skip junk bytes */ @@ -62,7 +58,7 @@ ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) state->x++; } - if (++state->count >= 79/2) { + if (++state->count >= 79 / 2) { state->state = NEWLINE; state->count = 0; } @@ -73,11 +69,9 @@ ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) state->errcode = IMAGING_CODEC_END; break; } - in = (UINT8*) im->image[state->y]; + in = (UINT8 *)im->image[state->y]; } - } return ptr - buf; - } diff --git a/src/libImaging/Except.c b/src/libImaging/Except.c index 3903b5bb8..f42ff9aec 100644 --- a/src/libImaging/Except.c +++ b/src/libImaging/Except.c @@ -19,41 +19,34 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - /* exception state */ void * -ImagingError_OSError(void) -{ +ImagingError_OSError(void) { fprintf(stderr, "*** exception: file access error\n"); return NULL; } void * -ImagingError_MemoryError(void) -{ +ImagingError_MemoryError(void) { fprintf(stderr, "*** exception: out of memory\n"); return NULL; } void * -ImagingError_ModeError(void) -{ +ImagingError_ModeError(void) { return ImagingError_ValueError("bad image mode"); } void * -ImagingError_Mismatch(void) -{ +ImagingError_Mismatch(void) { return ImagingError_ValueError("images don't match"); } void * -ImagingError_ValueError(const char *message) -{ +ImagingError_ValueError(const char *message) { if (!message) { message = "exception: bad argument to function"; } @@ -62,21 +55,18 @@ ImagingError_ValueError(const char *message) } void -ImagingError_Clear(void) -{ +ImagingError_Clear(void) { /* nop */; } /* thread state */ void -ImagingSectionEnter(ImagingSectionCookie* cookie) -{ +ImagingSectionEnter(ImagingSectionCookie *cookie) { /* pass */ } void -ImagingSectionLeave(ImagingSectionCookie* cookie) -{ +ImagingSectionLeave(ImagingSectionCookie *cookie) { /* pass */ } diff --git a/src/libImaging/File.c b/src/libImaging/File.c index 14688d661..76d0abccc 100644 --- a/src/libImaging/File.c +++ b/src/libImaging/File.c @@ -15,19 +15,15 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #include - int -ImagingSaveRaw(Imaging im, FILE* fp) -{ +ImagingSaveRaw(Imaging im, FILE *fp) { int x, y, i; if (strcmp(im->mode, "1") == 0 || strcmp(im->mode, "L") == 0) { - /* @PIL227: FIXME: for mode "1", map != 0 to 255 */ /* PGM "L" */ @@ -36,33 +32,29 @@ ImagingSaveRaw(Imaging im, FILE* fp) } } else { - /* PPM "RGB" or other internal format */ for (y = 0; y < im->ysize; y++) { for (x = i = 0; x < im->xsize; x++, i += im->pixelsize) { - fwrite(im->image[y]+i, 1, im->bands, fp); + fwrite(im->image[y] + i, 1, im->bands, fp); } } - } return 1; } - int -ImagingSavePPM(Imaging im, const char* outfile) -{ - FILE* fp; +ImagingSavePPM(Imaging im, const char *outfile) { + FILE *fp; if (!im) { - (void) ImagingError_ValueError(NULL); + (void)ImagingError_ValueError(NULL); return 0; } fp = fopen(outfile, "wb"); if (!fp) { - (void) ImagingError_OSError(); + (void)ImagingError_OSError(); return 0; } @@ -74,7 +66,7 @@ ImagingSavePPM(Imaging im, const char* outfile) fprintf(fp, "P6\n%d %d\n255\n", im->xsize, im->ysize); } else { fclose(fp); - (void) ImagingError_ModeError(); + (void)ImagingError_ModeError(); return 0; } @@ -84,4 +76,3 @@ ImagingSavePPM(Imaging im, const char* outfile) return 1; } - diff --git a/src/libImaging/Fill.c b/src/libImaging/Fill.c index da143b4f9..f72060228 100644 --- a/src/libImaging/Fill.c +++ b/src/libImaging/Fill.c @@ -15,14 +15,12 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #include "math.h" Imaging -ImagingFill(Imaging im, const void* colour) -{ +ImagingFill(Imaging im, const void *colour) { int x, y; ImagingSectionCookie cookie; @@ -53,7 +51,7 @@ ImagingFill(Imaging im, const void* colour) } } } else { - unsigned char cc = (unsigned char) *(UINT8*) colour; + unsigned char cc = (unsigned char)*(UINT8 *)colour; for (y = 0; y < im->ysize; y++) { memset(im->image[y], cc, im->linesize); } @@ -65,13 +63,12 @@ ImagingFill(Imaging im, const void* colour) } Imaging -ImagingFillLinearGradient(const char *mode) -{ +ImagingFillLinearGradient(const char *mode) { Imaging im; int y; if (strlen(mode) != 1) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } im = ImagingNewDirty(mode, 256, 256); @@ -79,22 +76,34 @@ ImagingFillLinearGradient(const char *mode) return NULL; } - for (y = 0; y < 256; y++) { - memset(im->image8[y], (unsigned char) y, 256); + if (im->image8) { + for (y = 0; y < 256; y++) { + memset(im->image8[y], (unsigned char)y, 256); + } + } else { + int x; + for (y = 0; y < 256; y++) { + for (x = 0; x < 256; x++) { + if (im->type == IMAGING_TYPE_FLOAT32) { + IMAGING_PIXEL_FLOAT32(im, x, y) = y; + } else { + IMAGING_PIXEL_INT32(im, x, y) = y; + } + } + } } return im; } Imaging -ImagingFillRadialGradient(const char *mode) -{ +ImagingFillRadialGradient(const char *mode) { Imaging im; int x, y; int d; if (strlen(mode) != 1) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } im = ImagingNewDirty(mode, 256, 256); @@ -104,11 +113,19 @@ ImagingFillRadialGradient(const char *mode) for (y = 0; y < 256; y++) { for (x = 0; x < 256; x++) { - d = (int) sqrt((double) ((x-128)*(x-128) + (y-128)*(y-128)) * 2.0); + d = (int)sqrt( + (double)((x - 128) * (x - 128) + (y - 128) * (y - 128)) * 2.0); if (d >= 255) { - im->image8[y][x] = 255; - } else { + d = 255; + } + if (im->image8) { im->image8[y][x] = d; + } else { + if (im->type == IMAGING_TYPE_FLOAT32) { + IMAGING_PIXEL_FLOAT32(im, x, y) = d; + } else { + IMAGING_PIXEL_INT32(im, x, y) = d; + } } } } diff --git a/src/libImaging/Filter.c b/src/libImaging/Filter.c index 0897ddbfe..fab3b4948 100644 --- a/src/libImaging/Filter.c +++ b/src/libImaging/Filter.c @@ -26,59 +26,59 @@ #include "Imaging.h" - -static inline UINT8 clip8(float in) -{ +static inline UINT8 +clip8(float in) { if (in <= 0.0) { return 0; } if (in >= 255.0) { return 255; } - return (UINT8) in; + return (UINT8)in; } Imaging -ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) -{ +ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) { Imaging imOut; int x, y; ImagingSectionCookie cookie; if (xmargin < 0 && ymargin < 0) { - return (Imaging) ImagingError_ValueError("bad kernel size"); + return (Imaging)ImagingError_ValueError("bad kernel size"); } imOut = ImagingNewDirty( - imIn->mode, imIn->xsize+2*xmargin, imIn->ysize+2*ymargin); + imIn->mode, imIn->xsize + 2 * xmargin, imIn->ysize + 2 * ymargin); if (!imOut) { return NULL; } -#define EXPAND_LINE(type, image, yin, yout) {\ - for (x = 0; x < xmargin; x++) {\ - imOut->image[yout][x] = imIn->image[yin][0];\ - }\ - for (x = 0; x < imIn->xsize; x++) {\ - imOut->image[yout][x+xmargin] = imIn->image[yin][x];\ - }\ - for (x = 0; x < xmargin; x++) {\ - imOut->image[yout][xmargin+imIn->xsize+x] =\ - imIn->image[yin][imIn->xsize-1];\ - }\ -} +#define EXPAND_LINE(type, image, yin, yout) \ + { \ + for (x = 0; x < xmargin; x++) { \ + imOut->image[yout][x] = imIn->image[yin][0]; \ + } \ + for (x = 0; x < imIn->xsize; x++) { \ + imOut->image[yout][x + xmargin] = imIn->image[yin][x]; \ + } \ + for (x = 0; x < xmargin; x++) { \ + imOut->image[yout][xmargin + imIn->xsize + x] = \ + imIn->image[yin][imIn->xsize - 1]; \ + } \ + } -#define EXPAND(type, image) {\ - for (y = 0; y < ymargin; y++) {\ - EXPAND_LINE(type, image, 0, y);\ - }\ - for (y = 0; y < imIn->ysize; y++) {\ - EXPAND_LINE(type, image, y, y+ymargin);\ - }\ - for (y = 0; y < ymargin; y++) {\ - EXPAND_LINE(type, image, imIn->ysize-1, ymargin+imIn->ysize+y);\ - }\ -} +#define EXPAND(type, image) \ + { \ + for (y = 0; y < ymargin; y++) { \ + EXPAND_LINE(type, image, 0, y); \ + } \ + for (y = 0; y < imIn->ysize; y++) { \ + EXPAND_LINE(type, image, y, y + ymargin); \ + } \ + for (y = 0; y < ymargin; y++) { \ + EXPAND_LINE(type, image, imIn->ysize - 1, ymargin + imIn->ysize + y); \ + } \ + } ImagingSectionEnter(&cookie); if (imIn->image8) { @@ -93,15 +93,11 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) return imOut; } - void -ImagingFilter3x3(Imaging imOut, Imaging im, const float* kernel, - float offset) -{ -#define KERNEL1x3(in0, x, kernel, d) ( \ - _i2f((UINT8) in0[x-d]) * (kernel)[0] + \ - _i2f((UINT8) in0[x]) * (kernel)[1] + \ - _i2f((UINT8) in0[x+d]) * (kernel)[2]) +ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) { +#define KERNEL1x3(in0, x, kernel, d) \ + (_i2f((UINT8)in0[x - d]) * (kernel)[0] + _i2f((UINT8)in0[x]) * (kernel)[1] + \ + _i2f((UINT8)in0[x + d]) * (kernel)[2]) int x = 0, y = 0; @@ -109,86 +105,84 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float* kernel, if (im->bands == 1) { // Add one time for rounding offset += 0.5; - for (y = 1; y < im->ysize-1; y++) { - UINT8* in_1 = (UINT8*) im->image[y-1]; - UINT8* in0 = (UINT8*) im->image[y]; - UINT8* in1 = (UINT8*) im->image[y+1]; - UINT8* out = (UINT8*) imOut->image[y]; + for (y = 1; y < im->ysize - 1; y++) { + UINT8 *in_1 = (UINT8 *)im->image[y - 1]; + UINT8 *in0 = (UINT8 *)im->image[y]; + UINT8 *in1 = (UINT8 *)im->image[y + 1]; + UINT8 *out = (UINT8 *)imOut->image[y]; out[0] = in0[0]; - for (x = 1; x < im->xsize-1; x++) { + for (x = 1; x < im->xsize - 1; x++) { float ss = offset; ss += KERNEL1x3(in1, x, &kernel[0], 1); ss += KERNEL1x3(in0, x, &kernel[3], 1); ss += KERNEL1x3(in_1, x, &kernel[6], 1); out[x] = clip8(ss); - } + } out[x] = in0[x]; } } else { // Add one time for rounding offset += 0.5; - for (y = 1; y < im->ysize-1; y++) { - UINT8* in_1 = (UINT8*) im->image[y-1]; - UINT8* in0 = (UINT8*) im->image[y]; - UINT8* in1 = (UINT8*) im->image[y+1]; - UINT8* out = (UINT8*) imOut->image[y]; + for (y = 1; y < im->ysize - 1; y++) { + UINT8 *in_1 = (UINT8 *)im->image[y - 1]; + UINT8 *in0 = (UINT8 *)im->image[y]; + UINT8 *in1 = (UINT8 *)im->image[y + 1]; + UINT8 *out = (UINT8 *)imOut->image[y]; memcpy(out, in0, sizeof(UINT32)); if (im->bands == 2) { - for (x = 1; x < im->xsize-1; x++) { + for (x = 1; x < im->xsize - 1; x++) { float ss0 = offset; float ss3 = offset; UINT32 v; - ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4); - ss3 += KERNEL1x3(in1, x*4+3, &kernel[0], 4); - ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4); - ss3 += KERNEL1x3(in0, x*4+3, &kernel[3], 4); - ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4); - ss3 += KERNEL1x3(in_1, x*4+3, &kernel[6], 4); + ss0 += KERNEL1x3(in1, x * 4 + 0, &kernel[0], 4); + ss3 += KERNEL1x3(in1, x * 4 + 3, &kernel[0], 4); + ss0 += KERNEL1x3(in0, x * 4 + 0, &kernel[3], 4); + ss3 += KERNEL1x3(in0, x * 4 + 3, &kernel[3], 4); + ss0 += KERNEL1x3(in_1, x * 4 + 0, &kernel[6], 4); + ss3 += KERNEL1x3(in_1, x * 4 + 3, &kernel[6], 4); v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3)); memcpy(out + x * sizeof(v), &v, sizeof(v)); } } else if (im->bands == 3) { - for (x = 1; x < im->xsize-1; x++) { + for (x = 1; x < im->xsize - 1; x++) { float ss0 = offset; float ss1 = offset; float ss2 = offset; UINT32 v; - ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4); - ss1 += KERNEL1x3(in1, x*4+1, &kernel[0], 4); - ss2 += KERNEL1x3(in1, x*4+2, &kernel[0], 4); - ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4); - ss1 += KERNEL1x3(in0, x*4+1, &kernel[3], 4); - ss2 += KERNEL1x3(in0, x*4+2, &kernel[3], 4); - ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4); - ss1 += KERNEL1x3(in_1, x*4+1, &kernel[6], 4); - ss2 += KERNEL1x3(in_1, x*4+2, &kernel[6], 4); - v = MAKE_UINT32( - clip8(ss0), clip8(ss1), clip8(ss2), 0); + ss0 += KERNEL1x3(in1, x * 4 + 0, &kernel[0], 4); + ss1 += KERNEL1x3(in1, x * 4 + 1, &kernel[0], 4); + ss2 += KERNEL1x3(in1, x * 4 + 2, &kernel[0], 4); + ss0 += KERNEL1x3(in0, x * 4 + 0, &kernel[3], 4); + ss1 += KERNEL1x3(in0, x * 4 + 1, &kernel[3], 4); + ss2 += KERNEL1x3(in0, x * 4 + 2, &kernel[3], 4); + ss0 += KERNEL1x3(in_1, x * 4 + 0, &kernel[6], 4); + ss1 += KERNEL1x3(in_1, x * 4 + 1, &kernel[6], 4); + ss2 += KERNEL1x3(in_1, x * 4 + 2, &kernel[6], 4); + v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0); memcpy(out + x * sizeof(v), &v, sizeof(v)); } } else if (im->bands == 4) { - for (x = 1; x < im->xsize-1; x++) { + for (x = 1; x < im->xsize - 1; x++) { float ss0 = offset; float ss1 = offset; float ss2 = offset; float ss3 = offset; UINT32 v; - ss0 += KERNEL1x3(in1, x*4+0, &kernel[0], 4); - ss1 += KERNEL1x3(in1, x*4+1, &kernel[0], 4); - ss2 += KERNEL1x3(in1, x*4+2, &kernel[0], 4); - ss3 += KERNEL1x3(in1, x*4+3, &kernel[0], 4); - ss0 += KERNEL1x3(in0, x*4+0, &kernel[3], 4); - ss1 += KERNEL1x3(in0, x*4+1, &kernel[3], 4); - ss2 += KERNEL1x3(in0, x*4+2, &kernel[3], 4); - ss3 += KERNEL1x3(in0, x*4+3, &kernel[3], 4); - ss0 += KERNEL1x3(in_1, x*4+0, &kernel[6], 4); - ss1 += KERNEL1x3(in_1, x*4+1, &kernel[6], 4); - ss2 += KERNEL1x3(in_1, x*4+2, &kernel[6], 4); - ss3 += KERNEL1x3(in_1, x*4+3, &kernel[6], 4); - v = MAKE_UINT32( - clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3)); + ss0 += KERNEL1x3(in1, x * 4 + 0, &kernel[0], 4); + ss1 += KERNEL1x3(in1, x * 4 + 1, &kernel[0], 4); + ss2 += KERNEL1x3(in1, x * 4 + 2, &kernel[0], 4); + ss3 += KERNEL1x3(in1, x * 4 + 3, &kernel[0], 4); + ss0 += KERNEL1x3(in0, x * 4 + 0, &kernel[3], 4); + ss1 += KERNEL1x3(in0, x * 4 + 1, &kernel[3], 4); + ss2 += KERNEL1x3(in0, x * 4 + 2, &kernel[3], 4); + ss3 += KERNEL1x3(in0, x * 4 + 3, &kernel[3], 4); + ss0 += KERNEL1x3(in_1, x * 4 + 0, &kernel[6], 4); + ss1 += KERNEL1x3(in_1, x * 4 + 1, &kernel[6], 4); + ss2 += KERNEL1x3(in_1, x * 4 + 2, &kernel[6], 4); + ss3 += KERNEL1x3(in_1, x * 4 + 3, &kernel[6], 4); + v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3)); memcpy(out + x * sizeof(v), &v, sizeof(v)); } } @@ -198,17 +192,13 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float* kernel, memcpy(imOut->image[y], im->image[y], im->linesize); } - void -ImagingFilter5x5(Imaging imOut, Imaging im, const float* kernel, - float offset) -{ -#define KERNEL1x5(in0, x, kernel, d) ( \ - _i2f((UINT8) in0[x-d-d]) * (kernel)[0] + \ - _i2f((UINT8) in0[x-d]) * (kernel)[1] + \ - _i2f((UINT8) in0[x]) * (kernel)[2] + \ - _i2f((UINT8) in0[x+d]) * (kernel)[3] + \ - _i2f((UINT8) in0[x+d+d]) * (kernel)[4]) +ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) { +#define KERNEL1x5(in0, x, kernel, d) \ + (_i2f((UINT8)in0[x - d - d]) * (kernel)[0] + \ + _i2f((UINT8)in0[x - d]) * (kernel)[1] + _i2f((UINT8)in0[x]) * (kernel)[2] + \ + _i2f((UINT8)in0[x + d]) * (kernel)[3] + \ + _i2f((UINT8)in0[x + d + d]) * (kernel)[4]) int x = 0, y = 0; @@ -217,17 +207,17 @@ ImagingFilter5x5(Imaging imOut, Imaging im, const float* kernel, if (im->bands == 1) { // Add one time for rounding offset += 0.5; - for (y = 2; y < im->ysize-2; y++) { - UINT8* in_2 = (UINT8*) im->image[y-2]; - UINT8* in_1 = (UINT8*) im->image[y-1]; - UINT8* in0 = (UINT8*) im->image[y]; - UINT8* in1 = (UINT8*) im->image[y+1]; - UINT8* in2 = (UINT8*) im->image[y+2]; - UINT8* out = (UINT8*) imOut->image[y]; + for (y = 2; y < im->ysize - 2; y++) { + UINT8 *in_2 = (UINT8 *)im->image[y - 2]; + UINT8 *in_1 = (UINT8 *)im->image[y - 1]; + UINT8 *in0 = (UINT8 *)im->image[y]; + UINT8 *in1 = (UINT8 *)im->image[y + 1]; + UINT8 *in2 = (UINT8 *)im->image[y + 2]; + UINT8 *out = (UINT8 *)imOut->image[y]; out[0] = in0[0]; out[1] = in0[1]; - for (x = 2; x < im->xsize-2; x++) { + for (x = 2; x < im->xsize - 2; x++) { float ss = offset; ss += KERNEL1x5(in2, x, &kernel[0], 1); ss += KERNEL1x5(in1, x, &kernel[5], 1); @@ -236,112 +226,109 @@ ImagingFilter5x5(Imaging imOut, Imaging im, const float* kernel, ss += KERNEL1x5(in_2, x, &kernel[20], 1); out[x] = clip8(ss); } - out[x+0] = in0[x+0]; - out[x+1] = in0[x+1]; + out[x + 0] = in0[x + 0]; + out[x + 1] = in0[x + 1]; } } else { // Add one time for rounding offset += 0.5; - for (y = 2; y < im->ysize-2; y++) { - UINT8* in_2 = (UINT8*) im->image[y-2]; - UINT8* in_1 = (UINT8*) im->image[y-1]; - UINT8* in0 = (UINT8*) im->image[y]; - UINT8* in1 = (UINT8*) im->image[y+1]; - UINT8* in2 = (UINT8*) im->image[y+2]; - UINT8* out = (UINT8*) imOut->image[y]; + for (y = 2; y < im->ysize - 2; y++) { + UINT8 *in_2 = (UINT8 *)im->image[y - 2]; + UINT8 *in_1 = (UINT8 *)im->image[y - 1]; + UINT8 *in0 = (UINT8 *)im->image[y]; + UINT8 *in1 = (UINT8 *)im->image[y + 1]; + UINT8 *in2 = (UINT8 *)im->image[y + 2]; + UINT8 *out = (UINT8 *)imOut->image[y]; memcpy(out, in0, sizeof(UINT32) * 2); if (im->bands == 2) { - for (x = 2; x < im->xsize-2; x++) { + for (x = 2; x < im->xsize - 2; x++) { float ss0 = offset; float ss3 = offset; UINT32 v; - ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4); - ss3 += KERNEL1x5(in2, x*4+3, &kernel[0], 4); - ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4); - ss3 += KERNEL1x5(in1, x*4+3, &kernel[5], 4); - ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4); - ss3 += KERNEL1x5(in0, x*4+3, &kernel[10], 4); - ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4); - ss3 += KERNEL1x5(in_1, x*4+3, &kernel[15], 4); - ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4); - ss3 += KERNEL1x5(in_2, x*4+3, &kernel[20], 4); + ss0 += KERNEL1x5(in2, x * 4 + 0, &kernel[0], 4); + ss3 += KERNEL1x5(in2, x * 4 + 3, &kernel[0], 4); + ss0 += KERNEL1x5(in1, x * 4 + 0, &kernel[5], 4); + ss3 += KERNEL1x5(in1, x * 4 + 3, &kernel[5], 4); + ss0 += KERNEL1x5(in0, x * 4 + 0, &kernel[10], 4); + ss3 += KERNEL1x5(in0, x * 4 + 3, &kernel[10], 4); + ss0 += KERNEL1x5(in_1, x * 4 + 0, &kernel[15], 4); + ss3 += KERNEL1x5(in_1, x * 4 + 3, &kernel[15], 4); + ss0 += KERNEL1x5(in_2, x * 4 + 0, &kernel[20], 4); + ss3 += KERNEL1x5(in_2, x * 4 + 3, &kernel[20], 4); v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3)); memcpy(out + x * sizeof(v), &v, sizeof(v)); } } else if (im->bands == 3) { - for (x = 2; x < im->xsize-2; x++) { + for (x = 2; x < im->xsize - 2; x++) { float ss0 = offset; float ss1 = offset; float ss2 = offset; UINT32 v; - ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4); - ss1 += KERNEL1x5(in2, x*4+1, &kernel[0], 4); - ss2 += KERNEL1x5(in2, x*4+2, &kernel[0], 4); - ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4); - ss1 += KERNEL1x5(in1, x*4+1, &kernel[5], 4); - ss2 += KERNEL1x5(in1, x*4+2, &kernel[5], 4); - ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4); - ss1 += KERNEL1x5(in0, x*4+1, &kernel[10], 4); - ss2 += KERNEL1x5(in0, x*4+2, &kernel[10], 4); - ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4); - ss1 += KERNEL1x5(in_1, x*4+1, &kernel[15], 4); - ss2 += KERNEL1x5(in_1, x*4+2, &kernel[15], 4); - ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4); - ss1 += KERNEL1x5(in_2, x*4+1, &kernel[20], 4); - ss2 += KERNEL1x5(in_2, x*4+2, &kernel[20], 4); - v = MAKE_UINT32( - clip8(ss0), clip8(ss1), clip8(ss2), 0); + ss0 += KERNEL1x5(in2, x * 4 + 0, &kernel[0], 4); + ss1 += KERNEL1x5(in2, x * 4 + 1, &kernel[0], 4); + ss2 += KERNEL1x5(in2, x * 4 + 2, &kernel[0], 4); + ss0 += KERNEL1x5(in1, x * 4 + 0, &kernel[5], 4); + ss1 += KERNEL1x5(in1, x * 4 + 1, &kernel[5], 4); + ss2 += KERNEL1x5(in1, x * 4 + 2, &kernel[5], 4); + ss0 += KERNEL1x5(in0, x * 4 + 0, &kernel[10], 4); + ss1 += KERNEL1x5(in0, x * 4 + 1, &kernel[10], 4); + ss2 += KERNEL1x5(in0, x * 4 + 2, &kernel[10], 4); + ss0 += KERNEL1x5(in_1, x * 4 + 0, &kernel[15], 4); + ss1 += KERNEL1x5(in_1, x * 4 + 1, &kernel[15], 4); + ss2 += KERNEL1x5(in_1, x * 4 + 2, &kernel[15], 4); + ss0 += KERNEL1x5(in_2, x * 4 + 0, &kernel[20], 4); + ss1 += KERNEL1x5(in_2, x * 4 + 1, &kernel[20], 4); + ss2 += KERNEL1x5(in_2, x * 4 + 2, &kernel[20], 4); + v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0); memcpy(out + x * sizeof(v), &v, sizeof(v)); } } else if (im->bands == 4) { - for (x = 2; x < im->xsize-2; x++) { + for (x = 2; x < im->xsize - 2; x++) { float ss0 = offset; float ss1 = offset; float ss2 = offset; float ss3 = offset; UINT32 v; - ss0 += KERNEL1x5(in2, x*4+0, &kernel[0], 4); - ss1 += KERNEL1x5(in2, x*4+1, &kernel[0], 4); - ss2 += KERNEL1x5(in2, x*4+2, &kernel[0], 4); - ss3 += KERNEL1x5(in2, x*4+3, &kernel[0], 4); - ss0 += KERNEL1x5(in1, x*4+0, &kernel[5], 4); - ss1 += KERNEL1x5(in1, x*4+1, &kernel[5], 4); - ss2 += KERNEL1x5(in1, x*4+2, &kernel[5], 4); - ss3 += KERNEL1x5(in1, x*4+3, &kernel[5], 4); - ss0 += KERNEL1x5(in0, x*4+0, &kernel[10], 4); - ss1 += KERNEL1x5(in0, x*4+1, &kernel[10], 4); - ss2 += KERNEL1x5(in0, x*4+2, &kernel[10], 4); - ss3 += KERNEL1x5(in0, x*4+3, &kernel[10], 4); - ss0 += KERNEL1x5(in_1, x*4+0, &kernel[15], 4); - ss1 += KERNEL1x5(in_1, x*4+1, &kernel[15], 4); - ss2 += KERNEL1x5(in_1, x*4+2, &kernel[15], 4); - ss3 += KERNEL1x5(in_1, x*4+3, &kernel[15], 4); - ss0 += KERNEL1x5(in_2, x*4+0, &kernel[20], 4); - ss1 += KERNEL1x5(in_2, x*4+1, &kernel[20], 4); - ss2 += KERNEL1x5(in_2, x*4+2, &kernel[20], 4); - ss3 += KERNEL1x5(in_2, x*4+3, &kernel[20], 4); - v = MAKE_UINT32( - clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3)); + ss0 += KERNEL1x5(in2, x * 4 + 0, &kernel[0], 4); + ss1 += KERNEL1x5(in2, x * 4 + 1, &kernel[0], 4); + ss2 += KERNEL1x5(in2, x * 4 + 2, &kernel[0], 4); + ss3 += KERNEL1x5(in2, x * 4 + 3, &kernel[0], 4); + ss0 += KERNEL1x5(in1, x * 4 + 0, &kernel[5], 4); + ss1 += KERNEL1x5(in1, x * 4 + 1, &kernel[5], 4); + ss2 += KERNEL1x5(in1, x * 4 + 2, &kernel[5], 4); + ss3 += KERNEL1x5(in1, x * 4 + 3, &kernel[5], 4); + ss0 += KERNEL1x5(in0, x * 4 + 0, &kernel[10], 4); + ss1 += KERNEL1x5(in0, x * 4 + 1, &kernel[10], 4); + ss2 += KERNEL1x5(in0, x * 4 + 2, &kernel[10], 4); + ss3 += KERNEL1x5(in0, x * 4 + 3, &kernel[10], 4); + ss0 += KERNEL1x5(in_1, x * 4 + 0, &kernel[15], 4); + ss1 += KERNEL1x5(in_1, x * 4 + 1, &kernel[15], 4); + ss2 += KERNEL1x5(in_1, x * 4 + 2, &kernel[15], 4); + ss3 += KERNEL1x5(in_1, x * 4 + 3, &kernel[15], 4); + ss0 += KERNEL1x5(in_2, x * 4 + 0, &kernel[20], 4); + ss1 += KERNEL1x5(in_2, x * 4 + 1, &kernel[20], 4); + ss2 += KERNEL1x5(in_2, x * 4 + 2, &kernel[20], 4); + ss3 += KERNEL1x5(in_2, x * 4 + 3, &kernel[20], 4); + v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3)); memcpy(out + x * sizeof(v), &v, sizeof(v)); } } - memcpy(out + x * sizeof(UINT32), in0 + x * sizeof(UINT32), sizeof(UINT32) * 2); + memcpy( + out + x * sizeof(UINT32), in0 + x * sizeof(UINT32), sizeof(UINT32) * 2); } } memcpy(imOut->image[y], im->image[y], im->linesize); - memcpy(imOut->image[y+1], im->image[y+1], im->linesize); + memcpy(imOut->image[y + 1], im->image[y + 1], im->linesize); } Imaging -ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel, - FLOAT32 offset) -{ +ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 offset) { Imaging imOut; ImagingSectionCookie cookie; - if ( ! im || im->type != IMAGING_TYPE_UINT8) { - return (Imaging) ImagingError_ModeError(); + if (!im || im->type != IMAGING_TYPE_UINT8) { + return (Imaging)ImagingError_ModeError(); } if (im->xsize < xsize || im->ysize < ysize) { @@ -349,7 +336,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel, } if ((xsize != 3 && xsize != 5) || xsize != ysize) { - return (Imaging) ImagingError_ValueError("bad kernel size"); + return (Imaging)ImagingError_ValueError("bad kernel size"); } imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); @@ -368,4 +355,3 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel, ImagingSectionLeave(&cookie); return imOut; } - diff --git a/src/libImaging/FliDecode.c b/src/libImaging/FliDecode.c index 84508013d..3a6030703 100644 --- a/src/libImaging/FliDecode.c +++ b/src/libImaging/FliDecode.c @@ -14,26 +14,21 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" +#define I16(ptr) ((ptr)[0] + ((ptr)[1] << 8)) -#define I16(ptr)\ - ((ptr)[0] + ((ptr)[1] << 8)) +#define I32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24)) -#define I32(ptr)\ - ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24)) - -#define ERR_IF_DATA_OOB(offset) \ - if ((data + (offset)) > ptr + bytes) {\ - state->errcode = IMAGING_CODEC_OVERRUN; \ - return -1; \ - } +#define ERR_IF_DATA_OOB(offset) \ + if ((data + (offset)) > ptr + bytes) { \ + state->errcode = IMAGING_CODEC_OVERRUN; \ + return -1; \ + } int -ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ - UINT8* ptr; +ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { + UINT8 *ptr; int framesize; int c, chunks, advance; int l, lines; @@ -62,36 +57,39 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt state->errcode = IMAGING_CODEC_OVERRUN; return -1; } - if (I16(ptr+4) != 0xF1FA) { + if (I16(ptr + 4) != 0xF1FA) { state->errcode = IMAGING_CODEC_UNKNOWN; return -1; } - chunks = I16(ptr+6); + chunks = I16(ptr + 6); ptr += 16; bytes -= 16; /* Process subchunks */ for (c = 0; c < chunks; c++) { - UINT8* data; + UINT8 *data; if (bytes < 10) { state->errcode = IMAGING_CODEC_OVERRUN; return -1; } data = ptr + 6; - switch (I16(ptr+4)) { - case 4: case 11: + switch (I16(ptr + 4)) { + case 4: + case 11: /* FLI COLOR chunk */ break; /* ignored; handled by Python code */ case 7: /* FLI SS2 chunk (word delta) */ /* OOB ok, we've got 4 bytes min on entry */ - lines = I16(data); data += 2; + lines = I16(data); + data += 2; for (l = y = 0; l < lines && y < state->ysize; l++, y++) { - UINT8* local_buf = (UINT8*) im->image[y]; + UINT8 *local_buf = (UINT8 *)im->image[y]; int p, packets; ERR_IF_DATA_OOB(2) - packets = I16(data); data += 2; + packets = I16(data); + data += 2; while (packets & 0x8000) { /* flag word */ if (packets & 0x4000) { @@ -100,20 +98,21 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt state->errcode = IMAGING_CODEC_OVERRUN; return -1; } - local_buf = (UINT8*) im->image[y]; + local_buf = (UINT8 *)im->image[y]; } else { /* store last byte (used if line width is odd) */ - local_buf[state->xsize-1] = (UINT8) packets; + local_buf[state->xsize - 1] = (UINT8)packets; } ERR_IF_DATA_OOB(2) - packets = I16(data); data += 2; + packets = I16(data); + data += 2; } for (p = x = 0; p < packets; p++) { ERR_IF_DATA_OOB(2) x += data[0]; /* pixel skip */ if (data[1] >= 128) { ERR_IF_DATA_OOB(4) - i = 256-data[1]; /* run */ + i = 256 - data[1]; /* run */ if (x + i + i > state->xsize) { break; } @@ -123,11 +122,11 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt } data += 2 + 2; } else { - i = 2 * (int) data[1]; /* chunk */ + i = 2 * (int)data[1]; /* chunk */ if (x + i > state->xsize) { break; } - ERR_IF_DATA_OOB(2+i) + ERR_IF_DATA_OOB(2 + i) memcpy(local_buf + x, data + 2, i); data += 2 + i; x += i; @@ -146,16 +145,18 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt case 12: /* FLI LC chunk (byte delta) */ /* OOB Check ok, we have 4 bytes min here */ - y = I16(data); ymax = y + I16(data+2); data += 4; + y = I16(data); + ymax = y + I16(data + 2); + data += 4; for (; y < ymax && y < state->ysize; y++) { - UINT8* out = (UINT8*) im->image[y]; - ERR_IF_DATA_OOB(1) + UINT8 *out = (UINT8 *)im->image[y]; + ERR_IF_DATA_OOB(1) int p, packets = *data++; for (p = x = 0; p < packets; p++, x += i) { ERR_IF_DATA_OOB(2) x += data[0]; /* skip pixels */ if (data[1] & 0x80) { - i = 256-data[1]; /* run */ + i = 256 - data[1]; /* run */ if (x + i > state->xsize) { break; } @@ -167,7 +168,7 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt if (x + i > state->xsize) { break; } - ERR_IF_DATA_OOB(2+i) + ERR_IF_DATA_OOB(2 + i) memcpy(out + x, data + 2, i); data += i + 2; } @@ -192,7 +193,7 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt /* FLI BRUN chunk */ /* OOB, ok, we've got 4 bytes min on entry */ for (y = 0; y < state->ysize; y++) { - UINT8* out = (UINT8*) im->image[y]; + UINT8 *out = (UINT8 *)im->image[y]; data += 1; /* ignore packetcount byte */ for (x = 0; x < state->xsize; x += i) { ERR_IF_DATA_OOB(2) @@ -201,7 +202,7 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt if (x + i > state->xsize) { break; /* safety first */ } - ERR_IF_DATA_OOB(i+1) + ERR_IF_DATA_OOB(i + 1) memcpy(out + x, data + 1, i); data += i + 1; } else { @@ -222,12 +223,12 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt break; case 16: /* COPY chunk */ - if (state->xsize > bytes/state->ysize) { + if (state->xsize > bytes / state->ysize) { /* not enough data for frame */ return ptr - buf; /* bytes consumed */ } for (y = 0; y < state->ysize; y++) { - UINT8* local_buf = (UINT8*) im->image[y]; + UINT8 *local_buf = (UINT8 *)im->image[y]; memcpy(local_buf, data, state->xsize); data += state->xsize; } @@ -242,6 +243,11 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt return -1; } advance = I32(ptr); + if (advance == 0 ) { + // If there's no advance, we're in an infinite loop + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } if (advance < 0 || advance > bytes) { state->errcode = IMAGING_CODEC_OVERRUN; return -1; diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index 06d0cf24d..0c5915792 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -15,28 +15,27 @@ /* Transpose operations */ Imaging -ImagingFlipLeftRight(Imaging imOut, Imaging imIn) -{ +ImagingFlipLeftRight(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y, xr; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return (Imaging) ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch(); } ImagingCopyPalette(imOut, imIn); -#define FLIP_LEFT_RIGHT(INT, image) \ - for (y = 0; y < imIn->ysize; y++) { \ - INT* in = (INT *)imIn->image[y]; \ - INT* out = (INT *)imOut->image[y]; \ - xr = imIn->xsize-1; \ +#define FLIP_LEFT_RIGHT(INT, image) \ + for (y = 0; y < imIn->ysize; y++) { \ + INT *in = (INT *)imIn->image[y]; \ + INT *out = (INT *)imOut->image[y]; \ + xr = imIn->xsize - 1; \ for (x = 0; x < imIn->xsize; x++, xr--) { \ - out[xr] = in[x]; \ - } \ + out[xr] = in[x]; \ + } \ } ImagingSectionEnter(&cookie); @@ -58,18 +57,16 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn) return imOut; } - Imaging -ImagingFlipTopBottom(Imaging imOut, Imaging imIn) -{ +ImagingFlipTopBottom(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int y, yr; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return (Imaging) ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch(); } ImagingCopyPalette(imOut, imIn); @@ -86,43 +83,45 @@ ImagingFlipTopBottom(Imaging imOut, Imaging imIn) return imOut; } - Imaging -ImagingRotate90(Imaging imOut, Imaging imIn) -{ +ImagingRotate90(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y, xx, yy, xr, xxsize, yysize; int xxx, yyy, xxxsize, yyysize; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { - return (Imaging) ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch(); } ImagingCopyPalette(imOut, imIn); -#define ROTATE_90(INT, image) \ - for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ - for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ +#define ROTATE_90(INT, image) \ + for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ + for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ - for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \ - for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \ - yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \ - xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \ - for (yyy = yy; yyy < yyysize; yyy++) { \ - INT* in = (INT *)imIn->image[yyy]; \ - xr = imIn->xsize - 1 - xx; \ - for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \ - INT* out = (INT *)imOut->image[xr]; \ - out[yyy] = in[xxx]; \ - } \ - } \ - } \ - } \ - } \ + for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \ + for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \ + yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \ + ? yy + ROTATE_SMALL_CHUNK \ + : imIn->ysize; \ + xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \ + ? xx + ROTATE_SMALL_CHUNK \ + : imIn->xsize; \ + for (yyy = yy; yyy < yyysize; yyy++) { \ + INT *in = (INT *)imIn->image[yyy]; \ + xr = imIn->xsize - 1 - xx; \ + for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \ + INT *out = (INT *)imOut->image[xr]; \ + out[yyy] = in[xxx]; \ + } \ + } \ + } \ + } \ + } \ } ImagingSectionEnter(&cookie); @@ -144,42 +143,44 @@ ImagingRotate90(Imaging imOut, Imaging imIn) return imOut; } - Imaging -ImagingTranspose(Imaging imOut, Imaging imIn) -{ +ImagingTranspose(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y, xx, yy, xxsize, yysize; int xxx, yyy, xxxsize, yyysize; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { - return (Imaging) ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch(); } ImagingCopyPalette(imOut, imIn); -#define TRANSPOSE(INT, image) \ - for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ - for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ +#define TRANSPOSE(INT, image) \ + for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ + for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ - for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \ - for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \ - yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \ - xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \ - for (yyy = yy; yyy < yyysize; yyy++) { \ - INT* in = (INT *)imIn->image[yyy]; \ - for (xxx = xx; xxx < xxxsize; xxx++) { \ - INT* out = (INT *)imOut->image[xxx]; \ - out[yyy] = in[xxx]; \ - } \ - } \ - } \ - } \ - } \ + for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \ + for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \ + yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \ + ? yy + ROTATE_SMALL_CHUNK \ + : imIn->ysize; \ + xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \ + ? xx + ROTATE_SMALL_CHUNK \ + : imIn->xsize; \ + for (yyy = yy; yyy < yyysize; yyy++) { \ + INT *in = (INT *)imIn->image[yyy]; \ + for (xxx = xx; xxx < xxxsize; xxx++) { \ + INT *out = (INT *)imOut->image[xxx]; \ + out[yyy] = in[xxx]; \ + } \ + } \ + } \ + } \ + } \ } ImagingSectionEnter(&cookie); @@ -201,44 +202,46 @@ ImagingTranspose(Imaging imOut, Imaging imIn) return imOut; } - Imaging -ImagingTransverse(Imaging imOut, Imaging imIn) -{ +ImagingTransverse(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y, xr, yr, xx, yy, xxsize, yysize; int xxx, yyy, xxxsize, yyysize; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { - return (Imaging) ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch(); } ImagingCopyPalette(imOut, imIn); -#define TRANSVERSE(INT, image) \ - for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ - for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ +#define TRANSVERSE(INT, image) \ + for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ + for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ - for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \ - for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \ - yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \ - xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \ - yr = imIn->ysize - 1 - yy; \ - for (yyy = yy; yyy < yyysize; yyy++, yr--) { \ - INT* in = (INT *)imIn->image[yyy]; \ - xr = imIn->xsize - 1 - xx; \ - for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \ - INT* out = (INT *)imOut->image[xr]; \ - out[yr] = in[xxx]; \ - } \ - } \ - } \ - } \ - } \ + for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \ + for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \ + yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \ + ? yy + ROTATE_SMALL_CHUNK \ + : imIn->ysize; \ + xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \ + ? xx + ROTATE_SMALL_CHUNK \ + : imIn->xsize; \ + yr = imIn->ysize - 1 - yy; \ + for (yyy = yy; yyy < yyysize; yyy++, yr--) { \ + INT *in = (INT *)imIn->image[yyy]; \ + xr = imIn->xsize - 1 - xx; \ + for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \ + INT *out = (INT *)imOut->image[xr]; \ + out[yr] = in[xxx]; \ + } \ + } \ + } \ + } \ + } \ } ImagingSectionEnter(&cookie); @@ -260,35 +263,33 @@ ImagingTransverse(Imaging imOut, Imaging imIn) return imOut; } - Imaging -ImagingRotate180(Imaging imOut, Imaging imIn) -{ +ImagingRotate180(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y, xr, yr; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return (Imaging) ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch(); } ImagingCopyPalette(imOut, imIn); -#define ROTATE_180(INT, image) \ - for (y = 0; y < imIn->ysize; y++, yr--) { \ - INT* in = (INT *)imIn->image[y]; \ - INT* out = (INT *)imOut->image[yr]; \ - xr = imIn->xsize-1; \ +#define ROTATE_180(INT, image) \ + for (y = 0; y < imIn->ysize; y++, yr--) { \ + INT *in = (INT *)imIn->image[y]; \ + INT *out = (INT *)imOut->image[yr]; \ + xr = imIn->xsize - 1; \ for (x = 0; x < imIn->xsize; x++, xr--) { \ - out[xr] = in[x]; \ - } \ + out[xr] = in[x]; \ + } \ } ImagingSectionEnter(&cookie); - yr = imIn->ysize-1; + yr = imIn->ysize - 1; if (imIn->image8) { if (strncmp(imIn->mode, "I;16", 4) == 0) { ROTATE_180(UINT16, image8) @@ -306,43 +307,45 @@ ImagingRotate180(Imaging imOut, Imaging imIn) return imOut; } - Imaging -ImagingRotate270(Imaging imOut, Imaging imIn) -{ +ImagingRotate270(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y, xx, yy, yr, xxsize, yysize; int xxx, yyy, xxxsize, yyysize; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { - return (Imaging) ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch(); } ImagingCopyPalette(imOut, imIn); -#define ROTATE_270(INT, image) \ - for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ - for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ +#define ROTATE_270(INT, image) \ + for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ + for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ - for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \ - for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \ - yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize ? yy + ROTATE_SMALL_CHUNK : imIn->ysize; \ - xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize ? xx + ROTATE_SMALL_CHUNK : imIn->xsize; \ - yr = imIn->ysize - 1 - yy; \ - for (yyy = yy; yyy < yyysize; yyy++, yr--) { \ - INT* in = (INT *)imIn->image[yyy]; \ - for (xxx = xx; xxx < xxxsize; xxx++) { \ - INT* out = (INT *)imOut->image[xxx]; \ - out[yr] = in[xxx]; \ - } \ - } \ - } \ - } \ - } \ + for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \ + for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \ + yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \ + ? yy + ROTATE_SMALL_CHUNK \ + : imIn->ysize; \ + xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \ + ? xx + ROTATE_SMALL_CHUNK \ + : imIn->xsize; \ + yr = imIn->ysize - 1 - yy; \ + for (yyy = yy; yyy < yyysize; yyy++, yr--) { \ + INT *in = (INT *)imIn->image[yyy]; \ + for (xxx = xx; xxx < xxxsize; xxx++) { \ + INT *out = (INT *)imOut->image[xxx]; \ + out[yr] = in[xxx]; \ + } \ + } \ + } \ + } \ + } \ } ImagingSectionEnter(&cookie); @@ -364,63 +367,74 @@ ImagingRotate270(Imaging imOut, Imaging imIn) return imOut; } - /* -------------------------------------------------------------------- */ /* Transforms */ /* transform primitives (ImagingTransformMap) */ static int -affine_transform(double* xout, double* yout, int x, int y, void* data) -{ +affine_transform(double *xout, double *yout, int x, int y, void *data) { /* full moon tonight. your compiler will generate bogus code for simple expressions, unless you reorganize the code, or install Service Pack 3 */ - double* a = (double*) data; - double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; - double a3 = a[3]; double a4 = a[4]; double a5 = a[5]; + double *a = (double *)data; + double a0 = a[0]; + double a1 = a[1]; + double a2 = a[2]; + double a3 = a[3]; + double a4 = a[4]; + double a5 = a[5]; double xin = x + 0.5; double yin = y + 0.5; - xout[0] = a0*xin + a1*yin + a2; - yout[0] = a3*xin + a4*yin + a5; + xout[0] = a0 * xin + a1 * yin + a2; + yout[0] = a3 * xin + a4 * yin + a5; return 1; } static int -perspective_transform(double* xout, double* yout, int x, int y, void* data) -{ - double* a = (double*) data; - double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; - double a3 = a[3]; double a4 = a[4]; double a5 = a[5]; - double a6 = a[6]; double a7 = a[7]; +perspective_transform(double *xout, double *yout, int x, int y, void *data) { + double *a = (double *)data; + double a0 = a[0]; + double a1 = a[1]; + double a2 = a[2]; + double a3 = a[3]; + double a4 = a[4]; + double a5 = a[5]; + double a6 = a[6]; + double a7 = a[7]; double xin = x + 0.5; double yin = y + 0.5; - xout[0] = (a0*xin + a1*yin + a2) / (a6*xin + a7*yin + 1); - yout[0] = (a3*xin + a4*yin + a5) / (a6*xin + a7*yin + 1); + xout[0] = (a0 * xin + a1 * yin + a2) / (a6 * xin + a7 * yin + 1); + yout[0] = (a3 * xin + a4 * yin + a5) / (a6 * xin + a7 * yin + 1); return 1; } static int -quad_transform(double* xout, double* yout, int x, int y, void* data) -{ +quad_transform(double *xout, double *yout, int x, int y, void *data) { /* quad warp: map quadrilateral to rectangle */ - double* a = (double*) data; - double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; double a3 = a[3]; - double a4 = a[4]; double a5 = a[5]; double a6 = a[6]; double a7 = a[7]; + double *a = (double *)data; + double a0 = a[0]; + double a1 = a[1]; + double a2 = a[2]; + double a3 = a[3]; + double a4 = a[4]; + double a5 = a[5]; + double a6 = a[6]; + double a7 = a[7]; double xin = x + 0.5; double yin = y + 0.5; - xout[0] = a0 + a1*xin + a2*yin + a3*xin*yin; - yout[0] = a4 + a5*xin + a6*yin + a7*xin*yin; + xout[0] = a0 + a1 * xin + a2 * yin + a3 * xin * yin; + yout[0] = a4 + a5 * xin + a6 * yin + a7 * xin * yin; return 1; } @@ -428,20 +442,18 @@ quad_transform(double* xout, double* yout, int x, int y, void* data) /* transform filters (ImagingTransformFilter) */ static int -nearest_filter8(void* out, Imaging im, double xin, double yin) -{ +nearest_filter8(void *out, Imaging im, double xin, double yin) { int x = COORD(xin); int y = COORD(yin); if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { return 0; } - ((UINT8*)out)[0] = im->image8[y][x]; + ((UINT8 *)out)[0] = im->image8[y][x]; return 1; } static int -nearest_filter16(void* out, Imaging im, double xin, double yin) -{ +nearest_filter16(void *out, Imaging im, double xin, double yin) { int x = COORD(xin); int y = COORD(yin); if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { @@ -452,8 +464,7 @@ nearest_filter16(void* out, Imaging im, double xin, double yin) } static int -nearest_filter32(void* out, Imaging im, double xin, double yin) -{ +nearest_filter32(void *out, Imaging im, double xin, double yin) { int x = COORD(xin); int y = COORD(yin); if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { @@ -463,54 +474,52 @@ nearest_filter32(void* out, Imaging im, double xin, double yin) return 1; } -#define XCLIP(im, x) ( ((x) < 0) ? 0 : ((x) < im->xsize) ? (x) : im->xsize-1 ) -#define YCLIP(im, y) ( ((y) < 0) ? 0 : ((y) < im->ysize) ? (y) : im->ysize-1 ) +#define XCLIP(im, x) (((x) < 0) ? 0 : ((x) < im->xsize) ? (x) : im->xsize - 1) +#define YCLIP(im, y) (((y) < 0) ? 0 : ((y) < im->ysize) ? (y) : im->ysize - 1) -#define BILINEAR(v, a, b, d)\ - (v = (a) + ( (b) - (a) ) * (d)) +#define BILINEAR(v, a, b, d) (v = (a) + ((b) - (a)) * (d)) -#define BILINEAR_HEAD(type)\ - int x, y;\ - int x0, x1;\ - double v1, v2;\ - double dx, dy;\ - type* in;\ - if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize) {\ - return 0;\ - }\ - xin -= 0.5;\ - yin -= 0.5;\ - x = FLOOR(xin);\ - y = FLOOR(yin);\ - dx = xin - x;\ +#define BILINEAR_HEAD(type) \ + int x, y; \ + int x0, x1; \ + double v1, v2; \ + double dx, dy; \ + type *in; \ + if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize) { \ + return 0; \ + } \ + xin -= 0.5; \ + yin -= 0.5; \ + x = FLOOR(xin); \ + y = FLOOR(yin); \ + dx = xin - x; \ dy = yin - y; -#define BILINEAR_BODY(type, image, step, offset) {\ - in = (type*) ((image)[YCLIP(im, y)] + offset);\ - x0 = XCLIP(im, x+0)*step;\ - x1 = XCLIP(im, x+1)*step;\ - BILINEAR(v1, in[x0], in[x1], dx);\ - if (y+1 >= 0 && y+1 < im->ysize) {\ - in = (type*) ((image)[y+1] + offset);\ - BILINEAR(v2, in[x0], in[x1], dx);\ - } else {\ - v2 = v1;\ - }\ - BILINEAR(v1, v1, v2, dy);\ -} +#define BILINEAR_BODY(type, image, step, offset) \ + { \ + in = (type *)((image)[YCLIP(im, y)] + offset); \ + x0 = XCLIP(im, x + 0) * step; \ + x1 = XCLIP(im, x + 1) * step; \ + BILINEAR(v1, in[x0], in[x1], dx); \ + if (y + 1 >= 0 && y + 1 < im->ysize) { \ + in = (type *)((image)[y + 1] + offset); \ + BILINEAR(v2, in[x0], in[x1], dx); \ + } else { \ + v2 = v1; \ + } \ + BILINEAR(v1, v1, v2, dy); \ + } static int -bilinear_filter8(void* out, Imaging im, double xin, double yin) -{ +bilinear_filter8(void *out, Imaging im, double xin, double yin) { BILINEAR_HEAD(UINT8); BILINEAR_BODY(UINT8, im->image8, 1, 0); - ((UINT8*)out)[0] = (UINT8) v1; + ((UINT8 *)out)[0] = (UINT8)v1; return 1; } static int -bilinear_filter32I(void* out, Imaging im, double xin, double yin) -{ +bilinear_filter32I(void *out, Imaging im, double xin, double yin) { INT32 k; BILINEAR_HEAD(INT32); BILINEAR_BODY(INT32, im->image32, 1, 0); @@ -520,8 +529,7 @@ bilinear_filter32I(void* out, Imaging im, double xin, double yin) } static int -bilinear_filter32F(void* out, Imaging im, double xin, double yin) -{ +bilinear_filter32F(void *out, Imaging im, double xin, double yin) { FLOAT32 k; BILINEAR_HEAD(FLOAT32); BILINEAR_BODY(FLOAT32, im->image32, 1, 0); @@ -531,26 +539,24 @@ bilinear_filter32F(void* out, Imaging im, double xin, double yin) } static int -bilinear_filter32LA(void* out, Imaging im, double xin, double yin) -{ +bilinear_filter32LA(void *out, Imaging im, double xin, double yin) { BILINEAR_HEAD(UINT8); BILINEAR_BODY(UINT8, im->image, 4, 0); - ((UINT8*)out)[0] = (UINT8) v1; - ((UINT8*)out)[1] = (UINT8) v1; - ((UINT8*)out)[2] = (UINT8) v1; + ((UINT8 *)out)[0] = (UINT8)v1; + ((UINT8 *)out)[1] = (UINT8)v1; + ((UINT8 *)out)[2] = (UINT8)v1; BILINEAR_BODY(UINT8, im->image, 4, 3); - ((UINT8*)out)[3] = (UINT8) v1; + ((UINT8 *)out)[3] = (UINT8)v1; return 1; } static int -bilinear_filter32RGB(void* out, Imaging im, double xin, double yin) -{ +bilinear_filter32RGB(void *out, Imaging im, double xin, double yin) { int b; BILINEAR_HEAD(UINT8); for (b = 0; b < im->bands; b++) { BILINEAR_BODY(UINT8, im->image, 4, b); - ((UINT8*)out)[b] = (UINT8) v1; + ((UINT8 *)out)[b] = (UINT8)v1; } return 1; } @@ -559,79 +565,79 @@ bilinear_filter32RGB(void* out, Imaging im, double xin, double yin) #undef BILINEAR_HEAD #undef BILINEAR_BODY -#define BICUBIC(v, v1, v2, v3, v4, d) {\ - double p1 = v2;\ - double p2 = -v1 + v3;\ - double p3 = 2*(v1 - v2) + v3 - v4;\ - double p4 = -v1 + v2 - v3 + v4;\ - v = p1 + (d)*(p2 + (d)*(p3 + (d)*p4));\ -} +#define BICUBIC(v, v1, v2, v3, v4, d) \ + { \ + double p1 = v2; \ + double p2 = -v1 + v3; \ + double p3 = 2 * (v1 - v2) + v3 - v4; \ + double p4 = -v1 + v2 - v3 + v4; \ + v = p1 + (d) * (p2 + (d) * (p3 + (d)*p4)); \ + } -#define BICUBIC_HEAD(type)\ - int x = FLOOR(xin);\ - int y = FLOOR(yin);\ - int x0, x1, x2, x3;\ - double v1, v2, v3, v4;\ - double dx, dy;\ - type* in;\ - if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize) {\ - return 0;\ - }\ - xin -= 0.5;\ - yin -= 0.5;\ - x = FLOOR(xin);\ - y = FLOOR(yin);\ - dx = xin - x;\ - dy = yin - y;\ - x--; y--; - -#define BICUBIC_BODY(type, image, step, offset) {\ - in = (type*) ((image)[YCLIP(im, y)] + offset);\ - x0 = XCLIP(im, x+0)*step;\ - x1 = XCLIP(im, x+1)*step;\ - x2 = XCLIP(im, x+2)*step;\ - x3 = XCLIP(im, x+3)*step;\ - BICUBIC(v1, in[x0], in[x1], in[x2], in[x3], dx);\ - if (y+1 >= 0 && y+1 < im->ysize) {\ - in = (type*) ((image)[y+1] + offset);\ - BICUBIC(v2, in[x0], in[x1], in[x2], in[x3], dx);\ - } else {\ - v2 = v1;\ - }\ - if (y+2 >= 0 && y+2 < im->ysize) {\ - in = (type*) ((image)[y+2] + offset);\ - BICUBIC(v3, in[x0], in[x1], in[x2], in[x3], dx);\ - } else {\ - v3 = v2;\ - }\ - if (y+3 >= 0 && y+3 < im->ysize) {\ - in = (type*) ((image)[y+3] + offset);\ - BICUBIC(v4, in[x0], in[x1], in[x2], in[x3], dx);\ - } else {\ - v4 = v3;\ - }\ - BICUBIC(v1, v1, v2, v3, v4, dy);\ -} +#define BICUBIC_HEAD(type) \ + int x = FLOOR(xin); \ + int y = FLOOR(yin); \ + int x0, x1, x2, x3; \ + double v1, v2, v3, v4; \ + double dx, dy; \ + type *in; \ + if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize) { \ + return 0; \ + } \ + xin -= 0.5; \ + yin -= 0.5; \ + x = FLOOR(xin); \ + y = FLOOR(yin); \ + dx = xin - x; \ + dy = yin - y; \ + x--; \ + y--; +#define BICUBIC_BODY(type, image, step, offset) \ + { \ + in = (type *)((image)[YCLIP(im, y)] + offset); \ + x0 = XCLIP(im, x + 0) * step; \ + x1 = XCLIP(im, x + 1) * step; \ + x2 = XCLIP(im, x + 2) * step; \ + x3 = XCLIP(im, x + 3) * step; \ + BICUBIC(v1, in[x0], in[x1], in[x2], in[x3], dx); \ + if (y + 1 >= 0 && y + 1 < im->ysize) { \ + in = (type *)((image)[y + 1] + offset); \ + BICUBIC(v2, in[x0], in[x1], in[x2], in[x3], dx); \ + } else { \ + v2 = v1; \ + } \ + if (y + 2 >= 0 && y + 2 < im->ysize) { \ + in = (type *)((image)[y + 2] + offset); \ + BICUBIC(v3, in[x0], in[x1], in[x2], in[x3], dx); \ + } else { \ + v3 = v2; \ + } \ + if (y + 3 >= 0 && y + 3 < im->ysize) { \ + in = (type *)((image)[y + 3] + offset); \ + BICUBIC(v4, in[x0], in[x1], in[x2], in[x3], dx); \ + } else { \ + v4 = v3; \ + } \ + BICUBIC(v1, v1, v2, v3, v4, dy); \ + } static int -bicubic_filter8(void* out, Imaging im, double xin, double yin) -{ +bicubic_filter8(void *out, Imaging im, double xin, double yin) { BICUBIC_HEAD(UINT8); BICUBIC_BODY(UINT8, im->image8, 1, 0); if (v1 <= 0.0) { - ((UINT8*)out)[0] = 0; + ((UINT8 *)out)[0] = 0; } else if (v1 >= 255.0) { - ((UINT8*)out)[0] = 255; + ((UINT8 *)out)[0] = 255; } else { - ((UINT8*)out)[0] = (UINT8) v1; + ((UINT8 *)out)[0] = (UINT8)v1; } return 1; } static int -bicubic_filter32I(void* out, Imaging im, double xin, double yin) -{ +bicubic_filter32I(void *out, Imaging im, double xin, double yin) { INT32 k; BICUBIC_HEAD(INT32); BICUBIC_BODY(INT32, im->image32, 1, 0); @@ -641,8 +647,7 @@ bicubic_filter32I(void* out, Imaging im, double xin, double yin) } static int -bicubic_filter32F(void* out, Imaging im, double xin, double yin) -{ +bicubic_filter32F(void *out, Imaging im, double xin, double yin) { FLOAT32 k; BICUBIC_HEAD(FLOAT32); BICUBIC_BODY(FLOAT32, im->image32, 1, 0); @@ -652,47 +657,45 @@ bicubic_filter32F(void* out, Imaging im, double xin, double yin) } static int -bicubic_filter32LA(void* out, Imaging im, double xin, double yin) -{ +bicubic_filter32LA(void *out, Imaging im, double xin, double yin) { BICUBIC_HEAD(UINT8); BICUBIC_BODY(UINT8, im->image, 4, 0); if (v1 <= 0.0) { - ((UINT8*)out)[0] = 0; - ((UINT8*)out)[1] = 0; - ((UINT8*)out)[2] = 0; + ((UINT8 *)out)[0] = 0; + ((UINT8 *)out)[1] = 0; + ((UINT8 *)out)[2] = 0; } else if (v1 >= 255.0) { - ((UINT8*)out)[0] = 255; - ((UINT8*)out)[1] = 255; - ((UINT8*)out)[2] = 255; + ((UINT8 *)out)[0] = 255; + ((UINT8 *)out)[1] = 255; + ((UINT8 *)out)[2] = 255; } else { - ((UINT8*)out)[0] = (UINT8) v1; - ((UINT8*)out)[1] = (UINT8) v1; - ((UINT8*)out)[2] = (UINT8) v1; + ((UINT8 *)out)[0] = (UINT8)v1; + ((UINT8 *)out)[1] = (UINT8)v1; + ((UINT8 *)out)[2] = (UINT8)v1; } BICUBIC_BODY(UINT8, im->image, 4, 3); if (v1 <= 0.0) { - ((UINT8*)out)[3] = 0; + ((UINT8 *)out)[3] = 0; } else if (v1 >= 255.0) { - ((UINT8*)out)[3] = 255; + ((UINT8 *)out)[3] = 255; } else { - ((UINT8*)out)[3] = (UINT8) v1; + ((UINT8 *)out)[3] = (UINT8)v1; } return 1; } static int -bicubic_filter32RGB(void* out, Imaging im, double xin, double yin) -{ +bicubic_filter32RGB(void *out, Imaging im, double xin, double yin) { int b; BICUBIC_HEAD(UINT8); for (b = 0; b < im->bands; b++) { BICUBIC_BODY(UINT8, im->image, 4, b); if (v1 <= 0.0) { - ((UINT8*)out)[b] = 0; + ((UINT8 *)out)[b] = 0; } else if (v1 >= 255.0) { - ((UINT8*)out)[b] = 255; + ((UINT8 *)out)[b] = 255; } else { - ((UINT8*)out)[b] = (UINT8) v1; + ((UINT8 *)out)[b] = (UINT8)v1; } } return 1; @@ -703,64 +706,63 @@ bicubic_filter32RGB(void* out, Imaging im, double xin, double yin) #undef BICUBIC_BODY static ImagingTransformFilter -getfilter(Imaging im, int filterid) -{ +getfilter(Imaging im, int filterid) { switch (filterid) { - case IMAGING_TRANSFORM_NEAREST: - if (im->image8) { - switch (im->type) { - case IMAGING_TYPE_UINT8: - return nearest_filter8; - case IMAGING_TYPE_SPECIAL: - switch (im->pixelsize) { - case 1: - return nearest_filter8; - case 2: - return nearest_filter16; - case 4: - return nearest_filter32; + case IMAGING_TRANSFORM_NEAREST: + if (im->image8) { + switch (im->type) { + case IMAGING_TYPE_UINT8: + return nearest_filter8; + case IMAGING_TYPE_SPECIAL: + switch (im->pixelsize) { + case 1: + return nearest_filter8; + case 2: + return nearest_filter16; + case 4: + return nearest_filter32; + } + } + } else { + return nearest_filter32; + } + break; + case IMAGING_TRANSFORM_BILINEAR: + if (im->image8) { + return bilinear_filter8; + } else if (im->image32) { + switch (im->type) { + case IMAGING_TYPE_UINT8: + if (im->bands == 2) { + return bilinear_filter32LA; + } else { + return bilinear_filter32RGB; + } + case IMAGING_TYPE_INT32: + return bilinear_filter32I; + case IMAGING_TYPE_FLOAT32: + return bilinear_filter32F; } } - } else { - return nearest_filter32; - } - break; - case IMAGING_TRANSFORM_BILINEAR: - if (im->image8) { - return bilinear_filter8; - } else if (im->image32) { - switch (im->type) { - case IMAGING_TYPE_UINT8: - if (im->bands == 2) { - return bilinear_filter32LA; - } else { - return bilinear_filter32RGB; + break; + case IMAGING_TRANSFORM_BICUBIC: + if (im->image8) { + return bicubic_filter8; + } else if (im->image32) { + switch (im->type) { + case IMAGING_TYPE_UINT8: + if (im->bands == 2) { + return bicubic_filter32LA; + } else { + return bicubic_filter32RGB; + } + case IMAGING_TYPE_INT32: + return bicubic_filter32I; + case IMAGING_TYPE_FLOAT32: + return bicubic_filter32F; } - case IMAGING_TYPE_INT32: - return bilinear_filter32I; - case IMAGING_TYPE_FLOAT32: - return bilinear_filter32F; } - } - break; - case IMAGING_TRANSFORM_BICUBIC: - if (im->image8) { - return bicubic_filter8; - } else if (im->image32) { - switch (im->type) { - case IMAGING_TYPE_UINT8: - if (im->bands == 2) { - return bicubic_filter32LA; - } else { - return bicubic_filter32RGB; - } - case IMAGING_TYPE_INT32: - return bicubic_filter32I; - case IMAGING_TYPE_FLOAT32: - return bicubic_filter32F; - } - } - break; + break; } /* no such filter */ return NULL; @@ -770,10 +772,16 @@ getfilter(Imaging im, int filterid) Imaging ImagingGenericTransform( - Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, - ImagingTransformMap transform, void* transform_data, - int filterid, int fill) -{ + Imaging imOut, + Imaging imIn, + int x0, + int y0, + int x1, + int y1, + ImagingTransformMap transform, + void *transform_data, + int filterid, + int fill) { /* slow generic transformation. use ImagingTransformAffine or ImagingScaleAffine where possible. */ @@ -784,11 +792,11 @@ ImagingGenericTransform( ImagingTransformFilter filter = getfilter(imIn, filterid); if (!filter) { - return (Imaging) ImagingError_ValueError("bad filter number"); + return (Imaging)ImagingError_ValueError("bad filter number"); } if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } ImagingCopyPalette(imOut, imIn); @@ -809,10 +817,10 @@ ImagingGenericTransform( } for (y = y0; y < y1; y++) { - out = imOut->image[y] + x0*imOut->pixelsize; + out = imOut->image[y] + x0 * imOut->pixelsize; for (x = x0; x < x1; x++) { - if ( ! transform(&xx, &yy, x-x0, y-y0, transform_data) || - ! filter(out, imIn, xx, yy)) { + if (!transform(&xx, &yy, x - x0, y - y0, transform_data) || + !filter(out, imIn, xx, yy)) { if (fill) { memset(out, 0, imOut->pixelsize); } @@ -827,10 +835,15 @@ ImagingGenericTransform( } static Imaging -ImagingScaleAffine(Imaging imOut, Imaging imIn, - int x0, int y0, int x1, int y1, - double a[6], int fill) -{ +ImagingScaleAffine( + Imaging imOut, + Imaging imIn, + int x0, + int y0, + int x1, + int y1, + double a[6], + int fill) { /* scale, nearest neighbour resampling */ ImagingSectionCookie cookie; @@ -841,7 +854,7 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, int *xintab; if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } ImagingCopyPalette(imOut, imIn); @@ -860,10 +873,10 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, } /* malloc check ok, uses calloc for overflow */ - xintab = (int*) calloc(imOut->xsize, sizeof(int)); + xintab = (int *)calloc(imOut->xsize, sizeof(int)); if (!xintab) { ImagingDelete(imOut); - return (Imaging) ImagingError_MemoryError(); + return (Imaging)ImagingError_MemoryError(); } xo = a[2] + a[0] * 0.5; @@ -875,8 +888,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, /* Pretabulate horizontal pixel positions */ for (x = x0; x < x1; x++) { xin = COORD(xo); - if (xin >= 0 && xin < (int) imIn->xsize) { - xmax = x+1; + if (xin >= 0 && xin < (int)imIn->xsize) { + xmax = x + 1; if (x < xmin) { xmin = x; } @@ -885,21 +898,21 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, xo += a[0]; } -#define AFFINE_SCALE(pixel, image)\ - for (y = y0; y < y1; y++) {\ - int yi = COORD(yo);\ - pixel *in, *out;\ - out = imOut->image[y];\ - if (fill && x1 > x0) {\ - memset(out+x0, 0, (x1-x0)*sizeof(pixel));\ - }\ - if (yi >= 0 && yi < imIn->ysize) {\ - in = imIn->image[yi];\ - for (x = xmin; x < xmax; x++) {\ - out[x] = in[xintab[x]];\ - }\ - }\ - yo += a[4];\ +#define AFFINE_SCALE(pixel, image) \ + for (y = y0; y < y1; y++) { \ + int yi = COORD(yo); \ + pixel *in, *out; \ + out = imOut->image[y]; \ + if (fill && x1 > x0) { \ + memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \ + } \ + if (yi >= 0 && yi < imIn->ysize) { \ + in = imIn->image[yi]; \ + for (x = xmin; x < xmax; x++) { \ + out[x] = in[xintab[x]]; \ + } \ + } \ + yo += a[4]; \ } ImagingSectionEnter(&cookie); @@ -920,17 +933,23 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, } static inline int -check_fixed(double a[6], int x, int y) -{ - return (fabs(x*a[0] + y*a[1] + a[2]) < 32768.0 && - fabs(x*a[3] + y*a[4] + a[5]) < 32768.0); +check_fixed(double a[6], int x, int y) { + return ( + fabs(x * a[0] + y * a[1] + a[2]) < 32768.0 && + fabs(x * a[3] + y * a[4] + a[5]) < 32768.0); } static inline Imaging -affine_fixed(Imaging imOut, Imaging imIn, - int x0, int y0, int x1, int y1, - double a[6], int filterid, int fill) -{ +affine_fixed( + Imaging imOut, + Imaging imIn, + int x0, + int y0, + int x1, + int y1, + double a[6], + int filterid, + int fill) { /* affine transform, nearest neighbour resampling, fixed point arithmetics */ @@ -943,41 +962,43 @@ affine_fixed(Imaging imOut, Imaging imIn, ImagingCopyPalette(imOut, imIn); - xsize = (int) imIn->xsize; - ysize = (int) imIn->ysize; + xsize = (int)imIn->xsize; + ysize = (int)imIn->ysize; /* use 16.16 fixed point arithmetics */ #define FIX(v) FLOOR((v)*65536.0 + 0.5) - a0 = FIX(a[0]); a1 = FIX(a[1]); - a3 = FIX(a[3]); a4 = FIX(a[4]); + a0 = FIX(a[0]); + a1 = FIX(a[1]); + a3 = FIX(a[3]); + a4 = FIX(a[4]); a2 = FIX(a[2] + a[0] * 0.5 + a[1] * 0.5); a5 = FIX(a[5] + a[3] * 0.5 + a[4] * 0.5); #undef FIX -#define AFFINE_TRANSFORM_FIXED(pixel, image)\ - for (y = y0; y < y1; y++) {\ - pixel *out;\ - xx = a2;\ - yy = a5;\ - out = imOut->image[y];\ - if (fill && x1 > x0) {\ - memset(out+x0, 0, (x1-x0)*sizeof(pixel));\ - }\ - for (x = x0; x < x1; x++, out++) {\ - xin = xx >> 16;\ - if (xin >= 0 && xin < xsize) {\ - yin = yy >> 16;\ - if (yin >= 0 && yin < ysize) {\ - *out = imIn->image[yin][xin];\ - }\ - }\ - xx += a0;\ - yy += a3;\ - }\ - a2 += a1;\ - a5 += a4;\ +#define AFFINE_TRANSFORM_FIXED(pixel, image) \ + for (y = y0; y < y1; y++) { \ + pixel *out; \ + xx = a2; \ + yy = a5; \ + out = imOut->image[y]; \ + if (fill && x1 > x0) { \ + memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \ + } \ + for (x = x0; x < x1; x++, out++) { \ + xin = xx >> 16; \ + if (xin >= 0 && xin < xsize) { \ + yin = yy >> 16; \ + if (yin >= 0 && yin < ysize) { \ + *out = imIn->image[yin][xin]; \ + } \ + } \ + xx += a0; \ + yy += a3; \ + } \ + a2 += a1; \ + a5 += a4; \ } ImagingSectionEnter(&cookie); @@ -996,10 +1017,16 @@ affine_fixed(Imaging imOut, Imaging imIn, } Imaging -ImagingTransformAffine(Imaging imOut, Imaging imIn, - int x0, int y0, int x1, int y1, - double a[6], int filterid, int fill) -{ +ImagingTransformAffine( + Imaging imOut, + Imaging imIn, + int x0, + int y0, + int x1, + int y1, + double a[6], + int filterid, + int fill) { /* affine transform, nearest neighbour resampling, floating point arithmetics*/ @@ -1012,10 +1039,7 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, if (filterid || imIn->type == IMAGING_TYPE_SPECIAL) { return ImagingGenericTransform( - imOut, imIn, - x0, y0, x1, y1, - affine_transform, a, - filterid, fill); + imOut, imIn, x0, y0, x1, y1, affine_transform, a, filterid, fill); } if (a[1] == 0 && a[3] == 0) { @@ -1024,7 +1048,7 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, } if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (x0 < 0) { @@ -1043,8 +1067,8 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, /* translate all four corners to check if they are within the range that can be represented by the fixed point arithmetics */ - if (check_fixed(a, 0, 0) && check_fixed(a, x1-x0, y1-y0) && - check_fixed(a, 0, y1-y0) && check_fixed(a, x1-x0, 0)) { + if (check_fixed(a, 0, 0) && check_fixed(a, x1 - x0, y1 - y0) && + check_fixed(a, 0, y1 - y0) && check_fixed(a, x1 - x0, 0)) { return affine_fixed(imOut, imIn, x0, y0, x1, y1, a, filterid, fill); } @@ -1054,34 +1078,34 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, ImagingCopyPalette(imOut, imIn); - xsize = (int) imIn->xsize; - ysize = (int) imIn->ysize; + xsize = (int)imIn->xsize; + ysize = (int)imIn->ysize; xo = a[2] + a[1] * 0.5 + a[0] * 0.5; yo = a[5] + a[4] * 0.5 + a[3] * 0.5; -#define AFFINE_TRANSFORM(pixel, image)\ - for (y = y0; y < y1; y++) {\ - pixel *out;\ - xx = xo;\ - yy = yo;\ - out = imOut->image[y];\ - if (fill && x1 > x0) {\ - memset(out+x0, 0, (x1-x0)*sizeof(pixel));\ - }\ - for (x = x0; x < x1; x++, out++) {\ - xin = COORD(xx);\ - if (xin >= 0 && xin < xsize) {\ - yin = COORD(yy);\ - if (yin >= 0 && yin < ysize) {\ - *out = imIn->image[yin][xin];\ - }\ - }\ - xx += a[0];\ - yy += a[3];\ - }\ - xo += a[1];\ - yo += a[4];\ +#define AFFINE_TRANSFORM(pixel, image) \ + for (y = y0; y < y1; y++) { \ + pixel *out; \ + xx = xo; \ + yy = yo; \ + out = imOut->image[y]; \ + if (fill && x1 > x0) { \ + memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \ + } \ + for (x = x0; x < x1; x++, out++) { \ + xin = COORD(xx); \ + if (xin >= 0 && xin < xsize) { \ + yin = COORD(yy); \ + if (yin >= 0 && yin < ysize) { \ + *out = imIn->image[yin][xin]; \ + } \ + } \ + xx += a[0]; \ + yy += a[3]; \ + } \ + xo += a[1]; \ + yo += a[4]; \ } ImagingSectionEnter(&cookie); @@ -1100,29 +1124,34 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, } Imaging -ImagingTransform(Imaging imOut, Imaging imIn, int method, - int x0, int y0, int x1, int y1, - double a[8], int filterid, int fill) -{ +ImagingTransform( + Imaging imOut, + Imaging imIn, + int method, + int x0, + int y0, + int x1, + int y1, + double a[8], + int filterid, + int fill) { ImagingTransformMap transform; - switch(method) { - case IMAGING_TRANSFORM_AFFINE: - return ImagingTransformAffine( - imOut, imIn, x0, y0, x1, y1, a, filterid, fill); - break; - case IMAGING_TRANSFORM_PERSPECTIVE: - transform = perspective_transform; - break; - case IMAGING_TRANSFORM_QUAD: - transform = quad_transform; - break; - default: - return (Imaging) ImagingError_ValueError("bad transform method"); + switch (method) { + case IMAGING_TRANSFORM_AFFINE: + return ImagingTransformAffine( + imOut, imIn, x0, y0, x1, y1, a, filterid, fill); + break; + case IMAGING_TRANSFORM_PERSPECTIVE: + transform = perspective_transform; + break; + case IMAGING_TRANSFORM_QUAD: + transform = quad_transform; + break; + default: + return (Imaging)ImagingError_ValueError("bad transform method"); } return ImagingGenericTransform( - imOut, imIn, - x0, y0, x1, y1, - transform, a, filterid, fill); + imOut, imIn, x0, y0, x1, y1, transform, a, filterid, fill); } diff --git a/src/libImaging/GetBBox.c b/src/libImaging/GetBBox.c index 8db78c2e2..e73153600 100644 --- a/src/libImaging/GetBBox.c +++ b/src/libImaging/GetBBox.c @@ -16,13 +16,10 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" - int -ImagingGetBBox(Imaging im, int bbox[4]) -{ +ImagingGetBBox(Imaging im, int bbox[4]) { /* Get the bounding box for any non-zero data in the image.*/ int x, y; @@ -33,26 +30,26 @@ ImagingGetBBox(Imaging im, int bbox[4]) bbox[1] = -1; bbox[2] = bbox[3] = 0; -#define GETBBOX(image, mask)\ - for (y = 0; y < im->ysize; y++) {\ - has_data = 0;\ - for (x = 0; x < im->xsize; x++) {\ - if (im->image[y][x] & mask) {\ - has_data = 1;\ - if (x < bbox[0]) {\ - bbox[0] = x;\ - }\ - if (x >= bbox[2]) {\ - bbox[2] = x+1;\ - }\ - }\ - }\ - if (has_data) {\ - if (bbox[1] < 0) {\ - bbox[1] = y;\ - }\ - bbox[3] = y+1;\ - }\ +#define GETBBOX(image, mask) \ + for (y = 0; y < im->ysize; y++) { \ + has_data = 0; \ + for (x = 0; x < im->xsize; x++) { \ + if (im->image[y][x] & mask) { \ + has_data = 1; \ + if (x < bbox[0]) { \ + bbox[0] = x; \ + } \ + if (x >= bbox[2]) { \ + bbox[2] = x + 1; \ + } \ + } \ + } \ + if (has_data) { \ + if (bbox[1] < 0) { \ + bbox[1] = y; \ + } \ + bbox[3] = y + 1; \ + } \ } if (im->image8) { @@ -60,16 +57,15 @@ ImagingGetBBox(Imaging im, int bbox[4]) } else { INT32 mask = 0xffffffff; if (im->bands == 3) { - ((UINT8*) &mask)[3] = 0; - } else if (strcmp(im->mode, "RGBa") == 0 || - strcmp(im->mode, "RGBA") == 0 || - strcmp(im->mode, "La") == 0 || - strcmp(im->mode, "LA") == 0 || - strcmp(im->mode, "PA") == 0) { + ((UINT8 *)&mask)[3] = 0; + } else if ( + strcmp(im->mode, "RGBa") == 0 || strcmp(im->mode, "RGBA") == 0 || + strcmp(im->mode, "La") == 0 || strcmp(im->mode, "LA") == 0 || + strcmp(im->mode, "PA") == 0) { #ifdef WORDS_BIGENDIAN - mask = 0x000000ff; + mask = 0x000000ff; #else - mask = 0xff000000; + mask = 0xff000000; #endif } GETBBOX(image32, mask); @@ -83,10 +79,8 @@ ImagingGetBBox(Imaging im, int bbox[4]) return 1; /* ok */ } - int -ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj) -{ +ImagingGetProjection(Imaging im, UINT8 *xproj, UINT8 *yproj) { /* Get projection arrays for non-zero data in the image.*/ int x, y; @@ -96,26 +90,26 @@ ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj) memset(xproj, 0, im->xsize); memset(yproj, 0, im->ysize); - #define GETPROJ(image, mask)\ - for (y = 0; y < im->ysize; y++) {\ - has_data = 0;\ - for (x = 0; x < im->xsize; x++) {\ - if (im->image[y][x] & mask) {\ - has_data = 1;\ - xproj[x] = 1;\ - }\ - }\ - if (has_data) {\ - yproj[y] = 1;\ - }\ - } +#define GETPROJ(image, mask) \ + for (y = 0; y < im->ysize; y++) { \ + has_data = 0; \ + for (x = 0; x < im->xsize; x++) { \ + if (im->image[y][x] & mask) { \ + has_data = 1; \ + xproj[x] = 1; \ + } \ + } \ + if (has_data) { \ + yproj[y] = 1; \ + } \ + } if (im->image8) { GETPROJ(image8, 0xff); } else { INT32 mask = 0xffffffff; if (im->bands == 3) { - ((UINT8*) &mask)[3] = 0; + ((UINT8 *)&mask)[3] = 0; } GETPROJ(image32, mask); } @@ -123,16 +117,14 @@ ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj) return 1; /* ok */ } - int -ImagingGetExtrema(Imaging im, void *extrema) -{ +ImagingGetExtrema(Imaging im, void *extrema) { int x, y; INT32 imin, imax; FLOAT32 fmin, fmax; if (im->bands != 1) { - (void) ImagingError_ModeError(); + (void)ImagingError_ModeError(); return -1; /* mismatch */ } @@ -141,111 +133,109 @@ ImagingGetExtrema(Imaging im, void *extrema) } switch (im->type) { - case IMAGING_TYPE_UINT8: - imin = imax = im->image8[0][0]; - for (y = 0; y < im->ysize; y++) { - UINT8* in = im->image8[y]; - for (x = 0; x < im->xsize; x++) { - if (imin > in[x]) { - imin = in[x]; - } else if (imax < in[x]) { - imax = in[x]; + case IMAGING_TYPE_UINT8: + imin = imax = im->image8[0][0]; + for (y = 0; y < im->ysize; y++) { + UINT8 *in = im->image8[y]; + for (x = 0; x < im->xsize; x++) { + if (imin > in[x]) { + imin = in[x]; + } else if (imax < in[x]) { + imax = in[x]; + } } } - } - ((UINT8*) extrema)[0] = (UINT8) imin; - ((UINT8*) extrema)[1] = (UINT8) imax; - break; - case IMAGING_TYPE_INT32: - imin = imax = im->image32[0][0]; - for (y = 0; y < im->ysize; y++) { - INT32* in = im->image32[y]; - for (x = 0; x < im->xsize; x++) { - if (imin > in[x]) { - imin = in[x]; - } else if (imax < in[x]) { - imax = in[x]; + ((UINT8 *)extrema)[0] = (UINT8)imin; + ((UINT8 *)extrema)[1] = (UINT8)imax; + break; + case IMAGING_TYPE_INT32: + imin = imax = im->image32[0][0]; + for (y = 0; y < im->ysize; y++) { + INT32 *in = im->image32[y]; + for (x = 0; x < im->xsize; x++) { + if (imin > in[x]) { + imin = in[x]; + } else if (imax < in[x]) { + imax = in[x]; + } } } - } - memcpy(extrema, &imin, sizeof(imin)); - memcpy(((char*)extrema) + sizeof(imin), &imax, sizeof(imax)); - break; - case IMAGING_TYPE_FLOAT32: - fmin = fmax = ((FLOAT32*) im->image32[0])[0]; - for (y = 0; y < im->ysize; y++) { - FLOAT32* in = (FLOAT32*) im->image32[y]; - for (x = 0; x < im->xsize; x++) { - if (fmin > in[x]) { - fmin = in[x]; - } else if (fmax < in[x]) { - fmax = in[x]; + memcpy(extrema, &imin, sizeof(imin)); + memcpy(((char *)extrema) + sizeof(imin), &imax, sizeof(imax)); + break; + case IMAGING_TYPE_FLOAT32: + fmin = fmax = ((FLOAT32 *)im->image32[0])[0]; + for (y = 0; y < im->ysize; y++) { + FLOAT32 *in = (FLOAT32 *)im->image32[y]; + for (x = 0; x < im->xsize; x++) { + if (fmin > in[x]) { + fmin = in[x]; + } else if (fmax < in[x]) { + fmax = in[x]; + } } } - } - memcpy(extrema, &fmin, sizeof(fmin)); - memcpy(((char*)extrema) + sizeof(fmin), &fmax, sizeof(fmax)); - break; - case IMAGING_TYPE_SPECIAL: - if (strcmp(im->mode, "I;16") == 0) { - UINT16 v; - UINT8* pixel = *im->image8; + memcpy(extrema, &fmin, sizeof(fmin)); + memcpy(((char *)extrema) + sizeof(fmin), &fmax, sizeof(fmax)); + break; + case IMAGING_TYPE_SPECIAL: + if (strcmp(im->mode, "I;16") == 0) { + UINT16 v; + UINT8 *pixel = *im->image8; #ifdef WORDS_BIGENDIAN - v = pixel[0] + (pixel[1] << 8); + v = pixel[0] + (pixel[1] << 8); #else - memcpy(&v, pixel, sizeof(v)); + memcpy(&v, pixel, sizeof(v)); #endif - imin = imax = v; - for (y = 0; y < im->ysize; y++) { - for (x = 0; x < im->xsize; x++) { - pixel = (UINT8*)im->image[y] + x * sizeof(v); + imin = imax = v; + for (y = 0; y < im->ysize; y++) { + for (x = 0; x < im->xsize; x++) { + pixel = (UINT8 *)im->image[y] + x * sizeof(v); #ifdef WORDS_BIGENDIAN - v = pixel[0] + (pixel[1] << 8); + v = pixel[0] + (pixel[1] << 8); #else - memcpy(&v, pixel, sizeof(v)); + memcpy(&v, pixel, sizeof(v)); #endif - if (imin > v) { - imin = v; - } else if (imax < v) { - imax = v; - } - } - } - v = (UINT16) imin; - memcpy(extrema, &v, sizeof(v)); - v = (UINT16) imax; - memcpy(((char*)extrema) + sizeof(v), &v, sizeof(v)); - break; - } - /* FALL THROUGH */ - default: - (void) ImagingError_ModeError(); - return -1; + if (imin > v) { + imin = v; + } else if (imax < v) { + imax = v; + } + } + } + v = (UINT16)imin; + memcpy(extrema, &v, sizeof(v)); + v = (UINT16)imax; + memcpy(((char *)extrema) + sizeof(v), &v, sizeof(v)); + break; + } + /* FALL THROUGH */ + default: + (void)ImagingError_ModeError(); + return -1; } return 1; /* ok */ } - /* static ImagingColorItem* getcolors8(Imaging im, int maxcolors, int* size);*/ -static ImagingColorItem* getcolors32(Imaging im, int maxcolors, int* size); +static ImagingColorItem * +getcolors32(Imaging im, int maxcolors, int *size); -ImagingColorItem* -ImagingGetColors(Imaging im, int maxcolors, int* size) -{ +ImagingColorItem * +ImagingGetColors(Imaging im, int maxcolors, int *size) { /* FIXME: add support for 8-bit images */ return getcolors32(im, maxcolors, size); } -static ImagingColorItem* -getcolors32(Imaging im, int maxcolors, int* size) -{ +static ImagingColorItem * +getcolors32(Imaging im, int maxcolors, int *size) { unsigned int h; unsigned int i, incr; int colors; INT32 pixel_mask; int x, y; - ImagingColorItem* table; - ImagingColorItem* v; + ImagingColorItem *table; + ImagingColorItem *v; unsigned int code_size; unsigned int code_poly; @@ -256,19 +246,19 @@ getcolors32(Imaging im, int maxcolors, int* size) Python's Unicode property database (written by yours truly) /F */ static int SIZES[] = { - 4,3, 8,3, 16,3, 32,5, 64,3, 128,3, 256,29, 512,17, 1024,9, 2048,5, - 4096,83, 8192,27, 16384,43, 32768,3, 65536,45, 131072,9, 262144,39, - 524288,39, 1048576,9, 2097152,5, 4194304,3, 8388608,33, 16777216,27, - 33554432,9, 67108864,71, 134217728,39, 268435456,9, 536870912,5, - 1073741824,83, 0 - }; + 4, 3, 8, 3, 16, 3, 32, 5, 64, 3, + 128, 3, 256, 29, 512, 17, 1024, 9, 2048, 5, + 4096, 83, 8192, 27, 16384, 43, 32768, 3, 65536, 45, + 131072, 9, 262144, 39, 524288, 39, 1048576, 9, 2097152, 5, + 4194304, 3, 8388608, 33, 16777216, 27, 33554432, 9, 67108864, 71, + 134217728, 39, 268435456, 9, 536870912, 5, 1073741824, 83, 0}; code_size = code_poly = code_mask = 0; for (i = 0; SIZES[i]; i += 2) { if (SIZES[i] > maxcolors) { code_size = SIZES[i]; - code_poly = SIZES[i+1]; + code_poly = SIZES[i + 1]; code_mask = code_size - 1; break; } @@ -292,13 +282,13 @@ getcolors32(Imaging im, int maxcolors, int* size) pixel_mask = 0xffffffff; if (im->bands == 3) { - ((UINT8*) &pixel_mask)[3] = 0; + ((UINT8 *)&pixel_mask)[3] = 0; } colors = 0; for (y = 0; y < im->ysize; y++) { - INT32* p = im->image32[y]; + INT32 *p = im->image32[y]; for (x = 0; x < im->xsize; x++) { INT32 pixel = p[x] & pixel_mask; h = (pixel); /* null hashing */ @@ -309,7 +299,8 @@ getcolors32(Imaging im, int maxcolors, int* size) if (colors++ == maxcolors) { goto overflow; } - v->x = x; v->y = y; + v->x = x; + v->y = y; v->pixel = pixel; v->count = 1; continue; @@ -329,7 +320,8 @@ getcolors32(Imaging im, int maxcolors, int* size) if (colors++ == maxcolors) { goto overflow; } - v->x = x; v->y = y; + v->x = x; + v->y = y; v->pixel = pixel; v->count = 1; break; @@ -348,7 +340,7 @@ getcolors32(Imaging im, int maxcolors, int* size) overflow: /* pack the table */ - for (x = y = 0; x < (int) code_size; x++) + for (x = y = 0; x < (int)code_size; x++) if (table[x].count) { if (x != y) { table[y] = table[x]; diff --git a/src/libImaging/Gif.h b/src/libImaging/Gif.h index bb118396c..91132e2e6 100644 --- a/src/libImaging/Gif.h +++ b/src/libImaging/Gif.h @@ -7,7 +7,6 @@ * Copyright (c) Fredrik Lundh 1995-96. */ - /* Max size for a LZW code word. */ #define GIFBITS 12 @@ -15,9 +14,7 @@ #define GIFTABLE (1< @@ -29,48 +28,44 @@ #include "Gif.h" - -#define NEWLINE(state, context) {\ - state->x = 0;\ - state->y += context->step;\ - while (state->y >= state->ysize)\ - switch (context->interlace) {\ - case 1:\ - context->repeat = state->y = 4;\ - context->interlace = 2;\ - break;\ - case 2:\ - context->step = 4;\ - context->repeat = state->y = 2;\ - context->interlace = 3;\ - break;\ - case 3:\ - context->step = 2;\ - context->repeat = state->y = 1;\ - context->interlace = 0;\ - break;\ - default:\ - return -1;\ - }\ - if (state->y < state->ysize) {\ - out = im->image8[state->y + state->yoff] + state->xoff;\ - }\ -} - +#define NEWLINE(state, context) \ + { \ + state->x = 0; \ + state->y += context->step; \ + while (state->y >= state->ysize) switch (context->interlace) { \ + case 1: \ + context->repeat = state->y = 4; \ + context->interlace = 2; \ + break; \ + case 2: \ + context->step = 4; \ + context->repeat = state->y = 2; \ + context->interlace = 3; \ + break; \ + case 3: \ + context->step = 2; \ + context->repeat = state->y = 1; \ + context->interlace = 0; \ + break; \ + default: \ + return -1; \ + } \ + if (state->y < state->ysize) { \ + out = im->image8[state->y + state->yoff] + state->xoff; \ + } \ + } int -ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes) -{ - UINT8* p; - UINT8* out; +ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes) { + UINT8 *p; + UINT8 *out; int c, i; int thiscode; - GIFDECODERSTATE *context = (GIFDECODERSTATE*) state->context; + GIFDECODERSTATE *context = (GIFDECODERSTATE *)state->context; UINT8 *ptr = buffer; if (!state->state) { - /* Initialise state */ if (context->bits < 0 || context->bits > 12) { state->errcode = IMAGING_CODEC_CONFIG; @@ -97,9 +92,7 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t out = im->image8[state->y + state->yoff] + state->xoff + state->x; for (;;) { - if (state->state == 1) { - /* First free entry in table */ context->next = context->clear + 2; @@ -115,7 +108,6 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t } if (context->bufferindex < GIFBUFFER) { - /* Return whole buffer in one chunk */ i = GIFBUFFER - context->bufferindex; p = &context->buffer[context->bufferindex]; @@ -123,24 +115,21 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t context->bufferindex = GIFBUFFER; } else { - /* Get current symbol */ while (context->bitcount < context->codesize) { - if (context->blocksize > 0) { - /* Read next byte */ - c = *ptr++; bytes--; + c = *ptr++; + bytes--; context->blocksize--; /* New bits are shifted in from from the left. */ - context->bitbuffer |= (INT32) c << context->bitcount; + context->bitbuffer |= (INT32)c << context->bitcount; context->bitcount += 8; } else { - /* New GIF block */ /* We don't start decoding unless we have a full block */ @@ -148,19 +137,19 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t return ptr - buffer; } c = *ptr; - if (bytes < c+1) { + if (bytes < c + 1) { return ptr - buffer; } context->blocksize = c; - ptr++; bytes--; - + ptr++; + bytes--; } } /* Extract current symbol from bit buffer. */ - c = (int) context->bitbuffer & context->codemask; + c = (int)context->bitbuffer & context->codemask; /* Adjust buffer */ context->bitbuffer >>= context->codesize; @@ -185,7 +174,6 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t p = &context->lastdata; if (state->state == 2) { - /* First valid symbol after clear; use as is */ if (c > context->clear) { state->errcode = IMAGING_CODEC_BROKEN; @@ -196,7 +184,6 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t state->state = 3; } else { - thiscode = c; if (c > context->next) { @@ -205,7 +192,6 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t } if (c == context->next) { - /* c == next is allowed. not sure why. */ if (context->bufferindex <= 0) { @@ -213,15 +199,12 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t return -1; } - context->buffer[--context->bufferindex] = - context->lastdata; + context->buffer[--context->bufferindex] = context->lastdata; c = context->lastcode; - } while (c >= context->clear) { - /* Copy data string to buffer (beginning from right) */ if (context->bufferindex <= 0 || c >= GIFTABLE) { @@ -229,8 +212,7 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t return -1; } - context->buffer[--context->bufferindex] = - context->data[c]; + context->buffer[--context->bufferindex] = context->data[c]; c = context->link[c]; } @@ -238,26 +220,22 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t context->lastdata = c; if (context->next < GIFTABLE) { - /* We'll only add this symbol if we have room - for it (take advise, Netscape!) */ + for it (take the advice, Netscape!) */ context->data[context->next] = c; context->link[context->next] = context->lastcode; if (context->next == context->codemask && - context->codesize < GIFBITS) { - + context->codesize < GIFBITS) { /* Expand code size */ context->codesize++; context->codemask = (1 << context->codesize) - 1; } context->next++; - } context->lastcode = thiscode; - } } @@ -270,29 +248,33 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t /* To squeeze some extra pixels out of this loop, we test for some common cases and handle them separately. */ - /* FIXME: should we handle the transparency index in here??? */ - - if (i == 1) { - if (state->x < state->xsize-1) { - /* Single pixel, not at the end of the line. */ - *out++ = p[0]; - state->x++; + /* If we have transparency, we need to use the regular loop. */ + if (context->transparency == -1) { + if (i == 1) { + if (state->x < state->xsize - 1) { + /* Single pixel, not at the end of the line. */ + *out++ = p[0]; + state->x++; + continue; + } + } else if (state->x + i <= state->xsize) { + /* This string fits into current line. */ + memcpy(out, p, i); + out += i; + state->x += i; + if (state->x == state->xsize) { + NEWLINE(state, context); + } continue; } - } else if (state->x + i <= state->xsize) { - /* This string fits into current line. */ - memcpy(out, p, i); - out += i; - state->x += i; - if (state->x == state->xsize) { - NEWLINE(state, context); - } - continue; } /* No shortcut, copy pixel by pixel */ for (c = 0; c < i; c++) { - *out++ = p[c]; + if (p[c] != context->transparency) { + *out = p[c]; + } + out++; if (++state->x >= state->xsize) { NEWLINE(state, context); } diff --git a/src/libImaging/GifEncode.c b/src/libImaging/GifEncode.c index e9c6c3149..f23245405 100644 --- a/src/libImaging/GifEncode.c +++ b/src/libImaging/GifEncode.c @@ -10,6 +10,7 @@ * 98-07-09 fl added interlace write support * 99-02-07 fl rewritten, now uses a run-length encoding strategy * 99-02-08 fl improved run-length encoding for long runs + * 2020-12-12 rdg Reworked for LZW compression. * * Copyright (c) Secret Labs AB 1997-99. * Copyright (c) Fredrik Lundh 1997. @@ -21,138 +22,206 @@ #include "Gif.h" -/* codes from 0 to 255 are literals */ -#define CLEAR_CODE 256 -#define EOF_CODE 257 -#define FIRST_CODE 258 -#define LAST_CODE 511 +enum { INIT, ENCODE, FINISH }; -enum { INIT, ENCODE, ENCODE_EOF, FLUSH, EXIT }; +/* GIF LZW encoder by Raymond Gardner. */ +/* Released here under PIL license. */ -/* to make things a little less complicated, we use a simple output - queue to hold completed blocks. the following inlined function - adds a byte to the current block. it allocates a new block if - necessary. */ +/* This LZW encoder conforms to the GIF LZW format specified in the original + * Compuserve GIF 87a and GIF 89a specifications (see e.g. + * https://www.w3.org/Graphics/GIF/spec-gif87.txt Appendix C and + * https://www.w3.org/Graphics/GIF/spec-gif89a.txt Appendix F). + */ -static inline int -emit(GIFENCODERSTATE *context, int byte) -{ - /* write a byte to the output buffer */ +/* Return values */ +#define GLZW_OK 0 +#define GLZW_NO_INPUT_AVAIL 1 +#define GLZW_NO_OUTPUT_AVAIL 2 +#define GLZW_INTERNAL_ERROR 3 - if (!context->block || context->block->size == 255) { - GIFENCODERBLOCK* block; +#define CODE_LIMIT 4096 - /* no room in the current block (or no current block); - allocate a new one */ +/* Values of entry_state */ +enum { LZW_INITIAL, LZW_TRY_IN1, LZW_TRY_IN2, LZW_TRY_OUT1, LZW_TRY_OUT2, + LZW_FINISHED }; - /* add current block to end of flush queue */ - if (context->block) { - block = context->flush; - while (block && block->next) { - block = block->next; +/* Values of control_state */ +enum { PUT_HEAD, PUT_INIT_CLEAR, PUT_CLEAR, PUT_LAST_HEAD, PUT_END }; + +static void glzwe_reset(GIFENCODERSTATE *st) { + st->next_code = st->end_code + 1; + st->max_code = 2 * st->clear_code - 1; + st->code_width = st->bits + 1; + memset(st->codes, 0, sizeof(st->codes)); +} + +static void glzwe_init(GIFENCODERSTATE *st) { + st->clear_code = 1 << st->bits; + st->end_code = st->clear_code + 1; + glzwe_reset(st); + st->entry_state = LZW_INITIAL; + st->buf_bits_left = 8; + st->code_buffer = 0; +} + +static int glzwe(GIFENCODERSTATE *st, const UINT8 *in_ptr, UINT8 *out_ptr, + UINT32 *in_avail, UINT32 *out_avail, + UINT32 end_of_data) { + switch (st->entry_state) { + + case LZW_TRY_IN1: +get_first_byte: + if (!*in_avail) { + if (end_of_data) { + goto end_of_data; } - if (block) { - block->next = context->block; + st->entry_state = LZW_TRY_IN1; + return GLZW_NO_INPUT_AVAIL; + } + st->head = *in_ptr++; + (*in_avail)--; + + case LZW_TRY_IN2: +encode_loop: + if (!*in_avail) { + if (end_of_data) { + st->code = st->head; + st->put_state = PUT_LAST_HEAD; + goto put_code; + } + st->entry_state = LZW_TRY_IN2; + return GLZW_NO_INPUT_AVAIL; + } + st->tail = *in_ptr++; + (*in_avail)--; + + /* Knuth TAOCP vol 3 sec. 6.4 algorithm D. */ + /* Hash found experimentally to be pretty good. */ + /* This works ONLY with TABLE_SIZE a power of 2. */ + st->probe = ((st->head ^ (st->tail << 6)) * 31) & (TABLE_SIZE - 1); + while (st->codes[st->probe]) { + if ((st->codes[st->probe] & 0xFFFFF) == + ((st->head << 8) | st->tail)) { + st->head = st->codes[st->probe] >> 20; + goto encode_loop; } else { - context->flush = context->block; + /* Reprobe decrement must be nonzero and relatively prime to table + * size. So, any odd positive number for power-of-2 size. */ + if ((st->probe -= ((st->tail << 2) | 1)) < 0) { + st->probe += TABLE_SIZE; + } } } - - /* get a new block */ - if (context->free) { - block = context->free; - context->free = NULL; + /* Key not found, probe is at empty slot. */ + st->code = st->head; + st->put_state = PUT_HEAD; + goto put_code; +insert_code_or_clear: /* jump here after put_code */ + if (st->next_code < CODE_LIMIT) { + st->codes[st->probe] = (st->next_code << 20) | + (st->head << 8) | st->tail; + if (st->next_code > st->max_code) { + st->max_code = st->max_code * 2 + 1; + st->code_width++; + } + st->next_code++; } else { - /* malloc check ok, small constant allocation */ - block = malloc(sizeof(GIFENCODERBLOCK)); - if (!block) { - return 0; + st->code = st->clear_code; + st->put_state = PUT_CLEAR; + goto put_code; +reset_after_clear: /* jump here after put_code */ + glzwe_reset(st); + } + st->head = st->tail; + goto encode_loop; + + case LZW_INITIAL: + glzwe_reset(st); + st->code = st->clear_code; + st->put_state = PUT_INIT_CLEAR; +put_code: + st->code_bits_left = st->code_width; +check_buf_bits: + if (!st->buf_bits_left) { /* out buffer full */ + + case LZW_TRY_OUT1: + if (!*out_avail) { + st->entry_state = LZW_TRY_OUT1; + return GLZW_NO_OUTPUT_AVAIL; } + *out_ptr++ = st->code_buffer; + (*out_avail)--; + st->code_buffer = 0; + st->buf_bits_left = 8; + } + /* code bits to pack */ + UINT32 n = st->buf_bits_left < st->code_bits_left + ? st->buf_bits_left : st->code_bits_left; + st->code_buffer |= + (st->code & ((1 << n) - 1)) << (8 - st->buf_bits_left); + st->code >>= n; + st->buf_bits_left -= n; + st->code_bits_left -= n; + if (st->code_bits_left) { + goto check_buf_bits; + } + switch (st->put_state) { + case PUT_INIT_CLEAR: + goto get_first_byte; + case PUT_HEAD: + goto insert_code_or_clear; + case PUT_CLEAR: + goto reset_after_clear; + case PUT_LAST_HEAD: + goto end_of_data; + case PUT_END: + goto flush_code_buffer; + default: + return GLZW_INTERNAL_ERROR; } - block->size = 0; - block->next = NULL; +end_of_data: + st->code = st->end_code; + st->put_state = PUT_END; + goto put_code; +flush_code_buffer: /* jump here after put_code */ + if (st->buf_bits_left < 8) { - context->block = block; + case LZW_TRY_OUT2: + if (!*out_avail) { + st->entry_state = LZW_TRY_OUT2; + return GLZW_NO_OUTPUT_AVAIL; + } + *out_ptr++ = st->code_buffer; + (*out_avail)--; + } + st->entry_state = LZW_FINISHED; + return GLZW_OK; + case LZW_FINISHED: + return GLZW_OK; + + default: + return GLZW_INTERNAL_ERROR; } - - /* write new byte to block */ - context->block->data[context->block->size++] = byte; - - return 1; -} - -/* write a code word to the current block. this is a macro to make - sure it's inlined on all platforms */ - -#define EMIT(code) {\ - context->bitbuffer |= ((INT32) (code)) << context->bitcount;\ - context->bitcount += 9;\ - while (context->bitcount >= 8) {\ - if (!emit(context, (UINT8) context->bitbuffer)) {\ - state->errcode = IMAGING_CODEC_MEMORY;\ - return 0;\ - }\ - context->bitbuffer >>= 8;\ - context->bitcount -= 8;\ - }\ -} - -/* write a run. we use a combination of literals and combinations of - literals. this can give quite decent compression for images with - long stretches of identical pixels. but remember: if you want - really good compression, use another file format. */ - -#define EMIT_RUN(label) {\ -label:\ - while (context->count > 0) {\ - int run = 2;\ - EMIT(context->last);\ - context->count--;\ - if (state->count++ == LAST_CODE) {\ - EMIT(CLEAR_CODE);\ - state->count = FIRST_CODE;\ - goto label;\ - }\ - while (context->count >= run) {\ - EMIT(state->count - 1);\ - context->count -= run;\ - run++;\ - if (state->count++ == LAST_CODE) {\ - EMIT(CLEAR_CODE);\ - state->count = FIRST_CODE;\ - goto label;\ - }\ - }\ - if (context->count > 1) {\ - EMIT(state->count - 1 - (run - context->count));\ - context->count = 0;\ - if (state->count++ == LAST_CODE) {\ - EMIT(CLEAR_CODE);\ - state->count = FIRST_CODE;\ - }\ - break;\ - }\ - }\ } +/* -END- GIF LZW encoder. */ int -ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) -{ +ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) { UINT8* ptr; - int this; - - GIFENCODERBLOCK* block; + UINT8* sub_block_ptr; + UINT8* sub_block_limit; + UINT8* buf_limit; GIFENCODERSTATE *context = (GIFENCODERSTATE*) state->context; + int r; - if (!state->state) { + UINT32 in_avail, in_used; + UINT32 out_avail, out_used; - /* place a clear code in the output buffer */ - context->bitbuffer = CLEAR_CODE; - context->bitcount = 9; - - state->count = FIRST_CODE; + if (state->state == INIT) { + state->state = ENCODE; + glzwe_init(context); if (context->interlace) { context->interlace = 1; @@ -161,170 +230,132 @@ ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->step = 1; } - context->last = -1; - + /* Need at least 2 bytes for data sub-block; 5 for empty image */ + if (bytes < 5) { + state->errcode = IMAGING_CODEC_CONFIG; + return 0; + } /* sanity check */ if (state->xsize <= 0 || state->ysize <= 0) { - state->state = ENCODE_EOF; + /* Is this better than an error return? */ + /* This will handle any legal "LZW Minimum Code Size" */ + memset(buf, 0, 5); + in_avail = 0; + out_avail = 5; + r = glzwe(context, (const UINT8 *)"", buf + 1, &in_avail, &out_avail, 1); + if (r == GLZW_OK) { + r = 5 - out_avail; + if (r < 1 || r > 3) { + state->errcode = IMAGING_CODEC_BROKEN; + return 0; + } + buf[0] = r; + state->errcode = IMAGING_CODEC_END; + return r + 2; + } else { + /* Should not be possible unless something external to this + * routine messes with our state data */ + state->errcode = IMAGING_CODEC_BROKEN; + return 0; + } + } + /* Init state->x to make if() below true the first time through. */ + state->x = state->xsize; + } + + buf_limit = buf + bytes; + sub_block_limit = sub_block_ptr = ptr = buf; + + /* On entry, buf is output buffer, bytes is space available in buf. + * Loop here getting input until buf is full or image is all encoded. */ + for (;;) { + /* Set up sub-block ptr and limit. sub_block_ptr stays at beginning + * of sub-block until it is full. ptr will advance when any data is + * placed in buf. + */ + if (ptr >= sub_block_limit) { + if (buf_limit - ptr < 2) { /* Need at least 2 for data sub-block */ + return ptr - buf; + } + sub_block_ptr = ptr; + sub_block_limit = sub_block_ptr + + (256 < buf_limit - sub_block_ptr ? + 256 : buf_limit - sub_block_ptr); + *ptr++ = 0; } - } + /* Get next row of pixels. */ + /* This if() originally tested state->x==0 for the first time through. + * This no longer works, as the loop will not advance state->x if + * glzwe() does not consume any input; this would advance the row + * spuriously. Now pre-init state->x above for first time, and avoid + * entering if() when state->state is FINISH, or it will loop + * infinitely. + */ + if (state->x >= state->xsize && state->state == ENCODE) { + if (!context->interlace && state->y >= state->ysize) { + state->state = FINISH; + continue; + } - ptr = buf; + /* get another line of data */ + state->shuffle( + state->buffer, + (UINT8*) im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, state->xsize + ); + state->x = 0; - for (;;) - - switch (state->state) { - - case INIT: - case ENCODE: - - /* identify and store a run of pixels */ - - if (state->x == 0 || state->x >= state->xsize) { - - if (!context->interlace && state->y >= state->ysize) { - state->state = ENCODE_EOF; + /* step forward, according to the interlace settings */ + state->y += context->step; + while (context->interlace && state->y >= state->ysize) { + switch (context->interlace) { + case 1: + state->y = 4; + context->interlace = 2; break; - } - - if (context->flush) { - state->state = FLUSH; + case 2: + context->step = 4; + state->y = 2; + context->interlace = 3; break; - } - - /* get another line of data */ - state->shuffle( - state->buffer, - (UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->xsize - ); - - state->x = 0; - - if (state->state == INIT) { - /* preload the run-length buffer and get going */ - context->last = state->buffer[0]; - context->count = state->x = 1; - state->state = ENCODE; - } - - /* step forward, according to the interlace settings */ - state->y += context->step; - while (context->interlace && state->y >= state->ysize) - switch (context->interlace) { - case 1: - state->y = 4; - context->interlace = 2; - break; - case 2: - context->step = 4; - state->y = 2; - context->interlace = 3; - break; - case 3: - context->step = 2; - state->y = 1; - context->interlace = 0; - break; - default: - /* just make sure we don't loop forever */ - context->interlace = 0; - } - + case 3: + context->step = 2; + state->y = 1; + context->interlace = 0; + break; + default: + /* just make sure we don't loop forever */ + context->interlace = 0; } + } + } - this = state->buffer[state->x++]; + in_avail = state->xsize - state->x; /* bytes left in line */ + out_avail = sub_block_limit - ptr; /* bytes left in sub-block */ + r = glzwe(context, &state->buffer[state->x], ptr, &in_avail, + &out_avail, state->state == FINISH); + out_used = sub_block_limit - ptr - out_avail; + *sub_block_ptr += out_used; + ptr += out_used; + in_used = state->xsize - state->x - in_avail; + state->x += in_used; - if (this == context->last) { - context->count++; - } else { - EMIT_RUN(label1); - context->last = this; - context->count = 1; - } - break; - - - case ENCODE_EOF: - - /* write the final run */ - EMIT_RUN(label2); - - /* write an end of image marker */ - EMIT(EOF_CODE); - - /* empty the bit buffer */ - while (context->bitcount > 0) { - if (!emit(context, (UINT8) context->bitbuffer)) { - state->errcode = IMAGING_CODEC_MEMORY; - return 0; - } - context->bitbuffer >>= 8; - context->bitcount -= 8; - } - - /* flush the last block, and exit */ - if (context->block) { - GIFENCODERBLOCK* block; - block = context->flush; - while (block && block->next) { - block = block->next; - } - if (block) { - block->next = context->block; - } else { - context->flush = context->block; - } - context->block = NULL; - } - - state->state = EXIT; - - /* fall through... */ - - case EXIT: - case FLUSH: - - while (context->flush) { - - /* get a block from the flush queue */ - block = context->flush; - - if (block->size > 0) { - - /* make sure it fits into the output buffer */ - if (bytes < block->size+1) { - return ptr - buf; - } - - ptr[0] = block->size; - memcpy(ptr+1, block->data, block->size); - - ptr += block->size+1; - bytes -= block->size+1; - - } - - context->flush = block->next; - - if (context->free) { - free(context->free); - } - context->free = block; - - } - - if (state->state == EXIT) { - /* this was the last block! */ - if (context->free) { - free(context->free); - } - state->errcode = IMAGING_CODEC_END; - return ptr - buf; - } - - state->state = ENCODE; - break; + if (r == GLZW_OK) { + /* Should not be possible when end-of-data flag is false. */ + state->errcode = IMAGING_CODEC_END; + return ptr - buf; + } else if (r == GLZW_NO_INPUT_AVAIL) { + /* Used all the input line; get another line */ + continue; + } else if (r == GLZW_NO_OUTPUT_AVAIL) { + /* subblock is full */ + continue; + } else { + /* Should not be possible unless something external to this + * routine messes with our state data */ + state->errcode = IMAGING_CODEC_BROKEN; + return 0; + } } } diff --git a/src/libImaging/HexDecode.c b/src/libImaging/HexDecode.c index 1def8766f..bd16cdbe1 100644 --- a/src/libImaging/HexDecode.c +++ b/src/libImaging/HexDecode.c @@ -13,23 +13,22 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" -#define HEX(v) ((v >= '0' && v <= '9') ? v - '0' :\ - (v >= 'a' && v <= 'f') ? v - 'a' + 10 :\ - (v >= 'A' && v <= 'F') ? v - 'A' + 10 : -1) +#define HEX(v) \ + ((v >= '0' && v <= '9') ? v - '0' \ + : (v >= 'a' && v <= 'f') ? v - 'a' + 10 \ + : (v >= 'A' && v <= 'F') ? v - 'A' + 10 \ + : -1) int -ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ - UINT8* ptr; +ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { + UINT8 *ptr; int a, b; ptr = buf; for (;;) { - if (bytes < 2) { return ptr - buf; } @@ -38,22 +37,19 @@ ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt b = HEX(ptr[1]); if (a < 0 || b < 0) { - ptr++; bytes--; } else { - ptr += 2; bytes -= 2; - state->buffer[state->x] = (a<<4) + b; + state->buffer[state->x] = (a << 4) + b; if (++state->x >= state->bytes) { - /* Got a full line, unpack it */ - state->shuffle((UINT8*) im->image[state->y], state->buffer, - state->xsize); + state->shuffle( + (UINT8 *)im->image[state->y], state->buffer, state->xsize); state->x = 0; @@ -62,7 +58,6 @@ ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt return -1; } } - } } } diff --git a/src/libImaging/Histo.c b/src/libImaging/Histo.c index 512e57a98..c5a547a64 100644 --- a/src/libImaging/Histo.c +++ b/src/libImaging/Histo.c @@ -16,10 +16,8 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - /* HISTOGRAM */ /* -------------------------------------------------------------------- * Take a histogram of an image. Returns a histogram object containing @@ -27,8 +25,7 @@ */ void -ImagingHistogramDelete(ImagingHistogram h) -{ +ImagingHistogramDelete(ImagingHistogram h) { if (h) { if (h->histogram) { free(h->histogram); @@ -38,31 +35,29 @@ ImagingHistogramDelete(ImagingHistogram h) } ImagingHistogram -ImagingHistogramNew(Imaging im) -{ +ImagingHistogramNew(Imaging im) { ImagingHistogram h; /* Create histogram descriptor */ h = calloc(1, sizeof(struct ImagingHistogramInstance)); if (!h) { - return (ImagingHistogram) ImagingError_MemoryError(); + return (ImagingHistogram)ImagingError_MemoryError(); } - strncpy(h->mode, im->mode, IMAGING_MODE_LENGTH-1); - h->mode[IMAGING_MODE_LENGTH-1] = 0; + strncpy(h->mode, im->mode, IMAGING_MODE_LENGTH - 1); + h->mode[IMAGING_MODE_LENGTH - 1] = 0; h->bands = im->bands; h->histogram = calloc(im->pixelsize, 256 * sizeof(long)); if (!h->histogram) { free(h); - return (ImagingHistogram) ImagingError_MemoryError(); + return (ImagingHistogram)ImagingError_MemoryError(); } return h; } ImagingHistogram -ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax) -{ +ImagingGetHistogram(Imaging im, Imaging imMask, void *minmax) { ImagingSectionCookie cookie; int x, y, i; ImagingHistogram h; @@ -107,13 +102,13 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax) } ImagingSectionEnter(&cookie); for (y = 0; y < im->ysize; y++) { - UINT8* in = (UINT8*) im->image32[y]; + UINT8 *in = (UINT8 *)im->image32[y]; for (x = 0; x < im->xsize; x++) { if (imMask->image8[y][x] != 0) { h->histogram[(*in++)]++; - h->histogram[(*in++)+256]++; - h->histogram[(*in++)+512]++; - h->histogram[(*in++)+768]++; + h->histogram[(*in++) + 256]++; + h->histogram[(*in++) + 512]++; + h->histogram[(*in++) + 768]++; } else { in += 4; } @@ -136,12 +131,12 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax) case IMAGING_TYPE_UINT8: ImagingSectionEnter(&cookie); for (y = 0; y < im->ysize; y++) { - UINT8* in = (UINT8*) im->image[y]; + UINT8 *in = (UINT8 *)im->image[y]; for (x = 0; x < im->xsize; x++) { h->histogram[(*in++)]++; - h->histogram[(*in++)+256]++; - h->histogram[(*in++)+512]++; - h->histogram[(*in++)+768]++; + h->histogram[(*in++) + 256]++; + h->histogram[(*in++) + 512]++; + h->histogram[(*in++) + 768]++; } } ImagingSectionLeave(&cookie); @@ -155,16 +150,16 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax) break; } memcpy(&imin, minmax, sizeof(imin)); - memcpy(&imax, ((char*)minmax) + sizeof(imin), sizeof(imax)); + memcpy(&imax, ((char *)minmax) + sizeof(imin), sizeof(imax)); if (imin >= imax) { break; } ImagingSectionEnter(&cookie); scale = 255.0F / (imax - imin); for (y = 0; y < im->ysize; y++) { - INT32* in = im->image32[y]; + INT32 *in = im->image32[y]; for (x = 0; x < im->xsize; x++) { - i = (int) (((*in++)-imin)*scale); + i = (int)(((*in++) - imin) * scale); if (i >= 0 && i < 256) { h->histogram[i]++; } @@ -181,16 +176,16 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax) break; } memcpy(&fmin, minmax, sizeof(fmin)); - memcpy(&fmax, ((char*)minmax) + sizeof(fmin), sizeof(fmax)); + memcpy(&fmax, ((char *)minmax) + sizeof(fmin), sizeof(fmax)); if (fmin >= fmax) { break; } ImagingSectionEnter(&cookie); scale = 255.0F / (fmax - fmin); for (y = 0; y < im->ysize; y++) { - FLOAT32* in = (FLOAT32*) im->image32[y]; + FLOAT32 *in = (FLOAT32 *)im->image32[y]; for (x = 0; x < im->xsize; x++) { - i = (int) (((*in++)-fmin)*scale); + i = (int)(((*in++) - fmin) * scale); if (i >= 0 && i < 256) { h->histogram[i]++; } diff --git a/src/libImaging/ImDib.h b/src/libImaging/ImDib.h index e5a2cc0f6..91ff3f322 100644 --- a/src/libImaging/ImDib.h +++ b/src/libImaging/ImDib.h @@ -35,20 +35,27 @@ struct ImagingDIBInstance { ImagingShuffler unpack; }; -typedef struct ImagingDIBInstance* ImagingDIB; +typedef struct ImagingDIBInstance *ImagingDIB; -extern char* ImagingGetModeDIB(int size_out[2]); +extern char * +ImagingGetModeDIB(int size_out[2]); -extern ImagingDIB ImagingNewDIB(const char *mode, int xsize, int ysize); +extern ImagingDIB +ImagingNewDIB(const char *mode, int xsize, int ysize); -extern void ImagingDeleteDIB(ImagingDIB im); +extern void +ImagingDeleteDIB(ImagingDIB im); -extern void ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]); -extern void ImagingExposeDIB(ImagingDIB dib, void *dc); +extern void +ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]); +extern void +ImagingExposeDIB(ImagingDIB dib, void *dc); -extern int ImagingQueryPaletteDIB(ImagingDIB dib, void *dc); +extern int +ImagingQueryPaletteDIB(ImagingDIB dib, void *dc); -extern void ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]); +extern void +ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]); #if defined(__cplusplus) } diff --git a/src/libImaging/ImPlatform.h b/src/libImaging/ImPlatform.h index 576ceaa58..9a2060edf 100644 --- a/src/libImaging/ImPlatform.h +++ b/src/libImaging/ImPlatform.h @@ -10,7 +10,8 @@ #include "Python.h" /* Workaround issue #2479 */ -#if PY_VERSION_HEX < 0x03070000 && defined(PySlice_GetIndicesEx) && !defined(PYPY_VERSION) +#if PY_VERSION_HEX < 0x03070000 && defined(PySlice_GetIndicesEx) && \ + !defined(PYPY_VERSION) #undef PySlice_GetIndicesEx #endif @@ -62,7 +63,7 @@ #define INT64 long #endif -#define INT8 signed char +#define INT8 signed char #define UINT8 unsigned char #define UINT16 unsigned INT16 @@ -76,11 +77,9 @@ #define FLOAT64 double #ifdef _MSC_VER -typedef signed __int64 int64_t; +typedef signed __int64 int64_t; #endif #ifdef __GNUC__ - #define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index d7dbe0325..6d18dee4e 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -10,20 +10,16 @@ * See the README file for information on usage and redistribution. */ - #include "ImPlatform.h" - #if defined(__cplusplus) extern "C" { #endif - #ifndef M_PI -#define M_PI 3.1415926535897932384626433832795 +#define M_PI 3.1415926535897932384626433832795 #endif - /* -------------------------------------------------------------------- */ /* @@ -57,12 +53,12 @@ extern "C" { /* Handles */ -typedef struct ImagingMemoryInstance* Imaging; +typedef struct ImagingMemoryInstance *Imaging; -typedef struct ImagingAccessInstance* ImagingAccess; -typedef struct ImagingHistogramInstance* ImagingHistogram; -typedef struct ImagingOutlineInstance* ImagingOutline; -typedef struct ImagingPaletteInstance* ImagingPalette; +typedef struct ImagingAccessInstance *ImagingAccess; +typedef struct ImagingHistogramInstance *ImagingHistogram; +typedef struct ImagingOutlineInstance *ImagingOutline; +typedef struct ImagingPaletteInstance *ImagingPalette; /* handle magics (used with PyCObject). */ #define IMAGING_MAGIC "PIL Imaging" @@ -73,7 +69,8 @@ typedef struct ImagingPaletteInstance* ImagingPalette; #define IMAGING_TYPE_FLOAT32 2 #define IMAGING_TYPE_SPECIAL 3 /* check mode for details */ -#define IMAGING_MODE_LENGTH 6+1 /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */ +#define IMAGING_MODE_LENGTH \ + 6 + 1 /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */ typedef struct { char *ptr; @@ -81,158 +78,178 @@ typedef struct { } ImagingMemoryBlock; struct ImagingMemoryInstance { - /* Format */ - char mode[IMAGING_MODE_LENGTH]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */ - int type; /* Data type (IMAGING_TYPE_*) */ - int depth; /* Depth (ignored in this version) */ - int bands; /* Number of bands (1, 2, 3, or 4) */ - int xsize; /* Image dimension. */ + char mode[IMAGING_MODE_LENGTH]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", + "YCbCr", "BGR;xy") */ + int type; /* Data type (IMAGING_TYPE_*) */ + int depth; /* Depth (ignored in this version) */ + int bands; /* Number of bands (1, 2, 3, or 4) */ + int xsize; /* Image dimension. */ int ysize; /* Colour palette (for "P" images only) */ ImagingPalette palette; /* Data pointers */ - UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */ - INT32 **image32; /* Set for 32-bit images (pixelsize=4). */ + UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */ + INT32 **image32; /* Set for 32-bit images (pixelsize=4). */ /* Internals */ - char **image; /* Actual raster data. */ - char *block; /* Set if data is allocated in a single block. */ - ImagingMemoryBlock *blocks; /* Memory blocks for pixel storage */ + char **image; /* Actual raster data. */ + char *block; /* Set if data is allocated in a single block. */ + ImagingMemoryBlock *blocks; /* Memory blocks for pixel storage */ - int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */ - int linesize; /* Size of a line, in bytes (xsize * pixelsize) */ + int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */ + int linesize; /* Size of a line, in bytes (xsize * pixelsize) */ /* Virtual methods */ void (*destroy)(Imaging im); }; +#define IMAGING_PIXEL_1(im, x, y) ((im)->image8[(y)][(x)]) +#define IMAGING_PIXEL_L(im, x, y) ((im)->image8[(y)][(x)]) +#define IMAGING_PIXEL_LA(im, x, y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_P(im, x, y) ((im)->image8[(y)][(x)]) +#define IMAGING_PIXEL_PA(im, x, y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_I(im, x, y) ((im)->image32[(y)][(x)]) +#define IMAGING_PIXEL_F(im, x, y) (((FLOAT32 *)(im)->image32[y])[x]) +#define IMAGING_PIXEL_RGB(im, x, y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_RGBA(im, x, y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_CMYK(im, x, y) ((im)->image[(y)][(x)*4]) +#define IMAGING_PIXEL_YCbCr(im, x, y) ((im)->image[(y)][(x)*4]) -#define IMAGING_PIXEL_1(im,x,y) ((im)->image8[(y)][(x)]) -#define IMAGING_PIXEL_L(im,x,y) ((im)->image8[(y)][(x)]) -#define IMAGING_PIXEL_LA(im,x,y) ((im)->image[(y)][(x)*4]) -#define IMAGING_PIXEL_P(im,x,y) ((im)->image8[(y)][(x)]) -#define IMAGING_PIXEL_PA(im,x,y) ((im)->image[(y)][(x)*4]) -#define IMAGING_PIXEL_I(im,x,y) ((im)->image32[(y)][(x)]) -#define IMAGING_PIXEL_F(im,x,y) (((FLOAT32*)(im)->image32[y])[x]) -#define IMAGING_PIXEL_RGB(im,x,y) ((im)->image[(y)][(x)*4]) -#define IMAGING_PIXEL_RGBA(im,x,y) ((im)->image[(y)][(x)*4]) -#define IMAGING_PIXEL_CMYK(im,x,y) ((im)->image[(y)][(x)*4]) -#define IMAGING_PIXEL_YCbCr(im,x,y) ((im)->image[(y)][(x)*4]) - -#define IMAGING_PIXEL_UINT8(im,x,y) ((im)->image8[(y)][(x)]) -#define IMAGING_PIXEL_INT32(im,x,y) ((im)->image32[(y)][(x)]) -#define IMAGING_PIXEL_FLOAT32(im,x,y) (((FLOAT32*)(im)->image32[y])[x]) +#define IMAGING_PIXEL_UINT8(im, x, y) ((im)->image8[(y)][(x)]) +#define IMAGING_PIXEL_INT32(im, x, y) ((im)->image32[(y)][(x)]) +#define IMAGING_PIXEL_FLOAT32(im, x, y) (((FLOAT32 *)(im)->image32[y])[x]) struct ImagingAccessInstance { - const char* mode; - void* (*line)(Imaging im, int x, int y); - void (*get_pixel)(Imaging im, int x, int y, void* pixel); - void (*put_pixel)(Imaging im, int x, int y, const void* pixel); + const char *mode; + void *(*line)(Imaging im, int x, int y); + void (*get_pixel)(Imaging im, int x, int y, void *pixel); + void (*put_pixel)(Imaging im, int x, int y, const void *pixel); }; struct ImagingHistogramInstance { - /* Format */ - char mode[IMAGING_MODE_LENGTH]; /* Band names (of corresponding source image) */ - int bands; /* Number of bands (1, 3, or 4) */ + char mode[IMAGING_MODE_LENGTH]; /* Band names (of corresponding source image) */ + int bands; /* Number of bands (1, 3, or 4) */ /* Data */ - long *histogram; /* Histogram (bands*256 longs) */ - + long *histogram; /* Histogram (bands*256 longs) */ }; - struct ImagingPaletteInstance { - /* Format */ - char mode[IMAGING_MODE_LENGTH]; /* Band names */ + char mode[IMAGING_MODE_LENGTH]; /* Band names */ /* Data */ - UINT8 palette[1024];/* Palette data (same format as image data) */ - - INT16* cache; /* Palette cache (used for predefined palettes) */ - int keep_cache; /* This palette will be reused; keep cache */ + UINT8 palette[1024]; /* Palette data (same format as image data) */ + INT16 *cache; /* Palette cache (used for predefined palettes) */ + int keep_cache; /* This palette will be reused; keep cache */ }; typedef struct ImagingMemoryArena { - int alignment; /* Alignment in memory of each line of an image */ - int block_size; /* Preferred block size, bytes */ - int blocks_max; /* Maximum number of cached blocks */ - int blocks_cached; /* Current number of blocks not associated with images */ + int alignment; /* Alignment in memory of each line of an image */ + int block_size; /* Preferred block size, bytes */ + int blocks_max; /* Maximum number of cached blocks */ + int blocks_cached; /* Current number of blocks not associated with images */ ImagingMemoryBlock *blocks_pool; - int stats_new_count; /* Number of new allocated images */ - int stats_allocated_blocks; /* Number of allocated blocks */ - int stats_reused_blocks; /* Number of blocks which were retrieved from a pool */ - int stats_reallocated_blocks; /* Number of blocks which were actually reallocated after retrieving */ - int stats_freed_blocks; /* Number of freed blocks */ -} *ImagingMemoryArena; - + int stats_new_count; /* Number of new allocated images */ + int stats_allocated_blocks; /* Number of allocated blocks */ + int stats_reused_blocks; /* Number of blocks which were retrieved from a pool */ + int stats_reallocated_blocks; /* Number of blocks which were actually reallocated + after retrieving */ + int stats_freed_blocks; /* Number of freed blocks */ +} * ImagingMemoryArena; /* Objects */ /* ------- */ extern struct ImagingMemoryArena ImagingDefaultArena; -extern int ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max); -extern void ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size); +extern int +ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max); +extern void +ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size); -extern Imaging ImagingNew(const char* mode, int xsize, int ysize); -extern Imaging ImagingNewDirty(const char* mode, int xsize, int ysize); -extern Imaging ImagingNew2Dirty(const char* mode, Imaging imOut, Imaging imIn); -extern void ImagingDelete(Imaging im); +extern Imaging +ImagingNew(const char *mode, int xsize, int ysize); +extern Imaging +ImagingNewDirty(const char *mode, int xsize, int ysize); +extern Imaging +ImagingNew2Dirty(const char *mode, Imaging imOut, Imaging imIn); +extern void +ImagingDelete(Imaging im); -extern Imaging ImagingNewBlock(const char* mode, int xsize, int ysize); +extern Imaging +ImagingNewBlock(const char *mode, int xsize, int ysize); -extern Imaging ImagingNewPrologue(const char *mode, - int xsize, int ysize); -extern Imaging ImagingNewPrologueSubtype(const char *mode, - int xsize, int ysize, - int structure_size); +extern Imaging +ImagingNewPrologue(const char *mode, int xsize, int ysize); +extern Imaging +ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int structure_size); -extern void ImagingCopyPalette(Imaging destination, Imaging source); +extern void +ImagingCopyPalette(Imaging destination, Imaging source); -extern void ImagingHistogramDelete(ImagingHistogram histogram); +extern void +ImagingHistogramDelete(ImagingHistogram histogram); -extern void ImagingAccessInit(void); -extern ImagingAccess ImagingAccessNew(Imaging im); -extern void _ImagingAccessDelete(Imaging im, ImagingAccess access); +extern void +ImagingAccessInit(void); +extern ImagingAccess +ImagingAccessNew(Imaging im); +extern void +_ImagingAccessDelete(Imaging im, ImagingAccess access); #define ImagingAccessDelete(im, access) /* nop, for now */ -extern ImagingPalette ImagingPaletteNew(const char *mode); -extern ImagingPalette ImagingPaletteNewBrowser(void); -extern ImagingPalette ImagingPaletteDuplicate(ImagingPalette palette); -extern void ImagingPaletteDelete(ImagingPalette palette); +extern ImagingPalette +ImagingPaletteNew(const char *mode); +extern ImagingPalette +ImagingPaletteNewBrowser(void); +extern ImagingPalette +ImagingPaletteDuplicate(ImagingPalette palette); +extern void +ImagingPaletteDelete(ImagingPalette palette); -extern int ImagingPaletteCachePrepare(ImagingPalette palette); -extern void ImagingPaletteCacheUpdate(ImagingPalette palette, - int r, int g, int b); -extern void ImagingPaletteCacheDelete(ImagingPalette palette); +extern int +ImagingPaletteCachePrepare(ImagingPalette palette); +extern void +ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b); +extern void +ImagingPaletteCacheDelete(ImagingPalette palette); -#define ImagingPaletteCache(p, r, g, b)\ - p->cache[(r>>2) + (g>>2)*64 + (b>>2)*64*64] +#define ImagingPaletteCache(p, r, g, b) \ + p->cache[(r >> 2) + (g >> 2) * 64 + (b >> 2) * 64 * 64] -extern Imaging ImagingQuantize(Imaging im, int colours, int mode, int kmeans); +extern Imaging +ImagingQuantize(Imaging im, int colours, int mode, int kmeans); /* Threading */ /* --------- */ -typedef void* ImagingSectionCookie; +typedef void *ImagingSectionCookie; -extern void ImagingSectionEnter(ImagingSectionCookie* cookie); -extern void ImagingSectionLeave(ImagingSectionCookie* cookie); +extern void +ImagingSectionEnter(ImagingSectionCookie *cookie); +extern void +ImagingSectionLeave(ImagingSectionCookie *cookie); /* Exceptions */ /* ---------- */ -extern void* ImagingError_OSError(void); -extern void* ImagingError_MemoryError(void); -extern void* ImagingError_ModeError(void); /* maps to ValueError by default */ -extern void* ImagingError_Mismatch(void); /* maps to ValueError by default */ -extern void* ImagingError_ValueError(const char* message); -extern void ImagingError_Clear(void); +extern void * +ImagingError_OSError(void); +extern void * +ImagingError_MemoryError(void); +extern void * +ImagingError_ModeError(void); /* maps to ValueError by default */ +extern void * +ImagingError_Mismatch(void); /* maps to ValueError by default */ +extern void * +ImagingError_ValueError(const char *message); +extern void +ImagingError_Clear(void); /* Transform callbacks */ /* ------------------- */ @@ -242,7 +259,6 @@ extern void ImagingError_Clear(void); #define IMAGING_TRANSFORM_PERSPECTIVE 2 #define IMAGING_TRANSFORM_QUAD 3 - /* standard filters */ #define IMAGING_TRANSFORM_NEAREST 0 #define IMAGING_TRANSFORM_BOX 4 @@ -251,249 +267,391 @@ extern void ImagingError_Clear(void); #define IMAGING_TRANSFORM_BICUBIC 3 #define IMAGING_TRANSFORM_LANCZOS 1 -typedef int (*ImagingTransformMap)(double* X, double* Y, - int x, int y, void* data); -typedef int (*ImagingTransformFilter)(void* out, Imaging im, - double x, double y); +typedef int (*ImagingTransformMap)(double *X, double *Y, int x, int y, void *data); +typedef int (*ImagingTransformFilter)(void *out, Imaging im, double x, double y); /* Image Manipulation Methods */ /* -------------------------- */ -extern Imaging ImagingAlphaComposite(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha); -extern Imaging ImagingCopy(Imaging im); -extern Imaging ImagingConvert(Imaging im, const char* mode, ImagingPalette palette, int dither); -extern Imaging ImagingConvertInPlace(Imaging im, const char* mode); -extern Imaging ImagingConvertMatrix(Imaging im, const char *mode, float m[]); -extern Imaging ImagingConvertTransparent(Imaging im, const char *mode, int r, int g, int b); -extern Imaging ImagingCrop(Imaging im, int x0, int y0, int x1, int y1); -extern Imaging ImagingExpand(Imaging im, int x, int y, int mode); -extern Imaging ImagingFill(Imaging im, const void* ink); -extern int ImagingFill2( - Imaging into, const void* ink, Imaging mask, - int x0, int y0, int x1, int y1); -extern Imaging ImagingFillBand(Imaging im, int band, int color); -extern Imaging ImagingFillLinearGradient(const char* mode); -extern Imaging ImagingFillRadialGradient(const char* mode); -extern Imaging ImagingFilter( - Imaging im, int xsize, int ysize, const FLOAT32* kernel, - FLOAT32 offset); -extern Imaging ImagingFlipLeftRight(Imaging imOut, Imaging imIn); -extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn); -extern Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius, - int passes); -extern Imaging ImagingGetBand(Imaging im, int band); -extern Imaging ImagingMerge(const char* mode, Imaging bands[4]); -extern int ImagingSplit(Imaging im, Imaging bands[4]); -extern int ImagingGetBBox(Imaging im, int bbox[4]); -typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem; -extern ImagingColorItem* ImagingGetColors(Imaging im, int maxcolors, - int *colors); -extern int ImagingGetExtrema(Imaging im, void *extrema); -extern int ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj); -extern ImagingHistogram ImagingGetHistogram( - Imaging im, Imaging mask, void *extrema); -extern Imaging ImagingModeFilter(Imaging im, int size); -extern Imaging ImagingNegative(Imaging im); -extern Imaging ImagingOffset(Imaging im, int xoffset, int yoffset); -extern int ImagingPaste( - Imaging into, Imaging im, Imaging mask, - int x0, int y0, int x1, int y1); -extern Imaging ImagingPoint( - Imaging im, const char* tablemode, const void* table); -extern Imaging ImagingPointTransform( - Imaging imIn, double scale, double offset); -extern Imaging ImagingPutBand(Imaging im, Imaging imIn, int band); -extern Imaging ImagingRankFilter(Imaging im, int size, int rank); -extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn); -extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); -extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); -extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn); -extern Imaging ImagingTransverse(Imaging imOut, Imaging imIn); -extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]); -extern Imaging ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]); -extern Imaging ImagingTransform( - Imaging imOut, Imaging imIn, int method, int x0, int y0, int x1, int y1, - double *a, int filter, int fill); -extern Imaging ImagingUnsharpMask( - Imaging imOut, Imaging im, float radius, int percent, int threshold); -extern Imaging ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n); -extern Imaging ImagingColorLUT3D_linear(Imaging imOut, Imaging imIn, - int table_channels, int size1D, int size2D, int size3D, INT16* table); +extern Imaging +ImagingAlphaComposite(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha); +extern Imaging +ImagingCopy(Imaging im); +extern Imaging +ImagingConvert(Imaging im, const char *mode, ImagingPalette palette, int dither); +extern Imaging +ImagingConvertInPlace(Imaging im, const char *mode); +extern Imaging +ImagingConvertMatrix(Imaging im, const char *mode, float m[]); +extern Imaging +ImagingConvertTransparent(Imaging im, const char *mode, int r, int g, int b); +extern Imaging +ImagingCrop(Imaging im, int x0, int y0, int x1, int y1); +extern Imaging +ImagingExpand(Imaging im, int x, int y, int mode); +extern Imaging +ImagingFill(Imaging im, const void *ink); +extern int +ImagingFill2( + Imaging into, const void *ink, Imaging mask, int x0, int y0, int x1, int y1); +extern Imaging +ImagingFillBand(Imaging im, int band, int color); +extern Imaging +ImagingFillLinearGradient(const char *mode); +extern Imaging +ImagingFillRadialGradient(const char *mode); +extern Imaging +ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 offset); +extern Imaging +ImagingFlipLeftRight(Imaging imOut, Imaging imIn); +extern Imaging +ImagingFlipTopBottom(Imaging imOut, Imaging imIn); +extern Imaging +ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius, int passes); +extern Imaging +ImagingGetBand(Imaging im, int band); +extern Imaging +ImagingMerge(const char *mode, Imaging bands[4]); +extern int +ImagingSplit(Imaging im, Imaging bands[4]); +extern int +ImagingGetBBox(Imaging im, int bbox[4]); +typedef struct { + int x, y; + INT32 count; + INT32 pixel; +} ImagingColorItem; +extern ImagingColorItem * +ImagingGetColors(Imaging im, int maxcolors, int *colors); +extern int +ImagingGetExtrema(Imaging im, void *extrema); +extern int +ImagingGetProjection(Imaging im, UINT8 *xproj, UINT8 *yproj); +extern ImagingHistogram +ImagingGetHistogram(Imaging im, Imaging mask, void *extrema); +extern Imaging +ImagingModeFilter(Imaging im, int size); +extern Imaging +ImagingNegative(Imaging im); +extern Imaging +ImagingOffset(Imaging im, int xoffset, int yoffset); +extern int +ImagingPaste(Imaging into, Imaging im, Imaging mask, int x0, int y0, int x1, int y1); +extern Imaging +ImagingPoint(Imaging im, const char *tablemode, const void *table); +extern Imaging +ImagingPointTransform(Imaging imIn, double scale, double offset); +extern Imaging +ImagingPutBand(Imaging im, Imaging imIn, int band); +extern Imaging +ImagingRankFilter(Imaging im, int size, int rank); +extern Imaging +ImagingRotate90(Imaging imOut, Imaging imIn); +extern Imaging +ImagingRotate180(Imaging imOut, Imaging imIn); +extern Imaging +ImagingRotate270(Imaging imOut, Imaging imIn); +extern Imaging +ImagingTranspose(Imaging imOut, Imaging imIn); +extern Imaging +ImagingTransverse(Imaging imOut, Imaging imIn); +extern Imaging +ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]); +extern Imaging +ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]); +extern Imaging +ImagingTransform( + Imaging imOut, + Imaging imIn, + int method, + int x0, + int y0, + int x1, + int y1, + double a[8], + int filter, + int fill); +extern Imaging +ImagingUnsharpMask(Imaging imOut, Imaging im, float radius, int percent, int threshold); +extern Imaging +ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n); +extern Imaging +ImagingColorLUT3D_linear( + Imaging imOut, + Imaging imIn, + int table_channels, + int size1D, + int size2D, + int size3D, + INT16 *table); -extern Imaging ImagingCopy2(Imaging imOut, Imaging imIn); -extern Imaging ImagingConvert2(Imaging imOut, Imaging imIn); +extern Imaging +ImagingCopy2(Imaging imOut, Imaging imIn); +extern Imaging +ImagingConvert2(Imaging imOut, Imaging imIn); /* Channel operations */ /* any mode, except "F" */ -extern Imaging ImagingChopLighter(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopDarker(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopDifference(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopMultiply(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopScreen(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopAdd( - Imaging imIn1, Imaging imIn2, float scale, int offset); -extern Imaging ImagingChopSubtract( - Imaging imIn1, Imaging imIn2, float scale, int offset); -extern Imaging ImagingChopAddModulo(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopSoftLight(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopHardLight(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingOverlay(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopLighter(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopDarker(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopDifference(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopMultiply(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopScreen(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopAdd(Imaging imIn1, Imaging imIn2, float scale, int offset); +extern Imaging +ImagingChopSubtract(Imaging imIn1, Imaging imIn2, float scale, int offset); +extern Imaging +ImagingChopAddModulo(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopSoftLight(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopHardLight(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingOverlay(Imaging imIn1, Imaging imIn2); /* "1" images only */ -extern Imaging ImagingChopAnd(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopOr(Imaging imIn1, Imaging imIn2); -extern Imaging ImagingChopXor(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopAnd(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopOr(Imaging imIn1, Imaging imIn2); +extern Imaging +ImagingChopXor(Imaging imIn1, Imaging imIn2); /* Graphics */ -extern int ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, const void* ink, int width, - int op); -extern int ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, - const void* ink, int op); -extern int ImagingDrawChord(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, const void* ink, int fill, - int width, int op); -extern int ImagingDrawEllipse(Imaging im, int x0, int y0, int x1, int y1, - const void* ink, int fill, int width, int op); -extern int ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, - const void* ink, int op); -extern int ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, - const void* ink, int width, int op); -extern int ImagingDrawPieslice(Imaging im, int x0, int y0, int x1, int y1, - float start, float end, const void* ink, int fill, - int width, int op); -extern int ImagingDrawPoint(Imaging im, int x, int y, const void* ink, int op); -extern int ImagingDrawPolygon(Imaging im, int points, int *xy, - const void* ink, int fill, int op); -extern int ImagingDrawRectangle(Imaging im, int x0, int y0, int x1, int y1, - const void* ink, int fill, int width, int op); +extern int +ImagingDrawArc( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink, + int width, + int op); +extern int +ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, const void *ink, int op); +extern int +ImagingDrawChord( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink, + int fill, + int width, + int op); +extern int +ImagingDrawEllipse( + Imaging im, + int x0, + int y0, + int x1, + int y1, + const void *ink, + int fill, + int width, + int op); +extern int +ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink, int op); +extern int +ImagingDrawWideLine( + Imaging im, int x0, int y0, int x1, int y1, const void *ink, int width, int op); +extern int +ImagingDrawPieslice( + Imaging im, + int x0, + int y0, + int x1, + int y1, + float start, + float end, + const void *ink, + int fill, + int width, + int op); +extern int +ImagingDrawPoint(Imaging im, int x, int y, const void *ink, int op); +extern int +ImagingDrawPolygon(Imaging im, int points, int *xy, const void *ink, int fill, int op); +extern int +ImagingDrawRectangle( + Imaging im, + int x0, + int y0, + int x1, + int y1, + const void *ink, + int fill, + int width, + int op); /* Level 2 graphics (WORK IN PROGRESS) */ -extern ImagingOutline ImagingOutlineNew(void); -extern void ImagingOutlineDelete(ImagingOutline outline); +extern ImagingOutline +ImagingOutlineNew(void); +extern void +ImagingOutlineDelete(ImagingOutline outline); -extern int ImagingDrawOutline(Imaging im, ImagingOutline outline, - const void* ink, int fill, int op); +extern int +ImagingDrawOutline( + Imaging im, ImagingOutline outline, const void *ink, int fill, int op); -extern int ImagingOutlineMove(ImagingOutline outline, float x, float y); -extern int ImagingOutlineLine(ImagingOutline outline, float x, float y); -extern int ImagingOutlineCurve(ImagingOutline outline, float x1, float y1, - float x2, float y2, float x3, float y3); -extern int ImagingOutlineTransform(ImagingOutline outline, double a[6]); +extern int +ImagingOutlineMove(ImagingOutline outline, float x, float y); +extern int +ImagingOutlineLine(ImagingOutline outline, float x, float y); +extern int +ImagingOutlineCurve( + ImagingOutline outline, float x1, float y1, float x2, float y2, float x3, float y3); +extern int +ImagingOutlineTransform(ImagingOutline outline, double a[6]); -extern int ImagingOutlineClose(ImagingOutline outline); +extern int +ImagingOutlineClose(ImagingOutline outline); /* Special effects */ -extern Imaging ImagingEffectSpread(Imaging imIn, int distance); -extern Imaging ImagingEffectNoise(int xsize, int ysize, float sigma); -extern Imaging ImagingEffectMandelbrot(int xsize, int ysize, - double extent[4], int quality); - +extern Imaging +ImagingEffectSpread(Imaging imIn, int distance); +extern Imaging +ImagingEffectNoise(int xsize, int ysize, float sigma); +extern Imaging +ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality); /* File I/O */ /* -------- */ /* Built-in drivers */ -extern Imaging ImagingOpenPPM(const char* filename); -extern int ImagingSavePPM(Imaging im, const char* filename); +extern Imaging +ImagingOpenPPM(const char *filename); +extern int +ImagingSavePPM(Imaging im, const char *filename); /* Codecs */ typedef struct ImagingCodecStateInstance *ImagingCodecState; -typedef int (*ImagingCodec)(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); +typedef int (*ImagingCodec)( + Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); -extern int ImagingBcnDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingBitDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingEpsEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); -extern int ImagingFliDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingGifDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingGifEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); -extern int ImagingHexDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -#ifdef HAVE_LIBJPEG -extern int ImagingJpegDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingJpegDecodeCleanup(ImagingCodecState state); -extern int ImagingJpegUseJCSExtensions(void); +extern int +ImagingBcnDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); +extern int +ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); +extern int +ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +#ifdef HAVE_LIBJPEG +extern int +ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingJpegDecodeCleanup(ImagingCodecState state); +extern int +ImagingJpegUseJCSExtensions(void); -extern int ImagingJpegEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); +extern int +ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); #endif #ifdef HAVE_OPENJPEG -extern int ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingJpeg2KDecodeCleanup(ImagingCodecState state); -extern int ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); -extern int ImagingJpeg2KEncodeCleanup(ImagingCodecState state); +extern int +ImagingJpeg2KDecode( + Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingJpeg2KDecodeCleanup(ImagingCodecState state); +extern int +ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); +extern int +ImagingJpeg2KEncodeCleanup(ImagingCodecState state); #endif -#ifdef HAVE_LIBTIFF -extern int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); +#ifdef HAVE_LIBTIFF +extern int +ImagingLibTiffDecode( + Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); #endif -#ifdef HAVE_LIBMPEG -extern int ImagingMpegDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); +#ifdef HAVE_LIBMPEG +extern int +ImagingMpegDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); #endif -extern int ImagingMspDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingPackbitsDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingPcdDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingPcxDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingPcxEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); -extern int ImagingRawDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingRawEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); -extern int ImagingSgiRleDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingSunRleDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingTgaRleDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingTgaRleEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); -extern int ImagingXbmDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingXbmEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); -#ifdef HAVE_LIBZ -extern int ImagingZipDecode(Imaging im, ImagingCodecState state, - UINT8* buffer, Py_ssize_t bytes); -extern int ImagingZipDecodeCleanup(ImagingCodecState state); -extern int ImagingZipEncode(Imaging im, ImagingCodecState state, - UINT8* buffer, int bytes); -extern int ImagingZipEncodeCleanup(ImagingCodecState state); +extern int +ImagingMspDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingPackbitsDecode( + Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); +extern int +ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); +extern int +ImagingSgiRleDecode( + Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingSunRleDecode( + Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingTgaRleDecode( + Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); +extern int +ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingXbmEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); +#ifdef HAVE_LIBZ +extern int +ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes); +extern int +ImagingZipDecodeCleanup(ImagingCodecState state); +extern int +ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes); +extern int +ImagingZipEncodeCleanup(ImagingCodecState state); #endif -typedef void (*ImagingShuffler)(UINT8* out, const UINT8* in, int pixels); +typedef void (*ImagingShuffler)(UINT8 *out, const UINT8 *in, int pixels); /* Public shufflers */ -extern void ImagingPackBGR(UINT8* out, const UINT8* in, int pixels); -extern void ImagingUnpackYCC(UINT8* out, const UINT8* in, int pixels); -extern void ImagingUnpackYCCA(UINT8* out, const UINT8* in, int pixels); +extern void +ImagingPackBGR(UINT8 *out, const UINT8 *in, int pixels); +extern void +ImagingUnpackYCC(UINT8 *out, const UINT8 *in, int pixels); +extern void +ImagingUnpackYCCA(UINT8 *out, const UINT8 *in, int pixels); -extern void ImagingConvertRGB2YCbCr(UINT8* out, const UINT8* in, int pixels); -extern void ImagingConvertYCbCr2RGB(UINT8* out, const UINT8* in, int pixels); +extern void +ImagingConvertRGB2YCbCr(UINT8 *out, const UINT8 *in, int pixels); +extern void +ImagingConvertYCbCr2RGB(UINT8 *out, const UINT8 *in, int pixels); -extern ImagingShuffler ImagingFindUnpacker(const char* mode, - const char* rawmode, int* bits_out); -extern ImagingShuffler ImagingFindPacker(const char* mode, - const char* rawmode, int* bits_out); +extern ImagingShuffler +ImagingFindUnpacker(const char *mode, const char *rawmode, int *bits_out); +extern ImagingShuffler +ImagingFindPacker(const char *mode, const char *rawmode, int *bits_out); struct ImagingCodecStateInstance { int count; @@ -509,30 +667,27 @@ struct ImagingCodecStateInstance { PyObject *fd; }; - - /* Codec read/write python fd */ -extern Py_ssize_t _imaging_read_pyFd(PyObject *fd, char* dest, Py_ssize_t bytes); -extern Py_ssize_t _imaging_write_pyFd(PyObject *fd, char* src, Py_ssize_t bytes); -extern int _imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence); -extern Py_ssize_t _imaging_tell_pyFd(PyObject *fd); - - +extern Py_ssize_t +_imaging_read_pyFd(PyObject *fd, char *dest, Py_ssize_t bytes); +extern Py_ssize_t +_imaging_write_pyFd(PyObject *fd, char *src, Py_ssize_t bytes); +extern int +_imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence); +extern Py_ssize_t +_imaging_tell_pyFd(PyObject *fd); /* Errcodes */ -#define IMAGING_CODEC_END 1 -#define IMAGING_CODEC_OVERRUN -1 -#define IMAGING_CODEC_BROKEN -2 -#define IMAGING_CODEC_UNKNOWN -3 -#define IMAGING_CODEC_CONFIG -8 -#define IMAGING_CODEC_MEMORY -9 - - +#define IMAGING_CODEC_END 1 +#define IMAGING_CODEC_OVERRUN -1 +#define IMAGING_CODEC_BROKEN -2 +#define IMAGING_CODEC_UNKNOWN -3 +#define IMAGING_CODEC_CONFIG -8 +#define IMAGING_CODEC_MEMORY -9 #include "ImagingUtils.h" extern UINT8 *clip8_lookups; - #if defined(__cplusplus) } #endif diff --git a/src/libImaging/ImagingUtils.h b/src/libImaging/ImagingUtils.h index 21c2688d8..ad6f280ac 100644 --- a/src/libImaging/ImagingUtils.h +++ b/src/libImaging/ImagingUtils.h @@ -1,47 +1,42 @@ #ifdef WORDS_BIGENDIAN - #define MAKE_UINT32(u0, u1, u2, u3) ((UINT32)(u3) | ((UINT32)(u2)<<8) | ((UINT32)(u1)<<16) | ((UINT32)(u0)<<24)) - #define MASK_UINT32_CHANNEL_0 0xff000000 - #define MASK_UINT32_CHANNEL_1 0x00ff0000 - #define MASK_UINT32_CHANNEL_2 0x0000ff00 - #define MASK_UINT32_CHANNEL_3 0x000000ff +#define MAKE_UINT32(u0, u1, u2, u3) \ + ((UINT32)(u3) | ((UINT32)(u2) << 8) | ((UINT32)(u1) << 16) | ((UINT32)(u0) << 24)) +#define MASK_UINT32_CHANNEL_0 0xff000000 +#define MASK_UINT32_CHANNEL_1 0x00ff0000 +#define MASK_UINT32_CHANNEL_2 0x0000ff00 +#define MASK_UINT32_CHANNEL_3 0x000000ff #else - #define MAKE_UINT32(u0, u1, u2, u3) ((UINT32)(u0) | ((UINT32)(u1)<<8) | ((UINT32)(u2)<<16) | ((UINT32)(u3)<<24)) - #define MASK_UINT32_CHANNEL_0 0x000000ff - #define MASK_UINT32_CHANNEL_1 0x0000ff00 - #define MASK_UINT32_CHANNEL_2 0x00ff0000 - #define MASK_UINT32_CHANNEL_3 0xff000000 +#define MAKE_UINT32(u0, u1, u2, u3) \ + ((UINT32)(u0) | ((UINT32)(u1) << 8) | ((UINT32)(u2) << 16) | ((UINT32)(u3) << 24)) +#define MASK_UINT32_CHANNEL_0 0x000000ff +#define MASK_UINT32_CHANNEL_1 0x0000ff00 +#define MASK_UINT32_CHANNEL_2 0x00ff0000 +#define MASK_UINT32_CHANNEL_3 0xff000000 #endif - -#define SHIFTFORDIV255(a)\ - ((((a) >> 8) + a) >> 8) +#define SHIFTFORDIV255(a) ((((a) >> 8) + a) >> 8) /* like (a * b + 127) / 255), but much faster on most platforms */ -#define MULDIV255(a, b, tmp)\ - (tmp = (a) * (b) + 128, SHIFTFORDIV255(tmp)) +#define MULDIV255(a, b, tmp) (tmp = (a) * (b) + 128, SHIFTFORDIV255(tmp)) -#define DIV255(a, tmp)\ - (tmp = (a) + 128, SHIFTFORDIV255(tmp)) +#define DIV255(a, tmp) (tmp = (a) + 128, SHIFTFORDIV255(tmp)) -#define BLEND(mask, in1, in2, tmp1)\ - DIV255(in1 * (255 - mask) + in2 * mask, tmp1) - -#define PREBLEND(mask, in1, in2, tmp1)\ - (MULDIV255(in1, (255 - mask), tmp1) + in2) +#define BLEND(mask, in1, in2, tmp1) DIV255(in1 *(255 - mask) + in2 * mask, tmp1) +#define PREBLEND(mask, in1, in2, tmp1) (MULDIV255(in1, (255 - mask), tmp1) + in2) #define CLIP8(v) ((v) <= 0 ? 0 : (v) < 256 ? (v) : 255) /* This is to work around a bug in GCC prior 4.9 in 64 bit mode. GCC generates code with partial dependency which is 3 times slower. See: http://stackoverflow.com/a/26588074/253146 */ -#if defined(__x86_64__) && defined(__SSE__) && ! defined(__NO_INLINE__) && \ - ! defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900) +#if defined(__x86_64__) && defined(__SSE__) && !defined(__NO_INLINE__) && \ + !defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900) static float __attribute__((always_inline)) inline _i2f(int v) { float x; - __asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=x"(x) : "r"(v) ); + __asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=x"(x) : "r"(v)); return x; } #else -static float inline _i2f(int v) { return (float) v; } +static float inline _i2f(int v) { return (float)v; } #endif diff --git a/src/libImaging/Jpeg.h b/src/libImaging/Jpeg.h index 280b6d638..a876d3bb6 100644 --- a/src/libImaging/Jpeg.h +++ b/src/libImaging/Jpeg.h @@ -12,13 +12,11 @@ #include - typedef struct { - struct jpeg_error_mgr pub; /* "public" fields */ - jmp_buf setjmp_buffer; /* for return to caller */ + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ } JPEGERROR; - /* -------------------------------------------------------------------- */ /* Decoder */ @@ -28,15 +26,14 @@ typedef struct { } JPEGSOURCE; typedef struct { - /* CONFIGURATION */ /* Jpeg file mode (empty if not known) */ - char jpegmode[8+1]; + char jpegmode[8 + 1]; /* Converter output mode (input to the shuffler). If empty, convert conversions are disabled */ - char rawmode[8+1]; + char rawmode[8 + 1]; /* If set, trade quality for speed */ int draft; @@ -54,7 +51,6 @@ typedef struct { } JPEGSTATE; - /* -------------------------------------------------------------------- */ /* Encoder */ @@ -64,7 +60,6 @@ typedef struct { } JPEGDESTINATION; typedef struct { - /* CONFIGURATION */ /* Quality (0-100, -1 means default) */ @@ -89,7 +84,7 @@ typedef struct { int subsampling; /* Converter input mode (input to the shuffler) */ - char rawmode[8+1]; + char rawmode[8 + 1]; /* Custom quantization tables () */ unsigned int *qtables; @@ -98,7 +93,8 @@ typedef struct { int qtablesLen; /* Extra data (to be injected after header) */ - char* extra; int extra_size; + char *extra; + int extra_size; /* PRIVATE CONTEXT (set by encoder) */ @@ -110,7 +106,7 @@ typedef struct { int extra_offset; - size_t rawExifLen; /* EXIF data length */ - char* rawExif; /* EXIF buffer pointer */ + size_t rawExifLen; /* EXIF data length */ + char *rawExif; /* EXIF buffer pointer */ } JPEGENCODERSTATE; diff --git a/src/libImaging/Jpeg2K.h b/src/libImaging/Jpeg2K.h index 7645b9326..f749ecfb2 100644 --- a/src/libImaging/Jpeg2K.h +++ b/src/libImaging/Jpeg2K.h @@ -24,7 +24,7 @@ typedef struct { int fd; /* File pointer, when opened */ - FILE * pfile; + FILE *pfile; /* Length of data, if available; otherwise, -1 */ off_t length; @@ -33,13 +33,13 @@ typedef struct { OPJ_CODEC_FORMAT format; /* Set to divide image resolution by 2**reduce. */ - int reduce; + int reduce; /* Set to limit the number of quality layers to decode (0 = all layers) */ - int layers; + int layers; /* PRIVATE CONTEXT (set by decoder) */ - const char *error_msg; + const char *error_msg; } JPEG2KDECODESTATE; @@ -51,36 +51,36 @@ typedef struct { /* CONFIGURATION */ /* File descriptor, if available; otherwise, -1 */ - int fd; + int fd; /* File pointer, when opened */ - FILE * pfile; + FILE *pfile; /* Specify the desired format */ OPJ_CODEC_FORMAT format; /* Image offset */ - int offset_x, offset_y; + int offset_x, offset_y; /* Tile information */ - int tile_offset_x, tile_offset_y; - int tile_size_x, tile_size_y; + int tile_offset_x, tile_offset_y; + int tile_size_x, tile_size_y; /* Quality layers (a sequence of numbers giving *either* rates or dB) */ - int quality_is_in_db; - PyObject *quality_layers; + int quality_is_in_db; + PyObject *quality_layers; /* Number of resolutions (DWT decompositions + 1 */ - int num_resolutions; + int num_resolutions; /* Code block size */ - int cblk_width, cblk_height; + int cblk_width, cblk_height; /* Precinct size */ - int precinct_width, precinct_height; + int precinct_width, precinct_height; /* Compression style */ - int irreversible; + int irreversible; /* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */ OPJ_PROG_ORDER progression; @@ -89,8 +89,7 @@ typedef struct { OPJ_CINEMA_MODE cinema_mode; /* PRIVATE CONTEXT (set by decoder) */ - const char *error_msg; - + const char *error_msg; } JPEG2KENCODESTATE; diff --git a/src/libImaging/Jpeg2KDecode.c b/src/libImaging/Jpeg2KDecode.c index 8cce5454f..601bd4b62 100644 --- a/src/libImaging/Jpeg2KDecode.c +++ b/src/libImaging/Jpeg2KDecode.c @@ -23,7 +23,7 @@ typedef struct { OPJ_UINT32 tile_index; OPJ_UINT32 data_size; - OPJ_INT32 x0, y0, x1, y1; + OPJ_INT32 x0, y0, x1, y1; OPJ_UINT32 nb_comps; } JPEG2KTILEINFO; @@ -32,9 +32,8 @@ typedef struct { /* -------------------------------------------------------------------- */ static void -j2k_error(const char *msg, void *client_data) -{ - JPEG2KDECODESTATE *state = (JPEG2KDECODESTATE *) client_data; +j2k_error(const char *msg, void *client_data) { + JPEG2KDECODESTATE *state = (JPEG2KDECODESTATE *)client_data; free((void *)state->error_msg); state->error_msg = strdup(msg); } @@ -44,8 +43,7 @@ j2k_error(const char *msg, void *client_data) /* -------------------------------------------------------------------- */ static OPJ_SIZE_T -j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) -{ +j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) { ImagingCodecState state = (ImagingCodecState)p_user_data; size_t len = _imaging_read_pyFd(state->fd, p_buffer, p_nb_bytes); @@ -54,8 +52,7 @@ j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) } static OPJ_OFF_T -j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) -{ +j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) { off_t pos; ImagingCodecState state = (ImagingCodecState)p_user_data; @@ -69,21 +66,20 @@ j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) /* Unpackers */ /* -------------------------------------------------------------------- */ -typedef void (*j2k_unpacker_t)(opj_image_t *in, - const JPEG2KTILEINFO *tileInfo, - const UINT8 *data, - Imaging im); +typedef void (*j2k_unpacker_t)( + opj_image_t *in, const JPEG2KTILEINFO *tileInfo, const UINT8 *data, Imaging im); struct j2k_decode_unpacker { - const char *mode; - OPJ_COLOR_SPACE color_space; - unsigned components; - j2k_unpacker_t unpacker; + const char *mode; + OPJ_COLOR_SPACE color_space; + unsigned components; + /* bool indicating if unpacker supports subsampling */ + int subsampling; + j2k_unpacker_t unpacker; }; -static inline -unsigned j2ku_shift(unsigned x, int n) -{ +static inline unsigned +j2ku_shift(unsigned x, int n) { if (n < 0) { return x >> -n; } else { @@ -92,9 +88,11 @@ unsigned j2ku_shift(unsigned x, int n) } static void -j2ku_gray_l(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, - const UINT8 *tiledata, Imaging im) -{ +j2ku_gray_l( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -115,41 +113,42 @@ j2ku_gray_l(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, /* csiz*h*w + offset = tileinfo.datasize */ switch (csiz) { - case 1: - for (y = 0; y < h; ++y) { - const UINT8 *data = &tiledata[y * w]; - UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - *row++ = j2ku_shift(offset + *data++, shift); + case 1: + for (y = 0; y < h; ++y) { + const UINT8 *data = &tiledata[y * w]; + UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + *row++ = j2ku_shift(offset + *data++, shift); + } } - } - break; - case 2: - for (y = 0; y < h; ++y) { - const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w]; - UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - *row++ = j2ku_shift(offset + *data++, shift); + break; + case 2: + for (y = 0; y < h; ++y) { + const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w]; + UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + *row++ = j2ku_shift(offset + *data++, shift); + } } - } - break; - case 4: - for (y = 0; y < h; ++y) { - const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w]; - UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - *row++ = j2ku_shift(offset + *data++, shift); + break; + case 4: + for (y = 0; y < h; ++y) { + const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w]; + UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + *row++ = j2ku_shift(offset + *data++, shift); + } } - } - break; + break; } } - static void -j2ku_gray_i(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, - const UINT8 *tiledata, Imaging im) -{ +j2ku_gray_i( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -169,41 +168,42 @@ j2ku_gray_i(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, } switch (csiz) { - case 1: - for (y = 0; y < h; ++y) { - const UINT8 *data = &tiledata[y * w]; - UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - *row++ = j2ku_shift(offset + *data++, shift); + case 1: + for (y = 0; y < h; ++y) { + const UINT8 *data = &tiledata[y * w]; + UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + *row++ = j2ku_shift(offset + *data++, shift); + } } - } - break; - case 2: - for (y = 0; y < h; ++y) { - const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w]; - UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - *row++ = j2ku_shift(offset + *data++, shift); + break; + case 2: + for (y = 0; y < h; ++y) { + const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w]; + UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + *row++ = j2ku_shift(offset + *data++, shift); + } } - } - break; - case 4: - for (y = 0; y < h; ++y) { - const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w]; - UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - *row++ = j2ku_shift(offset + *data++, shift); + break; + case 4: + for (y = 0; y < h; ++y) { + const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w]; + UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + *row++ = j2ku_shift(offset + *data++, shift); + } } - } - break; + break; } } - static void -j2ku_gray_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, - const UINT8 *tiledata, Imaging im) -{ +j2ku_gray_rgb( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -223,49 +223,51 @@ j2ku_gray_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, } switch (csiz) { - case 1: - for (y = 0; y < h; ++y) { - const UINT8 *data = &tiledata[y * w]; - UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - UINT8 byte = j2ku_shift(offset + *data++, shift); - row[0] = row[1] = row[2] = byte; - row[3] = 0xff; - row += 4; + case 1: + for (y = 0; y < h; ++y) { + const UINT8 *data = &tiledata[y * w]; + UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + UINT8 byte = j2ku_shift(offset + *data++, shift); + row[0] = row[1] = row[2] = byte; + row[3] = 0xff; + row += 4; + } } - } - break; - case 2: - for (y = 0; y < h; ++y) { - const UINT16 *data = (UINT16 *)&tiledata[2 * y * w]; - UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - UINT8 byte = j2ku_shift(offset + *data++, shift); - row[0] = row[1] = row[2] = byte; - row[3] = 0xff; - row += 4; + break; + case 2: + for (y = 0; y < h; ++y) { + const UINT16 *data = (UINT16 *)&tiledata[2 * y * w]; + UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + UINT8 byte = j2ku_shift(offset + *data++, shift); + row[0] = row[1] = row[2] = byte; + row[3] = 0xff; + row += 4; + } } - } - break; - case 4: - for (y = 0; y < h; ++y) { - const UINT32 *data = (UINT32 *)&tiledata[4 * y * w]; - UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; - for (x = 0; x < w; ++x) { - UINT8 byte = j2ku_shift(offset + *data++, shift); - row[0] = row[1] = row[2] = byte; - row[3] = 0xff; - row += 4; + break; + case 4: + for (y = 0; y < h; ++y) { + const UINT32 *data = (UINT32 *)&tiledata[4 * y * w]; + UINT8 *row = (UINT8 *)im->image[y0 + y] + x0; + for (x = 0; x < w; ++x) { + UINT8 byte = j2ku_shift(offset + *data++, shift); + row[0] = row[1] = row[2] = byte; + row[3] = 0xff; + row += 4; + } } - } - break; + break; } } static void -j2ku_graya_la(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, - const UINT8 *tiledata, Imaging im) -{ +j2ku_graya_la( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -304,15 +306,31 @@ j2ku_graya_la(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, UINT32 word = 0, aword = 0, byte; switch (csiz) { - case 1: word = *data++; break; - case 2: word = *(const UINT16 *)data; data += 2; break; - case 4: word = *(const UINT32 *)data; data += 4; break; + case 1: + word = *data++; + break; + case 2: + word = *(const UINT16 *)data; + data += 2; + break; + case 4: + word = *(const UINT32 *)data; + data += 4; + break; } switch (acsiz) { - case 1: aword = *adata++; break; - case 2: aword = *(const UINT16 *)adata; adata += 2; break; - case 4: aword = *(const UINT32 *)adata; adata += 4; break; + case 1: + aword = *adata++; + break; + case 2: + aword = *(const UINT16 *)adata; + adata += 2; + break; + case 4: + aword = *(const UINT32 *)adata; + adata += 4; + break; } byte = j2ku_shift(offset + word, shift); @@ -324,14 +342,17 @@ j2ku_graya_la(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, } static void -j2ku_srgb_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, - const UINT8 *tiledata, Imaging im) -{ +j2ku_srgb_rgb( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; int shifts[3], offsets[3], csiz[3]; + unsigned dx[3], dy[3]; const UINT8 *cdata[3]; const UINT8 *cptr = tiledata; unsigned n, x, y; @@ -341,6 +362,8 @@ j2ku_srgb_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, shifts[n] = 8 - in->comps[n].prec; offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0; csiz[n] = (in->comps[n].prec + 7) >> 3; + dx[n] = (in->comps[n].dx); + dy[n] = (in->comps[n].dy); if (csiz[n] == 3) { csiz[n] = 4; @@ -350,14 +373,14 @@ j2ku_srgb_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, offsets[n] += 1 << (-shifts[n] - 1); } - cptr += csiz[n] * w * h; + cptr += csiz[n] * (w / dx[n]) * (h / dy[n]); } for (y = 0; y < h; ++y) { const UINT8 *data[3]; UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4; for (n = 0; n < 3; ++n) { - data[n] = &cdata[n][csiz[n] * y * w]; + data[n] = &cdata[n][csiz[n] * (y / dy[n]) * (w / dx[n])]; } for (x = 0; x < w; ++x) { @@ -365,9 +388,15 @@ j2ku_srgb_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, UINT32 word = 0; switch (csiz[n]) { - case 1: word = *data[n]++; break; - case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break; - case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break; + case 1: + word = data[n][x / dx[n]]; + break; + case 2: + word = ((const UINT16 *)data[n])[x / dx[n]]; + break; + case 4: + word = ((const UINT32 *)data[n])[x / dx[n]]; + break; } row[n] = j2ku_shift(offsets[n] + word, shifts[n]); @@ -379,14 +408,17 @@ j2ku_srgb_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, } static void -j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, - const UINT8 *tiledata, Imaging im) -{ +j2ku_sycc_rgb( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; int shifts[3], offsets[3], csiz[3]; + unsigned dx[3], dy[3]; const UINT8 *cdata[3]; const UINT8 *cptr = tiledata; unsigned n, x, y; @@ -396,6 +428,8 @@ j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, shifts[n] = 8 - in->comps[n].prec; offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0; csiz[n] = (in->comps[n].prec + 7) >> 3; + dx[n] = (in->comps[n].dx); + dy[n] = (in->comps[n].dy); if (csiz[n] == 3) { csiz[n] = 4; @@ -405,7 +439,7 @@ j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, offsets[n] += 1 << (-shifts[n] - 1); } - cptr += csiz[n] * w * h; + cptr += csiz[n] * (w / dx[n]) * (h / dy[n]); } for (y = 0; y < h; ++y) { @@ -413,7 +447,7 @@ j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4; UINT8 *row_start = row; for (n = 0; n < 3; ++n) { - data[n] = &cdata[n][csiz[n] * y * w]; + data[n] = &cdata[n][csiz[n] * (y / dy[n]) * (w / dx[n])]; } for (x = 0; x < w; ++x) { @@ -421,9 +455,15 @@ j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, UINT32 word = 0; switch (csiz[n]) { - case 1: word = *data[n]++; break; - case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break; - case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break; + case 1: + word = data[n][x / dx[n]]; + break; + case 2: + word = ((const UINT16 *)data[n])[x / dx[n]]; + break; + case 4: + word = ((const UINT32 *)data[n])[x / dx[n]]; + break; } row[n] = j2ku_shift(offsets[n] + word, shifts[n]); @@ -437,14 +477,17 @@ j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, } static void -j2ku_srgba_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, - const UINT8 *tiledata, Imaging im) -{ +j2ku_srgba_rgba( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; int shifts[4], offsets[4], csiz[4]; + unsigned dx[4], dy[4]; const UINT8 *cdata[4]; const UINT8 *cptr = tiledata; unsigned n, x, y; @@ -454,6 +497,8 @@ j2ku_srgba_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, shifts[n] = 8 - in->comps[n].prec; offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0; csiz[n] = (in->comps[n].prec + 7) >> 3; + dx[n] = (in->comps[n].dx); + dy[n] = (in->comps[n].dy); if (csiz[n] == 3) { csiz[n] = 4; @@ -463,14 +508,14 @@ j2ku_srgba_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, offsets[n] += 1 << (-shifts[n] - 1); } - cptr += csiz[n] * w * h; + cptr += csiz[n] * (w / dx[n]) * (h / dy[n]); } for (y = 0; y < h; ++y) { const UINT8 *data[4]; UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4; for (n = 0; n < 4; ++n) { - data[n] = &cdata[n][csiz[n] * y * w]; + data[n] = &cdata[n][csiz[n] * (y / dy[n]) * (w / dx[n])]; } for (x = 0; x < w; ++x) { @@ -478,9 +523,15 @@ j2ku_srgba_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, UINT32 word = 0; switch (csiz[n]) { - case 1: word = *data[n]++; break; - case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break; - case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break; + case 1: + word = data[n][x / dx[n]]; + break; + case 2: + word = ((const UINT16 *)data[n])[x / dx[n]]; + break; + case 4: + word = ((const UINT32 *)data[n])[x / dx[n]]; + break; } row[n] = j2ku_shift(offsets[n] + word, shifts[n]); @@ -491,14 +542,17 @@ j2ku_srgba_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, } static void -j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, - const UINT8 *tiledata, Imaging im) -{ +j2ku_sycca_rgba( + opj_image_t *in, + const JPEG2KTILEINFO *tileinfo, + const UINT8 *tiledata, + Imaging im) { unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; int shifts[4], offsets[4], csiz[4]; + unsigned dx[4], dy[4]; const UINT8 *cdata[4]; const UINT8 *cptr = tiledata; unsigned n, x, y; @@ -508,6 +562,8 @@ j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, shifts[n] = 8 - in->comps[n].prec; offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0; csiz[n] = (in->comps[n].prec + 7) >> 3; + dx[n] = (in->comps[n].dx); + dy[n] = (in->comps[n].dy); if (csiz[n] == 3) { csiz[n] = 4; @@ -517,7 +573,7 @@ j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, offsets[n] += 1 << (-shifts[n] - 1); } - cptr += csiz[n] * w * h; + cptr += csiz[n] * (w / dx[n]) * (h / dy[n]); } for (y = 0; y < h; ++y) { @@ -525,7 +581,7 @@ j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4; UINT8 *row_start = row; for (n = 0; n < 4; ++n) { - data[n] = &cdata[n][csiz[n] * y * w]; + data[n] = &cdata[n][csiz[n] * (y / dy[n]) * (w / dx[n])]; } for (x = 0; x < w; ++x) { @@ -533,9 +589,15 @@ j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, UINT32 word = 0; switch (csiz[n]) { - case 1: word = *data[n]++; break; - case 2: word = *(const UINT16 *)data[n]; data[n] += 2; break; - case 4: word = *(const UINT32 *)data[n]; data[n] += 4; break; + case 1: + word = data[n][x / dx[n]]; + break; + case 2: + word = ((const UINT16 *)data[n])[x / dx[n]]; + break; + case 4: + word = ((const UINT32 *)data[n])[x / dx[n]]; + break; } row[n] = j2ku_shift(offsets[n] + word, shifts[n]); @@ -548,22 +610,22 @@ j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, } static const struct j2k_decode_unpacker j2k_unpackers[] = { - { "L", OPJ_CLRSPC_GRAY, 1, j2ku_gray_l }, - { "I;16", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i }, - { "I;16B", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i }, - { "LA", OPJ_CLRSPC_GRAY, 2, j2ku_graya_la }, - { "RGB", OPJ_CLRSPC_GRAY, 1, j2ku_gray_rgb }, - { "RGB", OPJ_CLRSPC_GRAY, 2, j2ku_gray_rgb }, - { "RGB", OPJ_CLRSPC_SRGB, 3, j2ku_srgb_rgb }, - { "RGB", OPJ_CLRSPC_SYCC, 3, j2ku_sycc_rgb }, - { "RGB", OPJ_CLRSPC_SRGB, 4, j2ku_srgb_rgb }, - { "RGB", OPJ_CLRSPC_SYCC, 4, j2ku_sycc_rgb }, - { "RGBA", OPJ_CLRSPC_GRAY, 1, j2ku_gray_rgb }, - { "RGBA", OPJ_CLRSPC_GRAY, 2, j2ku_graya_la }, - { "RGBA", OPJ_CLRSPC_SRGB, 3, j2ku_srgb_rgb }, - { "RGBA", OPJ_CLRSPC_SYCC, 3, j2ku_sycc_rgb }, - { "RGBA", OPJ_CLRSPC_SRGB, 4, j2ku_srgba_rgba }, - { "RGBA", OPJ_CLRSPC_SYCC, 4, j2ku_sycca_rgba }, + {"L", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_l}, + {"I;16", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_i}, + {"I;16B", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_i}, + {"LA", OPJ_CLRSPC_GRAY, 2, 0, j2ku_graya_la}, + {"RGB", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_rgb}, + {"RGB", OPJ_CLRSPC_GRAY, 2, 0, j2ku_gray_rgb}, + {"RGB", OPJ_CLRSPC_SRGB, 3, 1, j2ku_srgb_rgb}, + {"RGB", OPJ_CLRSPC_SYCC, 3, 1, j2ku_sycc_rgb}, + {"RGB", OPJ_CLRSPC_SRGB, 4, 1, j2ku_srgb_rgb}, + {"RGB", OPJ_CLRSPC_SYCC, 4, 1, j2ku_sycc_rgb}, + {"RGBA", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_rgb}, + {"RGBA", OPJ_CLRSPC_GRAY, 2, 0, j2ku_graya_la}, + {"RGBA", OPJ_CLRSPC_SRGB, 3, 1, j2ku_srgb_rgb}, + {"RGBA", OPJ_CLRSPC_SYCC, 3, 1, j2ku_sycc_rgb}, + {"RGBA", OPJ_CLRSPC_SRGB, 4, 1, j2ku_srgba_rgba}, + {"RGBA", OPJ_CLRSPC_SYCC, 4, 1, j2ku_sycca_rgba}, }; /* -------------------------------------------------------------------- */ @@ -578,9 +640,8 @@ enum { }; static int -j2k_decode_entry(Imaging im, ImagingCodecState state) -{ - JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context; +j2k_decode_entry(Imaging im, ImagingCodecState state) { + JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *)state->context; opj_stream_t *stream = NULL; opj_image_t *image = NULL; opj_codec_t *codec = NULL; @@ -589,8 +650,8 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) j2k_unpacker_t unpack = NULL; size_t buffer_size = 0, tile_bytes = 0; unsigned n, tile_height, tile_width; - int components; - + int subsampling; + int total_component_width = 0; stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE); @@ -645,18 +706,23 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) } /* Check that this image is something we can handle */ - if (image->numcomps < 1 || image->numcomps > 4 - || image->color_space == OPJ_CLRSPC_UNKNOWN) { + if (image->numcomps < 1 || image->numcomps > 4 || + image->color_space == OPJ_CLRSPC_UNKNOWN) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; goto quick_exit; } - for (n = 1; n < image->numcomps; ++n) { + /* + * Find first component with subsampling. + * + * This is a heuristic to determine the colorspace if unspecified. + */ + subsampling = -1; + for (n = 0; n < image->numcomps; ++n) { if (image->comps[n].dx != 1 || image->comps[n].dy != 1) { - state->errcode = IMAGING_CODEC_BROKEN; - state->state = J2K_STATE_FAILED; - goto quick_exit; + subsampling = n; + break; } } @@ -672,12 +738,14 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) If colorspace is unspecified, we assume: - Number of components Colorspace - ----------------------------------------- - 1 gray - 2 gray (+ alpha) - 3 sRGB - 4 sRGB (+ alpha) + Number of components Subsampling Colorspace + ------------------------------------------------------- + 1 Any gray + 2 Any gray (+ alpha) + 3 -1, 0 sRGB + 3 1, 2 YCbCr + 4 -1, 0, 3 sRGB (+ alpha) + 4 1, 2 YCbCr (+ alpha) */ @@ -686,15 +754,32 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) if (color_space == OPJ_CLRSPC_UNSPECIFIED) { switch (image->numcomps) { - case 1: case 2: color_space = OPJ_CLRSPC_GRAY; break; - case 3: case 4: color_space = OPJ_CLRSPC_SRGB; break; + case 1: + case 2: + color_space = OPJ_CLRSPC_GRAY; + break; + case 3: + case 4: + switch (subsampling) { + case -1: + case 0: + case 3: + color_space = OPJ_CLRSPC_SRGB; + break; + case 1: + case 2: + color_space = OPJ_CLRSPC_SYCC; + break; + } + break; } } - for (n = 0; n < sizeof(j2k_unpackers) / sizeof (j2k_unpackers[0]); ++n) { - if (color_space == j2k_unpackers[n].color_space - && image->numcomps == j2k_unpackers[n].components - && strcmp (im->mode, j2k_unpackers[n].mode) == 0) { + for (n = 0; n < sizeof(j2k_unpackers) / sizeof(j2k_unpackers[0]); ++n) { + if (color_space == j2k_unpackers[n].color_space && + image->numcomps == j2k_unpackers[n].components && + (j2k_unpackers[n].subsampling || (subsampling == -1)) && + strcmp(im->mode, j2k_unpackers[n].mode) == 0) { unpack = j2k_unpackers[n].unpacker; break; } @@ -713,14 +798,17 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) OPJ_BOOL should_continue; unsigned correction = (1 << params.cp_reduce) - 1; - if (!opj_read_tile_header(codec, - stream, - &tile_info.tile_index, - &tile_info.data_size, - &tile_info.x0, &tile_info.y0, - &tile_info.x1, &tile_info.y1, - &tile_info.nb_comps, - &should_continue)) { + if (!opj_read_tile_header( + codec, + stream, + &tile_info.tile_index, + &tile_info.data_size, + &tile_info.x0, + &tile_info.y0, + &tile_info.x1, + &tile_info.y1, + &tile_info.nb_comps, + &should_continue)) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; goto quick_exit; @@ -740,36 +828,51 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) /* Check the tile bounds; if the tile is outside the image area, or if it has a negative width or height (i.e. the coordinates are swapped), bail. */ - if (tile_info.x0 >= tile_info.x1 - || tile_info.y0 >= tile_info.y1 - || tile_info.x0 < 0 - || tile_info.y0 < 0 - || (OPJ_UINT32)tile_info.x0 < image->x0 - || (OPJ_UINT32)tile_info.y0 < image->y0 - || (OPJ_INT32)(tile_info.x1 - image->x0) > im->xsize - || (OPJ_INT32)(tile_info.y1 - image->y0) > im->ysize) { + if (tile_info.x0 >= tile_info.x1 || tile_info.y0 >= tile_info.y1 || + tile_info.x0 < 0 || tile_info.y0 < 0 || + (OPJ_UINT32)tile_info.x0 < image->x0 || + (OPJ_UINT32)tile_info.y0 < image->y0 || + (OPJ_INT32)(tile_info.x1 - image->x0) > im->xsize || + (OPJ_INT32)(tile_info.y1 - image->y0) > im->ysize) { + state->errcode = IMAGING_CODEC_BROKEN; + state->state = J2K_STATE_FAILED; + goto quick_exit; + } + + if (tile_info.nb_comps != image->numcomps) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; goto quick_exit; } /* Sometimes the tile_info.datasize we get back from openjpeg - is less than numcomps*w*h, and we overflow in the + is less than sum(comp_bytes)*w*h, and we overflow in the shuffle stage */ tile_width = tile_info.x1 - tile_info.x0; tile_height = tile_info.y1 - tile_info.y0; - components = tile_info.nb_comps == 3 ? 4 : tile_info.nb_comps; - if (( tile_width > UINT_MAX / components ) || - ( tile_height > UINT_MAX / components ) || - ( tile_width > UINT_MAX / (tile_height * components )) || - ( tile_height > UINT_MAX / (tile_width * components ))) { + + /* Total component width = sum (component_width) e.g, it's + legal for an la file to have a 1 byte width for l, and 4 for + a, and then a malicious file could have a smaller tile_bytes + */ + + for (n=0; n < tile_info.nb_comps; n++) { + // see csize /acsize calcs + int csize = (image->comps[n].prec + 7) >> 3; + csize = (csize == 3) ? 4 : csize; + total_component_width += csize; + } + if ((tile_width > UINT_MAX / total_component_width) || + (tile_height > UINT_MAX / total_component_width) || + (tile_width > UINT_MAX / (tile_height * total_component_width)) || + (tile_height > UINT_MAX / (tile_width * total_component_width))) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; goto quick_exit; } - tile_bytes = tile_width * tile_height * components; + tile_bytes = tile_width * tile_height * total_component_width; if (tile_bytes > tile_info.data_size) { tile_info.data_size = tile_bytes; @@ -777,22 +880,26 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) if (buffer_size < tile_info.data_size) { /* malloc check ok, overflow and tile size sanity check above */ - UINT8 *new = realloc (state->buffer, tile_info.data_size); + UINT8 *new = realloc(state->buffer, tile_info.data_size); if (!new) { state->errcode = IMAGING_CODEC_MEMORY; state->state = J2K_STATE_FAILED; goto quick_exit; } + /* Undefined behavior, sometimes decode_tile_data doesn't + fill the buffer and we do things with it later, leading + to valgrind errors. */ + memset(new, 0, tile_info.data_size); state->buffer = new; buffer_size = tile_info.data_size; } - - if (!opj_decode_tile_data(codec, - tile_info.tile_index, - (OPJ_BYTE *)state->buffer, - tile_info.data_size, - stream)) { + if (!opj_decode_tile_data( + codec, + tile_info.tile_index, + (OPJ_BYTE *)state->buffer, + tile_info.data_size, + stream)) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; goto quick_exit; @@ -811,12 +918,12 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) state->errcode = IMAGING_CODEC_END; if (context->pfile) { - if(fclose(context->pfile)){ + if (fclose(context->pfile)) { context->pfile = NULL; } } - quick_exit: +quick_exit: if (codec) { opj_destroy_codec(codec); } @@ -831,10 +938,8 @@ j2k_decode_entry(Imaging im, ImagingCodecState state) } int -ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ - - if (bytes){ +ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { + if (bytes) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; return -1; @@ -867,7 +972,7 @@ ImagingJpeg2KDecodeCleanup(ImagingCodecState state) { JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *)state->context; if (context->error_msg) { - free ((void *)context->error_msg); + free((void *)context->error_msg); } context->error_msg = NULL; @@ -876,8 +981,7 @@ ImagingJpeg2KDecodeCleanup(ImagingCodecState state) { } const char * -ImagingJpeg2KVersion(void) -{ +ImagingJpeg2KVersion(void) { return opj_version(); } diff --git a/src/libImaging/Jpeg2KEncode.c b/src/libImaging/Jpeg2KEncode.c index 5b18e472c..701853159 100644 --- a/src/libImaging/Jpeg2KEncode.c +++ b/src/libImaging/Jpeg2KEncode.c @@ -19,26 +19,24 @@ #include "Jpeg2K.h" -#define CINEMA_24_CS_LENGTH 1302083 -#define CINEMA_48_CS_LENGTH 651041 +#define CINEMA_24_CS_LENGTH 1302083 +#define CINEMA_48_CS_LENGTH 651041 #define COMP_24_CS_MAX_LENGTH 1041666 -#define COMP_48_CS_MAX_LENGTH 520833 +#define COMP_48_CS_MAX_LENGTH 520833 /* -------------------------------------------------------------------- */ /* Error handler */ /* -------------------------------------------------------------------- */ static void -j2k_error(const char *msg, void *client_data) -{ - JPEG2KENCODESTATE *state = (JPEG2KENCODESTATE *) client_data; +j2k_error(const char *msg, void *client_data) { + JPEG2KENCODESTATE *state = (JPEG2KENCODESTATE *)client_data; free((void *)state->error_msg); state->error_msg = strdup(msg); } static void -j2k_warn(const char *msg, void *client_data) -{ +j2k_warn(const char *msg, void *client_data) { // Null handler } @@ -47,8 +45,7 @@ j2k_warn(const char *msg, void *client_data) /* -------------------------------------------------------------------- */ static OPJ_SIZE_T -j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) -{ +j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) { ImagingCodecState state = (ImagingCodecState)p_user_data; unsigned int result; @@ -57,16 +54,14 @@ j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) return result ? result : (OPJ_SIZE_T)-1; } - static OPJ_OFF_T -j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) -{ +j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) { ImagingCodecState state = (ImagingCodecState)p_user_data; char *buffer; int result; /* Explicitly write zeros */ - buffer = calloc(p_nb_bytes,1); + buffer = calloc(p_nb_bytes, 1); if (!buffer) { return (OPJ_OFF_T)-1; } @@ -79,8 +74,7 @@ j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) } static OPJ_BOOL -j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data) -{ +j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data) { ImagingCodecState state = (ImagingCodecState)p_user_data; off_t pos = 0; @@ -94,16 +88,13 @@ j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data) /* Encoder */ /* -------------------------------------------------------------------- */ -typedef void (*j2k_pack_tile_t)(Imaging im, UINT8 *buf, - unsigned x0, unsigned y0, - unsigned w, unsigned h); +typedef void (*j2k_pack_tile_t)( + Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h); static void -j2k_pack_l(Imaging im, UINT8 *buf, - unsigned x0, unsigned y0, unsigned w, unsigned h) -{ +j2k_pack_l(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) { UINT8 *ptr = buf; - unsigned x,y; + unsigned x, y; for (y = 0; y < h; ++y) { UINT8 *data = (UINT8 *)(im->image[y + y0] + x0); for (x = 0; x < w; ++x) { @@ -113,11 +104,9 @@ j2k_pack_l(Imaging im, UINT8 *buf, } static void -j2k_pack_i16(Imaging im, UINT8 *buf, - unsigned x0, unsigned y0, unsigned w, unsigned h) -{ +j2k_pack_i16(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) { UINT8 *ptr = buf; - unsigned x,y; + unsigned x, y; for (y = 0; y < h; ++y) { UINT8 *data = (UINT8 *)(im->image[y + y0] + x0); for (x = 0; x < w; ++x) { @@ -127,14 +116,11 @@ j2k_pack_i16(Imaging im, UINT8 *buf, } } - static void -j2k_pack_la(Imaging im, UINT8 *buf, - unsigned x0, unsigned y0, unsigned w, unsigned h) -{ +j2k_pack_la(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) { UINT8 *ptr = buf; UINT8 *ptra = buf + w * h; - unsigned x,y; + unsigned x, y; for (y = 0; y < h; ++y) { UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0); for (x = 0; x < w; ++x) { @@ -146,13 +132,11 @@ j2k_pack_la(Imaging im, UINT8 *buf, } static void -j2k_pack_rgb(Imaging im, UINT8 *buf, - unsigned x0, unsigned y0, unsigned w, unsigned h) -{ +j2k_pack_rgb(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) { UINT8 *pr = buf; UINT8 *pg = pr + w * h; UINT8 *pb = pg + w * h; - unsigned x,y; + unsigned x, y; for (y = 0; y < h; ++y) { UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0); for (x = 0; x < w; ++x) { @@ -165,14 +149,13 @@ j2k_pack_rgb(Imaging im, UINT8 *buf, } static void -j2k_pack_rgba(Imaging im, UINT8 *buf, - unsigned x0, unsigned y0, unsigned w, unsigned h) -{ +j2k_pack_rgba( + Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) { UINT8 *pr = buf; UINT8 *pg = pr + w * h; UINT8 *pb = pg + w * h; UINT8 *pa = pb + w * h; - unsigned x,y; + unsigned x, y; for (y = 0; y < h; ++y) { UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0); for (x = 0; x < w; ++x) { @@ -192,8 +175,7 @@ enum { }; static void -j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) -{ +j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) { float rate; int n; @@ -215,8 +197,9 @@ j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) params->irreversible = 1; if (params->cp_cinema == OPJ_CINEMA4K_24) { - float max_rate = ((float)(components * im->xsize * im->ysize * 8) - / (CINEMA_24_CS_LENGTH * 8)); + float max_rate = + ((float)(components * im->xsize * im->ysize * 8) / + (CINEMA_24_CS_LENGTH * 8)); params->POC[0].tile = 1; params->POC[0].resno0 = 0; @@ -239,8 +222,9 @@ j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) if (params->tcp_rates[0] == 0) { params->tcp_rates[n] = max_rate; } else { - rate = ((float)(components * im->xsize * im->ysize * 8) - / (params->tcp_rates[n] * 8)); + rate = + ((float)(components * im->xsize * im->ysize * 8) / + (params->tcp_rates[n] * 8)); if (rate > CINEMA_24_CS_LENGTH) { params->tcp_rates[n] = max_rate; } @@ -249,16 +233,18 @@ j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) params->max_comp_size = COMP_24_CS_MAX_LENGTH; } else { - float max_rate = ((float)(components * im->xsize * im->ysize * 8) - / (CINEMA_48_CS_LENGTH * 8)); + float max_rate = + ((float)(components * im->xsize * im->ysize * 8) / + (CINEMA_48_CS_LENGTH * 8)); for (n = 0; n < params->tcp_numlayers; ++n) { rate = 0; if (params->tcp_rates[0] == 0) { params->tcp_rates[n] = max_rate; } else { - rate = ((float)(components * im->xsize * im->ysize * 8) - / (params->tcp_rates[n] * 8)); + rate = + ((float)(components * im->xsize * im->ysize * 8) / + (params->tcp_rates[n] * 8)); if (rate > CINEMA_48_CS_LENGTH) { params->tcp_rates[n] = max_rate; } @@ -270,8 +256,7 @@ j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) } static int -j2k_encode_entry(Imaging im, ImagingCodecState state) -{ +j2k_encode_entry(Imaging im, ImagingCodecState state) { JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context; opj_stream_t *stream = NULL; opj_image_t *image = NULL; @@ -312,35 +297,35 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) #endif /* Setup an opj_image */ - if (strcmp (im->mode, "L") == 0) { + if (strcmp(im->mode, "L") == 0) { components = 1; color_space = OPJ_CLRSPC_GRAY; pack = j2k_pack_l; - } else if (strcmp (im->mode, "I;16") == 0){ + } else if (strcmp(im->mode, "I;16") == 0) { components = 1; color_space = OPJ_CLRSPC_GRAY; pack = j2k_pack_i16; prec = 16; bpp = 12; - } else if (strcmp (im->mode, "I;16B") == 0){ + } else if (strcmp(im->mode, "I;16B") == 0) { components = 1; color_space = OPJ_CLRSPC_GRAY; pack = j2k_pack_i16; prec = 16; bpp = 12; - } else if (strcmp (im->mode, "LA") == 0) { + } else if (strcmp(im->mode, "LA") == 0) { components = 2; color_space = OPJ_CLRSPC_GRAY; pack = j2k_pack_la; - } else if (strcmp (im->mode, "RGB") == 0) { + } else if (strcmp(im->mode, "RGB") == 0) { components = 3; color_space = OPJ_CLRSPC_SRGB; pack = j2k_pack_rgb; - } else if (strcmp (im->mode, "YCbCr") == 0) { + } else if (strcmp(im->mode, "YCbCr") == 0) { components = 3; color_space = OPJ_CLRSPC_SYCC; pack = j2k_pack_rgb; - } else if (strcmp (im->mode, "RGBA") == 0) { + } else if (strcmp(im->mode, "RGBA") == 0) { components = 4; color_space = OPJ_CLRSPC_SRGB; pack = j2k_pack_rgba; @@ -400,8 +385,9 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) float *pq; if (len > 0) { - if ((unsigned)len > sizeof(params.tcp_rates) / sizeof(params.tcp_rates[0])) { - len = sizeof(params.tcp_rates)/sizeof(params.tcp_rates[0]); + if ((size_t)len > + sizeof(params.tcp_rates) / sizeof(params.tcp_rates[0])) { + len = sizeof(params.tcp_rates) / sizeof(params.tcp_rates[0]); } params.tcp_numlayers = (int)len; @@ -431,16 +417,16 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) params.numresolution = context->num_resolutions; } - if (context->cblk_width >= 4 && context->cblk_width <= 1024 - && context->cblk_height >= 4 && context->cblk_height <= 1024 - && context->cblk_width * context->cblk_height <= 4096) { + if (context->cblk_width >= 4 && context->cblk_width <= 1024 && + context->cblk_height >= 4 && context->cblk_height <= 1024 && + context->cblk_width * context->cblk_height <= 4096) { params.cblockw_init = context->cblk_width; params.cblockh_init = context->cblk_height; } - if (context->precinct_width >= 4 && context->precinct_height >= 4 - && context->precinct_width >= context->cblk_width - && context->precinct_height > context->cblk_height) { + if (context->precinct_width >= 4 && context->precinct_height >= 4 && + context->precinct_width >= context->cblk_width && + context->precinct_height > context->cblk_height) { params.prcw_init[0] = context->precinct_width; params.prch_init[0] = context->precinct_height; params.res_spec = 1; @@ -454,22 +440,28 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) params.cp_cinema = context->cinema_mode; switch (params.cp_cinema) { - case OPJ_OFF: - params.cp_rsiz = OPJ_STD_RSIZ; - break; - case OPJ_CINEMA2K_24: - case OPJ_CINEMA2K_48: - params.cp_rsiz = OPJ_CINEMA2K; - if (params.numresolution > 6) { - params.numresolution = 6; + case OPJ_OFF: + params.cp_rsiz = OPJ_STD_RSIZ; + break; + case OPJ_CINEMA2K_24: + case OPJ_CINEMA2K_48: + params.cp_rsiz = OPJ_CINEMA2K; + if (params.numresolution > 6) { + params.numresolution = 6; + } + break; + case OPJ_CINEMA4K_24: + params.cp_rsiz = OPJ_CINEMA4K; + if (params.numresolution > 7) { + params.numresolution = 7; + } + break; + } + + if (!context->num_resolutions) { + while (tile_width < (1 << (params.numresolution - 1U)) || tile_height < (1 << (params.numresolution - 1U))) { + params.numresolution -= 1; } - break; - case OPJ_CINEMA4K_24: - params.cp_rsiz = OPJ_CINEMA4K; - if (params.numresolution > 7) { - params.numresolution = 7; - } - break; } if (context->cinema_mode != OPJ_OFF) { @@ -504,24 +496,24 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) } /* Write each tile */ - tiles_x = (im->xsize + (params.image_offset_x0 - params.cp_tx0) - + tile_width - 1) / tile_width; - tiles_y = (im->ysize + (params.image_offset_y0 - params.cp_ty0) - + tile_height - 1) / tile_height; + tiles_x = (im->xsize + (params.image_offset_x0 - params.cp_tx0) + tile_width - 1) / + tile_width; + tiles_y = (im->ysize + (params.image_offset_y0 - params.cp_ty0) + tile_height - 1) / + tile_height; /* check for integer overflow for the malloc line, checking any expression that may multiply either tile_width or tile_height */ _overflow_scale_factor = components * prec; - if (( tile_width > UINT_MAX / _overflow_scale_factor ) || - ( tile_height > UINT_MAX / _overflow_scale_factor ) || - ( tile_width > UINT_MAX / (tile_height * _overflow_scale_factor )) || - ( tile_height > UINT_MAX / (tile_width * _overflow_scale_factor ))) { + if ((tile_width > UINT_MAX / _overflow_scale_factor) || + (tile_height > UINT_MAX / _overflow_scale_factor) || + (tile_width > UINT_MAX / (tile_height * _overflow_scale_factor)) || + (tile_height > UINT_MAX / (tile_width * _overflow_scale_factor))) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; goto quick_exit; } /* malloc check ok, checked for overflow above */ - state->buffer = malloc (tile_width * tile_height * components * prec / 8); + state->buffer = malloc(tile_width * tile_height * components * prec / 8); if (!state->buffer) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; @@ -564,8 +556,7 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) data_size = pixw * pixh * components * prec / 8; - if (!opj_write_tile(codec, tile_ndx++, state->buffer, - data_size, stream)) { + if (!opj_write_tile(codec, tile_ndx++, state->buffer, data_size, stream)) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; goto quick_exit; @@ -583,7 +574,7 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) state->state = J2K_STATE_DONE; ret = -1; - quick_exit: +quick_exit: if (codec) { opj_destroy_codec(codec); } @@ -598,14 +589,12 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) } int -ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) -{ +ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { if (state->state == J2K_STATE_FAILED) { return -1; } if (state->state == J2K_STATE_START) { - state->state = J2K_STATE_ENCODING; return j2k_encode_entry(im, state); @@ -628,12 +617,11 @@ ImagingJpeg2KEncodeCleanup(ImagingCodecState state) { } if (context->error_msg) { - free ((void *)context->error_msg); + free((void *)context->error_msg); } context->error_msg = NULL; - return -1; } diff --git a/src/libImaging/JpegDecode.c b/src/libImaging/JpegDecode.c index fb6112044..55d10a81a 100644 --- a/src/libImaging/JpegDecode.c +++ b/src/libImaging/JpegDecode.c @@ -21,10 +21,9 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" -#ifdef HAVE_LIBJPEG +#ifdef HAVE_LIBJPEG #undef HAVE_PROTOTYPES #undef HAVE_STDLIB_H @@ -37,7 +36,6 @@ #include "Jpeg.h" - #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) @@ -50,20 +48,19 @@ char *libjpeg_turbo_version = NULL; #endif int -ImagingJpegUseJCSExtensions() -{ +ImagingJpegUseJCSExtensions() { int use_jcs_extensions = 0; - #ifdef JCS_EXTENSIONS - #if defined(LIBJPEG_TURBO_VERSION_NUMBER) - #if LIBJPEG_TURBO_VERSION_NUMBER >= 1002010 - use_jcs_extensions = 1; - #endif - #else - if (libjpeg_turbo_version) { - use_jcs_extensions = strcmp(libjpeg_turbo_version, "1.2.1") >= 0; - } - #endif - #endif +#ifdef JCS_EXTENSIONS +#if defined(LIBJPEG_TURBO_VERSION_NUMBER) +#if LIBJPEG_TURBO_VERSION_NUMBER >= 1002010 + use_jcs_extensions = 1; +#endif +#else + if (libjpeg_turbo_version) { + use_jcs_extensions = strcmp(libjpeg_turbo_version, "1.2.1") >= 0; + } +#endif +#endif return use_jcs_extensions; } @@ -72,24 +69,19 @@ ImagingJpegUseJCSExtensions() /* -------------------------------------------------------------------- */ METHODDEF(void) -stub(j_decompress_ptr cinfo) -{ - /* empty */ -} +stub(j_decompress_ptr cinfo) { /* empty */ } METHODDEF(boolean) -fill_input_buffer(j_decompress_ptr cinfo) -{ +fill_input_buffer(j_decompress_ptr cinfo) { /* Suspension */ return FALSE; } METHODDEF(void) -skip_input_data(j_decompress_ptr cinfo, long num_bytes) -{ - JPEGSOURCE* source = (JPEGSOURCE*) cinfo->src; +skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + JPEGSOURCE *source = (JPEGSOURCE *)cinfo->src; - if (num_bytes > (long) source->pub.bytes_in_buffer) { + if (num_bytes > (long)source->pub.bytes_in_buffer) { /* We need to skip more data than we have in the buffer. This will force the JPEG library to suspend decoding. */ source->skip = num_bytes - source->pub.bytes_in_buffer; @@ -103,50 +95,42 @@ skip_input_data(j_decompress_ptr cinfo, long num_bytes) } } - GLOBAL(void) -jpeg_buffer_src(j_decompress_ptr cinfo, JPEGSOURCE* source) -{ - cinfo->src = (void*) source; +jpeg_buffer_src(j_decompress_ptr cinfo, JPEGSOURCE *source) { + cinfo->src = (void *)source; - /* Prepare for suspending reader */ - source->pub.init_source = stub; - source->pub.fill_input_buffer = fill_input_buffer; - source->pub.skip_input_data = skip_input_data; - source->pub.resync_to_restart = jpeg_resync_to_restart; - source->pub.term_source = stub; - source->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + /* Prepare for suspending reader */ + source->pub.init_source = stub; + source->pub.fill_input_buffer = fill_input_buffer; + source->pub.skip_input_data = skip_input_data; + source->pub.resync_to_restart = jpeg_resync_to_restart; + source->pub.term_source = stub; + source->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - source->skip = 0; + source->skip = 0; } - /* -------------------------------------------------------------------- */ /* Error handler */ /* -------------------------------------------------------------------- */ METHODDEF(void) -error(j_common_ptr cinfo) -{ - JPEGERROR* error; - error = (JPEGERROR*) cinfo->err; - longjmp(error->setjmp_buffer, 1); +error(j_common_ptr cinfo) { + JPEGERROR *error; + error = (JPEGERROR *)cinfo->err; + longjmp(error->setjmp_buffer, 1); } METHODDEF(void) -output(j_common_ptr cinfo) -{ - /* nothing */ -} +output(j_common_ptr cinfo) { /* nothing */ } /* -------------------------------------------------------------------- */ /* Decoder */ /* -------------------------------------------------------------------- */ int -ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ - JPEGSTATE* context = (JPEGSTATE*) state->context; +ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { + JPEGSTATE *context = (JPEGSTATE *)state->context; int ok; if (setjmp(context->error.setjmp_buffer)) { @@ -157,7 +141,6 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t by } if (!state->state) { - /* Setup decompression context */ context->cinfo.err = jpeg_std_error(&context->error.pub); context->error.pub.error_exit = error; @@ -167,7 +150,6 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t by /* Ready to decode */ state->state = 1; - } /* Load the source buffer */ @@ -182,137 +164,137 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t by } switch (state->state) { + case 1: - case 1: + /* Read JPEG header, until we find an image body. */ + do { + /* Note that we cannot return unless we have decoded + as much data as possible. */ + ok = jpeg_read_header(&context->cinfo, FALSE); - /* Read JPEG header, until we find an image body. */ - do { + } while (ok == JPEG_HEADER_TABLES_ONLY); - /* Note that we cannot return unless we have decoded - as much data as possible. */ - ok = jpeg_read_header(&context->cinfo, FALSE); + if (ok == JPEG_SUSPENDED) { + break; + } - } while (ok == JPEG_HEADER_TABLES_ONLY); + /* Decoder settings */ - if (ok == JPEG_SUSPENDED) { - break; - } + /* jpegmode indicates whats in the file; if not set, we'll + trust the decoder */ + if (strcmp(context->jpegmode, "L") == 0) { + context->cinfo.jpeg_color_space = JCS_GRAYSCALE; + } else if (strcmp(context->jpegmode, "RGB") == 0) { + context->cinfo.jpeg_color_space = JCS_RGB; + } else if (strcmp(context->jpegmode, "CMYK") == 0) { + context->cinfo.jpeg_color_space = JCS_CMYK; + } else if (strcmp(context->jpegmode, "YCbCr") == 0) { + context->cinfo.jpeg_color_space = JCS_YCbCr; + } else if (strcmp(context->jpegmode, "YCbCrK") == 0) { + context->cinfo.jpeg_color_space = JCS_YCCK; + } - /* Decoder settings */ - - /* jpegmode indicates whats in the file; if not set, we'll - trust the decoder */ - if (strcmp(context->jpegmode, "L") == 0) { - context->cinfo.jpeg_color_space = JCS_GRAYSCALE; - } else if (strcmp(context->jpegmode, "RGB") == 0) { - context->cinfo.jpeg_color_space = JCS_RGB; - } else if (strcmp(context->jpegmode, "CMYK") == 0) { - context->cinfo.jpeg_color_space = JCS_CMYK; - } else if (strcmp(context->jpegmode, "YCbCr") == 0) { - context->cinfo.jpeg_color_space = JCS_YCbCr; - } else if (strcmp(context->jpegmode, "YCbCrK") == 0) { - context->cinfo.jpeg_color_space = JCS_YCCK; - } - - /* rawmode indicates what we want from the decoder. if not - set, conversions are disabled */ - if (strcmp(context->rawmode, "L") == 0) { - context->cinfo.out_color_space = JCS_GRAYSCALE; - } else if (strcmp(context->rawmode, "RGB") == 0) { - context->cinfo.out_color_space = JCS_RGB; - } - #ifdef JCS_EXTENSIONS - else if (strcmp(context->rawmode, "RGBX") == 0) { + /* rawmode indicates what we want from the decoder. if not + set, conversions are disabled */ + if (strcmp(context->rawmode, "L") == 0) { + context->cinfo.out_color_space = JCS_GRAYSCALE; + } else if (strcmp(context->rawmode, "RGB") == 0) { + context->cinfo.out_color_space = JCS_RGB; + } +#ifdef JCS_EXTENSIONS + else if (strcmp(context->rawmode, "RGBX") == 0) { context->cinfo.out_color_space = JCS_EXT_RGBX; - } - #endif - else if (strcmp(context->rawmode, "CMYK") == 0 || - strcmp(context->rawmode, "CMYK;I") == 0) { - context->cinfo.out_color_space = JCS_CMYK; - } else if (strcmp(context->rawmode, "YCbCr") == 0) { - context->cinfo.out_color_space = JCS_YCbCr; - } else if (strcmp(context->rawmode, "YCbCrK") == 0) { - context->cinfo.out_color_space = JCS_YCCK; - } else { - /* Disable decoder conversions */ - context->cinfo.jpeg_color_space = JCS_UNKNOWN; - context->cinfo.out_color_space = JCS_UNKNOWN; - } + } +#endif + else if ( + strcmp(context->rawmode, "CMYK") == 0 || + strcmp(context->rawmode, "CMYK;I") == 0) { + context->cinfo.out_color_space = JCS_CMYK; + } else if (strcmp(context->rawmode, "YCbCr") == 0) { + context->cinfo.out_color_space = JCS_YCbCr; + } else if (strcmp(context->rawmode, "YCbCrK") == 0) { + context->cinfo.out_color_space = JCS_YCCK; + } else { + /* Disable decoder conversions */ + context->cinfo.jpeg_color_space = JCS_UNKNOWN; + context->cinfo.out_color_space = JCS_UNKNOWN; + } - if (context->scale > 1) { - context->cinfo.scale_num = 1; - context->cinfo.scale_denom = context->scale; - } - if (context->draft) { - context->cinfo.do_fancy_upsampling = FALSE; - context->cinfo.dct_method = JDCT_FASTEST; - } + if (context->scale > 1) { + context->cinfo.scale_num = 1; + context->cinfo.scale_denom = context->scale; + } + if (context->draft) { + context->cinfo.do_fancy_upsampling = FALSE; + context->cinfo.dct_method = JDCT_FASTEST; + } - state->state++; - /* fall through */ + state->state++; + /* fall through */ - case 2: + case 2: - /* Set things up for decompression (this processes the entire - file if necessary to return data line by line) */ - if (!jpeg_start_decompress(&context->cinfo)) { - break; - } + /* Set things up for decompression (this processes the entire + file if necessary to return data line by line) */ + if (!jpeg_start_decompress(&context->cinfo)) { + break; + } - state->state++; - /* fall through */ + state->state++; + /* fall through */ - case 3: + case 3: - /* Decompress a single line of data */ - ok = 1; - while (state->y < state->ysize) { - ok = jpeg_read_scanlines(&context->cinfo, &state->buffer, 1); + /* Decompress a single line of data */ + ok = 1; + while (state->y < state->ysize) { + ok = jpeg_read_scanlines(&context->cinfo, &state->buffer, 1); + if (ok != 1) { + break; + } + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->buffer, + state->xsize); + state->y++; + } if (ok != 1) { break; } - state->shuffle((UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->buffer, - state->xsize); - state->y++; - } - if (ok != 1) { - break; - } - state->state++; - /* fall through */ + state->state++; + /* fall through */ - case 4: + case 4: - /* Finish decompression */ - if (!jpeg_finish_decompress(&context->cinfo)) { - /* FIXME: add strictness mode test */ - if (state->y < state->ysize) { - break; + /* Finish decompression */ + if (!jpeg_finish_decompress(&context->cinfo)) { + /* FIXME: add strictness mode test */ + if (state->y < state->ysize) { + break; + } } - } - - /* Clean up */ - jpeg_destroy_decompress(&context->cinfo); - /* if (jerr.pub.num_warnings) return BROKEN; */ - return -1; + /* Clean up */ + jpeg_destroy_decompress(&context->cinfo); + /* if (jerr.pub.num_warnings) return BROKEN; */ + return -1; } /* Return number of bytes consumed */ return context->source.pub.next_input_byte - buf; - } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ -int ImagingJpegDecodeCleanup(ImagingCodecState state){ +int +ImagingJpegDecodeCleanup(ImagingCodecState state) { /* called to free the decompression engine when the decode terminates due to a corrupt or truncated image */ - JPEGSTATE* context = (JPEGSTATE*) state->context; + JPEGSTATE *context = (JPEGSTATE *)state->context; /* Clean up */ jpeg_destroy_decompress(&context->cinfo); @@ -320,4 +302,3 @@ int ImagingJpegDecodeCleanup(ImagingCodecState state){ } #endif - diff --git a/src/libImaging/JpegEncode.c b/src/libImaging/JpegEncode.c index ab730d92d..a44debcaf 100644 --- a/src/libImaging/JpegEncode.c +++ b/src/libImaging/JpegEncode.c @@ -19,10 +19,9 @@ * See the README file for details on usage and redistribution. */ - #include "Imaging.h" -#ifdef HAVE_LIBJPEG +#ifdef HAVE_LIBJPEG #undef HAVE_PROTOTYPES #undef HAVE_STDLIB_H @@ -40,51 +39,42 @@ /* -------------------------------------------------------------------- */ METHODDEF(void) -stub(j_compress_ptr cinfo) -{ - /* empty */ -} +stub(j_compress_ptr cinfo) { /* empty */ } METHODDEF(boolean) -empty_output_buffer (j_compress_ptr cinfo) -{ +empty_output_buffer(j_compress_ptr cinfo) { /* Suspension */ return FALSE; } GLOBAL(void) -jpeg_buffer_dest(j_compress_ptr cinfo, JPEGDESTINATION* destination) -{ - cinfo->dest = (void*) destination; +jpeg_buffer_dest(j_compress_ptr cinfo, JPEGDESTINATION *destination) { + cinfo->dest = (void *)destination; destination->pub.init_destination = stub; destination->pub.empty_output_buffer = empty_output_buffer; destination->pub.term_destination = stub; } - /* -------------------------------------------------------------------- */ /* Error handler */ /* -------------------------------------------------------------------- */ METHODDEF(void) -error(j_common_ptr cinfo) -{ - JPEGERROR* error; - error = (JPEGERROR*) cinfo->err; - (*cinfo->err->output_message) (cinfo); +error(j_common_ptr cinfo) { + JPEGERROR *error; + error = (JPEGERROR *)cinfo->err; + (*cinfo->err->output_message)(cinfo); longjmp(error->setjmp_buffer, 1); } - /* -------------------------------------------------------------------- */ /* Encoder */ /* -------------------------------------------------------------------- */ int -ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) -{ - JPEGENCODERSTATE* context = (JPEGENCODERSTATE*) state->context; +ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { + JPEGENCODERSTATE *context = (JPEGENCODERSTATE *)state->context; int ok; if (setjmp(context->error.setjmp_buffer)) { @@ -95,7 +85,6 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) } if (!state->state) { - /* Setup compression context (very similar to the decoder) */ context->cinfo.err = jpeg_std_error(&context->error.pub); context->error.pub.error_exit = error; @@ -106,7 +95,6 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) /* Ready to encode */ state->state = 1; - } /* Load the destination buffer */ @@ -114,7 +102,6 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->destination.pub.free_in_buffer = bytes; switch (state->state) { - case 1: context->cinfo.image_width = state->xsize; @@ -136,11 +123,11 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) case 32: context->cinfo.input_components = 4; context->cinfo.in_color_space = JCS_CMYK; - #ifdef JCS_EXTENSIONS +#ifdef JCS_EXTENSIONS if (strcmp(context->rawmode, "RGBX") == 0) { context->cinfo.in_color_space = JCS_EXT_RGBX; } - #endif +#endif break; default: state->errcode = IMAGING_CODEC_CONFIG; @@ -159,15 +146,20 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) quality = context->quality; } for (i = 0; i < context->qtablesLen; i++) { - jpeg_add_quant_table(&context->cinfo, i, &context->qtables[i * DCTSIZE2], - quality, FALSE); + jpeg_add_quant_table( + &context->cinfo, + i, + &context->qtables[i * DCTSIZE2], + quality, + FALSE); context->cinfo.comp_info[i].quant_tbl_no = i; last_q = i; } if (context->qtablesLen == 1) { - // jpeg_set_defaults created two qtables internally, but we only wanted one. - jpeg_add_quant_table(&context->cinfo, 1, &context->qtables[0], - quality, FALSE); + // jpeg_set_defaults created two qtables internally, but we only + // wanted one. + jpeg_add_quant_table( + &context->cinfo, 1, &context->qtables[0], quality, FALSE); } for (i = last_q; i < context->cinfo.num_components; i++) { context->cinfo.comp_info[i].quant_tbl_no = last_q; @@ -177,9 +169,8 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) } /* Set subsampling options */ - switch (context->subsampling) - { - case 0: /* 1x1 1x1 1x1 (4:4:4) : None */ + switch (context->subsampling) { + case 0: /* 1x1 1x1 1x1 (4:4:4) : None */ { context->cinfo.comp_info[0].h_samp_factor = 1; context->cinfo.comp_info[0].v_samp_factor = 1; @@ -189,7 +180,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->cinfo.comp_info[2].v_samp_factor = 1; break; } - case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */ + case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 1; @@ -199,7 +190,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->cinfo.comp_info[2].v_samp_factor = 1; break; } - case 2: /* 2x2, 1x1, 1x1 (4:2:0) : High */ + case 2: /* 2x2, 1x1, 1x1 (4:2:0) : High */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 2; @@ -209,23 +200,22 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->cinfo.comp_info[2].v_samp_factor = 1; break; } - default: - { + default: { /* Use the lib's default */ break; } - } - if (context->progressive) { - jpeg_simple_progression(&context->cinfo); - } - context->cinfo.smoothing_factor = context->smooth; - context->cinfo.optimize_coding = (boolean) context->optimize; - if (context->xdpi > 0 && context->ydpi > 0) { - context->cinfo.write_JFIF_header = TRUE; - context->cinfo.density_unit = 1; /* dots per inch */ - context->cinfo.X_density = context->xdpi; - context->cinfo.Y_density = context->ydpi; - } + } + if (context->progressive) { + jpeg_simple_progression(&context->cinfo); + } + context->cinfo.smoothing_factor = context->smooth; + context->cinfo.optimize_coding = (boolean)context->optimize; + if (context->xdpi > 0 && context->ydpi > 0) { + context->cinfo.write_JFIF_header = TRUE; + context->cinfo.density_unit = 1; /* dots per inch */ + context->cinfo.X_density = context->xdpi; + context->cinfo.Y_density = context->ydpi; + } switch (context->streamtype) { case 1: /* tables only -- not yet implemented */ @@ -248,13 +238,16 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) case 2: // check for exif len + 'APP1' header bytes - if (context->rawExifLen + 5 > context->destination.pub.free_in_buffer){ + if (context->rawExifLen + 5 > context->destination.pub.free_in_buffer) { break; } - //add exif header - if (context->rawExifLen > 0){ - jpeg_write_marker(&context->cinfo, JPEG_APP0+1, - (unsigned char*)context->rawExif, context->rawExifLen); + // add exif header + if (context->rawExifLen > 0) { + jpeg_write_marker( + &context->cinfo, + JPEG_APP0 + 1, + (unsigned char *)context->rawExif, + context->rawExifLen); } state->state++; @@ -267,8 +260,10 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) if (n > context->destination.pub.free_in_buffer) { n = context->destination.pub.free_in_buffer; } - memcpy(context->destination.pub.next_output_byte, - context->extra + context->extra_offset, n); + memcpy( + context->destination.pub.next_output_byte, + context->extra + context->extra_offset, + n); context->destination.pub.next_output_byte += n; context->destination.pub.free_in_buffer -= n; context->extra_offset += n; @@ -282,15 +277,17 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) } case 4: - if (1024 > context->destination.pub.free_in_buffer){ + if (1024 > context->destination.pub.free_in_buffer) { break; } ok = 1; while (state->y < state->ysize) { - state->shuffle(state->buffer, - (UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->xsize); + state->shuffle( + state->buffer, + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->xsize); ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1); if (ok != 1) { break; @@ -330,17 +327,14 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) /* if (jerr.pub.num_warnings) return BROKEN; */ state->errcode = IMAGING_CODEC_END; break; - } /* Return number of bytes in output buffer */ return context->destination.pub.next_output_byte - buf; - } -const char* -ImagingJpegVersion(void) -{ +const char * +ImagingJpegVersion(void) { static char version[20]; sprintf(version, "%d.%d", JPEG_LIB_VERSION / 10, JPEG_LIB_VERSION % 10); return version; diff --git a/src/libImaging/Matrix.c b/src/libImaging/Matrix.c index e02b7b312..137ed242a 100644 --- a/src/libImaging/Matrix.c +++ b/src/libImaging/Matrix.c @@ -13,65 +13,60 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - -#define CLIPF(v) ((v <= 0.0) ? 0 : (v >= 255.0F) ? 255 : (UINT8) v) - +#define CLIPF(v) ((v <= 0.0) ? 0 : (v >= 255.0F) ? 255 : (UINT8)v) Imaging -ImagingConvertMatrix(Imaging im, const char *mode, float m[]) -{ +ImagingConvertMatrix(Imaging im, const char *mode, float m[]) { Imaging imOut; int x, y; /* Assume there's enough data in the buffer */ if (!im) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (strcmp(mode, "L") == 0 && im->bands == 3) { - imOut = ImagingNewDirty("L", im->xsize, im->ysize); if (!imOut) { return NULL; } for (y = 0; y < im->ysize; y++) { - UINT8* in = (UINT8*) im->image[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT8 *in = (UINT8 *)im->image[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < im->xsize; x++) { - float v = m[0]*in[0] + m[1]*in[1] + m[2]*in[2] + m[3] + 0.5; + float v = m[0] * in[0] + m[1] * in[1] + m[2] * in[2] + m[3] + 0.5; out[x] = CLIPF(v); in += 4; } } } else if (strlen(mode) == 3 && im->bands == 3) { - imOut = ImagingNewDirty(mode, im->xsize, im->ysize); if (!imOut) { return NULL; } for (y = 0; y < im->ysize; y++) { - UINT8* in = (UINT8*) im->image[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT8 *in = (UINT8 *)im->image[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < im->xsize; x++) { - float v0 = m[0]*in[0] + m[1]*in[1] + m[2]*in[2] + m[3] + 0.5; - float v1 = m[4]*in[0] + m[5]*in[1] + m[6]*in[2] + m[7] + 0.5; - float v2 = m[8]*in[0] + m[9]*in[1] + m[10]*in[2] + m[11] + 0.5; + float v0 = m[0] * in[0] + m[1] * in[1] + m[2] * in[2] + m[3] + 0.5; + float v1 = m[4] * in[0] + m[5] * in[1] + m[6] * in[2] + m[7] + 0.5; + float v2 = m[8] * in[0] + m[9] * in[1] + m[10] * in[2] + m[11] + 0.5; out[0] = CLIPF(v0); out[1] = CLIPF(v1); out[2] = CLIPF(v2); - in += 4; out += 4; + in += 4; + out += 4; } } } else { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } return imOut; diff --git a/src/libImaging/ModeFilter.c b/src/libImaging/ModeFilter.c index b1cf7442c..757cbc3fb 100644 --- a/src/libImaging/ModeFilter.c +++ b/src/libImaging/ModeFilter.c @@ -16,8 +16,7 @@ #include "Imaging.h" Imaging -ImagingModeFilter(Imaging im, int size) -{ +ImagingModeFilter(Imaging im, int size) { Imaging imOut; int x, y, i; int xx, yy; @@ -26,7 +25,7 @@ ImagingModeFilter(Imaging im, int size) int histogram[256]; if (!im || im->bands != 1 || im->type != IMAGING_TYPE_UINT8) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); @@ -37,9 +36,8 @@ ImagingModeFilter(Imaging im, int size) size = size / 2; for (y = 0; y < imOut->ysize; y++) { - UINT8* out = &IMAGING_PIXEL_L(imOut, 0, y); + UINT8 *out = &IMAGING_PIXEL_L(imOut, 0, y); for (x = 0; x < imOut->xsize; x++) { - /* calculate histogram over current area */ /* FIXME: brute force! to improve, update the histogram @@ -50,7 +48,7 @@ ImagingModeFilter(Imaging im, int size) memset(histogram, 0, sizeof(histogram)); for (yy = y - size; yy <= y + size; yy++) { if (yy >= 0 && yy < imOut->ysize) { - UINT8* in = &IMAGING_PIXEL_L(im, 0, yy); + UINT8 *in = &IMAGING_PIXEL_L(im, 0, yy); for (xx = x - size; xx <= x + size; xx++) { if (xx >= 0 && xx < imOut->xsize) { histogram[in[xx]]++; @@ -65,7 +63,7 @@ ImagingModeFilter(Imaging im, int size) for (i = 1; i < 256; i++) { if (histogram[i] > maxcount) { maxcount = histogram[i]; - maxpixel = (UINT8) i; + maxpixel = (UINT8)i; } } @@ -74,9 +72,7 @@ ImagingModeFilter(Imaging im, int size) } else { out[x] = IMAGING_PIXEL_L(im, x, y); } - } - } ImagingCopyPalette(imOut, im); diff --git a/src/libImaging/Negative.c b/src/libImaging/Negative.c index 09c946bbe..70b96c397 100644 --- a/src/libImaging/Negative.c +++ b/src/libImaging/Negative.c @@ -16,18 +16,15 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - Imaging -ImagingNegative(Imaging im) -{ +ImagingNegative(Imaging im) { Imaging imOut; int x, y; if (!im) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); @@ -43,4 +40,3 @@ ImagingNegative(Imaging im) return imOut; } - diff --git a/src/libImaging/Offset.c b/src/libImaging/Offset.c index 29f038153..91ee91083 100644 --- a/src/libImaging/Offset.c +++ b/src/libImaging/Offset.c @@ -14,18 +14,15 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - Imaging -ImagingOffset(Imaging im, int xoffset, int yoffset) -{ +ImagingOffset(Imaging im, int xoffset, int yoffset) { int x, y; Imaging imOut; if (!im) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); @@ -48,13 +45,13 @@ ImagingOffset(Imaging im, int xoffset, int yoffset) yoffset += im->ysize; } -#define OFFSET(image)\ - for (y = 0; y < im->ysize; y++) {\ - for (x = 0; x < im->xsize; x++) {\ - int yi = (y + yoffset) % im->ysize;\ - int xi = (x + xoffset) % im->xsize;\ - imOut->image[y][x] = im->image[yi][xi];\ - }\ +#define OFFSET(image) \ + for (y = 0; y < im->ysize; y++) { \ + for (x = 0; x < im->xsize; x++) { \ + int yi = (y + yoffset) % im->ysize; \ + int xi = (x + xoffset) % im->xsize; \ + imOut->image[y][x] = im->image[yi][xi]; \ + } \ } if (im->image8) { diff --git a/src/libImaging/Pack.c b/src/libImaging/Pack.c index 0be7ad8c9..2fdee919f 100644 --- a/src/libImaging/Pack.c +++ b/src/libImaging/Pack.c @@ -1,4 +1,4 @@ - /* +/* * The Python Imaging Library. * $Id$ * @@ -25,7 +25,6 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #define R 0 @@ -41,20 +40,28 @@ /* byte swapping macros */ -#define C16N\ - (out[0]=tmp[0], out[1]=tmp[1]); -#define C16S\ - (out[1]=tmp[0], out[0]=tmp[1]); -#define C32N\ - (out[0]=tmp[0], out[1]=tmp[1], out[2]=tmp[2], out[3]=tmp[3]); -#define C32S\ - (out[3]=tmp[0], out[2]=tmp[1], out[1]=tmp[2], out[0]=tmp[3]); -#define C64N\ - (out[0]=tmp[0], out[1]=tmp[1], out[2]=tmp[2], out[3]=tmp[3],\ - out[4]=tmp[4], out[5]=tmp[5], out[6]=tmp[6], out[7]=tmp[7]); -#define C64S\ - (out[7]=tmp[0], out[6]=tmp[1], out[5]=tmp[2], out[4]=tmp[3],\ - out[3]=tmp[4], out[2]=tmp[5], out[1]=tmp[6], out[0]=tmp[7]); +#define C16N (out[0] = tmp[0], out[1] = tmp[1]); +#define C16S (out[1] = tmp[0], out[0] = tmp[1]); +#define C32N (out[0] = tmp[0], out[1] = tmp[1], out[2] = tmp[2], out[3] = tmp[3]); +#define C32S (out[3] = tmp[0], out[2] = tmp[1], out[1] = tmp[2], out[0] = tmp[3]); +#define C64N \ + (out[0] = tmp[0], \ + out[1] = tmp[1], \ + out[2] = tmp[2], \ + out[3] = tmp[3], \ + out[4] = tmp[4], \ + out[5] = tmp[5], \ + out[6] = tmp[6], \ + out[7] = tmp[7]); +#define C64S \ + (out[7] = tmp[0], \ + out[6] = tmp[1], \ + out[5] = tmp[2], \ + out[4] = tmp[3], \ + out[3] = tmp[4], \ + out[2] = tmp[5], \ + out[1] = tmp[6], \ + out[0] = tmp[7]); #ifdef WORDS_BIGENDIAN #define C16B C16N @@ -72,13 +79,12 @@ #define C64L C64N #endif - static void -pack1(UINT8* out, const UINT8* in, int pixels) -{ +pack1(UINT8 *out, const UINT8 *in, int pixels) { int i, m, b; /* bilevel (black is 0) */ - b = 0; m = 128; + b = 0; + m = 128; for (i = 0; i < pixels; i++) { if (in[i] != 0) { b |= m; @@ -86,7 +92,8 @@ pack1(UINT8* out, const UINT8* in, int pixels) m >>= 1; if (m == 0) { *out++ = b; - b = 0; m = 128; + b = 0; + m = 128; } } if (m != 128) { @@ -95,11 +102,11 @@ pack1(UINT8* out, const UINT8* in, int pixels) } static void -pack1I(UINT8* out, const UINT8* in, int pixels) -{ +pack1I(UINT8 *out, const UINT8 *in, int pixels) { int i, m, b; /* bilevel (black is 1) */ - b = 0; m = 128; + b = 0; + m = 128; for (i = 0; i < pixels; i++) { if (in[i] == 0) { b |= m; @@ -107,7 +114,8 @@ pack1I(UINT8* out, const UINT8* in, int pixels) m >>= 1; if (m == 0) { *out++ = b; - b = 0; m = 128; + b = 0; + m = 128; } } if (m != 128) { @@ -116,19 +124,20 @@ pack1I(UINT8* out, const UINT8* in, int pixels) } static void -pack1R(UINT8* out, const UINT8* in, int pixels) -{ +pack1R(UINT8 *out, const UINT8 *in, int pixels) { int i, m, b; /* bilevel, lsb first (black is 0) */ - b = 0; m = 1; + b = 0; + m = 1; for (i = 0; i < pixels; i++) { if (in[i] != 0) { b |= m; } m <<= 1; - if (m == 256){ + if (m == 256) { *out++ = b; - b = 0; m = 1; + b = 0; + m = 1; } } if (m != 1) { @@ -137,19 +146,20 @@ pack1R(UINT8* out, const UINT8* in, int pixels) } static void -pack1IR(UINT8* out, const UINT8* in, int pixels) -{ +pack1IR(UINT8 *out, const UINT8 *in, int pixels) { int i, m, b; /* bilevel, lsb first (black is 1) */ - b = 0; m = 1; + b = 0; + m = 1; for (i = 0; i < pixels; i++) { if (in[i] == 0) { b |= m; } m <<= 1; - if (m == 256){ + if (m == 256) { *out++ = b; - b = 0; m = 1; + b = 0; + m = 1; } } if (m != 1) { @@ -158,8 +168,7 @@ pack1IR(UINT8* out, const UINT8* in, int pixels) } static void -pack1L(UINT8* out, const UINT8* in, int pixels) -{ +pack1L(UINT8 *out, const UINT8 *in, int pixels) { int i; /* bilevel, stored as bytes */ for (i = 0; i < pixels; i++) { @@ -168,12 +177,11 @@ pack1L(UINT8* out, const UINT8* in, int pixels) } static void -packP4(UINT8* out, const UINT8* in, int pixels) -{ +packP4(UINT8 *out, const UINT8 *in, int pixels) { while (pixels >= 2) { - *out++ = (in[0] << 4) | - (in[1] & 15); - in += 2; pixels -= 2; + *out++ = (in[0] << 4) | (in[1] & 15); + in += 2; + pixels -= 2; } if (pixels) { @@ -182,34 +190,27 @@ packP4(UINT8* out, const UINT8* in, int pixels) } static void -packP2(UINT8* out, const UINT8* in, int pixels) -{ +packP2(UINT8 *out, const UINT8 *in, int pixels) { while (pixels >= 4) { - *out++ = (in[0] << 6) | - ((in[1] & 3) << 4) | - ((in[2] & 3) << 2) | - (in[3] & 3); - in += 4; pixels -= 4; + *out++ = (in[0] << 6) | ((in[1] & 3) << 4) | ((in[2] & 3) << 2) | (in[3] & 3); + in += 4; + pixels -= 4; } switch (pixels) { - case 3: - out[0] = (in[0] << 6) | - ((in[1] & 3) << 4) | - ((in[2] & 3) << 2); - break; - case 2: - out[0] = (in[0] << 6) | - ((in[1] & 3) << 4); - break; - case 1: - out[0] = (in[0] << 6); + case 3: + out[0] = (in[0] << 6) | ((in[1] & 3) << 4) | ((in[2] & 3) << 2); + break; + case 2: + out[0] = (in[0] << 6) | ((in[1] & 3) << 4); + break; + case 1: + out[0] = (in[0] << 6); } } static void -packL16(UINT8* out, const UINT8* in, int pixels) -{ +packL16(UINT8 *out, const UINT8 *in, int pixels) { int i; /* L -> L;16, e.g: \xff77 -> \x00\xff\x00\x77 */ for (i = 0; i < pixels; i++) { @@ -220,8 +221,7 @@ packL16(UINT8* out, const UINT8* in, int pixels) } static void -packL16B(UINT8* out, const UINT8* in, int pixels) -{ +packL16B(UINT8 *out, const UINT8 *in, int pixels) { int i; /* L -> L;16B, e.g: \xff77 -> \xff\x00\x77\x00 */ for (i = 0; i < pixels; i++) { @@ -231,34 +231,31 @@ packL16B(UINT8* out, const UINT8* in, int pixels) } } - static void -packLA(UINT8* out, const UINT8* in, int pixels) -{ +packLA(UINT8 *out, const UINT8 *in, int pixels) { int i; /* LA, pixel interleaved */ for (i = 0; i < pixels; i++) { out[0] = in[R]; out[1] = in[A]; - out += 2; in += 4; + out += 2; + in += 4; } } static void -packLAL(UINT8* out, const UINT8* in, int pixels) -{ +packLAL(UINT8 *out, const UINT8 *in, int pixels) { int i; /* LA, line interleaved */ for (i = 0; i < pixels; i++) { out[i] = in[R]; - out[i+pixels] = in[A]; + out[i + pixels] = in[A]; in += 4; } } void -ImagingPackRGB(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackRGB(UINT8 *out, const UINT8 *in, int pixels) { int i = 0; /* RGB triplets */ #ifdef __sparc @@ -267,25 +264,25 @@ ImagingPackRGB(UINT8* out, const UINT8* in, int pixels) out[0] = in[R]; out[1] = in[G]; out[2] = in[B]; - out += 3; in += 4; + out += 3; + in += 4; } #else - for (; i < pixels-1; i++) { + for (; i < pixels - 1; i++) { memcpy(out, in + i * 4, 4); out += 3; } for (; i < pixels; i++) { - out[0] = in[i*4+R]; - out[1] = in[i*4+G]; - out[2] = in[i*4+B]; + out[0] = in[i * 4 + R]; + out[1] = in[i * 4 + G]; + out[2] = in[i * 4 + B]; out += 3; } #endif } void -ImagingPackXRGB(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackXRGB(UINT8 *out, const UINT8 *in, int pixels) { int i; /* XRGB, triplets with left padding */ for (i = 0; i < pixels; i++) { @@ -293,26 +290,26 @@ ImagingPackXRGB(UINT8* out, const UINT8* in, int pixels) out[1] = in[R]; out[2] = in[G]; out[3] = in[B]; - out += 4; in += 4; + out += 4; + in += 4; } } void -ImagingPackBGR(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackBGR(UINT8 *out, const UINT8 *in, int pixels) { int i; /* RGB, reversed bytes */ for (i = 0; i < pixels; i++) { out[0] = in[B]; out[1] = in[G]; out[2] = in[R]; - out += 3; in += 4; + out += 3; + in += 4; } } void -ImagingPackBGRX(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackBGRX(UINT8 *out, const UINT8 *in, int pixels) { int i; /* BGRX, reversed bytes with right padding */ for (i = 0; i < pixels; i++) { @@ -320,13 +317,13 @@ ImagingPackBGRX(UINT8* out, const UINT8* in, int pixels) out[1] = in[G]; out[2] = in[R]; out[3] = 0; - out += 4; in += 4; + out += 4; + in += 4; } } void -ImagingPackXBGR(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackXBGR(UINT8 *out, const UINT8 *in, int pixels) { int i; /* XBGR, reversed bytes with left padding */ for (i = 0; i < pixels; i++) { @@ -334,13 +331,13 @@ ImagingPackXBGR(UINT8* out, const UINT8* in, int pixels) out[1] = in[B]; out[2] = in[G]; out[3] = in[R]; - out += 4; in += 4; + out += 4; + in += 4; } } void -ImagingPackBGRA(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackBGRA(UINT8 *out, const UINT8 *in, int pixels) { int i; /* BGRX, reversed bytes with right padding */ for (i = 0; i < pixels; i++) { @@ -348,13 +345,13 @@ ImagingPackBGRA(UINT8* out, const UINT8* in, int pixels) out[1] = in[G]; out[2] = in[R]; out[3] = in[A]; - out += 4; in += 4; + out += 4; + in += 4; } } void -ImagingPackABGR(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackABGR(UINT8 *out, const UINT8 *in, int pixels) { int i; /* XBGR, reversed bytes with left padding */ for (i = 0; i < pixels; i++) { @@ -362,13 +359,13 @@ ImagingPackABGR(UINT8* out, const UINT8* in, int pixels) out[1] = in[B]; out[2] = in[G]; out[3] = in[R]; - out += 4; in += 4; + out += 4; + in += 4; } } void -ImagingPackBGRa(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackBGRa(UINT8 *out, const UINT8 *in, int pixels) { int i; /* BGRa, reversed bytes with premultiplied alpha */ for (i = 0; i < pixels; i++) { @@ -377,43 +374,41 @@ ImagingPackBGRa(UINT8* out, const UINT8* in, int pixels) out[0] = MULDIV255(in[B], alpha, tmp); out[1] = MULDIV255(in[G], alpha, tmp); out[2] = MULDIV255(in[R], alpha, tmp); - out += 4; in += 4; + out += 4; + in += 4; } } static void -packRGBL(UINT8* out, const UINT8* in, int pixels) -{ +packRGBL(UINT8 *out, const UINT8 *in, int pixels) { int i; /* RGB, line interleaved */ for (i = 0; i < pixels; i++) { out[i] = in[R]; - out[i+pixels] = in[G]; - out[i+pixels+pixels] = in[B]; + out[i + pixels] = in[G]; + out[i + pixels + pixels] = in[B]; in += 4; } } static void -packRGBXL(UINT8* out, const UINT8* in, int pixels) -{ +packRGBXL(UINT8 *out, const UINT8 *in, int pixels) { int i; /* RGBX, line interleaved */ for (i = 0; i < pixels; i++) { out[i] = in[R]; - out[i+pixels] = in[G]; - out[i+pixels+pixels] = in[B]; - out[i+pixels+pixels+pixels] = in[X]; + out[i + pixels] = in[G]; + out[i + pixels + pixels] = in[B]; + out[i + pixels + pixels + pixels] = in[X]; in += 4; } } static void -packI16B(UINT8* out, const UINT8* in_, int pixels) -{ +packI16B(UINT8 *out, const UINT8 *in_, int pixels) { int i; UINT16 tmp_; - UINT8* tmp = (UINT8*) &tmp_; + UINT8 *tmp = (UINT8 *)&tmp_; for (i = 0; i < pixels; i++) { INT32 in; memcpy(&in, in_, sizeof(in)); @@ -425,96 +420,91 @@ packI16B(UINT8* out, const UINT8* in_, int pixels) tmp_ = in; } C16B; - out += 2; in_ += sizeof(in); + out += 2; + in_ += sizeof(in); } } static void -packI16N_I16B(UINT8* out, const UINT8* in, int pixels){ +packI16N_I16B(UINT8 *out, const UINT8 *in, int pixels) { int i; - UINT8* tmp = (UINT8*) in; + UINT8 *tmp = (UINT8 *)in; for (i = 0; i < pixels; i++) { C16B; - out += 2; tmp += 2; + out += 2; + tmp += 2; } - } static void -packI16N_I16(UINT8* out, const UINT8* in, int pixels){ +packI16N_I16(UINT8 *out, const UINT8 *in, int pixels) { int i; - UINT8* tmp = (UINT8*) in; + UINT8 *tmp = (UINT8 *)in; for (i = 0; i < pixels; i++) { C16L; - out += 2; tmp += 2; + out += 2; + tmp += 2; } } - static void -packI32S(UINT8* out, const UINT8* in, int pixels) -{ +packI32S(UINT8 *out, const UINT8 *in, int pixels) { int i; - UINT8* tmp = (UINT8*) in; + UINT8 *tmp = (UINT8 *)in; for (i = 0; i < pixels; i++) { C32L; - out += 4; tmp += 4; + out += 4; + tmp += 4; } } void -ImagingPackLAB(UINT8* out, const UINT8* in, int pixels) -{ +ImagingPackLAB(UINT8 *out, const UINT8 *in, int pixels) { int i; /* LAB triplets */ for (i = 0; i < pixels; i++) { out[0] = in[0]; out[1] = in[1] ^ 128; /* signed in outside world */ out[2] = in[2] ^ 128; - out += 3; in += 4; + out += 3; + in += 4; } } static void -copy1(UINT8* out, const UINT8* in, int pixels) -{ +copy1(UINT8 *out, const UINT8 *in, int pixels) { /* L, P */ memcpy(out, in, pixels); } static void -copy2(UINT8* out, const UINT8* in, int pixels) -{ +copy2(UINT8 *out, const UINT8 *in, int pixels) { /* I;16, etc */ - memcpy(out, in, pixels*2); + memcpy(out, in, pixels * 2); } static void -copy3(UINT8* out, const UINT8* in, int pixels) -{ +copy3(UINT8 *out, const UINT8 *in, int pixels) { /* BGR;24, etc */ - memcpy(out, in, pixels*3); + memcpy(out, in, pixels * 3); } static void -copy4(UINT8* out, const UINT8* in, int pixels) -{ +copy4(UINT8 *out, const UINT8 *in, int pixels) { /* RGBA, CMYK quadruples */ - memcpy(out, in, 4*pixels); + memcpy(out, in, 4 * pixels); } static void -copy4I(UINT8* out, const UINT8* in, int pixels) -{ +copy4I(UINT8 *out, const UINT8 *in, int pixels) { /* RGBA, CMYK quadruples, inverted */ int i; - for (i = 0; i < pixels*4; i++) { + for (i = 0; i < pixels * 4; i++) { out[i] = ~in[i]; } } static void -band0(UINT8* out, const UINT8* in, int pixels) -{ +band0(UINT8 *out, const UINT8 *in, int pixels) { int i; for (i = 0; i < pixels; i++, in += 4) { out[i] = in[0]; @@ -522,8 +512,7 @@ band0(UINT8* out, const UINT8* in, int pixels) } static void -band1(UINT8* out, const UINT8* in, int pixels) -{ +band1(UINT8 *out, const UINT8 *in, int pixels) { int i; for (i = 0; i < pixels; i++, in += 4) { out[i] = in[1]; @@ -531,8 +520,7 @@ band1(UINT8* out, const UINT8* in, int pixels) } static void -band2(UINT8* out, const UINT8* in, int pixels) -{ +band2(UINT8 *out, const UINT8 *in, int pixels) { int i; for (i = 0; i < pixels; i++, in += 4) { out[i] = in[2]; @@ -540,8 +528,7 @@ band2(UINT8* out, const UINT8* in, int pixels) } static void -band3(UINT8* out, const UINT8* in, int pixels) -{ +band3(UINT8 *out, const UINT8 *in, int pixels) { int i; for (i = 0; i < pixels; i++, in += 4) { out[i] = in[3]; @@ -549,143 +536,141 @@ band3(UINT8* out, const UINT8* in, int pixels) } static struct { - const char* mode; - const char* rawmode; + const char *mode; + const char *rawmode; int bits; ImagingShuffler pack; } packers[] = { /* bilevel */ - {"1", "1", 1, pack1}, - {"1", "1;I", 1, pack1I}, - {"1", "1;R", 1, pack1R}, - {"1", "1;IR", 1, pack1IR}, - {"1", "L", 8, pack1L}, + {"1", "1", 1, pack1}, + {"1", "1;I", 1, pack1I}, + {"1", "1;R", 1, pack1R}, + {"1", "1;IR", 1, pack1IR}, + {"1", "L", 8, pack1L}, /* greyscale */ - {"L", "L", 8, copy1}, - {"L", "L;16", 16, packL16}, - {"L", "L;16B", 16, packL16B}, + {"L", "L", 8, copy1}, + {"L", "L;16", 16, packL16}, + {"L", "L;16B", 16, packL16B}, /* greyscale w. alpha */ - {"LA", "LA", 16, packLA}, - {"LA", "LA;L", 16, packLAL}, + {"LA", "LA", 16, packLA}, + {"LA", "LA;L", 16, packLAL}, /* greyscale w. alpha premultiplied */ - {"La", "La", 16, packLA}, + {"La", "La", 16, packLA}, /* palette */ - {"P", "P;1", 1, pack1}, - {"P", "P;2", 2, packP2}, - {"P", "P;4", 4, packP4}, - {"P", "P", 8, copy1}, + {"P", "P;1", 1, pack1}, + {"P", "P;2", 2, packP2}, + {"P", "P;4", 4, packP4}, + {"P", "P", 8, copy1}, /* palette w. alpha */ - {"PA", "PA", 16, packLA}, - {"PA", "PA;L", 16, packLAL}, + {"PA", "PA", 16, packLA}, + {"PA", "PA;L", 16, packLAL}, /* true colour */ - {"RGB", "RGB", 24, ImagingPackRGB}, - {"RGB", "RGBX", 32, copy4}, - {"RGB", "XRGB", 32, ImagingPackXRGB}, - {"RGB", "BGR", 24, ImagingPackBGR}, - {"RGB", "BGRX", 32, ImagingPackBGRX}, - {"RGB", "XBGR", 32, ImagingPackXBGR}, - {"RGB", "RGB;L", 24, packRGBL}, - {"RGB", "R", 8, band0}, - {"RGB", "G", 8, band1}, - {"RGB", "B", 8, band2}, + {"RGB", "RGB", 24, ImagingPackRGB}, + {"RGB", "RGBX", 32, copy4}, + {"RGB", "XRGB", 32, ImagingPackXRGB}, + {"RGB", "BGR", 24, ImagingPackBGR}, + {"RGB", "BGRX", 32, ImagingPackBGRX}, + {"RGB", "XBGR", 32, ImagingPackXBGR}, + {"RGB", "RGB;L", 24, packRGBL}, + {"RGB", "R", 8, band0}, + {"RGB", "G", 8, band1}, + {"RGB", "B", 8, band2}, /* true colour w. alpha */ - {"RGBA", "RGBA", 32, copy4}, - {"RGBA", "RGBA;L", 32, packRGBXL}, - {"RGBA", "RGB", 24, ImagingPackRGB}, - {"RGBA", "BGR", 24, ImagingPackBGR}, - {"RGBA", "BGRA", 32, ImagingPackBGRA}, - {"RGBA", "ABGR", 32, ImagingPackABGR}, - {"RGBA", "BGRa", 32, ImagingPackBGRa}, - {"RGBA", "R", 8, band0}, - {"RGBA", "G", 8, band1}, - {"RGBA", "B", 8, band2}, - {"RGBA", "A", 8, band3}, + {"RGBA", "RGBA", 32, copy4}, + {"RGBA", "RGBA;L", 32, packRGBXL}, + {"RGBA", "RGB", 24, ImagingPackRGB}, + {"RGBA", "BGR", 24, ImagingPackBGR}, + {"RGBA", "BGRA", 32, ImagingPackBGRA}, + {"RGBA", "ABGR", 32, ImagingPackABGR}, + {"RGBA", "BGRa", 32, ImagingPackBGRa}, + {"RGBA", "R", 8, band0}, + {"RGBA", "G", 8, band1}, + {"RGBA", "B", 8, band2}, + {"RGBA", "A", 8, band3}, /* true colour w. alpha premultiplied */ - {"RGBa", "RGBa", 32, copy4}, - {"RGBa", "BGRa", 32, ImagingPackBGRA}, - {"RGBa", "aBGR", 32, ImagingPackABGR}, + {"RGBa", "RGBa", 32, copy4}, + {"RGBa", "BGRa", 32, ImagingPackBGRA}, + {"RGBa", "aBGR", 32, ImagingPackABGR}, /* true colour w. padding */ - {"RGBX", "RGBX", 32, copy4}, - {"RGBX", "RGBX;L", 32, packRGBXL}, - {"RGBX", "RGB", 24, ImagingPackRGB}, - {"RGBX", "BGR", 24, ImagingPackBGR}, - {"RGBX", "BGRX", 32, ImagingPackBGRX}, - {"RGBX", "XBGR", 32, ImagingPackXBGR}, - {"RGBX", "R", 8, band0}, - {"RGBX", "G", 8, band1}, - {"RGBX", "B", 8, band2}, - {"RGBX", "X", 8, band3}, + {"RGBX", "RGBX", 32, copy4}, + {"RGBX", "RGBX;L", 32, packRGBXL}, + {"RGBX", "RGB", 24, ImagingPackRGB}, + {"RGBX", "BGR", 24, ImagingPackBGR}, + {"RGBX", "BGRX", 32, ImagingPackBGRX}, + {"RGBX", "XBGR", 32, ImagingPackXBGR}, + {"RGBX", "R", 8, band0}, + {"RGBX", "G", 8, band1}, + {"RGBX", "B", 8, band2}, + {"RGBX", "X", 8, band3}, /* colour separation */ - {"CMYK", "CMYK", 32, copy4}, - {"CMYK", "CMYK;I", 32, copy4I}, - {"CMYK", "CMYK;L", 32, packRGBXL}, - {"CMYK", "C", 8, band0}, - {"CMYK", "M", 8, band1}, - {"CMYK", "Y", 8, band2}, - {"CMYK", "K", 8, band3}, + {"CMYK", "CMYK", 32, copy4}, + {"CMYK", "CMYK;I", 32, copy4I}, + {"CMYK", "CMYK;L", 32, packRGBXL}, + {"CMYK", "C", 8, band0}, + {"CMYK", "M", 8, band1}, + {"CMYK", "Y", 8, band2}, + {"CMYK", "K", 8, band3}, /* video (YCbCr) */ - {"YCbCr", "YCbCr", 24, ImagingPackRGB}, - {"YCbCr", "YCbCr;L", 24, packRGBL}, - {"YCbCr", "YCbCrX", 32, copy4}, - {"YCbCr", "YCbCrK", 32, copy4}, - {"YCbCr", "Y", 8, band0}, - {"YCbCr", "Cb", 8, band1}, - {"YCbCr", "Cr", 8, band2}, + {"YCbCr", "YCbCr", 24, ImagingPackRGB}, + {"YCbCr", "YCbCr;L", 24, packRGBL}, + {"YCbCr", "YCbCrX", 32, copy4}, + {"YCbCr", "YCbCrK", 32, copy4}, + {"YCbCr", "Y", 8, band0}, + {"YCbCr", "Cb", 8, band1}, + {"YCbCr", "Cr", 8, band2}, /* LAB Color */ - {"LAB", "LAB", 24, ImagingPackLAB}, - {"LAB", "L", 8, band0}, - {"LAB", "A", 8, band1}, - {"LAB", "B", 8, band2}, + {"LAB", "LAB", 24, ImagingPackLAB}, + {"LAB", "L", 8, band0}, + {"LAB", "A", 8, band1}, + {"LAB", "B", 8, band2}, /* HSV */ - {"HSV", "HSV", 24, ImagingPackRGB}, - {"HSV", "H", 8, band0}, - {"HSV", "S", 8, band1}, - {"HSV", "V", 8, band2}, + {"HSV", "HSV", 24, ImagingPackRGB}, + {"HSV", "H", 8, band0}, + {"HSV", "S", 8, band1}, + {"HSV", "V", 8, band2}, /* integer */ - {"I", "I", 32, copy4}, - {"I", "I;16B", 16, packI16B}, - {"I", "I;32S", 32, packI32S}, - {"I", "I;32NS", 32, copy4}, + {"I", "I", 32, copy4}, + {"I", "I;16B", 16, packI16B}, + {"I", "I;32S", 32, packI32S}, + {"I", "I;32NS", 32, copy4}, /* floating point */ - {"F", "F", 32, copy4}, - {"F", "F;32F", 32, packI32S}, - {"F", "F;32NF", 32, copy4}, + {"F", "F", 32, copy4}, + {"F", "F;32F", 32, packI32S}, + {"F", "F;32NF", 32, copy4}, /* storage modes */ - {"I;16", "I;16", 16, copy2}, - {"I;16", "I;16B", 16, packI16N_I16B}, - {"I;16B", "I;16B", 16, copy2}, - {"I;16L", "I;16L", 16, copy2}, - {"I;16", "I;16N", 16, packI16N_I16}, // LibTiff native->image endian. - {"I;16L", "I;16N", 16, packI16N_I16}, - {"I;16B", "I;16N", 16, packI16N_I16B}, - {"BGR;15", "BGR;15", 16, copy2}, - {"BGR;16", "BGR;16", 16, copy2}, - {"BGR;24", "BGR;24", 24, copy3}, + {"I;16", "I;16", 16, copy2}, + {"I;16", "I;16B", 16, packI16N_I16B}, + {"I;16B", "I;16B", 16, copy2}, + {"I;16L", "I;16L", 16, copy2}, + {"I;16", "I;16N", 16, packI16N_I16}, // LibTiff native->image endian. + {"I;16L", "I;16N", 16, packI16N_I16}, + {"I;16B", "I;16N", 16, packI16N_I16B}, + {"BGR;15", "BGR;15", 16, copy2}, + {"BGR;16", "BGR;16", 16, copy2}, + {"BGR;24", "BGR;24", 24, copy3}, {NULL} /* sentinel */ }; - ImagingShuffler -ImagingFindPacker(const char* mode, const char* rawmode, int* bits_out) -{ +ImagingFindPacker(const char *mode, const char *rawmode, int *bits_out) { int i; /* find a suitable pixel packer */ diff --git a/src/libImaging/PackDecode.c b/src/libImaging/PackDecode.c index 34671828a..7dd432b91 100644 --- a/src/libImaging/PackDecode.c +++ b/src/libImaging/PackDecode.c @@ -13,30 +13,27 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" int -ImagingPackbitsDecode(Imaging im, ImagingCodecState state, - UINT8* buf, Py_ssize_t bytes) -{ +ImagingPackbitsDecode( + Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { UINT8 n; - UINT8* ptr; + UINT8 *ptr; int i; ptr = buf; for (;;) { - if (bytes < 1) { return ptr - buf; } if (ptr[0] & 0x80) { - if (ptr[0] == 0x80) { /* Nop */ - ptr++; bytes--; + ptr++; + bytes--; continue; } @@ -53,12 +50,12 @@ ImagingPackbitsDecode(Imaging im, ImagingCodecState state, state->buffer[state->x++] = ptr[1]; } - ptr += 2; bytes -= 2; + ptr += 2; + bytes -= 2; } else { - /* Literal */ - n = ptr[0]+2; + n = ptr[0] + 2; if (bytes < n) { return ptr - buf; @@ -72,16 +69,17 @@ ImagingPackbitsDecode(Imaging im, ImagingCodecState state, state->buffer[state->x++] = ptr[i]; } - ptr += n; bytes -= n; - + ptr += n; + bytes -= n; } if (state->x >= state->bytes) { - /* Got a full line, unpack it */ - state->shuffle((UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->buffer, - state->xsize); + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->buffer, + state->xsize); state->x = 0; @@ -90,6 +88,5 @@ ImagingPackbitsDecode(Imaging im, ImagingCodecState state, return -1; } } - } } diff --git a/src/libImaging/Palette.c b/src/libImaging/Palette.c index ac548f50c..43bea61e3 100644 --- a/src/libImaging/Palette.c +++ b/src/libImaging/Palette.c @@ -16,46 +16,41 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #include - ImagingPalette -ImagingPaletteNew(const char* mode) -{ +ImagingPaletteNew(const char *mode) { /* Create a palette object */ int i; ImagingPalette palette; if (strcmp(mode, "RGB") && strcmp(mode, "RGBA")) { - return (ImagingPalette) ImagingError_ModeError(); + return (ImagingPalette)ImagingError_ModeError(); } palette = calloc(1, sizeof(struct ImagingPaletteInstance)); if (!palette) { - return (ImagingPalette) ImagingError_MemoryError(); + return (ImagingPalette)ImagingError_MemoryError(); } - strncpy(palette->mode, mode, IMAGING_MODE_LENGTH-1); - palette->mode[IMAGING_MODE_LENGTH-1] = 0; + strncpy(palette->mode, mode, IMAGING_MODE_LENGTH - 1); + palette->mode[IMAGING_MODE_LENGTH - 1] = 0; /* Initialize to ramp */ for (i = 0; i < 256; i++) { - palette->palette[i*4+0] = - palette->palette[i*4+1] = - palette->palette[i*4+2] = (UINT8) i; - palette->palette[i*4+3] = 255; /* opaque */ + palette->palette[i * 4 + 0] = palette->palette[i * 4 + 1] = + palette->palette[i * 4 + 2] = (UINT8)i; + palette->palette[i * 4 + 3] = 255; /* opaque */ } return palette; } ImagingPalette -ImagingPaletteNewBrowser(void) -{ +ImagingPaletteNewBrowser(void) { /* Create a standard "browser" palette object */ int i, r, g, b; @@ -70,9 +65,8 @@ ImagingPaletteNewBrowser(void) /* FIXME: Add 10-level windows palette here? */ for (i = 0; i < 10; i++) { - palette->palette[i*4+0] = - palette->palette[i*4+1] = - palette->palette[i*4+2] = 0; + palette->palette[i * 4 + 0] = palette->palette[i * 4 + 1] = + palette->palette[i * 4 + 2] = 0; } /* Simple 6x6x6 colour cube */ @@ -80,9 +74,9 @@ ImagingPaletteNewBrowser(void) for (b = 0; b < 256; b += 51) { for (g = 0; g < 256; g += 51) { for (r = 0; r < 256; r += 51) { - palette->palette[i*4+0] = r; - palette->palette[i*4+1] = g; - palette->palette[i*4+2] = b; + palette->palette[i * 4 + 0] = r; + palette->palette[i * 4 + 1] = g; + palette->palette[i * 4 + 2] = b; i++; } } @@ -92,17 +86,15 @@ ImagingPaletteNewBrowser(void) /* FIXME: add 30-level greyscale wedge here? */ for (; i < 256; i++) { - palette->palette[i*4+0] = - palette->palette[i*4+1] = - palette->palette[i*4+2] = 0; + palette->palette[i * 4 + 0] = palette->palette[i * 4 + 1] = + palette->palette[i * 4 + 2] = 0; } return palette; } ImagingPalette -ImagingPaletteDuplicate(ImagingPalette palette) -{ +ImagingPaletteDuplicate(ImagingPalette palette) { /* Duplicate palette descriptor */ ImagingPalette new_palette; @@ -113,7 +105,7 @@ ImagingPaletteDuplicate(ImagingPalette palette) /* malloc check ok, small constant allocation */ new_palette = malloc(sizeof(struct ImagingPaletteInstance)); if (!new_palette) { - return (ImagingPalette) ImagingError_MemoryError(); + return (ImagingPalette)ImagingError_MemoryError(); } memcpy(new_palette, palette, sizeof(struct ImagingPaletteInstance)); @@ -125,8 +117,7 @@ ImagingPaletteDuplicate(ImagingPalette palette) } void -ImagingPaletteDelete(ImagingPalette palette) -{ +ImagingPaletteDelete(ImagingPalette palette) { /* Destroy palette object */ if (palette) { @@ -137,7 +128,6 @@ ImagingPaletteDelete(ImagingPalette palette) } } - /* -------------------------------------------------------------------- */ /* Colour mapping */ /* -------------------------------------------------------------------- */ @@ -155,27 +145,26 @@ ImagingPaletteDelete(ImagingPalette palette) #define DIST(a, b, s) (a - b) * (a - b) * s /* Colour weights (no scaling, for now) */ -#define RSCALE 1 -#define GSCALE 1 -#define BSCALE 1 +#define RSCALE 1 +#define GSCALE 1 +#define BSCALE 1 /* Calculated scaled distances */ -#define RDIST(a, b) DIST(a, b, RSCALE*RSCALE) -#define GDIST(a, b) DIST(a, b, GSCALE*GSCALE) -#define BDIST(a, b) DIST(a, b, BSCALE*BSCALE) +#define RDIST(a, b) DIST(a, b, RSCALE *RSCALE) +#define GDIST(a, b) DIST(a, b, GSCALE *GSCALE) +#define BDIST(a, b) DIST(a, b, BSCALE *BSCALE) /* Incremental steps */ -#define RSTEP (4 * RSCALE) -#define GSTEP (4 * GSCALE) -#define BSTEP (4 * BSCALE) +#define RSTEP (4 * RSCALE) +#define GSTEP (4 * GSCALE) +#define BSTEP (4 * BSCALE) -#define BOX 8 +#define BOX 8 -#define BOXVOLUME BOX*BOX*BOX +#define BOXVOLUME BOX *BOX *BOX void -ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) -{ +ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) { int i, j; unsigned int dmin[256], dmax; int r0, g0, b0; @@ -187,32 +176,37 @@ ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) /* Get box boundaries for the given (r,g,b)-triplet. Each box covers eight cache slots (32 colour values, that is). */ - r0 = r & 0xe0; r1 = r0 + 0x1f; rc = (r0 + r1) / 2; - g0 = g & 0xe0; g1 = g0 + 0x1f; gc = (g0 + g1) / 2; - b0 = b & 0xe0; b1 = b0 + 0x1f; bc = (b0 + b1) / 2; + r0 = r & 0xe0; + r1 = r0 + 0x1f; + rc = (r0 + r1) / 2; + g0 = g & 0xe0; + g1 = g0 + 0x1f; + gc = (g0 + g1) / 2; + b0 = b & 0xe0; + b1 = b0 + 0x1f; + bc = (b0 + b1) / 2; /* Step 1 -- Select relevant palette entries (after Heckbert) */ /* For each palette entry, calculate the min and max distances to * any position in the box given by the colour we're looking for. */ - dmax = (unsigned int) ~0; + dmax = (unsigned int)~0; for (i = 0; i < 256; i++) { - int r, g, b; unsigned int tmin, tmax; /* Find min and max distances to any point in the box */ - r = palette->palette[i*4+0]; + r = palette->palette[i * 4 + 0]; tmin = (r < r0) ? RDIST(r, r1) : (r > r1) ? RDIST(r, r0) : 0; tmax = (r <= rc) ? RDIST(r, r1) : RDIST(r, r0); - g = palette->palette[i*4+1]; + g = palette->palette[i * 4 + 1]; tmin += (g < g0) ? GDIST(g, g1) : (g > g1) ? GDIST(g, g0) : 0; tmax += (g <= gc) ? GDIST(g, g1) : GDIST(g, g0); - b = palette->palette[i*4+2]; + b = palette->palette[i * 4 + 2]; tmin += (b < b0) ? BDIST(b, b1) : (b > b1) ? BDIST(b, b0) : 0; tmax += (b <= bc) ? BDIST(b, b1) : BDIST(b, b0); @@ -220,7 +214,6 @@ ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) if (tmax < dmax) { dmax = tmax; /* keep the smallest max distance only */ } - } /* Step 2 -- Incrementally update cache slot (after Thomas) */ @@ -230,22 +223,20 @@ ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) * distance is less than or equal the smallest max distance */ for (i = 0; i < BOXVOLUME; i++) { - d[i] = (unsigned int) ~0; + d[i] = (unsigned int)~0; } for (i = 0; i < 256; i++) { - if (dmin[i] <= dmax) { - int rd, gd, bd; int ri, gi, bi; int rx, gx, bx; - ri = (r0 - palette->palette[i*4+0]) * RSCALE; - gi = (g0 - palette->palette[i*4+1]) * GSCALE; - bi = (b0 - palette->palette[i*4+2]) * BSCALE; + ri = (r0 - palette->palette[i * 4 + 0]) * RSCALE; + gi = (g0 - palette->palette[i * 4 + 1]) * GSCALE; + bi = (b0 - palette->palette[i * 4 + 2]) * BSCALE; - rd = ri*ri + gi*gi + bi*bi; + rd = ri * ri + gi * gi + bi * bi; ri = ri * (2 * RSTEP) + RSTEP * RSTEP; gi = gi * (2 * GSTEP) + GSTEP * GSTEP; @@ -253,13 +244,15 @@ ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) rx = ri; for (r = j = 0; r < BOX; r++) { - gd = rd; gx = gi; + gd = rd; + gx = gi; for (g = 0; g < BOX; g++) { - bd = gd; bx = bi; + bd = gd; + bx = bi; for (b = 0; b < BOX; b++) { - if ((unsigned int) bd < d[j]) { + if ((unsigned int)bd < d[j]) { d[j] = bd; - c[j] = (UINT8) i; + c[j] = (UINT8)i; } bd += bx; bx += 2 * BSTEP * BSTEP; @@ -280,33 +273,30 @@ ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) * cache slot in the box. Update the cache. */ j = 0; - for (r = r0; r < r1; r+=4) { - for (g = g0; g < g1; g+=4) { - for (b = b0; b < b1; b+=4) { + for (r = r0; r < r1; r += 4) { + for (g = g0; g < g1; g += 4) { + for (b = b0; b < b1; b += 4) { ImagingPaletteCache(palette, r, g, b) = c[j++]; } } } } - int -ImagingPaletteCachePrepare(ImagingPalette palette) -{ +ImagingPaletteCachePrepare(ImagingPalette palette) { /* Add a colour cache to a palette */ int i; - int entries = 64*64*64; + int entries = 64 * 64 * 64; if (palette->cache == NULL) { - /* The cache is 512k. It might be a good idea to break it up into a pointer array (e.g. an 8-bit image?) */ /* malloc check ok, small constant allocation */ - palette->cache = (INT16*) malloc(entries * sizeof(INT16)); + palette->cache = (INT16 *)malloc(entries * sizeof(INT16)); if (!palette->cache) { - (void) ImagingError_MemoryError(); + (void)ImagingError_MemoryError(); return -1; } @@ -314,16 +304,13 @@ ImagingPaletteCachePrepare(ImagingPalette palette) for (i = 0; i < entries; i++) { palette->cache[i] = 0x100; } - } return 0; } - void -ImagingPaletteCacheDelete(ImagingPalette palette) -{ +ImagingPaletteCacheDelete(ImagingPalette palette) { /* Release the colour cache, if any */ if (palette && palette->cache) { diff --git a/src/libImaging/Paste.c b/src/libImaging/Paste.c index b89534423..a1bf18a92 100644 --- a/src/libImaging/Paste.c +++ b/src/libImaging/Paste.c @@ -23,11 +23,17 @@ #include "Imaging.h" - static inline void -paste(Imaging imOut, Imaging imIn, int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +paste( + Imaging imOut, + Imaging imIn, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* paste opaque region */ int y; @@ -38,25 +44,31 @@ paste(Imaging imOut, Imaging imIn, int dx, int dy, int sx, int sy, xsize *= pixelsize; for (y = 0; y < ysize; y++) { - memcpy(imOut->image[y+dy]+dx, imIn->image[y+sy]+sx, xsize); + memcpy(imOut->image[y + dy] + dx, imIn->image[y + sy] + sx, xsize); } } static inline void -paste_mask_1(Imaging imOut, Imaging imIn, Imaging imMask, - int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +paste_mask_1( + Imaging imOut, + Imaging imIn, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* paste with mode "1" mask */ int x, y; if (imOut->image8) { - for (y = 0; y < ysize; y++) { - UINT8* out = imOut->image8[y+dy]+dx; - UINT8* in = imIn->image8[y+sy]+sx; - UINT8* mask = imMask->image8[y+sy]+sx; + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *in = imIn->image8[y + sy] + sx; + UINT8 *mask = imMask->image8[y + sy] + sx; for (x = 0; x < xsize; x++) { if (*mask++) { *out = *in; @@ -66,11 +78,10 @@ paste_mask_1(Imaging imOut, Imaging imIn, Imaging imMask, } } else { - for (y = 0; y < ysize; y++) { - INT32* out = imOut->image32[y+dy]+dx; - INT32* in = imIn->image32[y+sy]+sx; - UINT8* mask = imMask->image8[y+sy]+sx; + INT32 *out = imOut->image32[y + dy] + dx; + INT32 *in = imIn->image32[y + sy] + sx; + UINT8 *mask = imMask->image8[y + sy] + sx; for (x = 0; x < xsize; x++) { if (*mask++) { *out = *in; @@ -82,21 +93,27 @@ paste_mask_1(Imaging imOut, Imaging imIn, Imaging imMask, } static inline void -paste_mask_L(Imaging imOut, Imaging imIn, Imaging imMask, - int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +paste_mask_L( + Imaging imOut, + Imaging imIn, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* paste with mode "L" matte */ int x, y; unsigned int tmp1; if (imOut->image8) { - for (y = 0; y < ysize; y++) { - UINT8* out = imOut->image8[y+dy]+dx; - UINT8* in = imIn->image8[y+sy]+sx; - UINT8* mask = imMask->image8[y+sy]+sx; + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *in = imIn->image8[y + sy] + sx; + UINT8 *mask = imMask->image8[y + sy] + sx; for (x = 0; x < xsize; x++) { *out = BLEND(*mask, *out, *in, tmp1); out++, in++, mask++; @@ -104,39 +121,46 @@ paste_mask_L(Imaging imOut, Imaging imIn, Imaging imMask, } } else { - for (y = 0; y < ysize; y++) { - UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx); - UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx); - UINT8* mask = (UINT8*) (imMask->image8[y+sy] + sx); + UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx); + UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx); + UINT8 *mask = (UINT8 *)(imMask->image8[y + sy] + sx); for (x = 0; x < xsize; x++) { UINT8 a = mask[0]; out[0] = BLEND(a, out[0], in[0], tmp1); out[1] = BLEND(a, out[1], in[1], tmp1); out[2] = BLEND(a, out[2], in[2], tmp1); out[3] = BLEND(a, out[3], in[3], tmp1); - out += 4; in += 4; mask ++; + out += 4; + in += 4; + mask++; } } } } static inline void -paste_mask_RGBA(Imaging imOut, Imaging imIn, Imaging imMask, - int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +paste_mask_RGBA( + Imaging imOut, + Imaging imIn, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* paste with mode "RGBA" matte */ int x, y; unsigned int tmp1; if (imOut->image8) { - for (y = 0; y < ysize; y++) { - UINT8* out = imOut->image8[y+dy]+dx; - UINT8* in = imIn->image8[y+sy]+sx; - UINT8* mask = (UINT8*) imMask->image[y+sy]+sx*4+3; + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *in = imIn->image8[y + sy] + sx; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 4 + 3; for (x = 0; x < xsize; x++) { *out = BLEND(*mask, *out, *in, tmp1); out++, in++, mask += 4; @@ -144,40 +168,46 @@ paste_mask_RGBA(Imaging imOut, Imaging imIn, Imaging imMask, } } else { - for (y = 0; y < ysize; y++) { - UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx); - UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx); - UINT8* mask = (UINT8*) (imMask->image32[y+sy] + sx); + UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx); + UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx); + UINT8 *mask = (UINT8 *)(imMask->image32[y + sy] + sx); for (x = 0; x < xsize; x++) { UINT8 a = mask[3]; out[0] = BLEND(a, out[0], in[0], tmp1); out[1] = BLEND(a, out[1], in[1], tmp1); out[2] = BLEND(a, out[2], in[2], tmp1); out[3] = BLEND(a, out[3], in[3], tmp1); - out += 4; in += 4; mask += 4; + out += 4; + in += 4; + mask += 4; } } } } - static inline void -paste_mask_RGBa(Imaging imOut, Imaging imIn, Imaging imMask, - int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +paste_mask_RGBa( + Imaging imOut, + Imaging imIn, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* paste with mode "RGBa" matte */ int x, y; unsigned int tmp1; if (imOut->image8) { - for (y = 0; y < ysize; y++) { - UINT8* out = imOut->image8[y+dy]+dx; - UINT8* in = imIn->image8[y+sy]+sx; - UINT8* mask = (UINT8*) imMask->image[y+sy]+sx*4+3; + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *in = imIn->image8[y + sy] + sx; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 4 + 3; for (x = 0; x < xsize; x++) { *out = PREBLEND(*mask, *out, *in, tmp1); out++, in++, mask += 4; @@ -185,34 +215,34 @@ paste_mask_RGBa(Imaging imOut, Imaging imIn, Imaging imMask, } } else { - for (y = 0; y < ysize; y++) { - UINT8* out = (UINT8*) (imOut->image32[y + dy] + dx); - UINT8* in = (UINT8*) (imIn->image32[y + sy] + sx); - UINT8* mask = (UINT8*) (imMask->image32[y+sy] + sx); + UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx); + UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx); + UINT8 *mask = (UINT8 *)(imMask->image32[y + sy] + sx); for (x = 0; x < xsize; x++) { UINT8 a = mask[3]; out[0] = PREBLEND(a, out[0], in[0], tmp1); out[1] = PREBLEND(a, out[1], in[1], tmp1); out[2] = PREBLEND(a, out[2], in[2], tmp1); out[3] = PREBLEND(a, out[3], in[3], tmp1); - out += 4; in += 4; mask += 4; + out += 4; + in += 4; + mask += 4; } } } } int -ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask, - int dx0, int dy0, int dx1, int dy1) -{ +ImagingPaste( + Imaging imOut, Imaging imIn, Imaging imMask, int dx0, int dy0, int dx1, int dy1) { int xsize, ysize; int pixelsize; int sx0, sy0; ImagingSectionCookie cookie; if (!imOut || !imIn) { - (void) ImagingError_ModeError(); + (void)ImagingError_ModeError(); return -1; } @@ -221,14 +251,13 @@ ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask, xsize = dx1 - dx0; ysize = dy1 - dy0; - if (xsize != imIn->xsize || ysize != imIn->ysize || - pixelsize != imIn->pixelsize) { - (void) ImagingError_Mismatch(); + if (xsize != imIn->xsize || ysize != imIn->ysize || pixelsize != imIn->pixelsize) { + (void)ImagingError_Mismatch(); return -1; } if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) { - (void) ImagingError_Mismatch(); + (void)ImagingError_Mismatch(); return -1; } @@ -258,30 +287,28 @@ ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask, } else if (strcmp(imMask->mode, "1") == 0) { ImagingSectionEnter(&cookie); - paste_mask_1(imOut, imIn, imMask, dx0, dy0, sx0, sy0, - xsize, ysize, pixelsize); + paste_mask_1(imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); } else if (strcmp(imMask->mode, "L") == 0) { ImagingSectionEnter(&cookie); - paste_mask_L(imOut, imIn, imMask, dx0, dy0, sx0, sy0, - xsize, ysize, pixelsize); + paste_mask_L(imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); } else if (strcmp(imMask->mode, "RGBA") == 0) { ImagingSectionEnter(&cookie); - paste_mask_RGBA(imOut, imIn, imMask, dx0, dy0, sx0, sy0, - xsize, ysize, pixelsize); + paste_mask_RGBA( + imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); } else if (strcmp(imMask->mode, "RGBa") == 0) { ImagingSectionEnter(&cookie); - paste_mask_RGBa(imOut, imIn, imMask, dx0, dy0, sx0, sy0, - xsize, ysize, pixelsize); + paste_mask_RGBa( + imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); } else { - (void) ImagingError_ValueError("bad transparency mask"); + (void)ImagingError_ValueError("bad transparency mask"); return -1; } @@ -289,9 +316,14 @@ ImagingPaste(Imaging imOut, Imaging imIn, Imaging imMask, } static inline void -fill(Imaging imOut, const void* ink_, int dx, int dy, - int xsize, int ysize, int pixelsize) -{ +fill( + Imaging imOut, + const void *ink_, + int dx, + int dy, + int xsize, + int ysize, + int pixelsize) { /* fill opaque region */ int x, y; @@ -302,30 +334,34 @@ fill(Imaging imOut, const void* ink_, int dx, int dy, memcpy(&ink8, ink_, sizeof(ink8)); if (imOut->image8 || ink32 == 0L) { - dx *= pixelsize; xsize *= pixelsize; for (y = 0; y < ysize; y++) { - memset(imOut->image[y+dy]+dx, ink8, xsize); + memset(imOut->image[y + dy] + dx, ink8, xsize); } } else { - for (y = 0; y < ysize; y++) { - INT32* out = imOut->image32[y+dy]+dx; + INT32 *out = imOut->image32[y + dy] + dx; for (x = 0; x < xsize; x++) { out[x] = ink32; } } - } } static inline void -fill_mask_1(Imaging imOut, const void* ink_, Imaging imMask, - int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +fill_mask_1( + Imaging imOut, + const void *ink_, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* fill with mode "1" mask */ int x, y; @@ -336,10 +372,9 @@ fill_mask_1(Imaging imOut, const void* ink_, Imaging imMask, memcpy(&ink8, ink_, sizeof(ink8)); if (imOut->image8) { - for (y = 0; y < ysize; y++) { - UINT8* out = imOut->image8[y+dy]+dx; - UINT8* mask = imMask->image8[y+sy]+sx; + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *mask = imMask->image8[y + sy] + sx; for (x = 0; x < xsize; x++) { if (*mask++) { *out = ink8; @@ -349,10 +384,9 @@ fill_mask_1(Imaging imOut, const void* ink_, Imaging imMask, } } else { - for (y = 0; y < ysize; y++) { - INT32* out = imOut->image32[y+dy]+dx; - UINT8* mask = imMask->image8[y+sy]+sx; + INT32 *out = imOut->image32[y + dy] + dx; + UINT8 *mask = imMask->image8[y + sy] + sx; for (x = 0; x < xsize; x++) { if (*mask++) { *out = ink32; @@ -364,20 +398,26 @@ fill_mask_1(Imaging imOut, const void* ink_, Imaging imMask, } static inline void -fill_mask_L(Imaging imOut, const UINT8* ink, Imaging imMask, - int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +fill_mask_L( + Imaging imOut, + const UINT8 *ink, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* fill with mode "L" matte */ int x, y, i; unsigned int tmp1; if (imOut->image8) { - for (y = 0; y < ysize; y++) { - UINT8* out = imOut->image8[y+dy]+dx; - UINT8* mask = imMask->image8[y+sy]+sx; + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *mask = imMask->image8[y + sy] + sx; for (x = 0; x < xsize; x++) { *out = BLEND(*mask, *out, ink[0], tmp1); out++, mask++; @@ -385,21 +425,20 @@ fill_mask_L(Imaging imOut, const UINT8* ink, Imaging imMask, } } else { - for (y = 0; y < ysize; y++) { - UINT8* out = (UINT8*) imOut->image[y+dy]+dx*pixelsize; - UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; + UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx * pixelsize; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx; for (x = 0; x < xsize; x++) { for (i = 0; i < pixelsize; i++) { UINT8 channel_mask = *mask; - if (( - strcmp(imOut->mode, "RGBa") == 0 || - strcmp(imOut->mode, "RGBA") == 0 || - strcmp(imOut->mode, "La") == 0 || - strcmp(imOut->mode, "LA") == 0 || - strcmp(imOut->mode, "PA") == 0 - ) && i != 3) { - channel_mask = 255 - (255 - channel_mask) * (1 - (255 - out[3]) / 255); + if ((strcmp(imOut->mode, "RGBa") == 0 || + strcmp(imOut->mode, "RGBA") == 0 || + strcmp(imOut->mode, "La") == 0 || + strcmp(imOut->mode, "LA") == 0 || + strcmp(imOut->mode, "PA") == 0) && + i != 3 && channel_mask != 0) { + channel_mask = + 255 - (255 - channel_mask) * (1 - (255 - out[3]) / 255); } out[i] = BLEND(channel_mask, out[i], ink[i], tmp1); } @@ -411,21 +450,27 @@ fill_mask_L(Imaging imOut, const UINT8* ink, Imaging imMask, } static inline void -fill_mask_RGBA(Imaging imOut, const UINT8* ink, Imaging imMask, - int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +fill_mask_RGBA( + Imaging imOut, + const UINT8 *ink, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* fill with mode "RGBA" matte */ int x, y, i; unsigned int tmp1; if (imOut->image8) { - - sx = sx*4+3; + sx = sx * 4 + 3; for (y = 0; y < ysize; y++) { - UINT8* out = imOut->image8[y+dy]+dx; - UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx; for (x = 0; x < xsize; x++) { *out = BLEND(*mask, *out, ink[0], tmp1); out++, mask += 4; @@ -433,12 +478,11 @@ fill_mask_RGBA(Imaging imOut, const UINT8* ink, Imaging imMask, } } else { - dx *= pixelsize; - sx = sx*4 + 3; + sx = sx * 4 + 3; for (y = 0; y < ysize; y++) { - UINT8* out = (UINT8*) imOut->image[y+dy]+dx; - UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; + UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx; for (x = 0; x < xsize; x++) { for (i = 0; i < pixelsize; i++) { *out = BLEND(*mask, *out, ink[i], tmp1); @@ -451,21 +495,27 @@ fill_mask_RGBA(Imaging imOut, const UINT8* ink, Imaging imMask, } static inline void -fill_mask_RGBa(Imaging imOut, const UINT8* ink, Imaging imMask, - int dx, int dy, int sx, int sy, - int xsize, int ysize, int pixelsize) -{ +fill_mask_RGBa( + Imaging imOut, + const UINT8 *ink, + Imaging imMask, + int dx, + int dy, + int sx, + int sy, + int xsize, + int ysize, + int pixelsize) { /* fill with mode "RGBa" matte */ int x, y, i; unsigned int tmp1; if (imOut->image8) { - - sx = sx*4 + 3; + sx = sx * 4 + 3; for (y = 0; y < ysize; y++) { - UINT8* out = imOut->image8[y+dy]+dx; - UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; + UINT8 *out = imOut->image8[y + dy] + dx; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx; for (x = 0; x < xsize; x++) { *out = PREBLEND(*mask, *out, ink[0], tmp1); out++, mask += 4; @@ -473,12 +523,11 @@ fill_mask_RGBa(Imaging imOut, const UINT8* ink, Imaging imMask, } } else { - dx *= pixelsize; - sx = sx*4 + 3; + sx = sx * 4 + 3; for (y = 0; y < ysize; y++) { - UINT8* out = (UINT8*) imOut->image[y+dy]+dx; - UINT8* mask = (UINT8*) imMask->image[y+sy]+sx; + UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx; + UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx; for (x = 0; x < xsize; x++) { for (i = 0; i < pixelsize; i++) { *out = PREBLEND(*mask, *out, ink[i], tmp1); @@ -491,16 +540,21 @@ fill_mask_RGBa(Imaging imOut, const UINT8* ink, Imaging imMask, } int -ImagingFill2(Imaging imOut, const void* ink, Imaging imMask, - int dx0, int dy0, int dx1, int dy1) -{ +ImagingFill2( + Imaging imOut, + const void *ink, + Imaging imMask, + int dx0, + int dy0, + int dx1, + int dy1) { ImagingSectionCookie cookie; int xsize, ysize; int pixelsize; int sx0, sy0; if (!imOut || !ink) { - (void) ImagingError_ModeError(); + (void)ImagingError_ModeError(); return -1; } @@ -510,7 +564,7 @@ ImagingFill2(Imaging imOut, const void* ink, Imaging imMask, ysize = dy1 - dy0; if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) { - (void) ImagingError_Mismatch(); + (void)ImagingError_Mismatch(); return -1; } @@ -540,30 +594,26 @@ ImagingFill2(Imaging imOut, const void* ink, Imaging imMask, } else if (strcmp(imMask->mode, "1") == 0) { ImagingSectionEnter(&cookie); - fill_mask_1(imOut, ink, imMask, dx0, dy0, sx0, sy0, - xsize, ysize, pixelsize); + fill_mask_1(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); } else if (strcmp(imMask->mode, "L") == 0) { ImagingSectionEnter(&cookie); - fill_mask_L(imOut, ink, imMask, dx0, dy0, sx0, sy0, - xsize, ysize, pixelsize); + fill_mask_L(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); } else if (strcmp(imMask->mode, "RGBA") == 0) { ImagingSectionEnter(&cookie); - fill_mask_RGBA(imOut, ink, imMask, dx0, dy0, sx0, sy0, - xsize, ysize, pixelsize); + fill_mask_RGBA(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); } else if (strcmp(imMask->mode, "RGBa") == 0) { ImagingSectionEnter(&cookie); - fill_mask_RGBa(imOut, ink, imMask, dx0, dy0, sx0, sy0, - xsize, ysize, pixelsize); + fill_mask_RGBa(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize); ImagingSectionLeave(&cookie); } else { - (void) ImagingError_ValueError("bad transparency mask"); + (void)ImagingError_ValueError("bad transparency mask"); return -1; } diff --git a/src/libImaging/PcdDecode.c b/src/libImaging/PcdDecode.c index ff192a174..f13803cb6 100644 --- a/src/libImaging/PcdDecode.c +++ b/src/libImaging/PcdDecode.c @@ -19,24 +19,20 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - int -ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ +ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { int x; int chunk; - UINT8* out; - UINT8* ptr; + UINT8 *out; + UINT8 *ptr; ptr = buf; chunk = 3 * state->xsize; for (;;) { - /* We need data for two full lines before we can do anything */ if (bytes < chunk) { return ptr - buf; @@ -46,13 +42,12 @@ ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt out = state->buffer; for (x = 0; x < state->xsize; x++) { out[0] = ptr[x]; - out[1] = ptr[(x+4*state->xsize)/2]; - out[2] = ptr[(x+5*state->xsize)/2]; + out[1] = ptr[(x + 4 * state->xsize) / 2]; + out[2] = ptr[(x + 5 * state->xsize) / 2]; out += 3; } - state->shuffle((UINT8*) im->image[state->y], - state->buffer, state->xsize); + state->shuffle((UINT8 *)im->image[state->y], state->buffer, state->xsize); if (++state->y >= state->ysize) { return -1; /* This can hardly happen */ @@ -61,14 +56,13 @@ ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt /* Unpack second line */ out = state->buffer; for (x = 0; x < state->xsize; x++) { - out[0] = ptr[x+state->xsize]; - out[1] = ptr[(x+4*state->xsize)/2]; - out[2] = ptr[(x+5*state->xsize)/2]; + out[0] = ptr[x + state->xsize]; + out[1] = ptr[(x + 4 * state->xsize) / 2]; + out[2] = ptr[(x + 5 * state->xsize) / 2]; out += 3; } - state->shuffle((UINT8*) im->image[state->y], - state->buffer, state->xsize); + state->shuffle((UINT8 *)im->image[state->y], state->buffer, state->xsize); if (++state->y >= state->ysize) { return -1; @@ -76,6 +70,5 @@ ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt ptr += chunk; bytes -= chunk; - } } diff --git a/src/libImaging/PcxDecode.c b/src/libImaging/PcxDecode.c index eb0fecc83..c95ffc869 100644 --- a/src/libImaging/PcxDecode.c +++ b/src/libImaging/PcxDecode.c @@ -13,14 +13,12 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" int -ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ +ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { UINT8 n; - UINT8* ptr; + UINT8 *ptr; if ((state->xsize * state->bits + 7) / 8 > state->bytes) { state->errcode = IMAGING_CODEC_OVERRUN; @@ -30,13 +28,11 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt ptr = buf; for (;;) { - if (bytes < 1) { return ptr - buf; } if ((*ptr & 0xC0) == 0xC0) { - /* Run */ if (bytes < 2) { return ptr - buf; @@ -53,14 +49,14 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt n--; } - ptr += 2; bytes -= 2; + ptr += 2; + bytes -= 2; } else { - /* Literal */ state->buffer[state->x++] = ptr[0]; - ptr++; bytes--; - + ptr++; + bytes--; } if (state->x >= state->bytes) { @@ -68,16 +64,19 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt int bands = state->bytes / state->xsize; int stride = state->bytes / bands; int i; - for (i=1; i< bands; i++) { // note -- skipping first band - memmove(&state->buffer[i*state->xsize], - &state->buffer[i*stride], - state->xsize); + for (i = 1; i < bands; i++) { // note -- skipping first band + memmove( + &state->buffer[i * state->xsize], + &state->buffer[i * stride], + state->xsize); } } /* Got a full line, unpack it */ - state->shuffle((UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->buffer, - state->xsize); + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->buffer, + state->xsize); state->x = 0; @@ -86,6 +85,5 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt return -1; } } - } } diff --git a/src/libImaging/PcxEncode.c b/src/libImaging/PcxEncode.c index 163b09b13..549614bfd 100644 --- a/src/libImaging/PcxEncode.c +++ b/src/libImaging/PcxEncode.c @@ -13,7 +13,6 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" enum { INIT, FETCH, ENCODE }; @@ -22,9 +21,8 @@ enum { INIT, FETCH, ENCODE }; #define LAST ystep int -ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) -{ - UINT8* ptr; +ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { + UINT8 *ptr; int this; int bytes_per_line = 0; int padding = 0; @@ -45,12 +43,12 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) } bpp = state->bits; - if (state->bits == 24){ + if (state->bits == 24) { planes = 3; bpp = 8; } - bytes_per_line = (state->xsize*bpp + 7) / 8; + bytes_per_line = (state->xsize * bpp + 7) / 8; /* The stride here needs to be kept in sync with the version in PcxImagePlugin.py. If it's not, the header and the body of the image will be out of sync and bad things will happen on decode. @@ -59,133 +57,131 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) padding = stride - bytes_per_line; - for (;;) { - switch (state->state) { - case FETCH: + case FETCH: - /* get a line of data */ - if (state->y >= state->ysize) { - state->errcode = IMAGING_CODEC_END; - return ptr - buf; - } + /* get a line of data */ + if (state->y >= state->ysize) { + state->errcode = IMAGING_CODEC_END; + return ptr - buf; + } - state->shuffle(state->buffer, - (UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->xsize); + state->shuffle( + state->buffer, + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->xsize); - state->y += 1; + state->y += 1; - state->count = 1; - state->LAST = state->buffer[0]; + state->count = 1; + state->LAST = state->buffer[0]; - state->x = 1; + state->x = 1; - state->state = ENCODE; - /* fall through */ + state->state = ENCODE; + /* fall through */ - case ENCODE: - /* compress this line */ + case ENCODE: + /* compress this line */ - /* when we arrive here, "count" contains the number of - bytes having the value of "LAST" that we've already - seen */ - do { - /* If we're encoding an odd width file, and we've - got more than one plane, we need to pad each - color row with padding bytes at the end. Since - The pixels are stored RRRRRGGGGGBBBBB, so we need - to have the padding be RRRRRPGGGGGPBBBBBP. Hence - the double loop - */ - while (state->x % bytes_per_line) { - - if (state->count == 63) { - /* this run is full; flush it */ - if (bytes < 2) { - return ptr - buf; - } - ptr[0] = 0xff; - ptr[1] = state->LAST; - ptr += 2; - bytes -= 2; - - state->count = 0; - } - - this = state->buffer[state->x]; - - if (this == state->LAST) { - /* extend the current run */ - state->x += 1; - state->count += 1; - - } else { - /* start a new run */ - if (state->count == 1 && (state->LAST < 0xc0)) { - if (bytes < 1) { + /* when we arrive here, "count" contains the number of + bytes having the value of "LAST" that we've already + seen */ + do { + /* If we're encoding an odd width file, and we've + got more than one plane, we need to pad each + color row with padding bytes at the end. Since + The pixels are stored RRRRRGGGGGBBBBB, so we need + to have the padding be RRRRRPGGGGGPBBBBBP. Hence + the double loop + */ + while (state->x % bytes_per_line) { + if (state->count == 63) { + /* this run is full; flush it */ + if (bytes < 2) { return ptr - buf; } - ptr[0] = state->LAST; - ptr += 1; - bytes -= 1; + ptr[0] = 0xff; + ptr[1] = state->LAST; + ptr += 2; + bytes -= 2; + + state->count = 0; + } + + this = state->buffer[state->x]; + + if (this == state->LAST) { + /* extend the current run */ + state->x += 1; + state->count += 1; + } else { - if (state->count > 0) { - if (bytes < 2) { + /* start a new run */ + if (state->count == 1 && (state->LAST < 0xc0)) { + if (bytes < 1) { return ptr - buf; } - ptr[0] = 0xc0 | state->count; - ptr[1] = state->LAST; - ptr += 2; - bytes -= 2; + ptr[0] = state->LAST; + ptr += 1; + bytes -= 1; + } else { + if (state->count > 0) { + if (bytes < 2) { + return ptr - buf; + } + ptr[0] = 0xc0 | state->count; + ptr[1] = state->LAST; + ptr += 2; + bytes -= 2; + } } + + state->LAST = this; + state->count = 1; + + state->x += 1; } - - state->LAST = this; - state->count = 1; - - state->x += 1; } - } - /* end of line; flush the current run */ - if (state->count == 1 && (state->LAST < 0xc0)) { - if (bytes < 1 + padding) { - return ptr - buf; - } - ptr[0] = state->LAST; - ptr += 1; - bytes -= 1; - } else { - if (state->count > 0) { - if (bytes < 2 + padding) { + /* end of line; flush the current run */ + if (state->count == 1 && (state->LAST < 0xc0)) { + if (bytes < 1 + padding) { return ptr - buf; } - ptr[0] = 0xc0 | state->count; - ptr[1] = state->LAST; - ptr += 2; - bytes -= 2; + ptr[0] = state->LAST; + ptr += 1; + bytes -= 1; + } else { + if (state->count > 0) { + if (bytes < 2 + padding) { + return ptr - buf; + } + ptr[0] = 0xc0 | state->count; + ptr[1] = state->LAST; + ptr += 2; + bytes -= 2; + } } - } - /* add the padding */ - for (i = 0; i < padding; i++) { - ptr[0] = 0; - ptr += 1; - bytes -= 1; - } - /* reset for the next color plane. */ - if (state->x < planes * bytes_per_line) { - state->count = 1; - state->LAST = state->buffer[state->x]; - state->x += 1; - } - } while (state->x < planes * bytes_per_line); + /* add the padding */ + for (i = 0; i < padding; i++) { + ptr[0] = 0; + ptr += 1; + bytes -= 1; + } + /* reset for the next color plane. */ + if (state->x < planes * bytes_per_line) { + state->count = 1; + state->LAST = state->buffer[state->x]; + state->x += 1; + } + } while (state->x < planes * bytes_per_line); - /* read next line */ - state->state = FETCH; - break; + /* read next line */ + state->state = FETCH; + break; } } } - diff --git a/src/libImaging/Point.c b/src/libImaging/Point.c index b70840b07..8883578cb 100644 --- a/src/libImaging/Point.c +++ b/src/libImaging/Point.c @@ -19,22 +19,20 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" typedef struct { - const void* table; + const void *table; } im_point_context; static void -im_point_8_8(Imaging imOut, Imaging imIn, im_point_context* context) -{ +im_point_8_8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 8-bit source, 8-bit destination */ - UINT8* table = (UINT8*) context->table; + UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { - UINT8* in = imIn->image8[y]; - UINT8* out = imOut->image8[y]; + UINT8 *in = imIn->image8[y]; + UINT8 *out = imOut->image8[y]; for (x = 0; x < imIn->xsize; x++) { out[x] = table[in[x]]; } @@ -42,68 +40,67 @@ im_point_8_8(Imaging imOut, Imaging imIn, im_point_context* context) } static void -im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context* context) -{ +im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 2x8-bit source, 2x8-bit destination */ - UINT8* table = (UINT8*) context->table; + UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn->xsize; x++) { out[0] = table[in[0]]; - out[3] = table[in[3]+256]; - in += 4; out += 4; + out[3] = table[in[3] + 256]; + in += 4; + out += 4; } } } static void -im_point_3x8_3x8(Imaging imOut, Imaging imIn, im_point_context* context) -{ +im_point_3x8_3x8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 3x8-bit source, 3x8-bit destination */ - UINT8* table = (UINT8*) context->table; + UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn->xsize; x++) { out[0] = table[in[0]]; - out[1] = table[in[1]+256]; - out[2] = table[in[2]+512]; - in += 4; out += 4; + out[1] = table[in[1] + 256]; + out[2] = table[in[2] + 512]; + in += 4; + out += 4; } } } static void -im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context* context) -{ +im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 4x8-bit source, 4x8-bit destination */ - UINT8* table = (UINT8*) context->table; + UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { - UINT8* in = (UINT8*) imIn->image[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT8 *in = (UINT8 *)imIn->image[y]; + UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn->xsize; x++) { out[0] = table[in[0]]; - out[1] = table[in[1]+256]; - out[2] = table[in[2]+512]; - out[3] = table[in[3]+768]; - in += 4; out += 4; + out[1] = table[in[1] + 256]; + out[2] = table[in[2] + 512]; + out[3] = table[in[3] + 768]; + in += 4; + out += 4; } } } static void -im_point_8_32(Imaging imOut, Imaging imIn, im_point_context* context) -{ +im_point_8_32(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 8-bit source, 32-bit destination */ - char* table = (char*) context->table; + char *table = (char *)context->table; for (y = 0; y < imIn->ysize; y++) { - UINT8* in = imIn->image8[y]; - INT32* out = imOut->image32[y]; + UINT8 *in = imIn->image8[y]; + INT32 *out = imOut->image32[y]; for (x = 0; x < imIn->xsize; x++) { memcpy(out + x, table + in[x] * sizeof(INT32), sizeof(INT32)); } @@ -111,14 +108,13 @@ im_point_8_32(Imaging imOut, Imaging imIn, im_point_context* context) } static void -im_point_32_8(Imaging imOut, Imaging imIn, im_point_context* context) -{ +im_point_32_8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 32-bit source, 8-bit destination */ - UINT8* table = (UINT8*) context->table; + UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { - INT32* in = imIn->image32[y]; - UINT8* out = imOut->image8[y]; + INT32 *in = imIn->image32[y]; + UINT8 *out = imOut->image8[y]; for (x = 0; x < imIn->xsize; x++) { int v = in[x]; if (v < 0) { @@ -132,17 +128,16 @@ im_point_32_8(Imaging imOut, Imaging imIn, im_point_context* context) } Imaging -ImagingPoint(Imaging imIn, const char* mode, const void* table) -{ +ImagingPoint(Imaging imIn, const char *mode, const void *table) { /* lookup table transform */ ImagingSectionCookie cookie; Imaging imOut; im_point_context context; - void (*point)(Imaging imIn, Imaging imOut, im_point_context* context); + void (*point)(Imaging imIn, Imaging imOut, im_point_context * context); if (!imIn) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (!mode) { @@ -166,22 +161,22 @@ ImagingPoint(Imaging imIn, const char* mode, const void* table) if (imIn->type == IMAGING_TYPE_UINT8) { if (imIn->bands == imOut->bands && imIn->type == imOut->type) { switch (imIn->bands) { - case 1: - point = im_point_8_8; - break; - case 2: - point = im_point_2x8_2x8; - break; - case 3: - point = im_point_3x8_3x8; - break; - case 4: - point = im_point_4x8_4x8; - break; - default: - /* this cannot really happen */ - point = im_point_8_8; - break; + case 1: + point = im_point_8_8; + break; + case 2: + point = im_point_2x8_2x8; + break; + case 3: + point = im_point_3x8_3x8; + break; + case 4: + point = im_point_4x8_4x8; + break; + default: + /* this cannot really happen */ + point = im_point_8_8; + break; } } else { point = im_point_8_32; @@ -201,26 +196,22 @@ ImagingPoint(Imaging imIn, const char* mode, const void* table) return imOut; - mode_mismatch: - return (Imaging) ImagingError_ValueError( - "point operation not supported for this mode" - ); +mode_mismatch: + return (Imaging)ImagingError_ValueError( + "point operation not supported for this mode"); } - Imaging -ImagingPointTransform(Imaging imIn, double scale, double offset) -{ +ImagingPointTransform(Imaging imIn, double scale, double offset) { /* scale/offset transform */ ImagingSectionCookie cookie; Imaging imOut; int x, y; - if (!imIn || (strcmp(imIn->mode, "I") != 0 && - strcmp(imIn->mode, "I;16") != 0 && + if (!imIn || (strcmp(imIn->mode, "I") != 0 && strcmp(imIn->mode, "I;16") != 0 && strcmp(imIn->mode, "F") != 0)) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); @@ -229,50 +220,50 @@ ImagingPointTransform(Imaging imIn, double scale, double offset) } switch (imIn->type) { - case IMAGING_TYPE_INT32: - ImagingSectionEnter(&cookie); - for (y = 0; y < imIn->ysize; y++) { - INT32* in = imIn->image32[y]; - INT32* out = imOut->image32[y]; - /* FIXME: add clipping? */ - for (x = 0; x < imIn->xsize; x++) { - out[x] = in[x] * scale + offset; - } - } - ImagingSectionLeave(&cookie); - break; - case IMAGING_TYPE_FLOAT32: - ImagingSectionEnter(&cookie); - for (y = 0; y < imIn->ysize; y++) { - FLOAT32* in = (FLOAT32*) imIn->image32[y]; - FLOAT32* out = (FLOAT32*) imOut->image32[y]; - for (x = 0; x < imIn->xsize; x++) { - out[x] = in[x] * scale + offset; - } - } - ImagingSectionLeave(&cookie); - break; - case IMAGING_TYPE_SPECIAL: - if (strcmp(imIn->mode,"I;16") == 0) { + case IMAGING_TYPE_INT32: ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { - char* in = (char*)imIn->image[y]; - char* out = (char*)imOut->image[y]; + INT32 *in = imIn->image32[y]; + INT32 *out = imOut->image32[y]; /* FIXME: add clipping? */ for (x = 0; x < imIn->xsize; x++) { - UINT16 v; - memcpy(&v, in + x * sizeof(v), sizeof(v)); - v = v * scale + offset; - memcpy(out + x * sizeof(UINT16), &v, sizeof(v)); + out[x] = in[x] * scale + offset; } } ImagingSectionLeave(&cookie); break; - } - /* FALL THROUGH */ - default: - ImagingDelete(imOut); - return (Imaging) ImagingError_ValueError("internal error"); + case IMAGING_TYPE_FLOAT32: + ImagingSectionEnter(&cookie); + for (y = 0; y < imIn->ysize; y++) { + FLOAT32 *in = (FLOAT32 *)imIn->image32[y]; + FLOAT32 *out = (FLOAT32 *)imOut->image32[y]; + for (x = 0; x < imIn->xsize; x++) { + out[x] = in[x] * scale + offset; + } + } + ImagingSectionLeave(&cookie); + break; + case IMAGING_TYPE_SPECIAL: + if (strcmp(imIn->mode, "I;16") == 0) { + ImagingSectionEnter(&cookie); + for (y = 0; y < imIn->ysize; y++) { + char *in = (char *)imIn->image[y]; + char *out = (char *)imOut->image[y]; + /* FIXME: add clipping? */ + for (x = 0; x < imIn->xsize; x++) { + UINT16 v; + memcpy(&v, in + x * sizeof(v), sizeof(v)); + v = v * scale + offset; + memcpy(out + x * sizeof(UINT16), &v, sizeof(v)); + } + } + ImagingSectionLeave(&cookie); + break; + } + /* FALL THROUGH */ + default: + ImagingDelete(imOut); + return (Imaging)ImagingError_ValueError("internal error"); } return imOut; diff --git a/src/libImaging/Quant.c b/src/libImaging/Quant.c index 6c9f8d9b7..1c6b9d6a2 100644 --- a/src/libImaging/Quant.c +++ b/src/libImaging/Quant.c @@ -43,169 +43,155 @@ typedef struct { } PixelHashData; typedef struct _PixelList { - struct _PixelList *next[3],*prev[3]; + struct _PixelList *next[3], *prev[3]; Pixel p; - unsigned int flag:1; + unsigned int flag : 1; int count; } PixelList; typedef struct _BoxNode { - struct _BoxNode *l,*r; - PixelList *head[3],*tail[3]; + struct _BoxNode *l, *r; + PixelList *head[3], *tail[3]; int axis; int volume; uint32_t pixelCount; } BoxNode; -#define _SQR(x) ((x)*(x)) -#define _DISTSQR(p1,p2) \ - _SQR((int)((p1)->c.r)-(int)((p2)->c.r))+ \ - _SQR((int)((p1)->c.g)-(int)((p2)->c.g))+ \ - _SQR((int)((p1)->c.b)-(int)((p2)->c.b)) +#define _SQR(x) ((x) * (x)) +#define _DISTSQR(p1, p2) \ + _SQR((int)((p1)->c.r) - (int)((p2)->c.r)) + \ + _SQR((int)((p1)->c.g) - (int)((p2)->c.g)) + \ + _SQR((int)((p1)->c.b) - (int)((p2)->c.b)) #define MAX_HASH_ENTRIES 65536 -#define PIXEL_HASH(r,g,b) \ - (((unsigned int)(r) )*463 ^ \ - ((unsigned int)(g)<< 8)*10069 ^ \ - ((unsigned int)(b)<<16)*64997) +#define PIXEL_HASH(r, g, b) \ + (((unsigned int)(r)) * 463 ^ ((unsigned int)(g) << 8) * 10069 ^ \ + ((unsigned int)(b) << 16) * 64997) -#define PIXEL_UNSCALE(p,q,s) \ - ((q)->c.r=(p)->c.r<<(s)), \ - ((q)->c.g=(p)->c.g<<(s)), \ - ((q)->c.b=(p)->c.b<<(s)) +#define PIXEL_UNSCALE(p, q, s) \ + ((q)->c.r = (p)->c.r << (s)), ((q)->c.g = (p)->c.g << (s)), \ + ((q)->c.b = (p)->c.b << (s)) -#define PIXEL_SCALE(p,q,s)\ - ((q)->c.r=(p)->c.r>>(s)), \ - ((q)->c.g=(p)->c.g>>(s)), \ - ((q)->c.b=(p)->c.b>>(s)) +#define PIXEL_SCALE(p, q, s) \ + ((q)->c.r = (p)->c.r >> (s)), ((q)->c.g = (p)->c.g >> (s)), \ + ((q)->c.b = (p)->c.b >> (s)) static uint32_t -unshifted_pixel_hash(const HashTable *h, const Pixel pixel) -{ - return PIXEL_HASH(pixel.c.r, pixel.c.g, pixel.c.b); +unshifted_pixel_hash(const HashTable *h, const Pixel pixel) { + return PIXEL_HASH(pixel.c.r, pixel.c.g, pixel.c.b); } static int -unshifted_pixel_cmp(const HashTable *h, const Pixel pixel1, const Pixel pixel2) -{ - if (pixel1.c.r==pixel2.c.r) { - if (pixel1.c.g==pixel2.c.g) { - if (pixel1.c.b==pixel2.c.b) { +unshifted_pixel_cmp(const HashTable *h, const Pixel pixel1, const Pixel pixel2) { + if (pixel1.c.r == pixel2.c.r) { + if (pixel1.c.g == pixel2.c.g) { + if (pixel1.c.b == pixel2.c.b) { return 0; } else { - return (int)(pixel1.c.b)-(int)(pixel2.c.b); + return (int)(pixel1.c.b) - (int)(pixel2.c.b); } } else { - return (int)(pixel1.c.g)-(int)(pixel2.c.g); + return (int)(pixel1.c.g) - (int)(pixel2.c.g); } } else { - return (int)(pixel1.c.r)-(int)(pixel2.c.r); + return (int)(pixel1.c.r) - (int)(pixel2.c.r); } } static uint32_t -pixel_hash(const HashTable *h,const Pixel pixel) -{ - PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h); - return PIXEL_HASH(pixel.c.r>>d->scale, pixel.c.g>>d->scale, pixel.c.b>>d->scale); +pixel_hash(const HashTable *h, const Pixel pixel) { + PixelHashData *d = (PixelHashData *)hashtable_get_user_data(h); + return PIXEL_HASH( + pixel.c.r >> d->scale, pixel.c.g >> d->scale, pixel.c.b >> d->scale); } static int -pixel_cmp(const HashTable *h,const Pixel pixel1, const Pixel pixel2) -{ - PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h); - uint32_t A,B; - A=PIXEL_HASH(pixel1.c.r>>d->scale, pixel1.c.g>>d->scale, pixel1.c.b>>d->scale); - B=PIXEL_HASH(pixel2.c.r>>d->scale, pixel2.c.g>>d->scale, pixel2.c.b>>d->scale); - return (A==B)?0:((A> d->scale, pixel1.c.g >> d->scale, pixel1.c.b >> d->scale); + B = PIXEL_HASH( + pixel2.c.r >> d->scale, pixel2.c.g >> d->scale, pixel2.c.b >> d->scale); + return (A == B) ? 0 : ((A < B) ? -1 : 1); } static void -exists_count_func(const HashTable *h, const Pixel key, uint32_t *val) -{ - *val+=1; +exists_count_func(const HashTable *h, const Pixel key, uint32_t *val) { + *val += 1; } static void -new_count_func(const HashTable *h, const Pixel key, uint32_t *val) -{ - *val=1; +new_count_func(const HashTable *h, const Pixel key, uint32_t *val) { + *val = 1; } static void -rehash_collide(const HashTable *h, - Pixel *keyp, - uint32_t *valp, - Pixel newkey, - uint32_t newval) -{ +rehash_collide( + const HashTable *h, Pixel *keyp, uint32_t *valp, Pixel newkey, uint32_t newval) { *valp += newval; } /* %% */ static HashTable * -create_pixel_hash(Pixel *pixelData,uint32_t nPixels) -{ - PixelHashData *d; - HashTable *hash; - uint32_t i; +create_pixel_hash(Pixel *pixelData, uint32_t nPixels) { + PixelHashData *d; + HashTable *hash; + uint32_t i; #ifndef NO_OUTPUT - uint32_t timer,timer2,timer3; + uint32_t timer, timer2, timer3; #endif - /* malloc check ok, small constant allocation */ - d=malloc(sizeof(PixelHashData)); - if (!d) { - return NULL; - } - hash=hashtable_new(pixel_hash,pixel_cmp); - hashtable_set_user_data(hash,d); - d->scale=0; + /* malloc check ok, small constant allocation */ + d = malloc(sizeof(PixelHashData)); + if (!d) { + return NULL; + } + hash = hashtable_new(pixel_hash, pixel_cmp); + hashtable_set_user_data(hash, d); + d->scale = 0; #ifndef NO_OUTPUT - timer=timer3=clock(); + timer = timer3 = clock(); #endif - for (i=0;iMAX_HASH_ENTRIES) { - d->scale++; + for (i = 0; i < nPixels; i++) { + if (!hashtable_insert_or_update_computed( + hash, pixelData[i], new_count_func, exists_count_func)) { + ; + } + while (hashtable_get_count(hash) > MAX_HASH_ENTRIES) { + d->scale++; #ifndef NO_OUTPUT - printf ("rehashing - new scale: %d\n",(int)d->scale); - timer2=clock(); + printf("rehashing - new scale: %d\n", (int)d->scale); + timer2 = clock(); #endif - hashtable_rehash_compute(hash,rehash_collide); + hashtable_rehash_compute(hash, rehash_collide); #ifndef NO_OUTPUT - timer2=clock()-timer2; - printf ("rehash took %f sec\n",timer2/(double)CLOCKS_PER_SEC); - timer+=timer2; + timer2 = clock() - timer2; + printf("rehash took %f sec\n", timer2 / (double)CLOCKS_PER_SEC); + timer += timer2; #endif - } - } + } + } #ifndef NO_OUTPUT - printf ("inserts took %f sec\n",(clock()-timer)/(double)CLOCKS_PER_SEC); + printf("inserts took %f sec\n", (clock() - timer) / (double)CLOCKS_PER_SEC); #endif #ifndef NO_OUTPUT - printf ("total %f sec\n",(clock()-timer3)/(double)CLOCKS_PER_SEC); + printf("total %f sec\n", (clock() - timer3) / (double)CLOCKS_PER_SEC); #endif - return hash; + return hash; } static void -destroy_pixel_hash(HashTable *hash) -{ - PixelHashData *d=(PixelHashData *)hashtable_get_user_data(hash); - if (d) { - free(d); - } - hashtable_free(hash); +destroy_pixel_hash(HashTable *hash) { + PixelHashData *d = (PixelHashData *)hashtable_get_user_data(hash); + if (d) { + free(d); + } + hashtable_free(hash); } - /* 1. hash quantized pixels. */ /* 2. create R,G,B lists of sorted quantized pixels. */ /* 3. median cut. */ @@ -215,659 +201,686 @@ destroy_pixel_hash(HashTable *hash) /* 7. map each pixel to nearest average. */ static int -compute_box_volume(BoxNode *b) -{ - unsigned char rl,rh,gl,gh,bl,bh; - if (b->volume>=0) { - return b->volume; - } - if (!b->head[0]) { - b->volume=0; - } else { - rh=b->head[0]->p.c.r; - rl=b->tail[0]->p.c.r; - gh=b->head[1]->p.c.g; - gl=b->tail[1]->p.c.g; - bh=b->head[2]->p.c.b; - bl=b->tail[2]->p.c.b; - b->volume=(rh-rl+1)*(gh-gl+1)*(bh-bl+1); - } - return b->volume; +compute_box_volume(BoxNode *b) { + unsigned char rl, rh, gl, gh, bl, bh; + if (b->volume >= 0) { + return b->volume; + } + if (!b->head[0]) { + b->volume = 0; + } else { + rh = b->head[0]->p.c.r; + rl = b->tail[0]->p.c.r; + gh = b->head[1]->p.c.g; + gl = b->tail[1]->p.c.g; + bh = b->head[2]->p.c.b; + bl = b->tail[2]->p.c.b; + b->volume = (rh - rl + 1) * (gh - gl + 1) * (bh - bl + 1); + } + return b->volume; } static void -hash_to_list(const HashTable *h, const Pixel pixel, const uint32_t count, void *u) -{ - PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h); - PixelList **pl=(PixelList **)u; - PixelList *p; - int i; - Pixel q; +hash_to_list(const HashTable *h, const Pixel pixel, const uint32_t count, void *u) { + PixelHashData *d = (PixelHashData *)hashtable_get_user_data(h); + PixelList **pl = (PixelList **)u; + PixelList *p; + int i; + Pixel q; - PIXEL_SCALE(&pixel,&q,d->scale); + PIXEL_SCALE(&pixel, &q, d->scale); - /* malloc check ok, small constant allocation */ - p=malloc(sizeof(PixelList)); - if (!p) { - return; - } + /* malloc check ok, small constant allocation */ + p = malloc(sizeof(PixelList)); + if (!p) { + return; + } - p->flag=0; - p->p=q; - p->count=count; - for (i=0;i<3;i++) { - p->next[i]=pl[i]; - p->prev[i]=NULL; - if (pl[i]) { - pl[i]->prev[i]=p; - } - pl[i]=p; - } + p->flag = 0; + p->p = q; + p->count = count; + for (i = 0; i < 3; i++) { + p->next[i] = pl[i]; + p->prev[i] = NULL; + if (pl[i]) { + pl[i]->prev[i] = p; + } + pl[i] = p; + } } static PixelList * -mergesort_pixels(PixelList *head, int i) -{ - PixelList *c,*t,*a,*b,*p; - if (!head||!head->next[i]) { - if (head) { - head->next[i]=NULL; - head->prev[i]=NULL; - } - return head; - } - for (c=t=head;c&&t;c=c->next[i],t=(t->next[i])?t->next[i]->next[i]:NULL); - if (c) { - if (c->prev[i]) { - c->prev[i]->next[i]=NULL; - } - c->prev[i]=NULL; - } - a=mergesort_pixels(head,i); - b=mergesort_pixels(c,i); - head=NULL; - p=NULL; - while (a&&b) { - if (a->p.a.v[i]>b->p.a.v[i]) { - c=a; - a=a->next[i]; - } else { - c=b; - b=b->next[i]; - } - c->prev[i]=p; - c->next[i]=NULL; - if (p) { - p->next[i]=c; - } - p=c; - if (!head) { - head=c; - } - } - if (a) { - c->next[i]=a; - a->prev[i]=c; - } else if (b) { - c->next[i]=b; - b->prev[i]=c; - } - return head; +mergesort_pixels(PixelList *head, int i) { + PixelList *c, *t, *a, *b, *p; + if (!head || !head->next[i]) { + if (head) { + head->next[i] = NULL; + head->prev[i] = NULL; + } + return head; + } + for (c = t = head; c && t; + c = c->next[i], t = (t->next[i]) ? t->next[i]->next[i] : NULL) + ; + if (c) { + if (c->prev[i]) { + c->prev[i]->next[i] = NULL; + } + c->prev[i] = NULL; + } + a = mergesort_pixels(head, i); + b = mergesort_pixels(c, i); + head = NULL; + p = NULL; + while (a && b) { + if (a->p.a.v[i] > b->p.a.v[i]) { + c = a; + a = a->next[i]; + } else { + c = b; + b = b->next[i]; + } + c->prev[i] = p; + c->next[i] = NULL; + if (p) { + p->next[i] = c; + } + p = c; + if (!head) { + head = c; + } + } + if (a) { + c->next[i] = a; + a->prev[i] = c; + } else if (b) { + c->next[i] = b; + b->prev[i] = c; + } + return head; } #if defined(TEST_MERGESORT) || defined(TEST_SORTED) static int -test_sorted(PixelList *pl[3]) -{ - int i,n,l; - PixelList *t; +test_sorted(PixelList *pl[3]) { + int i, n, l; + PixelList *t; - for(i=0;i<3;i++) { - n=0; - l=256; - for (t=pl[i];t;t=t->next[i]) { - if (lp.a.v[i]) return 0; - l=t->p.a.v[i]; - } - } - return 1; + for (i = 0; i < 3; i++) { + n = 0; + l = 256; + for (t = pl[i]; t; t = t->next[i]) { + if (l < t->p.a.v[i]) + return 0; + l = t->p.a.v[i]; + } + } + return 1; } #endif static int -box_heap_cmp(const Heap *h, const void *A, const void *B) -{ - BoxNode *a=(BoxNode *)A; - BoxNode *b=(BoxNode *)B; - return (int)a->pixelCount-(int)b->pixelCount; +box_heap_cmp(const Heap *h, const void *A, const void *B) { + BoxNode *a = (BoxNode *)A; + BoxNode *b = (BoxNode *)B; + return (int)a->pixelCount - (int)b->pixelCount; } -#define LUMINANCE(p) (77*(p)->c.r+150*(p)->c.g+29*(p)->c.b) +#define LUMINANCE(p) (77 * (p)->c.r + 150 * (p)->c.g + 29 * (p)->c.b) static int -splitlists(PixelList *h[3], - PixelList *t[3], - PixelList *nh[2][3], - PixelList *nt[2][3], - uint32_t nCount[2], - int axis, - uint32_t pixelCount) -{ - uint32_t left; +splitlists( + PixelList *h[3], + PixelList *t[3], + PixelList *nh[2][3], + PixelList *nt[2][3], + uint32_t nCount[2], + int axis, + uint32_t pixelCount) { + uint32_t left; - PixelList *l,*r,*c,*n; - int i; - int nRight,nLeft; - int splitColourVal; + PixelList *l, *r, *c, *n; + int i; + int nRight, nLeft; + int splitColourVal; #ifdef TEST_SPLIT - { - PixelList *_prevTest,*_nextTest; - int _i,_nextCount[3],_prevCount[3]; - for (_i=0;_i<3;_i++) { - for (_nextCount[_i]=0,_nextTest=h[_i];_nextTest&&_nextTest->next[_i];_nextTest=_nextTest->next[_i],_nextCount[_i]++); - for (_prevCount[_i]=0,_prevTest=t[_i];_prevTest&&_prevTest->prev[_i];_prevTest=_prevTest->prev[_i],_prevCount[_i]++); - if (_nextTest!=t[_i]) { - printf ("next-list of axis %d does not end at tail\n",_i); - exit(1); - } - if (_prevTest!=h[_i]) { - printf ("prev-list of axis %d does not end at head\n",_i); - exit(1); - } - for (;_nextTest&&_nextTest->prev[_i];_nextTest=_nextTest->prev[_i]); - for (;_prevTest&&_prevTest->next[_i];_prevTest=_prevTest->next[_i]); - if (_nextTest!=h[_i]) { - printf ("next-list of axis %d does not loop back to head\n",_i); - exit(1); - } - if (_prevTest!=t[_i]) { - printf ("prev-list of axis %d does not loop back to tail\n",_i); - exit(1); - } - } - for (_i=1;_i<3;_i++) { - if (_prevCount[_i]!=_prevCount[_i-1] || - _nextCount[_i]!=_nextCount[_i-1] || - _prevCount[_i]!=_nextCount[_i]) { - printf ("{%d %d %d} {%d %d %d}\n", + { + PixelList *_prevTest, *_nextTest; + int _i, _nextCount[3], _prevCount[3]; + for (_i = 0; _i < 3; _i++) { + for (_nextCount[_i] = 0, _nextTest = h[_i]; + _nextTest && _nextTest->next[_i]; + _nextTest = _nextTest->next[_i], _nextCount[_i]++) + ; + for (_prevCount[_i] = 0, _prevTest = t[_i]; + _prevTest && _prevTest->prev[_i]; + _prevTest = _prevTest->prev[_i], _prevCount[_i]++) + ; + if (_nextTest != t[_i]) { + printf("next-list of axis %d does not end at tail\n", _i); + exit(1); + } + if (_prevTest != h[_i]) { + printf("prev-list of axis %d does not end at head\n", _i); + exit(1); + } + for (; _nextTest && _nextTest->prev[_i]; _nextTest = _nextTest->prev[_i]) + ; + for (; _prevTest && _prevTest->next[_i]; _prevTest = _prevTest->next[_i]) + ; + if (_nextTest != h[_i]) { + printf("next-list of axis %d does not loop back to head\n", _i); + exit(1); + } + if (_prevTest != t[_i]) { + printf("prev-list of axis %d does not loop back to tail\n", _i); + exit(1); + } + } + for (_i = 1; _i < 3; _i++) { + if (_prevCount[_i] != _prevCount[_i - 1] || + _nextCount[_i] != _nextCount[_i - 1] || + _prevCount[_i] != _nextCount[_i]) { + printf( + "{%d %d %d} {%d %d %d}\n", _prevCount[0], _prevCount[1], _prevCount[2], _nextCount[0], _nextCount[1], _nextCount[2]); - exit(1); - } - } + exit(1); + } + } } #endif - nCount[0]=nCount[1]=0; - nLeft=nRight=0; - for (left=0,c=h[axis];c;) { - left=left+c->count; - nCount[0]+=c->count; - c->flag=0; - nLeft++; - c=c->next[axis]; - if (left*2>pixelCount) { - break; - } - } - if (c) { - splitColourVal=c->prev[axis]->p.a.v[axis]; - for (;c;c=c->next[axis]) { - if (splitColourVal!=c->p.a.v[axis]) { + nCount[0] = nCount[1] = 0; + nLeft = nRight = 0; + for (left = 0, c = h[axis]; c;) { + left = left + c->count; + nCount[0] += c->count; + c->flag = 0; + nLeft++; + c = c->next[axis]; + if (left * 2 > pixelCount) { break; - } - c->flag=0; - nLeft++; - nCount[0]+=c->count; - } - } - for (;c;c=c->next[axis]) { - c->flag=1; - nRight++; - nCount[1]+=c->count; - } - if (!nRight) { - for (c=t[axis],splitColourVal=t[axis]->p.a.v[axis];c;c=c->prev[axis]) { - if (splitColourVal!=c->p.a.v[axis]) { - break; - } - c->flag=1; - nRight++; - nLeft--; - nCount[0]-=c->count; - nCount[1]+=c->count; - } - } + } + } + if (c) { + splitColourVal = c->prev[axis]->p.a.v[axis]; + for (; c; c = c->next[axis]) { + if (splitColourVal != c->p.a.v[axis]) { + break; + } + c->flag = 0; + nLeft++; + nCount[0] += c->count; + } + } + for (; c; c = c->next[axis]) { + c->flag = 1; + nRight++; + nCount[1] += c->count; + } + if (!nRight) { + for (c = t[axis], splitColourVal = t[axis]->p.a.v[axis]; c; c = c->prev[axis]) { + if (splitColourVal != c->p.a.v[axis]) { + break; + } + c->flag = 1; + nRight++; + nLeft--; + nCount[0] -= c->count; + nCount[1] += c->count; + } + } #ifndef NO_OUTPUT - if (!nLeft) { - for (c=h[axis];c;c=c->next[axis]) { - printf ("[%d %d %d]\n",c->p.c.r,c->p.c.g,c->p.c.b); - } - printf ("warning... trivial split\n"); - } + if (!nLeft) { + for (c = h[axis]; c; c = c->next[axis]) { + printf("[%d %d %d]\n", c->p.c.r, c->p.c.g, c->p.c.b); + } + printf("warning... trivial split\n"); + } #endif - for (i=0;i<3;i++) { - l=r=NULL; - nh[0][i]=nt[0][i]=NULL; - nh[1][i]=nt[1][i]=NULL; - for (c=h[i];c;c=n) { - n=c->next[i]; - if (c->flag) { /* move pixel to right list*/ - if (r) { - r->next[i]=c; - } else { - nh[1][i]=c; + for (i = 0; i < 3; i++) { + l = r = NULL; + nh[0][i] = nt[0][i] = NULL; + nh[1][i] = nt[1][i] = NULL; + for (c = h[i]; c; c = n) { + n = c->next[i]; + if (c->flag) { /* move pixel to right list*/ + if (r) { + r->next[i] = c; + } else { + nh[1][i] = c; + } + c->prev[i] = r; + r = c; + } else { /* move pixel to left list */ + if (l) { + l->next[i] = c; + } else { + nh[0][i] = c; + } + c->prev[i] = l; + l = c; } - c->prev[i]=r; - r=c; - } else { /* move pixel to left list */ - if (l) { - l->next[i]=c; - } else { - nh[0][i]=c; - } - c->prev[i]=l; - l=c; - } - } - if (l) { - l->next[i]=NULL; - } - if (r) { - r->next[i]=NULL; - } - nt[0][i]=l; - nt[1][i]=r; - } - return 1; + } + if (l) { + l->next[i] = NULL; + } + if (r) { + r->next[i] = NULL; + } + nt[0][i] = l; + nt[1][i] = r; + } + return 1; } static int -split(BoxNode *node) -{ - unsigned char rl,rh,gl,gh,bl,bh; - int f[3]; - int best,axis; - int i; - PixelList *heads[2][3]; - PixelList *tails[2][3]; - uint32_t newCounts[2]; - BoxNode *left,*right; +split(BoxNode *node) { + unsigned char rl, rh, gl, gh, bl, bh; + int f[3]; + int best, axis; + int i; + PixelList *heads[2][3]; + PixelList *tails[2][3]; + uint32_t newCounts[2]; + BoxNode *left, *right; - rh=node->head[0]->p.c.r; - rl=node->tail[0]->p.c.r; - gh=node->head[1]->p.c.g; - gl=node->tail[1]->p.c.g; - bh=node->head[2]->p.c.b; - bl=node->tail[2]->p.c.b; + rh = node->head[0]->p.c.r; + rl = node->tail[0]->p.c.r; + gh = node->head[1]->p.c.g; + gl = node->tail[1]->p.c.g; + bh = node->head[2]->p.c.b; + bl = node->tail[2]->p.c.b; #ifdef TEST_SPLIT - printf ("splitting node [%d %d %d] [%d %d %d] ",rl,gl,bl,rh,gh,bh); + printf("splitting node [%d %d %d] [%d %d %d] ", rl, gl, bl, rh, gh, bh); #endif - f[0]=(rh-rl)*77; - f[1]=(gh-gl)*150; - f[2]=(bh-bl)*29; + f[0] = (rh - rl) * 77; + f[1] = (gh - gl) * 150; + f[2] = (bh - bl) * 29; - best=f[0]; - axis=0; - for (i=1;i<3;i++) { - if (besttail[_i]->next[_i]) { - printf ("tail is not tail\n"); - printf ("node->tail[%d]->next[%d]=%p\n",_i,_i,node->tail[_i]->next[_i]); - } - if (node->head[_i]->prev[_i]) { - printf ("head is not head\n"); - printf ("node->head[%d]->prev[%d]=%p\n",_i,_i,node->head[_i]->prev[_i]); - } - } + { + PixelList *_prevTest, *_nextTest; + int _i, _nextCount[3], _prevCount[3]; + for (_i = 0; _i < 3; _i++) { + if (node->tail[_i]->next[_i]) { + printf("tail is not tail\n"); + printf( + "node->tail[%d]->next[%d]=%p\n", _i, _i, node->tail[_i]->next[_i]); + } + if (node->head[_i]->prev[_i]) { + printf("head is not head\n"); + printf( + "node->head[%d]->prev[%d]=%p\n", _i, _i, node->head[_i]->prev[_i]); + } + } - for (_i=0;_i<3;_i++) { - for (_nextCount[_i]=0,_nextTest=node->head[_i];_nextTest&&_nextTest->next[_i];_nextTest=_nextTest->next[_i],_nextCount[_i]++); - for (_prevCount[_i]=0,_prevTest=node->tail[_i];_prevTest&&_prevTest->prev[_i];_prevTest=_prevTest->prev[_i],_prevCount[_i]++); - if (_nextTest!=node->tail[_i]) { - printf ("next-list of axis %d does not end at tail\n",_i); - } - if (_prevTest!=node->head[_i]) { - printf ("prev-list of axis %d does not end at head\n",_i); - } - for (;_nextTest&&_nextTest->prev[_i];_nextTest=_nextTest->prev[_i]); - for (;_prevTest&&_prevTest->next[_i];_prevTest=_prevTest->next[_i]); - if (_nextTest!=node->head[_i]) { - printf ("next-list of axis %d does not loop back to head\n",_i); - } - if (_prevTest!=node->tail[_i]) { - printf ("prev-list of axis %d does not loop back to tail\n",_i); - } - } - for (_i=1;_i<3;_i++) { - if (_prevCount[_i]!=_prevCount[_i-1] || - _nextCount[_i]!=_nextCount[_i-1] || - _prevCount[_i]!=_nextCount[_i]) { - printf ("{%d %d %d} {%d %d %d}\n", + for (_i = 0; _i < 3; _i++) { + for (_nextCount[_i] = 0, _nextTest = node->head[_i]; + _nextTest && _nextTest->next[_i]; + _nextTest = _nextTest->next[_i], _nextCount[_i]++) + ; + for (_prevCount[_i] = 0, _prevTest = node->tail[_i]; + _prevTest && _prevTest->prev[_i]; + _prevTest = _prevTest->prev[_i], _prevCount[_i]++) + ; + if (_nextTest != node->tail[_i]) { + printf("next-list of axis %d does not end at tail\n", _i); + } + if (_prevTest != node->head[_i]) { + printf("prev-list of axis %d does not end at head\n", _i); + } + for (; _nextTest && _nextTest->prev[_i]; _nextTest = _nextTest->prev[_i]) + ; + for (; _prevTest && _prevTest->next[_i]; _prevTest = _prevTest->next[_i]) + ; + if (_nextTest != node->head[_i]) { + printf("next-list of axis %d does not loop back to head\n", _i); + } + if (_prevTest != node->tail[_i]) { + printf("prev-list of axis %d does not loop back to tail\n", _i); + } + } + for (_i = 1; _i < 3; _i++) { + if (_prevCount[_i] != _prevCount[_i - 1] || + _nextCount[_i] != _nextCount[_i - 1] || + _prevCount[_i] != _nextCount[_i]) { + printf( + "{%d %d %d} {%d %d %d}\n", _prevCount[0], _prevCount[1], _prevCount[2], _nextCount[0], _nextCount[1], _nextCount[2]); - } - } + } + } } #endif - node->axis=axis; - if (!splitlists(node->head, - node->tail, - heads, - tails, - newCounts, - axis, - node->pixelCount)) { + node->axis = axis; + if (!splitlists( + node->head, node->tail, heads, tails, newCounts, axis, node->pixelCount)) { #ifndef NO_OUTPUT - printf ("list split failed.\n"); + printf("list split failed.\n"); #endif - return 0; - } + return 0; + } #ifdef TEST_SPLIT - if (!test_sorted(heads[0])) { - printf ("bug in split"); - exit(1); - } - if (!test_sorted(heads[1])) { - printf ("bug in split"); - exit(1); - } + if (!test_sorted(heads[0])) { + printf("bug in split"); + exit(1); + } + if (!test_sorted(heads[1])) { + printf("bug in split"); + exit(1); + } #endif - /* malloc check ok, small constant allocation */ - left=malloc(sizeof(BoxNode)); - right=malloc(sizeof(BoxNode)); - if (!left||!right) { - free(left); - free(right); - return 0; - } - for(i=0;i<3;i++) { - left->head[i]=heads[0][i]; - left->tail[i]=tails[0][i]; - right->head[i]=heads[1][i]; - right->tail[i]=tails[1][i]; - node->head[i]=NULL; - node->tail[i]=NULL; - } + /* malloc check ok, small constant allocation */ + left = malloc(sizeof(BoxNode)); + right = malloc(sizeof(BoxNode)); + if (!left || !right) { + free(left); + free(right); + return 0; + } + for (i = 0; i < 3; i++) { + left->head[i] = heads[0][i]; + left->tail[i] = tails[0][i]; + right->head[i] = heads[1][i]; + right->tail[i] = tails[1][i]; + node->head[i] = NULL; + node->tail[i] = NULL; + } #ifdef TEST_SPLIT - if (left->head[0]) { - rh=left->head[0]->p.c.r; - rl=left->tail[0]->p.c.r; - gh=left->head[1]->p.c.g; - gl=left->tail[1]->p.c.g; - bh=left->head[2]->p.c.b; - bl=left->tail[2]->p.c.b; - printf (" left node [%3d %3d %3d] [%3d %3d %3d]\n",rl,gl,bl,rh,gh,bh); - } - if (right->head[0]) { - rh=right->head[0]->p.c.r; - rl=right->tail[0]->p.c.r; - gh=right->head[1]->p.c.g; - gl=right->tail[1]->p.c.g; - bh=right->head[2]->p.c.b; - bl=right->tail[2]->p.c.b; - printf (" right node [%3d %3d %3d] [%3d %3d %3d]\n",rl,gl,bl,rh,gh,bh); - } + if (left->head[0]) { + rh = left->head[0]->p.c.r; + rl = left->tail[0]->p.c.r; + gh = left->head[1]->p.c.g; + gl = left->tail[1]->p.c.g; + bh = left->head[2]->p.c.b; + bl = left->tail[2]->p.c.b; + printf(" left node [%3d %3d %3d] [%3d %3d %3d]\n", rl, gl, bl, rh, gh, bh); + } + if (right->head[0]) { + rh = right->head[0]->p.c.r; + rl = right->tail[0]->p.c.r; + gh = right->head[1]->p.c.g; + gl = right->tail[1]->p.c.g; + bh = right->head[2]->p.c.b; + bl = right->tail[2]->p.c.b; + printf(" right node [%3d %3d %3d] [%3d %3d %3d]\n", rl, gl, bl, rh, gh, bh); + } #endif - left->l=left->r=NULL; - right->l=right->r=NULL; - left->axis=right->axis=-1; - left->volume=right->volume=-1; - left->pixelCount=newCounts[0]; - right->pixelCount=newCounts[1]; - node->l=left; - node->r=right; - return 1; + left->l = left->r = NULL; + right->l = right->r = NULL; + left->axis = right->axis = -1; + left->volume = right->volume = -1; + left->pixelCount = newCounts[0]; + right->pixelCount = newCounts[1]; + node->l = left; + node->r = right; + return 1; } static BoxNode * -median_cut(PixelList *hl[3], - uint32_t imPixelCount, - int nPixels) -{ - PixelList *tl[3]; - int i; - BoxNode *root; - Heap* h; - BoxNode *thisNode; +median_cut(PixelList *hl[3], uint32_t imPixelCount, int nPixels) { + PixelList *tl[3]; + int i; + BoxNode *root; + Heap *h; + BoxNode *thisNode; - h=ImagingQuantHeapNew(box_heap_cmp); - /* malloc check ok, small constant allocation */ - root=malloc(sizeof(BoxNode)); - if (!root) { ImagingQuantHeapFree(h); return NULL; } - for(i=0;i<3;i++) { - for (tl[i]=hl[i];tl[i]&&tl[i]->next[i];tl[i]=tl[i]->next[i]); - root->head[i]=hl[i]; - root->tail[i]=tl[i]; - } - root->l=root->r=NULL; - root->axis=-1; - root->volume=-1; - root->pixelCount=imPixelCount; + h = ImagingQuantHeapNew(box_heap_cmp); + /* malloc check ok, small constant allocation */ + root = malloc(sizeof(BoxNode)); + if (!root) { + ImagingQuantHeapFree(h); + return NULL; + } + for (i = 0; i < 3; i++) { + for (tl[i] = hl[i]; tl[i] && tl[i]->next[i]; tl[i] = tl[i]->next[i]) + ; + root->head[i] = hl[i]; + root->tail[i] = tl[i]; + } + root->l = root->r = NULL; + root->axis = -1; + root->volume = -1; + root->pixelCount = imPixelCount; - ImagingQuantHeapAdd(h,(void *)root); - while (--nPixels) { - do { - if (!ImagingQuantHeapRemove(h,(void **)&thisNode)) { - goto done; - } - } while (compute_box_volume(thisNode)==1); - if (!split(thisNode)) { + ImagingQuantHeapAdd(h, (void *)root); + while (--nPixels) { + do { + if (!ImagingQuantHeapRemove(h, (void **)&thisNode)) { + goto done; + } + } while (compute_box_volume(thisNode) == 1); + if (!split(thisNode)) { #ifndef NO_OUTPUT - printf ("Oops, split failed...\n"); + printf("Oops, split failed...\n"); #endif - exit (1); - } - ImagingQuantHeapAdd(h,(void *)(thisNode->l)); - ImagingQuantHeapAdd(h,(void *)(thisNode->r)); - } + exit(1); + } + ImagingQuantHeapAdd(h, (void *)(thisNode->l)); + ImagingQuantHeapAdd(h, (void *)(thisNode->r)); + } done: - ImagingQuantHeapFree(h); - return root; + ImagingQuantHeapFree(h); + return root; } static void -free_box_tree(BoxNode *n) -{ - PixelList *p,*pp; - if (n->l) { - free_box_tree(n->l); - } - if (n->r) { - free_box_tree(n->r); - } - for (p=n->head[0];p;p=pp) { - pp=p->next[0]; - free(p); - } - free(n); +free_box_tree(BoxNode *n) { + PixelList *p, *pp; + if (n->l) { + free_box_tree(n->l); + } + if (n->r) { + free_box_tree(n->r); + } + for (p = n->head[0]; p; p = pp) { + pp = p->next[0]; + free(p); + } + free(n); } #ifdef TEST_SPLIT_INTEGRITY static int -checkContained(BoxNode *n,Pixel *pp) -{ - if (n->l&&n->r) { - return checkContained(n->l,pp)+checkContained(n->r,pp); - } - if (n->l||n->r) { +checkContained(BoxNode *n, Pixel *pp) { + if (n->l && n->r) { + return checkContained(n->l, pp) + checkContained(n->r, pp); + } + if (n->l || n->r) { #ifndef NO_OUTPUT - printf ("box tree is dead\n"); + printf("box tree is dead\n"); #endif - return 0; - } - if ( - pp->c.r<=n->head[0]->p.c.r && - pp->c.r>=n->tail[0]->p.c.r && - pp->c.g<=n->head[1]->p.c.g && - pp->c.g>=n->tail[1]->p.c.g && - pp->c.b<=n->head[2]->p.c.b && - pp->c.b>=n->tail[2]->p.c.b) { - return 1; - } - return 0; + return 0; + } + if (pp->c.r <= n->head[0]->p.c.r && pp->c.r >= n->tail[0]->p.c.r && + pp->c.g <= n->head[1]->p.c.g && pp->c.g >= n->tail[1]->p.c.g && + pp->c.b <= n->head[2]->p.c.b && pp->c.b >= n->tail[2]->p.c.b) { + return 1; + } + return 0; } #endif static int -annotate_hash_table(BoxNode *n,HashTable *h,uint32_t *box) -{ - PixelList *p; - PixelHashData *d=(PixelHashData *)hashtable_get_user_data(h); - Pixel q; - if (n->l&&n->r) { - return annotate_hash_table(n->l,h,box) && annotate_hash_table(n->r,h,box); - } - if (n->l||n->r) { +annotate_hash_table(BoxNode *n, HashTable *h, uint32_t *box) { + PixelList *p; + PixelHashData *d = (PixelHashData *)hashtable_get_user_data(h); + Pixel q; + if (n->l && n->r) { + return annotate_hash_table(n->l, h, box) && annotate_hash_table(n->r, h, box); + } + if (n->l || n->r) { #ifndef NO_OUTPUT - printf ("box tree is dead\n"); + printf("box tree is dead\n"); #endif - return 0; - } - for (p=n->head[0];p;p=p->next[0]) { - PIXEL_UNSCALE(&(p->p),&q,d->scale); - if (!hashtable_insert(h,q,*box)) { + return 0; + } + for (p = n->head[0]; p; p = p->next[0]) { + PIXEL_UNSCALE(&(p->p), &q, d->scale); + if (!hashtable_insert(h, q, *box)) { #ifndef NO_OUTPUT - printf ("hashtable insert failed\n"); + printf("hashtable insert failed\n"); #endif - return 0; - } - } - if (n->head[0]) { - (*box)++; - } - return 1; + return 0; + } + } + if (n->head[0]) { + (*box)++; + } + return 1; +} + +typedef struct { + uint32_t *distance; + uint32_t index; +} DistanceWithIndex; + +static int +_distance_index_cmp(const void *a, const void *b) { + DistanceWithIndex *A = (DistanceWithIndex *)a; + DistanceWithIndex *B = (DistanceWithIndex *)b; + if (*A->distance == *B->distance) { + return A->index < B->index ? -1 : +1; + } + return *A->distance < *B->distance ? -1 : +1; } static int -_sort_ulong_ptr_keys(const void *a, const void *b) -{ - uint32_t A=**(uint32_t **)a; - uint32_t B=**(uint32_t **)b; - return (A==B)?0:((A*(skRow[k]));k--) { - skRow[k]=skRow[k-1]; - } - if (k!=j) { - skRow[k]=skElt; - } - } - } - return 1; -} - -static int -build_distance_tables(uint32_t *avgDist, - uint32_t **avgDistSortKey, - Pixel *p, - uint32_t nEntries) -{ - uint32_t i,j; - - for (i=0;i *(skRow[k])); k--) { + skRow[k] = skRow[k - 1]; } - } - hashtable_insert(h2,pixelData[i],bestmatch); - } - pixelArray[i]=bestmatch; - } - hashtable_free(h2); - return 1; + if (k != j) { + skRow[k] = skElt; + } + } + } + return 1; +} + +static int +build_distance_tables( + uint32_t *avgDist, uint32_t **avgDistSortKey, Pixel *p, uint32_t nEntries) { + uint32_t i, j; + DistanceWithIndex *dwi; + + for (i = 0; i < nEntries; i++) { + avgDist[i * nEntries + i] = 0; + avgDistSortKey[i * nEntries + i] = &(avgDist[i * nEntries + i]); + for (j = 0; j < i; j++) { + avgDist[j * nEntries + i] = avgDist[i * nEntries + j] = + _DISTSQR(p + i, p + j); + avgDistSortKey[j * nEntries + i] = &(avgDist[j * nEntries + i]); + avgDistSortKey[i * nEntries + j] = &(avgDist[i * nEntries + j]); + } + } + + dwi = calloc(nEntries, sizeof(DistanceWithIndex)); + if (!dwi) { + return 0; + } + for (i = 0; i < nEntries; i++) { + for (j = 0; j < nEntries; j++) { + dwi[j] = (DistanceWithIndex){ + &(avgDist[i * nEntries + j]), + j + }; + } + qsort( + dwi, + nEntries, + sizeof(DistanceWithIndex), + _distance_index_cmp); + for (j = 0; j < nEntries; j++) { + avgDistSortKey[i * nEntries + j] = dwi[j].distance; + } + } + free(dwi); + return 1; +} + +static int +map_image_pixels( + Pixel *pixelData, + uint32_t nPixels, + Pixel *paletteData, + uint32_t nPaletteEntries, + uint32_t *avgDist, + uint32_t **avgDistSortKey, + uint32_t *pixelArray) { + uint32_t *aD, **aDSK; + uint32_t idx; + uint32_t i, j; + uint32_t bestdist, bestmatch, dist; + uint32_t initialdist; + HashTable *h2; + + h2 = hashtable_new(unshifted_pixel_hash, unshifted_pixel_cmp); + for (i = 0; i < nPixels; i++) { + if (!hashtable_lookup(h2, pixelData[i], &bestmatch)) { + bestmatch = 0; + initialdist = _DISTSQR(paletteData + bestmatch, pixelData + i); + bestdist = initialdist; + initialdist <<= 2; + aDSK = avgDistSortKey + bestmatch * nPaletteEntries; + aD = avgDist + bestmatch * nPaletteEntries; + for (j = 0; j < nPaletteEntries; j++) { + idx = aDSK[j] - aD; + if (*(aDSK[j]) <= initialdist) { + dist = _DISTSQR(paletteData + idx, pixelData + i); + if (dist < bestdist) { + bestdist = dist; + bestmatch = idx; + } + } else { + break; + } + } + hashtable_insert(h2, pixelData[i], bestmatch); + } + pixelArray[i] = bestmatch; + } + hashtable_free(h2); + return 1; } static int @@ -880,54 +893,53 @@ map_image_pixels_from_quantized_pixels( uint32_t **avgDistSortKey, uint32_t *pixelArray, uint32_t *avg[3], - uint32_t *count) -{ - uint32_t *aD,**aDSK; - uint32_t idx; - uint32_t i,j; - uint32_t bestdist,bestmatch,dist; - uint32_t initialdist; - HashTable *h2; - int changes=0; + uint32_t *count) { + uint32_t *aD, **aDSK; + uint32_t idx; + uint32_t i, j; + uint32_t bestdist, bestmatch, dist; + uint32_t initialdist; + HashTable *h2; + int changes = 0; - h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp); - for (i=0;i1) { - printf ("pixel in two boxes\n"); - for(i=0;i<3;i++) { - free (avg[i]); - } - free(count); - return 0; - } + if (!(i % 100)) { + printf("%05d\r", i); + fflush(stdout); + } + if (checkContained(root, pixelData + i) > 1) { + printf("pixel in two boxes\n"); + for (i = 0; i < 3; i++) { + free(avg[i]); + } + free(count); + return 0; + } #endif - if (!hashtable_lookup(medianBoxHash,pixelData[i],&paletteEntry)) { + if (!hashtable_lookup(medianBoxHash, pixelData[i], &paletteEntry)) { #ifndef NO_OUTPUT - printf ("pixel lookup failed\n"); + printf("pixel lookup failed\n"); #endif - for(i=0;i<3;i++) { - free (avg[i]); - } - free(count); - return 0; - } - if (paletteEntry>=nPaletteEntries) { + for (i = 0; i < 3; i++) { + free(avg[i]); + } + free(count); + return 0; + } + if (paletteEntry >= nPaletteEntries) { #ifndef NO_OUTPUT - printf ("panic - paletteEntry>=nPaletteEntries (%d>=%d)\n",(int)paletteEntry,(int)nPaletteEntries); + printf( + "panic - paletteEntry>=nPaletteEntries (%d>=%d)\n", + (int)paletteEntry, + (int)nPaletteEntries); #endif - for(i=0;i<3;i++) { - free (avg[i]); - } - free(count); - return 0; - } - avg[0][paletteEntry]+=pixelData[i].c.r; - avg[1][paletteEntry]+=pixelData[i].c.g; - avg[2][paletteEntry]+=pixelData[i].c.b; - count[paletteEntry]++; - } - /* malloc check ok, using calloc */ - p=calloc(nPaletteEntries, sizeof(Pixel)); - if (!p) { - for(i=0;i<3;i++) { - free (avg[i]); - } - free(count); - return 0; - } - for (i=0;i=nPaletteEntries) { + memset(count, 0, sizeof(uint32_t) * nPaletteEntries); + for (i = 0; i < 3; i++) { + memset(avg[i], 0, sizeof(uint32_t) * nPaletteEntries); + } + for (i = 0; i < nPixels; i++) { + if (qp[i] >= nPaletteEntries) { #ifndef NO_OUTPUT - printf ("scream\n"); + printf("scream\n"); #endif - return 0; - } - avg[0][qp[i]]+=pixelData[i].c.r; - avg[1][qp[i]]+=pixelData[i].c.g; - avg[2][qp[i]]+=pixelData[i].c.b; - count[qp[i]]++; - } - for (i=0;i UINT32_MAX / (sizeof(uint32_t))) { - return 0; - } - /* malloc check ok, using calloc */ - if (!(count=calloc(nPaletteEntries, sizeof(uint32_t)))) { - return 0; - } - for(i=0;i<3;i++) { - avg[i]=NULL; - } - for(i=0;i<3;i++) { - /* malloc check ok, using calloc */ - if (!(avg[i]=calloc(nPaletteEntries, sizeof(uint32_t)))) { - goto error_1; - } - } + if (nPaletteEntries > UINT32_MAX / (sizeof(uint32_t))) { + return 0; + } + /* malloc check ok, using calloc */ + if (!(count = calloc(nPaletteEntries, sizeof(uint32_t)))) { + return 0; + } + for (i = 0; i < 3; i++) { + avg[i] = NULL; + } + for (i = 0; i < 3; i++) { + /* malloc check ok, using calloc */ + if (!(avg[i] = calloc(nPaletteEntries, sizeof(uint32_t)))) { + goto error_1; + } + } - /* this is enough of a check, since the multiplication n*size is done above */ - if (nPaletteEntries > UINT32_MAX / nPaletteEntries) { - goto error_1; - } - /* malloc check ok, using calloc, checking n*n above */ - avgDist=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t)); - if (!avgDist) { goto error_1; } + /* this is enough of a check, since the multiplication n*size is done above */ + if (nPaletteEntries > UINT32_MAX / nPaletteEntries) { + goto error_1; + } + /* malloc check ok, using calloc, checking n*n above */ + avgDist = calloc(nPaletteEntries * nPaletteEntries, sizeof(uint32_t)); + if (!avgDist) { + goto error_1; + } - /* malloc check ok, using calloc, checking n*n above */ - avgDistSortKey=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t *)); - if (!avgDistSortKey) { goto error_2; } + /* malloc check ok, using calloc, checking n*n above */ + avgDistSortKey = calloc(nPaletteEntries * nPaletteEntries, sizeof(uint32_t *)); + if (!avgDistSortKey) { + goto error_2; + } #ifndef NO_OUTPUT - printf("[");fflush(stdout); + printf("["); + fflush(stdout); #endif - while (1) { - if (!built) { - compute_palette_from_quantized_pixels(pixelData,nPixels,paletteData,nPaletteEntries,avg,count,qp); - build_distance_tables(avgDist,avgDistSortKey,paletteData,nPaletteEntries); - built=1; - } else { - recompute_palette_from_averages(paletteData,nPaletteEntries,avg,count); - resort_distance_tables(avgDist,avgDistSortKey,paletteData,nPaletteEntries); - } - changes=map_image_pixels_from_quantized_pixels(pixelData, - nPixels, - paletteData, - nPaletteEntries, - avgDist, - avgDistSortKey, - qp, - avg, - count); - if (changes<0) { - goto error_3; - } + while (1) { + if (!built) { + compute_palette_from_quantized_pixels( + pixelData, nPixels, paletteData, nPaletteEntries, avg, count, qp); + if (!build_distance_tables( + avgDist, avgDistSortKey, paletteData, nPaletteEntries)) { + goto error_3; + } + built = 1; + } else { + recompute_palette_from_averages(paletteData, nPaletteEntries, avg, count); + resort_distance_tables( + avgDist, avgDistSortKey, paletteData, nPaletteEntries); + } + changes = map_image_pixels_from_quantized_pixels( + pixelData, + nPixels, + paletteData, + nPaletteEntries, + avgDist, + avgDistSortKey, + qp, + avg, + count); + if (changes < 0) { + goto error_3; + } #ifndef NO_OUTPUT - printf (".(%d)",changes);fflush(stdout); + printf(".(%d)", changes); + fflush(stdout); #endif - if (changes<=threshold) { - break; - } - } + if (changes <= threshold) { + break; + } + } #ifndef NO_OUTPUT - printf("]\n"); + printf("]\n"); #endif - if (avgDistSortKey) { - free(avgDistSortKey); - } - if (avgDist) { - free(avgDist); - } - for(i=0;i<3;i++) { - if (avg[i]) { - free (avg[i]); - } - } - if (count) { - free(count); - } - return 1; + if (avgDistSortKey) { + free(avgDistSortKey); + } + if (avgDist) { + free(avgDist); + } + for (i = 0; i < 3; i++) { + if (avg[i]) { + free(avg[i]); + } + } + if (count) { + free(count); + } + return 1; error_3: - if (avgDistSortKey) { - free(avgDistSortKey); - } + if (avgDistSortKey) { + free(avgDistSortKey); + } error_2: - if (avgDist) { - free(avgDist); - } + if (avgDist) { + free(avgDist); + } error_1: - for(i=0;i<3;i++) { - if (avg[i]) { - free (avg[i]); - } - } - if (count) { - free(count); - } - return 0; + for (i = 0; i < 3; i++) { + if (avg[i]) { + free(avg[i]); + } + } + if (count) { + free(count); + } + return 0; } -int -quantize(Pixel *pixelData, - uint32_t nPixels, - uint32_t nQuantPixels, - Pixel **palette, - uint32_t *paletteLength, - uint32_t **quantizedPixels, - int kmeans) -{ - PixelList *hl[3]; - HashTable *h; - BoxNode *root; - uint32_t i; - uint32_t *qp; - uint32_t nPaletteEntries; +static int +quantize( + Pixel *pixelData, + uint32_t nPixels, + uint32_t nQuantPixels, + Pixel **palette, + uint32_t *paletteLength, + uint32_t **quantizedPixels, + int kmeans) { + PixelList *hl[3]; + HashTable *h; + BoxNode *root; + uint32_t i; + uint32_t *qp; + uint32_t nPaletteEntries; - uint32_t *avgDist; - uint32_t **avgDistSortKey; - Pixel *p; + uint32_t *avgDist; + uint32_t **avgDistSortKey; + Pixel *p; #ifndef NO_OUTPUT - uint32_t timer,timer2; + uint32_t timer, timer2; #endif #ifndef NO_OUTPUT - timer2=clock(); - printf ("create hash table..."); fflush(stdout); timer=clock(); + timer2 = clock(); + printf("create hash table..."); + fflush(stdout); + timer = clock(); #endif - h=create_pixel_hash(pixelData,nPixels); + h = create_pixel_hash(pixelData, nPixels); #ifndef NO_OUTPUT - printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); + printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC); #endif - if (!h) { - goto error_0; - } + if (!h) { + goto error_0; + } #ifndef NO_OUTPUT - printf ("create lists from hash table..."); fflush(stdout); timer=clock(); + printf("create lists from hash table..."); + fflush(stdout); + timer = clock(); #endif - hl[0]=hl[1]=hl[2]=NULL; - hashtable_foreach(h,hash_to_list,hl); + hl[0] = hl[1] = hl[2] = NULL; + hashtable_foreach(h, hash_to_list, hl); #ifndef NO_OUTPUT - printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); + printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC); #endif - if (!hl[0]) { - goto error_1; - } + if (!hl[0]) { + goto error_1; + } #ifndef NO_OUTPUT - printf ("mergesort lists..."); fflush(stdout); timer=clock(); + printf("mergesort lists..."); + fflush(stdout); + timer = clock(); #endif - for(i=0;i<3;i++) { - hl[i]=mergesort_pixels(hl[i],i); - } + for (i = 0; i < 3; i++) { + hl[i] = mergesort_pixels(hl[i], i); + } #ifdef TEST_MERGESORT - if (!test_sorted(hl)) { - printf ("bug in mergesort\n"); - goto error_1; - } + if (!test_sorted(hl)) { + printf("bug in mergesort\n"); + goto error_1; + } #endif #ifndef NO_OUTPUT - printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); + printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC); #endif #ifndef NO_OUTPUT - printf ("median cut..."); fflush(stdout); timer=clock(); + printf("median cut..."); + fflush(stdout); + timer = clock(); #endif - root=median_cut(hl,nPixels,nQuantPixels); + root = median_cut(hl, nPixels, nQuantPixels); #ifndef NO_OUTPUT - printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); + printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC); #endif - if (!root) { - goto error_1; - } - nPaletteEntries=0; + if (!root) { + goto error_1; + } + nPaletteEntries = 0; #ifndef NO_OUTPUT - printf ("median cut tree to hash table..."); fflush(stdout); timer=clock(); + printf("median cut tree to hash table..."); + fflush(stdout); + timer = clock(); #endif - annotate_hash_table(root,h,&nPaletteEntries); + annotate_hash_table(root, h, &nPaletteEntries); #ifndef NO_OUTPUT - printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); + printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC); #endif #ifndef NO_OUTPUT - printf ("compute palette...\n"); fflush(stdout); timer=clock(); + printf("compute palette...\n"); + fflush(stdout); + timer = clock(); #endif - if (!compute_palette_from_median_cut(pixelData,nPixels,h,&p,nPaletteEntries)) { - goto error_3; - } + if (!compute_palette_from_median_cut(pixelData, nPixels, h, &p, nPaletteEntries)) { + goto error_3; + } #ifndef NO_OUTPUT - printf ("done (%f)\n",(clock()-timer)/(double)CLOCKS_PER_SEC); + printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC); #endif - free_box_tree(root); - root=NULL; + free_box_tree(root); + root = NULL; - /* malloc check ok, using calloc for overflow */ - qp=calloc(nPixels, sizeof(uint32_t)); - if (!qp) { goto error_4; } + /* malloc check ok, using calloc for overflow */ + qp = calloc(nPixels, sizeof(uint32_t)); + if (!qp) { + goto error_4; + } - if (nPaletteEntries > UINT32_MAX / nPaletteEntries ) { - goto error_5; - } - /* malloc check ok, using calloc for overflow, check of n*n above */ - avgDist=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t)); - if (!avgDist) { goto error_5; } + if (nPaletteEntries > UINT32_MAX / nPaletteEntries) { + goto error_5; + } + /* malloc check ok, using calloc for overflow, check of n*n above */ + avgDist = calloc(nPaletteEntries * nPaletteEntries, sizeof(uint32_t)); + if (!avgDist) { + goto error_5; + } - /* malloc check ok, using calloc for overflow, check of n*n above */ - avgDistSortKey=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t *)); - if (!avgDistSortKey) { goto error_6; } + /* malloc check ok, using calloc for overflow, check of n*n above */ + avgDistSortKey = calloc(nPaletteEntries * nPaletteEntries, sizeof(uint32_t *)); + if (!avgDistSortKey) { + goto error_6; + } - if (!build_distance_tables(avgDist,avgDistSortKey,p,nPaletteEntries)) { - goto error_7; - } + if (!build_distance_tables(avgDist, avgDistSortKey, p, nPaletteEntries)) { + goto error_7; + } - if (!map_image_pixels_from_median_box(pixelData,nPixels,p,nPaletteEntries,h,avgDist,avgDistSortKey,qp)) { - goto error_7; - } + if (!map_image_pixels_from_median_box( + pixelData, nPixels, p, nPaletteEntries, h, avgDist, avgDistSortKey, qp)) { + goto error_7; + } #ifdef TEST_NEAREST_NEIGHBOUR #include - { - uint32_t bestmatch,bestdist,dist; - HashTable *h2; - printf ("nearest neighbour search (full search)..."); fflush(stdout); timer=clock(); - h2=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp); - for (i=0;inew),&pixel); - if (data->secondPixel || newDistdata->furthestDistance) { - data->furthestDistance=oldDist; - data->furthest.v=pixel.v; - } +compute_distances(const HashTable *h, const Pixel pixel, uint32_t *dist, void *u) { + DistanceData *data = (DistanceData *)u; + uint32_t oldDist = *dist; + uint32_t newDist; + newDist = _DISTSQR(&(data->new), &pixel); + if (data->secondPixel || newDist < oldDist) { + *dist = newDist; + oldDist = newDist; + } + if (oldDist > data->furthestDistance) { + data->furthestDistance = oldDist; + data->furthest.v = pixel.v; + } } -int -quantize2(Pixel *pixelData, - uint32_t nPixels, - uint32_t nQuantPixels, - Pixel **palette, - uint32_t *paletteLength, - uint32_t **quantizedPixels, - int kmeans) -{ - HashTable *h; - uint32_t i; - uint32_t mean[3]; - Pixel *p; - DistanceData data; +static int +quantize2( + Pixel *pixelData, + uint32_t nPixels, + uint32_t nQuantPixels, + Pixel **palette, + uint32_t *paletteLength, + uint32_t **quantizedPixels, + int kmeans) { + HashTable *h; + uint32_t i; + uint32_t mean[3]; + Pixel *p; + DistanceData data; - uint32_t *qp; - uint32_t *avgDist; - uint32_t **avgDistSortKey; + uint32_t *qp; + uint32_t *avgDist; + uint32_t **avgDistSortKey; - /* malloc check ok, using calloc */ - p=calloc(nQuantPixels, sizeof(Pixel)); - if (!p) { - return 0; - } - mean[0]=mean[1]=mean[2]=0; - h=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp); - for (i=0;i UINT32_MAX / nQuantPixels ) { - goto error_2; - } + if (nQuantPixels > UINT32_MAX / nQuantPixels) { + goto error_2; + } - /* malloc check ok, using calloc for overflow, check of n*n above */ - avgDist=calloc(nQuantPixels*nQuantPixels, sizeof(uint32_t)); - if (!avgDist) { goto error_2; } + /* malloc check ok, using calloc for overflow, check of n*n above */ + avgDist = calloc(nQuantPixels * nQuantPixels, sizeof(uint32_t)); + if (!avgDist) { + goto error_2; + } - /* malloc check ok, using calloc for overflow, check of n*n above */ - avgDistSortKey=calloc(nQuantPixels*nQuantPixels, sizeof(uint32_t *)); - if (!avgDistSortKey) { goto error_3; } + /* malloc check ok, using calloc for overflow, check of n*n above */ + avgDistSortKey = calloc(nQuantPixels * nQuantPixels, sizeof(uint32_t *)); + if (!avgDistSortKey) { + goto error_3; + } - if (!build_distance_tables(avgDist,avgDistSortKey,p,nQuantPixels)) { - goto error_4; - } + if (!build_distance_tables(avgDist, avgDistSortKey, p, nQuantPixels)) { + goto error_4; + } - if (!map_image_pixels(pixelData,nPixels,p,nQuantPixels,avgDist,avgDistSortKey,qp)) { - goto error_4; - } - if (kmeans) { - k_means(pixelData,nPixels,p,nQuantPixels,qp,kmeans-1); - } + if (!map_image_pixels( + pixelData, nPixels, p, nQuantPixels, avgDist, avgDistSortKey, qp)) { + goto error_4; + } + if (kmeans) { + k_means(pixelData, nPixels, p, nQuantPixels, qp, kmeans - 1); + } - *paletteLength=nQuantPixels; - *palette=p; - *quantizedPixels=qp; - free(avgDistSortKey); - free(avgDist); - return 1; + *paletteLength = nQuantPixels; + *palette = p; + *quantizedPixels = qp; + free(avgDistSortKey); + free(avgDist); + return 1; error_4: - free(avgDistSortKey); + free(avgDistSortKey); error_3: - free(avgDist); + free(avgDist); error_2: - free(qp); + free(qp); error_1: - free(p); - return 0; + free(p); + return 0; } Imaging -ImagingQuantize(Imaging im, int colors, int mode, int kmeans) -{ +ImagingQuantize(Imaging im, int colors, int mode, int kmeans) { int i, j; int x, y, v; - UINT8* pp; - Pixel* p; - Pixel* palette; + UINT8 *pp; + Pixel *p; + Pixel *palette; uint32_t paletteLength; int result; - uint32_t* newData; + uint32_t *newData; Imaging imOut; int withAlpha = 0; ImagingSectionCookie cookie; @@ -1605,17 +1656,17 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) if (colors < 1 || colors > 256) { /* FIXME: for colors > 256, consider returning an RGB image instead (see @PIL205) */ - return (Imaging) ImagingError_ValueError("bad number of colors"); + return (Imaging)ImagingError_ValueError("bad number of colors"); } if (strcmp(im->mode, "L") != 0 && strcmp(im->mode, "P") != 0 && - strcmp(im->mode, "RGB") != 0 && strcmp(im->mode, "RGBA") !=0) { + strcmp(im->mode, "RGB") != 0 && strcmp(im->mode, "RGBA") != 0) { return ImagingError_ModeError(); } /* only octree and imagequant supports RGBA */ if (!strcmp(im->mode, "RGBA") && mode != 2 && mode != 3) { - return ImagingError_ModeError(); + return ImagingError_ModeError(); } if (im->xsize > INT_MAX / im->ysize) { @@ -1653,90 +1704,97 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) for (i = y = 0; y < im->ysize; y++) { for (x = 0; x < im->xsize; x++, i++) { v = im->image8[y][x]; - p[i].c.r = pp[v*4+0]; - p[i].c.g = pp[v*4+1]; - p[i].c.b = pp[v*4+2]; - p[i].c.a = pp[v*4+3]; + p[i].c.r = pp[v * 4 + 0]; + p[i].c.g = pp[v * 4 + 1]; + p[i].c.b = pp[v * 4 + 2]; + p[i].c.a = pp[v * 4 + 3]; } } } else if (!strcmp(im->mode, "RGB") || !strcmp(im->mode, "RGBA")) { /* true colour */ + withAlpha = !strcmp(im->mode, "RGBA"); + int transparency = 0; + unsigned char r, g, b; for (i = y = 0; y < im->ysize; y++) { for (x = 0; x < im->xsize; x++, i++) { p[i].v = im->image32[y][x]; + if (withAlpha && p[i].c.a == 0) { + if (transparency == 0) { + transparency = 1; + r = p[i].c.r; + g = p[i].c.g; + b = p[i].c.b; + } else { + /* Set all subsequent transparent pixels + to the same colour as the first */ + p[i].c.r = r; + p[i].c.g = g; + p[i].c.b = b; + } + } } } } else { free(p); - return (Imaging) ImagingError_ValueError("internal error"); + return (Imaging)ImagingError_ValueError("internal error"); } ImagingSectionEnter(&cookie); switch (mode) { - case 0: - /* median cut */ - result = quantize( - p, - im->xsize*im->ysize, - colors, - &palette, - &paletteLength, - &newData, - kmeans - ); - break; - case 1: - /* maximum coverage */ - result = quantize2( - p, - im->xsize*im->ysize, - colors, - &palette, - &paletteLength, - &newData, - kmeans - ); - break; - case 2: - if (!strcmp(im->mode, "RGBA")) { - withAlpha = 1; - } - result = quantize_octree( - p, - im->xsize*im->ysize, - colors, - &palette, - &paletteLength, - &newData, - withAlpha - ); - break; - case 3: + case 0: + /* median cut */ + result = quantize( + p, + im->xsize * im->ysize, + colors, + &palette, + &paletteLength, + &newData, + kmeans); + break; + case 1: + /* maximum coverage */ + result = quantize2( + p, + im->xsize * im->ysize, + colors, + &palette, + &paletteLength, + &newData, + kmeans); + break; + case 2: + result = quantize_octree( + p, + im->xsize * im->ysize, + colors, + &palette, + &paletteLength, + &newData, + withAlpha); + break; + case 3: #ifdef HAVE_LIBIMAGEQUANT - if (!strcmp(im->mode, "RGBA")) { - withAlpha = 1; - } - result = quantize_pngquant( - p, - im->xsize, - im->ysize, - colors, - &palette, - &paletteLength, - &newData, - withAlpha - ); + result = quantize_pngquant( + p, + im->xsize, + im->ysize, + colors, + &palette, + &paletteLength, + &newData, + withAlpha); #else - result = -1; + result = -1; #endif - break; - default: - result = 0; - break; + break; + default: + result = 0; + break; } free(p); @@ -1748,7 +1806,7 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) for (i = y = 0; y < im->ysize; y++) { for (x = 0; x < im->xsize; x++) { - imOut->image8[y][x] = (unsigned char) newData[i++]; + imOut->image8[y][x] = (unsigned char)newData[i++]; } } @@ -1756,14 +1814,14 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) pp = imOut->palette->palette; - for (i = j = 0; i < (int) paletteLength; i++) { + for (i = j = 0; i < (int)paletteLength; i++) { *pp++ = palette[i].c.r; *pp++ = palette[i].c.g; *pp++ = palette[i].c.b; if (withAlpha) { - *pp++ = palette[i].c.a; + *pp++ = palette[i].c.a; } else { - *pp++ = 255; + *pp++ = 255; } } for (; i < 256; i++) { @@ -1783,14 +1841,12 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) return imOut; } else { - if (result == -1) { - return (Imaging) ImagingError_ValueError( + return (Imaging)ImagingError_ValueError( "dependency required by this method was not " "enabled at compile time"); } - return (Imaging) ImagingError_ValueError("quantization error"); - + return (Imaging)ImagingError_ValueError("quantization error"); } } diff --git a/src/libImaging/QuantHash.c b/src/libImaging/QuantHash.c index 6ff95d885..ea75d6037 100644 --- a/src/libImaging/QuantHash.c +++ b/src/libImaging/QuantHash.c @@ -24,290 +24,313 @@ #include "QuantHash.h" typedef struct _HashNode { - struct _HashNode *next; - HashKey_t key; - HashVal_t value; + struct _HashNode *next; + HashKey_t key; + HashVal_t value; } HashNode; struct _HashTable { - HashNode **table; - uint32_t length; - uint32_t count; - HashFunc hashFunc; - HashCmpFunc cmpFunc; - void *userData; + HashNode **table; + uint32_t length; + uint32_t count; + HashFunc hashFunc; + HashCmpFunc cmpFunc; + void *userData; }; #define MIN_LENGTH 11 #define RESIZE_FACTOR 3 -static int _hashtable_insert_node(HashTable *,HashNode *,int,int,CollisionFunc); +static int +_hashtable_insert_node(HashTable *, HashNode *, int, int, CollisionFunc); -HashTable *hashtable_new(HashFunc hf,HashCmpFunc cf) { - HashTable *h; - h=malloc(sizeof(HashTable)); - if (!h) { return NULL; } - h->hashFunc=hf; - h->cmpFunc=cf; - h->length=MIN_LENGTH; - h->count=0; - h->userData=NULL; - h->table=malloc(sizeof(HashNode *)*h->length); - if (!h->table) { free(h); return NULL; } - memset (h->table,0,sizeof(HashNode *)*h->length); - return h; +HashTable * +hashtable_new(HashFunc hf, HashCmpFunc cf) { + HashTable *h; + h = malloc(sizeof(HashTable)); + if (!h) { + return NULL; + } + h->hashFunc = hf; + h->cmpFunc = cf; + h->length = MIN_LENGTH; + h->count = 0; + h->userData = NULL; + h->table = malloc(sizeof(HashNode *) * h->length); + if (!h->table) { + free(h); + return NULL; + } + memset(h->table, 0, sizeof(HashNode *) * h->length); + return h; } -static uint32_t _findPrime(uint32_t start,int dir) { - static int unit[]={0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0}; - uint32_t t; - while (start>1) { - if (!unit[start&0x0f]) { - start+=dir; - continue; - } - for (t=2;t=sqrt((double)start)) { - break; - } - start+=dir; - } - return start; +static uint32_t +_findPrime(uint32_t start, int dir) { + static int unit[] = {0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0}; + uint32_t t; + while (start > 1) { + if (!unit[start & 0x0f]) { + start += dir; + continue; + } + for (t = 2; t < sqrt((double)start); t++) { + if (!start % t) { + break; + } + } + if (t >= sqrt((double)start)) { + break; + } + start += dir; + } + return start; } -static void _hashtable_rehash(HashTable *h,CollisionFunc cf,uint32_t newSize) { - HashNode **oldTable=h->table; - uint32_t i; - HashNode *n,*nn; - uint32_t oldSize; - oldSize=h->length; - h->table=malloc(sizeof(HashNode *)*newSize); - if (!h->table) { - h->table=oldTable; - return; - } - h->length=newSize; - h->count=0; - memset (h->table,0,sizeof(HashNode *)*h->length); - for (i=0;inext; - _hashtable_insert_node(h,n,0,0,cf); - } - } - free(oldTable); +static void +_hashtable_rehash(HashTable *h, CollisionFunc cf, uint32_t newSize) { + HashNode **oldTable = h->table; + uint32_t i; + HashNode *n, *nn; + uint32_t oldSize; + oldSize = h->length; + h->table = malloc(sizeof(HashNode *) * newSize); + if (!h->table) { + h->table = oldTable; + return; + } + h->length = newSize; + h->count = 0; + memset(h->table, 0, sizeof(HashNode *) * h->length); + for (i = 0; i < oldSize; i++) { + for (n = oldTable[i]; n; n = nn) { + nn = n->next; + _hashtable_insert_node(h, n, 0, 0, cf); + } + } + free(oldTable); } -static void _hashtable_resize(HashTable *h) { - uint32_t newSize; - uint32_t oldSize; - oldSize=h->length; - newSize=oldSize; - if (h->count*RESIZE_FACTORlength) { - newSize=_findPrime(h->length/2-1,-1); - } else if (h->length*RESIZE_FACTORcount) { - newSize=_findPrime(h->length*2+1,+1); - } - if (newSizelength; + newSize = oldSize; + if (h->count * RESIZE_FACTOR < h->length) { + newSize = _findPrime(h->length / 2 - 1, -1); + } else if (h->length * RESIZE_FACTOR < h->count) { + newSize = _findPrime(h->length * 2 + 1, +1); + } + if (newSize < MIN_LENGTH) { + newSize = oldSize; + } + if (newSize != oldSize) { + _hashtable_rehash(h, NULL, newSize); + } } -static int _hashtable_insert_node(HashTable *h,HashNode *node,int resize,int update,CollisionFunc cf) { - uint32_t hash=h->hashFunc(h,node->key)%h->length; - HashNode **n,*nv; - int i; +static int +_hashtable_insert_node( + HashTable *h, HashNode *node, int resize, int update, CollisionFunc cf) { + uint32_t hash = h->hashFunc(h, node->key) % h->length; + HashNode **n, *nv; + int i; - for (n=&(h->table[hash]);*n;n=&((*n)->next)) { - nv=*n; - i=h->cmpFunc(h,nv->key,node->key); - if (!i) { - if (cf) { - nv->key=node->key; - cf(h,&(nv->key),&(nv->value),node->key,node->value); - free(node); + for (n = &(h->table[hash]); *n; n = &((*n)->next)) { + nv = *n; + i = h->cmpFunc(h, nv->key, node->key); + if (!i) { + if (cf) { + nv->key = node->key; + cf(h, &(nv->key), &(nv->value), node->key, node->value); + free(node); + return 1; + } else { + nv->key = node->key; + nv->value = node->value; + free(node); + return 1; + } + } else if (i > 0) { + break; + } + } + if (!update) { + node->next = *n; + *n = node; + h->count++; + if (resize) { + _hashtable_resize(h); + } + return 1; + } else { + return 0; + } +} + +static int +_hashtable_insert(HashTable *h, HashKey_t key, HashVal_t val, int resize, int update) { + HashNode **n, *nv; + HashNode *t; + int i; + uint32_t hash = h->hashFunc(h, key) % h->length; + + for (n = &(h->table[hash]); *n; n = &((*n)->next)) { + nv = *n; + i = h->cmpFunc(h, nv->key, key); + if (!i) { + nv->value = val; return 1; - } else { - nv->key=node->key; - nv->value=node->value; - free(node); - return 1; - } - } else if (i>0) { - break; - } - } - if (!update) { - node->next=*n; - *n=node; - h->count++; - if (resize) { - _hashtable_resize(h); - } - return 1; - } else { - return 0; - } -} - -static int _hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val,int resize,int update) { - HashNode **n,*nv; - HashNode *t; - int i; - uint32_t hash=h->hashFunc(h,key)%h->length; - - for (n=&(h->table[hash]);*n;n=&((*n)->next)) { - nv=*n; - i=h->cmpFunc(h,nv->key,key); - if (!i) { - nv->value=val; - return 1; - } else if (i>0) { - break; - } - } - if (!update) { - t=malloc(sizeof(HashNode)); - if (!t) { - return 0; - } - t->next=*n; - *n=t; - t->key=key; - t->value=val; - h->count++; - if (resize) { - _hashtable_resize(h); - } - return 1; - } else { - return 0; - } -} - -int hashtable_insert_or_update_computed(HashTable *h, - HashKey_t key, - ComputeFunc newFunc, - ComputeFunc existsFunc) { - HashNode **n,*nv; - HashNode *t; - int i; - uint32_t hash=h->hashFunc(h,key)%h->length; - - for (n=&(h->table[hash]);*n;n=&((*n)->next)) { - nv=*n; - i=h->cmpFunc(h,nv->key,key); - if (!i) { - if (existsFunc) { - existsFunc(h,nv->key,&(nv->value)); - } else { + } else if (i > 0) { + break; + } + } + if (!update) { + t = malloc(sizeof(HashNode)); + if (!t) { return 0; - } - return 1; - } else if (i>0) { - break; - } - } - t=malloc(sizeof(HashNode)); - if (!t) { - return 0; - } - t->key=key; - t->next=*n; - *n=t; - if (newFunc) { - newFunc(h,t->key,&(t->value)); - } else { - free(t); - return 0; - } - h->count++; - _hashtable_resize(h); - return 1; + } + t->next = *n; + *n = t; + t->key = key; + t->value = val; + h->count++; + if (resize) { + _hashtable_resize(h); + } + return 1; + } else { + return 0; + } } -int hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val) { - return _hashtable_insert(h,key,val,1,0); +int +hashtable_insert_or_update_computed( + HashTable *h, HashKey_t key, ComputeFunc newFunc, ComputeFunc existsFunc) { + HashNode **n, *nv; + HashNode *t; + int i; + uint32_t hash = h->hashFunc(h, key) % h->length; + + for (n = &(h->table[hash]); *n; n = &((*n)->next)) { + nv = *n; + i = h->cmpFunc(h, nv->key, key); + if (!i) { + if (existsFunc) { + existsFunc(h, nv->key, &(nv->value)); + } else { + return 0; + } + return 1; + } else if (i > 0) { + break; + } + } + t = malloc(sizeof(HashNode)); + if (!t) { + return 0; + } + t->key = key; + t->next = *n; + *n = t; + if (newFunc) { + newFunc(h, t->key, &(t->value)); + } else { + free(t); + return 0; + } + h->count++; + _hashtable_resize(h); + return 1; } -void hashtable_foreach_update(HashTable *h,IteratorUpdateFunc i,void *u) { - HashNode *n; - uint32_t x; - - if (h->table) { - for (x=0;xlength;x++) { - for (n=h->table[x];n;n=n->next) { - i(h,n->key,&(n->value),u); - } - } - } +int +hashtable_insert(HashTable *h, HashKey_t key, HashVal_t val) { + return _hashtable_insert(h, key, val, 1, 0); } -void hashtable_foreach(HashTable *h,IteratorFunc i,void *u) { - HashNode *n; - uint32_t x; +void +hashtable_foreach_update(HashTable *h, IteratorUpdateFunc i, void *u) { + HashNode *n; + uint32_t x; - if (h->table) { - for (x=0;xlength;x++) { - for (n=h->table[x];n;n=n->next) { - i(h,n->key,n->value,u); - } - } - } + if (h->table) { + for (x = 0; x < h->length; x++) { + for (n = h->table[x]; n; n = n->next) { + i(h, n->key, &(n->value), u); + } + } + } } -void hashtable_free(HashTable *h) { - HashNode *n,*nn; - uint32_t i; +void +hashtable_foreach(HashTable *h, IteratorFunc i, void *u) { + HashNode *n; + uint32_t x; - if (h->table) { - for (i=0;ilength;i++) { - for (n=h->table[i];n;n=nn) { - nn=n->next; - free(n); - } - } - free(h->table); - } - free(h); + if (h->table) { + for (x = 0; x < h->length; x++) { + for (n = h->table[x]; n; n = n->next) { + i(h, n->key, n->value, u); + } + } + } } -void hashtable_rehash_compute(HashTable *h,CollisionFunc cf) { - _hashtable_rehash(h,cf,h->length); +void +hashtable_free(HashTable *h) { + HashNode *n, *nn; + uint32_t i; + + if (h->table) { + for (i = 0; i < h->length; i++) { + for (n = h->table[i]; n; n = nn) { + nn = n->next; + free(n); + } + } + free(h->table); + } + free(h); } -int hashtable_lookup(const HashTable *h,const HashKey_t key,HashVal_t *valp) { - uint32_t hash=h->hashFunc(h,key)%h->length; - HashNode *n; - int i; - - for (n=h->table[hash];n;n=n->next) { - i=h->cmpFunc(h,n->key,key); - if (!i) { - *valp=n->value; - return 1; - } else if (i>0) { - break; - } - } - return 0; +void +hashtable_rehash_compute(HashTable *h, CollisionFunc cf) { + _hashtable_rehash(h, cf, h->length); } -uint32_t hashtable_get_count(const HashTable *h) { - return h->count; +int +hashtable_lookup(const HashTable *h, const HashKey_t key, HashVal_t *valp) { + uint32_t hash = h->hashFunc(h, key) % h->length; + HashNode *n; + int i; + + for (n = h->table[hash]; n; n = n->next) { + i = h->cmpFunc(h, n->key, key); + if (!i) { + *valp = n->value; + return 1; + } else if (i > 0) { + break; + } + } + return 0; } -void *hashtable_get_user_data(const HashTable *h) { - return h->userData; +uint32_t +hashtable_get_count(const HashTable *h) { + return h->count; } -void *hashtable_set_user_data(HashTable *h,void *data) { - void *r=h->userData; - h->userData=data; - return r; +void * +hashtable_get_user_data(const HashTable *h) { + return h->userData; +} + +void * +hashtable_set_user_data(HashTable *h, void *data) { + void *r = h->userData; + h->userData = data; + return r; } diff --git a/src/libImaging/QuantHash.h b/src/libImaging/QuantHash.h index 9874114e5..fc1a99003 100644 --- a/src/libImaging/QuantHash.h +++ b/src/libImaging/QuantHash.h @@ -18,23 +18,38 @@ typedef struct _HashTable HashTable; typedef Pixel HashKey_t; typedef uint32_t HashVal_t; -typedef uint32_t (*HashFunc)(const HashTable *,const HashKey_t); -typedef int (*HashCmpFunc)(const HashTable *,const HashKey_t,const HashKey_t); -typedef void (*IteratorFunc)(const HashTable *,const HashKey_t,const HashVal_t,void *); -typedef void (*IteratorUpdateFunc)(const HashTable *,const HashKey_t,HashVal_t *,void *); -typedef void (*ComputeFunc)(const HashTable *,const HashKey_t,HashVal_t *); -typedef void (*CollisionFunc)(const HashTable *,HashKey_t *,HashVal_t *,HashKey_t,HashVal_t); +typedef uint32_t (*HashFunc)(const HashTable *, const HashKey_t); +typedef int (*HashCmpFunc)(const HashTable *, const HashKey_t, const HashKey_t); +typedef void (*IteratorFunc)( + const HashTable *, const HashKey_t, const HashVal_t, void *); +typedef void (*IteratorUpdateFunc)( + const HashTable *, const HashKey_t, HashVal_t *, void *); +typedef void (*ComputeFunc)(const HashTable *, const HashKey_t, HashVal_t *); +typedef void (*CollisionFunc)( + const HashTable *, HashKey_t *, HashVal_t *, HashKey_t, HashVal_t); -HashTable * hashtable_new(HashFunc hf,HashCmpFunc cf); -void hashtable_free(HashTable *h); -void hashtable_foreach(HashTable *h,IteratorFunc i,void *u); -void hashtable_foreach_update(HashTable *h,IteratorUpdateFunc i,void *u); -int hashtable_insert(HashTable *h,HashKey_t key,HashVal_t val); -int hashtable_lookup(const HashTable *h,const HashKey_t key,HashVal_t *valp); -int hashtable_insert_or_update_computed(HashTable *h,HashKey_t key,ComputeFunc newFunc,ComputeFunc existsFunc); -void *hashtable_set_user_data(HashTable *h,void *data); -void *hashtable_get_user_data(const HashTable *h); -uint32_t hashtable_get_count(const HashTable *h); -void hashtable_rehash_compute(HashTable *h,CollisionFunc cf); +HashTable * +hashtable_new(HashFunc hf, HashCmpFunc cf); +void +hashtable_free(HashTable *h); +void +hashtable_foreach(HashTable *h, IteratorFunc i, void *u); +void +hashtable_foreach_update(HashTable *h, IteratorUpdateFunc i, void *u); +int +hashtable_insert(HashTable *h, HashKey_t key, HashVal_t val); +int +hashtable_lookup(const HashTable *h, const HashKey_t key, HashVal_t *valp); +int +hashtable_insert_or_update_computed( + HashTable *h, HashKey_t key, ComputeFunc newFunc, ComputeFunc existsFunc); +void * +hashtable_set_user_data(HashTable *h, void *data); +void * +hashtable_get_user_data(const HashTable *h); +uint32_t +hashtable_get_count(const HashTable *h); +void +hashtable_rehash_compute(HashTable *h, CollisionFunc cf); -#endif // __QUANTHASH_H__ +#endif // __QUANTHASH_H__ diff --git a/src/libImaging/QuantHeap.c b/src/libImaging/QuantHeap.c index 6877e34a3..6fb52d890 100644 --- a/src/libImaging/QuantHeap.c +++ b/src/libImaging/QuantHeap.c @@ -25,10 +25,10 @@ #include "QuantHeap.h" struct _Heap { - void **heap; - unsigned int heapsize; - unsigned int heapcount; - HeapCmpFunc cf; + void **heap; + unsigned int heapsize; + unsigned int heapcount; + HeapCmpFunc cf; }; #define INITIAL_SIZE 256 @@ -36,127 +36,141 @@ struct _Heap { // #define DEBUG #ifdef DEBUG -static int _heap_test(Heap *); +static int +_heap_test(Heap *); #endif -void ImagingQuantHeapFree(Heap *h) { - free(h->heap); - free(h); +void +ImagingQuantHeapFree(Heap *h) { + free(h->heap); + free(h); } -static int _heap_grow(Heap *h,unsigned int newsize) { - void *newheap; - if (!newsize) { - newsize=h->heapsize<<1; - } - if (newsizeheapsize) { - return 0; - } - if (newsize > INT_MAX / sizeof(void *)){ - return 0; - } - /* malloc check ok, using calloc for overflow, also checking - above due to memcpy below*/ - newheap=calloc(newsize, sizeof(void *)); - if (!newheap) { - return 0; - } - memcpy(newheap,h->heap,sizeof(void *)*h->heapsize); - free(h->heap); - h->heap=newheap; - h->heapsize=newsize; - return 1; +static int +_heap_grow(Heap *h, unsigned int newsize) { + void *newheap; + if (!newsize) { + newsize = h->heapsize << 1; + } + if (newsize < h->heapsize) { + return 0; + } + if (newsize > INT_MAX / sizeof(void *)) { + return 0; + } + /* malloc check ok, using calloc for overflow, also checking + above due to memcpy below*/ + newheap = calloc(newsize, sizeof(void *)); + if (!newheap) { + return 0; + } + memcpy(newheap, h->heap, sizeof(void *) * h->heapsize); + free(h->heap); + h->heap = newheap; + h->heapsize = newsize; + return 1; } #ifdef DEBUG -static int _heap_test(Heap *h) { - unsigned int k; - for (k=1;k*2<=h->heapcount;k++) { - if (h->cf(h,h->heap[k],h->heap[k*2])<0) { - printf ("heap is bad\n"); - return 0; - } - if (k*2+1<=h->heapcount && h->cf(h,h->heap[k],h->heap[k*2+1])<0) { - printf ("heap is bad\n"); - return 0; - } - } - return 1; +static int +_heap_test(Heap *h) { + unsigned int k; + for (k = 1; k * 2 <= h->heapcount; k++) { + if (h->cf(h, h->heap[k], h->heap[k * 2]) < 0) { + printf("heap is bad\n"); + return 0; + } + if (k * 2 + 1 <= h->heapcount && h->cf(h, h->heap[k], h->heap[k * 2 + 1]) < 0) { + printf("heap is bad\n"); + return 0; + } + } + return 1; } #endif -int ImagingQuantHeapRemove(Heap* h,void **r) { - unsigned int k,l; - void *v; +int +ImagingQuantHeapRemove(Heap *h, void **r) { + unsigned int k, l; + void *v; - if (!h->heapcount) { - return 0; - } - *r=h->heap[1]; - v=h->heap[h->heapcount--]; - for (k=1;k*2<=h->heapcount;k=l) { - l=k*2; - if (lheapcount) { - if (h->cf(h,h->heap[l],h->heap[l+1])<0) { - l++; - } - } - if (h->cf(h,v,h->heap[l])>0) { - break; - } - h->heap[k]=h->heap[l]; - } - h->heap[k]=v; + if (!h->heapcount) { + return 0; + } + *r = h->heap[1]; + v = h->heap[h->heapcount--]; + for (k = 1; k * 2 <= h->heapcount; k = l) { + l = k * 2; + if (l < h->heapcount) { + if (h->cf(h, h->heap[l], h->heap[l + 1]) < 0) { + l++; + } + } + if (h->cf(h, v, h->heap[l]) > 0) { + break; + } + h->heap[k] = h->heap[l]; + } + h->heap[k] = v; #ifdef DEBUG - if (!_heap_test(h)) { printf ("oops - heap_remove messed up the heap\n"); exit(1); } + if (!_heap_test(h)) { + printf("oops - heap_remove messed up the heap\n"); + exit(1); + } #endif - return 1; + return 1; } -int ImagingQuantHeapAdd(Heap *h,void *val) { - int k; - if (h->heapcount==h->heapsize-1) { - _heap_grow(h,0); - } - k=++h->heapcount; - while (k!=1) { - if (h->cf(h,val,h->heap[k/2])<=0) { - break; - } - h->heap[k]=h->heap[k/2]; - k>>=1; - } - h->heap[k]=val; +int +ImagingQuantHeapAdd(Heap *h, void *val) { + int k; + if (h->heapcount == h->heapsize - 1) { + _heap_grow(h, 0); + } + k = ++h->heapcount; + while (k != 1) { + if (h->cf(h, val, h->heap[k / 2]) <= 0) { + break; + } + h->heap[k] = h->heap[k / 2]; + k >>= 1; + } + h->heap[k] = val; #ifdef DEBUG - if (!_heap_test(h)) { printf ("oops - heap_add messed up the heap\n"); exit(1); } + if (!_heap_test(h)) { + printf("oops - heap_add messed up the heap\n"); + exit(1); + } #endif - return 1; + return 1; } -int ImagingQuantHeapTop(Heap *h,void **r) { - if (!h->heapcount) { - return 0; - } - *r=h->heap[1]; - return 1; +int +ImagingQuantHeapTop(Heap *h, void **r) { + if (!h->heapcount) { + return 0; + } + *r = h->heap[1]; + return 1; } -Heap *ImagingQuantHeapNew(HeapCmpFunc cf) { - Heap *h; +Heap * +ImagingQuantHeapNew(HeapCmpFunc cf) { + Heap *h; - /* malloc check ok, small constant allocation */ - h=malloc(sizeof(Heap)); - if (!h) { - return NULL; - } - h->heapsize=INITIAL_SIZE; - /* malloc check ok, using calloc for overflow */ - h->heap=calloc(h->heapsize, sizeof(void *)); - if (!h->heap) { - free(h); - return NULL; - } - h->heapcount=0; - h->cf=cf; - return h; + /* malloc check ok, small constant allocation */ + h = malloc(sizeof(Heap)); + if (!h) { + return NULL; + } + h->heapsize = INITIAL_SIZE; + /* malloc check ok, using calloc for overflow */ + h->heap = calloc(h->heapsize, sizeof(void *)); + if (!h->heap) { + free(h); + return NULL; + } + h->heapcount = 0; + h->cf = cf; + return h; } diff --git a/src/libImaging/QuantHeap.h b/src/libImaging/QuantHeap.h index 77bf0d9d5..c5286dff2 100644 --- a/src/libImaging/QuantHeap.h +++ b/src/libImaging/QuantHeap.h @@ -16,12 +16,16 @@ typedef struct _Heap Heap; -typedef int (*HeapCmpFunc)(const Heap *,const void *,const void *); +typedef int (*HeapCmpFunc)(const Heap *, const void *, const void *); -void ImagingQuantHeapFree(Heap *); -int ImagingQuantHeapRemove(Heap *,void **); -int ImagingQuantHeapAdd(Heap *,void *); -int ImagingQuantHeapTop(Heap *,void **); +void +ImagingQuantHeapFree(Heap *); +int +ImagingQuantHeapRemove(Heap *, void **); +int +ImagingQuantHeapAdd(Heap *, void *); +int +ImagingQuantHeapTop(Heap *, void **); Heap *ImagingQuantHeapNew(HeapCmpFunc); -#endif // __QUANTHEAP_H__ +#endif // __QUANTHEAP_H__ diff --git a/src/libImaging/QuantOctree.c b/src/libImaging/QuantOctree.c index e1205acc3..b8d4d1d7c 100644 --- a/src/libImaging/QuantOctree.c +++ b/src/libImaging/QuantOctree.c @@ -31,490 +31,508 @@ #include "ImagingUtils.h" #include "QuantOctree.h" -typedef struct _ColorBucket{ - /* contains palette index when used for look up cube */ - uint32_t count; - uint64_t r; - uint64_t g; - uint64_t b; - uint64_t a; -} *ColorBucket; +typedef struct _ColorBucket { + /* contains palette index when used for look up cube */ + uint32_t count; + uint64_t r; + uint64_t g; + uint64_t b; + uint64_t a; +} * ColorBucket; -typedef struct _ColorCube{ - unsigned int rBits, gBits, bBits, aBits; - unsigned int rWidth, gWidth, bWidth, aWidth; - unsigned int rOffset, gOffset, bOffset, aOffset; +typedef struct _ColorCube { + unsigned int rBits, gBits, bBits, aBits; + unsigned int rWidth, gWidth, bWidth, aWidth; + unsigned int rOffset, gOffset, bOffset, aOffset; - unsigned long size; - ColorBucket buckets; -} *ColorCube; + unsigned long size; + ColorBucket buckets; +} * ColorCube; -#define MAX(a, b) (a)>(b) ? (a) : (b) +#define MAX(a, b) (a) > (b) ? (a) : (b) static ColorCube new_color_cube(int r, int g, int b, int a) { - ColorCube cube; + ColorCube cube; - /* malloc check ok, small constant allocation */ - cube = malloc(sizeof(struct _ColorCube)); - if (!cube) { - return NULL; + /* malloc check ok, small constant allocation */ + cube = malloc(sizeof(struct _ColorCube)); + if (!cube) { + return NULL; } - cube->rBits = MAX(r, 0); - cube->gBits = MAX(g, 0); - cube->bBits = MAX(b, 0); - cube->aBits = MAX(a, 0); + cube->rBits = MAX(r, 0); + cube->gBits = MAX(g, 0); + cube->bBits = MAX(b, 0); + cube->aBits = MAX(a, 0); - /* overflow check for size multiplication below */ - if (cube->rBits + cube->gBits + cube->bBits + cube->aBits > 31) { - free(cube); - return NULL; - } + /* overflow check for size multiplication below */ + if (cube->rBits + cube->gBits + cube->bBits + cube->aBits > 31) { + free(cube); + return NULL; + } - /* the width of the cube for each dimension */ - cube->rWidth = 1<rBits; - cube->gWidth = 1<gBits; - cube->bWidth = 1<bBits; - cube->aWidth = 1<aBits; + /* the width of the cube for each dimension */ + cube->rWidth = 1 << cube->rBits; + cube->gWidth = 1 << cube->gBits; + cube->bWidth = 1 << cube->bBits; + cube->aWidth = 1 << cube->aBits; - /* the offsets of each color */ + /* the offsets of each color */ - cube->rOffset = cube->gBits + cube->bBits + cube->aBits; - cube->gOffset = cube->bBits + cube->aBits; - cube->bOffset = cube->aBits; - cube->aOffset = 0; + cube->rOffset = cube->gBits + cube->bBits + cube->aBits; + cube->gOffset = cube->bBits + cube->aBits; + cube->bOffset = cube->aBits; + cube->aOffset = 0; - /* the number of color buckets */ - cube->size = cube->rWidth * cube->gWidth * cube->bWidth * cube->aWidth; - /* malloc check ok, overflow checked above */ - cube->buckets = calloc(cube->size, sizeof(struct _ColorBucket)); + /* the number of color buckets */ + cube->size = cube->rWidth * cube->gWidth * cube->bWidth * cube->aWidth; + /* malloc check ok, overflow checked above */ + cube->buckets = calloc(cube->size, sizeof(struct _ColorBucket)); - if (!cube->buckets) { - free(cube); - return NULL; - } - return cube; + if (!cube->buckets) { + free(cube); + return NULL; + } + return cube; } static void free_color_cube(ColorCube cube) { - if (cube != NULL) { - free(cube->buckets); - free(cube); - } + if (cube != NULL) { + free(cube->buckets); + free(cube); + } } static long -color_bucket_offset_pos(const ColorCube cube, - unsigned int r, unsigned int g, unsigned int b, unsigned int a) -{ - return r<rOffset | g<gOffset | b<bOffset | a<aOffset; +color_bucket_offset_pos( + const ColorCube cube, + unsigned int r, + unsigned int g, + unsigned int b, + unsigned int a) { + return r << cube->rOffset | g << cube->gOffset | b << cube->bOffset | + a << cube->aOffset; } static long color_bucket_offset(const ColorCube cube, const Pixel *p) { - unsigned int r = p->c.r>>(8-cube->rBits); - unsigned int g = p->c.g>>(8-cube->gBits); - unsigned int b = p->c.b>>(8-cube->bBits); - unsigned int a = p->c.a>>(8-cube->aBits); - return color_bucket_offset_pos(cube, r, g, b, a); + unsigned int r = p->c.r >> (8 - cube->rBits); + unsigned int g = p->c.g >> (8 - cube->gBits); + unsigned int b = p->c.b >> (8 - cube->bBits); + unsigned int a = p->c.a >> (8 - cube->aBits); + return color_bucket_offset_pos(cube, r, g, b, a); } static ColorBucket color_bucket_from_cube(const ColorCube cube, const Pixel *p) { - unsigned int offset = color_bucket_offset(cube, p); - return &cube->buckets[offset]; + unsigned int offset = color_bucket_offset(cube, p); + return &cube->buckets[offset]; } static void add_color_to_color_cube(const ColorCube cube, const Pixel *p) { - ColorBucket bucket = color_bucket_from_cube(cube, p); - bucket->count += 1; - bucket->r += p->c.r; - bucket->g += p->c.g; - bucket->b += p->c.b; - bucket->a += p->c.a; + ColorBucket bucket = color_bucket_from_cube(cube, p); + bucket->count += 1; + bucket->r += p->c.r; + bucket->g += p->c.g; + bucket->b += p->c.b; + bucket->a += p->c.a; } static unsigned long count_used_color_buckets(const ColorCube cube) { - unsigned long usedBuckets = 0; - unsigned long i; - for (i=0; i < cube->size; i++) { - if (cube->buckets[i].count > 0) { - usedBuckets += 1; - } - } - return usedBuckets; + unsigned long usedBuckets = 0; + unsigned long i; + for (i = 0; i < cube->size; i++) { + if (cube->buckets[i].count > 0) { + usedBuckets += 1; + } + } + return usedBuckets; } static void avg_color_from_color_bucket(const ColorBucket bucket, Pixel *dst) { - float count = bucket->count; - if (count != 0) { - dst->c.r = CLIP8((int)(bucket->r / count)); - dst->c.g = CLIP8((int)(bucket->g / count)); - dst->c.b = CLIP8((int)(bucket->b / count)); - dst->c.a = CLIP8((int)(bucket->a / count)); - } else { - dst->c.r = 0; - dst->c.g = 0; - dst->c.b = 0; - dst->c.a = 0; - } + float count = bucket->count; + if (count != 0) { + dst->c.r = CLIP8((int)(bucket->r / count)); + dst->c.g = CLIP8((int)(bucket->g / count)); + dst->c.b = CLIP8((int)(bucket->b / count)); + dst->c.a = CLIP8((int)(bucket->a / count)); + } else { + dst->c.r = 0; + dst->c.g = 0; + dst->c.b = 0; + dst->c.a = 0; + } } static int compare_bucket_count(const ColorBucket a, const ColorBucket b) { - return b->count - a->count; + return b->count - a->count; } static ColorBucket create_sorted_color_palette(const ColorCube cube) { - ColorBucket buckets; - if (cube->size > LONG_MAX / sizeof(struct _ColorBucket)) { - return NULL; - } - /* malloc check ok, calloc + overflow check above for memcpy */ - buckets = calloc(cube->size, sizeof(struct _ColorBucket)); - if (!buckets) { - return NULL; - } - memcpy(buckets, cube->buckets, sizeof(struct _ColorBucket)*cube->size); + ColorBucket buckets; + if (cube->size > LONG_MAX / sizeof(struct _ColorBucket)) { + return NULL; + } + /* malloc check ok, calloc + overflow check above for memcpy */ + buckets = calloc(cube->size, sizeof(struct _ColorBucket)); + if (!buckets) { + return NULL; + } + memcpy(buckets, cube->buckets, sizeof(struct _ColorBucket) * cube->size); - qsort(buckets, cube->size, sizeof(struct _ColorBucket), - (int (*)(void const *, void const *))&compare_bucket_count); + qsort( + buckets, + cube->size, + sizeof(struct _ColorBucket), + (int (*)(void const *, void const *)) & compare_bucket_count); - return buckets; + return buckets; } -void add_bucket_values(ColorBucket src, ColorBucket dst) { - dst->count += src->count; - dst->r += src->r; - dst->g += src->g; - dst->b += src->b; - dst->a += src->a; +void +add_bucket_values(ColorBucket src, ColorBucket dst) { + dst->count += src->count; + dst->r += src->r; + dst->g += src->g; + dst->b += src->b; + dst->a += src->a; } /* expand or shrink a given cube to level */ -static ColorCube copy_color_cube(const ColorCube cube, - unsigned int rBits, unsigned int gBits, unsigned int bBits, unsigned int aBits) -{ - unsigned int r, g, b, a; - long src_pos, dst_pos; - unsigned int src_reduce[4] = {0}, dst_reduce[4] = {0}; - unsigned int width[4]; - ColorCube result; +static ColorCube +copy_color_cube( + const ColorCube cube, + unsigned int rBits, + unsigned int gBits, + unsigned int bBits, + unsigned int aBits) { + unsigned int r, g, b, a; + long src_pos, dst_pos; + unsigned int src_reduce[4] = {0}, dst_reduce[4] = {0}; + unsigned int width[4]; + ColorCube result; - result = new_color_cube(rBits, gBits, bBits, aBits); - if (!result) { - return NULL; - } + result = new_color_cube(rBits, gBits, bBits, aBits); + if (!result) { + return NULL; + } - if (cube->rBits > rBits) { - dst_reduce[0] = cube->rBits - result->rBits; - width[0] = cube->rWidth; - } else { - src_reduce[0] = result->rBits - cube->rBits; - width[0] = result->rWidth; - } - if (cube->gBits > gBits) { - dst_reduce[1] = cube->gBits - result->gBits; - width[1] = cube->gWidth; - } else { - src_reduce[1] = result->gBits - cube->gBits; - width[1] = result->gWidth; - } - if (cube->bBits > bBits) { - dst_reduce[2] = cube->bBits - result->bBits; - width[2] = cube->bWidth; - } else { - src_reduce[2] = result->bBits - cube->bBits; - width[2] = result->bWidth; - } - if (cube->aBits > aBits) { - dst_reduce[3] = cube->aBits - result->aBits; - width[3] = cube->aWidth; - } else { - src_reduce[3] = result->aBits - cube->aBits; - width[3] = result->aWidth; - } + if (cube->rBits > rBits) { + dst_reduce[0] = cube->rBits - result->rBits; + width[0] = cube->rWidth; + } else { + src_reduce[0] = result->rBits - cube->rBits; + width[0] = result->rWidth; + } + if (cube->gBits > gBits) { + dst_reduce[1] = cube->gBits - result->gBits; + width[1] = cube->gWidth; + } else { + src_reduce[1] = result->gBits - cube->gBits; + width[1] = result->gWidth; + } + if (cube->bBits > bBits) { + dst_reduce[2] = cube->bBits - result->bBits; + width[2] = cube->bWidth; + } else { + src_reduce[2] = result->bBits - cube->bBits; + width[2] = result->bWidth; + } + if (cube->aBits > aBits) { + dst_reduce[3] = cube->aBits - result->aBits; + width[3] = cube->aWidth; + } else { + src_reduce[3] = result->aBits - cube->aBits; + width[3] = result->aWidth; + } - for (r=0; r>src_reduce[0], - g>>src_reduce[1], - b>>src_reduce[2], - a>>src_reduce[3]); - dst_pos = color_bucket_offset_pos(result, - r>>dst_reduce[0], - g>>dst_reduce[1], - b>>dst_reduce[2], - a>>dst_reduce[3]); - add_bucket_values( - &cube->buckets[src_pos], - &result->buckets[dst_pos] - ); + for (r = 0; r < width[0]; r++) { + for (g = 0; g < width[1]; g++) { + for (b = 0; b < width[2]; b++) { + for (a = 0; a < width[3]; a++) { + src_pos = color_bucket_offset_pos( + cube, + r >> src_reduce[0], + g >> src_reduce[1], + b >> src_reduce[2], + a >> src_reduce[3]); + dst_pos = color_bucket_offset_pos( + result, + r >> dst_reduce[0], + g >> dst_reduce[1], + b >> dst_reduce[2], + a >> dst_reduce[3]); + add_bucket_values( + &cube->buckets[src_pos], &result->buckets[dst_pos]); + } } - } - } - } - return result; + } + } + return result; } void subtract_color_buckets(ColorCube cube, ColorBucket buckets, long nBuckets) { - ColorBucket minuend, subtrahend; - long i; - Pixel p; - for (i=0; icount == 0) { - continue; - } + // If the subtrahend contains no buckets, there is nothing to subtract. + if (subtrahend->count == 0) { + continue; + } - avg_color_from_color_bucket(subtrahend, &p); - minuend = color_bucket_from_cube(cube, &p); - minuend->count -= subtrahend->count; - minuend->r -= subtrahend->r; - minuend->g -= subtrahend->g; - minuend->b -= subtrahend->b; - minuend->a -= subtrahend->a; - } + avg_color_from_color_bucket(subtrahend, &p); + minuend = color_bucket_from_cube(cube, &p); + minuend->count -= subtrahend->count; + minuend->r -= subtrahend->r; + minuend->g -= subtrahend->g; + minuend->b -= subtrahend->b; + minuend->a -= subtrahend->a; + } } static void set_lookup_value(const ColorCube cube, const Pixel *p, long value) { - ColorBucket bucket = color_bucket_from_cube(cube, p); - bucket->count = value; + ColorBucket bucket = color_bucket_from_cube(cube, p); + bucket->count = value; } uint64_t lookup_color(const ColorCube cube, const Pixel *p) { - ColorBucket bucket = color_bucket_from_cube(cube, p); - return bucket->count; + ColorBucket bucket = color_bucket_from_cube(cube, p); + return bucket->count; } -void add_lookup_buckets(ColorCube cube, ColorBucket palette, long nColors, long offset) { - long i; - Pixel p; - for (i=offset; i LONG_MAX - nBucketsB || - (nBucketsA+nBucketsB) > LONG_MAX / sizeof(struct _ColorBucket)) { - return NULL; - } - /* malloc check ok, overflow check above */ - result = calloc(nBucketsA + nBucketsB, sizeof(struct _ColorBucket)); - if (!result) { - return NULL; - } - memcpy(result, bucketsA, sizeof(struct _ColorBucket) * nBucketsA); - memcpy(&result[nBucketsA], bucketsB, sizeof(struct _ColorBucket) * nBucketsB); - return result; +combined_palette( + ColorBucket bucketsA, + unsigned long nBucketsA, + ColorBucket bucketsB, + unsigned long nBucketsB) { + ColorBucket result; + if (nBucketsA > LONG_MAX - nBucketsB || + (nBucketsA + nBucketsB) > LONG_MAX / sizeof(struct _ColorBucket)) { + return NULL; + } + /* malloc check ok, overflow check above */ + result = calloc(nBucketsA + nBucketsB, sizeof(struct _ColorBucket)); + if (!result) { + return NULL; + } + memcpy(result, bucketsA, sizeof(struct _ColorBucket) * nBucketsA); + memcpy(&result[nBucketsA], bucketsB, sizeof(struct _ColorBucket) * nBucketsB); + return result; } static Pixel * create_palette_array(const ColorBucket palette, unsigned int paletteLength) { - Pixel *paletteArray; - unsigned int i; + Pixel *paletteArray; + unsigned int i; - /* malloc check ok, calloc for overflow */ - paletteArray = calloc(paletteLength, sizeof(Pixel)); - if (!paletteArray) { - return NULL; - } + /* malloc check ok, calloc for overflow */ + paletteArray = calloc(paletteLength, sizeof(Pixel)); + if (!paletteArray) { + return NULL; + } - for (i=0; i 64). + /* + Create two color cubes, one fine grained with 8x16x8=1024 + colors buckets and a coarse with 4x4x4=64 color buckets. + The coarse one guarantees that there are color buckets available for + the whole color range (assuming nQuantPixels > 64). - For a quantization to 256 colors all 64 coarse colors will be used - plus the 192 most used color buckets from the fine color cube. - The average of all colors within one bucket is used as the actual - color for that bucket. + For a quantization to 256 colors all 64 coarse colors will be used + plus the 192 most used color buckets from the fine color cube. + The average of all colors within one bucket is used as the actual + color for that bucket. - For images with alpha the cubes gets a forth dimension, - 8x16x8x8 and 4x4x4x4. - */ + For images with alpha the cubes gets a forth dimension, + 8x16x8x8 and 4x4x4x4. + */ - /* create fine cube */ - fineCube = new_color_cube(cubeBits[0], cubeBits[1], - cubeBits[2], cubeBits[3]); - if (!fineCube) { - goto error; - } - for (i=0; i nQuantPixels) { - nCoarseColors = nQuantPixels; - } + /* limit to nQuantPixels */ + if (nCoarseColors > nQuantPixels) { + nCoarseColors = nQuantPixels; + } - /* how many space do we have in our palette for fine colors? */ - nFineColors = nQuantPixels - nCoarseColors; + /* how many space do we have in our palette for fine colors? */ + nFineColors = nQuantPixels - nCoarseColors; - /* create fine color palette */ - paletteBucketsFine = create_sorted_color_palette(fineCube); - if (!paletteBucketsFine) { - goto error; - } + /* create fine color palette */ + paletteBucketsFine = create_sorted_color_palette(fineCube); + if (!paletteBucketsFine) { + goto error; + } - /* remove the used fine colors from the coarse cube */ - subtract_color_buckets(coarseCube, paletteBucketsFine, nFineColors); + /* remove the used fine colors from the coarse cube */ + subtract_color_buckets(coarseCube, paletteBucketsFine, nFineColors); - /* did the subtraction cleared one or more coarse bucket? */ - while (nCoarseColors > count_used_color_buckets(coarseCube)) { - /* then we can use the free buckets for fine colors */ - nAlreadySubtracted = nFineColors; - nCoarseColors = count_used_color_buckets(coarseCube); - nFineColors = nQuantPixels - nCoarseColors; - subtract_color_buckets(coarseCube, &paletteBucketsFine[nAlreadySubtracted], - nFineColors-nAlreadySubtracted); - } + /* did the subtraction cleared one or more coarse bucket? */ + while (nCoarseColors > count_used_color_buckets(coarseCube)) { + /* then we can use the free buckets for fine colors */ + nAlreadySubtracted = nFineColors; + nCoarseColors = count_used_color_buckets(coarseCube); + nFineColors = nQuantPixels - nCoarseColors; + subtract_color_buckets( + coarseCube, + &paletteBucketsFine[nAlreadySubtracted], + nFineColors - nAlreadySubtracted); + } - /* create our palette buckets with fine and coarse combined */ - paletteBucketsCoarse = create_sorted_color_palette(coarseCube); - if (!paletteBucketsCoarse) { - goto error; - } - paletteBuckets = combined_palette(paletteBucketsCoarse, nCoarseColors, - paletteBucketsFine, nFineColors); + /* create our palette buckets with fine and coarse combined */ + paletteBucketsCoarse = create_sorted_color_palette(coarseCube); + if (!paletteBucketsCoarse) { + goto error; + } + paletteBuckets = combined_palette( + paletteBucketsCoarse, nCoarseColors, paletteBucketsFine, nFineColors); - free(paletteBucketsFine); - paletteBucketsFine = NULL; - free(paletteBucketsCoarse); - paletteBucketsCoarse = NULL; - if (!paletteBuckets) { - goto error; - } + free(paletteBucketsFine); + paletteBucketsFine = NULL; + free(paletteBucketsCoarse); + paletteBucketsCoarse = NULL; + if (!paletteBuckets) { + goto error; + } - /* add all coarse colors to our coarse lookup cube. */ - coarseLookupCube = new_color_cube(cubeBits[4], cubeBits[5], - cubeBits[6], cubeBits[7]); - if (!coarseLookupCube) { - goto error; - } - add_lookup_buckets(coarseLookupCube, paletteBuckets, nCoarseColors, 0); + /* add all coarse colors to our coarse lookup cube. */ + coarseLookupCube = + new_color_cube(cubeBits[4], cubeBits[5], cubeBits[6], cubeBits[7]); + if (!coarseLookupCube) { + goto error; + } + add_lookup_buckets(coarseLookupCube, paletteBuckets, nCoarseColors, 0); - /* expand coarse cube (64) to larger fine cube (4k). the value of each - coarse bucket is then present in the according 64 fine buckets. */ - lookupCube = copy_color_cube(coarseLookupCube, cubeBits[0], cubeBits[1], - cubeBits[2], cubeBits[3]); - if (!lookupCube) { - goto error; - } + /* expand coarse cube (64) to larger fine cube (4k). the value of each + coarse bucket is then present in the according 64 fine buckets. */ + lookupCube = copy_color_cube( + coarseLookupCube, cubeBits[0], cubeBits[1], cubeBits[2], cubeBits[3]); + if (!lookupCube) { + goto error; + } - /* add fine colors to the lookup cube */ - add_lookup_buckets(lookupCube, paletteBuckets, nFineColors, nCoarseColors); + /* add fine colors to the lookup cube */ + add_lookup_buckets(lookupCube, paletteBuckets, nFineColors, nCoarseColors); - /* create result pixels and map palette indices */ - /* malloc check ok, calloc for overflow */ - qp = calloc(nPixels, sizeof(Pixel)); - if (!qp) { - goto error; - } - map_image_pixels(pixelData, nPixels, lookupCube, qp); + /* create result pixels and map palette indices */ + /* malloc check ok, calloc for overflow */ + qp = calloc(nPixels, sizeof(Pixel)); + if (!qp) { + goto error; + } + map_image_pixels(pixelData, nPixels, lookupCube, qp); - /* convert palette buckets to RGB pixel palette */ - *palette = create_palette_array(paletteBuckets, nQuantPixels); - if (!(*palette)) { - goto error; - } + /* convert palette buckets to RGB pixel palette */ + *palette = create_palette_array(paletteBuckets, nQuantPixels); + if (!(*palette)) { + goto error; + } - *quantizedPixels = qp; - *paletteLength = nQuantPixels; + *quantizedPixels = qp; + *paletteLength = nQuantPixels; - free_color_cube(coarseCube); - free_color_cube(fineCube); - free_color_cube(lookupCube); - free_color_cube(coarseLookupCube); - free(paletteBuckets); - return 1; + free_color_cube(coarseCube); + free_color_cube(fineCube); + free_color_cube(lookupCube); + free_color_cube(coarseLookupCube); + free(paletteBuckets); + return 1; error: - /* everything is initialized to NULL - so we are safe to call free */ - free(qp); - free_color_cube(lookupCube); - free_color_cube(coarseLookupCube); - free(paletteBuckets); - free(paletteBucketsCoarse); - free(paletteBucketsFine); - free_color_cube(coarseCube); - free_color_cube(fineCube); - return 0; + /* everything is initialized to NULL + so we are safe to call free */ + free(qp); + free_color_cube(lookupCube); + free_color_cube(coarseLookupCube); + free(paletteBuckets); + free(paletteBucketsCoarse); + free(paletteBucketsFine); + free_color_cube(coarseCube); + free_color_cube(fineCube); + return 0; } diff --git a/src/libImaging/QuantOctree.h b/src/libImaging/QuantOctree.h index 968644eda..e1c504074 100644 --- a/src/libImaging/QuantOctree.h +++ b/src/libImaging/QuantOctree.h @@ -3,12 +3,7 @@ #include "QuantTypes.h" -int quantize_octree(Pixel *, - uint32_t, - uint32_t, - Pixel **, - uint32_t *, - uint32_t **, - int); +int +quantize_octree(Pixel *, uint32_t, uint32_t, Pixel **, uint32_t *, uint32_t **, int); #endif diff --git a/src/libImaging/QuantPngQuant.c b/src/libImaging/QuantPngQuant.c index 7a23ec8c5..7a36300e4 100644 --- a/src/libImaging/QuantPngQuant.c +++ b/src/libImaging/QuantPngQuant.c @@ -26,8 +26,7 @@ quantize_pngquant( Pixel **palette, uint32_t *paletteLength, uint32_t **quantizedPixels, - int withAlpha) -{ + int withAlpha) { int result = 0; liq_image *image = NULL; liq_attr *attr = NULL; @@ -41,23 +40,24 @@ quantize_pngquant( /* configure pngquant */ attr = liq_attr_create(); - if (!attr) { goto err; } + if (!attr) { + goto err; + } if (quantPixels) { liq_set_max_colors(attr, quantPixels); } /* prepare input image */ - image = liq_image_create_rgba( - attr, - pixelData, - width, - height, - 0.45455 /* gamma */); - if (!image) { goto err; } + image = liq_image_create_rgba(attr, pixelData, width, height, 0.45455 /* gamma */); + if (!image) { + goto err; + } /* quantize the image */ remap = liq_quantize_image(attr, image); - if (!remap) { goto err; } + if (!remap) { + goto err; + } liq_set_output_gamma(remap, 0.45455); liq_set_dithering_level(remap, 1); @@ -65,7 +65,9 @@ quantize_pngquant( const liq_palette *l_palette = liq_get_palette(remap); *paletteLength = l_palette->count; *palette = malloc(sizeof(Pixel) * l_palette->count); - if (!*palette) { goto err; } + if (!*palette) { + goto err; + } for (i = 0; i < l_palette->count; i++) { (*palette)[i].c.b = l_palette->entries[i].b; (*palette)[i].c.g = l_palette->entries[i].g; @@ -75,9 +77,13 @@ quantize_pngquant( /* write output pixels (pngquant uses char array) */ charMatrix = malloc(width * height); - if (!charMatrix) { goto err; } - charMatrixRows = malloc(height * sizeof(unsigned char*)); - if (!charMatrixRows) { goto err; } + if (!charMatrix) { + goto err; + } + charMatrixRows = malloc(height * sizeof(unsigned char *)); + if (!charMatrixRows) { + goto err; + } for (y = 0; y < height; y++) { charMatrixRows[y] = &charMatrix[y * width]; } @@ -87,7 +93,9 @@ quantize_pngquant( /* transcribe output pixels (pillow uses uint32_t array) */ *quantizedPixels = malloc(sizeof(uint32_t) * width * height); - if (!*quantizedPixels) { goto err; } + if (!*quantizedPixels) { + goto err; + } for (i = 0; i < width * height; i++) { (*quantizedPixels)[i] = charMatrix[i]; } @@ -106,16 +114,15 @@ err: } free(charMatrix); free(charMatrixRows); - if (!result) { + if (!result) { free(*quantizedPixels); free(*palette); } return result; } -const char* -ImagingImageQuantVersion(void) -{ +const char * +ImagingImageQuantVersion(void) { static char version[20]; int number = liq_version(); sprintf(version, "%d.%d.%d", number / 10000, (number / 100) % 100, number % 100); diff --git a/src/libImaging/QuantPngQuant.h b/src/libImaging/QuantPngQuant.h index fb0b4cc03..d65e42590 100644 --- a/src/libImaging/QuantPngQuant.h +++ b/src/libImaging/QuantPngQuant.h @@ -3,7 +3,9 @@ #include "QuantTypes.h" -int quantize_pngquant(Pixel *, +int +quantize_pngquant( + Pixel *, unsigned int, unsigned int, uint32_t, diff --git a/src/libImaging/QuantTypes.h b/src/libImaging/QuantTypes.h index 411485498..986b70806 100644 --- a/src/libImaging/QuantTypes.h +++ b/src/libImaging/QuantTypes.h @@ -20,13 +20,13 @@ typedef unsigned __int64 uint64_t; #endif typedef union { - struct { - unsigned char r,g,b,a; - } c; - struct { - unsigned char v[4]; - } a; - uint32_t v; + struct { + unsigned char r, g, b, a; + } c; + struct { + unsigned char v[4]; + } a; + uint32_t v; } Pixel; #endif diff --git a/src/libImaging/RankFilter.c b/src/libImaging/RankFilter.c index 897e4d7b6..73a6baecb 100644 --- a/src/libImaging/RankFilter.c +++ b/src/libImaging/RankFilter.c @@ -17,94 +17,98 @@ /* Fast rank algorithm (due to Wirth), based on public domain code by Nicolas Devillard, available at http://ndevilla.free.fr */ -#define SWAP(type,a,b) { register type t=(a);(a)=(b);(b)=t; } +#define SWAP(type, a, b) \ + { \ + register type t = (a); \ + (a) = (b); \ + (b) = t; \ + } -#define MakeRankFunction(type)\ -static type Rank##type(type a[], int n, int k)\ -{\ - register int i, j, l, m;\ - register type x;\ - l = 0; m = n-1;\ - while (l < m) {\ - x = a[k];\ - i = l;\ - j = m;\ - do {\ - while (a[i] < x) {\ - i++;\ - }\ - while (x < a[j]) {\ - j--;\ - }\ - if (i <= j) {\ - SWAP(type, a[i], a[j]);\ - i++; j--;\ - }\ - } while (i <= j);\ - if (j < k) {\ - l = i;\ - }\ - if (k < i) {\ - m = j;\ - }\ - }\ - return a[k];\ -} +#define MakeRankFunction(type) \ + static type Rank##type(type a[], int n, int k) { \ + register int i, j, l, m; \ + register type x; \ + l = 0; \ + m = n - 1; \ + while (l < m) { \ + x = a[k]; \ + i = l; \ + j = m; \ + do { \ + while (a[i] < x) { \ + i++; \ + } \ + while (x < a[j]) { \ + j--; \ + } \ + if (i <= j) { \ + SWAP(type, a[i], a[j]); \ + i++; \ + j--; \ + } \ + } while (i <= j); \ + if (j < k) { \ + l = i; \ + } \ + if (k < i) { \ + m = j; \ + } \ + } \ + return a[k]; \ + } -MakeRankFunction(UINT8) -MakeRankFunction(INT32) -MakeRankFunction(FLOAT32) +MakeRankFunction(UINT8) MakeRankFunction(INT32) MakeRankFunction(FLOAT32) -Imaging -ImagingRankFilter(Imaging im, int size, int rank) -{ + Imaging ImagingRankFilter(Imaging im, int size, int rank) { Imaging imOut = NULL; int x, y; int i, margin, size2; if (!im || im->bands != 1 || im->type == IMAGING_TYPE_SPECIAL) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (!(size & 1)) { - return (Imaging) ImagingError_ValueError("bad filter size"); + return (Imaging)ImagingError_ValueError("bad filter size"); } /* malloc check ok, for overflow in the define below */ - if (size > INT_MAX / size || - size > INT_MAX / (size * (int)sizeof(FLOAT32))) { - return (Imaging) ImagingError_ValueError("filter size too large"); + if (size > INT_MAX / size || size > INT_MAX / (size * (int)sizeof(FLOAT32))) { + return (Imaging)ImagingError_ValueError("filter size too large"); } size2 = size * size; - margin = (size-1) / 2; + margin = (size - 1) / 2; if (rank < 0 || rank >= size2) { - return (Imaging) ImagingError_ValueError("bad rank value"); + return (Imaging)ImagingError_ValueError("bad rank value"); } - imOut = ImagingNew(im->mode, im->xsize - 2*margin, im->ysize - 2*margin); + imOut = ImagingNew(im->mode, im->xsize - 2 * margin, im->ysize - 2 * margin); if (!imOut) { return NULL; } /* malloc check ok, checked above */ -#define RANK_BODY(type) do {\ - type* buf = malloc(size2 * sizeof(type));\ - if (!buf) {\ - goto nomemory;\ - }\ - for (y = 0; y < imOut->ysize; y++) {\ - for (x = 0; x < imOut->xsize; x++) {\ - for (i = 0; i < size; i++) {\ - memcpy(buf + i*size, &IMAGING_PIXEL_##type(im, x, y+i),\ - size * sizeof(type));\ - }\ - IMAGING_PIXEL_##type(imOut, x, y) = Rank##type(buf, size2, rank);\ - }\ - }\ - free(buf); \ -} while (0) +#define RANK_BODY(type) \ + do { \ + type *buf = malloc(size2 * sizeof(type)); \ + if (!buf) { \ + goto nomemory; \ + } \ + for (y = 0; y < imOut->ysize; y++) { \ + for (x = 0; x < imOut->xsize; x++) { \ + for (i = 0; i < size; i++) { \ + memcpy( \ + buf + i * size, \ + &IMAGING_PIXEL_##type(im, x, y + i), \ + size * sizeof(type)); \ + } \ + IMAGING_PIXEL_##type(imOut, x, y) = Rank##type(buf, size2, rank); \ + } \ + } \ + free(buf); \ + } while (0) if (im->image8) { RANK_BODY(UINT8); @@ -115,7 +119,7 @@ ImagingRankFilter(Imaging im, int size, int rank) } else { /* safety net (we shouldn't end up here) */ ImagingDelete(imOut); - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } ImagingCopyPalette(imOut, im); @@ -124,5 +128,5 @@ ImagingRankFilter(Imaging im, int size, int rank) nomemory: ImagingDelete(imOut); - return (Imaging) ImagingError_MemoryError(); + return (Imaging)ImagingError_MemoryError(); } diff --git a/src/libImaging/Raw.h b/src/libImaging/Raw.h index 4d28fa546..ab718837f 100644 --- a/src/libImaging/Raw.h +++ b/src/libImaging/Raw.h @@ -1,7 +1,6 @@ /* Raw.h */ typedef struct { - /* CONFIGURATION */ /* Distance between lines (0=no padding) */ diff --git a/src/libImaging/RawDecode.c b/src/libImaging/RawDecode.c index ca3d37149..24abe4804 100644 --- a/src/libImaging/RawDecode.c +++ b/src/libImaging/RawDecode.c @@ -13,22 +13,18 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #include "Raw.h" - int -ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ +ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { enum { LINE = 1, SKIP }; - RAWSTATE* rawstate = state->context; + RAWSTATE *rawstate = state->context; - UINT8* ptr; + UINT8 *ptr; if (state->state == 0) { - /* Initialize context variables */ /* get size of image data and padding */ @@ -45,22 +41,19 @@ ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt /* check image orientation */ if (state->ystep < 0) { - state->y = state->ysize-1; + state->y = state->ysize - 1; state->ystep = -1; } else { state->ystep = 1; } state->state = LINE; - } ptr = buf; for (;;) { - if (state->state == SKIP) { - /* Skip padding between lines */ if (bytes < rawstate->skip) { @@ -71,7 +64,6 @@ ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt bytes -= rawstate->skip; state->state = LINE; - } if (bytes < state->bytes) { @@ -79,8 +71,10 @@ ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt } /* Unpack data */ - state->shuffle((UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, ptr, state->xsize); + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff] + state->xoff * im->pixelsize, + ptr, + state->xsize); ptr += state->bytes; bytes -= state->bytes; @@ -93,7 +87,5 @@ ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt } state->state = SKIP; - } - } diff --git a/src/libImaging/RawEncode.c b/src/libImaging/RawEncode.c index fb4ab3346..50de8d982 100644 --- a/src/libImaging/RawEncode.c +++ b/src/libImaging/RawEncode.c @@ -17,16 +17,13 @@ * * See the README file for information on usage and redistribution. */ - #include "Imaging.h" int -ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) -{ - UINT8* ptr; +ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { + UINT8 *ptr; if (!state->state) { - /* The "count" field holds the stride, if specified. Fix things up so "bytes" is the full size, and "count" the packed size */ @@ -48,14 +45,13 @@ ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) /* The "ystep" field specifies the orientation */ if (state->ystep < 0) { - state->y = state->ysize-1; + state->y = state->ysize - 1; state->ystep = -1; } else { state->ystep = 1; } state->state = 1; - } if (bytes < state->bytes) { @@ -66,9 +62,10 @@ ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) ptr = buf; while (bytes >= state->bytes) { - - state->shuffle(ptr, (UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->xsize); + state->shuffle( + ptr, + (UINT8 *)im->image[state->y + state->yoff] + state->xoff * im->pixelsize, + state->xsize); if (state->bytes > state->count) { /* zero-pad the buffer, if necessary */ @@ -84,9 +81,7 @@ ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) state->errcode = IMAGING_CODEC_END; break; } - } return ptr - buf; - } diff --git a/src/libImaging/Reduce.c b/src/libImaging/Reduce.c index f6488deb2..60928d2bc 100644 --- a/src/libImaging/Reduce.c +++ b/src/libImaging/Reduce.c @@ -2,39 +2,35 @@ #include -#define ROUND_UP(f) ((int) ((f) >= 0.0 ? (f) + 0.5F : (f) - 0.5F)) - +#define ROUND_UP(f) ((int)((f) >= 0.0 ? (f) + 0.5F : (f)-0.5F)) UINT32 -division_UINT32(int divider, int result_bits) -{ +division_UINT32(int divider, int result_bits) { UINT32 max_dividend = (1 << result_bits) * divider; float max_int = (1 << 30) * 4.0; - return (UINT32) (max_int / max_dividend); + return (UINT32)(max_int / max_dividend); } - void -ImagingReduceNxN(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) -{ +ImagingReduceNxN(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) { /* The most general implementation for any xscale and yscale - */ + */ int x, y, xx, yy; UINT32 multiplier = division_UINT32(yscale * xscale, 8); UINT32 amend = yscale * xscale / 2; if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; + int yy_from = box[1] + y * yscale; for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 ss = amend; for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image8[yy]; UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1]; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss += line0[xx + 0] + line0[xx + 1] + - line1[xx + 0] + line1[xx + 1]; + ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] + + line1[xx + 1]; } if (xscale & 0x01) { ss += line0[xx + 0] + line1[xx + 0]; @@ -54,125 +50,128 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; + int yy_from = box[1] + y * yscale; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss3 = amend; for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line0[xx*4 + 0] + line0[xx*4 + 4] + - line1[xx*4 + 0] + line1[xx*4 + 4]; - ss3 += line0[xx*4 + 3] + line0[xx*4 + 7] + - line1[xx*4 + 3] + line1[xx*4 + 7]; + ss0 += line0[xx * 4 + 0] + line0[xx * 4 + 4] + + line1[xx * 4 + 0] + line1[xx * 4 + 4]; + ss3 += line0[xx * 4 + 3] + line0[xx * 4 + 7] + + line1[xx * 4 + 3] + line1[xx * 4 + 7]; } if (xscale & 0x01) { - ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; - ss3 += line0[xx*4 + 3] + line1[xx*4 + 3]; + ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss3 += line0[xx * 4 + 3] + line1[xx * 4 + 3]; } } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line[xx*4 + 0] + line[xx*4 + 4]; - ss3 += line[xx*4 + 3] + line[xx*4 + 7]; + ss0 += line[xx * 4 + 0] + line[xx * 4 + 4]; + ss3 += line[xx * 4 + 3] + line[xx * 4 + 7]; } if (xscale & 0x01) { - ss0 += line[xx*4 + 0]; - ss3 += line[xx*4 + 3]; + ss0 += line[xx * 4 + 0]; + ss3 += line[xx * 4 + 3]; } } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, 0, - 0, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, 0, 0, (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend; for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line0[xx*4 + 0] + line0[xx*4 + 4] + - line1[xx*4 + 0] + line1[xx*4 + 4]; - ss1 += line0[xx*4 + 1] + line0[xx*4 + 5] + - line1[xx*4 + 1] + line1[xx*4 + 5]; - ss2 += line0[xx*4 + 2] + line0[xx*4 + 6] + - line1[xx*4 + 2] + line1[xx*4 + 6]; + ss0 += line0[xx * 4 + 0] + line0[xx * 4 + 4] + + line1[xx * 4 + 0] + line1[xx * 4 + 4]; + ss1 += line0[xx * 4 + 1] + line0[xx * 4 + 5] + + line1[xx * 4 + 1] + line1[xx * 4 + 5]; + ss2 += line0[xx * 4 + 2] + line0[xx * 4 + 6] + + line1[xx * 4 + 2] + line1[xx * 4 + 6]; } if (xscale & 0x01) { - ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; - ss1 += line0[xx*4 + 1] + line1[xx*4 + 1]; - ss2 += line0[xx*4 + 2] + line1[xx*4 + 2]; + ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss1 += line0[xx * 4 + 1] + line1[xx * 4 + 1]; + ss2 += line0[xx * 4 + 2] + line1[xx * 4 + 2]; } } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line[xx*4 + 0] + line[xx*4 + 4]; - ss1 += line[xx*4 + 1] + line[xx*4 + 5]; - ss2 += line[xx*4 + 2] + line[xx*4 + 6]; + ss0 += line[xx * 4 + 0] + line[xx * 4 + 4]; + ss1 += line[xx * 4 + 1] + line[xx * 4 + 5]; + ss2 += line[xx * 4 + 2] + line[xx * 4 + 6]; } if (xscale & 0x01) { - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; } } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, 0); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line0[xx*4 + 0] + line0[xx*4 + 4] + - line1[xx*4 + 0] + line1[xx*4 + 4]; - ss1 += line0[xx*4 + 1] + line0[xx*4 + 5] + - line1[xx*4 + 1] + line1[xx*4 + 5]; - ss2 += line0[xx*4 + 2] + line0[xx*4 + 6] + - line1[xx*4 + 2] + line1[xx*4 + 6]; - ss3 += line0[xx*4 + 3] + line0[xx*4 + 7] + - line1[xx*4 + 3] + line1[xx*4 + 7]; + ss0 += line0[xx * 4 + 0] + line0[xx * 4 + 4] + + line1[xx * 4 + 0] + line1[xx * 4 + 4]; + ss1 += line0[xx * 4 + 1] + line0[xx * 4 + 5] + + line1[xx * 4 + 1] + line1[xx * 4 + 5]; + ss2 += line0[xx * 4 + 2] + line0[xx * 4 + 6] + + line1[xx * 4 + 2] + line1[xx * 4 + 6]; + ss3 += line0[xx * 4 + 3] + line0[xx * 4 + 7] + + line1[xx * 4 + 3] + line1[xx * 4 + 7]; } if (xscale & 0x01) { - ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; - ss1 += line0[xx*4 + 1] + line1[xx*4 + 1]; - ss2 += line0[xx*4 + 2] + line1[xx*4 + 2]; - ss3 += line0[xx*4 + 3] + line1[xx*4 + 3]; + ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss1 += line0[xx * 4 + 1] + line1[xx * 4 + 1]; + ss2 += line0[xx * 4 + 2] + line1[xx * 4 + 2]; + ss3 += line0[xx * 4 + 3] + line1[xx * 4 + 3]; } } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line[xx*4 + 0] + line[xx*4 + 4]; - ss1 += line[xx*4 + 1] + line[xx*4 + 5]; - ss2 += line[xx*4 + 2] + line[xx*4 + 6]; - ss3 += line[xx*4 + 3] + line[xx*4 + 7]; + ss0 += line[xx * 4 + 0] + line[xx * 4 + 4]; + ss1 += line[xx * 4 + 1] + line[xx * 4 + 5]; + ss2 += line[xx * 4 + 2] + line[xx * 4 + 6]; + ss3 += line[xx * 4 + 3] + line[xx * 4 + 7]; } if (xscale & 0x01) { - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; - ss3 += line[xx*4 + 3]; + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; + ss3 += line[xx * 4 + 3]; } } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -180,12 +179,10 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale } } - void -ImagingReduce1xN(Imaging imOut, Imaging imIn, int box[4], int yscale) -{ +ImagingReduce1xN(Imaging imOut, Imaging imIn, int box[4], int yscale) { /* Optimized implementation for xscale = 1. - */ + */ int x, y, yy; int xscale = 1; UINT32 multiplier = division_UINT32(yscale * xscale, 8); @@ -193,9 +190,9 @@ ImagingReduce1xN(Imaging imOut, Imaging imIn, int box[4], int yscale) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; + int yy_from = box[1] + y * yscale; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 ss = amend; for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image8[yy]; @@ -211,74 +208,77 @@ ImagingReduce1xN(Imaging imOut, Imaging imIn, int box[4], int yscale) } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; + int yy_from = box[1] + y * yscale; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss3 = amend; for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; - ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; - ss3 += line0[xx*4 + 3] + line1[xx*4 + 3]; + ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss3 += line0[xx * 4 + 3] + line1[xx * 4 + 3]; } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; - ss0 += line[xx*4 + 0]; - ss3 += line[xx*4 + 3]; + ss0 += line[xx * 4 + 0]; + ss3 += line[xx * 4 + 3]; } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, 0, - 0, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, 0, 0, (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend; for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; - ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; - ss1 += line0[xx*4 + 1] + line1[xx*4 + 1]; - ss2 += line0[xx*4 + 2] + line1[xx*4 + 2]; + ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss1 += line0[xx * 4 + 1] + line1[xx * 4 + 1]; + ss2 += line0[xx * 4 + 2] + line1[xx * 4 + 2]; } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, 0); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; - ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; - ss1 += line0[xx*4 + 1] + line1[xx*4 + 1]; - ss2 += line0[xx*4 + 2] + line1[xx*4 + 2]; - ss3 += line0[xx*4 + 3] + line1[xx*4 + 3]; + ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss1 += line0[xx * 4 + 1] + line1[xx * 4 + 1]; + ss2 += line0[xx * 4 + 2] + line1[xx * 4 + 2]; + ss3 += line0[xx * 4 + 3] + line1[xx * 4 + 3]; } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; - ss3 += line[xx*4 + 3]; + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; + ss3 += line[xx * 4 + 3]; } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -286,12 +286,10 @@ ImagingReduce1xN(Imaging imOut, Imaging imIn, int box[4], int yscale) } } - void -ImagingReduceNx1(Imaging imOut, Imaging imIn, int box[4], int xscale) -{ +ImagingReduceNx1(Imaging imOut, Imaging imIn, int box[4], int xscale) { /* Optimized implementation for yscale = 1. - */ + */ int x, y, xx; int yscale = 1; UINT32 multiplier = division_UINT32(yscale * xscale, 8); @@ -299,10 +297,10 @@ ImagingReduceNx1(Imaging imOut, Imaging imIn, int box[4], int xscale) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line = (UINT8 *)imIn->image8[yy]; for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 ss = amend; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss += line[xx + 0] + line[xx + 1]; @@ -315,66 +313,69 @@ ImagingReduceNx1(Imaging imOut, Imaging imIn, int box[4], int xscale) } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line = (UINT8 *)imIn->image[yy]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss3 = amend; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line[xx*4 + 0] + line[xx*4 + 4]; - ss3 += line[xx*4 + 3] + line[xx*4 + 7]; + ss0 += line[xx * 4 + 0] + line[xx * 4 + 4]; + ss3 += line[xx * 4 + 3] + line[xx * 4 + 7]; } if (xscale & 0x01) { - ss0 += line[xx*4 + 0]; - ss3 += line[xx*4 + 3]; + ss0 += line[xx * 4 + 0]; + ss3 += line[xx * 4 + 3]; } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, 0, - 0, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, 0, 0, (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line[xx*4 + 0] + line[xx*4 + 4]; - ss1 += line[xx*4 + 1] + line[xx*4 + 5]; - ss2 += line[xx*4 + 2] + line[xx*4 + 6]; + ss0 += line[xx * 4 + 0] + line[xx * 4 + 4]; + ss1 += line[xx * 4 + 1] + line[xx * 4 + 5]; + ss2 += line[xx * 4 + 2] + line[xx * 4 + 6]; } if (xscale & 0x01) { - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, 0); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss0 += line[xx*4 + 0] + line[xx*4 + 4]; - ss1 += line[xx*4 + 1] + line[xx*4 + 5]; - ss2 += line[xx*4 + 2] + line[xx*4 + 6]; - ss3 += line[xx*4 + 3] + line[xx*4 + 7]; + ss0 += line[xx * 4 + 0] + line[xx * 4 + 4]; + ss1 += line[xx * 4 + 1] + line[xx * 4 + 5]; + ss2 += line[xx * 4 + 2] + line[xx * 4 + 6]; + ss3 += line[xx * 4 + 3] + line[xx * 4 + 7]; } if (xscale & 0x01) { - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; - ss3 += line[xx*4 + 3]; + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; + ss3 += line[xx * 4 + 3]; } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -383,10 +384,9 @@ ImagingReduceNx1(Imaging imOut, Imaging imIn, int box[4], int xscale) } void -ImagingReduce1x2(Imaging imOut, Imaging imIn, int box[4]) -{ +ImagingReduce1x2(Imaging imOut, Imaging imIn, int box[4]) { /* Optimized implementation for xscale = 1 and yscale = 2. - */ + */ int xscale = 1, yscale = 2; int x, y; UINT32 ss0, ss1, ss2, ss3; @@ -394,61 +394,53 @@ ImagingReduce1x2(Imaging imOut, Imaging imIn, int box[4]) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1]; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; - ss0 = line0[xx + 0] + - line1[xx + 0]; + int xx = box[0] + x * xscale; + ss0 = line0[xx + 0] + line1[xx + 0]; imOut->image8[y][x] = (ss0 + amend) >> 1; } } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + - line1[xx*4 + 0]; - ss3 = line0[xx*4 + 3] + - line1[xx*4 + 3]; - v = MAKE_UINT32((ss0 + amend) >> 1, 0, - 0, (ss3 + amend) >> 1); + ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss3 = line0[xx * 4 + 3] + line1[xx * 4 + 3]; + v = MAKE_UINT32((ss0 + amend) >> 1, 0, 0, (ss3 + amend) >> 1); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + - line1[xx*4 + 0]; - ss1 = line0[xx*4 + 1] + - line1[xx*4 + 1]; - ss2 = line0[xx*4 + 2] + - line1[xx*4 + 2]; - v = MAKE_UINT32((ss0 + amend) >> 1, (ss1 + amend) >> 1, - (ss2 + amend) >> 1, 0); + ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss1 = line0[xx * 4 + 1] + line1[xx * 4 + 1]; + ss2 = line0[xx * 4 + 2] + line1[xx * 4 + 2]; + v = MAKE_UINT32( + (ss0 + amend) >> 1, (ss1 + amend) >> 1, (ss2 + amend) >> 1, 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + - line1[xx*4 + 0]; - ss1 = line0[xx*4 + 1] + - line1[xx*4 + 1]; - ss2 = line0[xx*4 + 2] + - line1[xx*4 + 2]; - ss3 = line0[xx*4 + 3] + - line1[xx*4 + 3]; - v = MAKE_UINT32((ss0 + amend) >> 1, (ss1 + amend) >> 1, - (ss2 + amend) >> 1, (ss3 + amend) >> 1); + ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0]; + ss1 = line0[xx * 4 + 1] + line1[xx * 4 + 1]; + ss2 = line0[xx * 4 + 2] + line1[xx * 4 + 2]; + ss3 = line0[xx * 4 + 3] + line1[xx * 4 + 3]; + v = MAKE_UINT32( + (ss0 + amend) >> 1, + (ss1 + amend) >> 1, + (ss2 + amend) >> 1, + (ss3 + amend) >> 1); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -456,12 +448,10 @@ ImagingReduce1x2(Imaging imOut, Imaging imIn, int box[4]) } } - void -ImagingReduce2x1(Imaging imOut, Imaging imIn, int box[4]) -{ +ImagingReduce2x1(Imaging imOut, Imaging imIn, int box[4]) { /* Optimized implementation for xscale = 2 and yscale = 1. - */ + */ int xscale = 2, yscale = 1; int x, y; UINT32 ss0, ss1, ss2, ss3; @@ -469,49 +459,51 @@ ImagingReduce2x1(Imaging imOut, Imaging imIn, int box[4]) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0]; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; ss0 = line0[xx + 0] + line0[xx + 1]; imOut->image8[y][x] = (ss0 + amend) >> 1; } } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image[yy + 0]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7]; - v = MAKE_UINT32((ss0 + amend) >> 1, 0, - 0, (ss3 + amend) >> 1); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7]; + v = MAKE_UINT32((ss0 + amend) >> 1, 0, 0, (ss3 + amend) >> 1); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6]; - v = MAKE_UINT32((ss0 + amend) >> 1, (ss1 + amend) >> 1, - (ss2 + amend) >> 1, 0); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6]; + v = MAKE_UINT32( + (ss0 + amend) >> 1, (ss1 + amend) >> 1, (ss2 + amend) >> 1, 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7]; - v = MAKE_UINT32((ss0 + amend) >> 1, (ss1 + amend) >> 1, - (ss2 + amend) >> 1, (ss3 + amend) >> 1); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7]; + v = MAKE_UINT32( + (ss0 + amend) >> 1, + (ss1 + amend) >> 1, + (ss2 + amend) >> 1, + (ss3 + amend) >> 1); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -519,12 +511,10 @@ ImagingReduce2x1(Imaging imOut, Imaging imIn, int box[4]) } } - void -ImagingReduce2x2(Imaging imOut, Imaging imIn, int box[4]) -{ +ImagingReduce2x2(Imaging imOut, Imaging imIn, int box[4]) { /* Optimized implementation for xscale = 2 and yscale = 2. - */ + */ int xscale = 2, yscale = 2; int x, y; UINT32 ss0, ss1, ss2, ss3; @@ -532,61 +522,62 @@ ImagingReduce2x2(Imaging imOut, Imaging imIn, int box[4]) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1]; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; - ss0 = line0[xx + 0] + line0[xx + 1] + - line1[xx + 0] + line1[xx + 1]; + int xx = box[0] + x * xscale; + ss0 = line0[xx + 0] + line0[xx + 1] + line1[xx + 0] + line1[xx + 1]; imOut->image8[y][x] = (ss0 + amend) >> 2; } } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + - line1[xx*4 + 0] + line1[xx*4 + 4]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + - line1[xx*4 + 3] + line1[xx*4 + 7]; - v = MAKE_UINT32((ss0 + amend) >> 2, 0, - 0, (ss3 + amend) >> 2); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line1[xx * 4 + 0] + + line1[xx * 4 + 4]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line1[xx * 4 + 3] + + line1[xx * 4 + 7]; + v = MAKE_UINT32((ss0 + amend) >> 2, 0, 0, (ss3 + amend) >> 2); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + - line1[xx*4 + 0] + line1[xx*4 + 4]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + - line1[xx*4 + 1] + line1[xx*4 + 5]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + - line1[xx*4 + 2] + line1[xx*4 + 6]; - v = MAKE_UINT32((ss0 + amend) >> 2, (ss1 + amend) >> 2, - (ss2 + amend) >> 2, 0); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line1[xx * 4 + 0] + + line1[xx * 4 + 4]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line1[xx * 4 + 1] + + line1[xx * 4 + 5]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line1[xx * 4 + 2] + + line1[xx * 4 + 6]; + v = MAKE_UINT32( + (ss0 + amend) >> 2, (ss1 + amend) >> 2, (ss2 + amend) >> 2, 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + - line1[xx*4 + 0] + line1[xx*4 + 4]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + - line1[xx*4 + 1] + line1[xx*4 + 5]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + - line1[xx*4 + 2] + line1[xx*4 + 6]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + - line1[xx*4 + 3] + line1[xx*4 + 7]; - v = MAKE_UINT32((ss0 + amend) >> 2, (ss1 + amend) >> 2, - (ss2 + amend) >> 2, (ss3 + amend) >> 2); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line1[xx * 4 + 0] + + line1[xx * 4 + 4]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line1[xx * 4 + 1] + + line1[xx * 4 + 5]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line1[xx * 4 + 2] + + line1[xx * 4 + 6]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line1[xx * 4 + 3] + + line1[xx * 4 + 7]; + v = MAKE_UINT32( + (ss0 + amend) >> 2, + (ss1 + amend) >> 2, + (ss2 + amend) >> 2, + (ss3 + amend) >> 2); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -594,12 +585,10 @@ ImagingReduce2x2(Imaging imOut, Imaging imIn, int box[4]) } } - void -ImagingReduce1x3(Imaging imOut, Imaging imIn, int box[4]) -{ +ImagingReduce1x3(Imaging imOut, Imaging imIn, int box[4]) { /* Optimized implementation for xscale = 1 and yscale = 3. - */ + */ int xscale = 1, yscale = 3; int x, y; UINT32 ss0, ss1, ss2, ss3; @@ -608,76 +597,62 @@ ImagingReduce1x3(Imaging imOut, Imaging imIn, int box[4]) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1]; UINT8 *line2 = (UINT8 *)imIn->image8[yy + 2]; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; - ss0 = line0[xx + 0] + - line1[xx + 0] + - line2[xx + 0]; + int xx = box[0] + x * xscale; + ss0 = line0[xx + 0] + line1[xx + 0] + line2[xx + 0]; imOut->image8[y][x] = ((ss0 + amend) * multiplier) >> 24; } } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; UINT8 *line2 = (UINT8 *)imIn->image[yy + 2]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + - line1[xx*4 + 0] + - line2[xx*4 + 0]; - ss3 = line0[xx*4 + 3] + - line1[xx*4 + 3] + - line2[xx*4 + 3]; + ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0] + line2[xx * 4 + 0]; + ss3 = line0[xx * 4 + 3] + line1[xx * 4 + 3] + line2[xx * 4 + 3]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, 0, - 0, ((ss3 + amend) * multiplier) >> 24); + ((ss0 + amend) * multiplier) >> 24, + 0, + 0, + ((ss3 + amend) * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + - line1[xx*4 + 0] + - line2[xx*4 + 0]; - ss1 = line0[xx*4 + 1] + - line1[xx*4 + 1] + - line2[xx*4 + 1]; - ss2 = line0[xx*4 + 2] + - line1[xx*4 + 2] + - line2[xx*4 + 2]; + ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0] + line2[xx * 4 + 0]; + ss1 = line0[xx * 4 + 1] + line1[xx * 4 + 1] + line2[xx * 4 + 1]; + ss2 = line0[xx * 4 + 2] + line1[xx * 4 + 2] + line2[xx * 4 + 2]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, ((ss1 + amend) * multiplier) >> 24, - ((ss2 + amend) * multiplier) >> 24, 0); + ((ss0 + amend) * multiplier) >> 24, + ((ss1 + amend) * multiplier) >> 24, + ((ss2 + amend) * multiplier) >> 24, + 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + - line1[xx*4 + 0] + - line2[xx*4 + 0]; - ss1 = line0[xx*4 + 1] + - line1[xx*4 + 1] + - line2[xx*4 + 1]; - ss2 = line0[xx*4 + 2] + - line1[xx*4 + 2] + - line2[xx*4 + 2]; - ss3 = line0[xx*4 + 3] + - line1[xx*4 + 3] + - line2[xx*4 + 3]; + ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0] + line2[xx * 4 + 0]; + ss1 = line0[xx * 4 + 1] + line1[xx * 4 + 1] + line2[xx * 4 + 1]; + ss2 = line0[xx * 4 + 2] + line1[xx * 4 + 2] + line2[xx * 4 + 2]; + ss3 = line0[xx * 4 + 3] + line1[xx * 4 + 3] + line2[xx * 4 + 3]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, ((ss1 + amend) * multiplier) >> 24, - ((ss2 + amend) * multiplier) >> 24, ((ss3 + amend) * multiplier) >> 24); + ((ss0 + amend) * multiplier) >> 24, + ((ss1 + amend) * multiplier) >> 24, + ((ss2 + amend) * multiplier) >> 24, + ((ss3 + amend) * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -685,12 +660,10 @@ ImagingReduce1x3(Imaging imOut, Imaging imIn, int box[4]) } } - void -ImagingReduce3x1(Imaging imOut, Imaging imIn, int box[4]) -{ +ImagingReduce3x1(Imaging imOut, Imaging imIn, int box[4]) { /* Optimized implementation for xscale = 3 and yscale = 1. - */ + */ int xscale = 3, yscale = 1; int x, y; UINT32 ss0, ss1, ss2, ss3; @@ -699,52 +672,58 @@ ImagingReduce3x1(Imaging imOut, Imaging imIn, int box[4]) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0]; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2]; imOut->image8[y][x] = ((ss0 + amend) * multiplier) >> 24; } } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image[yy + 0]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + line0[xx*4 + 11]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, 0, - 0, ((ss3 + amend) * multiplier) >> 24); + ((ss0 + amend) * multiplier) >> 24, + 0, + 0, + ((ss3 + amend) * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + line0[xx*4 + 9]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + line0[xx*4 + 10]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, ((ss1 + amend) * multiplier) >> 24, - ((ss2 + amend) * multiplier) >> 24, 0); + ((ss0 + amend) * multiplier) >> 24, + ((ss1 + amend) * multiplier) >> 24, + ((ss2 + amend) * multiplier) >> 24, + 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + line0[xx*4 + 9]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + line0[xx*4 + 10]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + line0[xx*4 + 11]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, ((ss1 + amend) * multiplier) >> 24, - ((ss2 + amend) * multiplier) >> 24, ((ss3 + amend) * multiplier) >> 24); + ((ss0 + amend) * multiplier) >> 24, + ((ss1 + amend) * multiplier) >> 24, + ((ss2 + amend) * multiplier) >> 24, + ((ss3 + amend) * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -752,12 +731,10 @@ ImagingReduce3x1(Imaging imOut, Imaging imIn, int box[4]) } } - void -ImagingReduce3x3(Imaging imOut, Imaging imIn, int box[4]) -{ +ImagingReduce3x3(Imaging imOut, Imaging imIn, int box[4]) { /* Optimized implementation for xscale = 3 and yscale = 3. - */ + */ int xscale = 3, yscale = 3; int x, y; UINT32 ss0, ss1, ss2, ss3; @@ -766,76 +743,82 @@ ImagingReduce3x3(Imaging imOut, Imaging imIn, int box[4]) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1]; UINT8 *line2 = (UINT8 *)imIn->image8[yy + 2]; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; - ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2] + - line1[xx + 0] + line1[xx + 1] + line1[xx + 2] + - line2[xx + 0] + line2[xx + 1] + line2[xx + 2]; + int xx = box[0] + x * xscale; + ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2] + line1[xx + 0] + + line1[xx + 1] + line1[xx + 2] + line2[xx + 0] + line2[xx + 1] + + line2[xx + 2]; imOut->image8[y][x] = ((ss0 + amend) * multiplier) >> 24; } } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; UINT8 *line2 = (UINT8 *)imIn->image[yy + 2]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + line0[xx*4 + 11] + - line1[xx*4 + 3] + line1[xx*4 + 7] + line1[xx*4 + 11] + - line2[xx*4 + 3] + line2[xx*4 + 7] + line2[xx*4 + 11]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line1[xx * 4 + 0] + line1[xx * 4 + 4] + line1[xx * 4 + 8] + + line2[xx * 4 + 0] + line2[xx * 4 + 4] + line2[xx * 4 + 8]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] + + line1[xx * 4 + 3] + line1[xx * 4 + 7] + line1[xx * 4 + 11] + + line2[xx * 4 + 3] + line2[xx * 4 + 7] + line2[xx * 4 + 11]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, 0, - 0, ((ss3 + amend) * multiplier) >> 24); + ((ss0 + amend) * multiplier) >> 24, + 0, + 0, + ((ss3 + amend) * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + line0[xx*4 + 9] + - line1[xx*4 + 1] + line1[xx*4 + 5] + line1[xx*4 + 9] + - line2[xx*4 + 1] + line2[xx*4 + 5] + line2[xx*4 + 9]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + line0[xx*4 + 10] + - line1[xx*4 + 2] + line1[xx*4 + 6] + line1[xx*4 + 10] + - line2[xx*4 + 2] + line2[xx*4 + 6] + line2[xx*4 + 10]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line1[xx * 4 + 0] + line1[xx * 4 + 4] + line1[xx * 4 + 8] + + line2[xx * 4 + 0] + line2[xx * 4 + 4] + line2[xx * 4 + 8]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] + + line1[xx * 4 + 1] + line1[xx * 4 + 5] + line1[xx * 4 + 9] + + line2[xx * 4 + 1] + line2[xx * 4 + 5] + line2[xx * 4 + 9]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] + + line1[xx * 4 + 2] + line1[xx * 4 + 6] + line1[xx * 4 + 10] + + line2[xx * 4 + 2] + line2[xx * 4 + 6] + line2[xx * 4 + 10]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, ((ss1 + amend) * multiplier) >> 24, - ((ss2 + amend) * multiplier) >> 24, 0); + ((ss0 + amend) * multiplier) >> 24, + ((ss1 + amend) * multiplier) >> 24, + ((ss2 + amend) * multiplier) >> 24, + 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + line0[xx*4 + 9] + - line1[xx*4 + 1] + line1[xx*4 + 5] + line1[xx*4 + 9] + - line2[xx*4 + 1] + line2[xx*4 + 5] + line2[xx*4 + 9]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + line0[xx*4 + 10] + - line1[xx*4 + 2] + line1[xx*4 + 6] + line1[xx*4 + 10] + - line2[xx*4 + 2] + line2[xx*4 + 6] + line2[xx*4 + 10]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + line0[xx*4 + 11] + - line1[xx*4 + 3] + line1[xx*4 + 7] + line1[xx*4 + 11] + - line2[xx*4 + 3] + line2[xx*4 + 7] + line2[xx*4 + 11]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line1[xx * 4 + 0] + line1[xx * 4 + 4] + line1[xx * 4 + 8] + + line2[xx * 4 + 0] + line2[xx * 4 + 4] + line2[xx * 4 + 8]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] + + line1[xx * 4 + 1] + line1[xx * 4 + 5] + line1[xx * 4 + 9] + + line2[xx * 4 + 1] + line2[xx * 4 + 5] + line2[xx * 4 + 9]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] + + line1[xx * 4 + 2] + line1[xx * 4 + 6] + line1[xx * 4 + 10] + + line2[xx * 4 + 2] + line2[xx * 4 + 6] + line2[xx * 4 + 10]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] + + line1[xx * 4 + 3] + line1[xx * 4 + 7] + line1[xx * 4 + 11] + + line2[xx * 4 + 3] + line2[xx * 4 + 7] + line2[xx * 4 + 11]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, ((ss1 + amend) * multiplier) >> 24, - ((ss2 + amend) * multiplier) >> 24, ((ss3 + amend) * multiplier) >> 24); + ((ss0 + amend) * multiplier) >> 24, + ((ss1 + amend) * multiplier) >> 24, + ((ss2 + amend) * multiplier) >> 24, + ((ss3 + amend) * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -844,10 +827,9 @@ ImagingReduce3x3(Imaging imOut, Imaging imIn, int box[4]) } void -ImagingReduce4x4(Imaging imOut, Imaging imIn, int box[4]) -{ +ImagingReduce4x4(Imaging imOut, Imaging imIn, int box[4]) { /* Optimized implementation for xscale = 4 and yscale = 4. - */ + */ int xscale = 4, yscale = 4; int x, y; UINT32 ss0, ss1, ss2, ss3; @@ -855,13 +837,13 @@ ImagingReduce4x4(Imaging imOut, Imaging imIn, int box[4]) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1]; UINT8 *line2 = (UINT8 *)imIn->image8[yy + 2]; UINT8 *line3 = (UINT8 *)imIn->image8[yy + 3]; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2] + line0[xx + 3] + line1[xx + 0] + line1[xx + 1] + line1[xx + 2] + line1[xx + 3] + line2[xx + 0] + line2[xx + 1] + line2[xx + 2] + line2[xx + 3] + @@ -871,69 +853,89 @@ ImagingReduce4x4(Imaging imOut, Imaging imIn, int box[4]) } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; UINT8 *line2 = (UINT8 *)imIn->image[yy + 2]; UINT8 *line3 = (UINT8 *)imIn->image[yy + 3]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + line0[xx*4 + 12] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + line1[xx*4 + 12] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8] + line2[xx*4 + 12] + - line3[xx*4 + 0] + line3[xx*4 + 4] + line3[xx*4 + 8] + line3[xx*4 + 12]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + line0[xx*4 + 11] + line0[xx*4 + 15] + - line1[xx*4 + 3] + line1[xx*4 + 7] + line1[xx*4 + 11] + line1[xx*4 + 15] + - line2[xx*4 + 3] + line2[xx*4 + 7] + line2[xx*4 + 11] + line2[xx*4 + 15] + - line3[xx*4 + 3] + line3[xx*4 + 7] + line3[xx*4 + 11] + line3[xx*4 + 15]; - v = MAKE_UINT32((ss0 + amend) >> 4, 0, - 0, (ss3 + amend) >> 4); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line0[xx * 4 + 12] + line1[xx * 4 + 0] + line1[xx * 4 + 4] + + line1[xx * 4 + 8] + line1[xx * 4 + 12] + line2[xx * 4 + 0] + + line2[xx * 4 + 4] + line2[xx * 4 + 8] + line2[xx * 4 + 12] + + line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] + + line3[xx * 4 + 12]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] + + line0[xx * 4 + 15] + line1[xx * 4 + 3] + line1[xx * 4 + 7] + + line1[xx * 4 + 11] + line1[xx * 4 + 15] + line2[xx * 4 + 3] + + line2[xx * 4 + 7] + line2[xx * 4 + 11] + line2[xx * 4 + 15] + + line3[xx * 4 + 3] + line3[xx * 4 + 7] + line3[xx * 4 + 11] + + line3[xx * 4 + 15]; + v = MAKE_UINT32((ss0 + amend) >> 4, 0, 0, (ss3 + amend) >> 4); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + line0[xx*4 + 12] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + line1[xx*4 + 12] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8] + line2[xx*4 + 12] + - line3[xx*4 + 0] + line3[xx*4 + 4] + line3[xx*4 + 8] + line3[xx*4 + 12]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + line0[xx*4 + 9] + line0[xx*4 + 13] + - line1[xx*4 + 1] + line1[xx*4 + 5] + line1[xx*4 + 9] + line1[xx*4 + 13] + - line2[xx*4 + 1] + line2[xx*4 + 5] + line2[xx*4 + 9] + line2[xx*4 + 13] + - line3[xx*4 + 1] + line3[xx*4 + 5] + line3[xx*4 + 9] + line3[xx*4 + 13]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + line0[xx*4 + 10] + line0[xx*4 + 14] + - line1[xx*4 + 2] + line1[xx*4 + 6] + line1[xx*4 + 10] + line1[xx*4 + 14] + - line2[xx*4 + 2] + line2[xx*4 + 6] + line2[xx*4 + 10] + line2[xx*4 + 14] + - line3[xx*4 + 2] + line3[xx*4 + 6] + line3[xx*4 + 10] + line3[xx*4 + 14]; - v = MAKE_UINT32((ss0 + amend) >> 4, (ss1 + amend) >> 4, - (ss2 + amend) >> 4, 0); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line0[xx * 4 + 12] + line1[xx * 4 + 0] + line1[xx * 4 + 4] + + line1[xx * 4 + 8] + line1[xx * 4 + 12] + line2[xx * 4 + 0] + + line2[xx * 4 + 4] + line2[xx * 4 + 8] + line2[xx * 4 + 12] + + line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] + + line3[xx * 4 + 12]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] + + line0[xx * 4 + 13] + line1[xx * 4 + 1] + line1[xx * 4 + 5] + + line1[xx * 4 + 9] + line1[xx * 4 + 13] + line2[xx * 4 + 1] + + line2[xx * 4 + 5] + line2[xx * 4 + 9] + line2[xx * 4 + 13] + + line3[xx * 4 + 1] + line3[xx * 4 + 5] + line3[xx * 4 + 9] + + line3[xx * 4 + 13]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] + + line0[xx * 4 + 14] + line1[xx * 4 + 2] + line1[xx * 4 + 6] + + line1[xx * 4 + 10] + line1[xx * 4 + 14] + line2[xx * 4 + 2] + + line2[xx * 4 + 6] + line2[xx * 4 + 10] + line2[xx * 4 + 14] + + line3[xx * 4 + 2] + line3[xx * 4 + 6] + line3[xx * 4 + 10] + + line3[xx * 4 + 14]; + v = MAKE_UINT32( + (ss0 + amend) >> 4, (ss1 + amend) >> 4, (ss2 + amend) >> 4, 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + line0[xx*4 + 12] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + line1[xx*4 + 12] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8] + line2[xx*4 + 12] + - line3[xx*4 + 0] + line3[xx*4 + 4] + line3[xx*4 + 8] + line3[xx*4 + 12]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + line0[xx*4 + 9] + line0[xx*4 + 13] + - line1[xx*4 + 1] + line1[xx*4 + 5] + line1[xx*4 + 9] + line1[xx*4 + 13] + - line2[xx*4 + 1] + line2[xx*4 + 5] + line2[xx*4 + 9] + line2[xx*4 + 13] + - line3[xx*4 + 1] + line3[xx*4 + 5] + line3[xx*4 + 9] + line3[xx*4 + 13]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + line0[xx*4 + 10] + line0[xx*4 + 14] + - line1[xx*4 + 2] + line1[xx*4 + 6] + line1[xx*4 + 10] + line1[xx*4 + 14] + - line2[xx*4 + 2] + line2[xx*4 + 6] + line2[xx*4 + 10] + line2[xx*4 + 14] + - line3[xx*4 + 2] + line3[xx*4 + 6] + line3[xx*4 + 10] + line3[xx*4 + 14]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + line0[xx*4 + 11] + line0[xx*4 + 15] + - line1[xx*4 + 3] + line1[xx*4 + 7] + line1[xx*4 + 11] + line1[xx*4 + 15] + - line2[xx*4 + 3] + line2[xx*4 + 7] + line2[xx*4 + 11] + line2[xx*4 + 15] + - line3[xx*4 + 3] + line3[xx*4 + 7] + line3[xx*4 + 11] + line3[xx*4 + 15]; - v = MAKE_UINT32((ss0 + amend) >> 4, (ss1 + amend) >> 4, - (ss2 + amend) >> 4, (ss3 + amend) >> 4); + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line0[xx * 4 + 12] + line1[xx * 4 + 0] + line1[xx * 4 + 4] + + line1[xx * 4 + 8] + line1[xx * 4 + 12] + line2[xx * 4 + 0] + + line2[xx * 4 + 4] + line2[xx * 4 + 8] + line2[xx * 4 + 12] + + line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] + + line3[xx * 4 + 12]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] + + line0[xx * 4 + 13] + line1[xx * 4 + 1] + line1[xx * 4 + 5] + + line1[xx * 4 + 9] + line1[xx * 4 + 13] + line2[xx * 4 + 1] + + line2[xx * 4 + 5] + line2[xx * 4 + 9] + line2[xx * 4 + 13] + + line3[xx * 4 + 1] + line3[xx * 4 + 5] + line3[xx * 4 + 9] + + line3[xx * 4 + 13]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] + + line0[xx * 4 + 14] + line1[xx * 4 + 2] + line1[xx * 4 + 6] + + line1[xx * 4 + 10] + line1[xx * 4 + 14] + line2[xx * 4 + 2] + + line2[xx * 4 + 6] + line2[xx * 4 + 10] + line2[xx * 4 + 14] + + line3[xx * 4 + 2] + line3[xx * 4 + 6] + line3[xx * 4 + 10] + + line3[xx * 4 + 14]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] + + line0[xx * 4 + 15] + line1[xx * 4 + 3] + line1[xx * 4 + 7] + + line1[xx * 4 + 11] + line1[xx * 4 + 15] + line2[xx * 4 + 3] + + line2[xx * 4 + 7] + line2[xx * 4 + 11] + line2[xx * 4 + 15] + + line3[xx * 4 + 3] + line3[xx * 4 + 7] + line3[xx * 4 + 11] + + line3[xx * 4 + 15]; + v = MAKE_UINT32( + (ss0 + amend) >> 4, + (ss1 + amend) >> 4, + (ss2 + amend) >> 4, + (ss3 + amend) >> 4); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -941,12 +943,10 @@ ImagingReduce4x4(Imaging imOut, Imaging imIn, int box[4]) } } - void -ImagingReduce5x5(Imaging imOut, Imaging imIn, int box[4]) -{ +ImagingReduce5x5(Imaging imOut, Imaging imIn, int box[4]) { /* Fast special case for xscale = 5 and yscale = 5. - */ + */ int xscale = 5, yscale = 5; int x, y; UINT32 ss0, ss1, ss2, ss3; @@ -955,25 +955,27 @@ ImagingReduce5x5(Imaging imOut, Imaging imIn, int box[4]) if (imIn->image8) { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1]; UINT8 *line2 = (UINT8 *)imIn->image8[yy + 2]; UINT8 *line3 = (UINT8 *)imIn->image8[yy + 3]; UINT8 *line4 = (UINT8 *)imIn->image8[yy + 4]; for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; - ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2] + line0[xx + 3] + line0[xx + 4] + - line1[xx + 0] + line1[xx + 1] + line1[xx + 2] + line1[xx + 3] + line1[xx + 4] + - line2[xx + 0] + line2[xx + 1] + line2[xx + 2] + line2[xx + 3] + line2[xx + 4] + - line3[xx + 0] + line3[xx + 1] + line3[xx + 2] + line3[xx + 3] + line3[xx + 4] + - line4[xx + 0] + line4[xx + 1] + line4[xx + 2] + line4[xx + 3] + line4[xx + 4]; + int xx = box[0] + x * xscale; + ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2] + line0[xx + 3] + + line0[xx + 4] + line1[xx + 0] + line1[xx + 1] + line1[xx + 2] + + line1[xx + 3] + line1[xx + 4] + line2[xx + 0] + line2[xx + 1] + + line2[xx + 2] + line2[xx + 3] + line2[xx + 4] + line3[xx + 0] + + line3[xx + 1] + line3[xx + 2] + line3[xx + 3] + line3[xx + 4] + + line4[xx + 0] + line4[xx + 1] + line4[xx + 2] + line4[xx + 3] + + line4[xx + 4]; imOut->image8[y][x] = ((ss0 + amend) * multiplier) >> 24; } } } else { for (y = 0; y < box[3] / yscale; y++) { - int yy = box[1] + y*yscale; + int yy = box[1] + y * yscale; UINT8 *line0 = (UINT8 *)imIn->image[yy + 0]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; UINT8 *line2 = (UINT8 *)imIn->image[yy + 2]; @@ -981,74 +983,116 @@ ImagingReduce5x5(Imaging imOut, Imaging imIn, int box[4]) UINT8 *line4 = (UINT8 *)imIn->image[yy + 4]; if (imIn->bands == 2) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + line0[xx*4 + 12] + line0[xx*4 + 16] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + line1[xx*4 + 12] + line1[xx*4 + 16] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8] + line2[xx*4 + 12] + line2[xx*4 + 16] + - line3[xx*4 + 0] + line3[xx*4 + 4] + line3[xx*4 + 8] + line3[xx*4 + 12] + line3[xx*4 + 16] + - line4[xx*4 + 0] + line4[xx*4 + 4] + line4[xx*4 + 8] + line4[xx*4 + 12] + line4[xx*4 + 16]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + line0[xx*4 + 11] + line0[xx*4 + 15] + line0[xx*4 + 19] + - line1[xx*4 + 3] + line1[xx*4 + 7] + line1[xx*4 + 11] + line1[xx*4 + 15] + line1[xx*4 + 19] + - line2[xx*4 + 3] + line2[xx*4 + 7] + line2[xx*4 + 11] + line2[xx*4 + 15] + line2[xx*4 + 19] + - line3[xx*4 + 3] + line3[xx*4 + 7] + line3[xx*4 + 11] + line3[xx*4 + 15] + line3[xx*4 + 19] + - line4[xx*4 + 3] + line4[xx*4 + 7] + line4[xx*4 + 11] + line4[xx*4 + 15] + line4[xx*4 + 19]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line0[xx * 4 + 12] + line0[xx * 4 + 16] + line1[xx * 4 + 0] + + line1[xx * 4 + 4] + line1[xx * 4 + 8] + line1[xx * 4 + 12] + + line1[xx * 4 + 16] + line2[xx * 4 + 0] + line2[xx * 4 + 4] + + line2[xx * 4 + 8] + line2[xx * 4 + 12] + line2[xx * 4 + 16] + + line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] + + line3[xx * 4 + 12] + line3[xx * 4 + 16] + line4[xx * 4 + 0] + + line4[xx * 4 + 4] + line4[xx * 4 + 8] + line4[xx * 4 + 12] + + line4[xx * 4 + 16]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] + + line0[xx * 4 + 15] + line0[xx * 4 + 19] + line1[xx * 4 + 3] + + line1[xx * 4 + 7] + line1[xx * 4 + 11] + line1[xx * 4 + 15] + + line1[xx * 4 + 19] + line2[xx * 4 + 3] + line2[xx * 4 + 7] + + line2[xx * 4 + 11] + line2[xx * 4 + 15] + line2[xx * 4 + 19] + + line3[xx * 4 + 3] + line3[xx * 4 + 7] + line3[xx * 4 + 11] + + line3[xx * 4 + 15] + line3[xx * 4 + 19] + line4[xx * 4 + 3] + + line4[xx * 4 + 7] + line4[xx * 4 + 11] + line4[xx * 4 + 15] + + line4[xx * 4 + 19]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, 0, - 0, ((ss3 + amend) * multiplier) >> 24); + ((ss0 + amend) * multiplier) >> 24, + 0, + 0, + ((ss3 + amend) * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + line0[xx*4 + 12] + line0[xx*4 + 16] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + line1[xx*4 + 12] + line1[xx*4 + 16] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8] + line2[xx*4 + 12] + line2[xx*4 + 16] + - line3[xx*4 + 0] + line3[xx*4 + 4] + line3[xx*4 + 8] + line3[xx*4 + 12] + line3[xx*4 + 16] + - line4[xx*4 + 0] + line4[xx*4 + 4] + line4[xx*4 + 8] + line4[xx*4 + 12] + line4[xx*4 + 16]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + line0[xx*4 + 9] + line0[xx*4 + 13] + line0[xx*4 + 17] + - line1[xx*4 + 1] + line1[xx*4 + 5] + line1[xx*4 + 9] + line1[xx*4 + 13] + line1[xx*4 + 17] + - line2[xx*4 + 1] + line2[xx*4 + 5] + line2[xx*4 + 9] + line2[xx*4 + 13] + line2[xx*4 + 17] + - line3[xx*4 + 1] + line3[xx*4 + 5] + line3[xx*4 + 9] + line3[xx*4 + 13] + line3[xx*4 + 17] + - line4[xx*4 + 1] + line4[xx*4 + 5] + line4[xx*4 + 9] + line4[xx*4 + 13] + line4[xx*4 + 17]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + line0[xx*4 + 10] + line0[xx*4 + 14] + line0[xx*4 + 18] + - line1[xx*4 + 2] + line1[xx*4 + 6] + line1[xx*4 + 10] + line1[xx*4 + 14] + line1[xx*4 + 18] + - line2[xx*4 + 2] + line2[xx*4 + 6] + line2[xx*4 + 10] + line2[xx*4 + 14] + line2[xx*4 + 18] + - line3[xx*4 + 2] + line3[xx*4 + 6] + line3[xx*4 + 10] + line3[xx*4 + 14] + line3[xx*4 + 18] + - line4[xx*4 + 2] + line4[xx*4 + 6] + line4[xx*4 + 10] + line4[xx*4 + 14] + line4[xx*4 + 18]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line0[xx * 4 + 12] + line0[xx * 4 + 16] + line1[xx * 4 + 0] + + line1[xx * 4 + 4] + line1[xx * 4 + 8] + line1[xx * 4 + 12] + + line1[xx * 4 + 16] + line2[xx * 4 + 0] + line2[xx * 4 + 4] + + line2[xx * 4 + 8] + line2[xx * 4 + 12] + line2[xx * 4 + 16] + + line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] + + line3[xx * 4 + 12] + line3[xx * 4 + 16] + line4[xx * 4 + 0] + + line4[xx * 4 + 4] + line4[xx * 4 + 8] + line4[xx * 4 + 12] + + line4[xx * 4 + 16]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] + + line0[xx * 4 + 13] + line0[xx * 4 + 17] + line1[xx * 4 + 1] + + line1[xx * 4 + 5] + line1[xx * 4 + 9] + line1[xx * 4 + 13] + + line1[xx * 4 + 17] + line2[xx * 4 + 1] + line2[xx * 4 + 5] + + line2[xx * 4 + 9] + line2[xx * 4 + 13] + line2[xx * 4 + 17] + + line3[xx * 4 + 1] + line3[xx * 4 + 5] + line3[xx * 4 + 9] + + line3[xx * 4 + 13] + line3[xx * 4 + 17] + line4[xx * 4 + 1] + + line4[xx * 4 + 5] + line4[xx * 4 + 9] + line4[xx * 4 + 13] + + line4[xx * 4 + 17]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] + + line0[xx * 4 + 14] + line0[xx * 4 + 18] + line1[xx * 4 + 2] + + line1[xx * 4 + 6] + line1[xx * 4 + 10] + line1[xx * 4 + 14] + + line1[xx * 4 + 18] + line2[xx * 4 + 2] + line2[xx * 4 + 6] + + line2[xx * 4 + 10] + line2[xx * 4 + 14] + line2[xx * 4 + 18] + + line3[xx * 4 + 2] + line3[xx * 4 + 6] + line3[xx * 4 + 10] + + line3[xx * 4 + 14] + line3[xx * 4 + 18] + line4[xx * 4 + 2] + + line4[xx * 4 + 6] + line4[xx * 4 + 10] + line4[xx * 4 + 14] + + line4[xx * 4 + 18]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, ((ss1 + amend) * multiplier) >> 24, - ((ss2 + amend) * multiplier) >> 24, 0); + ((ss0 + amend) * multiplier) >> 24, + ((ss1 + amend) * multiplier) >> 24, + ((ss2 + amend) * multiplier) >> 24, + 0); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 for (x = 0; x < box[2] / xscale; x++) { - int xx = box[0] + x*xscale; + int xx = box[0] + x * xscale; UINT32 v; - ss0 = line0[xx*4 + 0] + line0[xx*4 + 4] + line0[xx*4 + 8] + line0[xx*4 + 12] + line0[xx*4 + 16] + - line1[xx*4 + 0] + line1[xx*4 + 4] + line1[xx*4 + 8] + line1[xx*4 + 12] + line1[xx*4 + 16] + - line2[xx*4 + 0] + line2[xx*4 + 4] + line2[xx*4 + 8] + line2[xx*4 + 12] + line2[xx*4 + 16] + - line3[xx*4 + 0] + line3[xx*4 + 4] + line3[xx*4 + 8] + line3[xx*4 + 12] + line3[xx*4 + 16] + - line4[xx*4 + 0] + line4[xx*4 + 4] + line4[xx*4 + 8] + line4[xx*4 + 12] + line4[xx*4 + 16]; - ss1 = line0[xx*4 + 1] + line0[xx*4 + 5] + line0[xx*4 + 9] + line0[xx*4 + 13] + line0[xx*4 + 17] + - line1[xx*4 + 1] + line1[xx*4 + 5] + line1[xx*4 + 9] + line1[xx*4 + 13] + line1[xx*4 + 17] + - line2[xx*4 + 1] + line2[xx*4 + 5] + line2[xx*4 + 9] + line2[xx*4 + 13] + line2[xx*4 + 17] + - line3[xx*4 + 1] + line3[xx*4 + 5] + line3[xx*4 + 9] + line3[xx*4 + 13] + line3[xx*4 + 17] + - line4[xx*4 + 1] + line4[xx*4 + 5] + line4[xx*4 + 9] + line4[xx*4 + 13] + line4[xx*4 + 17]; - ss2 = line0[xx*4 + 2] + line0[xx*4 + 6] + line0[xx*4 + 10] + line0[xx*4 + 14] + line0[xx*4 + 18] + - line1[xx*4 + 2] + line1[xx*4 + 6] + line1[xx*4 + 10] + line1[xx*4 + 14] + line1[xx*4 + 18] + - line2[xx*4 + 2] + line2[xx*4 + 6] + line2[xx*4 + 10] + line2[xx*4 + 14] + line2[xx*4 + 18] + - line3[xx*4 + 2] + line3[xx*4 + 6] + line3[xx*4 + 10] + line3[xx*4 + 14] + line3[xx*4 + 18] + - line4[xx*4 + 2] + line4[xx*4 + 6] + line4[xx*4 + 10] + line4[xx*4 + 14] + line4[xx*4 + 18]; - ss3 = line0[xx*4 + 3] + line0[xx*4 + 7] + line0[xx*4 + 11] + line0[xx*4 + 15] + line0[xx*4 + 19] + - line1[xx*4 + 3] + line1[xx*4 + 7] + line1[xx*4 + 11] + line1[xx*4 + 15] + line1[xx*4 + 19] + - line2[xx*4 + 3] + line2[xx*4 + 7] + line2[xx*4 + 11] + line2[xx*4 + 15] + line2[xx*4 + 19] + - line3[xx*4 + 3] + line3[xx*4 + 7] + line3[xx*4 + 11] + line3[xx*4 + 15] + line3[xx*4 + 19] + - line4[xx*4 + 3] + line4[xx*4 + 7] + line4[xx*4 + 11] + line4[xx*4 + 15] + line4[xx*4 + 19]; + ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] + + line0[xx * 4 + 12] + line0[xx * 4 + 16] + line1[xx * 4 + 0] + + line1[xx * 4 + 4] + line1[xx * 4 + 8] + line1[xx * 4 + 12] + + line1[xx * 4 + 16] + line2[xx * 4 + 0] + line2[xx * 4 + 4] + + line2[xx * 4 + 8] + line2[xx * 4 + 12] + line2[xx * 4 + 16] + + line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] + + line3[xx * 4 + 12] + line3[xx * 4 + 16] + line4[xx * 4 + 0] + + line4[xx * 4 + 4] + line4[xx * 4 + 8] + line4[xx * 4 + 12] + + line4[xx * 4 + 16]; + ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] + + line0[xx * 4 + 13] + line0[xx * 4 + 17] + line1[xx * 4 + 1] + + line1[xx * 4 + 5] + line1[xx * 4 + 9] + line1[xx * 4 + 13] + + line1[xx * 4 + 17] + line2[xx * 4 + 1] + line2[xx * 4 + 5] + + line2[xx * 4 + 9] + line2[xx * 4 + 13] + line2[xx * 4 + 17] + + line3[xx * 4 + 1] + line3[xx * 4 + 5] + line3[xx * 4 + 9] + + line3[xx * 4 + 13] + line3[xx * 4 + 17] + line4[xx * 4 + 1] + + line4[xx * 4 + 5] + line4[xx * 4 + 9] + line4[xx * 4 + 13] + + line4[xx * 4 + 17]; + ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] + + line0[xx * 4 + 14] + line0[xx * 4 + 18] + line1[xx * 4 + 2] + + line1[xx * 4 + 6] + line1[xx * 4 + 10] + line1[xx * 4 + 14] + + line1[xx * 4 + 18] + line2[xx * 4 + 2] + line2[xx * 4 + 6] + + line2[xx * 4 + 10] + line2[xx * 4 + 14] + line2[xx * 4 + 18] + + line3[xx * 4 + 2] + line3[xx * 4 + 6] + line3[xx * 4 + 10] + + line3[xx * 4 + 14] + line3[xx * 4 + 18] + line4[xx * 4 + 2] + + line4[xx * 4 + 6] + line4[xx * 4 + 10] + line4[xx * 4 + 14] + + line4[xx * 4 + 18]; + ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] + + line0[xx * 4 + 15] + line0[xx * 4 + 19] + line1[xx * 4 + 3] + + line1[xx * 4 + 7] + line1[xx * 4 + 11] + line1[xx * 4 + 15] + + line1[xx * 4 + 19] + line2[xx * 4 + 3] + line2[xx * 4 + 7] + + line2[xx * 4 + 11] + line2[xx * 4 + 15] + line2[xx * 4 + 19] + + line3[xx * 4 + 3] + line3[xx * 4 + 7] + line3[xx * 4 + 11] + + line3[xx * 4 + 15] + line3[xx * 4 + 19] + line4[xx * 4 + 3] + + line4[xx * 4 + 7] + line4[xx * 4 + 11] + line4[xx * 4 + 15] + + line4[xx * 4 + 19]; v = MAKE_UINT32( - ((ss0 + amend) * multiplier) >> 24, ((ss1 + amend) * multiplier) >> 24, - ((ss2 + amend) * multiplier) >> 24, ((ss3 + amend) * multiplier) >> 24); + ((ss0 + amend) * multiplier) >> 24, + ((ss1 + amend) * multiplier) >> 24, + ((ss2 + amend) * multiplier) >> 24, + ((ss3 + amend) * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -1056,12 +1100,10 @@ ImagingReduce5x5(Imaging imOut, Imaging imIn, int box[4]) } } - void -ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) -{ +ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) { /* Fill the last row and the last column for any xscale and yscale. - */ + */ int x, y, xx, yy; if (imIn->image8) { @@ -1070,13 +1112,13 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int ys UINT32 multiplier = division_UINT32(scale, 8); UINT32 amend = scale / 2; for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; + int yy_from = box[1] + y * yscale; UINT32 ss = amend; x = box[2] / xscale; for (yy = yy_from; yy < yy_from + yscale; yy++) { UINT8 *line = (UINT8 *)imIn->image8[yy]; - for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { + for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } @@ -1089,9 +1131,9 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int ys UINT32 amend = scale / 2; y = box[3] / yscale; for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 ss = amend; - for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { + for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) { UINT8 *line = (UINT8 *)imIn->image8[yy]; for (xx = xx_from; xx < xx_from + xscale; xx++) { ss += line[xx + 0]; @@ -1107,9 +1149,9 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int ys UINT32 ss = amend; x = box[2] / xscale; y = box[3] / yscale; - for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { + for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) { UINT8 *line = (UINT8 *)imIn->image8[yy]; - for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { + for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } @@ -1121,23 +1163,25 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int ys UINT32 multiplier = division_UINT32(scale, 8); UINT32 amend = scale / 2; for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; + int yy_from = box[1] + y * yscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; x = box[2] / xscale; for (yy = yy_from; yy < yy_from + yscale; yy++) { UINT8 *line = (UINT8 *)imIn->image[yy]; - for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; - ss3 += line[xx*4 + 3]; + for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) { + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; + ss3 += line[xx * 4 + 3]; } } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -1147,21 +1191,23 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int ys UINT32 amend = scale / 2; y = box[3] / yscale; for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; + int xx_from = box[0] + x * xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; - for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { + for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) { UINT8 *line = (UINT8 *)imIn->image[yy]; for (xx = xx_from; xx < xx_from + xscale; xx++) { - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; - ss3 += line[xx*4 + 3]; + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; + ss3 += line[xx * 4 + 3]; } } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } @@ -1173,265 +1219,262 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int ys UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; x = box[2] / xscale; y = box[3] / yscale; - for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { + for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) { UINT8 *line = (UINT8 *)imIn->image[yy]; - for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { - ss0 += line[xx*4 + 0]; - ss1 += line[xx*4 + 1]; - ss2 += line[xx*4 + 2]; - ss3 += line[xx*4 + 3]; + for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) { + ss0 += line[xx * 4 + 0]; + ss1 += line[xx * 4 + 1]; + ss2 += line[xx * 4 + 2]; + ss3 += line[xx * 4 + 3]; } } v = MAKE_UINT32( - (ss0 * multiplier) >> 24, (ss1 * multiplier) >> 24, - (ss2 * multiplier) >> 24, (ss3 * multiplier) >> 24); + (ss0 * multiplier) >> 24, + (ss1 * multiplier) >> 24, + (ss2 * multiplier) >> 24, + (ss3 * multiplier) >> 24); memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } } - void -ImagingReduceNxN_32bpc(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) -{ +ImagingReduceNxN_32bpc( + Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) { /* The most general implementation for any xscale and yscale - */ + */ int x, y, xx, yy; double multiplier = 1.0 / (yscale * xscale); - switch(imIn->type) { - case IMAGING_TYPE_INT32: - for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; - for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; - double ss = 0; - for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { - INT32 *line0 = (INT32 *)imIn->image32[yy]; - INT32 *line1 = (INT32 *)imIn->image32[yy + 1]; - for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss += line0[xx + 0] + line0[xx + 1] + - line1[xx + 0] + line1[xx + 1]; + switch (imIn->type) { + case IMAGING_TYPE_INT32: + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y * yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x * xscale; + double ss = 0; + for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { + INT32 *line0 = (INT32 *)imIn->image32[yy]; + INT32 *line1 = (INT32 *)imIn->image32[yy + 1]; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { + ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] + + line1[xx + 1]; + } + if (xscale & 0x01) { + ss += line0[xx + 0] + line1[xx + 0]; + } } - if (xscale & 0x01) { - ss += line0[xx + 0] + line1[xx + 0]; + if (yscale & 0x01) { + INT32 *line = (INT32 *)imIn->image32[yy]; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { + ss += line[xx + 0] + line[xx + 1]; + } + if (xscale & 0x01) { + ss += line[xx + 0]; + } } + IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); } - if (yscale & 0x01) { - INT32 *line = (INT32 *)imIn->image32[yy]; - for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss += line[xx + 0] + line[xx + 1]; - } - if (xscale & 0x01) { - ss += line[xx + 0]; - } - } - IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); } - } - break; + break; - case IMAGING_TYPE_FLOAT32: - for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; - for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; - double ss = 0; - for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { - FLOAT32 *line0 = (FLOAT32 *)imIn->image32[yy]; - FLOAT32 *line1 = (FLOAT32 *)imIn->image32[yy + 1]; - for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss += line0[xx + 0] + line0[xx + 1] + - line1[xx + 0] + line1[xx + 1]; + case IMAGING_TYPE_FLOAT32: + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y * yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x * xscale; + double ss = 0; + for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { + FLOAT32 *line0 = (FLOAT32 *)imIn->image32[yy]; + FLOAT32 *line1 = (FLOAT32 *)imIn->image32[yy + 1]; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { + ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] + + line1[xx + 1]; + } + if (xscale & 0x01) { + ss += line0[xx + 0] + line1[xx + 0]; + } } - if (xscale & 0x01) { - ss += line0[xx + 0] + line1[xx + 0]; + if (yscale & 0x01) { + FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { + ss += line[xx + 0] + line[xx + 1]; + } + if (xscale & 0x01) { + ss += line[xx + 0]; + } } + IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; } - if (yscale & 0x01) { - FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; - for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { - ss += line[xx + 0] + line[xx + 1]; - } - if (xscale & 0x01) { - ss += line[xx + 0]; - } - } - IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; } - } - break; + break; } } - void -ImagingReduceCorners_32bpc(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) -{ +ImagingReduceCorners_32bpc( + Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) { /* Fill the last row and the last column for any xscale and yscale. - */ + */ int x, y, xx, yy; - switch(imIn->type) { - case IMAGING_TYPE_INT32: - if (box[2] % xscale) { - double multiplier = 1.0 / ((box[2] % xscale) * yscale); - for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; + switch (imIn->type) { + case IMAGING_TYPE_INT32: + if (box[2] % xscale) { + double multiplier = 1.0 / ((box[2] % xscale) * yscale); + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y * yscale; + double ss = 0; + x = box[2] / xscale; + for (yy = yy_from; yy < yy_from + yscale; yy++) { + INT32 *line = (INT32 *)imIn->image32[yy]; + for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) { + ss += line[xx + 0]; + } + } + IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); + } + } + if (box[3] % yscale) { + double multiplier = 1.0 / (xscale * (box[3] % yscale)); + y = box[3] / yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x * xscale; + double ss = 0; + for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) { + INT32 *line = (INT32 *)imIn->image32[yy]; + for (xx = xx_from; xx < xx_from + xscale; xx++) { + ss += line[xx + 0]; + } + } + IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); + } + } + if (box[2] % xscale && box[3] % yscale) { + double multiplier = 1.0 / ((box[2] % xscale) * (box[3] % yscale)); double ss = 0; x = box[2] / xscale; - for (yy = yy_from; yy < yy_from + yscale; yy++) { + y = box[3] / yscale; + for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) { INT32 *line = (INT32 *)imIn->image32[yy]; - for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { + for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); } - } - if (box[3] % yscale) { - double multiplier = 1.0 / (xscale * (box[3] % yscale)); - y = box[3] / yscale; - for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; - double ss = 0; - for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { - INT32 *line = (INT32 *)imIn->image32[yy]; - for (xx = xx_from; xx < xx_from + xscale; xx++) { - ss += line[xx + 0]; - } - } - IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); - } - } - if (box[2] % xscale && box[3] % yscale) { - double multiplier = 1.0 / ((box[2] % xscale) * (box[3] % yscale)); - double ss = 0; - x = box[2] / xscale; - y = box[3] / yscale; - for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { - INT32 *line = (INT32 *)imIn->image32[yy]; - for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { - ss += line[xx + 0]; - } - } - IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); - } - break; + break; - case IMAGING_TYPE_FLOAT32: - if (box[2] % xscale) { - double multiplier = 1.0 / ((box[2] % xscale) * yscale); - for (y = 0; y < box[3] / yscale; y++) { - int yy_from = box[1] + y*yscale; + case IMAGING_TYPE_FLOAT32: + if (box[2] % xscale) { + double multiplier = 1.0 / ((box[2] % xscale) * yscale); + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y * yscale; + double ss = 0; + x = box[2] / xscale; + for (yy = yy_from; yy < yy_from + yscale; yy++) { + FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; + for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) { + ss += line[xx + 0]; + } + } + IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; + } + } + if (box[3] % yscale) { + double multiplier = 1.0 / (xscale * (box[3] % yscale)); + y = box[3] / yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x * xscale; + double ss = 0; + for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) { + FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; + for (xx = xx_from; xx < xx_from + xscale; xx++) { + ss += line[xx + 0]; + } + } + IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; + } + } + if (box[2] % xscale && box[3] % yscale) { + double multiplier = 1.0 / ((box[2] % xscale) * (box[3] % yscale)); double ss = 0; x = box[2] / xscale; - for (yy = yy_from; yy < yy_from + yscale; yy++) { + y = box[3] / yscale; + for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) { FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; - for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { + for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; } - } - if (box[3] % yscale) { - double multiplier = 1.0 / (xscale * (box[3] % yscale)); - y = box[3] / yscale; - for (x = 0; x < box[2] / xscale; x++) { - int xx_from = box[0] + x*xscale; - double ss = 0; - for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { - FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; - for (xx = xx_from; xx < xx_from + xscale; xx++) { - ss += line[xx + 0]; - } - } - IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; - } - } - if (box[2] % xscale && box[3] % yscale) { - double multiplier = 1.0 / ((box[2] % xscale) * (box[3] % yscale)); - double ss = 0; - x = box[2] / xscale; - y = box[3] / yscale; - for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { - FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; - for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { - ss += line[xx + 0]; - } - } - IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; - } - break; + break; } } - Imaging -ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]) -{ +ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]) { ImagingSectionCookie cookie; Imaging imOut = NULL; if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->type == IMAGING_TYPE_SPECIAL) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } - imOut = ImagingNewDirty(imIn->mode, - (box[2] + xscale - 1) / xscale, - (box[3] + yscale - 1) / yscale); - if ( ! imOut) { + imOut = ImagingNewDirty( + imIn->mode, (box[2] + xscale - 1) / xscale, (box[3] + yscale - 1) / yscale); + if (!imOut) { return NULL; } ImagingSectionEnter(&cookie); - switch(imIn->type) { - case IMAGING_TYPE_UINT8: - if (xscale == 1) { - if (yscale == 2) { - ImagingReduce1x2(imOut, imIn, box); - } else if (yscale == 3) { - ImagingReduce1x3(imOut, imIn, box); + switch (imIn->type) { + case IMAGING_TYPE_UINT8: + if (xscale == 1) { + if (yscale == 2) { + ImagingReduce1x2(imOut, imIn, box); + } else if (yscale == 3) { + ImagingReduce1x3(imOut, imIn, box); + } else { + ImagingReduce1xN(imOut, imIn, box, yscale); + } + } else if (yscale == 1) { + if (xscale == 2) { + ImagingReduce2x1(imOut, imIn, box); + } else if (xscale == 3) { + ImagingReduce3x1(imOut, imIn, box); + } else { + ImagingReduceNx1(imOut, imIn, box, xscale); + } + } else if (xscale == yscale && xscale <= 5) { + if (xscale == 2) { + ImagingReduce2x2(imOut, imIn, box); + } else if (xscale == 3) { + ImagingReduce3x3(imOut, imIn, box); + } else if (xscale == 4) { + ImagingReduce4x4(imOut, imIn, box); + } else { + ImagingReduce5x5(imOut, imIn, box); + } } else { - ImagingReduce1xN(imOut, imIn, box, yscale); + ImagingReduceNxN(imOut, imIn, box, xscale, yscale); } - } else if (yscale == 1) { - if (xscale == 2) { - ImagingReduce2x1(imOut, imIn, box); - } else if (xscale == 3) { - ImagingReduce3x1(imOut, imIn, box); - } else { - ImagingReduceNx1(imOut, imIn, box, xscale); - } - } else if (xscale == yscale && xscale <= 5) { - if (xscale == 2) { - ImagingReduce2x2(imOut, imIn, box); - } else if (xscale == 3) { - ImagingReduce3x3(imOut, imIn, box); - } else if (xscale == 4) { - ImagingReduce4x4(imOut, imIn, box); - } else { - ImagingReduce5x5(imOut, imIn, box); - } - } else { - ImagingReduceNxN(imOut, imIn, box, xscale, yscale); - } - ImagingReduceCorners(imOut, imIn, box, xscale, yscale); - break; + ImagingReduceCorners(imOut, imIn, box, xscale, yscale); + break; - case IMAGING_TYPE_INT32: - case IMAGING_TYPE_FLOAT32: - ImagingReduceNxN_32bpc(imOut, imIn, box, xscale, yscale); + case IMAGING_TYPE_INT32: + case IMAGING_TYPE_FLOAT32: + ImagingReduceNxN_32bpc(imOut, imIn, box, xscale, yscale); - ImagingReduceCorners_32bpc(imOut, imIn, box, xscale, yscale); - break; + ImagingReduceCorners_32bpc(imOut, imIn, box, xscale, yscale); + break; } ImagingSectionLeave(&cookie); diff --git a/src/libImaging/Resample.c b/src/libImaging/Resample.c index b12e023f8..cf79d8a4e 100644 --- a/src/libImaging/Resample.c +++ b/src/libImaging/Resample.c @@ -2,36 +2,34 @@ #include - -#define ROUND_UP(f) ((int) ((f) >= 0.0 ? (f) + 0.5F : (f) - 0.5F)) - +#define ROUND_UP(f) ((int)((f) >= 0.0 ? (f) + 0.5F : (f)-0.5F)) struct filter { double (*filter)(double x); double support; }; -static inline double box_filter(double x) -{ +static inline double +box_filter(double x) { if (x > -0.5 && x <= 0.5) { return 1.0; } return 0.0; } -static inline double bilinear_filter(double x) -{ +static inline double +bilinear_filter(double x) { if (x < 0.0) { x = -x; } if (x < 1.0) { - return 1.0-x; + return 1.0 - x; } return 0.0; } -static inline double hamming_filter(double x) -{ +static inline double +hamming_filter(double x) { if (x < 0.0) { x = -x; } @@ -45,15 +43,16 @@ static inline double hamming_filter(double x) return sin(x) / x * (0.54f + 0.46f * cos(x)); } -static inline double bicubic_filter(double x) -{ - /* https://en.wikipedia.org/wiki/Bicubic_interpolation#Bicubic_convolution_algorithm */ +static inline double +bicubic_filter(double x) { + /* https://en.wikipedia.org/wiki/Bicubic_interpolation#Bicubic_convolution_algorithm + */ #define a -0.5 if (x < 0.0) { x = -x; } if (x < 1.0) { - return ((a + 2.0) * x - (a + 3.0)) * x*x + 1; + return ((a + 2.0) * x - (a + 3.0)) * x * x + 1; } if (x < 2.0) { return (((x - 5) * x + 8) * x - 4) * a; @@ -62,8 +61,8 @@ static inline double bicubic_filter(double x) #undef a } -static inline double sinc_filter(double x) -{ +static inline double +sinc_filter(double x) { if (x == 0.0) { return 1.0; } @@ -71,21 +70,20 @@ static inline double sinc_filter(double x) return sin(x) / x; } -static inline double lanczos_filter(double x) -{ +static inline double +lanczos_filter(double x) { /* truncated sinc */ if (-3.0 <= x && x < 3.0) { - return sinc_filter(x) * sinc_filter(x/3); + return sinc_filter(x) * sinc_filter(x / 3); } return 0.0; } -static struct filter BOX = { box_filter, 0.5 }; -static struct filter BILINEAR = { bilinear_filter, 1.0 }; -static struct filter HAMMING = { hamming_filter, 1.0 }; -static struct filter BICUBIC = { bicubic_filter, 2.0 }; -static struct filter LANCZOS = { lanczos_filter, 3.0 }; - +static struct filter BOX = {box_filter, 0.5}; +static struct filter BILINEAR = {bilinear_filter, 1.0}; +static struct filter HAMMING = {hamming_filter, 1.0}; +static struct filter BICUBIC = {bicubic_filter, 2.0}; +static struct filter LANCZOS = {lanczos_filter, 3.0}; /* 8 bits for result. Filter can have negative areas. In one cases the sum of the coefficients will be negative, @@ -93,102 +91,102 @@ static struct filter LANCZOS = { lanczos_filter, 3.0 }; two extra bits for overflow and int type. */ #define PRECISION_BITS (32 - 8 - 2) - /* Handles values form -640 to 639. */ UINT8 _clip8_lookups[1280] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, }; UINT8 *clip8_lookups = &_clip8_lookups[640]; -static inline UINT8 clip8(int in) -{ +static inline UINT8 +clip8(int in) { return clip8_lookups[in >> PRECISION_BITS]; } - int -precompute_coeffs(int inSize, float in0, float in1, int outSize, - struct filter *filterp, int **boundsp, double **kkp) { +precompute_coeffs( + int inSize, + float in0, + float in1, + int outSize, + struct filter *filterp, + int **boundsp, + double **kkp) { double support, scale, filterscale; double center, ww, ss; int xx, x, ksize, xmin, xmax; @@ -196,7 +194,7 @@ precompute_coeffs(int inSize, float in0, float in1, int outSize, double *kk, *k; /* prepare for horizontal stretch */ - filterscale = scale = (double) (in1 - in0) / outSize; + filterscale = scale = (double)(in1 - in0) / outSize; if (filterscale < 1.0) { filterscale = 1.0; } @@ -205,7 +203,7 @@ precompute_coeffs(int inSize, float in0, float in1, int outSize, support = filterp->support * filterscale; /* maximum number of coeffs */ - ksize = (int) ceil(support) * 2 + 1; + ksize = (int)ceil(support) * 2 + 1; // check for overflow if (outSize > INT_MAX / (ksize * (int)sizeof(double))) { @@ -216,14 +214,14 @@ precompute_coeffs(int inSize, float in0, float in1, int outSize, /* coefficient buffer */ /* malloc check ok, overflow checked above */ kk = malloc(outSize * ksize * sizeof(double)); - if ( ! kk) { + if (!kk) { ImagingError_MemoryError(); return 0; } /* malloc check ok, ksize*sizeof(double) > 2*sizeof(int) */ bounds = malloc(outSize * 2 * sizeof(int)); - if ( ! bounds) { + if (!bounds) { free(kk); ImagingError_MemoryError(); return 0; @@ -234,12 +232,12 @@ precompute_coeffs(int inSize, float in0, float in1, int outSize, ww = 0.0; ss = 1.0 / filterscale; // Round the value - xmin = (int) (center - support + 0.5); + xmin = (int)(center - support + 0.5); if (xmin < 0) { xmin = 0; } // Round the value - xmax = (int) (center + support + 0.5); + xmax = (int)(center + support + 0.5); if (xmax > inSize) { xmax = inSize; } @@ -267,38 +265,33 @@ precompute_coeffs(int inSize, float in0, float in1, int outSize, return ksize; } - void -normalize_coeffs_8bpc(int outSize, int ksize, double *prekk) -{ +normalize_coeffs_8bpc(int outSize, int ksize, double *prekk) { int x; INT32 *kk; // use the same buffer for normalized coefficients - kk = (INT32 *) prekk; + kk = (INT32 *)prekk; for (x = 0; x < outSize * ksize; x++) { if (prekk[x] < 0) { - kk[x] = (int) (-0.5 + prekk[x] * (1 << PRECISION_BITS)); + kk[x] = (int)(-0.5 + prekk[x] * (1 << PRECISION_BITS)); } else { - kk[x] = (int) (0.5 + prekk[x] * (1 << PRECISION_BITS)); + kk[x] = (int)(0.5 + prekk[x] * (1 << PRECISION_BITS)); } } } - - void -ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset, - int ksize, int *bounds, double *prekk) -{ +ImagingResampleHorizontal_8bpc( + Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *prekk) { ImagingSectionCookie cookie; int ss0, ss1, ss2, ss3; int xx, yy, x, xmin, xmax; INT32 *k, *kk; // use the same buffer for normalized coefficients - kk = (INT32 *) prekk; + kk = (INT32 *)prekk; normalize_coeffs_8bpc(imOut->xsize, ksize, prekk); ImagingSectionEnter(&cookie); @@ -308,9 +301,9 @@ ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset, xmin = bounds[xx * 2 + 0]; xmax = bounds[xx * 2 + 1]; k = &kk[xx * ksize]; - ss0 = 1 << (PRECISION_BITS -1); + ss0 = 1 << (PRECISION_BITS - 1); for (x = 0; x < xmax; x++) { - ss0 += ((UINT8) imIn->image8[yy + offset][x + xmin]) * k[x]; + ss0 += ((UINT8)imIn->image8[yy + offset][x + xmin]) * k[x]; } imOut->image8[yy][xx] = clip8(ss0); } @@ -323,10 +316,12 @@ ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset, xmin = bounds[xx * 2 + 0]; xmax = bounds[xx * 2 + 1]; k = &kk[xx * ksize]; - ss0 = ss3 = 1 << (PRECISION_BITS -1); + ss0 = ss3 = 1 << (PRECISION_BITS - 1); for (x = 0; x < xmax; x++) { - ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x]; - ss3 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 3]) * k[x]; + ss0 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 0]) * + k[x]; + ss3 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 3]) * + k[x]; } v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3)); memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v)); @@ -339,11 +334,14 @@ ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset, xmin = bounds[xx * 2 + 0]; xmax = bounds[xx * 2 + 1]; k = &kk[xx * ksize]; - ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1); + ss0 = ss1 = ss2 = 1 << (PRECISION_BITS - 1); for (x = 0; x < xmax; x++) { - ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x]; - ss1 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 1]) * k[x]; - ss2 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 2]) * k[x]; + ss0 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 0]) * + k[x]; + ss1 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 1]) * + k[x]; + ss2 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 2]) * + k[x]; } v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0); memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v)); @@ -356,12 +354,16 @@ ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset, xmin = bounds[xx * 2 + 0]; xmax = bounds[xx * 2 + 1]; k = &kk[xx * ksize]; - ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1); + ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS - 1); for (x = 0; x < xmax; x++) { - ss0 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 0]) * k[x]; - ss1 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 1]) * k[x]; - ss2 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 2]) * k[x]; - ss3 += ((UINT8) imIn->image[yy + offset][(x + xmin)*4 + 3]) * k[x]; + ss0 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 0]) * + k[x]; + ss1 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 1]) * + k[x]; + ss2 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 2]) * + k[x]; + ss3 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 3]) * + k[x]; } v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3)); memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v)); @@ -372,18 +374,16 @@ ImagingResampleHorizontal_8bpc(Imaging imOut, Imaging imIn, int offset, ImagingSectionLeave(&cookie); } - void -ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset, - int ksize, int *bounds, double *prekk) -{ +ImagingResampleVertical_8bpc( + Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *prekk) { ImagingSectionCookie cookie; int ss0, ss1, ss2, ss3; int xx, yy, y, ymin, ymax; INT32 *k, *kk; // use the same buffer for normalized coefficients - kk = (INT32 *) prekk; + kk = (INT32 *)prekk; normalize_coeffs_8bpc(imOut->ysize, ksize, prekk); ImagingSectionEnter(&cookie); @@ -393,9 +393,9 @@ ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset, ymin = bounds[yy * 2 + 0]; ymax = bounds[yy * 2 + 1]; for (xx = 0; xx < imOut->xsize; xx++) { - ss0 = 1 << (PRECISION_BITS -1); + ss0 = 1 << (PRECISION_BITS - 1); for (y = 0; y < ymax; y++) { - ss0 += ((UINT8) imIn->image8[y + ymin][xx]) * k[y]; + ss0 += ((UINT8)imIn->image8[y + ymin][xx]) * k[y]; } imOut->image8[yy][xx] = clip8(ss0); } @@ -408,10 +408,10 @@ ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset, ymax = bounds[yy * 2 + 1]; for (xx = 0; xx < imOut->xsize; xx++) { UINT32 v; - ss0 = ss3 = 1 << (PRECISION_BITS -1); + ss0 = ss3 = 1 << (PRECISION_BITS - 1); for (y = 0; y < ymax; y++) { - ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y]; - ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y]; + ss0 += ((UINT8)imIn->image[y + ymin][xx * 4 + 0]) * k[y]; + ss3 += ((UINT8)imIn->image[y + ymin][xx * 4 + 3]) * k[y]; } v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3)); memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v)); @@ -424,11 +424,11 @@ ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset, ymax = bounds[yy * 2 + 1]; for (xx = 0; xx < imOut->xsize; xx++) { UINT32 v; - ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1); + ss0 = ss1 = ss2 = 1 << (PRECISION_BITS - 1); for (y = 0; y < ymax; y++) { - ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y]; - ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y]; - ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y]; + ss0 += ((UINT8)imIn->image[y + ymin][xx * 4 + 0]) * k[y]; + ss1 += ((UINT8)imIn->image[y + ymin][xx * 4 + 1]) * k[y]; + ss2 += ((UINT8)imIn->image[y + ymin][xx * 4 + 2]) * k[y]; } v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0); memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v)); @@ -441,12 +441,12 @@ ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset, ymax = bounds[yy * 2 + 1]; for (xx = 0; xx < imOut->xsize; xx++) { UINT32 v; - ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1); + ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS - 1); for (y = 0; y < ymax; y++) { - ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y]; - ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y]; - ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y]; - ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y]; + ss0 += ((UINT8)imIn->image[y + ymin][xx * 4 + 0]) * k[y]; + ss1 += ((UINT8)imIn->image[y + ymin][xx * 4 + 1]) * k[y]; + ss2 += ((UINT8)imIn->image[y + ymin][xx * 4 + 2]) * k[y]; + ss3 += ((UINT8)imIn->image[y + ymin][xx * 4 + 3]) * k[y]; } v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3)); memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v)); @@ -457,18 +457,16 @@ ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset, ImagingSectionLeave(&cookie); } - void -ImagingResampleHorizontal_32bpc(Imaging imOut, Imaging imIn, int offset, - int ksize, int *bounds, double *kk) -{ +ImagingResampleHorizontal_32bpc( + Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *kk) { ImagingSectionCookie cookie; double ss; int xx, yy, x, xmin, xmax; double *k; ImagingSectionEnter(&cookie); - switch(imIn->type) { + switch (imIn->type) { case IMAGING_TYPE_INT32: for (yy = 0; yy < imOut->ysize; yy++) { for (xx = 0; xx < imOut->xsize; xx++) { @@ -502,18 +500,16 @@ ImagingResampleHorizontal_32bpc(Imaging imOut, Imaging imIn, int offset, ImagingSectionLeave(&cookie); } - void -ImagingResampleVertical_32bpc(Imaging imOut, Imaging imIn, int offset, - int ksize, int *bounds, double *kk) -{ +ImagingResampleVertical_32bpc( + Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *kk) { ImagingSectionCookie cookie; double ss; int xx, yy, y, ymin, ymax; double *k; ImagingSectionEnter(&cookie); - switch(imIn->type) { + switch (imIn->type) { case IMAGING_TYPE_INT32: for (yy = 0; yy < imOut->ysize; yy++) { ymin = bounds[yy * 2 + 0]; @@ -547,36 +543,36 @@ ImagingResampleVertical_32bpc(Imaging imOut, Imaging imIn, int offset, ImagingSectionLeave(&cookie); } - -typedef void (*ResampleFunction)(Imaging imOut, Imaging imIn, int offset, - int ksize, int *bounds, double *kk); - +typedef void (*ResampleFunction)( + Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *kk); Imaging -ImagingResampleInner(Imaging imIn, int xsize, int ysize, - struct filter *filterp, float box[4], - ResampleFunction ResampleHorizontal, - ResampleFunction ResampleVertical); - +ImagingResampleInner( + Imaging imIn, + int xsize, + int ysize, + struct filter *filterp, + float box[4], + ResampleFunction ResampleHorizontal, + ResampleFunction ResampleVertical); Imaging -ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]) -{ +ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]) { struct filter *filterp; ResampleFunction ResampleHorizontal; ResampleFunction ResampleVertical; if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } if (imIn->type == IMAGING_TYPE_SPECIAL) { - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } else if (imIn->image8) { ResampleHorizontal = ImagingResampleHorizontal_8bpc; ResampleVertical = ImagingResampleVertical_8bpc; } else { - switch(imIn->type) { + switch (imIn->type) { case IMAGING_TYPE_UINT8: ResampleHorizontal = ImagingResampleHorizontal_8bpc; ResampleVertical = ImagingResampleVertical_8bpc; @@ -587,44 +583,44 @@ ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]) ResampleVertical = ImagingResampleVertical_32bpc; break; default: - return (Imaging) ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(); } } /* check filter */ switch (filter) { - case IMAGING_TRANSFORM_BOX: - filterp = &BOX; - break; - case IMAGING_TRANSFORM_BILINEAR: - filterp = &BILINEAR; - break; - case IMAGING_TRANSFORM_HAMMING: - filterp = &HAMMING; - break; - case IMAGING_TRANSFORM_BICUBIC: - filterp = &BICUBIC; - break; - case IMAGING_TRANSFORM_LANCZOS: - filterp = &LANCZOS; - break; - default: - return (Imaging) ImagingError_ValueError( - "unsupported resampling filter" - ); + case IMAGING_TRANSFORM_BOX: + filterp = &BOX; + break; + case IMAGING_TRANSFORM_BILINEAR: + filterp = &BILINEAR; + break; + case IMAGING_TRANSFORM_HAMMING: + filterp = &HAMMING; + break; + case IMAGING_TRANSFORM_BICUBIC: + filterp = &BICUBIC; + break; + case IMAGING_TRANSFORM_LANCZOS: + filterp = &LANCZOS; + break; + default: + return (Imaging)ImagingError_ValueError("unsupported resampling filter"); } - return ImagingResampleInner(imIn, xsize, ysize, filterp, box, - ResampleHorizontal, ResampleVertical); + return ImagingResampleInner( + imIn, xsize, ysize, filterp, box, ResampleHorizontal, ResampleVertical); } - Imaging -ImagingResampleInner(Imaging imIn, int xsize, int ysize, - struct filter *filterp, float box[4], - ResampleFunction ResampleHorizontal, - ResampleFunction ResampleVertical) -{ +ImagingResampleInner( + Imaging imIn, + int xsize, + int ysize, + struct filter *filterp, + float box[4], + ResampleFunction ResampleHorizontal, + ResampleFunction ResampleVertical) { Imaging imTemp = NULL; Imaging imOut = NULL; @@ -637,15 +633,15 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, need_horizontal = xsize != imIn->xsize || box[0] || box[2] != xsize; need_vertical = ysize != imIn->ysize || box[1] || box[3] != ysize; - ksize_horiz = precompute_coeffs(imIn->xsize, box[0], box[2], xsize, - filterp, &bounds_horiz, &kk_horiz); - if ( ! ksize_horiz) { + ksize_horiz = precompute_coeffs( + imIn->xsize, box[0], box[2], xsize, filterp, &bounds_horiz, &kk_horiz); + if (!ksize_horiz) { return NULL; } - ksize_vert = precompute_coeffs(imIn->ysize, box[1], box[3], ysize, - filterp, &bounds_vert, &kk_vert); - if ( ! ksize_vert) { + ksize_vert = precompute_coeffs( + imIn->ysize, box[1], box[3], ysize, filterp, &bounds_vert, &kk_vert); + if (!ksize_vert) { free(bounds_horiz); free(kk_horiz); return NULL; @@ -654,8 +650,7 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, // First used row in the source image ybox_first = bounds_vert[0]; // Last used row in the source image - ybox_last = bounds_vert[ysize*2 - 2] + bounds_vert[ysize*2 - 1]; - + ybox_last = bounds_vert[ysize * 2 - 2] + bounds_vert[ysize * 2 - 1]; /* two-pass resize, horizontal pass */ if (need_horizontal) { @@ -666,12 +661,12 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, imTemp = ImagingNewDirty(imIn->mode, xsize, ybox_last - ybox_first); if (imTemp) { - ResampleHorizontal(imTemp, imIn, ybox_first, - ksize_horiz, bounds_horiz, kk_horiz); + ResampleHorizontal( + imTemp, imIn, ybox_first, ksize_horiz, bounds_horiz, kk_horiz); } free(bounds_horiz); free(kk_horiz); - if ( ! imTemp) { + if (!imTemp) { free(bounds_vert); free(kk_vert); return NULL; @@ -688,15 +683,14 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize); if (imOut) { /* imIn can be the original image or horizontally resampled one */ - ResampleVertical(imOut, imIn, 0, - ksize_vert, bounds_vert, kk_vert); + ResampleVertical(imOut, imIn, 0, ksize_vert, bounds_vert, kk_vert); } /* it's safe to call ImagingDelete with empty value if previous step was not performed. */ ImagingDelete(imTemp); free(bounds_vert); free(kk_vert); - if ( ! imOut) { + if (!imOut) { return NULL; } } else { @@ -706,7 +700,7 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, } /* none of the previous steps are performed, copying */ - if ( ! imOut) { + if (!imOut) { imOut = ImagingCopy(imIn); } diff --git a/src/libImaging/Sgi.h b/src/libImaging/Sgi.h index 8015d6661..39dd68825 100644 --- a/src/libImaging/Sgi.h +++ b/src/libImaging/Sgi.h @@ -1,7 +1,6 @@ /* Sgi.h */ typedef struct { - /* CONFIGURATION */ /* Number of bytes per channel per pixel */ diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c index a03ecd456..4eef44ba5 100644 --- a/src/libImaging/SgiRleDecode.c +++ b/src/libImaging/SgiRleDecode.c @@ -20,18 +20,63 @@ #define RLE_COPY_FLAG 0x80 #define RLE_MAX_RUN 0x7f -static void read4B(UINT32* dest, UINT8* buf) -{ +static void +read4B(UINT32 *dest, UINT8 *buf) { *dest = (UINT32)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); } -static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize) -{ +/* + SgiRleDecoding is done in a single channel row oriented set of RLE chunks. + + * The file is arranged as + - SGI Header + - Rle Offset Table + - Rle Length Table + - Scanline Data + + * Each RLE atom is c->bpc bytes wide (1 or 2) + + * Each RLE Chunk is [specifier atom] [ 1 or n data atoms ] + + * Copy Atoms are a byte with the high bit set, and the low 7 are + the number of bytes to copy from the source to the + destination. e.g. + + CBBBBBBBB or 0CHLHLHLHLHLHL (B=byte, H/L = Hi low bytes) + + * Run atoms do not have the high bit set, and the low 7 bits are + the number of copies of the next atom to copy to the + destination. e.g.: + + RB -> BBBBB or RHL -> HLHLHLHLHL + + The upshot of this is, there is no way to determine the required + length of the input buffer from reloffset and rlelength without + going through the data at that scan line. + + Furthermore, there's no requirement that individual scan lines + pointed to from the rleoffset table are in any sort of order or + used only once, or even disjoint. There's also no requirement that + all of the data in the scan line area of the image file be used + + */ +static int +expandrow(UINT8 *dest, UINT8 *src, int n, int z, int xsize, UINT8 *end_of_buffer) { + /* + * n here is the number of rlechunks + * z is the number of channels, for calculating the interleave + * offset to go to RGBA style pixels + * xsize is the row width + * end_of_buffer is the address of the end of the input buffer + */ + UINT8 pixel, count; int x = 0; - for (;n > 0; n--) - { + for (; n > 0; n--) { + if (src > end_of_buffer) { + return -1; + } pixel = *src++; if (n == 1 && pixel != 0) { return n; @@ -45,34 +90,39 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize) } x += count; if (pixel & RLE_COPY_FLAG) { - while(count--) { + if (src + count > end_of_buffer) { + return -1; + } + while (count--) { *dest = *src++; dest += z; } - } - else { + } else { + if (src > end_of_buffer) { + return -1; + } pixel = *src++; while (count--) { *dest = pixel; dest += z; } } - } return 0; } -static int expandrow2(UINT8* dest, const UINT8* src, int n, int z, int xsize) -{ +static int +expandrow2(UINT8 *dest, const UINT8 *src, int n, int z, int xsize, UINT8 *end_of_buffer) { UINT8 pixel, count; - int x = 0; - for (;n > 0; n--) - { + for (; n > 0; n--) { + if (src + 1 > end_of_buffer) { + return -1; + } pixel = src[1]; - src+=2; + src += 2; if (n == 1 && pixel != 0) { return n; } @@ -85,44 +135,67 @@ static int expandrow2(UINT8* dest, const UINT8* src, int n, int z, int xsize) } x += count; if (pixel & RLE_COPY_FLAG) { - while(count--) { + if (src + 2 * count > end_of_buffer) { + return -1; + } + while (count--) { memcpy(dest, src, 2); src += 2; dest += z * 2; } - } - else { + } else { + if (src + 2 > end_of_buffer) { + return -1; + } while (count--) { memcpy(dest, src, 2); dest += z * 2; } - src+=2; + src += 2; } } return 0; } - int -ImagingSgiRleDecode(Imaging im, ImagingCodecState state, - UINT8* buf, Py_ssize_t bytes) -{ +ImagingSgiRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { UINT8 *ptr; SGISTATE *c; int err = 0; int status; + /* size check */ + if (im->xsize > INT_MAX / im->bands || im->ysize > INT_MAX / im->bands) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + /* Get all data from File descriptor */ - c = (SGISTATE*)state->context; + c = (SGISTATE *)state->context; _imaging_seek_pyFd(state->fd, 0L, SEEK_END); c->bufsize = _imaging_tell_pyFd(state->fd); c->bufsize -= SGI_HEADER_SIZE; + + c->tablen = im->bands * im->ysize; + /* below, we populate the starttab and lentab into the bufsize, + each with 4 bytes per element of tablen + Check here before we allocate any memory + */ + if (c->bufsize < 8 * c->tablen) { + state->errcode = IMAGING_CODEC_OVERRUN; + return -1; + } + ptr = malloc(sizeof(UINT8) * c->bufsize); if (!ptr) { - return IMAGING_CODEC_MEMORY; + state->errcode = IMAGING_CODEC_MEMORY; + return -1; } _imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET); - _imaging_read_pyFd(state->fd, (char*)ptr, c->bufsize); + if (_imaging_read_pyFd(state->fd, (char *)ptr, c->bufsize) != c->bufsize) { + state->errcode = IMAGING_CODEC_UNKNOWN; + return -1; + } /* decoder initialization */ @@ -134,82 +207,82 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, state->ystep = 1; } - if (im->xsize > INT_MAX / im->bands || - im->ysize > INT_MAX / im->bands) { - err = IMAGING_CODEC_MEMORY; - goto sgi_finish_decode; - } - /* Allocate memory for RLE tables and rows */ free(state->buffer); state->buffer = NULL; /* malloc overflow check above */ state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2); - c->tablen = im->bands * im->ysize; c->starttab = calloc(c->tablen, sizeof(UINT32)); c->lengthtab = calloc(c->tablen, sizeof(UINT32)); - if (!state->buffer || - !c->starttab || - !c->lengthtab) { + if (!state->buffer || !c->starttab || !c->lengthtab) { err = IMAGING_CODEC_MEMORY; goto sgi_finish_decode; } /* populate offsets table */ - for (c->tabindex = 0, c->bufindex = 0; c->tabindex < c->tablen; c->tabindex++, c->bufindex+=4) { + for (c->tabindex = 0, c->bufindex = 0; c->tabindex < c->tablen; + c->tabindex++, c->bufindex += 4) { read4B(&c->starttab[c->tabindex], &ptr[c->bufindex]); } /* populate lengths table */ - for (c->tabindex = 0, c->bufindex = c->tablen * sizeof(UINT32); c->tabindex < c->tablen; c->tabindex++, c->bufindex+=4) { + for (c->tabindex = 0, c->bufindex = c->tablen * sizeof(UINT32); + c->tabindex < c->tablen; + c->tabindex++, c->bufindex += 4) { read4B(&c->lengthtab[c->tabindex], &ptr[c->bufindex]); } - state->count += c->tablen * sizeof(UINT32) * 2; - /* read compressed rows */ - for (c->rowno = 0; c->rowno < im->ysize; c->rowno++, state->y += state->ystep) - { - for (c->channo = 0; c->channo < im->bands; c->channo++) - { + for (c->rowno = 0; c->rowno < im->ysize; c->rowno++, state->y += state->ystep) { + for (c->channo = 0; c->channo < im->bands; c->channo++) { c->rleoffset = c->starttab[c->rowno + c->channo * im->ysize]; c->rlelength = c->lengthtab[c->rowno + c->channo * im->ysize]; + + // Check for underflow of rleoffset-SGI_HEADER_SIZE + if (c->rleoffset < SGI_HEADER_SIZE) { + state->errcode = IMAGING_CODEC_OVERRUN; + goto sgi_finish_decode; + } + c->rleoffset -= SGI_HEADER_SIZE; - if (c->rleoffset + c->rlelength > c->bufsize) { - state->errcode = IMAGING_CODEC_OVERRUN; - return -1; - } - /* row decompression */ - if (c->bpc ==1) { - status = expandrow(&state->buffer[c->channo], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize); - } - else { - status = expandrow2(&state->buffer[c->channo * 2], &ptr[c->rleoffset], c->rlelength, im->bands, im->xsize); + if (c->bpc == 1) { + status = expandrow( + &state->buffer[c->channo], + &ptr[c->rleoffset], + c->rlelength, + im->bands, + im->xsize, + &ptr[c->bufsize-1]); + } else { + status = expandrow2( + &state->buffer[c->channo * 2], + &ptr[c->rleoffset], + c->rlelength, + im->bands, + im->xsize, + &ptr[c->bufsize-1]); } if (status == -1) { state->errcode = IMAGING_CODEC_OVERRUN; - return -1; + goto sgi_finish_decode; } else if (status == 1) { goto sgi_finish_decode; } - state->count += c->rlelength; } /* store decompressed data in image */ - state->shuffle((UINT8*)im->image[state->y], state->buffer, im->xsize); - + state->shuffle((UINT8 *)im->image[state->y], state->buffer, im->xsize); } - c->bufsize++; - -sgi_finish_decode: ; +sgi_finish_decode:; free(c->starttab); free(c->lengthtab); free(ptr); - if (err != 0){ - return err; + if (err != 0) { + state->errcode = err; + return -1; } - return state->count - c->bufsize; + return 0; } diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index c9a24e6aa..76750aaf7 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -34,11 +34,9 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" #include - int ImagingNewCount = 0; /* -------------------------------------------------------------------- @@ -46,18 +44,17 @@ int ImagingNewCount = 0; */ Imaging -ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) -{ +ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { Imaging im; /* linesize overflow check, roughly the current largest space req'd */ if (xsize > (INT_MAX / 4) - 1) { - return (Imaging) ImagingError_MemoryError(); + return (Imaging)ImagingError_MemoryError(); } - im = (Imaging) calloc(1, size); + im = (Imaging)calloc(1, size); if (!im) { - return (Imaging) ImagingError_MemoryError(); + return (Imaging)ImagingError_MemoryError(); } /* Setup image descriptor */ @@ -115,8 +112,9 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) im->linesize = xsize * 4; im->type = IMAGING_TYPE_INT32; - } else if (strcmp(mode, "I;16") == 0 || strcmp(mode, "I;16L") == 0 \ - || strcmp(mode, "I;16B") == 0 || strcmp(mode, "I;16N") == 0) { + } else if ( + strcmp(mode, "I;16") == 0 || strcmp(mode, "I;16L") == 0 || + strcmp(mode, "I;16B") == 0 || strcmp(mode, "I;16N") == 0) { /* EXPERIMENTAL */ /* 16-bit raw integer images */ im->bands = 1; @@ -135,7 +133,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) /* 15-bit reversed true colour */ im->bands = 1; im->pixelsize = 2; - im->linesize = (xsize*2 + 3) & -4; + im->linesize = (xsize * 2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "BGR;16") == 0) { @@ -143,7 +141,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) /* 16-bit reversed true colour */ im->bands = 1; im->pixelsize = 2; - im->linesize = (xsize*2 + 3) & -4; + im->linesize = (xsize * 2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "BGR;24") == 0) { @@ -151,7 +149,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) /* 24-bit reversed true colour */ im->bands = 1; im->pixelsize = 3; - im->linesize = (xsize*3 + 3) & -4; + im->linesize = (xsize * 3 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "BGR;32") == 0) { @@ -159,7 +157,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) /* 32-bit reversed true colour */ im->bands = 1; im->pixelsize = 4; - im->linesize = (xsize*4 + 3) & -4; + im->linesize = (xsize * 4 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "RGBX") == 0) { @@ -204,7 +202,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) } else { free(im); - return (Imaging) ImagingError_ValueError("unrecognized image mode"); + return (Imaging)ImagingError_ValueError("unrecognized image mode"); } /* Setup image descriptor */ @@ -212,21 +210,23 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) /* Pointer array (allocate at least one line, to avoid MemoryError exceptions on platforms where calloc(0, x) returns NULL) */ - im->image = (char **) calloc((ysize > 0) ? ysize : 1, sizeof(void *)); + im->image = (char **)calloc((ysize > 0) ? ysize : 1, sizeof(void *)); - if ( ! im->image) { + if (!im->image) { free(im); - return (Imaging) ImagingError_MemoryError(); + return (Imaging)ImagingError_MemoryError(); } /* Initialize alias pointers to pixel data. */ switch (im->pixelsize) { - case 1: case 2: case 3: - im->image8 = (UINT8 **) im->image; - break; - case 4: - im->image32 = (INT32 **) im->image; - break; + case 1: + case 2: + case 3: + im->image8 = (UINT8 **)im->image; + break; + case 4: + im->image32 = (INT32 **)im->image; + break; } ImagingDefaultArena.stats_new_count += 1; @@ -235,15 +235,13 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) } Imaging -ImagingNewPrologue(const char *mode, int xsize, int ysize) -{ +ImagingNewPrologue(const char *mode, int xsize, int ysize) { return ImagingNewPrologueSubtype( mode, xsize, ysize, sizeof(struct ImagingMemoryInstance)); } void -ImagingDelete(Imaging im) -{ +ImagingDelete(Imaging im) { if (!im) { return; } @@ -263,7 +261,6 @@ ImagingDelete(Imaging im) free(im); } - /* Array Storage Type */ /* ------------------ */ /* Allocate image as an array of line buffers. */ @@ -271,17 +268,20 @@ ImagingDelete(Imaging im) #define IMAGING_PAGE_SIZE (4096) struct ImagingMemoryArena ImagingDefaultArena = { - 1, // alignment - 16*1024*1024, // block_size - 0, // blocks_max - 0, // blocks_cached - NULL, // blocks_pool - 0, 0, 0, 0, 0 // Stats + 1, // alignment + 16 * 1024 * 1024, // block_size + 0, // blocks_max + 0, // blocks_cached + NULL, // blocks_pool + 0, + 0, + 0, + 0, + 0 // Stats }; int -ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max) -{ +ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max) { void *p; /* Free already cached blocks */ ImagingMemoryClearCache(arena, blocks_max); @@ -291,14 +291,14 @@ ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max) arena->blocks_pool = NULL; } else if (arena->blocks_pool != NULL) { p = realloc(arena->blocks_pool, sizeof(*arena->blocks_pool) * blocks_max); - if ( ! p) { + if (!p) { // Leave previous blocks_max value return 0; } arena->blocks_pool = p; } else { arena->blocks_pool = calloc(sizeof(*arena->blocks_pool), blocks_max); - if ( ! arena->blocks_pool) { + if (!arena->blocks_pool) { return 0; } } @@ -308,8 +308,7 @@ ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max) } void -ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size) -{ +ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size) { while (arena->blocks_cached > new_size) { arena->blocks_cached -= 1; free(arena->blocks_pool[arena->blocks_cached].ptr); @@ -318,8 +317,7 @@ ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size) } ImagingMemoryBlock -memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty) -{ +memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty) { ImagingMemoryBlock block = {NULL, 0}; if (arena->blocks_cached > 0) { @@ -327,16 +325,16 @@ memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty) arena->blocks_cached -= 1; block = arena->blocks_pool[arena->blocks_cached]; // Reallocate if needed - if (block.size != requested_size){ + if (block.size != requested_size) { block.ptr = realloc(block.ptr, requested_size); } - if ( ! block.ptr) { + if (!block.ptr) { // Can't allocate, free previous pointer (it is still valid) free(arena->blocks_pool[arena->blocks_cached].ptr); arena->stats_freed_blocks += 1; return block; } - if ( ! dirty) { + if (!dirty) { memset(block.ptr, 0, requested_size); } arena->stats_reused_blocks += 1; @@ -356,9 +354,8 @@ memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty) } void -memory_return_block(ImagingMemoryArena arena, ImagingMemoryBlock block) -{ - if (arena->blocks_cached < arena->blocks_max) { +memory_return_block(ImagingMemoryArena arena, ImagingMemoryBlock block) { + if (arena->blocks_cached < arena->blocks_max) { // Reduce block size if (block.size > arena->block_size) { block.size = arena->block_size; @@ -372,15 +369,13 @@ memory_return_block(ImagingMemoryArena arena, ImagingMemoryBlock block) } } - static void -ImagingDestroyArray(Imaging im) -{ +ImagingDestroyArray(Imaging im) { int y = 0; if (im->blocks) { while (im->blocks[y].ptr) { - memory_return_block(&ImagingDefaultArena, im->blocks[y]); + memory_return_block(&ImagingDefaultArena, im->blocks[y]); y += 1; } free(im->blocks); @@ -388,8 +383,7 @@ ImagingDestroyArray(Imaging im) } Imaging -ImagingAllocateArray(Imaging im, int dirty, int block_size) -{ +ImagingAllocateArray(Imaging im, int dirty, int block_size) { int y, line_in_block, current_block; ImagingMemoryArena arena = &ImagingDefaultArena; ImagingMemoryBlock block = {NULL, 0}; @@ -397,7 +391,7 @@ ImagingAllocateArray(Imaging im, int dirty, int block_size) char *aligned_ptr = NULL; /* 0-width or 0-height image. No need to do anything */ - if ( ! im->linesize || ! im->ysize) { + if (!im->linesize || !im->ysize) { return im; } @@ -412,8 +406,8 @@ ImagingAllocateArray(Imaging im, int dirty, int block_size) /* One extra pointer is always NULL */ im->blocks = calloc(sizeof(*im->blocks), blocks_count + 1); - if ( ! im->blocks) { - return (Imaging) ImagingError_MemoryError(); + if (!im->blocks) { + return (Imaging)ImagingError_MemoryError(); } /* Allocate image as an array of lines */ @@ -428,9 +422,9 @@ ImagingAllocateArray(Imaging im, int dirty, int block_size) } required = lines_remaining * aligned_linesize + arena->alignment - 1; block = memory_get_block(arena, required, dirty); - if ( ! block.ptr) { + if (!block.ptr) { ImagingDestroyArray(im); - return (Imaging) ImagingError_MemoryError(); + return (Imaging)ImagingError_MemoryError(); } im->blocks[current_block] = block; /* Bulletproof code from libc _int_memalign */ @@ -454,42 +448,38 @@ ImagingAllocateArray(Imaging im, int dirty, int block_size) return im; } - /* Block Storage Type */ /* ------------------ */ /* Allocate image as a single block. */ static void -ImagingDestroyBlock(Imaging im) -{ +ImagingDestroyBlock(Imaging im) { if (im->block) { free(im->block); } } Imaging -ImagingAllocateBlock(Imaging im) -{ +ImagingAllocateBlock(Imaging im) { Py_ssize_t y, i; /* overflow check for malloc */ - if (im->linesize && - im->ysize > INT_MAX / im->linesize) { - return (Imaging) ImagingError_MemoryError(); + if (im->linesize && im->ysize > INT_MAX / im->linesize) { + return (Imaging)ImagingError_MemoryError(); } if (im->ysize * im->linesize <= 0) { /* some platforms return NULL for malloc(0); this fix prevents MemoryError on zero-sized images on such platforms */ - im->block = (char *) malloc(1); + im->block = (char *)malloc(1); } else { /* malloc check ok, overflow check above */ - im->block = (char *) calloc(im->ysize, im->linesize); + im->block = (char *)calloc(im->ysize, im->linesize); } - if ( ! im->block) { - return (Imaging) ImagingError_MemoryError(); + if (!im->block) { + return (Imaging)ImagingError_MemoryError(); } for (y = i = 0; y < im->ysize; y++) { @@ -507,16 +497,15 @@ ImagingAllocateBlock(Imaging im) */ Imaging -ImagingNewInternal(const char* mode, int xsize, int ysize, int dirty) -{ +ImagingNewInternal(const char *mode, int xsize, int ysize, int dirty) { Imaging im; if (xsize < 0 || ysize < 0) { - return (Imaging) ImagingError_ValueError("bad image size"); + return (Imaging)ImagingError_ValueError("bad image size"); } im = ImagingNewPrologue(mode, xsize, ysize); - if ( ! im) { + if (!im) { return NULL; } @@ -536,28 +525,25 @@ ImagingNewInternal(const char* mode, int xsize, int ysize, int dirty) } Imaging -ImagingNew(const char* mode, int xsize, int ysize) -{ +ImagingNew(const char *mode, int xsize, int ysize) { return ImagingNewInternal(mode, xsize, ysize, 0); } Imaging -ImagingNewDirty(const char* mode, int xsize, int ysize) -{ +ImagingNewDirty(const char *mode, int xsize, int ysize) { return ImagingNewInternal(mode, xsize, ysize, 1); } Imaging -ImagingNewBlock(const char* mode, int xsize, int ysize) -{ +ImagingNewBlock(const char *mode, int xsize, int ysize) { Imaging im; if (xsize < 0 || ysize < 0) { - return (Imaging) ImagingError_ValueError("bad image size"); + return (Imaging)ImagingError_ValueError("bad image size"); } im = ImagingNewPrologue(mode, xsize, ysize); - if ( ! im) { + if (!im) { return NULL; } @@ -570,15 +556,13 @@ ImagingNewBlock(const char* mode, int xsize, int ysize) } Imaging -ImagingNew2Dirty(const char* mode, Imaging imOut, Imaging imIn) -{ +ImagingNew2Dirty(const char *mode, Imaging imOut, Imaging imIn) { /* allocate or validate output image */ if (imOut) { /* make sure images match */ - if (strcmp(imOut->mode, mode) != 0 - || imOut->xsize != imIn->xsize - || imOut->ysize != imIn->ysize) { + if (strcmp(imOut->mode, mode) != 0 || imOut->xsize != imIn->xsize || + imOut->ysize != imIn->ysize) { return ImagingError_Mismatch(); } } else { @@ -593,8 +577,7 @@ ImagingNew2Dirty(const char* mode, Imaging imOut, Imaging imIn) } void -ImagingCopyPalette(Imaging destination, Imaging source) -{ +ImagingCopyPalette(Imaging destination, Imaging source) { if (source->palette) { if (destination->palette) { ImagingPaletteDelete(destination->palette); diff --git a/src/libImaging/SunRleDecode.c b/src/libImaging/SunRleDecode.c index acb39133a..9d8e1292a 100644 --- a/src/libImaging/SunRleDecode.c +++ b/src/libImaging/SunRleDecode.c @@ -15,37 +15,30 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - int -ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ +ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { int n; - UINT8* ptr; + UINT8 *ptr; UINT8 extra_data = 0; UINT8 extra_bytes = 0; ptr = buf; for (;;) { - if (bytes < 1) { return ptr - buf; } if (ptr[0] == 0x80) { - if (bytes < 2) { break; } n = ptr[1]; - if (n == 0) { - /* Literal 0x80 (2 bytes) */ n = 1; @@ -55,7 +48,6 @@ ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes -= 2; } else { - /* Run (3 bytes) */ if (bytes < 3) { break; @@ -84,7 +76,7 @@ ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t n += 1; if (state->x + n > state->bytes) { - extra_bytes = n; /* full value */ + extra_bytes = n; /* full value */ n = state->bytes - state->x; extra_bytes -= n; extra_data = ptr[2]; @@ -94,11 +86,9 @@ ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t ptr += 3; bytes -= 3; - } } else { - /* Literal byte */ n = 1; @@ -106,18 +96,18 @@ ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t ptr += 1; bytes -= 1; - } for (;;) { state->x += n; if (state->x >= state->bytes) { - /* Got a full line, unpack it */ - state->shuffle((UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->buffer, - state->xsize); + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->buffer, + state->xsize); state->x = 0; @@ -132,7 +122,7 @@ ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t } if (state->x > 0) { - break; // assert + break; // assert } if (extra_bytes >= state->bytes) { diff --git a/src/libImaging/TgaRleDecode.c b/src/libImaging/TgaRleDecode.c index b1364e004..273ecdffd 100644 --- a/src/libImaging/TgaRleDecode.c +++ b/src/libImaging/TgaRleDecode.c @@ -14,43 +14,35 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - int -ImagingTgaRleDecode(Imaging im, ImagingCodecState state, - UINT8* buf, Py_ssize_t bytes) -{ +ImagingTgaRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { int n, depth; - UINT8* ptr; + UINT8 *ptr; ptr = buf; if (state->state == 0) { - /* check image orientation */ if (state->ystep < 0) { - state->y = state->ysize-1; + state->y = state->ysize - 1; state->ystep = -1; } else { state->ystep = 1; } state->state = 1; - } depth = state->count; for (;;) { - if (bytes < 1) { return ptr - buf; } if (ptr[0] & 0x80) { - /* Run (1 + pixelsize bytes) */ if (bytes < 1 + depth) { @@ -69,7 +61,7 @@ ImagingTgaRleDecode(Imaging im, ImagingCodecState state, } else { int i; for (i = 0; i < n; i += depth) { - memcpy(state->buffer + state->x + i, ptr+1, depth); + memcpy(state->buffer + state->x + i, ptr + 1, depth); } } @@ -77,7 +69,6 @@ ImagingTgaRleDecode(Imaging im, ImagingCodecState state, bytes -= 1 + depth; } else { - /* Literal (1+n+1 bytes block) */ n = depth * (ptr[0] + 1); @@ -94,17 +85,17 @@ ImagingTgaRleDecode(Imaging im, ImagingCodecState state, ptr += 1 + n; bytes -= 1 + n; - } state->x += n; if (state->x >= state->bytes) { - /* Got a full line, unpack it */ - state->shuffle((UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->buffer, - state->xsize); + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->buffer, + state->xsize); state->x = 0; @@ -114,9 +105,7 @@ ImagingTgaRleDecode(Imaging im, ImagingCodecState state, /* End of file (errcode = 0) */ return -1; } - } - } return ptr - buf; diff --git a/src/libImaging/TgaRleEncode.c b/src/libImaging/TgaRleEncode.c index c65dcf5ec..aa7e7b96d 100644 --- a/src/libImaging/TgaRleEncode.c +++ b/src/libImaging/TgaRleEncode.c @@ -4,18 +4,15 @@ #include #include - -static int comparePixels(const UINT8* buf, int x, int bytesPerPixel) -{ +static int +comparePixels(const UINT8 *buf, int x, int bytesPerPixel) { buf += x * bytesPerPixel; return memcmp(buf, buf + bytesPerPixel, bytesPerPixel) == 0; } - int -ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) -{ - UINT8* dst; +ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { + UINT8 *dst; int bytesPerPixel; if (state->state == 0) { @@ -40,7 +37,7 @@ ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) * excluding the 1-byte descriptor. */ if (state->count == 0) { - UINT8* row; + UINT8 *row; UINT8 descriptor; int startX; @@ -64,8 +61,8 @@ ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) if (state->x == 0) { state->shuffle( state->buffer, - (UINT8*)im->image[state->y + state->yoff] - + state->xoff * im->pixelsize, + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, state->xsize); } @@ -149,9 +146,7 @@ ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) } memcpy( - dst, - state->buffer + (state->x * bytesPerPixel - state->count), - flushCount); + dst, state->buffer + (state->x * bytesPerPixel - state->count), flushCount); dst += flushCount; bytes -= flushCount; diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index f33cbc6bd..46bd101b5 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -23,7 +23,8 @@ /* Convert C file descriptor to WinApi HFILE if LibTiff was compiled with tif_win32.c * * This cast is safe, as the top 32-bits of HFILE are guaranteed to be zero, - * see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication + * see + * https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication */ #ifndef USE_WIN32_FILEIO #define fd_to_tiff_fd(fd) (fd) @@ -31,33 +32,45 @@ #define fd_to_tiff_fd(fd) ((int)_get_osfhandle(fd)) #endif -void dump_state(const TIFFSTATE *state){ - TRACE(("State: Location %u size %d eof %d data: %p ifd: %d\n", (uint)state->loc, - (int)state->size, (uint)state->eof, state->data, state->ifd)); +void +dump_state(const TIFFSTATE *state) { + TRACE( + ("State: Location %u size %d eof %d data: %p ifd: %d\n", + (uint)state->loc, + (int)state->size, + (uint)state->eof, + state->data, + state->ifd)); } /* procs for TIFFOpenClient */ -tsize_t _tiffReadProc(thandle_t hdata, tdata_t buf, tsize_t size) { +tsize_t +_tiffReadProc(thandle_t hdata, tdata_t buf, tsize_t size) { TIFFSTATE *state = (TIFFSTATE *)hdata; tsize_t to_read; TRACE(("_tiffReadProc: %d \n", (int)size)); dump_state(state); + if (state->loc > state->eof) { + TIFFError("_tiffReadProc", "Invalid Read at loc %" PRIu64 ", eof: %" PRIu64, state->loc, state->eof); + return 0; + } to_read = min(size, min(state->size, (tsize_t)state->eof) - (tsize_t)state->loc); TRACE(("to_read: %d\n", (int)to_read)); _TIFFmemcpy(buf, (UINT8 *)state->data + state->loc, to_read); state->loc += (toff_t)to_read; - TRACE( ("location: %u\n", (uint)state->loc)); + TRACE(("location: %u\n", (uint)state->loc)); return to_read; } -tsize_t _tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) { +tsize_t +_tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) { TIFFSTATE *state = (TIFFSTATE *)hdata; tsize_t to_write; @@ -65,14 +78,14 @@ tsize_t _tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) { dump_state(state); to_write = min(size, state->size - (tsize_t)state->loc); - if (state->flrealloc && size>to_write) { + if (state->flrealloc && size > to_write) { tdata_t new_data; - tsize_t newsize=state->size; + tsize_t newsize = state->size; while (newsize < (size + state->size)) { - if (newsize > INT_MAX - 64*1024){ + if (newsize > INT_MAX - 64 * 1024) { return 0; } - newsize += 64*1024; + newsize += 64 * 1024; // newsize*=2; // UNDONE, by 64k chunks? } TRACE(("Reallocing in write to %d bytes\n", (int)newsize)); @@ -97,27 +110,29 @@ tsize_t _tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) { return to_write; } -toff_t _tiffSeekProc(thandle_t hdata, toff_t off, int whence) { +toff_t +_tiffSeekProc(thandle_t hdata, toff_t off, int whence) { TIFFSTATE *state = (TIFFSTATE *)hdata; TRACE(("_tiffSeekProc: off: %u whence: %d \n", (uint)off, whence)); dump_state(state); switch (whence) { - case 0: - state->loc = off; - break; - case 1: - state->loc += off; - break; - case 2: - state->loc = state->eof + off; - break; + case 0: + state->loc = off; + break; + case 1: + state->loc += off; + break; + case 2: + state->loc = state->eof + off; + break; } dump_state(state); return state->loc; } -int _tiffCloseProc(thandle_t hdata) { +int +_tiffCloseProc(thandle_t hdata) { TIFFSTATE *state = (TIFFSTATE *)hdata; TRACE(("_tiffCloseProc \n")); @@ -126,8 +141,8 @@ int _tiffCloseProc(thandle_t hdata) { return 0; } - -toff_t _tiffSizeProc(thandle_t hdata) { +toff_t +_tiffSizeProc(thandle_t hdata) { TIFFSTATE *state = (TIFFSTATE *)hdata; TRACE(("_tiffSizeProc \n")); @@ -136,7 +151,8 @@ toff_t _tiffSizeProc(thandle_t hdata) { return (toff_t)state->size; } -int _tiffMapProc(thandle_t hdata, tdata_t* pbase, toff_t* psize) { +int +_tiffMapProc(thandle_t hdata, tdata_t *pbase, toff_t *psize) { TIFFSTATE *state = (TIFFSTATE *)hdata; TRACE(("_tiffMapProc input size: %u, data: %p\n", (uint)*psize, *pbase)); @@ -148,25 +164,41 @@ int _tiffMapProc(thandle_t hdata, tdata_t* pbase, toff_t* psize) { return (1); } -int _tiffNullMapProc(thandle_t hdata, tdata_t* pbase, toff_t* psize) { - (void) hdata; (void) pbase; (void) psize; +int +_tiffNullMapProc(thandle_t hdata, tdata_t *pbase, toff_t *psize) { + (void)hdata; + (void)pbase; + (void)psize; return (0); } -void _tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) { +void +_tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) { TRACE(("_tiffUnMapProc\n")); - (void) hdata; (void) base; (void) size; + (void)hdata; + (void)base; + (void)size; } -int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) { +int +ImagingLibTiffInit(ImagingCodecState state, int fp, uint32_t offset) { TIFFSTATE *clientstate = (TIFFSTATE *)state->context; TRACE(("initing libtiff\n")); - TRACE(("filepointer: %d \n", fp)); - TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state, - state->x, state->y, state->ystep)); - TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize, - state->xoff, state->yoff)); + TRACE(("filepointer: %d \n", fp)); + TRACE( + ("State: count %d, state %d, x %d, y %d, ystep %d\n", + state->count, + state->state, + state->x, + state->y, + state->ystep)); + TRACE( + ("State: xsize %d, ysize %d, xoff %d, yoff %d \n", + state->xsize, + state->ysize, + state->xoff, + state->yoff)); TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes)); TRACE(("State: context %p \n", state->context)); @@ -180,138 +212,394 @@ int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) { return 1; } +int +_pickUnpackers(Imaging im, ImagingCodecState state, TIFF *tiff, uint16_t planarconfig, ImagingShuffler *unpackers) { + // if number of bands is 1, there is no difference with contig case + if (planarconfig == PLANARCONFIG_SEPARATE && im->bands > 1) { + uint16_t bits_per_sample = 8; -int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) { - uint16 photometric = 0; - - TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); - - // To avoid dealing with YCbCr subsampling, let libtiff handle it - if (photometric == PHOTOMETRIC_YCBCR) { - UINT32 tile_width, tile_height, swap_line_size, i_row; - UINT32* swap_line; - - TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); - TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_height); - - swap_line_size = tile_width * sizeof(UINT32); - if (tile_width != swap_line_size / sizeof(UINT32)) { + TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); + if (bits_per_sample != 8 && bits_per_sample != 16) { + TRACE(("Invalid value for bits per sample: %d\n", bits_per_sample)); + state->errcode = IMAGING_CODEC_BROKEN; return -1; } - /* Read the tile into an RGBA array */ - if (!TIFFReadRGBATile(tiff, col, row, buffer)) { - return -1; - } + // We'll pick appropriate set of unpackers depending on planar_configuration + // It does not matter if data is RGB(A), CMYK or LUV really, + // we just copy it plane by plane + unpackers[0] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "R;16N" : "R", NULL); + unpackers[1] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "G;16N" : "G", NULL); + unpackers[2] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "B;16N" : "B", NULL); + unpackers[3] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "A;16N" : "A", NULL); - swap_line = (UINT32*)malloc(swap_line_size); - if (swap_line == NULL) { - return -1; - } - /* - * For some reason the TIFFReadRGBATile() function chooses the - * lower left corner as the origin. Vertically mirror scanlines. - */ - for(i_row = 0; i_row < tile_height / 2; i_row++) { - UINT32 *top_line, *bottom_line; + return im->bands; + } else { + unpackers[0] = state->shuffle; - top_line = buffer + tile_width * i_row; - bottom_line = buffer + tile_width * (tile_height - i_row - 1); + return 1; + } +} - memcpy(swap_line, top_line, 4*tile_width); - memcpy(top_line, bottom_line, 4*tile_width); - memcpy(bottom_line, swap_line, 4*tile_width); - } +int +_decodeAsRGBA(Imaging im, ImagingCodecState state, TIFF *tiff) { + // To avoid dealing with YCbCr subsampling and other complications, let libtiff handle it + // Use a TIFFRGBAImage wrapping the tiff image, and let libtiff handle + // all of the conversion. Metadata read from the TIFFRGBAImage could + // be different from the metadata that the base tiff returns. - free(swap_line); + INT32 current_row; + UINT8 *new_data; + UINT32 rows_per_block, row_byte_size, rows_to_read; + int ret; + TIFFRGBAImage img; + char emsg[1024] = ""; - return 0; + // Since using TIFFRGBAImage* functions, we can read whole tiff into rastrr in one call + // Let's select smaller block size. Multiplying image width by (tile length OR rows per strip) + // gives us manageable block size in pixels + if (TIFFIsTiled(tiff)) { + ret = TIFFGetFieldDefaulted(tiff, TIFFTAG_TILELENGTH, &rows_per_block); + } + else { + ret = TIFFGetFieldDefaulted(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_block); } - if (TIFFReadTile(tiff, (tdata_t)buffer, col, row, 0, 0) == -1) { - TRACE(("Decode Error, Tile at %dx%d\n", col, row)); + if (ret != 1 || rows_per_block==(UINT32)(-1)) { + rows_per_block = state->ysize; + } + + TRACE(("RowsPerBlock: %u \n", rows_per_block)); + + if (!(TIFFRGBAImageOK(tiff, emsg) && TIFFRGBAImageBegin(&img, tiff, 0, emsg))) { + TRACE(("Decode error, msg: %s", emsg)); + state->errcode = IMAGING_CODEC_BROKEN; + // nothing to clean up, just return return -1; } - TRACE(("Successfully read tile at %dx%d; \n\n", col, row)); + img.req_orientation = ORIENTATION_TOPLEFT; + img.col_offset = 0; + /* overflow check for row byte size */ + if (INT_MAX / 4 < img.width) { + state->errcode = IMAGING_CODEC_MEMORY; + goto decodergba_err; + } + + // TiffRGBAImages are 32bits/pixel. + row_byte_size = img.width * 4; + + /* overflow check for realloc */ + if (INT_MAX / row_byte_size < rows_per_block) { + state->errcode = IMAGING_CODEC_MEMORY; + goto decodergba_err; + } + + state->bytes = rows_per_block * row_byte_size; + + TRACE(("BlockSize: %d \n", state->bytes)); + + /* realloc to fit whole strip */ + /* malloc check above */ + new_data = realloc(state->buffer, state->bytes); + if (!new_data) { + state->errcode = IMAGING_CODEC_MEMORY; + goto decodergba_err; + } + + state->buffer = new_data; + + for (; state->y < state->ysize; state->y += rows_per_block) { + img.row_offset = state->y; + rows_to_read = min(rows_per_block, img.height - state->y); + + if (!TIFFRGBAImageGet(&img, (UINT32 *)state->buffer, img.width, rows_to_read)) { + TRACE(("Decode Error, y: %d\n", state->y)); + state->errcode = IMAGING_CODEC_BROKEN; + goto decodergba_err; + } + +#if WORDS_BIGENDIAN + TIFFSwabArrayOfLong((UINT32 *)state->buffer, img.width * rows_to_read); +#endif + + TRACE(("Decoded strip for row %d \n", state->y)); + + // iterate over each row in the strip and stuff data into image + for (current_row = 0; + current_row < min((INT32)rows_per_block, state->ysize - state->y); + current_row++) { + TRACE(("Writing data into line %d ; \n", state->y + current_row)); + + // UINT8 * bbb = state->buffer + current_row * (state->bytes / + // rows_per_block); TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], + // ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff + current_row] + + state->xoff * im->pixelsize, + state->buffer + current_row * row_byte_size, + state->xsize); + } + } + +decodergba_err: + TIFFRGBAImageEnd(&img); + if (state->errcode != 0) { + return -1; + } return 0; } -int ReadStrip(TIFF* tiff, UINT32 row, UINT32* buffer) { - uint16 photometric = 0; // init to not PHOTOMETRIC_YCBCR - TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); +int +_decodeTile(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) { + INT32 x, y, tile_y, current_tile_length, current_tile_width; + UINT32 tile_width, tile_length; + tsize_t tile_bytes_size, row_byte_size; + UINT8 *new_data; - // To avoid dealing with YCbCr subsampling, let libtiff handle it - if (photometric == PHOTOMETRIC_YCBCR) { - TIFFRGBAImage img; - char emsg[1024] = ""; - UINT32 rows_per_strip, rows_to_read; - int ok; + tile_bytes_size = TIFFTileSize(tiff); - - TIFFGetFieldDefaulted(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); - if ((row % rows_per_strip) != 0) { - TRACE(("Row passed to ReadStrip() must be first in a strip.")); - return -1; - } - - if (TIFFRGBAImageOK(tiff, emsg) && TIFFRGBAImageBegin(&img, tiff, 0, emsg)) { - TRACE(("Initialized RGBAImage\n")); - - img.req_orientation = ORIENTATION_TOPLEFT; - img.row_offset = row; - img.col_offset = 0; - - rows_to_read = min(rows_per_strip, img.height - row); - - TRACE(("rows to read: %d\n", rows_to_read)); - ok = TIFFRGBAImageGet(&img, buffer, img.width, rows_to_read); - - TIFFRGBAImageEnd(&img); - } else { - ok = 0; - } - - if (ok == 0) { - TRACE(("Decode Error, row %d; msg: %s\n", row, emsg)); - return -1; - } - - return 0; + if (tile_bytes_size == 0) { + TRACE(("Decode Error, Can not calculate TileSize\n")); + state->errcode = IMAGING_CODEC_BROKEN; + return -1; } - if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, row, 0), (tdata_t)buffer, -1) == -1) { - TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, row, 0))); + row_byte_size = TIFFTileRowSize(tiff); + + if (row_byte_size == 0 || row_byte_size > tile_bytes_size) { + TRACE(("Decode Error, Can not calculate TileRowSize\n")); + state->errcode = IMAGING_CODEC_BROKEN; return -1; } + /* overflow check for realloc */ + if (tile_bytes_size > INT_MAX - 1) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); + TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); + + if (tile_width > INT_MAX || tile_length > INT_MAX) { + // state->x and state->y are ints + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + if (tile_bytes_size > ((tile_length * state->bits / planes + 7) / 8) * tile_width) { + // If the tile size as expected by LibTiff isn't what we're expecting, abort. + // man: TIFFTileSize returns the equivalent size for a tile of data as it would be returned in a + // call to TIFFReadTile ... + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + + state->bytes = tile_bytes_size; + + TRACE(("TIFFTileSize: %d\n", state->bytes)); + + /* realloc to fit whole tile */ + /* malloc check above */ + new_data = realloc(state->buffer, state->bytes); + if (!new_data) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + state->buffer = new_data; + + for (y = state->yoff; y < state->ysize; y += tile_length) { + int plane; + for (plane = 0; plane < planes; plane++) { + ImagingShuffler shuffler = unpackers[plane]; + for (x = state->xoff; x < state->xsize; x += tile_width) { + if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) { + TRACE(("Decode Error, Tile at %dx%d\n", x, y)); + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + + TRACE(("Read tile at %dx%d; \n\n", x, y)); + + current_tile_width = min((INT32) tile_width, state->xsize - x); + current_tile_length = min((INT32) tile_length, state->ysize - y); + // iterate over each line in the tile and stuff data into image + for (tile_y = 0; tile_y < current_tile_length; tile_y++) { + TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); + + // UINT8 * bbb = state->buffer + tile_y * row_byte_size; + // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + + shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize, + state->buffer + tile_y * row_byte_size, + current_tile_width + ); + } + } + } + } + return 0; } -int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes) { +int +_decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) { + INT32 strip_row = 0; + UINT8 *new_data; + UINT32 rows_per_strip; + int ret; + tsize_t strip_size, row_byte_size, unpacker_row_byte_size; + + ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); + if (ret != 1 || rows_per_strip==(UINT32)(-1)) { + rows_per_strip = state->ysize; + } + + if (rows_per_strip > INT_MAX) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + TRACE(("RowsPerStrip: %u\n", rows_per_strip)); + + strip_size = TIFFStripSize(tiff); + if (strip_size > INT_MAX - 1) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + unpacker_row_byte_size = (state->xsize * state->bits / planes + 7) / 8; + if (strip_size > (unpacker_row_byte_size * rows_per_strip)) { + // If the strip size as expected by LibTiff isn't what we're expecting, abort. + // man: TIFFStripSize returns the equivalent size for a strip of data as it would be returned in a + // call to TIFFReadEncodedStrip ... + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + + state->bytes = strip_size; + + TRACE(("StripSize: %d \n", state->bytes)); + + row_byte_size = TIFFScanlineSize(tiff); + + // if the unpacker calculated row size is > row byte size, (at least) the last + // row of the strip will have a read buffer overflow. + if (row_byte_size == 0 || unpacker_row_byte_size > row_byte_size) { + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + + TRACE(("RowsByteSize: %u \n", row_byte_size)); + + /* realloc to fit whole strip */ + /* malloc check above */ + new_data = realloc(state->buffer, state->bytes); + if (!new_data) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + state->buffer = new_data; + + for (; state->y < state->ysize; state->y += rows_per_strip) { + int plane; + for (plane = 0; plane < planes; plane++) { + ImagingShuffler shuffler = unpackers[plane]; + if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, state->y, plane), (tdata_t)state->buffer, strip_size) == -1) { + TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + + TRACE(("Decoded strip for row %d \n", state->y)); + + // iterate over each row in the strip and stuff data into image + for (strip_row = 0; + strip_row < min((INT32) rows_per_strip, state->ysize - state->y); + strip_row++) { + TRACE(("Writing data into line %d ; \n", state->y + strip_row)); + + // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip); + // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + + shuffler( + (UINT8*) im->image[state->y + state->yoff + strip_row] + + state->xoff * im->pixelsize, + state->buffer + strip_row * row_byte_size, + state->xsize); + } + } + } + + return 0; +} + +int +ImagingLibTiffDecode( + Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes) { TIFFSTATE *clientstate = (TIFFSTATE *)state->context; char *filename = "tempfile.tif"; char *mode = "r"; TIFF *tiff; + uint16_t photometric = 0; // init to not PHOTOMETRIC_YCBCR + uint16_t compression; + int readAsRGBA = 0; + uint16_t planarconfig = 0; + int planes = 1; + ImagingShuffler unpackers[4]; + UINT32 img_width, img_height; + + memset(unpackers, 0, sizeof(ImagingShuffler) * 4); /* buffer is the encoded file, bytes is the length of the encoded file */ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */ TRACE(("in decoder: bytes %d\n", bytes)); - TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state, - state->x, state->y, state->ystep)); - TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize, - state->xoff, state->yoff)); + TRACE( + ("State: count %d, state %d, x %d, y %d, ystep %d\n", + state->count, + state->state, + state->x, + state->y, + state->ystep)); + TRACE( + ("State: xsize %d, ysize %d, xoff %d, yoff %d \n", + state->xsize, + state->ysize, + state->xoff, + state->yoff)); TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes)); - TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3])); - TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3])); - TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n", - im->mode, im->type, im->bands, im->xsize, im->ysize)); - TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n", - im->image8, im->image32, im->image, im->block)); - TRACE(("Image: pixelsize: %d, linesize %d \n", - im->pixelsize, im->linesize)); + TRACE( + ("Buffer: %p: %c%c%c%c\n", + buffer, + (char)buffer[0], + (char)buffer[1], + (char)buffer[2], + (char)buffer[3])); + TRACE( + ("State->Buffer: %c%c%c%c\n", + (char)state->buffer[0], + (char)state->buffer[1], + (char)state->buffer[2], + (char)state->buffer[3])); + TRACE( + ("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n", + im->mode, + im->type, + im->bands, + im->xsize, + im->ysize)); + TRACE( + ("Image: image8 %p, image32 %p, image %p, block %p \n", + im->image8, + im->image32, + im->image, + im->block)); + TRACE(("Image: pixelsize: %d, linesize %d \n", im->pixelsize, im->linesize)); dump_state(clientstate); clientstate->size = bytes; @@ -325,181 +613,113 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ TIFFSetWarningHandlerExt(NULL); if (clientstate->fp) { - TRACE(("Opening using fd: %d\n",clientstate->fp)); - lseek(clientstate->fp,0,SEEK_SET); // Sometimes, I get it set to the end. + TRACE(("Opening using fd: %d\n", clientstate->fp)); + lseek(clientstate->fp, 0, SEEK_SET); // Sometimes, I get it set to the end. tiff = TIFFFdOpen(fd_to_tiff_fd(clientstate->fp), filename, mode); } else { TRACE(("Opening from string\n")); - tiff = TIFFClientOpen(filename, mode, - (thandle_t) clientstate, - _tiffReadProc, _tiffWriteProc, - _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, - _tiffMapProc, _tiffUnmapProc); + tiff = TIFFClientOpen( + filename, + mode, + (thandle_t)clientstate, + _tiffReadProc, + _tiffWriteProc, + _tiffSeekProc, + _tiffCloseProc, + _tiffSizeProc, + _tiffMapProc, + _tiffUnmapProc); } - if (!tiff){ + if (!tiff) { TRACE(("Error, didn't get the tiff\n")); state->errcode = IMAGING_CODEC_BROKEN; return -1; } - if (clientstate->ifd){ + if (clientstate->ifd) { int rv; - uint32 ifdoffset = clientstate->ifd; + uint32_t ifdoffset = clientstate->ifd; TRACE(("reading tiff ifd %u\n", ifdoffset)); rv = TIFFSetSubDirectory(tiff, ifdoffset); - if (!rv){ + if (!rv) { TRACE(("error in TIFFSetSubDirectory")); - return -1; + goto decode_err; } } - if (TIFFIsTiled(tiff)) { - INT32 x, y, tile_y; - UINT32 tile_width, tile_length, current_tile_width, row_byte_size; - UINT8 *new_data; + TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &img_width); + TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &img_height); - TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); - TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); + if (state->xsize != img_width || state->ysize != img_height) { + TRACE( + ("Inconsistent Image Error: %d =? %d, %d =? %d", + state->xsize, + img_width, + state->ysize, + img_height)); + state->errcode = IMAGING_CODEC_BROKEN; + goto decode_err; + } - /* overflow check for row_byte_size calculation */ - if ((UINT32) INT_MAX / state->bits < tile_width) { - state->errcode = IMAGING_CODEC_MEMORY; - TIFFClose(tiff); - return -1; + + TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); + TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression); + TIFFGetFieldDefaulted(tiff, TIFFTAG_PLANARCONFIG, &planarconfig); + + // Dealing with YCbCr images is complicated in case if subsampling + // Let LibTiff read them as RGBA + readAsRGBA = photometric == PHOTOMETRIC_YCBCR; + + if (readAsRGBA && compression == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) { + // If using new JPEG compression, let libjpeg do RGB conversion for performance reasons + TIFFSetField(tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + readAsRGBA = 0; + } + + if (readAsRGBA) { + _decodeAsRGBA(im, state, tiff); + } + else { + planes = _pickUnpackers(im, state, tiff, planarconfig, unpackers); + if (planes <= 0) { + goto decode_err; } - // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size - row_byte_size = (tile_width * state->bits + 7) / 8; - - /* overflow check for realloc */ - if (INT_MAX / row_byte_size < tile_length) { - state->errcode = IMAGING_CODEC_MEMORY; - TIFFClose(tiff); - return -1; + if (TIFFIsTiled(tiff)) { + _decodeTile(im, state, tiff, planes, unpackers); } - - state->bytes = row_byte_size * tile_length; - - if (TIFFTileSize(tiff) > state->bytes) { - // If the strip size as expected by LibTiff isn't what we're expecting, abort. - state->errcode = IMAGING_CODEC_MEMORY; - TIFFClose(tiff); - return -1; + else { + _decodeStrip(im, state, tiff, planes, unpackers); } - /* realloc to fit whole tile */ - /* malloc check above */ - new_data = realloc (state->buffer, state->bytes); - if (!new_data) { - state->errcode = IMAGING_CODEC_MEMORY; - TIFFClose(tiff); - return -1; - } + if (!state->errcode) { + // Check if raw mode was RGBa and it was stored on separate planes + // so we have to convert it to RGBA + if (planes > 3 && strcmp(im->mode, "RGBA") == 0) { + uint16_t extrasamples; + uint16_t* sampleinfo; + ImagingShuffler shuffle; + INT32 y; - state->buffer = new_data; + TIFFGetFieldDefaulted(tiff, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); - TRACE(("TIFFTileSize: %d\n", state->bytes)); + if (extrasamples >= 1 && + (sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED || sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA) + ) { + shuffle = ImagingFindUnpacker("RGBA", "RGBa", NULL); - for (y = state->yoff; y < state->ysize; y += tile_length) { - for (x = state->xoff; x < state->xsize; x += tile_width) { - if (ReadTile(tiff, x, y, (UINT32*) state->buffer) == -1) { - TRACE(("Decode Error, Tile at %dx%d\n", x, y)); - state->errcode = IMAGING_CODEC_BROKEN; - TIFFClose(tiff); - return -1; + for (y = state->yoff; y < state->ysize; y++) { + UINT8* ptr = (UINT8*) im->image[y + state->yoff] + + state->xoff * im->pixelsize; + shuffle(ptr, ptr, state->xsize); + } } - - TRACE(("Read tile at %dx%d; \n\n", x, y)); - - current_tile_width = min((INT32) tile_width, state->xsize - x); - - // iterate over each line in the tile and stuff data into image - for (tile_y = 0; tile_y < min((INT32) tile_length, state->ysize - y); tile_y++) { - TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); - - // UINT8 * bbb = state->buffer + tile_y * row_byte_size; - // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - - state->shuffle((UINT8*) im->image[tile_y + y] + x * im->pixelsize, - state->buffer + tile_y * row_byte_size, - current_tile_width - ); - } - } - } - } else { - INT32 strip_row; - UINT8 *new_data; - UINT32 rows_per_strip, row_byte_size; - int ret; - - ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); - if (ret != 1) { - rows_per_strip = state->ysize; - } - TRACE(("RowsPerStrip: %u \n", rows_per_strip)); - - // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size - row_byte_size = (state->xsize * state->bits + 7) / 8; - - /* overflow check for realloc */ - if (INT_MAX / row_byte_size < rows_per_strip) { - state->errcode = IMAGING_CODEC_MEMORY; - TIFFClose(tiff); - return -1; - } - - state->bytes = rows_per_strip * row_byte_size; - - TRACE(("StripSize: %d \n", state->bytes)); - - if (TIFFStripSize(tiff) > state->bytes) { - // If the strip size as expected by LibTiff isn't what we're expecting, abort. - // man: TIFFStripSize returns the equivalent size for a strip of data as it would be returned in a - // call to TIFFReadEncodedStrip ... - - state->errcode = IMAGING_CODEC_MEMORY; - TIFFClose(tiff); - return -1; - } - - /* realloc to fit whole strip */ - /* malloc check above */ - new_data = realloc (state->buffer, state->bytes); - if (!new_data) { - state->errcode = IMAGING_CODEC_MEMORY; - TIFFClose(tiff); - return -1; - } - - state->buffer = new_data; - - for (; state->y < state->ysize; state->y += rows_per_strip) { - if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) { - TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); - state->errcode = IMAGING_CODEC_BROKEN; - TIFFClose(tiff); - return -1; - } - - TRACE(("Decoded strip for row %d \n", state->y)); - - // iterate over each row in the strip and stuff data into image - for (strip_row = 0; strip_row < min((INT32) rows_per_strip, state->ysize - state->y); strip_row++) { - TRACE(("Writing data into line %d ; \n", state->y + strip_row)); - - // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip); - // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - - state->shuffle((UINT8*) im->image[state->y + state->yoff + strip_row] + - state->xoff * im->pixelsize, - state->buffer + strip_row * row_byte_size, - state->xsize); } } } + decode_err: TIFFClose(tiff); TRACE(("Done Decoding, Returning \n")); // Returning -1 here to force ImageFile.load to break, rather than @@ -507,7 +727,8 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ return -1; } -int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) { +int +ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) { // Open the FD or the pointer as a tiff file, for writing. // We may have to do some monkeying around to make this really work. // If we have a fp, then we're good. @@ -516,21 +737,30 @@ int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) { // Going to have to deal with the directory as well. TIFFSTATE *clientstate = (TIFFSTATE *)state->context; - int bufsize = 64*1024; + int bufsize = 64 * 1024; char *mode = "w"; TRACE(("initing libtiff\n")); - TRACE(("Filename %s, filepointer: %d \n", filename, fp)); - TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state, - state->x, state->y, state->ystep)); - TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize, - state->xoff, state->yoff)); + TRACE(("Filename %s, filepointer: %d \n", filename, fp)); + TRACE( + ("State: count %d, state %d, x %d, y %d, ystep %d\n", + state->count, + state->state, + state->x, + state->y, + state->ystep)); + TRACE( + ("State: xsize %d, ysize %d, xoff %d, yoff %d \n", + state->xsize, + state->ysize, + state->xoff, + state->yoff)); TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes)); TRACE(("State: context %p \n", state->context)); clientstate->loc = 0; clientstate->size = 0; - clientstate->eof =0; + clientstate->eof = 0; clientstate->data = 0; clientstate->flrealloc = 0; clientstate->fp = fp; @@ -538,27 +768,33 @@ int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) { state->state = 0; if (fp) { - TRACE(("Opening using fd: %d for writing \n",clientstate->fp)); + TRACE(("Opening using fd: %d for writing \n", clientstate->fp)); clientstate->tiff = TIFFFdOpen(fd_to_tiff_fd(clientstate->fp), filename, mode); } else { - // malloc a buffer to write the tif, we're going to need to realloc or something if we need bigger. + // malloc a buffer to write the tif, we're going to need to realloc or something + // if we need bigger. TRACE(("Opening a buffer for writing \n")); /* malloc check ok, small constant allocation */ clientstate->data = malloc(bufsize); clientstate->size = bufsize; - clientstate->flrealloc=1; + clientstate->flrealloc = 1; if (!clientstate->data) { TRACE(("Error, couldn't allocate a buffer of size %d\n", bufsize)); return 0; } - clientstate->tiff = TIFFClientOpen(filename, mode, - (thandle_t) clientstate, - _tiffReadProc, _tiffWriteProc, - _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, - _tiffNullMapProc, _tiffUnmapProc); /*force no mmap*/ - + clientstate->tiff = TIFFClientOpen( + filename, + mode, + (thandle_t)clientstate, + _tiffReadProc, + _tiffWriteProc, + _tiffSeekProc, + _tiffCloseProc, + _tiffSizeProc, + _tiffNullMapProc, + _tiffUnmapProc); /*force no mmap*/ } if (!clientstate->tiff) { @@ -567,26 +803,33 @@ int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) { } return 1; - } -int ImagingLibTiffMergeFieldInfo(ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length){ +int +ImagingLibTiffMergeFieldInfo( + ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length) { // Refer to libtiff docs (http://www.simplesystems.org/libtiff/addingtags.html) TIFFSTATE *clientstate = (TIFFSTATE *)state->context; - uint32 n; + uint32_t n; int status = 0; // custom fields added with ImagingLibTiffMergeFieldInfo are only used for // decoding, ignore readcount; - int readcount = 0; + int readcount = 1; // we support writing a single value, or a variable number of values int writecount = 1; // whether the first value should encode the number of values. int passcount = 0; TIFFFieldInfo info[] = { - { key, readcount, writecount, field_type, FIELD_CUSTOM, 1, passcount, "CustomField" } - }; + {key, + readcount, + writecount, + field_type, + FIELD_CUSTOM, + 1, + passcount, + "CustomField"}}; if (is_var_length) { info[0].field_writecount = -1; @@ -599,7 +842,8 @@ int ImagingLibTiffMergeFieldInfo(ImagingCodecState state, TIFFDataType field_typ n = sizeof(info) / sizeof(info[0]); // Test for libtiff 4.0 or later, excluding libtiff 3.9.6 and 3.9.7 -#if TIFFLIB_VERSION >= 20111221 && TIFFLIB_VERSION != 20120218 && TIFFLIB_VERSION != 20120922 +#if TIFFLIB_VERSION >= 20111221 && TIFFLIB_VERSION != 20120218 && \ + TIFFLIB_VERSION != 20120922 status = TIFFMergeFieldInfo(clientstate->tiff, info, n); #else TIFFMergeFieldInfo(clientstate->tiff, info, n); @@ -607,7 +851,8 @@ int ImagingLibTiffMergeFieldInfo(ImagingCodecState state, TIFFDataType field_typ return status; } -int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...){ +int +ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...) { // after tif_dir.c->TIFFSetField. TIFFSTATE *clientstate = (TIFFSTATE *)state->context; va_list ap; @@ -619,8 +864,8 @@ int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...){ return status; } - -int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes) { +int +ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes) { /* One shot encoder. Encode everything to the tiff in the clientstate. If we're running off of a FD, then run once, we're good, everything ends up in the file, we close and we're done. @@ -634,35 +879,65 @@ int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int TIFF *tiff = clientstate->tiff; TRACE(("in encoder: bytes %d\n", bytes)); - TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state, - state->x, state->y, state->ystep)); - TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize, - state->xoff, state->yoff)); + TRACE( + ("State: count %d, state %d, x %d, y %d, ystep %d\n", + state->count, + state->state, + state->x, + state->y, + state->ystep)); + TRACE( + ("State: xsize %d, ysize %d, xoff %d, yoff %d \n", + state->xsize, + state->ysize, + state->xoff, + state->yoff)); TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes)); - TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3])); - TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3])); - TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n", - im->mode, im->type, im->bands, im->xsize, im->ysize)); - TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n", - im->image8, im->image32, im->image, im->block)); - TRACE(("Image: pixelsize: %d, linesize %d \n", - im->pixelsize, im->linesize)); + TRACE( + ("Buffer: %p: %c%c%c%c\n", + buffer, + (char)buffer[0], + (char)buffer[1], + (char)buffer[2], + (char)buffer[3])); + TRACE( + ("State->Buffer: %c%c%c%c\n", + (char)state->buffer[0], + (char)state->buffer[1], + (char)state->buffer[2], + (char)state->buffer[3])); + TRACE( + ("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n", + im->mode, + im->type, + im->bands, + im->xsize, + im->ysize)); + TRACE( + ("Image: image8 %p, image32 %p, image %p, block %p \n", + im->image8, + im->image32, + im->image, + im->block)); + TRACE(("Image: pixelsize: %d, linesize %d \n", im->pixelsize, im->linesize)); dump_state(clientstate); if (state->state == 0) { TRACE(("Encoding line bt line")); - while(state->y < state->ysize){ - state->shuffle(state->buffer, - (UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, - state->xsize); + while (state->y < state->ysize) { + state->shuffle( + state->buffer, + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->xsize); - if (TIFFWriteScanline(tiff, (tdata_t)(state->buffer), (uint32)state->y, 0) == -1) { + if (TIFFWriteScanline( + tiff, (tdata_t)(state->buffer), (uint32_t)state->y, 0) == -1) { TRACE(("Encode Error, row %d\n", state->y)); state->errcode = IMAGING_CODEC_BROKEN; TIFFClose(tiff); - if (!clientstate->fp){ + if (!clientstate->fp) { free(clientstate->data); } return -1; @@ -671,7 +946,7 @@ int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int } if (state->y == state->ysize) { - state->state=1; + state->state = 1; TRACE(("Flushing \n")); if (!TIFFFlush(tiff)) { @@ -679,7 +954,7 @@ int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int // likely reason is memory. state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); - if (!clientstate->fp){ + if (!clientstate->fp) { free(clientstate->data); } return -1; @@ -688,13 +963,19 @@ int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int TIFFClose(tiff); // reset the clientstate metadata to use it to read out the buffer. clientstate->loc = 0; - clientstate->size = clientstate->eof; // redundant? + clientstate->size = clientstate->eof; // redundant? } } if (state->state == 1 && !clientstate->fp) { int read = (int)_tiffReadProc(clientstate, (tdata_t)buffer, (tsize_t)bytes); - TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3])); + TRACE( + ("Buffer: %p: %c%c%c%c\n", + buffer, + (char)buffer[0], + (char)buffer[1], + (char)buffer[2], + (char)buffer[3])); if (clientstate->loc == clientstate->eof) { TRACE(("Hit EOF, calling an end, freeing data")); state->errcode = IMAGING_CODEC_END; @@ -707,9 +988,8 @@ int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int return 0; } -const char* -ImagingTiffVersion(void) -{ +const char * +ImagingTiffVersion(void) { return TIFFGetVersion(); } diff --git a/src/libImaging/TiffDecode.h b/src/libImaging/TiffDecode.h index 3d27e65b6..c7c7d48ed 100644 --- a/src/libImaging/TiffDecode.h +++ b/src/libImaging/TiffDecode.h @@ -20,8 +20,8 @@ */ #ifndef min -#define min(x,y) (( x > y ) ? y : x ) -#define max(x,y) (( x < y ) ? y : x ) +#define min(x, y) ((x > y) ? y : x) +#define max(x, y) ((x < y) ? y : x) #endif #ifndef _PIL_LIBTIFF_ @@ -32,22 +32,24 @@ typedef struct { toff_t loc; /* toff_t == uint32 */ tsize_t size; /* tsize_t == int32 */ int fp; - uint32 ifd; /* offset of the ifd, used for multipage + uint32_t ifd; /* offset of the ifd, used for multipage * Should be uint32 for libtiff 3.9.x * uint64 for libtiff 4.0.x */ - TIFF *tiff; /* Used in write */ + TIFF *tiff; /* Used in write */ toff_t eof; - int flrealloc;/* may we realloc */ + int flrealloc; /* may we realloc */ } TIFFSTATE; - - -extern int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset); -extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp); -extern int ImagingLibTiffMergeFieldInfo(ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length); -extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...); - +extern int +ImagingLibTiffInit(ImagingCodecState state, int fp, uint32_t offset); +extern int +ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp); +extern int +ImagingLibTiffMergeFieldInfo( + ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length); +extern int +ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...); /* Trace debugging diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index 917da6ab3..5dac95c1d 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -46,20 +46,28 @@ /* byte-swapping macros */ -#define C16N\ - (tmp[0]=in[0], tmp[1]=in[1]); -#define C16S\ - (tmp[1]=in[0], tmp[0]=in[1]); -#define C32N\ - (tmp[0]=in[0], tmp[1]=in[1], tmp[2]=in[2], tmp[3]=in[3]); -#define C32S\ - (tmp[3]=in[0], tmp[2]=in[1], tmp[1]=in[2], tmp[0]=in[3]); -#define C64N\ - (tmp[0]=in[0], tmp[1]=in[1], tmp[2]=in[2], tmp[3]=in[3],\ - tmp[4]=in[4], tmp[5]=in[5], tmp[6]=in[6], tmp[7]=in[7]); -#define C64S\ - (tmp[7]=in[0], tmp[6]=in[1], tmp[5]=in[2], tmp[4]=in[3],\ - tmp[3]=in[4], tmp[2]=in[5], tmp[1]=in[6], tmp[0]=in[7]); +#define C16N (tmp[0] = in[0], tmp[1] = in[1]); +#define C16S (tmp[1] = in[0], tmp[0] = in[1]); +#define C32N (tmp[0] = in[0], tmp[1] = in[1], tmp[2] = in[2], tmp[3] = in[3]); +#define C32S (tmp[3] = in[0], tmp[2] = in[1], tmp[1] = in[2], tmp[0] = in[3]); +#define C64N \ + (tmp[0] = in[0], \ + tmp[1] = in[1], \ + tmp[2] = in[2], \ + tmp[3] = in[3], \ + tmp[4] = in[4], \ + tmp[5] = in[5], \ + tmp[6] = in[6], \ + tmp[7] = in[7]); +#define C64S \ + (tmp[7] = in[0], \ + tmp[6] = in[1], \ + tmp[5] = in[2], \ + tmp[4] = in[3], \ + tmp[3] = in[4], \ + tmp[2] = in[5], \ + tmp[1] = in[6], \ + tmp[0] = in[7]); #ifdef WORDS_BIGENDIAN #define C16B C16N @@ -80,111 +88,163 @@ /* bit-swapping */ static UINT8 BITFLIP[] = { - 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, - 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, - 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, - 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, - 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, - 210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, - 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22, - 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, - 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97, - 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, - 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, 197, 37, - 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, - 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 3, 131, 67, - 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, - 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 7, - 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, - 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, - 255 -}; + 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, + 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, + 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, + 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, + 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, + 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, + 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, + 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, + 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, + 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, + 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, + 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255}; /* Unpack to "1" image */ static void -unpack1(UINT8* out, const UINT8* in, int pixels) -{ +unpack1(UINT8 *out, const UINT8 *in, int pixels) { /* bits (msb first, white is non-zero) */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = (byte & 128) ? 255 : 0; byte <<= 1; - case 7: *out++ = (byte & 128) ? 255 : 0; byte <<= 1; - case 6: *out++ = (byte & 128) ? 255 : 0; byte <<= 1; - case 5: *out++ = (byte & 128) ? 255 : 0; byte <<= 1; - case 4: *out++ = (byte & 128) ? 255 : 0; byte <<= 1; - case 3: *out++ = (byte & 128) ? 255 : 0; byte <<= 1; - case 2: *out++ = (byte & 128) ? 255 : 0; byte <<= 1; - case 1: *out++ = (byte & 128) ? 255 : 0; + default: + *out++ = (byte & 128) ? 255 : 0; + byte <<= 1; + case 7: + *out++ = (byte & 128) ? 255 : 0; + byte <<= 1; + case 6: + *out++ = (byte & 128) ? 255 : 0; + byte <<= 1; + case 5: + *out++ = (byte & 128) ? 255 : 0; + byte <<= 1; + case 4: + *out++ = (byte & 128) ? 255 : 0; + byte <<= 1; + case 3: + *out++ = (byte & 128) ? 255 : 0; + byte <<= 1; + case 2: + *out++ = (byte & 128) ? 255 : 0; + byte <<= 1; + case 1: + *out++ = (byte & 128) ? 255 : 0; } pixels -= 8; } } static void -unpack1I(UINT8* out, const UINT8* in, int pixels) -{ +unpack1I(UINT8 *out, const UINT8 *in, int pixels) { /* bits (msb first, white is zero) */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = (byte & 128) ? 0 : 255; byte <<= 1; - case 7: *out++ = (byte & 128) ? 0 : 255; byte <<= 1; - case 6: *out++ = (byte & 128) ? 0 : 255; byte <<= 1; - case 5: *out++ = (byte & 128) ? 0 : 255; byte <<= 1; - case 4: *out++ = (byte & 128) ? 0 : 255; byte <<= 1; - case 3: *out++ = (byte & 128) ? 0 : 255; byte <<= 1; - case 2: *out++ = (byte & 128) ? 0 : 255; byte <<= 1; - case 1: *out++ = (byte & 128) ? 0 : 255; + default: + *out++ = (byte & 128) ? 0 : 255; + byte <<= 1; + case 7: + *out++ = (byte & 128) ? 0 : 255; + byte <<= 1; + case 6: + *out++ = (byte & 128) ? 0 : 255; + byte <<= 1; + case 5: + *out++ = (byte & 128) ? 0 : 255; + byte <<= 1; + case 4: + *out++ = (byte & 128) ? 0 : 255; + byte <<= 1; + case 3: + *out++ = (byte & 128) ? 0 : 255; + byte <<= 1; + case 2: + *out++ = (byte & 128) ? 0 : 255; + byte <<= 1; + case 1: + *out++ = (byte & 128) ? 0 : 255; } pixels -= 8; } } static void -unpack1R(UINT8* out, const UINT8* in, int pixels) -{ +unpack1R(UINT8 *out, const UINT8 *in, int pixels) { /* bits (lsb first, white is non-zero) */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = (byte & 1) ? 255 : 0; byte >>= 1; - case 7: *out++ = (byte & 1) ? 255 : 0; byte >>= 1; - case 6: *out++ = (byte & 1) ? 255 : 0; byte >>= 1; - case 5: *out++ = (byte & 1) ? 255 : 0; byte >>= 1; - case 4: *out++ = (byte & 1) ? 255 : 0; byte >>= 1; - case 3: *out++ = (byte & 1) ? 255 : 0; byte >>= 1; - case 2: *out++ = (byte & 1) ? 255 : 0; byte >>= 1; - case 1: *out++ = (byte & 1) ? 255 : 0; + default: + *out++ = (byte & 1) ? 255 : 0; + byte >>= 1; + case 7: + *out++ = (byte & 1) ? 255 : 0; + byte >>= 1; + case 6: + *out++ = (byte & 1) ? 255 : 0; + byte >>= 1; + case 5: + *out++ = (byte & 1) ? 255 : 0; + byte >>= 1; + case 4: + *out++ = (byte & 1) ? 255 : 0; + byte >>= 1; + case 3: + *out++ = (byte & 1) ? 255 : 0; + byte >>= 1; + case 2: + *out++ = (byte & 1) ? 255 : 0; + byte >>= 1; + case 1: + *out++ = (byte & 1) ? 255 : 0; } pixels -= 8; } } static void -unpack1IR(UINT8* out, const UINT8* in, int pixels) -{ +unpack1IR(UINT8 *out, const UINT8 *in, int pixels) { /* bits (lsb first, white is zero) */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = (byte & 1) ? 0 : 255; byte >>= 1; - case 7: *out++ = (byte & 1) ? 0 : 255; byte >>= 1; - case 6: *out++ = (byte & 1) ? 0 : 255; byte >>= 1; - case 5: *out++ = (byte & 1) ? 0 : 255; byte >>= 1; - case 4: *out++ = (byte & 1) ? 0 : 255; byte >>= 1; - case 3: *out++ = (byte & 1) ? 0 : 255; byte >>= 1; - case 2: *out++ = (byte & 1) ? 0 : 255; byte >>= 1; - case 1: *out++ = (byte & 1) ? 0 : 255; + default: + *out++ = (byte & 1) ? 0 : 255; + byte >>= 1; + case 7: + *out++ = (byte & 1) ? 0 : 255; + byte >>= 1; + case 6: + *out++ = (byte & 1) ? 0 : 255; + byte >>= 1; + case 5: + *out++ = (byte & 1) ? 0 : 255; + byte >>= 1; + case 4: + *out++ = (byte & 1) ? 0 : 255; + byte >>= 1; + case 3: + *out++ = (byte & 1) ? 0 : 255; + byte >>= 1; + case 2: + *out++ = (byte & 1) ? 0 : 255; + byte >>= 1; + case 1: + *out++ = (byte & 1) ? 0 : 255; } pixels -= 8; } } static void -unpack18(UINT8* out, const UINT8* in, int pixels) -{ +unpack18(UINT8 *out, const UINT8 *in, int pixels) { /* Unpack a '|b1' image, which is a numpy boolean. 1 == true, 0==false, in bytes */ @@ -194,160 +254,188 @@ unpack18(UINT8* out, const UINT8* in, int pixels) } } - - /* Unpack to "L" image */ static void -unpackL2(UINT8* out, const UINT8* in, int pixels) -{ +unpackL2(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles (msb first, white is non-zero) */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2; - case 3: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2; - case 2: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2; - case 1: *out++ = ((byte >> 6) & 0x03U) * 0x55U; + default: + *out++ = ((byte >> 6) & 0x03U) * 0x55U; + byte <<= 2; + case 3: + *out++ = ((byte >> 6) & 0x03U) * 0x55U; + byte <<= 2; + case 2: + *out++ = ((byte >> 6) & 0x03U) * 0x55U; + byte <<= 2; + case 1: + *out++ = ((byte >> 6) & 0x03U) * 0x55U; } pixels -= 4; } } static void -unpackL2I(UINT8* out, const UINT8* in, int pixels) -{ +unpackL2I(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles (msb first, white is zero) */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2; - case 3: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2; - case 2: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2; - case 1: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); + default: + *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); + byte <<= 2; + case 3: + *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); + byte <<= 2; + case 2: + *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); + byte <<= 2; + case 1: + *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); } pixels -= 4; } } static void -unpackL2R(UINT8* out, const UINT8* in, int pixels) -{ +unpackL2R(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles (bit order reversed, white is non-zero) */ while (pixels > 0) { UINT8 byte = *in++; byte = BITFLIP[byte]; switch (pixels) { - default: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2; - case 3: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2; - case 2: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2; - case 1: *out++ = ((byte >> 6) & 0x03U) * 0x55U; + default: + *out++ = ((byte >> 6) & 0x03U) * 0x55U; + byte <<= 2; + case 3: + *out++ = ((byte >> 6) & 0x03U) * 0x55U; + byte <<= 2; + case 2: + *out++ = ((byte >> 6) & 0x03U) * 0x55U; + byte <<= 2; + case 1: + *out++ = ((byte >> 6) & 0x03U) * 0x55U; } pixels -= 4; } } static void -unpackL2IR(UINT8* out, const UINT8* in, int pixels) -{ +unpackL2IR(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles (bit order reversed, white is zero) */ while (pixels > 0) { UINT8 byte = *in++; byte = BITFLIP[byte]; switch (pixels) { - default: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2; - case 3: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2; - case 2: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2; - case 1: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); + default: + *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); + byte <<= 2; + case 3: + *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); + byte <<= 2; + case 2: + *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); + byte <<= 2; + case 1: + *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); } pixels -= 4; } } static void -unpackL4(UINT8* out, const UINT8* in, int pixels) -{ +unpackL4(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles (msb first, white is non-zero) */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = ((byte >> 4) & 0x0FU) * 0x11U; byte <<= 4; - case 1: *out++ = ((byte >> 4) & 0x0FU) * 0x11U; + default: + *out++ = ((byte >> 4) & 0x0FU) * 0x11U; + byte <<= 4; + case 1: + *out++ = ((byte >> 4) & 0x0FU) * 0x11U; } pixels -= 2; } } static void -unpackL4I(UINT8* out, const UINT8* in, int pixels) -{ +unpackL4I(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles (msb first, white is zero) */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); byte <<= 4; - case 1: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); + default: + *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); + byte <<= 4; + case 1: + *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); } pixels -= 2; } } static void -unpackL4R(UINT8* out, const UINT8* in, int pixels) -{ +unpackL4R(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles (bit order reversed, white is non-zero) */ while (pixels > 0) { UINT8 byte = *in++; byte = BITFLIP[byte]; switch (pixels) { - default: *out++ = ((byte >> 4) & 0x0FU) * 0x11U; byte <<= 4; - case 1: *out++ = ((byte >> 4) & 0x0FU) * 0x11U; + default: + *out++ = ((byte >> 4) & 0x0FU) * 0x11U; + byte <<= 4; + case 1: + *out++ = ((byte >> 4) & 0x0FU) * 0x11U; } pixels -= 2; } } static void -unpackL4IR(UINT8* out, const UINT8* in, int pixels) -{ +unpackL4IR(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles (bit order reversed, white is zero) */ while (pixels > 0) { UINT8 byte = *in++; byte = BITFLIP[byte]; switch (pixels) { - default: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); byte <<= 4; - case 1: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); + default: + *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); + byte <<= 4; + case 1: + *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); } pixels -= 2; } } static void -unpackLA(UINT8* _out, const UINT8* in, int pixels) -{ +unpackLA(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* LA, pixel interleaved */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[1]); memcpy(_out, &iv, sizeof(iv)); - in += 2; _out += 4; + in += 2; + _out += 4; } } static void -unpackLAL(UINT8* _out, const UINT8* in, int pixels) -{ +unpackLAL(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* LA, line interleaved */ - for (i = 0; i < pixels; i++, _out+=4) { - UINT32 iv = MAKE_UINT32(in[i], in[i], in[i], in[i+pixels]); + for (i = 0; i < pixels; i++, _out += 4) { + UINT32 iv = MAKE_UINT32(in[i], in[i], in[i], in[i + pixels]); memcpy(_out, &iv, sizeof(iv)); } } static void -unpackLI(UINT8* out, const UINT8* in, int pixels) -{ +unpackLI(UINT8 *out, const UINT8 *in, int pixels) { /* negative */ int i; for (i = 0; i < pixels; i++) { @@ -356,8 +444,7 @@ unpackLI(UINT8* out, const UINT8* in, int pixels) } static void -unpackLR(UINT8* out, const UINT8* in, int pixels) -{ +unpackLR(UINT8 *out, const UINT8 *in, int pixels) { int i; /* RGB, bit reversed */ for (i = 0; i < pixels; i++) { @@ -366,8 +453,7 @@ unpackLR(UINT8* out, const UINT8* in, int pixels) } static void -unpackL16(UINT8* out, const UINT8* in, int pixels) -{ +unpackL16(UINT8 *out, const UINT8 *in, int pixels) { /* int16 (upper byte, little endian) */ int i; for (i = 0; i < pixels; i++) { @@ -377,8 +463,7 @@ unpackL16(UINT8* out, const UINT8* in, int pixels) } static void -unpackL16B(UINT8* out, const UINT8* in, int pixels) -{ +unpackL16B(UINT8 *out, const UINT8 *in, int pixels) { int i; /* int16 (upper byte, big endian) */ for (i = 0; i < pixels; i++) { @@ -387,66 +472,86 @@ unpackL16B(UINT8* out, const UINT8* in, int pixels) } } - /* Unpack to "P" image */ static void -unpackP1(UINT8* out, const UINT8* in, int pixels) -{ +unpackP1(UINT8 *out, const UINT8 *in, int pixels) { /* bits */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = (byte >> 7) & 1; byte <<= 1; - case 7: *out++ = (byte >> 7) & 1; byte <<= 1; - case 6: *out++ = (byte >> 7) & 1; byte <<= 1; - case 5: *out++ = (byte >> 7) & 1; byte <<= 1; - case 4: *out++ = (byte >> 7) & 1; byte <<= 1; - case 3: *out++ = (byte >> 7) & 1; byte <<= 1; - case 2: *out++ = (byte >> 7) & 1; byte <<= 1; - case 1: *out++ = (byte >> 7) & 1; + default: + *out++ = (byte >> 7) & 1; + byte <<= 1; + case 7: + *out++ = (byte >> 7) & 1; + byte <<= 1; + case 6: + *out++ = (byte >> 7) & 1; + byte <<= 1; + case 5: + *out++ = (byte >> 7) & 1; + byte <<= 1; + case 4: + *out++ = (byte >> 7) & 1; + byte <<= 1; + case 3: + *out++ = (byte >> 7) & 1; + byte <<= 1; + case 2: + *out++ = (byte >> 7) & 1; + byte <<= 1; + case 1: + *out++ = (byte >> 7) & 1; } pixels -= 8; } } static void -unpackP2(UINT8* out, const UINT8* in, int pixels) -{ +unpackP2(UINT8 *out, const UINT8 *in, int pixels) { /* bit pairs */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = (byte >> 6) & 3; byte <<= 2; - case 3: *out++ = (byte >> 6) & 3; byte <<= 2; - case 2: *out++ = (byte >> 6) & 3; byte <<= 2; - case 1: *out++ = (byte >> 6) & 3; + default: + *out++ = (byte >> 6) & 3; + byte <<= 2; + case 3: + *out++ = (byte >> 6) & 3; + byte <<= 2; + case 2: + *out++ = (byte >> 6) & 3; + byte <<= 2; + case 1: + *out++ = (byte >> 6) & 3; } pixels -= 4; } } static void -unpackP4(UINT8* out, const UINT8* in, int pixels) -{ +unpackP4(UINT8 *out, const UINT8 *in, int pixels) { /* nibbles */ while (pixels > 0) { UINT8 byte = *in++; switch (pixels) { - default: *out++ = (byte >> 4) & 15; byte <<= 4; - case 1: *out++ = (byte >> 4) & 15; + default: + *out++ = (byte >> 4) & 15; + byte <<= 4; + case 1: + *out++ = (byte >> 4) & 15; } pixels -= 2; } } static void -unpackP2L(UINT8* out, const UINT8* in, int pixels) -{ +unpackP2L(UINT8 *out, const UINT8 *in, int pixels) { int i, j, m, s; /* bit layers */ m = 128; - s = (pixels+7)/8; + s = (pixels + 7) / 8; for (i = j = 0; i < pixels; i++) { out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0); if ((m >>= 1) == 0) { @@ -457,15 +562,14 @@ unpackP2L(UINT8* out, const UINT8* in, int pixels) } static void -unpackP4L(UINT8* out, const UINT8* in, int pixels) -{ +unpackP4L(UINT8 *out, const UINT8 *in, int pixels) { int i, j, m, s; /* bit layers (trust the optimizer ;-) */ m = 128; - s = (pixels+7)/8; + s = (pixels + 7) / 8; for (i = j = 0; i < pixels; i++) { out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0) + - ((in[j + 2*s] & m) ? 4 : 0) + ((in[j + 3*s] & m) ? 8 : 0); + ((in[j + 2 * s] & m) ? 4 : 0) + ((in[j + 3 * s] & m) ? 8 : 0); if ((m >>= 1) == 0) { m = 128; j++; @@ -473,403 +577,410 @@ unpackP4L(UINT8* out, const UINT8* in, int pixels) } } - /* Unpack to "RGB" image */ void -ImagingUnpackRGB(UINT8* _out, const UINT8* in, int pixels) -{ +ImagingUnpackRGB(UINT8 *_out, const UINT8 *in, int pixels) { int i = 0; /* RGB triplets */ - for (; i < pixels-1; i++) { + for (; i < pixels - 1; i++) { UINT32 iv; memcpy(&iv, in, sizeof(iv)); iv |= MASK_UINT32_CHANNEL_3; memcpy(_out, &iv, sizeof(iv)); - in += 3; _out += 4; + in += 3; + _out += 4; } for (; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[0], in[1], in[2], 255); memcpy(_out, &iv, sizeof(iv)); - in += 3; _out += 4; + in += 3; + _out += 4; } } void -unpackRGB16L(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGB16L(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* 16-bit RGB triplets, little-endian order */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[1], in[3], in[5], 255); memcpy(_out, &iv, sizeof(iv)); - in += 6; _out += 4; + in += 6; + _out += 4; } } void -unpackRGB16B(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGB16B(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* 16-bit RGB triplets, big-endian order */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[0], in[2], in[4], 255); memcpy(_out, &iv, sizeof(iv)); - in += 6; _out += 4; + in += 6; + _out += 4; } } static void -unpackRGBL(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBL(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGB, line interleaved */ - for (i = 0; i < pixels; i++, _out+=4) { - UINT32 iv = MAKE_UINT32(in[i], in[i+pixels], in[i+pixels+pixels], 255); + for (i = 0; i < pixels; i++, _out += 4) { + UINT32 iv = MAKE_UINT32(in[i], in[i + pixels], in[i + pixels + pixels], 255); memcpy(_out, &iv, sizeof(iv)); } } static void -unpackRGBR(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBR(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGB, bit reversed */ for (i = 0; i < pixels; i++) { - UINT32 iv = MAKE_UINT32(BITFLIP[in[0]], BITFLIP[in[1]], - BITFLIP[in[2]], 255); + UINT32 iv = MAKE_UINT32(BITFLIP[in[0]], BITFLIP[in[1]], BITFLIP[in[2]], 255); memcpy(_out, &iv, sizeof(iv)); - in += 3; _out += 4; + in += 3; + _out += 4; } } void -ImagingUnpackBGR(UINT8* _out, const UINT8* in, int pixels) -{ +ImagingUnpackBGR(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGB, reversed bytes */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], 255); memcpy(_out, &iv, sizeof(iv)); - in += 3; _out += 4; + in += 3; + _out += 4; } } void -ImagingUnpackRGB15(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackRGB15(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; /* RGB, 5 bits per pixel */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[R] = (pixel & 31) * 255 / 31; - out[G] = ((pixel>>5) & 31) * 255 / 31; - out[B] = ((pixel>>10) & 31) * 255 / 31; + out[G] = ((pixel >> 5) & 31) * 255 / 31; + out[B] = ((pixel >> 10) & 31) * 255 / 31; out[A] = 255; - out += 4; in += 2; + out += 4; + in += 2; } } void -ImagingUnpackRGBA15(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackRGBA15(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; /* RGB, 5/5/5/1 bits per pixel */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[R] = (pixel & 31) * 255 / 31; - out[G] = ((pixel>>5) & 31) * 255 / 31; - out[B] = ((pixel>>10) & 31) * 255 / 31; - out[A] = (pixel>>15) * 255; - out += 4; in += 2; + out[G] = ((pixel >> 5) & 31) * 255 / 31; + out[B] = ((pixel >> 10) & 31) * 255 / 31; + out[A] = (pixel >> 15) * 255; + out += 4; + in += 2; } } void -ImagingUnpackBGR15(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackBGR15(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; /* RGB, reversed bytes, 5 bits per pixel */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[B] = (pixel & 31) * 255 / 31; - out[G] = ((pixel>>5) & 31) * 255 / 31; - out[R] = ((pixel>>10) & 31) * 255 / 31; + out[G] = ((pixel >> 5) & 31) * 255 / 31; + out[R] = ((pixel >> 10) & 31) * 255 / 31; out[A] = 255; - out += 4; in += 2; + out += 4; + in += 2; } } void -ImagingUnpackBGRA15(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackBGRA15(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; /* RGB, reversed bytes, 5/5/5/1 bits per pixel */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[B] = (pixel & 31) * 255 / 31; - out[G] = ((pixel>>5) & 31) * 255 / 31; - out[R] = ((pixel>>10) & 31) * 255 / 31; - out[A] = (pixel>>15) * 255; - out += 4; in += 2; + out[G] = ((pixel >> 5) & 31) * 255 / 31; + out[R] = ((pixel >> 10) & 31) * 255 / 31; + out[A] = (pixel >> 15) * 255; + out += 4; + in += 2; } } void -ImagingUnpackRGB16(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackRGB16(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; /* RGB, 5/6/5 bits per pixel */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[R] = (pixel & 31) * 255 / 31; - out[G] = ((pixel>>5) & 63) * 255 / 63; - out[B] = ((pixel>>11) & 31) * 255 / 31; + out[G] = ((pixel >> 5) & 63) * 255 / 63; + out[B] = ((pixel >> 11) & 31) * 255 / 31; out[A] = 255; - out += 4; in += 2; + out += 4; + in += 2; } } void -ImagingUnpackBGR16(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackBGR16(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; /* RGB, reversed bytes, 5/6/5 bits per pixel */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[B] = (pixel & 31) * 255 / 31; - out[G] = ((pixel>>5) & 63) * 255 / 63; - out[R] = ((pixel>>11) & 31) * 255 / 31; + out[G] = ((pixel >> 5) & 63) * 255 / 63; + out[R] = ((pixel >> 11) & 31) * 255 / 31; out[A] = 255; - out += 4; in += 2; + out += 4; + in += 2; } } void -ImagingUnpackRGB4B(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackRGB4B(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; /* RGB, 4 bits per pixel */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[R] = (pixel & 15) * 17; - out[G] = ((pixel>>4) & 15) * 17; - out[B] = ((pixel>>8) & 15) * 17; + out[G] = ((pixel >> 4) & 15) * 17; + out[B] = ((pixel >> 8) & 15) * 17; out[A] = 255; - out += 4; in += 2; + out += 4; + in += 2; } } void -ImagingUnpackRGBA4B(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackRGBA4B(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; /* RGBA, 4 bits per pixel */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[R] = (pixel & 15) * 17; - out[G] = ((pixel>>4) & 15) * 17; - out[B] = ((pixel>>8) & 15) * 17; - out[A] = ((pixel>>12) & 15) * 17; - out += 4; in += 2; + out[G] = ((pixel >> 4) & 15) * 17; + out[B] = ((pixel >> 8) & 15) * 17; + out[A] = ((pixel >> 12) & 15) * 17; + out += 4; + in += 2; } } static void -ImagingUnpackBGRX(UINT8* _out, const UINT8* in, int pixels) -{ +ImagingUnpackBGRX(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGB, reversed bytes with padding */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], 255); memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } static void -ImagingUnpackXRGB(UINT8* _out, const UINT8* in, int pixels) -{ +ImagingUnpackXRGB(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGB, leading pad */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[1], in[2], in[3], 255); memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } static void -ImagingUnpackXBGR(UINT8* _out, const UINT8* in, int pixels) -{ +ImagingUnpackXBGR(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGB, reversed bytes, leading pad */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[3], in[2], in[1], 255); memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } /* Unpack to "RGBA" image */ static void -unpackRGBALA(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBALA(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* greyscale with alpha */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[1]); memcpy(_out, &iv, sizeof(iv)); - in += 2; _out += 4; + in += 2; + _out += 4; } } static void -unpackRGBALA16B(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBALA16B(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* 16-bit greyscale with alpha, big-endian */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[2]); memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } static void -unpackRGBa16L(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBa16L(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* premultiplied 16-bit RGBA, little-endian */ for (i = 0; i < pixels; i++) { int a = in[7]; UINT32 iv; - if ( ! a) { + if (!a) { iv = 0; } else if (a == 255) { iv = MAKE_UINT32(in[1], in[3], in[5], a); } else { - iv = MAKE_UINT32(CLIP8(in[1] * 255 / a), - CLIP8(in[3] * 255 / a), - CLIP8(in[5] * 255 / a), a); + iv = MAKE_UINT32( + CLIP8(in[1] * 255 / a), + CLIP8(in[3] * 255 / a), + CLIP8(in[5] * 255 / a), + a); } memcpy(_out, &iv, sizeof(iv)); - in += 8; _out += 4; + in += 8; + _out += 4; } } static void -unpackRGBa16B(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBa16B(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* premultiplied 16-bit RGBA, big-endian */ for (i = 0; i < pixels; i++) { int a = in[6]; UINT32 iv; - if ( ! a) { + if (!a) { iv = 0; } else if (a == 255) { iv = MAKE_UINT32(in[0], in[2], in[4], a); } else { - iv = MAKE_UINT32(CLIP8(in[0] * 255 / a), - CLIP8(in[2] * 255 / a), - CLIP8(in[4] * 255 / a), a); + iv = MAKE_UINT32( + CLIP8(in[0] * 255 / a), + CLIP8(in[2] * 255 / a), + CLIP8(in[4] * 255 / a), + a); } memcpy(_out, &iv, sizeof(iv)); - in += 8; _out += 4; + in += 8; + _out += 4; } } static void -unpackRGBa(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBa(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* premultiplied RGBA */ for (i = 0; i < pixels; i++) { int a = in[3]; UINT32 iv; - if ( ! a) { + if (!a) { iv = 0; } else if (a == 255) { iv = MAKE_UINT32(in[0], in[1], in[2], a); } else { - iv = MAKE_UINT32(CLIP8(in[0] * 255 / a), - CLIP8(in[1] * 255 / a), - CLIP8(in[2] * 255 / a), a); + iv = MAKE_UINT32( + CLIP8(in[0] * 255 / a), + CLIP8(in[1] * 255 / a), + CLIP8(in[2] * 255 / a), + a); } memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } static void -unpackRGBaskip1(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBaskip1(UINT8 *_out, const UINT8 *in, int pixels) { int i; - UINT32* out = (UINT32*) _out; + UINT32 *out = (UINT32 *)_out; /* premultiplied RGBA */ for (i = 0; i < pixels; i++) { int a = in[3]; - if ( ! a) { + if (!a) { out[i] = 0; } else if (a == 255) { out[i] = MAKE_UINT32(in[0], in[1], in[2], a); } else { - out[i] = MAKE_UINT32(CLIP8(in[0] * 255 / a), - CLIP8(in[1] * 255 / a), - CLIP8(in[2] * 255 / a), a); + out[i] = MAKE_UINT32( + CLIP8(in[0] * 255 / a), + CLIP8(in[1] * 255 / a), + CLIP8(in[2] * 255 / a), + a); } in += 5; } } static void -unpackRGBaskip2(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBaskip2(UINT8 *_out, const UINT8 *in, int pixels) { int i; - UINT32* out = (UINT32*) _out; + UINT32 *out = (UINT32 *)_out; /* premultiplied RGBA */ for (i = 0; i < pixels; i++) { int a = in[3]; - if ( ! a) { + if (!a) { out[i] = 0; } else if (a == 255) { out[i] = MAKE_UINT32(in[0], in[1], in[2], a); } else { - out[i] = MAKE_UINT32(CLIP8(in[0] * 255 / a), - CLIP8(in[1] * 255 / a), - CLIP8(in[2] * 255 / a), a); + out[i] = MAKE_UINT32( + CLIP8(in[0] * 255 / a), + CLIP8(in[1] * 255 / a), + CLIP8(in[2] * 255 / a), + a); } in += 6; } } static void -unpackBGRa(UINT8* _out, const UINT8* in, int pixels) -{ +unpackBGRa(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* premultiplied BGRA */ for (i = 0; i < pixels; i++) { int a = in[3]; UINT32 iv; - if ( ! a) { + if (!a) { iv = 0; } else if (a == 255) { iv = MAKE_UINT32(in[2], in[1], in[0], a); } else { - iv = MAKE_UINT32(CLIP8(in[2] * 255 / a), - CLIP8(in[1] * 255 / a), - CLIP8(in[0] * 255 / a), a); + iv = MAKE_UINT32( + CLIP8(in[2] * 255 / a), + CLIP8(in[1] * 255 / a), + CLIP8(in[0] * 255 / a), + a); } memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } static void -unpackRGBAI(UINT8* out, const UINT8* in, int pixels) -{ +unpackRGBAI(UINT8 *out, const UINT8 *in, int pixels) { int i; /* RGBA, inverted RGB bytes (FlashPix) */ for (i = 0; i < pixels; i++) { @@ -877,28 +988,30 @@ unpackRGBAI(UINT8* out, const UINT8* in, int pixels) out[G] = ~in[1]; out[B] = ~in[2]; out[A] = in[3]; - out += 4; in += 4; + out += 4; + in += 4; } } static void -unpackRGBAL(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBAL(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGBA, line interleaved */ - for (i = 0; i < pixels; i++, _out+=4) { - UINT32 iv = MAKE_UINT32(in[i], in[i+pixels], in[i+pixels+pixels], - in[i+pixels+pixels+pixels]); + for (i = 0; i < pixels; i++, _out += 4) { + UINT32 iv = MAKE_UINT32( + in[i], + in[i + pixels], + in[i + pixels + pixels], + in[i + pixels + pixels + pixels]); memcpy(_out, &iv, sizeof(iv)); } } void -unpackRGBA16L(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBA16L(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* 16-bit RGBA, little-endian order */ - for (i = 0; i < pixels; i++, _out+=4) { + for (i = 0; i < pixels; i++, _out += 4) { UINT32 iv = MAKE_UINT32(in[1], in[3], in[5], in[7]); memcpy(_out, &iv, sizeof(iv)); in += 8; @@ -906,11 +1019,10 @@ unpackRGBA16L(UINT8* _out, const UINT8* in, int pixels) } void -unpackRGBA16B(UINT8* _out, const UINT8* in, int pixels) -{ +unpackRGBA16B(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* 16-bit RGBA, big-endian order */ - for (i = 0; i < pixels; i++, _out+=4) { + for (i = 0; i < pixels; i++, _out += 4) { UINT32 iv = MAKE_UINT32(in[0], in[2], in[4], in[6]); memcpy(_out, &iv, sizeof(iv)); in += 8; @@ -918,53 +1030,52 @@ unpackRGBA16B(UINT8* _out, const UINT8* in, int pixels) } static void -unpackARGB(UINT8* _out, const UINT8* in, int pixels) -{ +unpackARGB(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGBA, leading pad */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[1], in[2], in[3], in[0]); memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } static void -unpackABGR(UINT8* _out, const UINT8* in, int pixels) -{ +unpackABGR(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGBA, reversed bytes */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[3], in[2], in[1], in[0]); memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } static void -unpackBGRA(UINT8* _out, const UINT8* in, int pixels) -{ +unpackBGRA(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* RGBA, reversed bytes */ for (i = 0; i < pixels; i++) { UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], in[3]); memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } - /* Unpack to "CMYK" image */ static void -unpackCMYKI(UINT8* _out, const UINT8* in, int pixels) -{ +unpackCMYKI(UINT8 *_out, const UINT8 *in, int pixels) { int i; /* CMYK, inverted bytes (Photoshop 2.5) */ for (i = 0; i < pixels; i++) { UINT32 iv = ~MAKE_UINT32(in[0], in[1], in[2], in[3]); memcpy(_out, &iv, sizeof(iv)); - in += 4; _out += 4; + in += 4; + _out += 4; } } @@ -980,8 +1091,7 @@ unpackCMYKI(UINT8* _out, const UINT8* in, int pixels) internally, and we'll unshift for saving and whatnot. */ void -ImagingUnpackLAB(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackLAB(UINT8 *out, const UINT8 *in, int pixels) { int i; /* LAB triplets */ for (i = 0; i < pixels; i++) { @@ -989,32 +1099,34 @@ ImagingUnpackLAB(UINT8* out, const UINT8* in, int pixels) out[1] = in[1] ^ 128; /* signed in outside world */ out[2] = in[2] ^ 128; out[3] = 255; - out += 4; in += 3; + out += 4; + in += 3; } } static void -unpackI16N_I16B(UINT8* out, const UINT8* in, int pixels){ +unpackI16N_I16B(UINT8 *out, const UINT8 *in, int pixels) { int i; - UINT8* tmp = (UINT8*) out; + UINT8 *tmp = (UINT8 *)out; for (i = 0; i < pixels; i++) { C16B; - in += 2; tmp += 2; + in += 2; + tmp += 2; } - } static void -unpackI16N_I16(UINT8* out, const UINT8* in, int pixels){ +unpackI16N_I16(UINT8 *out, const UINT8 *in, int pixels) { int i; - UINT8* tmp = (UINT8*) out; + UINT8 *tmp = (UINT8 *)out; for (i = 0; i < pixels; i++) { C16L; - in += 2; tmp += 2; + in += 2; + tmp += 2; } } static void -unpackI12_I16(UINT8* out, const UINT8* in, int pixels){ +unpackI12_I16(UINT8 *out, const UINT8 *in, int pixels) { /* Fillorder 1/MSB -> LittleEndian, for 12bit integer greyscale tiffs. According to the TIFF spec: @@ -1036,103 +1148,100 @@ unpackI12_I16(UINT8* out, const UINT8* in, int pixels){ int i; UINT16 pixel; #ifdef WORDS_BIGENDIAN - UINT8* tmp = (UINT8 *)&pixel; + UINT8 *tmp = (UINT8 *)&pixel; #endif - for (i = 0; i < pixels-1; i+=2) { - pixel = (((UINT16) in[0]) << 4 ) + (in[1] >>4); + for (i = 0; i < pixels - 1; i += 2) { + pixel = (((UINT16)in[0]) << 4) + (in[1] >> 4); #ifdef WORDS_BIGENDIAN - out[0] = tmp[1]; out[1] = tmp[0]; + out[0] = tmp[1]; + out[1] = tmp[0]; #else memcpy(out, &pixel, sizeof(pixel)); #endif - out+=2; - pixel = (((UINT16) (in[1] & 0x0F)) << 8) + in[2]; + out += 2; + pixel = (((UINT16)(in[1] & 0x0F)) << 8) + in[2]; #ifdef WORDS_BIGENDIAN - out[0] = tmp[1]; out[1] = tmp[0]; + out[0] = tmp[1]; + out[1] = tmp[0]; #else memcpy(out, &pixel, sizeof(pixel)); #endif - in += 3; out+=2; + in += 3; + out += 2; } - if (i == pixels-1) { - pixel = (((UINT16) in[0]) << 4 ) + (in[1] >>4); + if (i == pixels - 1) { + pixel = (((UINT16)in[0]) << 4) + (in[1] >> 4); #ifdef WORDS_BIGENDIAN - out[0] = tmp[1]; out[1] = tmp[0]; + out[0] = tmp[1]; + out[1] = tmp[0]; #else memcpy(out, &pixel, sizeof(pixel)); #endif } } - static void -copy1(UINT8* out, const UINT8* in, int pixels) -{ +copy1(UINT8 *out, const UINT8 *in, int pixels) { /* L, P */ memcpy(out, in, pixels); } static void -copy2(UINT8* out, const UINT8* in, int pixels) -{ +copy2(UINT8 *out, const UINT8 *in, int pixels) { /* I;16 */ - memcpy(out, in, pixels*2); + memcpy(out, in, pixels * 2); } static void -copy4(UINT8* out, const UINT8* in, int pixels) -{ +copy4(UINT8 *out, const UINT8 *in, int pixels) { /* RGBA, CMYK quadruples */ memcpy(out, in, 4 * pixels); } static void -copy4skip1(UINT8* _out, const UINT8* in, int pixels) -{ +copy4skip1(UINT8 *_out, const UINT8 *in, int pixels) { int i; for (i = 0; i < pixels; i++) { memcpy(_out, in, 4); - in += 5; _out += 4; + in += 5; + _out += 4; } } static void -copy4skip2(UINT8* _out, const UINT8* in, int pixels) -{ +copy4skip2(UINT8 *_out, const UINT8 *in, int pixels) { int i; for (i = 0; i < pixels; i++) { memcpy(_out, in, 4); - in += 6; _out += 4; + in += 6; + _out += 4; } } - /* Unpack to "I" and "F" images */ -#define UNPACK_RAW(NAME, GET, INTYPE, OUTTYPE)\ -static void NAME(UINT8* out_, const UINT8* in, int pixels)\ -{\ - int i;\ - OUTTYPE* out = (OUTTYPE*) out_;\ - for (i = 0; i < pixels; i++, in += sizeof(INTYPE)) {\ - out[i] = (OUTTYPE) ((INTYPE) GET);\ - }\ -} +#define UNPACK_RAW(NAME, GET, INTYPE, OUTTYPE) \ + static void NAME(UINT8 *out_, const UINT8 *in, int pixels) { \ + int i; \ + OUTTYPE *out = (OUTTYPE *)out_; \ + for (i = 0; i < pixels; i++, in += sizeof(INTYPE)) { \ + out[i] = (OUTTYPE)((INTYPE)GET); \ + } \ + } -#define UNPACK(NAME, COPY, INTYPE, OUTTYPE)\ -static void NAME(UINT8* out_, const UINT8* in, int pixels)\ -{\ - int i;\ - OUTTYPE* out = (OUTTYPE*) out_;\ - INTYPE tmp_;\ - UINT8* tmp = (UINT8*) &tmp_;\ - for (i = 0; i < pixels; i++, in += sizeof(INTYPE)) {\ - COPY;\ - out[i] = (OUTTYPE) tmp_;\ - }\ -} +#define UNPACK(NAME, COPY, INTYPE, OUTTYPE) \ + static void NAME(UINT8 *out_, const UINT8 *in, int pixels) { \ + int i; \ + OUTTYPE *out = (OUTTYPE *)out_; \ + INTYPE tmp_; \ + UINT8 *tmp = (UINT8 *)&tmp_; \ + for (i = 0; i < pixels; i++, in += sizeof(INTYPE)) { \ + COPY; \ + out[i] = (OUTTYPE)tmp_; \ + } \ + } UNPACK_RAW(unpackI8, in[0], UINT8, INT32) UNPACK_RAW(unpackI8S, in[0], INT8, INT32) @@ -1172,12 +1281,10 @@ UNPACK(unpackF64BF, C64B, FLOAT64, FLOAT32) UNPACK(unpackF64NF, C64N, FLOAT64, FLOAT32) #endif - /* Misc. unpackers */ static void -band0(UINT8* out, const UINT8* in, int pixels) -{ +band0(UINT8 *out, const UINT8 *in, int pixels) { int i; /* band 0 only */ for (i = 0; i < pixels; i++) { @@ -1187,8 +1294,7 @@ band0(UINT8* out, const UINT8* in, int pixels) } static void -band1(UINT8* out, const UINT8* in, int pixels) -{ +band1(UINT8 *out, const UINT8 *in, int pixels) { int i; /* band 1 only */ for (i = 0; i < pixels; i++) { @@ -1198,8 +1304,7 @@ band1(UINT8* out, const UINT8* in, int pixels) } static void -band2(UINT8* out, const UINT8* in, int pixels) -{ +band2(UINT8 *out, const UINT8 *in, int pixels) { int i; /* band 2 only */ for (i = 0; i < pixels; i++) { @@ -1209,8 +1314,7 @@ band2(UINT8* out, const UINT8* in, int pixels) } static void -band3(UINT8* out, const UINT8* in, int pixels) -{ +band3(UINT8 *out, const UINT8 *in, int pixels) { /* band 3 only */ int i; for (i = 0; i < pixels; i++) { @@ -1220,8 +1324,7 @@ band3(UINT8* out, const UINT8* in, int pixels) } static void -band0I(UINT8* out, const UINT8* in, int pixels) -{ +band0I(UINT8 *out, const UINT8 *in, int pixels) { int i; /* band 0 only */ for (i = 0; i < pixels; i++) { @@ -1231,8 +1334,7 @@ band0I(UINT8* out, const UINT8* in, int pixels) } static void -band1I(UINT8* out, const UINT8* in, int pixels) -{ +band1I(UINT8 *out, const UINT8 *in, int pixels) { int i; /* band 1 only */ for (i = 0; i < pixels; i++) { @@ -1242,8 +1344,7 @@ band1I(UINT8* out, const UINT8* in, int pixels) } static void -band2I(UINT8* out, const UINT8* in, int pixels) -{ +band2I(UINT8 *out, const UINT8 *in, int pixels) { int i; /* band 2 only */ for (i = 0; i < pixels; i++) { @@ -1253,8 +1354,7 @@ band2I(UINT8* out, const UINT8* in, int pixels) } static void -band3I(UINT8* out, const UINT8* in, int pixels) -{ +band3I(UINT8 *out, const UINT8 *in, int pixels) { /* band 3 only */ int i; for (i = 0; i < pixels; i++) { @@ -1263,9 +1363,97 @@ band3I(UINT8* out, const UINT8* in, int pixels) } } +static void +band016B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 0 only, big endian */ + for (i = 0; i < pixels; i++) { + out[0] = in[0]; + out += 4; in += 2; + } +} + +static void +band116B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 1 only, big endian */ + for (i = 0; i < pixels; i++) { + out[1] = in[0]; + out += 4; in += 2; + } +} + +static void +band216B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 2 only, big endian */ + for (i = 0; i < pixels; i++) { + out[2] = in[0]; + out += 4; in += 2; + } +} + +static void +band316B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 3 only, big endian */ + for (i = 0; i < pixels; i++) { + out[3] = in[0]; + out += 4; in += 2; + } +} + +static void +band016L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 0 only, little endian */ + for (i = 0; i < pixels; i++) { + out[0] = in[1]; + out += 4; in += 2; + } +} + +static void +band116L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 1 only, little endian */ + for (i = 0; i < pixels; i++) { + out[1] = in[1]; + out += 4; in += 2; + } +} + +static void +band216L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 2 only, little endian */ + for (i = 0; i < pixels; i++) { + out[2] = in[1]; + out += 4; in += 2; + } +} + +static void +band316L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 3 only, little endian */ + for (i = 0; i < pixels; i++) { + out[3] = in[1]; + out += 4; in += 2; + } +} + static struct { - const char* mode; - const char* rawmode; + const char *mode; + const char *rawmode; int bits; ImagingShuffler unpack; } unpackers[] = { @@ -1282,244 +1470,273 @@ static struct { /* exception: rawmodes "I" and "F" are always native endian byte order */ /* bilevel */ - {"1", "1", 1, unpack1}, - {"1", "1;I", 1, unpack1I}, - {"1", "1;R", 1, unpack1R}, - {"1", "1;IR", 1, unpack1IR}, - {"1", "1;8", 8, unpack18}, + {"1", "1", 1, unpack1}, + {"1", "1;I", 1, unpack1I}, + {"1", "1;R", 1, unpack1R}, + {"1", "1;IR", 1, unpack1IR}, + {"1", "1;8", 8, unpack18}, /* greyscale */ - {"L", "L;2", 2, unpackL2}, - {"L", "L;2I", 2, unpackL2I}, - {"L", "L;2R", 2, unpackL2R}, - {"L", "L;2IR", 2, unpackL2IR}, + {"L", "L;2", 2, unpackL2}, + {"L", "L;2I", 2, unpackL2I}, + {"L", "L;2R", 2, unpackL2R}, + {"L", "L;2IR", 2, unpackL2IR}, - {"L", "L;4", 4, unpackL4}, - {"L", "L;4I", 4, unpackL4I}, - {"L", "L;4R", 4, unpackL4R}, - {"L", "L;4IR", 4, unpackL4IR}, + {"L", "L;4", 4, unpackL4}, + {"L", "L;4I", 4, unpackL4I}, + {"L", "L;4R", 4, unpackL4R}, + {"L", "L;4IR", 4, unpackL4IR}, - {"L", "L", 8, copy1}, - {"L", "L;I", 8, unpackLI}, - {"L", "L;R", 8, unpackLR}, - {"L", "L;16", 16, unpackL16}, - {"L", "L;16B", 16, unpackL16B}, + {"L", "L", 8, copy1}, + {"L", "L;I", 8, unpackLI}, + {"L", "L;R", 8, unpackLR}, + {"L", "L;16", 16, unpackL16}, + {"L", "L;16B", 16, unpackL16B}, /* greyscale w. alpha */ - {"LA", "LA", 16, unpackLA}, - {"LA", "LA;L", 16, unpackLAL}, + {"LA", "LA", 16, unpackLA}, + {"LA", "LA;L", 16, unpackLAL}, /* greyscale w. alpha premultiplied */ - {"La", "La", 16, unpackLA}, + {"La", "La", 16, unpackLA}, /* palette */ - {"P", "P;1", 1, unpackP1}, - {"P", "P;2", 2, unpackP2}, - {"P", "P;2L", 2, unpackP2L}, - {"P", "P;4", 4, unpackP4}, - {"P", "P;4L", 4, unpackP4L}, - {"P", "P", 8, copy1}, - {"P", "P;R", 8, unpackLR}, + {"P", "P;1", 1, unpackP1}, + {"P", "P;2", 2, unpackP2}, + {"P", "P;2L", 2, unpackP2L}, + {"P", "P;4", 4, unpackP4}, + {"P", "P;4L", 4, unpackP4L}, + {"P", "P", 8, copy1}, + {"P", "P;R", 8, unpackLR}, /* palette w. alpha */ - {"PA", "PA", 16, unpackLA}, - {"PA", "PA;L", 16, unpackLAL}, + {"PA", "PA", 16, unpackLA}, + {"PA", "PA;L", 16, unpackLAL}, /* true colour */ - {"RGB", "RGB", 24, ImagingUnpackRGB}, - {"RGB", "RGB;L", 24, unpackRGBL}, - {"RGB", "RGB;R", 24, unpackRGBR}, - {"RGB", "RGB;16L", 48, unpackRGB16L}, - {"RGB", "RGB;16B", 48, unpackRGB16B}, - {"RGB", "BGR", 24, ImagingUnpackBGR}, - {"RGB", "RGB;15", 16, ImagingUnpackRGB15}, - {"RGB", "BGR;15", 16, ImagingUnpackBGR15}, - {"RGB", "RGB;16", 16, ImagingUnpackRGB16}, - {"RGB", "BGR;16", 16, ImagingUnpackBGR16}, - {"RGB", "RGB;4B", 16, ImagingUnpackRGB4B}, - {"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ - {"RGB", "RGBX", 32, copy4}, - {"RGB", "RGBX;L", 32, unpackRGBAL}, - {"RGB", "RGBA;L", 32, unpackRGBAL}, - {"RGB", "BGRX", 32, ImagingUnpackBGRX}, - {"RGB", "XRGB", 32, ImagingUnpackXRGB}, - {"RGB", "XBGR", 32, ImagingUnpackXBGR}, - {"RGB", "YCC;P", 24, ImagingUnpackYCC}, - {"RGB", "R", 8, band0}, - {"RGB", "G", 8, band1}, - {"RGB", "B", 8, band2}, + {"RGB", "RGB", 24, ImagingUnpackRGB}, + {"RGB", "RGB;L", 24, unpackRGBL}, + {"RGB", "RGB;R", 24, unpackRGBR}, + {"RGB", "RGB;16L", 48, unpackRGB16L}, + {"RGB", "RGB;16B", 48, unpackRGB16B}, + {"RGB", "BGR", 24, ImagingUnpackBGR}, + {"RGB", "RGB;15", 16, ImagingUnpackRGB15}, + {"RGB", "BGR;15", 16, ImagingUnpackBGR15}, + {"RGB", "RGB;16", 16, ImagingUnpackRGB16}, + {"RGB", "BGR;16", 16, ImagingUnpackBGR16}, + {"RGB", "RGB;4B", 16, ImagingUnpackRGB4B}, + {"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ + {"RGB", "RGBX", 32, copy4}, + {"RGB", "RGBX;L", 32, unpackRGBAL}, + {"RGB", "RGBA;L", 32, unpackRGBAL}, + {"RGB", "BGRX", 32, ImagingUnpackBGRX}, + {"RGB", "XRGB", 32, ImagingUnpackXRGB}, + {"RGB", "XBGR", 32, ImagingUnpackXBGR}, + {"RGB", "YCC;P", 24, ImagingUnpackYCC}, + {"RGB", "R", 8, band0}, + {"RGB", "G", 8, band1}, + {"RGB", "B", 8, band2}, + {"RGB", "R;16L", 16, band016L}, + {"RGB", "G;16L", 16, band116L}, + {"RGB", "B;16L", 16, band216L}, + {"RGB", "R;16B", 16, band016B}, + {"RGB", "G;16B", 16, band116B}, + {"RGB", "B;16B", 16, band216B}, /* true colour w. alpha */ - {"RGBA", "LA", 16, unpackRGBALA}, - {"RGBA", "LA;16B", 32, unpackRGBALA16B}, - {"RGBA", "RGBA", 32, copy4}, - {"RGBA", "RGBAX", 40, copy4skip1}, - {"RGBA", "RGBAXX", 48, copy4skip2}, - {"RGBA", "RGBa", 32, unpackRGBa}, - {"RGBA", "RGBaX", 40, unpackRGBaskip1}, - {"RGBA", "RGBaXX", 48, unpackRGBaskip2}, - {"RGBA", "RGBa;16L", 64, unpackRGBa16L}, - {"RGBA", "RGBa;16B", 64, unpackRGBa16B}, - {"RGBA", "BGRa", 32, unpackBGRa}, - {"RGBA", "RGBA;I", 32, unpackRGBAI}, - {"RGBA", "RGBA;L", 32, unpackRGBAL}, - {"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15}, - {"RGBA", "BGRA;15", 16, ImagingUnpackBGRA15}, - {"RGBA", "RGBA;4B", 16, ImagingUnpackRGBA4B}, - {"RGBA", "RGBA;16L", 64, unpackRGBA16L}, - {"RGBA", "RGBA;16B", 64, unpackRGBA16B}, - {"RGBA", "BGRA", 32, unpackBGRA}, - {"RGBA", "ARGB", 32, unpackARGB}, - {"RGBA", "ABGR", 32, unpackABGR}, - {"RGBA", "YCCA;P", 32, ImagingUnpackYCCA}, - {"RGBA", "R", 8, band0}, - {"RGBA", "G", 8, band1}, - {"RGBA", "B", 8, band2}, - {"RGBA", "A", 8, band3}, + {"RGBA", "LA", 16, unpackRGBALA}, + {"RGBA", "LA;16B", 32, unpackRGBALA16B}, + {"RGBA", "RGBA", 32, copy4}, + {"RGBA", "RGBAX", 40, copy4skip1}, + {"RGBA", "RGBAXX", 48, copy4skip2}, + {"RGBA", "RGBa", 32, unpackRGBa}, + {"RGBA", "RGBaX", 40, unpackRGBaskip1}, + {"RGBA", "RGBaXX", 48, unpackRGBaskip2}, + {"RGBA", "RGBa;16L", 64, unpackRGBa16L}, + {"RGBA", "RGBa;16B", 64, unpackRGBa16B}, + {"RGBA", "BGRa", 32, unpackBGRa}, + {"RGBA", "RGBA;I", 32, unpackRGBAI}, + {"RGBA", "RGBA;L", 32, unpackRGBAL}, + {"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15}, + {"RGBA", "BGRA;15", 16, ImagingUnpackBGRA15}, + {"RGBA", "RGBA;4B", 16, ImagingUnpackRGBA4B}, + {"RGBA", "RGBA;16L", 64, unpackRGBA16L}, + {"RGBA", "RGBA;16B", 64, unpackRGBA16B}, + {"RGBA", "BGRA", 32, unpackBGRA}, + {"RGBA", "ARGB", 32, unpackARGB}, + {"RGBA", "ABGR", 32, unpackABGR}, + {"RGBA", "YCCA;P", 32, ImagingUnpackYCCA}, + {"RGBA", "R", 8, band0}, + {"RGBA", "G", 8, band1}, + {"RGBA", "B", 8, band2}, + {"RGBA", "A", 8, band3}, + {"RGBA", "R;16L", 16, band016L}, + {"RGBA", "G;16L", 16, band116L}, + {"RGBA", "B;16L", 16, band216L}, + {"RGBA", "A;16L", 16, band316L}, + {"RGBA", "R;16B", 16, band016B}, + {"RGBA", "G;16B", 16, band116B}, + {"RGBA", "B;16B", 16, band216B}, + {"RGBA", "A;16B", 16, band316B}, #ifdef WORDS_BIGENDIAN - {"RGB", "RGB;16N", 48, unpackRGB16B}, - {"RGBA", "RGBa;16N", 64, unpackRGBa16B}, - {"RGBA", "RGBA;16N", 64, unpackRGBA16B}, - {"RGBX", "RGBX;16N", 64, unpackRGBA16B}, + {"RGB", "RGB;16N", 48, unpackRGB16B}, + {"RGBA", "RGBa;16N", 64, unpackRGBa16B}, + {"RGBA", "RGBA;16N", 64, unpackRGBA16B}, + {"RGBX", "RGBX;16N", 64, unpackRGBA16B}, + {"RGB", "R;16N", 16, band016B}, + {"RGB", "G;16N", 16, band116B}, + {"RGB", "B;16N", 16, band216B}, + + {"RGBA", "R;16N", 16, band016B}, + {"RGBA", "G;16N", 16, band116B}, + {"RGBA", "B;16N", 16, band216B}, + {"RGBA", "A;16N", 16, band316B}, #else - {"RGB", "RGB;16N", 48, unpackRGB16L}, - {"RGBA", "RGBa;16N", 64, unpackRGBa16L}, - {"RGBA", "RGBA;16N", 64, unpackRGBA16L}, - {"RGBX", "RGBX;16N", 64, unpackRGBA16B}, + {"RGB", "RGB;16N", 48, unpackRGB16L}, + {"RGBA", "RGBa;16N", 64, unpackRGBa16L}, + {"RGBA", "RGBA;16N", 64, unpackRGBA16L}, + {"RGBX", "RGBX;16N", 64, unpackRGBA16L}, + {"RGB", "R;16N", 16, band016L}, + {"RGB", "G;16N", 16, band116L}, + {"RGB", "B;16N", 16, band216L}, + + + {"RGBA", "R;16N", 16, band016L}, + {"RGBA", "G;16N", 16, band116L}, + {"RGBA", "B;16N", 16, band216L}, + {"RGBA", "A;16N", 16, band316L}, #endif /* true colour w. alpha premultiplied */ - {"RGBa", "RGBa", 32, copy4}, - {"RGBa", "BGRa", 32, unpackBGRA}, - {"RGBa", "aRGB", 32, unpackARGB}, - {"RGBa", "aBGR", 32, unpackABGR}, + {"RGBa", "RGBa", 32, copy4}, + {"RGBa", "BGRa", 32, unpackBGRA}, + {"RGBa", "aRGB", 32, unpackARGB}, + {"RGBa", "aBGR", 32, unpackABGR}, /* true colour w. padding */ - {"RGBX", "RGB", 24, ImagingUnpackRGB}, - {"RGBX", "RGB;L", 24, unpackRGBL}, - {"RGBX", "RGB;16B", 48, unpackRGB16B}, - {"RGBX", "BGR", 24, ImagingUnpackBGR}, - {"RGBX", "RGB;15", 16, ImagingUnpackRGB15}, - {"RGBX", "BGR;15", 16, ImagingUnpackBGR15}, - {"RGBX", "RGB;4B", 16, ImagingUnpackRGB4B}, - {"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ - {"RGBX", "RGBX", 32, copy4}, - {"RGBX", "RGBXX", 40, copy4skip1}, - {"RGBX", "RGBXXX", 48, copy4skip2}, - {"RGBX", "RGBX;L", 32, unpackRGBAL}, - {"RGBX", "RGBX;16L", 64, unpackRGBA16L}, - {"RGBX", "RGBX;16B", 64, unpackRGBA16B}, - {"RGBX", "BGRX", 32, ImagingUnpackBGRX}, - {"RGBX", "XRGB", 32, ImagingUnpackXRGB}, - {"RGBX", "XBGR", 32, ImagingUnpackXBGR}, - {"RGBX", "YCC;P", 24, ImagingUnpackYCC}, - {"RGBX", "R", 8, band0}, - {"RGBX", "G", 8, band1}, - {"RGBX", "B", 8, band2}, - {"RGBX", "X", 8, band3}, + {"RGBX", "RGB", 24, ImagingUnpackRGB}, + {"RGBX", "RGB;L", 24, unpackRGBL}, + {"RGBX", "RGB;16B", 48, unpackRGB16B}, + {"RGBX", "BGR", 24, ImagingUnpackBGR}, + {"RGBX", "RGB;15", 16, ImagingUnpackRGB15}, + {"RGBX", "BGR;15", 16, ImagingUnpackBGR15}, + {"RGBX", "RGB;4B", 16, ImagingUnpackRGB4B}, + {"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ + {"RGBX", "RGBX", 32, copy4}, + {"RGBX", "RGBXX", 40, copy4skip1}, + {"RGBX", "RGBXXX", 48, copy4skip2}, + {"RGBX", "RGBX;L", 32, unpackRGBAL}, + {"RGBX", "RGBX;16L", 64, unpackRGBA16L}, + {"RGBX", "RGBX;16B", 64, unpackRGBA16B}, + {"RGBX", "BGRX", 32, ImagingUnpackBGRX}, + {"RGBX", "XRGB", 32, ImagingUnpackXRGB}, + {"RGBX", "XBGR", 32, ImagingUnpackXBGR}, + {"RGBX", "YCC;P", 24, ImagingUnpackYCC}, + {"RGBX", "R", 8, band0}, + {"RGBX", "G", 8, band1}, + {"RGBX", "B", 8, band2}, + {"RGBX", "X", 8, band3}, /* colour separation */ - {"CMYK", "CMYK", 32, copy4}, - {"CMYK", "CMYKX", 40, copy4skip1}, - {"CMYK", "CMYKXX", 48, copy4skip2}, - {"CMYK", "CMYK;I", 32, unpackCMYKI}, - {"CMYK", "CMYK;L", 32, unpackRGBAL}, - {"CMYK", "CMYK;16L", 64, unpackRGBA16L}, - {"CMYK", "CMYK;16B", 64, unpackRGBA16B}, - {"CMYK", "C", 8, band0}, - {"CMYK", "M", 8, band1}, - {"CMYK", "Y", 8, band2}, - {"CMYK", "K", 8, band3}, - {"CMYK", "C;I", 8, band0I}, - {"CMYK", "M;I", 8, band1I}, - {"CMYK", "Y;I", 8, band2I}, - {"CMYK", "K;I", 8, band3I}, + {"CMYK", "CMYK", 32, copy4}, + {"CMYK", "CMYKX", 40, copy4skip1}, + {"CMYK", "CMYKXX", 48, copy4skip2}, + {"CMYK", "CMYK;I", 32, unpackCMYKI}, + {"CMYK", "CMYK;L", 32, unpackRGBAL}, + {"CMYK", "CMYK;16L", 64, unpackRGBA16L}, + {"CMYK", "CMYK;16B", 64, unpackRGBA16B}, + {"CMYK", "C", 8, band0}, + {"CMYK", "M", 8, band1}, + {"CMYK", "Y", 8, band2}, + {"CMYK", "K", 8, band3}, + {"CMYK", "C;I", 8, band0I}, + {"CMYK", "M;I", 8, band1I}, + {"CMYK", "Y;I", 8, band2I}, + {"CMYK", "K;I", 8, band3I}, #ifdef WORDS_BIGENDIAN - {"CMYK", "CMYK;16N", 64, unpackRGBA16B}, + {"CMYK", "CMYK;16N", 64, unpackRGBA16B}, #else - {"CMYK", "CMYK;16N", 64, unpackRGBA16L}, + {"CMYK", "CMYK;16N", 64, unpackRGBA16L}, #endif /* video (YCbCr) */ - {"YCbCr", "YCbCr", 24, ImagingUnpackRGB}, - {"YCbCr", "YCbCr;L", 24, unpackRGBL}, - {"YCbCr", "YCbCrX", 32, copy4}, - {"YCbCr", "YCbCrK", 32, copy4}, + {"YCbCr", "YCbCr", 24, ImagingUnpackRGB}, + {"YCbCr", "YCbCr;L", 24, unpackRGBL}, + {"YCbCr", "YCbCrX", 32, copy4}, + {"YCbCr", "YCbCrK", 32, copy4}, /* LAB Color */ - {"LAB", "LAB", 24, ImagingUnpackLAB}, - {"LAB", "L", 8, band0}, - {"LAB", "A", 8, band1}, - {"LAB", "B", 8, band2}, + {"LAB", "LAB", 24, ImagingUnpackLAB}, + {"LAB", "L", 8, band0}, + {"LAB", "A", 8, band1}, + {"LAB", "B", 8, band2}, /* HSV Color */ - {"HSV", "HSV", 24, ImagingUnpackRGB}, - {"HSV", "H", 8, band0}, - {"HSV", "S", 8, band1}, - {"HSV", "V", 8, band2}, + {"HSV", "HSV", 24, ImagingUnpackRGB}, + {"HSV", "H", 8, band0}, + {"HSV", "S", 8, band1}, + {"HSV", "V", 8, band2}, /* integer variations */ - {"I", "I", 32, copy4}, - {"I", "I;8", 8, unpackI8}, - {"I", "I;8S", 8, unpackI8S}, - {"I", "I;16", 16, unpackI16}, - {"I", "I;16S", 16, unpackI16S}, - {"I", "I;16B", 16, unpackI16B}, - {"I", "I;16BS", 16, unpackI16BS}, - {"I", "I;16N", 16, unpackI16N}, - {"I", "I;16NS", 16, unpackI16NS}, - {"I", "I;32", 32, unpackI32}, - {"I", "I;32S", 32, unpackI32S}, - {"I", "I;32B", 32, unpackI32B}, - {"I", "I;32BS", 32, unpackI32BS}, - {"I", "I;32N", 32, unpackI32N}, - {"I", "I;32NS", 32, unpackI32NS}, + {"I", "I", 32, copy4}, + {"I", "I;8", 8, unpackI8}, + {"I", "I;8S", 8, unpackI8S}, + {"I", "I;16", 16, unpackI16}, + {"I", "I;16S", 16, unpackI16S}, + {"I", "I;16B", 16, unpackI16B}, + {"I", "I;16BS", 16, unpackI16BS}, + {"I", "I;16N", 16, unpackI16N}, + {"I", "I;16NS", 16, unpackI16NS}, + {"I", "I;32", 32, unpackI32}, + {"I", "I;32S", 32, unpackI32S}, + {"I", "I;32B", 32, unpackI32B}, + {"I", "I;32BS", 32, unpackI32BS}, + {"I", "I;32N", 32, unpackI32N}, + {"I", "I;32NS", 32, unpackI32NS}, /* floating point variations */ - {"F", "F", 32, copy4}, - {"F", "F;8", 8, unpackF8}, - {"F", "F;8S", 8, unpackF8S}, - {"F", "F;16", 16, unpackF16}, - {"F", "F;16S", 16, unpackF16S}, - {"F", "F;16B", 16, unpackF16B}, - {"F", "F;16BS", 16, unpackF16BS}, - {"F", "F;16N", 16, unpackF16N}, - {"F", "F;16NS", 16, unpackF16NS}, - {"F", "F;32", 32, unpackF32}, - {"F", "F;32S", 32, unpackF32S}, - {"F", "F;32B", 32, unpackF32B}, - {"F", "F;32BS", 32, unpackF32BS}, - {"F", "F;32N", 32, unpackF32N}, - {"F", "F;32NS", 32, unpackF32NS}, - {"F", "F;32F", 32, unpackF32F}, - {"F", "F;32BF", 32, unpackF32BF}, - {"F", "F;32NF", 32, unpackF32NF}, + {"F", "F", 32, copy4}, + {"F", "F;8", 8, unpackF8}, + {"F", "F;8S", 8, unpackF8S}, + {"F", "F;16", 16, unpackF16}, + {"F", "F;16S", 16, unpackF16S}, + {"F", "F;16B", 16, unpackF16B}, + {"F", "F;16BS", 16, unpackF16BS}, + {"F", "F;16N", 16, unpackF16N}, + {"F", "F;16NS", 16, unpackF16NS}, + {"F", "F;32", 32, unpackF32}, + {"F", "F;32S", 32, unpackF32S}, + {"F", "F;32B", 32, unpackF32B}, + {"F", "F;32BS", 32, unpackF32BS}, + {"F", "F;32N", 32, unpackF32N}, + {"F", "F;32NS", 32, unpackF32NS}, + {"F", "F;32F", 32, unpackF32F}, + {"F", "F;32BF", 32, unpackF32BF}, + {"F", "F;32NF", 32, unpackF32NF}, #ifdef FLOAT64 - {"F", "F;64F", 64, unpackF64F}, - {"F", "F;64BF", 64, unpackF64BF}, - {"F", "F;64NF", 64, unpackF64NF}, + {"F", "F;64F", 64, unpackF64F}, + {"F", "F;64BF", 64, unpackF64BF}, + {"F", "F;64NF", 64, unpackF64NF}, #endif /* storage modes */ - {"I;16", "I;16", 16, copy2}, - {"I;16B", "I;16B", 16, copy2}, - {"I;16L", "I;16L", 16, copy2}, + {"I;16", "I;16", 16, copy2}, + {"I;16B", "I;16B", 16, copy2}, + {"I;16L", "I;16L", 16, copy2}, - {"I;16", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. - {"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. - {"I;16B", "I;16N", 16, unpackI16N_I16B}, + {"I;16", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. + {"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. + {"I;16B", "I;16N", 16, unpackI16N_I16B}, - {"I;16", "I;12", 12, unpackI12_I16}, // 12 bit Tiffs stored in 16bits. + {"I;16", "I;12", 12, unpackI12_I16}, // 12 bit Tiffs stored in 16bits. {NULL} /* sentinel */ }; - ImagingShuffler -ImagingFindUnpacker(const char* mode, const char* rawmode, int* bits_out) -{ +ImagingFindUnpacker(const char *mode, const char *rawmode, int *bits_out) { int i; /* find a suitable pixel unpacker */ diff --git a/src/libImaging/UnpackYCC.c b/src/libImaging/UnpackYCC.c index d6bce17ad..0b177bdd4 100644 --- a/src/libImaging/UnpackYCC.c +++ b/src/libImaging/UnpackYCC.c @@ -13,150 +13,151 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - /* Tables generated by pcdtables.py, based on transforms taken from the "Colour Space Conversions FAQ" by Roberts/Ford. */ -static INT16 L[] = { 0, 1, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, -19, 20, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 35, 37, 38, 39, 41, -42, 43, 45, 46, 48, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 62, 64, -65, 67, 68, 69, 71, 72, 73, 75, 76, 77, 79, 80, 82, 83, 84, 86, 87, -88, 90, 91, 92, 94, 95, 96, 98, 99, 101, 102, 103, 105, 106, 107, 109, -110, 111, 113, 114, 115, 117, 118, 120, 121, 122, 124, 125, 126, 128, -129, 130, 132, 133, 134, 136, 137, 139, 140, 141, 143, 144, 145, 147, -148, 149, 151, 152, 153, 155, 156, 158, 159, 160, 162, 163, 164, 166, -167, 168, 170, 171, 173, 174, 175, 177, 178, 179, 181, 182, 183, 185, -186, 187, 189, 190, 192, 193, 194, 196, 197, 198, 200, 201, 202, 204, -205, 206, 208, 209, 211, 212, 213, 215, 216, 217, 219, 220, 221, 223, -224, 225, 227, 228, 230, 231, 232, 234, 235, 236, 238, 239, 240, 242, -243, 245, 246, 247, 249, 250, 251, 253, 254, 255, 257, 258, 259, 261, -262, 264, 265, 266, 268, 269, 270, 272, 273, 274, 276, 277, 278, 280, -281, 283, 284, 285, 287, 288, 289, 291, 292, 293, 295, 296, 297, 299, -300, 302, 303, 304, 306, 307, 308, 310, 311, 312, 314, 315, 317, 318, -319, 321, 322, 323, 325, 326, 327, 329, 330, 331, 333, 334, 336, 337, -338, 340, 341, 342, 344, 345, 346 }; +static INT16 L[] = { + 0, 1, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20, + 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 35, 37, 38, 39, 41, 42, + 43, 45, 46, 48, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 62, 64, + 65, 67, 68, 69, 71, 72, 73, 75, 76, 77, 79, 80, 82, 83, 84, 86, + 87, 88, 90, 91, 92, 94, 95, 96, 98, 99, 101, 102, 103, 105, 106, 107, + 109, 110, 111, 113, 114, 115, 117, 118, 120, 121, 122, 124, 125, 126, 128, 129, + 130, 132, 133, 134, 136, 137, 139, 140, 141, 143, 144, 145, 147, 148, 149, 151, + 152, 153, 155, 156, 158, 159, 160, 162, 163, 164, 166, 167, 168, 170, 171, 173, + 174, 175, 177, 178, 179, 181, 182, 183, 185, 186, 187, 189, 190, 192, 193, 194, + 196, 197, 198, 200, 201, 202, 204, 205, 206, 208, 209, 211, 212, 213, 215, 216, + 217, 219, 220, 221, 223, 224, 225, 227, 228, 230, 231, 232, 234, 235, 236, 238, + 239, 240, 242, 243, 245, 246, 247, 249, 250, 251, 253, 254, 255, 257, 258, 259, + 261, 262, 264, 265, 266, 268, 269, 270, 272, 273, 274, 276, 277, 278, 280, 281, + 283, 284, 285, 287, 288, 289, 291, 292, 293, 295, 296, 297, 299, 300, 302, 303, + 304, 306, 307, 308, 310, 311, 312, 314, 315, 317, 318, 319, 321, 322, 323, 325, + 326, 327, 329, 330, 331, 333, 334, 336, 337, 338, 340, 341, 342, 344, 345, 346}; -static INT16 CB[] = { -345, -343, -341, -338, -336, -334, -332, -329, --327, -325, -323, -321, -318, -316, -314, -312, -310, -307, -305, --303, -301, -298, -296, -294, -292, -290, -287, -285, -283, -281, --278, -276, -274, -272, -270, -267, -265, -263, -261, -258, -256, --254, -252, -250, -247, -245, -243, -241, -239, -236, -234, -232, --230, -227, -225, -223, -221, -219, -216, -214, -212, -210, -207, --205, -203, -201, -199, -196, -194, -192, -190, -188, -185, -183, --181, -179, -176, -174, -172, -170, -168, -165, -163, -161, -159, --156, -154, -152, -150, -148, -145, -143, -141, -139, -137, -134, --132, -130, -128, -125, -123, -121, -119, -117, -114, -112, -110, --108, -105, -103, -101, -99, -97, -94, -92, -90, -88, -85, -83, -81, --79, -77, -74, -72, -70, -68, -66, -63, -61, -59, -57, -54, -52, -50, --48, -46, -43, -41, -39, -37, -34, -32, -30, -28, -26, -23, -21, -19, --17, -15, -12, -10, -8, -6, -3, -1, 0, 2, 4, 7, 9, 11, 13, 16, 18, 20, -22, 24, 27, 29, 31, 33, 35, 38, 40, 42, 44, 47, 49, 51, 53, 55, 58, -60, 62, 64, 67, 69, 71, 73, 75, 78, 80, 82, 84, 86, 89, 91, 93, 95, -98, 100, 102, 104, 106, 109, 111, 113, 115, 118, 120, 122, 124, 126, -129, 131, 133, 135, 138, 140, 142, 144, 146, 149, 151, 153, 155, 157, -160, 162, 164, 166, 169, 171, 173, 175, 177, 180, 182, 184, 186, 189, -191, 193, 195, 197, 200, 202, 204, 206, 208, 211, 213, 215, 217, 220 }; +static INT16 CB[] = { + -345, -343, -341, -338, -336, -334, -332, -329, -327, -325, -323, -321, -318, -316, + -314, -312, -310, -307, -305, -303, -301, -298, -296, -294, -292, -290, -287, -285, + -283, -281, -278, -276, -274, -272, -270, -267, -265, -263, -261, -258, -256, -254, + -252, -250, -247, -245, -243, -241, -239, -236, -234, -232, -230, -227, -225, -223, + -221, -219, -216, -214, -212, -210, -207, -205, -203, -201, -199, -196, -194, -192, + -190, -188, -185, -183, -181, -179, -176, -174, -172, -170, -168, -165, -163, -161, + -159, -156, -154, -152, -150, -148, -145, -143, -141, -139, -137, -134, -132, -130, + -128, -125, -123, -121, -119, -117, -114, -112, -110, -108, -105, -103, -101, -99, + -97, -94, -92, -90, -88, -85, -83, -81, -79, -77, -74, -72, -70, -68, + -66, -63, -61, -59, -57, -54, -52, -50, -48, -46, -43, -41, -39, -37, + -34, -32, -30, -28, -26, -23, -21, -19, -17, -15, -12, -10, -8, -6, + -3, -1, 0, 2, 4, 7, 9, 11, 13, 16, 18, 20, 22, 24, + 27, 29, 31, 33, 35, 38, 40, 42, 44, 47, 49, 51, 53, 55, + 58, 60, 62, 64, 67, 69, 71, 73, 75, 78, 80, 82, 84, 86, + 89, 91, 93, 95, 98, 100, 102, 104, 106, 109, 111, 113, 115, 118, + 120, 122, 124, 126, 129, 131, 133, 135, 138, 140, 142, 144, 146, 149, + 151, 153, 155, 157, 160, 162, 164, 166, 169, 171, 173, 175, 177, 180, + 182, 184, 186, 189, 191, 193, 195, 197, 200, 202, 204, 206, 208, 211, + 213, 215, 217, 220}; -static INT16 GB[] = { 67, 67, 66, 66, 65, 65, 65, 64, 64, 63, 63, 62, -62, 62, 61, 61, 60, 60, 59, 59, 59, 58, 58, 57, 57, 56, 56, 56, 55, -55, 54, 54, 53, 53, 52, 52, 52, 51, 51, 50, 50, 49, 49, 49, 48, 48, -47, 47, 46, 46, 46, 45, 45, 44, 44, 43, 43, 43, 42, 42, 41, 41, 40, -40, 40, 39, 39, 38, 38, 37, 37, 37, 36, 36, 35, 35, 34, 34, 34, 33, -33, 32, 32, 31, 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, -25, 25, 25, 24, 24, 23, 23, 22, 22, 22, 21, 21, 20, 20, 19, 19, 19, -18, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 13, 13, 12, 12, 12, 11, -11, 10, 10, 9, 9, 9, 8, 8, 7, 7, 6, 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, -1, 1, 0, 0, 0, 0, 0, -1, -1, -2, -2, -2, -3, -3, -4, -4, -5, -5, -5, --6, -6, -7, -7, -8, -8, -8, -9, -9, -10, -10, -11, -11, -11, -12, -12, --13, -13, -14, -14, -14, -15, -15, -16, -16, -17, -17, -18, -18, -18, --19, -19, -20, -20, -21, -21, -21, -22, -22, -23, -23, -24, -24, -24, --25, -25, -26, -26, -27, -27, -27, -28, -28, -29, -29, -30, -30, -30, --31, -31, -32, -32, -33, -33, -33, -34, -34, -35, -35, -36, -36, -36, --37, -37, -38, -38, -39, -39, -39, -40, -40, -41, -41, -42 }; +static INT16 GB[] = { + 67, 67, 66, 66, 65, 65, 65, 64, 64, 63, 63, 62, 62, 62, 61, 61, + 60, 60, 59, 59, 59, 58, 58, 57, 57, 56, 56, 56, 55, 55, 54, 54, + 53, 53, 52, 52, 52, 51, 51, 50, 50, 49, 49, 49, 48, 48, 47, 47, + 46, 46, 46, 45, 45, 44, 44, 43, 43, 43, 42, 42, 41, 41, 40, 40, + 40, 39, 39, 38, 38, 37, 37, 37, 36, 36, 35, 35, 34, 34, 34, 33, + 33, 32, 32, 31, 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, + 26, 25, 25, 25, 24, 24, 23, 23, 22, 22, 22, 21, 21, 20, 20, 19, + 19, 19, 18, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 13, 13, 12, + 12, 12, 11, 11, 10, 10, 9, 9, 9, 8, 8, 7, 7, 6, 6, 6, + 5, 5, 4, 4, 3, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, + -1, -1, -2, -2, -2, -3, -3, -4, -4, -5, -5, -5, -6, -6, -7, -7, + -8, -8, -8, -9, -9, -10, -10, -11, -11, -11, -12, -12, -13, -13, -14, -14, + -14, -15, -15, -16, -16, -17, -17, -18, -18, -18, -19, -19, -20, -20, -21, -21, + -21, -22, -22, -23, -23, -24, -24, -24, -25, -25, -26, -26, -27, -27, -27, -28, + -28, -29, -29, -30, -30, -30, -31, -31, -32, -32, -33, -33, -33, -34, -34, -35, + -35, -36, -36, -36, -37, -37, -38, -38, -39, -39, -39, -40, -40, -41, -41, -42}; -static INT16 CR[] = { -249, -247, -245, -243, -241, -239, -238, -236, --234, -232, -230, -229, -227, -225, -223, -221, -219, -218, -216, --214, -212, -210, -208, -207, -205, -203, -201, -199, -198, -196, --194, -192, -190, -188, -187, -185, -183, -181, -179, -178, -176, --174, -172, -170, -168, -167, -165, -163, -161, -159, -157, -156, --154, -152, -150, -148, -147, -145, -143, -141, -139, -137, -136, --134, -132, -130, -128, -127, -125, -123, -121, -119, -117, -116, --114, -112, -110, -108, -106, -105, -103, -101, -99, -97, -96, -94, --92, -90, -88, -86, -85, -83, -81, -79, -77, -76, -74, -72, -70, -68, --66, -65, -63, -61, -59, -57, -55, -54, -52, -50, -48, -46, -45, -43, --41, -39, -37, -35, -34, -32, -30, -28, -26, -25, -23, -21, -19, -17, --15, -14, -12, -10, -8, -6, -4, -3, -1, 0, 2, 4, 5, 7, 9, 11, 13, 15, -16, 18, 20, 22, 24, 26, 27, 29, 31, 33, 35, 36, 38, 40, 42, 44, 46, -47, 49, 51, 53, 55, 56, 58, 60, 62, 64, 66, 67, 69, 71, 73, 75, 77, -78, 80, 82, 84, 86, 87, 89, 91, 93, 95, 97, 98, 100, 102, 104, 106, -107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 129, 131, -133, 135, 137, 138, 140, 142, 144, 146, 148, 149, 151, 153, 155, 157, -158, 160, 162, 164, 166, 168, 169, 171, 173, 175, 177, 179, 180, 182, -184, 186, 188, 189, 191, 193, 195, 197, 199, 200, 202, 204, 206, 208, -209, 211, 213, 215 }; +static INT16 CR[] = { + -249, -247, -245, -243, -241, -239, -238, -236, -234, -232, -230, -229, -227, -225, + -223, -221, -219, -218, -216, -214, -212, -210, -208, -207, -205, -203, -201, -199, + -198, -196, -194, -192, -190, -188, -187, -185, -183, -181, -179, -178, -176, -174, + -172, -170, -168, -167, -165, -163, -161, -159, -157, -156, -154, -152, -150, -148, + -147, -145, -143, -141, -139, -137, -136, -134, -132, -130, -128, -127, -125, -123, + -121, -119, -117, -116, -114, -112, -110, -108, -106, -105, -103, -101, -99, -97, + -96, -94, -92, -90, -88, -86, -85, -83, -81, -79, -77, -76, -74, -72, + -70, -68, -66, -65, -63, -61, -59, -57, -55, -54, -52, -50, -48, -46, + -45, -43, -41, -39, -37, -35, -34, -32, -30, -28, -26, -25, -23, -21, + -19, -17, -15, -14, -12, -10, -8, -6, -4, -3, -1, 0, 2, 4, + 5, 7, 9, 11, 13, 15, 16, 18, 20, 22, 24, 26, 27, 29, + 31, 33, 35, 36, 38, 40, 42, 44, 46, 47, 49, 51, 53, 55, + 56, 58, 60, 62, 64, 66, 67, 69, 71, 73, 75, 77, 78, 80, + 82, 84, 86, 87, 89, 91, 93, 95, 97, 98, 100, 102, 104, 106, + 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 129, 131, + 133, 135, 137, 138, 140, 142, 144, 146, 148, 149, 151, 153, 155, 157, + 158, 160, 162, 164, 166, 168, 169, 171, 173, 175, 177, 179, 180, 182, + 184, 186, 188, 189, 191, 193, 195, 197, 199, 200, 202, 204, 206, 208, + 209, 211, 213, 215}; -static INT16 GR[] = { 127, 126, 125, 124, 123, 122, 121, 121, 120, 119, -118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 108, 107, 106, -105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 95, 94, 93, 92, 91, -90, 89, 88, 87, 86, 85, 84, 83, 83, 82, 81, 80, 79, 78, 77, 76, 75, -74, 73, 72, 71, 70, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, -58, 57, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 45, 44, -43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 32, 31, 30, 29, 28, -27, 26, 25, 24, 23, 22, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, -11, 10, 9, 8, 7, 6, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2, -3, -4, -5, -5, --6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -18, -19, --20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -31, -32, --33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -44, -45, --46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, --59, -60, -61, -62, -63, -64, -65, -66, -67, -68, -69, -69, -70, -71, --72, -73, -74, -75, -76, -77, -78, -79, -80, -81, -82, -82, -83, -84, --85, -86, -87, -88, -89, -90, -91, -92, -93, -94, -94, -95, -96, -97, --98, -99, -100, -101, -102, -103, -104, -105, -106, -107, -107, -108 }; +static INT16 GR[] = { + 127, 126, 125, 124, 123, 122, 121, 121, 120, 119, 118, 117, 116, 115, 114, + 113, 112, 111, 110, 109, 108, 108, 107, 106, 105, 104, 103, 102, 101, 100, + 99, 98, 97, 96, 95, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, + 85, 84, 83, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, + 71, 70, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, + 57, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 45, + 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 32, 31, + 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 19, 18, 17, + 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 3, + 2, 1, 0, 0, -1, -2, -3, -4, -5, -5, -6, -7, -8, -9, -10, + -11, -12, -13, -14, -15, -16, -17, -18, -18, -19, -20, -21, -22, -23, -24, + -25, -26, -27, -28, -29, -30, -31, -31, -32, -33, -34, -35, -36, -37, -38, + -39, -40, -41, -42, -43, -44, -44, -45, -46, -47, -48, -49, -50, -51, -52, + -53, -54, -55, -56, -56, -57, -58, -59, -60, -61, -62, -63, -64, -65, -66, + -67, -68, -69, -69, -70, -71, -72, -73, -74, -75, -76, -77, -78, -79, -80, + -81, -82, -82, -83, -84, -85, -86, -87, -88, -89, -90, -91, -92, -93, -94, + -94, -95, -96, -97, -98, -99, -100, -101, -102, -103, -104, -105, -106, -107, -107, + -108}; #define R 0 #define G 1 #define B 2 #define A 3 -#define YCC2RGB(rgb, y, cb, cr) {\ - int l = L[y];\ - int r = l + CR[cr];\ - int g = l + GR[cr] + GB[cb];\ - int b = l + CB[cb];\ - rgb[0] = (r <= 0) ? 0 : (r >= 255) ? 255 : r;\ - rgb[1] = (g <= 0) ? 0 : (g >= 255) ? 255 : g;\ - rgb[2] = (b <= 0) ? 0 : (b >= 255) ? 255 : b;\ -} +#define YCC2RGB(rgb, y, cb, cr) \ + { \ + int l = L[y]; \ + int r = l + CR[cr]; \ + int g = l + GR[cr] + GB[cb]; \ + int b = l + CB[cb]; \ + rgb[0] = (r <= 0) ? 0 : (r >= 255) ? 255 : r; \ + rgb[1] = (g <= 0) ? 0 : (g >= 255) ? 255 : g; \ + rgb[2] = (b <= 0) ? 0 : (b >= 255) ? 255 : b; \ + } void -ImagingUnpackYCC(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackYCC(UINT8 *out, const UINT8 *in, int pixels) { int i; /* PhotoYCC triplets */ for (i = 0; i < pixels; i++) { YCC2RGB(out, in[0], in[1], in[2]); out[A] = 255; - out += 4; in += 3; + out += 4; + in += 3; } } void -ImagingUnpackYCCA(UINT8* out, const UINT8* in, int pixels) -{ +ImagingUnpackYCCA(UINT8 *out, const UINT8 *in, int pixels) { int i; /* PhotoYCC triplets plus premultiplied alpha */ for (i = 0; i < pixels; i++) { /* Divide by alpha */ UINT8 rgb[3]; - rgb[0] = (in[3] == 0) ? 0 : (((int) in[0] * 255) / in[3]); - rgb[1] = (in[3] == 0) ? 0 : (((int) in[1] * 255) / in[3]); - rgb[2] = (in[3] == 0) ? 0 : (((int) in[2] * 255) / in[3]); + rgb[0] = (in[3] == 0) ? 0 : (((int)in[0] * 255) / in[3]); + rgb[1] = (in[3] == 0) ? 0 : (((int)in[1] * 255) / in[3]); + rgb[2] = (in[3] == 0) ? 0 : (((int)in[2] * 255) / in[3]); /* Convert non-multiplied data to RGB */ YCC2RGB(out, rgb[0], rgb[1], rgb[2]); out[A] = in[3]; - out += 4; in += 4; + out += 4; + in += 4; } } diff --git a/src/libImaging/UnsharpMask.c b/src/libImaging/UnsharpMask.c index 59e595e82..643ced49f 100644 --- a/src/libImaging/UnsharpMask.c +++ b/src/libImaging/UnsharpMask.c @@ -8,26 +8,22 @@ #include "Imaging.h" - typedef UINT8 pixel[4]; - -static inline UINT8 clip8(int in) -{ +static inline UINT8 +clip8(int in) { if (in >= 255) { - return 255; + return 255; } if (in <= 0) { return 0; } - return (UINT8) in; + return (UINT8)in; } - Imaging -ImagingUnsharpMask(Imaging imOut, Imaging imIn, float radius, int percent, - int threshold) -{ +ImagingUnsharpMask( + Imaging imOut, Imaging imIn, float radius, int percent, int threshold) { ImagingSectionCookie cookie; Imaging result; @@ -53,8 +49,7 @@ ImagingUnsharpMask(Imaging imOut, Imaging imIn, float radius, int percent, ImagingSectionEnter(&cookie); for (y = 0; y < imIn->ysize; y++) { - if (imIn->image8) - { + if (imIn->image8) { lineIn8 = imIn->image8[y]; lineOut8 = imOut->image8[y]; for (x = 0; x < imIn->xsize; x++) { @@ -74,20 +69,24 @@ ImagingUnsharpMask(Imaging imOut, Imaging imIn, float radius, int percent, for (x = 0; x < imIn->xsize; x++) { /* compare in/out pixels, apply sharpening */ diff = lineIn[x][0] - lineOut[x][0]; - lineOut[x][0] = abs(diff) > threshold ? - clip8(lineIn[x][0] + diff * percent / 100) : lineIn[x][0]; + lineOut[x][0] = abs(diff) > threshold + ? clip8(lineIn[x][0] + diff * percent / 100) + : lineIn[x][0]; diff = lineIn[x][1] - lineOut[x][1]; - lineOut[x][1] = abs(diff) > threshold ? - clip8(lineIn[x][1] + diff * percent / 100) : lineIn[x][1]; + lineOut[x][1] = abs(diff) > threshold + ? clip8(lineIn[x][1] + diff * percent / 100) + : lineIn[x][1]; diff = lineIn[x][2] - lineOut[x][2]; - lineOut[x][2] = abs(diff) > threshold ? - clip8(lineIn[x][2] + diff * percent / 100) : lineIn[x][2]; + lineOut[x][2] = abs(diff) > threshold + ? clip8(lineIn[x][2] + diff * percent / 100) + : lineIn[x][2]; diff = lineIn[x][3] - lineOut[x][3]; - lineOut[x][3] = abs(diff) > threshold ? - clip8(lineIn[x][3] + diff * percent / 100) : lineIn[x][3]; + lineOut[x][3] = abs(diff) > threshold + ? clip8(lineIn[x][3] + diff * percent / 100) + : lineIn[x][3]; } } } diff --git a/src/libImaging/XbmDecode.c b/src/libImaging/XbmDecode.c index 607f1058a..d6690de3d 100644 --- a/src/libImaging/XbmDecode.c +++ b/src/libImaging/XbmDecode.c @@ -13,19 +13,19 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" -#define HEX(v) ((v >= '0' && v <= '9') ? v - '0' :\ - (v >= 'a' && v <= 'f') ? v - 'a' + 10 :\ - (v >= 'A' && v <= 'F') ? v - 'A' + 10 : 0) +#define HEX(v) \ + ((v >= '0' && v <= '9') ? v - '0' \ + : (v >= 'a' && v <= 'f') ? v - 'a' + 10 \ + : (v >= 'A' && v <= 'F') ? v - 'A' + 10 \ + : 0) int -ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ +ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { enum { BYTE = 1, SKIP }; - UINT8* ptr; + UINT8 *ptr; if (!state->state) { state->state = SKIP; @@ -34,9 +34,7 @@ ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt ptr = buf; for (;;) { - if (state->state == SKIP) { - /* Skip forward until next 'x' */ while (bytes > 0) { @@ -52,20 +50,17 @@ ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt } state->state = BYTE; - } if (bytes < 3) { return ptr - buf; } - state->buffer[state->x] = (HEX(ptr[1])<<4) + HEX(ptr[2]); + state->buffer[state->x] = (HEX(ptr[1]) << 4) + HEX(ptr[2]); if (++state->x >= state->bytes) { - /* Got a full line, unpack it */ - state->shuffle((UINT8*) im->image[state->y], state->buffer, - state->xsize); + state->shuffle((UINT8 *)im->image[state->y], state->buffer, state->xsize); state->x = 0; @@ -79,7 +74,5 @@ ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt bytes -= 3; state->state = SKIP; - } - } diff --git a/src/libImaging/XbmEncode.c b/src/libImaging/XbmEncode.c index d1bc086db..eec4c0d84 100644 --- a/src/libImaging/XbmEncode.c +++ b/src/libImaging/XbmEncode.c @@ -13,25 +13,20 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" - int -ImagingXbmEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) -{ +ImagingXbmEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { const char *hex = "0123456789abcdef"; - UINT8* ptr = buf; + UINT8 *ptr = buf; int i, n; if (!state->state) { - /* 8 pixels are stored in no more than 6 bytes */ - state->bytes = 6*(state->xsize+7)/8; + state->bytes = 6 * (state->xsize + 7) / 8; state->state = 1; - } if (bytes < state->bytes) { @@ -42,60 +37,54 @@ ImagingXbmEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) ptr = buf; while (bytes >= state->bytes) { + state->shuffle( + state->buffer, + (UINT8 *)im->image[state->y + state->yoff] + state->xoff * im->pixelsize, + state->xsize); - state->shuffle(state->buffer, - (UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, state->xsize); - - if (state->y < state->ysize-1) { - + if (state->y < state->ysize - 1) { /* any line but the last */ for (n = 0; n < state->xsize; n += 8) { - - i = state->buffer[n/8]; + i = state->buffer[n / 8]; *ptr++ = '0'; *ptr++ = 'x'; - *ptr++ = hex[(i>>4)&15]; - *ptr++ = hex[i&15]; + *ptr++ = hex[(i >> 4) & 15]; + *ptr++ = hex[i & 15]; *ptr++ = ','; bytes -= 5; - if (++state->count >= 79/5) { + if (++state->count >= 79 / 5) { *ptr++ = '\n'; bytes--; state->count = 0; } - } state->y++; } else { - /* last line */ for (n = 0; n < state->xsize; n += 8) { - - i = state->buffer[n/8]; + i = state->buffer[n / 8]; *ptr++ = '0'; *ptr++ = 'x'; - *ptr++ = hex[(i>>4)&15]; - *ptr++ = hex[i&15]; + *ptr++ = hex[(i >> 4) & 15]; + *ptr++ = hex[i & 15]; - if (n < state->xsize-8) { + if (n < state->xsize - 8) { *ptr++ = ','; - if (++state->count >= 79/5) { - *ptr++ = '\n'; - bytes--; - state->count = 0; + if (++state->count >= 79 / 5) { + *ptr++ = '\n'; + bytes--; + state->count = 0; } } else { *ptr++ = '\n'; } bytes -= 5; - } state->errcode = IMAGING_CODEC_END; diff --git a/src/libImaging/ZipCodecs.h b/src/libImaging/ZipCodecs.h index b05c93bb4..50218b6c6 100644 --- a/src/libImaging/ZipCodecs.h +++ b/src/libImaging/ZipCodecs.h @@ -7,19 +7,15 @@ * Copyright (c) Fredrik Lundh 1996. */ - #include "zlib.h" - /* modes */ #define ZIP_PNG 0 /* continuous, filtered image data */ #define ZIP_PNG_PALETTE 1 /* non-continuous data, disable filtering */ #define ZIP_TIFF_PREDICTOR 2 /* TIFF, with predictor */ #define ZIP_TIFF 3 /* TIFF, without predictor */ - typedef struct { - /* CONFIGURATION */ /* Codec mode */ @@ -34,29 +30,29 @@ typedef struct { int compress_type; /* Predefined dictionary (experimental) */ - char* dictionary; + char *dictionary; int dictionary_size; /* PRIVATE CONTEXT (set by decoder/encoder) */ - z_stream z_stream; /* (de)compression stream */ + z_stream z_stream; /* (de)compression stream */ - UINT8* previous; /* previous line (allocated) */ + UINT8 *previous; /* previous line (allocated) */ - int last_output; /* # bytes last output by inflate */ + int last_output; /* # bytes last output by inflate */ /* Compressor specific stuff */ - UINT8* prior; /* filter storage (allocated) */ - UINT8* up; - UINT8* average; - UINT8* paeth; + UINT8 *prior; /* filter storage (allocated) */ + UINT8 *up; + UINT8 *average; + UINT8 *paeth; - UINT8* output; /* output data */ + UINT8 *output; /* output data */ - int prefix; /* size of filter prefix (0 for TIFF data) */ + int prefix; /* size of filter prefix (0 for TIFF data) */ - int interlaced; /* is the image interlaced? (PNG) */ + int interlaced; /* is the image interlaced? (PNG) */ - int pass; /* current pass of the interlaced image (PNG) */ + int pass; /* current pass of the interlaced image (PNG) */ } ZIPSTATE; diff --git a/src/libImaging/ZipDecode.c b/src/libImaging/ZipDecode.c index a09ee82f7..874967834 100644 --- a/src/libImaging/ZipDecode.c +++ b/src/libImaging/ZipDecode.c @@ -15,23 +15,22 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" -#ifdef HAVE_LIBZ +#ifdef HAVE_LIBZ #include "ZipCodecs.h" -static const int OFFSET[] = { 7, 3, 3, 1, 1, 0, 0 }; -static const int STARTING_COL[] = { 0, 4, 0, 2, 0, 1, 0 }; -static const int STARTING_ROW[] = { 0, 0, 4, 0, 2, 0, 1 }; -static const int COL_INCREMENT[] = { 8, 8, 4, 4, 2, 2, 1 }; -static const int ROW_INCREMENT[] = { 8, 8, 8, 4, 4, 2, 2 }; +static const int OFFSET[] = {7, 3, 3, 1, 1, 0, 0}; +static const int STARTING_COL[] = {0, 4, 0, 2, 0, 1, 0}; +static const int STARTING_ROW[] = {0, 0, 4, 0, 2, 0, 1}; +static const int COL_INCREMENT[] = {8, 8, 4, 4, 2, 2, 1}; +static const int ROW_INCREMENT[] = {8, 8, 8, 4, 4, 2, 2}; /* Get the length in bytes of a scanline in the pass specified, * for interlaced images */ -static int get_row_len(ImagingCodecState state, int pass) -{ +static int +get_row_len(ImagingCodecState state, int pass) { int row_len = (state->xsize + OFFSET[pass]) / COL_INCREMENT[pass]; return ((row_len * state->bits) + 7) / 8; } @@ -41,17 +40,15 @@ static int get_row_len(ImagingCodecState state, int pass) /* -------------------------------------------------------------------- */ int -ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes) -{ - ZIPSTATE* context = (ZIPSTATE*) state->context; +ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { + ZIPSTATE *context = (ZIPSTATE *)state->context; int err; int n; - UINT8* ptr; + UINT8 *ptr; int i, bpp; int row_len; if (!state->state) { - /* Initialization */ if (context->mode == ZIP_PNG || context->mode == ZIP_PNG_PALETTE) { context->prefix = 1; /* PNG */ @@ -66,8 +63,8 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt prefix, and allocate a buffer to hold the previous line */ free(state->buffer); /* malloc check ok, overflow checked above */ - state->buffer = (UINT8*) malloc(state->bytes+1); - context->previous = (UINT8*) malloc(state->bytes+1); + state->buffer = (UINT8 *)malloc(state->bytes + 1); + context->previous = (UINT8 *)malloc(state->bytes + 1); if (!state->buffer || !context->previous) { state->errcode = IMAGING_CODEC_MEMORY; return -1; @@ -76,12 +73,12 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt context->last_output = 0; /* Initialize to black */ - memset(context->previous, 0, state->bytes+1); + memset(context->previous, 0, state->bytes + 1); /* Setup decompression context */ - context->z_stream.zalloc = (alloc_func) NULL; - context->z_stream.zfree = (free_func) NULL; - context->z_stream.opaque = (voidpf) NULL; + context->z_stream.zalloc = (alloc_func)NULL; + context->z_stream.zfree = (free_func)NULL; + context->z_stream.opaque = (voidpf)NULL; err = inflateInit(&context->z_stream); if (err < 0) { @@ -98,7 +95,6 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt /* Ready to decode */ state->state = 1; - } if (context->interlaced) { @@ -113,10 +109,8 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt /* Decompress what we've got this far */ while (context->z_stream.avail_in > 0) { - context->z_stream.next_out = state->buffer + context->last_output; - context->z_stream.avail_out = - row_len + context->prefix - context->last_output; + context->z_stream.avail_out = row_len + context->prefix - context->last_output; err = inflate(&context->z_stream, Z_NO_FLUSH); @@ -144,74 +138,74 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt /* Apply predictor */ switch (context->mode) { - case ZIP_PNG: - switch (state->buffer[0]) { - case 0: + case ZIP_PNG: + switch (state->buffer[0]) { + case 0: + break; + case 1: + /* prior */ + bpp = (state->bits + 7) / 8; + for (i = bpp + 1; i <= row_len; i++) { + state->buffer[i] += state->buffer[i - bpp]; + } + break; + case 2: + /* up */ + for (i = 1; i <= row_len; i++) { + state->buffer[i] += context->previous[i]; + } + break; + case 3: + /* average */ + bpp = (state->bits + 7) / 8; + for (i = 1; i <= bpp; i++) { + state->buffer[i] += context->previous[i] / 2; + } + for (; i <= row_len; i++) { + state->buffer[i] += + (state->buffer[i - bpp] + context->previous[i]) / 2; + } + break; + case 4: + /* paeth filtering */ + bpp = (state->bits + 7) / 8; + for (i = 1; i <= bpp; i++) { + state->buffer[i] += context->previous[i]; + } + for (; i <= row_len; i++) { + int a, b, c; + int pa, pb, pc; + + /* fetch pixels */ + a = state->buffer[i - bpp]; + b = context->previous[i]; + c = context->previous[i - bpp]; + + /* distances to surrounding pixels */ + pa = abs(b - c); + pb = abs(a - c); + pc = abs(a + b - 2 * c); + + /* pick predictor with the shortest distance */ + state->buffer[i] += (pa <= pb && pa <= pc) ? a + : (pb <= pc) ? b + : c; + } + break; + default: + state->errcode = IMAGING_CODEC_UNKNOWN; + free(context->previous); + context->previous = NULL; + inflateEnd(&context->z_stream); + return -1; + } break; - case 1: - /* prior */ + case ZIP_TIFF_PREDICTOR: bpp = (state->bits + 7) / 8; - for (i = bpp+1; i <= row_len; i++) { - state->buffer[i] += state->buffer[i-bpp]; + for (i = bpp + 1; i <= row_len; i++) { + state->buffer[i] += state->buffer[i - bpp]; } break; - case 2: - /* up */ - for (i = 1; i <= row_len; i++) { - state->buffer[i] += context->previous[i]; - } - break; - case 3: - /* average */ - bpp = (state->bits + 7) / 8; - for (i = 1; i <= bpp; i++) { - state->buffer[i] += context->previous[i]/2; - } - for (; i <= row_len; i++) { - state->buffer[i] += - (state->buffer[i-bpp] + context->previous[i])/2; - } - break; - case 4: - /* paeth filtering */ - bpp = (state->bits + 7) / 8; - for (i = 1; i <= bpp; i++) { - state->buffer[i] += context->previous[i]; - } - for (; i <= row_len; i++) { - int a, b, c; - int pa, pb, pc; - - /* fetch pixels */ - a = state->buffer[i-bpp]; - b = context->previous[i]; - c = context->previous[i-bpp]; - - /* distances to surrounding pixels */ - pa = abs(b - c); - pb = abs(a - c); - pc = abs(a + b - 2*c); - - /* pick predictor with the shortest distance */ - state->buffer[i] += - (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; - - } - break; - default: - state->errcode = IMAGING_CODEC_UNKNOWN; - free(context->previous); - context->previous = NULL; - inflateEnd(&context->z_stream); - return -1; - } - break; - case ZIP_TIFF_PREDICTOR: - bpp = (state->bits + 7) / 8; - for (i = bpp+1; i <= row_len; i++) { - state->buffer[i] += state->buffer[i-bpp]; - } - break; } /* Stuff data into the image */ @@ -220,20 +214,22 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt if (state->bits >= 8) { /* Stuff pixels in their correct location, one by one */ for (i = 0; i < row_len; i += ((state->bits + 7) / 8)) { - state->shuffle((UINT8*) im->image[state->y] + - col * im->pixelsize, - state->buffer + context->prefix + i, 1); + state->shuffle( + (UINT8 *)im->image[state->y] + col * im->pixelsize, + state->buffer + context->prefix + i, + 1); col += COL_INCREMENT[context->pass]; } } else { /* Handle case with more than a pixel in each byte */ - int row_bits = ((state->xsize + OFFSET[context->pass]) - / COL_INCREMENT[context->pass]) * state->bits; + int row_bits = ((state->xsize + OFFSET[context->pass]) / + COL_INCREMENT[context->pass]) * + state->bits; for (i = 0; i < row_bits; i += state->bits) { UINT8 byte = *(state->buffer + context->prefix + (i / 8)); byte <<= (i % 8); - state->shuffle((UINT8*) im->image[state->y] + - col * im->pixelsize, &byte, 1); + state->shuffle( + (UINT8 *)im->image[state->y] + col * im->pixelsize, &byte, 1); col += COL_INCREMENT[context->pass]; } } @@ -250,13 +246,14 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt row_len = get_row_len(state, context->pass); /* Since we're moving to the "first" line, the previous line * should be black to make filters work correctly */ - memset(state->buffer, 0, state->bytes+1); + memset(state->buffer, 0, state->bytes + 1); } } else { - state->shuffle((UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, - state->buffer + context->prefix, - state->xsize); + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->buffer + context->prefix, + state->xsize); state->y++; } @@ -264,7 +261,6 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt context->last_output = 0; if (state->y >= state->ysize || err == Z_STREAM_END) { - /* The image and the data should end simultaneously */ /* if (state->y < state->ysize || err != Z_STREAM_END) state->errcode = IMAGING_CODEC_BROKEN; */ @@ -273,26 +269,23 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt context->previous = NULL; inflateEnd(&context->z_stream); return -1; /* end of file (errcode=0) */ - } /* Swap buffer pointers */ ptr = state->buffer; state->buffer = context->previous; context->previous = ptr; - } return bytes; /* consumed all of it */ - } - -int ImagingZipDecodeCleanup(ImagingCodecState state){ +int +ImagingZipDecodeCleanup(ImagingCodecState state) { /* called to free the decompression engine when the decode terminates due to a corrupt or truncated image */ - ZIPSTATE* context = (ZIPSTATE*) state->context; + ZIPSTATE *context = (ZIPSTATE *)state->context; /* Clean up */ if (context->previous) { diff --git a/src/libImaging/ZipEncode.c b/src/libImaging/ZipEncode.c index 4e862af57..edbce3682 100644 --- a/src/libImaging/ZipEncode.c +++ b/src/libImaging/ZipEncode.c @@ -14,25 +14,22 @@ * See the README file for information on usage and redistribution. */ - #include "Imaging.h" -#ifdef HAVE_LIBZ +#ifdef HAVE_LIBZ #include "ZipCodecs.h" int -ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) -{ - ZIPSTATE* context = (ZIPSTATE*) state->context; +ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) { + ZIPSTATE *context = (ZIPSTATE *)state->context; int err; int compress_level, compress_type; - UINT8* ptr; + UINT8 *ptr; int i, bpp, s, sum; ImagingSectionCookie cookie; if (!state->state) { - /* Initialization */ /* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */ @@ -47,14 +44,14 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) and allocate filter buffers */ free(state->buffer); /* malloc check ok, overflow checked above */ - state->buffer = (UINT8*) malloc(state->bytes+1); - context->previous = (UINT8*) malloc(state->bytes+1); - context->prior = (UINT8*) malloc(state->bytes+1); - context->up = (UINT8*) malloc(state->bytes+1); - context->average = (UINT8*) malloc(state->bytes+1); - context->paeth = (UINT8*) malloc(state->bytes+1); - if (!state->buffer || !context->previous || !context->prior || - !context->up || !context->average || !context->paeth) { + state->buffer = (UINT8 *)malloc(state->bytes + 1); + context->previous = (UINT8 *)malloc(state->bytes + 1); + context->prior = (UINT8 *)malloc(state->bytes + 1); + context->up = (UINT8 *)malloc(state->bytes + 1); + context->average = (UINT8 *)malloc(state->bytes + 1); + context->paeth = (UINT8 *)malloc(state->bytes + 1); + if (!state->buffer || !context->previous || !context->prior || !context->up || + !context->average || !context->paeth) { free(context->paeth); free(context->average); free(context->up); @@ -72,7 +69,7 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->paeth[0] = 4; /* Initialise previous buffer to black */ - memset(context->previous, 0, state->bytes+1); + memset(context->previous, 0, state->bytes + 1); /* Setup compression context */ context->z_stream.zalloc = (alloc_func)0; @@ -81,33 +78,37 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) context->z_stream.next_in = 0; context->z_stream.avail_in = 0; - compress_level = (context->optimize) ? Z_BEST_COMPRESSION - : context->compress_level; + compress_level = + (context->optimize) ? Z_BEST_COMPRESSION : context->compress_level; if (context->compress_type == -1) { - compress_type = (context->mode == ZIP_PNG) ? Z_FILTERED - : Z_DEFAULT_STRATEGY; + compress_type = + (context->mode == ZIP_PNG) ? Z_FILTERED : Z_DEFAULT_STRATEGY; } else { compress_type = context->compress_type; } - err = deflateInit2(&context->z_stream, - /* compression level */ - compress_level, - /* compression method */ - Z_DEFLATED, - /* compression memory resources */ - 15, 9, - /* compression strategy (image data are filtered)*/ - compress_type); + err = deflateInit2( + &context->z_stream, + /* compression level */ + compress_level, + /* compression method */ + Z_DEFLATED, + /* compression memory resources */ + 15, + 9, + /* compression strategy (image data are filtered)*/ + compress_type); if (err < 0) { state->errcode = IMAGING_CODEC_CONFIG; return -1; } if (context->dictionary && context->dictionary_size > 0) { - err = deflateSetDictionary(&context->z_stream, (unsigned char *)context->dictionary, - context->dictionary_size); + err = deflateSetDictionary( + &context->z_stream, + (unsigned char *)context->dictionary, + context->dictionary_size); if (err < 0) { state->errcode = IMAGING_CODEC_CONFIG; return -1; @@ -116,7 +117,6 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) /* Ready to decode */ state->state = 1; - } /* Setup the destination buffer */ @@ -147,203 +147,194 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) ImagingSectionEnter(&cookie); for (;;) { - switch (state->state) { + case 1: - case 1: - - /* Compress image data */ - while (context->z_stream.avail_out > 0) { - - if (state->y >= state->ysize) { - /* End of image; now flush compressor buffers */ - state->state = 2; - break; - - } - - /* Stuff image data into the compressor */ - state->shuffle(state->buffer+1, - (UINT8*) im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, - state->xsize); - - state->y++; - - context->output = state->buffer; - - if (context->mode == ZIP_PNG) { - - /* Filter the image data. For each line, select - the filter that gives the least total distance - from zero for the filtered data (taken from - LIBPNG) */ - - bpp = (state->bits + 7) / 8; - - /* 0. No filter */ - for (i = 1, sum = 0; i <= state->bytes; i++) { - UINT8 v = state->buffer[i]; - sum += (v < 128) ? v : 256 - v; + /* Compress image data */ + while (context->z_stream.avail_out > 0) { + if (state->y >= state->ysize) { + /* End of image; now flush compressor buffers */ + state->state = 2; + break; } - /* 2. Up. We'll test this first to save time when - an image line is identical to the one above. */ - if (sum > 0) { - for (i = 1, s = 0; i <= state->bytes; i++) { - UINT8 v = state->buffer[i] - context->previous[i]; - context->up[i] = v; - s += (v < 128) ? v : 256 - v; - } - if (s < sum) { - context->output = context->up; - sum = s; /* 0 if line was duplicated */ - } - } + /* Stuff image data into the compressor */ + state->shuffle( + state->buffer + 1, + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->xsize); - /* 1. Prior */ - if (sum > 0) { - for (i = 1, s = 0; i <= bpp; i++) { + state->y++; + + context->output = state->buffer; + + if (context->mode == ZIP_PNG) { + /* Filter the image data. For each line, select + the filter that gives the least total distance + from zero for the filtered data (taken from + LIBPNG) */ + + bpp = (state->bits + 7) / 8; + + /* 0. No filter */ + for (i = 1, sum = 0; i <= state->bytes; i++) { UINT8 v = state->buffer[i]; - context->prior[i] = v; - s += (v < 128) ? v : 256 - v; + sum += (v < 128) ? v : 256 - v; } - for (; i <= state->bytes; i++) { - UINT8 v = state->buffer[i] - state->buffer[i-bpp]; - context->prior[i] = v; - s += (v < 128) ? v : 256 - v; + + /* 2. Up. We'll test this first to save time when + an image line is identical to the one above. */ + if (sum > 0) { + for (i = 1, s = 0; i <= state->bytes; i++) { + UINT8 v = state->buffer[i] - context->previous[i]; + context->up[i] = v; + s += (v < 128) ? v : 256 - v; + } + if (s < sum) { + context->output = context->up; + sum = s; /* 0 if line was duplicated */ + } } - if (s < sum) { - context->output = context->prior; - sum = s; /* 0 if line is solid */ + + /* 1. Prior */ + if (sum > 0) { + for (i = 1, s = 0; i <= bpp; i++) { + UINT8 v = state->buffer[i]; + context->prior[i] = v; + s += (v < 128) ? v : 256 - v; + } + for (; i <= state->bytes; i++) { + UINT8 v = state->buffer[i] - state->buffer[i - bpp]; + context->prior[i] = v; + s += (v < 128) ? v : 256 - v; + } + if (s < sum) { + context->output = context->prior; + sum = s; /* 0 if line is solid */ + } + } + + /* 3. Average (not very common in real-life images, + so its only used with the optimize option) */ + if (context->optimize && sum > 0) { + for (i = 1, s = 0; i <= bpp; i++) { + UINT8 v = state->buffer[i] - context->previous[i] / 2; + context->average[i] = v; + s += (v < 128) ? v : 256 - v; + } + for (; i <= state->bytes; i++) { + UINT8 v = + state->buffer[i] - + (state->buffer[i - bpp] + context->previous[i]) / 2; + context->average[i] = v; + s += (v < 128) ? v : 256 - v; + } + if (s < sum) { + context->output = context->average; + sum = s; + } + } + + /* 4. Paeth */ + if (sum > 0) { + for (i = 1, s = 0; i <= bpp; i++) { + UINT8 v = state->buffer[i] - context->previous[i]; + context->paeth[i] = v; + s += (v < 128) ? v : 256 - v; + } + for (; i <= state->bytes; i++) { + UINT8 v; + int a, b, c; + int pa, pb, pc; + + /* fetch pixels */ + a = state->buffer[i - bpp]; + b = context->previous[i]; + c = context->previous[i - bpp]; + + /* distances to surrounding pixels */ + pa = abs(b - c); + pb = abs(a - c); + pc = abs(a + b - 2 * c); + + /* pick predictor with the shortest distance */ + v = state->buffer[i] - ((pa <= pb && pa <= pc) ? a + : (pb <= pc) ? b + : c); + context->paeth[i] = v; + s += (v < 128) ? v : 256 - v; + } + if (s < sum) { + context->output = context->paeth; + sum = s; + } } } - /* 3. Average (not very common in real-life images, - so its only used with the optimize option) */ - if (context->optimize && sum > 0) { - for (i = 1, s = 0; i <= bpp; i++) { - UINT8 v = state->buffer[i] - context->previous[i]/2; - context->average[i] = v; - s += (v < 128) ? v : 256 - v; - } - for (; i <= state->bytes; i++) { - UINT8 v = state->buffer[i] - - (state->buffer[i-bpp] + context->previous[i])/2; - context->average[i] = v; - s += (v < 128) ? v : 256 - v; - } - if (s < sum) { - context->output = context->average; - sum = s; + /* Compress this line */ + context->z_stream.next_in = context->output; + context->z_stream.avail_in = state->bytes + 1; + + err = deflate(&context->z_stream, Z_NO_FLUSH); + + if (err < 0) { + /* Something went wrong inside the compression library */ + if (err == Z_DATA_ERROR) { + state->errcode = IMAGING_CODEC_BROKEN; + } else if (err == Z_MEM_ERROR) { + state->errcode = IMAGING_CODEC_MEMORY; + } else { + state->errcode = IMAGING_CODEC_CONFIG; } + free(context->paeth); + free(context->average); + free(context->up); + free(context->prior); + free(context->previous); + deflateEnd(&context->z_stream); + ImagingSectionLeave(&cookie); + return -1; } - /* 4. Paeth */ - if (sum > 0) { - for (i = 1, s = 0; i <= bpp; i++) { - UINT8 v = state->buffer[i] - context->previous[i]; - context->paeth[i] = v; - s += (v < 128) ? v : 256 - v; - } - for (; i <= state->bytes; i++) { - UINT8 v; - int a, b, c; - int pa, pb, pc; - - /* fetch pixels */ - a = state->buffer[i-bpp]; - b = context->previous[i]; - c = context->previous[i-bpp]; - - /* distances to surrounding pixels */ - pa = abs(b - c); - pb = abs(a - c); - pc = abs(a + b - 2*c); - - /* pick predictor with the shortest distance */ - v = state->buffer[i] - - ((pa <= pb && pa <= pc) ? a : - (pb <= pc) ? b : c); - context->paeth[i] = v; - s += (v < 128) ? v : 256 - v; - } - if (s < sum) { - context->output = context->paeth; - sum = s; - } - } - } - - /* Compress this line */ - context->z_stream.next_in = context->output; - context->z_stream.avail_in = state->bytes+1; - - err = deflate(&context->z_stream, Z_NO_FLUSH); - - if (err < 0) { - /* Something went wrong inside the compression library */ - if (err == Z_DATA_ERROR) { - state->errcode = IMAGING_CODEC_BROKEN; - } else if (err == Z_MEM_ERROR) { - state->errcode = IMAGING_CODEC_MEMORY; - } else { - state->errcode = IMAGING_CODEC_CONFIG; - } - free(context->paeth); - free(context->average); - free(context->up); - free(context->prior); - free(context->previous); - deflateEnd(&context->z_stream); - ImagingSectionLeave(&cookie); - return -1; - } - - /* Swap buffer pointers */ - ptr = state->buffer; - state->buffer = context->previous; - context->previous = ptr; - - } - - if (context->z_stream.avail_out == 0) { - break; /* Buffer full */ - } - - case 2: - - /* End of image data; flush compressor buffers */ - - while (context->z_stream.avail_out > 0) { - - err = deflate(&context->z_stream, Z_FINISH); - - if (err == Z_STREAM_END) { - - free(context->paeth); - free(context->average); - free(context->up); - free(context->prior); - free(context->previous); - - deflateEnd(&context->z_stream); - - state->errcode = IMAGING_CODEC_END; - - break; + /* Swap buffer pointers */ + ptr = state->buffer; + state->buffer = context->previous; + context->previous = ptr; } if (context->z_stream.avail_out == 0) { break; /* Buffer full */ } - } + case 2: + /* End of image data; flush compressor buffers */ + + while (context->z_stream.avail_out > 0) { + err = deflate(&context->z_stream, Z_FINISH); + + if (err == Z_STREAM_END) { + free(context->paeth); + free(context->average); + free(context->up); + free(context->prior); + free(context->previous); + + deflateEnd(&context->z_stream); + + state->errcode = IMAGING_CODEC_END; + + break; + } + + if (context->z_stream.avail_out == 0) { + break; /* Buffer full */ + } + } } ImagingSectionLeave(&cookie); return bytes - context->z_stream.avail_out; - } /* Should never ever arrive here... */ @@ -358,21 +349,18 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) int ImagingZipEncodeCleanup(ImagingCodecState state) { - ZIPSTATE* context = (ZIPSTATE*) state->context; + ZIPSTATE *context = (ZIPSTATE *)state->context; if (context->dictionary) { - free (context->dictionary); + free(context->dictionary); context->dictionary = NULL; } return -1; } - - -const char* -ImagingZipVersion(void) -{ +const char * +ImagingZipVersion(void) { return zlibVersion(); } diff --git a/src/libImaging/codec_fd.c b/src/libImaging/codec_fd.c index 5cde31cdc..526168110 100644 --- a/src/libImaging/codec_fd.c +++ b/src/libImaging/codec_fd.c @@ -1,10 +1,8 @@ #include "Python.h" #include "Imaging.h" - Py_ssize_t -_imaging_read_pyFd(PyObject *fd, char* dest, Py_ssize_t bytes) -{ +_imaging_read_pyFd(PyObject *fd, char *dest, Py_ssize_t bytes) { /* dest should be a buffer bytes long, returns length of read -1 on error */ @@ -29,16 +27,13 @@ _imaging_read_pyFd(PyObject *fd, char* dest, Py_ssize_t bytes) Py_DECREF(result); return length; - err: +err: Py_DECREF(result); return -1; - } Py_ssize_t -_imaging_write_pyFd(PyObject *fd, char* src, Py_ssize_t bytes) -{ - +_imaging_write_pyFd(PyObject *fd, char *src, Py_ssize_t bytes) { PyObject *result; PyObject *byteObj; @@ -49,24 +44,20 @@ _imaging_write_pyFd(PyObject *fd, char* src, Py_ssize_t bytes) Py_DECREF(result); return bytes; - } int -_imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence) -{ +_imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence) { PyObject *result; result = PyObject_CallMethod(fd, "seek", "ni", offset, whence); Py_DECREF(result); return 0; - } Py_ssize_t -_imaging_tell_pyFd(PyObject *fd) -{ +_imaging_tell_pyFd(PyObject *fd) { PyObject *result; Py_ssize_t location; diff --git a/src/map.c b/src/map.c index df2718ed7..c298bd148 100644 --- a/src/map.c +++ b/src/map.c @@ -23,320 +23,56 @@ #include "libImaging/Imaging.h" /* compatibility wrappers (defined in _imaging.c) */ -extern int PyImaging_CheckBuffer(PyObject* buffer); -extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view); +extern int +PyImaging_CheckBuffer(PyObject *buffer); +extern int +PyImaging_GetBuffer(PyObject *buffer, Py_buffer *view); -/* -------------------------------------------------------------------- */ -/* Standard mapper */ - -typedef struct { - PyObject_HEAD - char* base; - int size; - int offset; -#ifdef _WIN32 - HANDLE hFile; - HANDLE hMap; -#endif -} ImagingMapperObject; - -static PyTypeObject ImagingMapperType; - -ImagingMapperObject* -PyImaging_MapperNew(const char* filename, int readonly) -{ - ImagingMapperObject *mapper; - - if (PyType_Ready(&ImagingMapperType) < 0) { - return NULL; - } - - mapper = PyObject_New(ImagingMapperObject, &ImagingMapperType); - if (mapper == NULL) { - return NULL; - } - - mapper->base = NULL; - mapper->size = mapper->offset = 0; - -#ifdef _WIN32 - mapper->hFile = (HANDLE)-1; - mapper->hMap = (HANDLE)-1; - - /* FIXME: currently supports readonly mappings only */ - mapper->hFile = CreateFile( - filename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (mapper->hFile == (HANDLE)-1) { - PyErr_SetString(PyExc_OSError, "cannot open file"); - Py_DECREF(mapper); - return NULL; - } - - mapper->hMap = CreateFileMapping( - mapper->hFile, NULL, - PAGE_READONLY, - 0, 0, NULL); - if (mapper->hMap == (HANDLE)-1) { - CloseHandle(mapper->hFile); - PyErr_SetString(PyExc_OSError, "cannot map file"); - Py_DECREF(mapper); - return NULL; - } - - mapper->base = (char*) MapViewOfFile( - mapper->hMap, - FILE_MAP_READ, - 0, 0, 0); - - mapper->size = GetFileSize(mapper->hFile, 0); -#endif - - return mapper; -} - -static void -mapping_dealloc(ImagingMapperObject* mapper) -{ -#ifdef _WIN32 - if (mapper->base != 0) { - UnmapViewOfFile(mapper->base); - } - if (mapper->hMap != (HANDLE)-1) { - CloseHandle(mapper->hMap); - } - if (mapper->hFile != (HANDLE)-1) { - CloseHandle(mapper->hFile); - } - mapper->base = 0; - mapper->hMap = mapper->hFile = (HANDLE)-1; -#endif - PyObject_Del(mapper); -} - -/* -------------------------------------------------------------------- */ -/* standard file operations */ - -static PyObject* -mapping_read(ImagingMapperObject* mapper, PyObject* args) -{ - PyObject* buf; - - int size = -1; - if (!PyArg_ParseTuple(args, "|i", &size)) { - return NULL; - } - - /* check size */ - if (size < 0 || mapper->offset + size > mapper->size) { - size = mapper->size - mapper->offset; - } - if (size < 0) { - size = 0; - } - - buf = PyBytes_FromStringAndSize(NULL, size); - if (!buf) { - return NULL; - } - - if (size > 0) { - memcpy(PyBytes_AsString(buf), mapper->base + mapper->offset, size); - mapper->offset += size; - } - - return buf; -} - -static PyObject* -mapping_seek(ImagingMapperObject* mapper, PyObject* args) -{ - int offset; - int whence = 0; - if (!PyArg_ParseTuple(args, "i|i", &offset, &whence)) { - return NULL; - } - - switch (whence) { - case 0: /* SEEK_SET */ - mapper->offset = offset; - break; - case 1: /* SEEK_CUR */ - mapper->offset += offset; - break; - case 2: /* SEEK_END */ - mapper->offset = mapper->size + offset; - break; - default: - /* FIXME: raise ValueError? */ - break; - } - - Py_INCREF(Py_None); - return Py_None; -} - -/* -------------------------------------------------------------------- */ -/* map entire image */ - -extern PyObject*PyImagingNew(Imaging im); - -static void -ImagingDestroyMap(Imaging im) -{ - return; /* nothing to do! */ -} - -static PyObject* -mapping_readimage(ImagingMapperObject* mapper, PyObject* args) -{ - int y, size; - Imaging im; - - char* mode; - int xsize; - int ysize; - int stride; - int orientation; - if (!PyArg_ParseTuple(args, "s(ii)ii", &mode, &xsize, &ysize, - &stride, &orientation)) { - return NULL; - } - - if (stride <= 0) { - /* FIXME: maybe we should call ImagingNewPrologue instead */ - if (!strcmp(mode, "L") || !strcmp(mode, "P")) { - stride = xsize; - } else if (!strcmp(mode, "I;16") || !strcmp(mode, "I;16B")) { - stride = xsize * 2; - } else { - stride = xsize * 4; - } - } - - size = ysize * stride; - - if (mapper->offset + size > mapper->size) { - PyErr_SetString(PyExc_OSError, "image file truncated"); - return NULL; - } - - im = ImagingNewPrologue(mode, xsize, ysize); - if (!im) { - return NULL; - } - - /* setup file pointers */ - if (orientation > 0) { - for (y = 0; y < ysize; y++) { - im->image[y] = mapper->base + mapper->offset + y * stride; - } - } else { - for (y = 0; y < ysize; y++) { - im->image[ysize-y-1] = mapper->base + mapper->offset + y * stride; - } - } - - im->destroy = ImagingDestroyMap; - - mapper->offset += size; - - return PyImagingNew(im); -} - -static struct PyMethodDef methods[] = { - /* standard file interface */ - {"read", (PyCFunction)mapping_read, 1}, - {"seek", (PyCFunction)mapping_seek, 1}, - /* extensions */ - {"readimage", (PyCFunction)mapping_readimage, 1}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject ImagingMapperType = { - PyVarObject_HEAD_INIT(NULL, 0) - "ImagingMapper", /*tp_name*/ - sizeof(ImagingMapperObject), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)mapping_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - methods, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ -}; - -PyObject* -PyImaging_Mapper(PyObject* self, PyObject* args) -{ - char* filename; - if (!PyArg_ParseTuple(args, "s", &filename)) { - return NULL; - } - - return (PyObject*) PyImaging_MapperNew(filename, 1); -} +extern PyObject * +PyImagingNew(Imaging im); /* -------------------------------------------------------------------- */ /* Buffer mapper */ typedef struct ImagingBufferInstance { struct ImagingMemoryInstance im; - PyObject* target; + PyObject *target; Py_buffer view; } ImagingBufferInstance; static void -mapping_destroy_buffer(Imaging im) -{ - ImagingBufferInstance* buffer = (ImagingBufferInstance*) im; +mapping_destroy_buffer(Imaging im) { + ImagingBufferInstance *buffer = (ImagingBufferInstance *)im; PyBuffer_Release(&buffer->view); Py_XDECREF(buffer->target); } -PyObject* -PyImaging_MapBuffer(PyObject* self, PyObject* args) -{ +PyObject * +PyImaging_MapBuffer(PyObject *self, PyObject *args) { Py_ssize_t y, size; Imaging im; - PyObject* target; + PyObject *target; Py_buffer view; - char* mode; - char* codec; + char *mode; + char *codec; Py_ssize_t offset; int xsize, ysize; int stride; int ystep; - if (!PyArg_ParseTuple(args, "O(ii)sn(sii)", &target, &xsize, &ysize, - &codec, &offset, &mode, &stride, &ystep)) { + if (!PyArg_ParseTuple( + args, + "O(ii)sn(sii)", + &target, + &xsize, + &ysize, + &codec, + &offset, + &mode, + &stride, + &ystep)) { return NULL; } @@ -360,7 +96,7 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args) return NULL; } - size = (Py_ssize_t) ysize * stride; + size = (Py_ssize_t)ysize * stride; if (offset > PY_SSIZE_T_MAX - size) { PyErr_SetString(PyExc_MemoryError, "Integer overflow in offset"); @@ -383,8 +119,7 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args) return NULL; } - im = ImagingNewPrologueSubtype( - mode, xsize, ysize, sizeof(ImagingBufferInstance)); + im = ImagingNewPrologueSubtype(mode, xsize, ysize, sizeof(ImagingBufferInstance)); if (!im) { PyBuffer_Release(&view); return NULL; @@ -393,20 +128,19 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args) /* setup file pointers */ if (ystep > 0) { for (y = 0; y < ysize; y++) { - im->image[y] = (char*)view.buf + offset + y * stride; + im->image[y] = (char *)view.buf + offset + y * stride; } } else { for (y = 0; y < ysize; y++) { - im->image[ysize-y-1] = (char*)view.buf + offset + y * stride; + im->image[ysize - y - 1] = (char *)view.buf + offset + y * stride; } } im->destroy = mapping_destroy_buffer; Py_INCREF(target); - ((ImagingBufferInstance*) im)->target = target; - ((ImagingBufferInstance*) im)->view = view; + ((ImagingBufferInstance *)im)->target = target; + ((ImagingBufferInstance *)im)->view = view; return PyImagingNew(im); } - diff --git a/src/outline.c b/src/outline.c index a109189e1..0a9a3646e 100644 --- a/src/outline.c +++ b/src/outline.c @@ -21,22 +21,19 @@ #include "libImaging/Imaging.h" - /* -------------------------------------------------------------------- */ /* Class */ typedef struct { - PyObject_HEAD - ImagingOutline outline; + PyObject_HEAD ImagingOutline outline; } OutlineObject; static PyTypeObject OutlineType; #define PyOutline_Check(op) (Py_TYPE(op) == &OutlineType) -static OutlineObject* -_outline_new(void) -{ +static OutlineObject * +_outline_new(void) { OutlineObject *self; if (PyType_Ready(&OutlineType) < 0) { @@ -54,43 +51,37 @@ _outline_new(void) } static void -_outline_dealloc(OutlineObject* self) -{ +_outline_dealloc(OutlineObject *self) { ImagingOutlineDelete(self->outline); PyObject_Del(self); } ImagingOutline -PyOutline_AsOutline(PyObject* outline) -{ +PyOutline_AsOutline(PyObject *outline) { if (PyOutline_Check(outline)) { - return ((OutlineObject*) outline)->outline; + return ((OutlineObject *)outline)->outline; } return NULL; } - /* -------------------------------------------------------------------- */ /* Factories */ -PyObject* -PyOutline_Create(PyObject* self, PyObject* args) -{ +PyObject * +PyOutline_Create(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":outline")) { return NULL; } - return (PyObject*) _outline_new(); + return (PyObject *)_outline_new(); } - /* -------------------------------------------------------------------- */ /* Methods */ -static PyObject* -_outline_move(OutlineObject* self, PyObject* args) -{ +static PyObject * +_outline_move(OutlineObject *self, PyObject *args) { float x0, y0; if (!PyArg_ParseTuple(args, "ff", &x0, &y0)) { return NULL; @@ -102,9 +93,8 @@ _outline_move(OutlineObject* self, PyObject* args) return Py_None; } -static PyObject* -_outline_line(OutlineObject* self, PyObject* args) -{ +static PyObject * +_outline_line(OutlineObject *self, PyObject *args) { float x1, y1; if (!PyArg_ParseTuple(args, "ff", &x1, &y1)) { return NULL; @@ -116,9 +106,8 @@ _outline_line(OutlineObject* self, PyObject* args) return Py_None; } -static PyObject* -_outline_curve(OutlineObject* self, PyObject* args) -{ +static PyObject * +_outline_curve(OutlineObject *self, PyObject *args) { float x1, y1, x2, y2, x3, y3; if (!PyArg_ParseTuple(args, "ffffff", &x1, &y1, &x2, &y2, &x3, &y3)) { return NULL; @@ -130,9 +119,8 @@ _outline_curve(OutlineObject* self, PyObject* args) return Py_None; } -static PyObject* -_outline_close(OutlineObject* self, PyObject* args) -{ +static PyObject * +_outline_close(OutlineObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":close")) { return NULL; } @@ -143,11 +131,10 @@ _outline_close(OutlineObject* self, PyObject* args) return Py_None; } -static PyObject* -_outline_transform(OutlineObject* self, PyObject* args) -{ +static PyObject * +_outline_transform(OutlineObject *self, PyObject *args) { double a[6]; - if (!PyArg_ParseTuple(args, "(dddddd)", a+0, a+1, a+2, a+3, a+4, a+5)) { + if (!PyArg_ParseTuple(args, "(dddddd)", a + 0, a + 1, a + 2, a + 3, a + 4, a + 5)) { return NULL; } @@ -158,44 +145,43 @@ _outline_transform(OutlineObject* self, PyObject* args) } static struct PyMethodDef _outline_methods[] = { - {"line", (PyCFunction)_outline_line, 1}, - {"curve", (PyCFunction)_outline_curve, 1}, - {"move", (PyCFunction)_outline_move, 1}, - {"close", (PyCFunction)_outline_close, 1}, - {"transform", (PyCFunction)_outline_transform, 1}, + {"line", (PyCFunction)_outline_line, METH_VARARGS}, + {"curve", (PyCFunction)_outline_curve, METH_VARARGS}, + {"move", (PyCFunction)_outline_move, METH_VARARGS}, + {"close", (PyCFunction)_outline_close, METH_VARARGS}, + {"transform", (PyCFunction)_outline_transform, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; static PyTypeObject OutlineType = { - PyVarObject_HEAD_INIT(NULL, 0) - "Outline", /*tp_name*/ - sizeof(OutlineObject), /*tp_size*/ - 0, /*tp_itemsize*/ + PyVarObject_HEAD_INIT(NULL, 0) "Outline", /*tp_name*/ + sizeof(OutlineObject), /*tp_size*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)_outline_dealloc,/*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - _outline_methods, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ + (destructor)_outline_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + _outline_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ }; diff --git a/src/path.c b/src/path.c index 62e7e15b5..4764c58aa 100644 --- a/src/path.c +++ b/src/path.c @@ -25,37 +25,36 @@ * See the README file for information on usage and redistribution. */ - #include "Python.h" #include "libImaging/Imaging.h" #include /* compatibility wrappers (defined in _imaging.c) */ -extern int PyImaging_CheckBuffer(PyObject* buffer); -extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view); +extern int +PyImaging_CheckBuffer(PyObject *buffer); +extern int +PyImaging_GetBuffer(PyObject *buffer, Py_buffer *view); /* -------------------------------------------------------------------- */ /* Class */ /* -------------------------------------------------------------------- */ typedef struct { - PyObject_HEAD - Py_ssize_t count; + PyObject_HEAD Py_ssize_t count; double *xy; int index; /* temporary use, e.g. in decimate */ } PyPathObject; static PyTypeObject PyPathType; -static double* -alloc_array(Py_ssize_t count) -{ - double* xy; +static double * +alloc_array(Py_ssize_t count) { + double *xy; if (count < 0) { return ImagingError_MemoryError(); } - if ((unsigned long long)count > (SIZE_MAX / (2 * sizeof(double))) - 1 ) { + if ((unsigned long long)count > (SIZE_MAX / (2 * sizeof(double))) - 1) { return ImagingError_MemoryError(); } xy = malloc(2 * count * sizeof(double) + 1); @@ -65,14 +64,13 @@ alloc_array(Py_ssize_t count) return xy; } -static PyPathObject* -path_new(Py_ssize_t count, double* xy, int duplicate) -{ +static PyPathObject * +path_new(Py_ssize_t count, double *xy, int duplicate) { PyPathObject *path; if (duplicate) { /* duplicate path */ - double* p = alloc_array(count); + double *p = alloc_array(count); if (!p) { return NULL; } @@ -98,8 +96,7 @@ path_new(Py_ssize_t count, double* xy, int duplicate) } static void -path_dealloc(PyPathObject* path) -{ +path_dealloc(PyPathObject *path) { free(path->xy); PyObject_Del(path); } @@ -111,14 +108,13 @@ path_dealloc(PyPathObject* path) #define PyPath_Check(op) (Py_TYPE(op) == &PyPathType) Py_ssize_t -PyPath_Flatten(PyObject* data, double **pxy) -{ +PyPath_Flatten(PyObject *data, double **pxy) { Py_ssize_t i, j, n; double *xy; if (PyPath_Check(data)) { /* This was another path object. */ - PyPathObject *path = (PyPathObject*) data; + PyPathObject *path = (PyPathObject *)data; xy = alloc_array(path->count); if (!xy) { return -1; @@ -132,13 +128,13 @@ PyPath_Flatten(PyObject* data, double **pxy) /* Assume the buffer contains floats */ Py_buffer buffer; if (PyImaging_GetBuffer(data, &buffer) == 0) { - float *ptr = (float*) buffer.buf; + float *ptr = (float *)buffer.buf; n = buffer.len / (2 * sizeof(float)); xy = alloc_array(n); if (!xy) { return -1; } - for (i = 0; i < n+n; i++) { + for (i = 0; i < n + n; i++) { xy[i] = ptr[i]; } *pxy = xy; @@ -174,7 +170,7 @@ PyPath_Flatten(PyObject* data, double **pxy) if (PyFloat_Check(op)) { xy[j++] = PyFloat_AS_DOUBLE(op); } else if (PyLong_Check(op)) { - xy[j++] = (float) PyLong_AS_LONG(op); + xy[j++] = (float)PyLong_AS_LONG(op); } else if (PyNumber_Check(op)) { xy[j++] = PyFloat_AsDouble(op); } else if (PyArg_ParseTuple(op, "dd", &x, &y)) { @@ -192,7 +188,7 @@ PyPath_Flatten(PyObject* data, double **pxy) if (PyFloat_Check(op)) { xy[j++] = PyFloat_AS_DOUBLE(op); } else if (PyLong_Check(op)) { - xy[j++] = (float) PyLong_AS_LONG(op); + xy[j++] = (float)PyLong_AS_LONG(op); } else if (PyNumber_Check(op)) { xy[j++] = PyFloat_AsDouble(op); } else if (PyArg_ParseTuple(op, "dd", &x, &y)) { @@ -209,8 +205,7 @@ PyPath_Flatten(PyObject* data, double **pxy) PyObject *op = PySequence_GetItem(data, i); if (!op) { /* treat IndexError as end of sequence */ - if (PyErr_Occurred() && - PyErr_ExceptionMatches(PyExc_IndexError)) { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_IndexError)) { PyErr_Clear(); break; } else { @@ -221,7 +216,7 @@ PyPath_Flatten(PyObject* data, double **pxy) if (PyFloat_Check(op)) { xy[j++] = PyFloat_AS_DOUBLE(op); } else if (PyLong_Check(op)) { - xy[j++] = (float) PyLong_AS_LONG(op); + xy[j++] = (float)PyLong_AS_LONG(op); } else if (PyNumber_Check(op)) { xy[j++] = PyFloat_AsDouble(op); } else if (PyArg_ParseTuple(op, "dd", &x, &y)) { @@ -243,23 +238,20 @@ PyPath_Flatten(PyObject* data, double **pxy) } *pxy = xy; - return j/2; + return j / 2; } - /* -------------------------------------------------------------------- */ /* Factories */ /* -------------------------------------------------------------------- */ -PyObject* -PyPath_Create(PyObject* self, PyObject* args) -{ - PyObject* data; +PyObject * +PyPath_Create(PyObject *self, PyObject *args) { + PyObject *data; Py_ssize_t count; double *xy; if (PyArg_ParseTuple(args, "n:Path", &count)) { - /* number of vertices */ xy = alloc_array(count); if (!xy) { @@ -267,7 +259,6 @@ PyPath_Create(PyObject* self, PyObject* args) } } else { - /* sequence or other path */ PyErr_Clear(); if (!PyArg_ParseTuple(args, "O", &data)) { @@ -280,17 +271,15 @@ PyPath_Create(PyObject* self, PyObject* args) } } - return (PyObject*) path_new(count, xy, 0); + return (PyObject *)path_new(count, xy, 0); } - /* -------------------------------------------------------------------- */ /* Methods */ /* -------------------------------------------------------------------- */ -static PyObject* -path_compact(PyPathObject* self, PyObject* args) -{ +static PyObject * +path_compact(PyPathObject *self, PyObject *args) { /* Simple-minded method to shorten path. A point is removed if the city block distance to the previous point is less than the given distance */ @@ -307,9 +296,10 @@ path_compact(PyPathObject* self, PyObject* args) /* remove bogus vertices */ for (i = j = 1; i < self->count; i++) { - if (fabs(xy[j+j-2]-xy[i+i]) + fabs(xy[j+j-1]-xy[i+i+1]) >= cityblock) { - xy[j+j] = xy[i+i]; - xy[j+j+1] = xy[i+i+1]; + if (fabs(xy[j + j - 2] - xy[i + i]) + fabs(xy[j + j - 1] - xy[i + i + 1]) >= + cityblock) { + xy[j + j] = xy[i + i]; + xy[j + j + 1] = xy[i + i + 1]; j++; } } @@ -324,9 +314,8 @@ path_compact(PyPathObject* self, PyObject* args) return Py_BuildValue("i", i); /* number of removed vertices */ } -static PyObject* -path_getbbox(PyPathObject* self, PyObject* args) -{ +static PyObject * +path_getbbox(PyPathObject *self, PyObject *args) { /* Find bounding box */ Py_ssize_t i; double *xy; @@ -342,26 +331,25 @@ path_getbbox(PyPathObject* self, PyObject* args) y0 = y1 = xy[1]; for (i = 1; i < self->count; i++) { - if (xy[i+i] < x0) { - x0 = xy[i+i]; + if (xy[i + i] < x0) { + x0 = xy[i + i]; } - if (xy[i+i] > x1) { - x1 = xy[i+i]; + if (xy[i + i] > x1) { + x1 = xy[i + i]; } - if (xy[i+i+1] < y0) { - y0 = xy[i+i+1]; + if (xy[i + i + 1] < y0) { + y0 = xy[i + i + 1]; } - if (xy[i+i+1] > y1) { - y1 = xy[i+i+1]; + if (xy[i + i + 1] > y1) { + y1 = xy[i + i + 1]; } } return Py_BuildValue("dddd", x0, y0, x1, y1); } -static PyObject* -path_getitem(PyPathObject* self, Py_ssize_t i) -{ +static PyObject * +path_getitem(PyPathObject *self, Py_ssize_t i) { if (i < 0) { i = self->count + i; } @@ -370,12 +358,11 @@ path_getitem(PyPathObject* self, Py_ssize_t i) return NULL; } - return Py_BuildValue("dd", self->xy[i+i], self->xy[i+i+1]); + return Py_BuildValue("dd", self->xy[i + i], self->xy[i + i + 1]); } -static PyObject* -path_getslice(PyPathObject* self, Py_ssize_t ilow, Py_ssize_t ihigh) -{ +static PyObject * +path_getslice(PyPathObject *self, Py_ssize_t ilow, Py_ssize_t ihigh) { /* adjust arguments */ if (ilow < 0) { ilow = 0; @@ -391,22 +378,20 @@ path_getslice(PyPathObject* self, Py_ssize_t ilow, Py_ssize_t ihigh) ihigh = self->count; } - return (PyObject*) path_new(ihigh - ilow, self->xy + ilow * 2, 1); + return (PyObject *)path_new(ihigh - ilow, self->xy + ilow * 2, 1); } static Py_ssize_t -path_len(PyPathObject* self) -{ +path_len(PyPathObject *self) { return self->count; } -static PyObject* -path_map(PyPathObject* self, PyObject* args) -{ +static PyObject * +path_map(PyPathObject *self, PyObject *args) { /* Map coordinate set through function */ Py_ssize_t i; double *xy; - PyObject* function; + PyObject *function; if (!PyArg_ParseTuple(args, "O:map", &function)) { return NULL; @@ -416,15 +401,15 @@ path_map(PyPathObject* self, PyObject* args) /* apply function to coordinate set */ for (i = 0; i < self->count; i++) { - double x = xy[i+i]; - double y = xy[i+i+1]; - PyObject* item = PyObject_CallFunction(function, "dd", x, y); + double x = xy[i + i]; + double y = xy[i + i + 1]; + PyObject *item = PyObject_CallFunction(function, "dd", x, y); if (!item || !PyArg_ParseTuple(item, "dd", &x, &y)) { Py_XDECREF(item); return NULL; } - xy[i+i] = x; - xy[i+i+1] = y; + xy[i + i] = x; + xy[i + i + 1] = y; Py_DECREF(item); } @@ -433,23 +418,20 @@ path_map(PyPathObject* self, PyObject* args) } static int -path_setitem(PyPathObject* self, Py_ssize_t i, PyObject* op) -{ - double* xy; +path_setitem(PyPathObject *self, Py_ssize_t i, PyObject *op) { + double *xy; if (i < 0 || i >= self->count) { - PyErr_SetString(PyExc_IndexError, - "path assignment index out of range"); + PyErr_SetString(PyExc_IndexError, "path assignment index out of range"); return -1; } if (op == NULL) { - PyErr_SetString(PyExc_TypeError, - "cannot delete from path"); + PyErr_SetString(PyExc_TypeError, "cannot delete from path"); return -1; } - xy = &self->xy[i+i]; + xy = &self->xy[i + i]; if (!PyArg_ParseTuple(op, "dd", &xy[0], &xy[1])) { return -1; @@ -458,9 +440,8 @@ path_setitem(PyPathObject* self, Py_ssize_t i, PyObject* op) return 0; } -static PyObject* -path_tolist(PyPathObject* self, PyObject* args) -{ +static PyObject * +path_tolist(PyPathObject *self, PyObject *args) { PyObject *list; Py_ssize_t i; @@ -470,9 +451,9 @@ path_tolist(PyPathObject* self, PyObject* args) } if (flat) { - list = PyList_New(self->count*2); - for (i = 0; i < self->count*2; i++) { - PyObject* item; + list = PyList_New(self->count * 2); + for (i = 0; i < self->count * 2; i++) { + PyObject *item; item = PyFloat_FromDouble(self->xy[i]); if (!item) { goto error; @@ -482,8 +463,8 @@ path_tolist(PyPathObject* self, PyObject* args) } else { list = PyList_New(self->count); for (i = 0; i < self->count; i++) { - PyObject* item; - item = Py_BuildValue("dd", self->xy[i+i], self->xy[i+i+1]); + PyObject *item; + item = Py_BuildValue("dd", self->xy[i + i], self->xy[i + i + 1]); if (!item) { goto error; } @@ -498,9 +479,8 @@ error: return NULL; } -static PyObject* -path_transform(PyPathObject* self, PyObject* args) -{ +static PyObject * +path_transform(PyPathObject *self, PyObject *args) { /* Apply affine transform to coordinate set */ Py_ssize_t i; double *xy; @@ -508,9 +488,8 @@ path_transform(PyPathObject* self, PyObject* args) double wrap = 0.0; - if (!PyArg_ParseTuple(args, "(dddddd)|d:transform", - &a, &b, &c, &d, &e, &f, - &wrap)) { + if (!PyArg_ParseTuple( + args, "(dddddd)|d:transform", &a, &b, &c, &d, &e, &f, &wrap)) { return NULL; } @@ -520,23 +499,23 @@ path_transform(PyPathObject* self, PyObject* args) if (b == 0.0 && d == 0.0) { /* scaling */ for (i = 0; i < self->count; i++) { - xy[i+i] = a*xy[i+i]+c; - xy[i+i+1] = e*xy[i+i+1]+f; + xy[i + i] = a * xy[i + i] + c; + xy[i + i + 1] = e * xy[i + i + 1] + f; } } else { /* affine transform */ for (i = 0; i < self->count; i++) { - double x = xy[i+i]; - double y = xy[i+i+1]; - xy[i+i] = a*x+b*y+c; - xy[i+i+1] = d*x+e*y+f; + double x = xy[i + i]; + double y = xy[i + i + 1]; + xy[i + i] = a * x + b * y + c; + xy[i + i + 1] = d * x + e * y + f; } } /* special treatment of geographical map data */ if (wrap != 0.0) { for (i = 0; i < self->count; i++) { - xy[i+i] = fmod(xy[i+i], wrap); + xy[i + i] = fmod(xy[i + i], wrap); } } @@ -545,27 +524,23 @@ path_transform(PyPathObject* self, PyObject* args) } static struct PyMethodDef methods[] = { - {"getbbox", (PyCFunction)path_getbbox, 1}, - {"tolist", (PyCFunction)path_tolist, 1}, - {"compact", (PyCFunction)path_compact, 1}, - {"map", (PyCFunction)path_map, 1}, - {"transform", (PyCFunction)path_transform, 1}, + {"getbbox", (PyCFunction)path_getbbox, METH_VARARGS}, + {"tolist", (PyCFunction)path_tolist, METH_VARARGS}, + {"compact", (PyCFunction)path_compact, METH_VARARGS}, + {"map", (PyCFunction)path_map, METH_VARARGS}, + {"transform", (PyCFunction)path_transform, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; -static PyObject* -path_getattr_id(PyPathObject* self, void* closure) -{ - return Py_BuildValue("n", (Py_ssize_t) self->xy); +static PyObject * +path_getattr_id(PyPathObject *self, void *closure) { + return Py_BuildValue("n", (Py_ssize_t)self->xy); } -static struct PyGetSetDef getsetters[] = { - { "id", (getter) path_getattr_id }, - { NULL } -}; +static struct PyGetSetDef getsetters[] = {{"id", (getter)path_getattr_id}, {NULL}}; -static PyObject* -path_subscript(PyPathObject* self, PyObject* item) { +static PyObject * +path_subscript(PyPathObject *self, PyObject *item) { if (PyIndex_Check(item)) { Py_ssize_t i; i = PyNumber_AsSsize_t(item, PyExc_IndexError); @@ -584,71 +559,64 @@ path_subscript(PyPathObject* self, PyObject* item) { if (slicelength <= 0) { double *xy = alloc_array(0); - return (PyObject*) path_new(0, xy, 0); - } - else if (step == 1) { + return (PyObject *)path_new(0, xy, 0); + } else if (step == 1) { return path_getslice(self, start, stop); - } - else { + } else { PyErr_SetString(PyExc_TypeError, "slice steps not supported"); return NULL; } - } - else { - PyErr_Format(PyExc_TypeError, - "Path indices must be integers, not %.200s", - Py_TYPE(item)->tp_name); + } else { + PyErr_Format( + PyExc_TypeError, + "Path indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); return NULL; } } static PySequenceMethods path_as_sequence = { - (lenfunc)path_len, /*sq_length*/ - (binaryfunc)0, /*sq_concat*/ - (ssizeargfunc)0, /*sq_repeat*/ - (ssizeargfunc)path_getitem, /*sq_item*/ - (ssizessizeargfunc)path_getslice, /*sq_slice*/ - (ssizeobjargproc)path_setitem, /*sq_ass_item*/ - (ssizessizeobjargproc)0, /*sq_ass_slice*/ + (lenfunc)path_len, /*sq_length*/ + (binaryfunc)0, /*sq_concat*/ + (ssizeargfunc)0, /*sq_repeat*/ + (ssizeargfunc)path_getitem, /*sq_item*/ + (ssizessizeargfunc)path_getslice, /*sq_slice*/ + (ssizeobjargproc)path_setitem, /*sq_ass_item*/ + (ssizessizeobjargproc)0, /*sq_ass_slice*/ }; static PyMappingMethods path_as_mapping = { - (lenfunc)path_len, - (binaryfunc)path_subscript, - NULL -}; + (lenfunc)path_len, (binaryfunc)path_subscript, NULL}; static PyTypeObject PyPathType = { - PyVarObject_HEAD_INIT(NULL, 0) - "Path", /*tp_name*/ - sizeof(PyPathObject), /*tp_size*/ - 0, /*tp_itemsize*/ + PyVarObject_HEAD_INIT(NULL, 0) "Path", /*tp_name*/ + sizeof(PyPathObject), /*tp_size*/ + 0, /*tp_itemsize*/ /* methods */ - (destructor)path_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - &path_as_sequence, /*tp_as_sequence */ - &path_as_mapping, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - methods, /*tp_methods*/ - 0, /*tp_members*/ - getsetters, /*tp_getset*/ + (destructor)path_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + &path_as_sequence, /*tp_as_sequence */ + &path_as_mapping, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + methods, /*tp_methods*/ + 0, /*tp_members*/ + getsetters, /*tp_getset*/ }; - diff --git a/src/thirdparty/fribidi-shim/fribidi.c b/src/thirdparty/fribidi-shim/fribidi.c new file mode 100644 index 000000000..abbab07b0 --- /dev/null +++ b/src/thirdparty/fribidi-shim/fribidi.c @@ -0,0 +1,104 @@ + +#ifndef _WIN32 +#include +#else +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#define FRIBIDI_SHIM_IMPLEMENTATION + +#include "fribidi.h" + + +/* FriBiDi>=1.0.0 adds bracket_types param, ignore and call legacy function */ +FriBidiLevel fribidi_get_par_embedding_levels_ex_compat( + const FriBidiCharType *bidi_types, + const FriBidiBracketType *bracket_types, + const FriBidiStrIndex len, + FriBidiParType *pbase_dir, + FriBidiLevel *embedding_levels) +{ + return fribidi_get_par_embedding_levels( + bidi_types, len, pbase_dir, embedding_levels); +} + +/* FriBiDi>=1.0.0 gets bracket types here, ignore */ +void fribidi_get_bracket_types_compat( + const FriBidiChar *str, + const FriBidiStrIndex len, + const FriBidiCharType *types, + FriBidiBracketType *btypes) +{ /* no-op*/ } + + +int load_fribidi(void) { + int error = 0; + + p_fribidi = 0; + + /* Microsoft needs a totally different system */ +#ifndef _WIN32 +#define LOAD_FUNCTION(func) \ + func = (t_##func)dlsym(p_fribidi, #func); \ + error = error || (func == 0); + + p_fribidi = dlopen("libfribidi.so", RTLD_LAZY); + if (!p_fribidi) { + p_fribidi = dlopen("libfribidi.so.0", RTLD_LAZY); + } + if (!p_fribidi) { + p_fribidi = dlopen("libfribidi.dylib", RTLD_LAZY); + } +#else +#define LOAD_FUNCTION(func) \ + func = (t_##func)GetProcAddress(p_fribidi, #func); \ + error = error || (func == 0); + + p_fribidi = LoadLibrary("fribidi"); + if (!p_fribidi) { + p_fribidi = LoadLibrary("fribidi-0"); + } + /* MSYS2 */ + if (!p_fribidi) { + p_fribidi = LoadLibrary("libfribidi-0"); + } +#endif + + if (!p_fribidi) { + return 1; + } + + /* load FriBiDi>=1.0.0 functions first, use error to detect version */ + LOAD_FUNCTION(fribidi_get_par_embedding_levels_ex); + LOAD_FUNCTION(fribidi_get_bracket_types); + if (error) { + /* using FriBiDi<1.0.0, ignore new parameters */ + error = 0; + fribidi_get_par_embedding_levels_ex = &fribidi_get_par_embedding_levels_ex_compat; + fribidi_get_bracket_types = &fribidi_get_bracket_types_compat; + } + + LOAD_FUNCTION(fribidi_unicode_to_charset); + LOAD_FUNCTION(fribidi_charset_to_unicode); + LOAD_FUNCTION(fribidi_get_bidi_types); + LOAD_FUNCTION(fribidi_get_par_embedding_levels); + +#ifndef _WIN32 + fribidi_version_info = *(const char**)dlsym(p_fribidi, "fribidi_version_info"); + if (dlerror() || error || (fribidi_version_info == 0)) { + dlclose(p_fribidi); + p_fribidi = 0; + return 2; + } +#else + fribidi_version_info = *(const char**)GetProcAddress(p_fribidi, "fribidi_version_info"); + if (error || (fribidi_version_info == 0)) { + FreeLibrary(p_fribidi); + p_fribidi = 0; + return 2; + } +#endif + + return 0; +} diff --git a/src/thirdparty/fribidi-shim/fribidi.h b/src/thirdparty/fribidi-shim/fribidi.h new file mode 100644 index 000000000..7712a5b22 --- /dev/null +++ b/src/thirdparty/fribidi-shim/fribidi.h @@ -0,0 +1,111 @@ + +#define FRIBIDI_MAJOR_VERSION 1 + +/* fribidi-types.h */ + +# if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \ + defined (_sgi) || defined (__sun) || defined (sun) || \ + defined (__digital__) || defined (__HP_cc) +# include +# elif defined (_AIX) +# include +# else +# include +# endif + +typedef uint32_t FriBidiChar; +typedef int FriBidiStrIndex; + +typedef FriBidiChar FriBidiBracketType; + + + +/* fribidi-char-sets.h */ + +typedef enum +{ + _FRIBIDI_CHAR_SET_NOT_FOUND, + FRIBIDI_CHAR_SET_UTF8, + FRIBIDI_CHAR_SET_CAP_RTL, + FRIBIDI_CHAR_SET_ISO8859_6, + FRIBIDI_CHAR_SET_ISO8859_8, + FRIBIDI_CHAR_SET_CP1255, + FRIBIDI_CHAR_SET_CP1256, + _FRIBIDI_CHAR_SETS_NUM_PLUS_ONE +} +FriBidiCharSet; + + + +/* fribidi-bidi-types.h */ + +typedef signed char FriBidiLevel; + +#define FRIBIDI_TYPE_LTR_VAL 0x00000110L +#define FRIBIDI_TYPE_RTL_VAL 0x00000111L +#define FRIBIDI_TYPE_ON_VAL 0x00000040L + +typedef uint32_t FriBidiCharType; +#define FRIBIDI_TYPE_LTR FRIBIDI_TYPE_LTR_VAL + +typedef uint32_t FriBidiParType; +#define FRIBIDI_PAR_LTR FRIBIDI_TYPE_LTR_VAL +#define FRIBIDI_PAR_RTL FRIBIDI_TYPE_RTL_VAL +#define FRIBIDI_PAR_ON FRIBIDI_TYPE_ON_VAL + +#define FRIBIDI_LEVEL_IS_RTL(lev) ((lev) & 1) +#define FRIBIDI_DIR_TO_LEVEL(dir) ((FriBidiLevel) (FRIBIDI_IS_RTL(dir) ? 1 : 0)) +#define FRIBIDI_IS_RTL(p) ((p) & 0x00000001L) +#define FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS(p) ((p) & 0x00901000L) + + + +/* functions */ + +#ifdef FRIBIDI_SHIM_IMPLEMENTATION +#define FRIBIDI_ENTRY +#else +#define FRIBIDI_ENTRY extern +#endif + +#define FRIBIDI_FUNC(ret, name, ...) \ + typedef ret (*t_##name) (__VA_ARGS__); \ + FRIBIDI_ENTRY t_##name name; + +FRIBIDI_FUNC(FriBidiStrIndex, fribidi_unicode_to_charset, + FriBidiCharSet, const FriBidiChar *, FriBidiStrIndex, char *); + +FRIBIDI_FUNC(FriBidiStrIndex, fribidi_charset_to_unicode, + FriBidiCharSet, const char *, FriBidiStrIndex, FriBidiChar *); + +FRIBIDI_FUNC(void, fribidi_get_bidi_types, + const FriBidiChar *, const FriBidiStrIndex, FriBidiCharType *); + +FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels, + const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *, + FriBidiLevel *); + +/* FriBiDi>=1.0.0 */ +FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels_ex, + const FriBidiCharType *, const FriBidiBracketType *, const FriBidiStrIndex, + FriBidiParType *, FriBidiLevel *); + +/* FriBiDi>=1.0.0 */ +FRIBIDI_FUNC(void, fribidi_get_bracket_types, + const FriBidiChar *, const FriBidiStrIndex, const FriBidiCharType *, + FriBidiBracketType *); + +#undef FRIBIDI_FUNC + +/* constant, not a function */ +FRIBIDI_ENTRY const char *fribidi_version_info; + + + +/* shim */ + +FRIBIDI_ENTRY void *p_fribidi; + +FRIBIDI_ENTRY int load_fribidi(void); + +#undef FRIBIDI_ENTRY diff --git a/src/thirdparty/raqm/AUTHORS b/src/thirdparty/raqm/AUTHORS new file mode 100644 index 000000000..bd5c3ac6b --- /dev/null +++ b/src/thirdparty/raqm/AUTHORS @@ -0,0 +1,9 @@ +Abderraouf Adjal +Ali Yousuf +Anood Almuharbi +Asma Albahanta +Fahad Alsaidi +Ibtisam Almabsali +Khaled Hosny +Mazoon Almaamari +Shamsa Alqassabi diff --git a/src/thirdparty/raqm/COPYING b/src/thirdparty/raqm/COPYING new file mode 100644 index 000000000..196511ef6 --- /dev/null +++ b/src/thirdparty/raqm/COPYING @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright © 2015 Information Technology Authority (ITA) +Copyright © 2016 Khaled Hosny + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/thirdparty/raqm/NEWS b/src/thirdparty/raqm/NEWS new file mode 100644 index 000000000..29c9ae0e5 --- /dev/null +++ b/src/thirdparty/raqm/NEWS @@ -0,0 +1,89 @@ +Overview of changes leading to 0.7.1 +Sunday, November 22, 2020 +==================================== + +Require HarfBuzz >= 2.0.0 + +Build and documentation fixes. + +Overview of changes leading to 0.7.0 +Monday, May 27, 2019 +==================================== + +New API: + * raqm_version + * raqm_version_string + * raqm_version_atleast + * RAQM_VERSION_MAJOR + * RAQM_VERSION_MICRO + * RAQM_VERSION_MINOR + * RAQM_VERSION_STRING + * RAQM_VERSION_ATLEAST + +Overview of changes leading to 0.6.0 +Sunday, May 5, 2019 +==================================== + +Fix TTB direction regression from the previous release. + +Correctly detect script of Common and Inherite characters at start of text. + +Undef HAVE_CONFIG_H workaround, for older versions of Fribidi. + +Drop test suite dependency on GLib. + +Port test runner to Python instead of shell script. + +New API: +* raqm_set_invisible_glyph() + +Overview of changes leading to 0.5.0 +Saturday, February 24, 2018 +==================================== + +Use FriBiDi 1.x API when available. + +Overview of changes leading to 0.4.0 +Sunday, January 21, 2018 +==================================== + +Set begin-of-text and end-of-text HarfBuzz buffer flags. + +Dynamically allocate memory instead of using stack allocation for input text. + +Accept zero length text and do nothing instead of treating it as error. + +Overview of changes leading to 0.3.0 +Monday, August 21, 2017 +==================================== + +Fix stack corruption on MSVC. + +New API: +* raqm_set_freetype_load_flags + +Overview of changes leading to 0.2.0 +Wednesday, August 25, 2016 +==================================== + +Fix building with MSVC due to lacking C99 support. + +Make multiple fonts support actually work. Start and length now respect the +input encoding. + +New API: +* raqm_index_to_position +* raqm_position_to_index +* raqm_set_language + +Overview of changes leading to 0.1.1 +Sunday, May 1, 2016 +==================================== + +Fix make check on 32-bit systems. + +Overview of changes leading to 0.1.0 +Wednesday, January 20, 2016 +==================================== + +First release. diff --git a/src/thirdparty/raqm/README b/src/thirdparty/raqm/README new file mode 100644 index 000000000..7940bf3b6 --- /dev/null +++ b/src/thirdparty/raqm/README @@ -0,0 +1,85 @@ +Raqm +==== + +[![Linux & macOS build](https://travis-ci.org/HOST-Oman/libraqm.svg?branch=master)](https://travis-ci.org/HOST-Oman/libraqm) +[![Windows build](https://img.shields.io/appveyor/ci/HOSTOman/libraqm/master.svg)](https://ci.appveyor.com/project/HOSTOman/libraqm) + +Raqm is a small library that encapsulates the logic for complex text layout and +provides a convenient API. + +It currently provides bidirectional text support (using [FriBiDi][1]), shaping +(using [HarfBuzz][2]), and proper script itemization. As a result, +Raqm can support most writing systems covered by Unicode. + +The documentation can be accessed on the web at: +> http://host-oman.github.io/libraqm/ + +Raqm (Arabic: رَقْم) is writing, also number or digit and the Arabic word for +digital (رَقَمِيّ) shares the same root, so it is a play on “digital writing”. + +Building +-------- + +Raqm depends on the following libraries: +* [FreeType][3] +* [HarfBuzz][2] +* [FriBiDi][1] + +To build the documentation you will also need: +* [GTK-Doc][4] + +To install dependencies on Fedora: + + sudo dnf install freetype-devel harfbuzz-devel fribidi-devel gtk-doc + +To install dependencies on Ubuntu: + + sudo apt-get install libfreetype6-dev libharfbuzz-dev libfribidi-dev \ + gtk-doc-tools + +On Mac OS X you can use Homebrew: + + brew install freetype harfbuzz fribidi gtk-doc + export XML_CATALOG_FILES="/usr/local/etc/xml/catalog" # for the docs + +Once you have the source code and the dependencies, you can proceed to build. +To do that, run the customary sequence of commands in the source code +directory: + + $ ./configure + $ make + $ make install + +To build the documentation, pass `--enable-gtk-doc` to the `configure` script. + +To run the tests: + + $ make check + +Contributing +------------ + +Once you have made a change that you are happy with, contribute it back, we’ll +be happy to integrate it! Just fork the repository and make a pull request. + +Projects using Raqm +------------------- + +1. [ImageMagick](https://github.com/ImageMagick/ImageMagick) +2. [LibGD](https://github.com/libgd/libgd) +3. [FontView](https://github.com/googlei18n/fontview) +4. [Pillow](https://github.com/python-pillow) +5. [mplcairo](https://github.com/anntzer/mplcairo) + +The following projects have patches to support complex text layout using Raqm: + +2. SDL_ttf: https://bugzilla.libsdl.org/show_bug.cgi?id=3211 +3. Pygame: https://bitbucket.org/pygame/pygame/pull-requests/52 +4. Blender: https://developer.blender.org/D1809 + + + +[1]: http://fribidi.org +[2]: http://harfbuzz.org +[3]: https://www.freetype.org +[4]: https://www.gtk.org/gtk-doc diff --git a/src/thirdparty/raqm/raqm-version.h b/src/thirdparty/raqm/raqm-version.h new file mode 100644 index 000000000..94b25ada7 --- /dev/null +++ b/src/thirdparty/raqm/raqm-version.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef _RAQM_H_IN_ +#error "Include instead." +#endif + +#ifndef _RAQM_VERSION_H_ +#define _RAQM_VERSION_H_ + +#define RAQM_VERSION_MAJOR 0 +#define RAQM_VERSION_MINOR 7 +#define RAQM_VERSION_MICRO 1 + +#define RAQM_VERSION_STRING "0.7.1" + +#define RAQM_VERSION_ATLEAST(major,minor,micro) \ + ((major)*10000+(minor)*100+(micro) <= \ + RAQM_VERSION_MAJOR*10000+RAQM_VERSION_MINOR*100+RAQM_VERSION_MICRO) + +#endif /* _RAQM_VERSION_H_ */ diff --git a/src/thirdparty/raqm/raqm.c b/src/thirdparty/raqm/raqm.c new file mode 100644 index 000000000..5a0b2078e --- /dev/null +++ b/src/thirdparty/raqm/raqm.c @@ -0,0 +1,2074 @@ +/* + * Copyright © 2015 Information Technology Authority (ITA) + * Copyright © 2016 Khaled Hosny + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#undef HAVE_CONFIG_H // Workaround for Fribidi 1.0.5 and earlier +#endif + +#include +#include + +#ifdef HAVE_FRIBIDI_SYSTEM +#include +#else +#include "../fribidi-shim/fribidi.h" +#endif + +#include +#include + +#include "raqm.h" + +#if FRIBIDI_MAJOR_VERSION >= 1 +#define USE_FRIBIDI_EX_API +#endif + +/** + * SECTION:raqm + * @title: Raqm + * @short_description: A library for complex text layout + * @include: raqm.h + * + * Raqm is a light weight text layout library with strong emphasis on + * supporting languages and writing systems that require complex text layout. + * + * The main object in Raqm API is #raqm_t, it stores all the states of the + * input text, its properties, and the output of the layout process. + * + * To start, you create a #raqm_t object, add text and font(s) to it, run the + * layout process, and finally query about the output. For example: + * + * |[ + * #include "raqm.h" + * + * int + * main (int argc, char *argv[]) + * { + * const char *fontfile; + * const char *text; + * const char *direction; + * const char *language; + * int ret = 1; + * + * FT_Library library = NULL; + * FT_Face face = NULL; + * + * if (argc < 5) + * { + * printf ("Usage: %s FONT_FILE TEXT DIRECTION LANG\n", argv[0]); + * return 1; + * } + * + * fontfile = argv[1]; + * text = argv[2]; + * direction = argv[3]; + * language = argv[4]; + * + * if (FT_Init_FreeType (&library) == 0) + * { + * if (FT_New_Face (library, fontfile, 0, &face) == 0) + * { + * if (FT_Set_Char_Size (face, face->units_per_EM, 0, 0, 0) == 0) + * { + * raqm_t *rq = raqm_create (); + * if (rq != NULL) + * { + * raqm_direction_t dir = RAQM_DIRECTION_DEFAULT; + * + * if (strcmp (direction, "r") == 0) + * dir = RAQM_DIRECTION_RTL; + * else if (strcmp (direction, "l") == 0) + * dir = RAQM_DIRECTION_LTR; + * + * if (raqm_set_text_utf8 (rq, text, strlen (text)) && + * raqm_set_freetype_face (rq, face) && + * raqm_set_par_direction (rq, dir) && + * raqm_set_language (rq, language, 0, strlen (text)) && + * raqm_layout (rq)) + * { + * size_t count, i; + * raqm_glyph_t *glyphs = raqm_get_glyphs (rq, &count); + * + * ret = !(glyphs != NULL || count == 0); + * + * printf("glyph count: %zu\n", count); + * for (i = 0; i < count; i++) + * { + * printf ("gid#%d off: (%d, %d) adv: (%d, %d) idx: %d\n", + * glyphs[i].index, + * glyphs[i].x_offset, + * glyphs[i].y_offset, + * glyphs[i].x_advance, + * glyphs[i].y_advance, + * glyphs[i].cluster); + * } + * } + * + * raqm_destroy (rq); + * } + * } + * + * FT_Done_Face (face); + * } + * + * FT_Done_FreeType (library); + * } + * + * return ret; + * } + * ]| + * To compile this example: + * |[ + * cc -o test test.c `pkg-config --libs --cflags raqm` + * ]| + */ + +/* For enabling debug mode */ +/*#define RAQM_DEBUG 1*/ +#ifdef RAQM_DEBUG +#define RAQM_DBG(...) fprintf (stderr, __VA_ARGS__) +#else +#define RAQM_DBG(...) +#endif + +#ifdef RAQM_TESTING +# define RAQM_TEST(...) printf (__VA_ARGS__) +# define SCRIPT_TO_STRING(script) \ + char buff[5]; \ + hb_tag_to_string (hb_script_to_iso15924_tag (script), buff); \ + buff[4] = '\0'; +#else +# define RAQM_TEST(...) +#endif + +typedef enum { + RAQM_FLAG_NONE = 0, + RAQM_FLAG_UTF8 = 1 << 0 +} _raqm_flags_t; + +typedef struct { + FT_Face ftface; + hb_language_t lang; + hb_script_t script; +} _raqm_text_info; + +typedef struct _raqm_run raqm_run_t; + +struct _raqm { + int ref_count; + + uint32_t *text; + char *text_utf8; + size_t text_len; + + _raqm_text_info *text_info; + + raqm_direction_t base_dir; + raqm_direction_t resolved_dir; + + hb_feature_t *features; + size_t features_len; + + raqm_run_t *runs; + raqm_glyph_t *glyphs; + + _raqm_flags_t flags; + + int ft_loadflags; + int invisible_glyph; +}; + +struct _raqm_run { + int pos; + int len; + + hb_direction_t direction; + hb_script_t script; + hb_font_t *font; + hb_buffer_t *buffer; + + raqm_run_t *next; +}; + +static uint32_t +_raqm_u8_to_u32_index (raqm_t *rq, + uint32_t index); + +static bool +_raqm_init_text_info (raqm_t *rq) +{ + hb_language_t default_lang; + + if (rq->text_info) + return true; + + rq->text_info = malloc (sizeof (_raqm_text_info) * rq->text_len); + if (!rq->text_info) + return false; + + default_lang = hb_language_get_default (); + for (size_t i = 0; i < rq->text_len; i++) + { + rq->text_info[i].ftface = NULL; + rq->text_info[i].lang = default_lang; + rq->text_info[i].script = HB_SCRIPT_INVALID; + } + + return true; +} + +static void +_raqm_free_text_info (raqm_t *rq) +{ + if (!rq->text_info) + return; + + for (size_t i = 0; i < rq->text_len; i++) + { + if (rq->text_info[i].ftface) + FT_Done_Face (rq->text_info[i].ftface); + } + + free (rq->text_info); + rq->text_info = NULL; +} + +static bool +_raqm_compare_text_info (_raqm_text_info a, + _raqm_text_info b) +{ + if (a.ftface != b.ftface) + return false; + + if (a.lang != b.lang) + return false; + + if (a.script != b.script) + return false; + + return true; +} + +/** + * raqm_create: + * + * Creates a new #raqm_t with all its internal states initialized to their + * defaults. + * + * Return value: + * A newly allocated #raqm_t with a reference count of 1. The initial reference + * count should be released with raqm_destroy() when you are done using the + * #raqm_t. Returns %NULL in case of error. + * + * Since: 0.1 + */ +raqm_t * +raqm_create (void) +{ + raqm_t *rq; + + rq = malloc (sizeof (raqm_t)); + if (!rq) + return NULL; + + rq->ref_count = 1; + + rq->text = NULL; + rq->text_utf8 = NULL; + rq->text_len = 0; + + rq->text_info = NULL; + + rq->base_dir = RAQM_DIRECTION_DEFAULT; + rq->resolved_dir = RAQM_DIRECTION_DEFAULT; + + rq->features = NULL; + rq->features_len = 0; + + rq->runs = NULL; + rq->glyphs = NULL; + + rq->flags = RAQM_FLAG_NONE; + + rq->ft_loadflags = -1; + rq->invisible_glyph = 0; + + return rq; +} + +/** + * raqm_reference: + * @rq: a #raqm_t. + * + * Increases the reference count on @rq by one. This prevents @rq from being + * destroyed until a matching call to raqm_destroy() is made. + * + * Return value: + * The referenced #raqm_t. + * + * Since: 0.1 + */ +raqm_t * +raqm_reference (raqm_t *rq) +{ + if (rq) + rq->ref_count++; + + return rq; +} + +static void +_raqm_free_runs (raqm_t *rq) +{ + raqm_run_t *runs = rq->runs; + while (runs) + { + raqm_run_t *run = runs; + runs = runs->next; + + hb_buffer_destroy (run->buffer); + hb_font_destroy (run->font); + free (run); + } +} + +/** + * raqm_destroy: + * @rq: a #raqm_t. + * + * Decreases the reference count on @rq by one. If the result is zero, then @rq + * and all associated resources are freed. + * See cairo_reference(). + * + * Since: 0.1 + */ +void +raqm_destroy (raqm_t *rq) +{ + if (!rq || --rq->ref_count != 0) + return; + + free (rq->text); + free (rq->text_utf8); + _raqm_free_text_info (rq); + _raqm_free_runs (rq); + free (rq->glyphs); + free (rq); +} + +/** + * raqm_set_text: + * @rq: a #raqm_t. + * @text: a UTF-32 encoded text string. + * @len: the length of @text. + * + * Adds @text to @rq to be used for layout. It must be a valid UTF-32 text, any + * invalid character will be replaced with U+FFFD. The text should typically + * represent a full paragraph, since doing the layout of chunks of text + * separately can give improper output. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_text (raqm_t *rq, + const uint32_t *text, + size_t len) +{ + if (!rq || !text) + return false; + + rq->text_len = len; + + /* Empty string, don’t fail but do nothing */ + if (!len) + return true; + + free (rq->text); + + rq->text = malloc (sizeof (uint32_t) * rq->text_len); + if (!rq->text) + return false; + + _raqm_free_text_info (rq); + if (!_raqm_init_text_info (rq)) + return false; + + memcpy (rq->text, text, sizeof (uint32_t) * rq->text_len); + + return true; +} + +/** + * raqm_set_text_utf8: + * @rq: a #raqm_t. + * @text: a UTF-8 encoded text string. + * @len: the length of @text in UTF-8 bytes. + * + * Same as raqm_set_text(), but for text encoded in UTF-8 encoding. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_text_utf8 (raqm_t *rq, + const char *text, + size_t len) +{ + uint32_t *unicode; + size_t ulen; + bool ok; + + if (!rq || !text) + return false; + + /* Empty string, don’t fail but do nothing */ + if (!len) + { + rq->text_len = len; + return true; + } + + RAQM_TEST ("Text is: %s\n", text); + + rq->flags |= RAQM_FLAG_UTF8; + + rq->text_utf8 = malloc (sizeof (char) * len); + if (!rq->text_utf8) + return false; + + unicode = malloc (sizeof (uint32_t) * len); + if (!unicode) + return false; + + memcpy (rq->text_utf8, text, sizeof (char) * len); + + ulen = fribidi_charset_to_unicode (FRIBIDI_CHAR_SET_UTF8, + text, len, unicode); + + ok = raqm_set_text (rq, unicode, ulen); + + free (unicode); + return ok; +} + +/** + * raqm_set_par_direction: + * @rq: a #raqm_t. + * @dir: the direction of the paragraph. + * + * Sets the paragraph direction, also known as block direction in CSS. For + * horizontal text, this controls the overall direction in the Unicode + * Bidirectional Algorithm, so when the text is mainly right-to-left (with or + * without some left-to-right) text, then the base direction should be set to + * #RAQM_DIRECTION_RTL and vice versa. + * + * The default is #RAQM_DIRECTION_DEFAULT, which determines the paragraph + * direction based on the first character with strong bidi type (see [rule + * P2](http://unicode.org/reports/tr9/#P2) in Unicode Bidirectional Algorithm), + * which can be good enough for many cases but has problems when a mainly + * right-to-left paragraph starts with a left-to-right character and vice versa + * as the detected paragraph direction will be the wrong one, or when text does + * not contain any characters with string bidi types (e.g. only punctuation or + * numbers) as this will default to left-to-right paragraph direction. + * + * For vertical, top-to-bottom text, #RAQM_DIRECTION_TTB should be used. Raqm, + * however, provides limited vertical text support and does not handle rotated + * horizontal text in vertical text, instead everything is treated as vertical + * text. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_par_direction (raqm_t *rq, + raqm_direction_t dir) +{ + if (!rq) + return false; + + rq->base_dir = dir; + + return true; +} + +/** + * raqm_set_language: + * @rq: a #raqm_t. + * @lang: a BCP47 language code. + * @start: index of first character that should use @face. + * @len: number of characters using @face. + * + * Sets a [BCP47 language + * code](https://www.w3.org/International/articles/language-tags/) to be used + * for @len-number of characters staring at @start. The @start and @len are + * input string array indices (i.e. counting bytes in UTF-8 and scaler values + * in UTF-32). + * + * This method can be used repeatedly to set different languages for different + * parts of the text. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Stability: + * Unstable + * + * Since: 0.2 + */ +bool +raqm_set_language (raqm_t *rq, + const char *lang, + size_t start, + size_t len) +{ + hb_language_t language; + size_t end = start + len; + + if (!rq) + return false; + + if (!rq->text_len) + return true; + + if (rq->flags & RAQM_FLAG_UTF8) + { + start = _raqm_u8_to_u32_index (rq, start); + end = _raqm_u8_to_u32_index (rq, end); + } + + if (start >= rq->text_len || end > rq->text_len) + return false; + + if (!rq->text_info) + return false; + + language = hb_language_from_string (lang, -1); + for (size_t i = start; i < end; i++) + { + rq->text_info[i].lang = language; + } + + return true; +} + +/** + * raqm_add_font_feature: + * @rq: a #raqm_t. + * @feature: (transfer none): a font feature string. + * @len: length of @feature, -1 for %NULL-terminated. + * + * Adds a font feature to be used by the #raqm_t during text layout. This is + * usually used to turn on optional font features that are not enabled by + * default, for example `dlig` or `ss01`, but can be also used to turn off + * default font features. + * + * @feature is string representing a single font feature, in the syntax + * understood by hb_feature_from_string(). + * + * This function can be called repeatedly, new features will be appended to the + * end of the features list and can potentially override previous features. + * + * Return value: + * %true if parsing @feature succeeded, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_add_font_feature (raqm_t *rq, + const char *feature, + int len) +{ + hb_bool_t ok; + hb_feature_t fea; + + if (!rq) + return false; + + ok = hb_feature_from_string (feature, len, &fea); + if (ok) + { + rq->features_len++; + rq->features = realloc (rq->features, + sizeof (hb_feature_t) * (rq->features_len)); + if (!rq->features) + return false; + + rq->features[rq->features_len - 1] = fea; + } + + return ok; +} + +static hb_font_t * +_raqm_create_hb_font (raqm_t *rq, + FT_Face face) +{ + hb_font_t *font = hb_ft_font_create_referenced (face); + + if (rq->ft_loadflags >= 0) + hb_ft_font_set_load_flags (font, rq->ft_loadflags); + + return font; +} + +static bool +_raqm_set_freetype_face (raqm_t *rq, + FT_Face face, + size_t start, + size_t end) +{ + if (!rq) + return false; + + if (!rq->text_len) + return true; + + if (start >= rq->text_len || end > rq->text_len) + return false; + + if (!rq->text_info) + return false; + + for (size_t i = start; i < end; i++) + { + if (rq->text_info[i].ftface) + FT_Done_Face (rq->text_info[i].ftface); + rq->text_info[i].ftface = face; + FT_Reference_Face (face); + } + + return true; +} + +/** + * raqm_set_freetype_face: + * @rq: a #raqm_t. + * @face: an #FT_Face. + * + * Sets an #FT_Face to be used for all characters in @rq. + * + * See also raqm_set_freetype_face_range(). + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_freetype_face (raqm_t *rq, + FT_Face face) +{ + return _raqm_set_freetype_face (rq, face, 0, rq->text_len); +} + +/** + * raqm_set_freetype_face_range: + * @rq: a #raqm_t. + * @face: an #FT_Face. + * @start: index of first character that should use @face. + * @len: number of characters using @face. + * + * Sets an #FT_Face to be used for @len-number of characters staring at @start. + * The @start and @len are input string array indices (i.e. counting bytes in + * UTF-8 and scaler values in UTF-32). + * + * This method can be used repeatedly to set different faces for different + * parts of the text. It is the responsibility of the client to make sure that + * face ranges cover the whole text. + * + * See also raqm_set_freetype_face(). + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_freetype_face_range (raqm_t *rq, + FT_Face face, + size_t start, + size_t len) +{ + size_t end = start + len; + + if (!rq) + return false; + + if (!rq->text_len) + return true; + + if (rq->flags & RAQM_FLAG_UTF8) + { + start = _raqm_u8_to_u32_index (rq, start); + end = _raqm_u8_to_u32_index (rq, end); + } + + return _raqm_set_freetype_face (rq, face, start, end); +} + +/** + * raqm_set_freetype_load_flags: + * @rq: a #raqm_t. + * @flags: FreeType load flags. + * + * Sets the load flags passed to FreeType when loading glyphs, should be the + * same flags used by the client when rendering FreeType glyphs. + * + * This requires version of HarfBuzz that has hb_ft_font_set_load_flags(), for + * older version the flags will be ignored. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.3 + */ +bool +raqm_set_freetype_load_flags (raqm_t *rq, + int flags) +{ + if (!rq) + return false; + + rq->ft_loadflags = flags; + + return true; +} + +/** + * raqm_set_invisible_glyph: + * @rq: a #raqm_t. + * @gid: glyph id to use for invisible glyphs. + * + * Sets the glyph id to be used for invisible glyhphs. + * + * If @gid is negative, invisible glyphs will be suppressed from the output. + * This requires HarfBuzz 1.8.0 or later. If raqm is used with an earlier + * HarfBuzz version, the return value will be %false and the shaping behavior + * does not change. + * + * If @gid is zero, invisible glyphs will be rendered as space. + * This works on all versions of HarfBuzz. + * + * If @gid is a positive number, it will be used for invisible glyphs. + * This requires a version of HarfBuzz that has + * hb_buffer_set_invisible_glyph(). For older versions, the return value + * will be %false and the shaping behavior does not change. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.6 + */ +bool +raqm_set_invisible_glyph (raqm_t *rq, + int gid) +{ + if (!rq) + return false; + +#ifndef HAVE_HB_BUFFER_SET_INVISIBLE_GLYPH + if (gid > 0) + return false; +#endif + +#if !defined(HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) || \ + !HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES + if (gid < 0) + return false; +#endif + + rq->invisible_glyph = gid; + return true; +} + +static bool +_raqm_itemize (raqm_t *rq); + +static bool +_raqm_shape (raqm_t *rq); + +/** + * raqm_layout: + * @rq: a #raqm_t. + * + * Run the text layout process on @rq. This is the main Raqm function where the + * Unicode Bidirectional Text algorithm will be applied to the text in @rq, + * text shaping, and any other part of the layout process. + * + * Return value: + * %true if the layout process was successful, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_layout (raqm_t *rq) +{ + if (!rq) + return false; + + if (!rq->text_len) + return true; + + if (!rq->text_info) + return false; + + for (size_t i = 0; i < rq->text_len; i++) + { + if (!rq->text_info[i].ftface) + return false; + } + + if (!_raqm_itemize (rq)) + return false; + + if (!_raqm_shape (rq)) + return false; + + return true; +} + +static uint32_t +_raqm_u32_to_u8_index (raqm_t *rq, + uint32_t index); + +/** + * raqm_get_glyphs: + * @rq: a #raqm_t. + * @length: (out): output array length. + * + * Gets the final result of Raqm layout process, an array of #raqm_glyph_t + * containing the glyph indices in the font, their positions and other possible + * information. + * + * Return value: (transfer none): + * An array of #raqm_glyph_t, or %NULL in case of error. This is owned by @rq + * and must not be freed. + * + * Since: 0.1 + */ +raqm_glyph_t * +raqm_get_glyphs (raqm_t *rq, + size_t *length) +{ + size_t count = 0; + + if (!rq || !rq->runs || !length) + { + if (length) + *length = 0; + return NULL; + } + + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + count += hb_buffer_get_length (run->buffer); + + *length = count; + + if (rq->glyphs) + free (rq->glyphs); + + rq->glyphs = malloc (sizeof (raqm_glyph_t) * count); + if (!rq->glyphs) + { + *length = 0; + return NULL; + } + + RAQM_TEST ("Glyph information:\n"); + + count = 0; + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + size_t len; + hb_glyph_info_t *info; + hb_glyph_position_t *position; + + len = hb_buffer_get_length (run->buffer); + info = hb_buffer_get_glyph_infos (run->buffer, NULL); + position = hb_buffer_get_glyph_positions (run->buffer, NULL); + + for (size_t i = 0; i < len; i++) + { + rq->glyphs[count + i].index = info[i].codepoint; + rq->glyphs[count + i].cluster = info[i].cluster; + rq->glyphs[count + i].x_advance = position[i].x_advance; + rq->glyphs[count + i].y_advance = position[i].y_advance; + rq->glyphs[count + i].x_offset = position[i].x_offset; + rq->glyphs[count + i].y_offset = position[i].y_offset; + rq->glyphs[count + i].ftface = rq->text_info[info[i].cluster].ftface; + + RAQM_TEST ("glyph [%d]\tx_offset: %d\ty_offset: %d\tx_advance: %d\tfont: %s\n", + rq->glyphs[count + i].index, rq->glyphs[count + i].x_offset, + rq->glyphs[count + i].y_offset, rq->glyphs[count + i].x_advance, + rq->glyphs[count + i].ftface->family_name); + } + + count += len; + } + + if (rq->flags & RAQM_FLAG_UTF8) + { +#ifdef RAQM_TESTING + RAQM_TEST ("\nUTF-32 clusters:"); + for (size_t i = 0; i < count; i++) + RAQM_TEST (" %02d", rq->glyphs[i].cluster); + RAQM_TEST ("\n"); +#endif + + for (size_t i = 0; i < count; i++) + rq->glyphs[i].cluster = _raqm_u32_to_u8_index (rq, + rq->glyphs[i].cluster); + +#ifdef RAQM_TESTING + RAQM_TEST ("UTF-8 clusters: "); + for (size_t i = 0; i < count; i++) + RAQM_TEST (" %02d", rq->glyphs[i].cluster); + RAQM_TEST ("\n"); +#endif + } + return rq->glyphs; +} + +static bool +_raqm_resolve_scripts (raqm_t *rq); + +static hb_direction_t +_raqm_hb_dir (raqm_t *rq, FriBidiLevel level) +{ + hb_direction_t dir = HB_DIRECTION_LTR; + + if (rq->base_dir == RAQM_DIRECTION_TTB) + dir = HB_DIRECTION_TTB; + else if (FRIBIDI_LEVEL_IS_RTL (level)) + dir = HB_DIRECTION_RTL; + + return dir; +} + +typedef struct { + size_t pos; + size_t len; + FriBidiLevel level; +} _raqm_bidi_run; + +static void +_raqm_reverse_run (_raqm_bidi_run *run, const size_t len) +{ + assert (run); + + for (size_t i = 0; i < len / 2; i++) + { + _raqm_bidi_run temp = run[i]; + run[i] = run[len - 1 - i]; + run[len - 1 - i] = temp; + } +} + +static _raqm_bidi_run * +_raqm_reorder_runs (const FriBidiCharType *types, + const size_t len, + const FriBidiParType base_dir, + /* input and output */ + FriBidiLevel *levels, + /* output */ + size_t *run_count) +{ + FriBidiLevel level; + FriBidiLevel last_level = -1; + FriBidiLevel max_level = 0; + size_t run_start = 0; + size_t run_index = 0; + _raqm_bidi_run *runs = NULL; + size_t count = 0; + + if (len == 0) + { + *run_count = 0; + return NULL; + } + + assert (types); + assert (levels); + + /* L1. Reset the embedding levels of some chars: + 4. any sequence of white space characters at the end of the line. */ + for (int i = len - 1; + i >= 0 && FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS (types[i]); i--) + { + levels[i] = FRIBIDI_DIR_TO_LEVEL (base_dir); + } + + /* Find max_level of the line. We don't reuse the paragraph + * max_level, both for a cleaner API, and that the line max_level + * may be far less than paragraph max_level. */ + for (int i = len - 1; i >= 0; i--) + { + if (levels[i] > max_level) + max_level = levels[i]; + } + + for (size_t i = 0; i < len; i++) + { + if (levels[i] != last_level) + count++; + + last_level = levels[i]; + } + + runs = malloc (sizeof (_raqm_bidi_run) * count); + + while (run_start < len) + { + size_t run_end = run_start; + while (run_end < len && levels[run_start] == levels[run_end]) + { + run_end++; + } + + runs[run_index].pos = run_start; + runs[run_index].level = levels[run_start]; + runs[run_index].len = run_end - run_start; + run_start = run_end; + run_index++; + } + + /* L2. Reorder. */ + for (level = max_level; level > 0; level--) + { + for (int i = count - 1; i >= 0; i--) + { + if (runs[i].level >= level) + { + int end = i; + for (i--; (i >= 0 && runs[i].level >= level); i--) + ; + _raqm_reverse_run (runs + i + 1, end - i); + } + } + } + + *run_count = count; + return runs; +} + +static bool +_raqm_itemize (raqm_t *rq) +{ + FriBidiParType par_type = FRIBIDI_PAR_ON; + FriBidiCharType *types; +#ifdef USE_FRIBIDI_EX_API + FriBidiBracketType *btypes; +#endif + FriBidiLevel *levels; + _raqm_bidi_run *runs = NULL; + raqm_run_t *last; + int max_level; + size_t run_count; + bool ok = true; + +#ifdef RAQM_TESTING + switch (rq->base_dir) + { + case RAQM_DIRECTION_RTL: + RAQM_TEST ("Direction is: RTL\n\n"); + break; + case RAQM_DIRECTION_LTR: + RAQM_TEST ("Direction is: LTR\n\n"); + break; + case RAQM_DIRECTION_TTB: + RAQM_TEST ("Direction is: TTB\n\n"); + break; + case RAQM_DIRECTION_DEFAULT: + default: + RAQM_TEST ("Direction is: DEFAULT\n\n"); + break; + } +#endif + + types = calloc (rq->text_len, sizeof (FriBidiCharType)); +#ifdef USE_FRIBIDI_EX_API + btypes = calloc (rq->text_len, sizeof (FriBidiBracketType)); +#endif + levels = calloc (rq->text_len, sizeof (FriBidiLevel)); + if (!types || !levels +#ifdef USE_FRIBIDI_EX_API + || !btypes +#endif + ) + { + ok = false; + goto done; + } + + if (rq->base_dir == RAQM_DIRECTION_RTL) + par_type = FRIBIDI_PAR_RTL; + else if (rq->base_dir == RAQM_DIRECTION_LTR) + par_type = FRIBIDI_PAR_LTR; + + if (rq->base_dir == RAQM_DIRECTION_TTB) + { + /* Treat every thing as LTR in vertical text */ + max_level = 1; + memset (types, FRIBIDI_TYPE_LTR, rq->text_len); + memset (levels, 0, rq->text_len); + rq->resolved_dir = RAQM_DIRECTION_LTR; + } + else + { + fribidi_get_bidi_types (rq->text, rq->text_len, types); +#ifdef USE_FRIBIDI_EX_API + fribidi_get_bracket_types (rq->text, rq->text_len, types, btypes); + max_level = fribidi_get_par_embedding_levels_ex (types, btypes, + rq->text_len, &par_type, + levels); +#else + max_level = fribidi_get_par_embedding_levels (types, rq->text_len, + &par_type, levels); +#endif + + if (par_type == FRIBIDI_PAR_LTR) + rq->resolved_dir = RAQM_DIRECTION_LTR; + else + rq->resolved_dir = RAQM_DIRECTION_RTL; + } + + if (max_level == 0) + { + ok = false; + goto done; + } + + if (!_raqm_resolve_scripts (rq)) + { + ok = false; + goto done; + } + + /* Get the number of bidi runs */ + runs = _raqm_reorder_runs (types, rq->text_len, par_type, levels, &run_count); + if (!runs) + { + ok = false; + goto done; + } + +#ifdef RAQM_TESTING + RAQM_TEST ("Number of runs before script itemization: %zu\n\n", run_count); + + RAQM_TEST ("Fribidi Runs:\n"); + for (size_t i = 0; i < run_count; i++) + { + RAQM_TEST ("run[%zu]:\t start: %zu\tlength: %zu\tlevel: %d\n", + i, runs[i].pos, runs[i].len, runs[i].level); + } + RAQM_TEST ("\n"); +#endif + + last = NULL; + for (size_t i = 0; i < run_count; i++) + { + raqm_run_t *run = calloc (1, sizeof (raqm_run_t)); + if (!run) + { + ok = false; + goto done; + } + + if (!rq->runs) + rq->runs = run; + + if (last) + last->next = run; + + run->direction = _raqm_hb_dir (rq, runs[i].level); + + if (HB_DIRECTION_IS_BACKWARD (run->direction)) + { + run->pos = runs[i].pos + runs[i].len - 1; + run->script = rq->text_info[run->pos].script; + run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface); + for (int j = runs[i].len - 1; j >= 0; j--) + { + _raqm_text_info info = rq->text_info[runs[i].pos + j]; + if (!_raqm_compare_text_info (rq->text_info[run->pos], info)) + { + raqm_run_t *newrun = calloc (1, sizeof (raqm_run_t)); + if (!newrun) + { + ok = false; + goto done; + } + newrun->pos = runs[i].pos + j; + newrun->len = 1; + newrun->direction = _raqm_hb_dir (rq, runs[i].level); + newrun->script = info.script; + newrun->font = _raqm_create_hb_font (rq, info.ftface); + run->next = newrun; + run = newrun; + } + else + { + run->len++; + run->pos = runs[i].pos + j; + } + } + } + else + { + run->pos = runs[i].pos; + run->script = rq->text_info[run->pos].script; + run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface); + for (size_t j = 0; j < runs[i].len; j++) + { + _raqm_text_info info = rq->text_info[runs[i].pos + j]; + if (!_raqm_compare_text_info (rq->text_info[run->pos], info)) + { + raqm_run_t *newrun = calloc (1, sizeof (raqm_run_t)); + if (!newrun) + { + ok = false; + goto done; + } + newrun->pos = runs[i].pos + j; + newrun->len = 1; + newrun->direction = _raqm_hb_dir (rq, runs[i].level); + newrun->script = info.script; + newrun->font = _raqm_create_hb_font (rq, info.ftface); + run->next = newrun; + run = newrun; + } + else + run->len++; + } + } + + last = run; + last->next = NULL; + } + +#ifdef RAQM_TESTING + run_count = 0; + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + run_count++; + RAQM_TEST ("Number of runs after script itemization: %zu\n\n", run_count); + + run_count = 0; + RAQM_TEST ("Final Runs:\n"); + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + SCRIPT_TO_STRING (run->script); + RAQM_TEST ("run[%zu]:\t start: %d\tlength: %d\tdirection: %s\tscript: %s\tfont: %s\n", + run_count++, run->pos, run->len, + hb_direction_to_string (run->direction), buff, + rq->text_info[run->pos].ftface->family_name); + } + RAQM_TEST ("\n"); +#endif + +done: + free (runs); + free (types); +#ifdef USE_FRIBIDI_EX_API + free (btypes); +#endif + free (levels); + + return ok; +} + +/* Stack to handle script detection */ +typedef struct { + size_t capacity; + size_t size; + int *pair_index; + hb_script_t *script; +} _raqm_stack_t; + +/* Special paired characters for script detection */ +static size_t paired_len = 34; +static const FriBidiChar paired_chars[] = +{ + 0x0028, 0x0029, /* ascii paired punctuation */ + 0x003c, 0x003e, + 0x005b, 0x005d, + 0x007b, 0x007d, + 0x00ab, 0x00bb, /* guillemets */ + 0x2018, 0x2019, /* general punctuation */ + 0x201c, 0x201d, + 0x2039, 0x203a, + 0x3008, 0x3009, /* chinese paired punctuation */ + 0x300a, 0x300b, + 0x300c, 0x300d, + 0x300e, 0x300f, + 0x3010, 0x3011, + 0x3014, 0x3015, + 0x3016, 0x3017, + 0x3018, 0x3019, + 0x301a, 0x301b +}; + +static void +_raqm_stack_free (_raqm_stack_t *stack) +{ + free (stack->script); + free (stack->pair_index); + free (stack); +} + +/* Stack handling functions */ +static _raqm_stack_t * +_raqm_stack_new (size_t max) +{ + _raqm_stack_t *stack; + stack = calloc (1, sizeof (_raqm_stack_t)); + if (!stack) + return NULL; + + stack->script = malloc (sizeof (hb_script_t) * max); + if (!stack->script) + { + _raqm_stack_free (stack); + return NULL; + } + + stack->pair_index = malloc (sizeof (int) * max); + if (!stack->pair_index) + { + _raqm_stack_free (stack); + return NULL; + } + + stack->size = 0; + stack->capacity = max; + + return stack; +} + +static bool +_raqm_stack_pop (_raqm_stack_t *stack) +{ + if (!stack->size) + { + RAQM_DBG ("Stack is Empty\n"); + return false; + } + + stack->size--; + + return true; +} + +static hb_script_t +_raqm_stack_top (_raqm_stack_t *stack) +{ + if (!stack->size) + { + RAQM_DBG ("Stack is Empty\n"); + return HB_SCRIPT_INVALID; /* XXX: check this */ + } + + return stack->script[stack->size]; +} + +static bool +_raqm_stack_push (_raqm_stack_t *stack, + hb_script_t script, + int pair_index) +{ + if (stack->size == stack->capacity) + { + RAQM_DBG ("Stack is Full\n"); + return false; + } + + stack->size++; + stack->script[stack->size] = script; + stack->pair_index[stack->size] = pair_index; + + return true; +} + +static int +_get_pair_index (const FriBidiChar ch) +{ + int lower = 0; + int upper = paired_len - 1; + + while (lower <= upper) + { + int mid = (lower + upper) / 2; + if (ch < paired_chars[mid]) + upper = mid - 1; + else if (ch > paired_chars[mid]) + lower = mid + 1; + else + return mid; + } + + return -1; +} + +#define STACK_IS_EMPTY(script) ((script)->size <= 0) +#define IS_OPEN(pair_index) (((pair_index) & 1) == 0) + +/* Resolve the script for each character in the input string, if the character + * script is common or inherited it takes the script of the character before it + * except paired characters which we try to make them use the same script. We + * then split the BiDi runs, if necessary, on script boundaries. + */ +static bool +_raqm_resolve_scripts (raqm_t *rq) +{ + int last_script_index = -1; + int last_set_index = -1; + hb_script_t last_script = HB_SCRIPT_INVALID; + _raqm_stack_t *stack = NULL; + hb_unicode_funcs_t* unicode_funcs = hb_unicode_funcs_get_default (); + + for (size_t i = 0; i < rq->text_len; ++i) + rq->text_info[i].script = hb_unicode_script (unicode_funcs, rq->text[i]); + +#ifdef RAQM_TESTING + RAQM_TEST ("Before script detection:\n"); + for (size_t i = 0; i < rq->text_len; ++i) + { + SCRIPT_TO_STRING (rq->text_info[i].script); + RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); + } + RAQM_TEST ("\n"); +#endif + + stack = _raqm_stack_new (rq->text_len); + if (!stack) + return false; + + for (int i = 0; i < (int) rq->text_len; i++) + { + if (rq->text_info[i].script == HB_SCRIPT_COMMON && last_script_index != -1) + { + int pair_index = _get_pair_index (rq->text[i]); + if (pair_index >= 0) + { + if (IS_OPEN (pair_index)) + { + /* is a paired character */ + rq->text_info[i].script = last_script; + last_set_index = i; + _raqm_stack_push (stack, rq->text_info[i].script, pair_index); + } + else + { + /* is a close paired character */ + /* find matching opening (by getting the last even index for current + * odd index) */ + while (!STACK_IS_EMPTY (stack) && + stack->pair_index[stack->size] != (pair_index & ~1)) + { + _raqm_stack_pop (stack); + } + if (!STACK_IS_EMPTY (stack)) + { + rq->text_info[i].script = _raqm_stack_top (stack); + last_script = rq->text_info[i].script; + last_set_index = i; + } + else + { + rq->text_info[i].script = last_script; + last_set_index = i; + } + } + } + else + { + rq->text_info[i].script = last_script; + last_set_index = i; + } + } + else if (rq->text_info[i].script == HB_SCRIPT_INHERITED && + last_script_index != -1) + { + rq->text_info[i].script = last_script; + last_set_index = i; + } + else + { + for (int j = last_set_index + 1; j < i; ++j) + rq->text_info[j].script = rq->text_info[i].script; + last_script = rq->text_info[i].script; + last_script_index = i; + last_set_index = i; + } + } + + /* Loop backwards and change any remaining Common or Inherit characters to + * take the script if the next character. + * https://github.com/HOST-Oman/libraqm/issues/95 + */ + for (int i = rq->text_len - 2; i >= 0; --i) + { + if (rq->text_info[i].script == HB_SCRIPT_INHERITED || + rq->text_info[i].script == HB_SCRIPT_COMMON) + rq->text_info[i].script = rq->text_info[i + 1].script; + } + +#ifdef RAQM_TESTING + RAQM_TEST ("After script detection:\n"); + for (size_t i = 0; i < rq->text_len; ++i) + { + SCRIPT_TO_STRING (rq->text_info[i].script); + RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); + } + RAQM_TEST ("\n"); +#endif + + _raqm_stack_free (stack); + + return true; +} + +static bool +_raqm_shape (raqm_t *rq) +{ + hb_buffer_flags_t hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT; + +#if defined(HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && \ + HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES + if (rq->invisible_glyph < 0) + hb_buffer_flags |= HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES; +#endif + + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + run->buffer = hb_buffer_create (); + + hb_buffer_add_utf32 (run->buffer, rq->text, rq->text_len, + run->pos, run->len); + hb_buffer_set_script (run->buffer, run->script); + hb_buffer_set_language (run->buffer, rq->text_info[run->pos].lang); + hb_buffer_set_direction (run->buffer, run->direction); + hb_buffer_set_flags (run->buffer, hb_buffer_flags); + +#ifdef HAVE_HB_BUFFER_SET_INVISIBLE_GLYPH + if (rq->invisible_glyph > 0) + hb_buffer_set_invisible_glyph (run->buffer, rq->invisible_glyph); +#endif + + hb_shape_full (run->font, run->buffer, rq->features, rq->features_len, + NULL); + } + + return true; +} + +/* Convert index from UTF-32 to UTF-8 */ +static uint32_t +_raqm_u32_to_u8_index (raqm_t *rq, + uint32_t index) +{ + FriBidiStrIndex length; + char *output = malloc ((sizeof (char) * 4 * index) + 1); + + length = fribidi_unicode_to_charset (FRIBIDI_CHAR_SET_UTF8, + rq->text, + index, + output); + + free (output); + return length; +} + +/* Convert index from UTF-8 to UTF-32 */ +static uint32_t +_raqm_u8_to_u32_index (raqm_t *rq, + uint32_t index) +{ + FriBidiStrIndex length; + uint32_t *output = malloc (sizeof (uint32_t) * (index + 1)); + + length = fribidi_charset_to_unicode (FRIBIDI_CHAR_SET_UTF8, + rq->text_utf8, + index, + output); + + free (output); + return length; +} + +static bool +_raqm_allowed_grapheme_boundary (hb_codepoint_t l_char, + hb_codepoint_t r_char); + +static bool +_raqm_in_hangul_syllable (hb_codepoint_t ch); + +/** + * raqm_index_to_position: + * @rq: a #raqm_t. + * @index: (inout): character index. + * @x: (out): output x position. + * @y: (out): output y position. + * + * Calculates the cursor position after the character at @index. If the character + * is right-to-left, then the cursor will be at the left of it, whereas if the + * character is left-to-right, then the cursor will be at the right of it. + * + * Return value: + * %true if the process was successful, %false otherwise. + * + * Since: 0.2 + */ +bool +raqm_index_to_position (raqm_t *rq, + size_t *index, + int *x, + int *y) +{ + /* We don't currently support multiline, so y is always 0 */ + *y = 0; + *x = 0; + + if (rq == NULL) + return false; + + if (rq->flags & RAQM_FLAG_UTF8) + *index = _raqm_u8_to_u32_index (rq, *index); + + if (*index >= rq->text_len) + return false; + + RAQM_TEST ("\n"); + + while (*index < rq->text_len) + { + if (_raqm_allowed_grapheme_boundary (rq->text[*index], rq->text[*index + 1])) + break; + + ++*index; + } + + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + size_t len; + hb_glyph_info_t *info; + hb_glyph_position_t *position; + len = hb_buffer_get_length (run->buffer); + info = hb_buffer_get_glyph_infos (run->buffer, NULL); + position = hb_buffer_get_glyph_positions (run->buffer, NULL); + + for (size_t i = 0; i < len; i++) + { + uint32_t curr_cluster = info[i].cluster; + uint32_t next_cluster = curr_cluster; + *x += position[i].x_advance; + + if (run->direction == HB_DIRECTION_LTR) + { + for (size_t j = i + 1; j < len && next_cluster == curr_cluster; j++) + next_cluster = info[j].cluster; + } + else + { + for (int j = i - 1; i != 0 && j >= 0 && next_cluster == curr_cluster; + j--) + next_cluster = info[j].cluster; + } + + if (next_cluster == curr_cluster) + next_cluster = run->pos + run->len; + + if (*index < next_cluster && *index >= curr_cluster) + { + if (run->direction == HB_DIRECTION_RTL) + *x -= position[i].x_advance; + *index = curr_cluster; + goto found; + } + } + } + +found: + if (rq->flags & RAQM_FLAG_UTF8) + *index = _raqm_u32_to_u8_index (rq, *index); + RAQM_TEST ("The position is %d at index %zu\n",*x ,*index); + return true; +} + +/** + * raqm_position_to_index: + * @rq: a #raqm_t. + * @x: x position. + * @y: y position. + * @index: (out): output character index. + * + * Returns the @index of the character at @x and @y position within text. + * If the position is outside the text, the last character is chosen as + * @index. + * + * Return value: + * %true if the process was successful, %false in case of error. + * + * Since: 0.2 + */ +bool +raqm_position_to_index (raqm_t *rq, + int x, + int y, + size_t *index) +{ + int delta_x = 0, current_x = 0; + (void)y; + + if (rq == NULL) + return false; + + if (x < 0) /* Get leftmost index */ + { + if (rq->resolved_dir == RAQM_DIRECTION_RTL) + *index = rq->text_len; + else + *index = 0; + return true; + } + + RAQM_TEST ("\n"); + + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + size_t len; + hb_glyph_info_t *info; + hb_glyph_position_t *position; + len = hb_buffer_get_length (run->buffer); + info = hb_buffer_get_glyph_infos (run->buffer, NULL); + position = hb_buffer_get_glyph_positions (run->buffer, NULL); + + for (size_t i = 0; i < len; i++) + { + delta_x = position[i].x_advance; + if (x < (current_x + delta_x)) + { + bool before = false; + if (run->direction == HB_DIRECTION_LTR) + before = (x < current_x + (delta_x / 2)); + else + before = (x > current_x + (delta_x / 2)); + + if (before) + *index = info[i].cluster; + else + { + uint32_t curr_cluster = info[i].cluster; + uint32_t next_cluster = curr_cluster; + if (run->direction == HB_DIRECTION_LTR) + for (size_t j = i + 1; j < len && next_cluster == curr_cluster; j++) + next_cluster = info[j].cluster; + else + for (int j = i - 1; i != 0 && j >= 0 && next_cluster == curr_cluster; + j--) + next_cluster = info[j].cluster; + + if (next_cluster == curr_cluster) + next_cluster = run->pos + run->len; + + *index = next_cluster; + } + if (_raqm_allowed_grapheme_boundary (rq->text[*index],rq->text[*index + 1])) + { + RAQM_TEST ("The start-index is %zu at position %d \n", *index, x); + return true; + } + + while (*index < (unsigned)run->pos + run->len) + { + if (_raqm_allowed_grapheme_boundary (rq->text[*index], + rq->text[*index + 1])) + { + *index += 1; + break; + } + *index += 1; + } + RAQM_TEST ("The start-index is %zu at position %d \n", *index, x); + return true; + } + else + current_x += delta_x; + } + } + + /* Get rightmost index*/ + if (rq->resolved_dir == RAQM_DIRECTION_RTL) + *index = 0; + else + *index = rq->text_len; + + RAQM_TEST ("The start-index is %zu at position %d \n", *index, x); + + return true; +} + +typedef enum +{ + RAQM_GRAPHEM_CR, + RAQM_GRAPHEM_LF, + RAQM_GRAPHEM_CONTROL, + RAQM_GRAPHEM_EXTEND, + RAQM_GRAPHEM_REGIONAL_INDICATOR, + RAQM_GRAPHEM_PREPEND, + RAQM_GRAPHEM_SPACING_MARK, + RAQM_GRAPHEM_HANGUL_SYLLABLE, + RAQM_GRAPHEM_OTHER +} _raqm_grapheme_t; + +static _raqm_grapheme_t +_raqm_get_grapheme_break (hb_codepoint_t ch, + hb_unicode_general_category_t category); + +static bool +_raqm_allowed_grapheme_boundary (hb_codepoint_t l_char, + hb_codepoint_t r_char) +{ + hb_unicode_general_category_t l_category; + hb_unicode_general_category_t r_category; + _raqm_grapheme_t l_grapheme, r_grapheme; + hb_unicode_funcs_t* unicode_funcs = hb_unicode_funcs_get_default (); + + l_category = hb_unicode_general_category (unicode_funcs, l_char); + r_category = hb_unicode_general_category (unicode_funcs, r_char); + l_grapheme = _raqm_get_grapheme_break (l_char, l_category); + r_grapheme = _raqm_get_grapheme_break (r_char, r_category); + + if (l_grapheme == RAQM_GRAPHEM_CR && r_grapheme == RAQM_GRAPHEM_LF) + return false; /*Do not break between a CR and LF GB3*/ + if (l_grapheme == RAQM_GRAPHEM_CONTROL || l_grapheme == RAQM_GRAPHEM_CR || + l_grapheme == RAQM_GRAPHEM_LF || r_grapheme == RAQM_GRAPHEM_CONTROL || + r_grapheme == RAQM_GRAPHEM_CR || r_grapheme == RAQM_GRAPHEM_LF) + return true; /*Break before and after CONTROL GB4, GB5*/ + if (r_grapheme == RAQM_GRAPHEM_HANGUL_SYLLABLE) + return false; /*Do not break Hangul syllable sequences. GB6, GB7, GB8*/ + if (l_grapheme == RAQM_GRAPHEM_REGIONAL_INDICATOR && + r_grapheme == RAQM_GRAPHEM_REGIONAL_INDICATOR) + return false; /*Do not break between regional indicator symbols. GB8a*/ + if (r_grapheme == RAQM_GRAPHEM_EXTEND) + return false; /*Do not break before extending characters. GB9*/ + /*Do not break before SpacingMarks, or after Prepend characters.GB9a, GB9b*/ + if (l_grapheme == RAQM_GRAPHEM_PREPEND) + return false; + if (r_grapheme == RAQM_GRAPHEM_SPACING_MARK) + return false; + return true; /*Otherwise, break everywhere. GB1, GB2, GB10*/ +} + +static _raqm_grapheme_t +_raqm_get_grapheme_break (hb_codepoint_t ch, + hb_unicode_general_category_t category) +{ + _raqm_grapheme_t gb_type; + + gb_type = RAQM_GRAPHEM_OTHER; + switch ((int)category) + { + case HB_UNICODE_GENERAL_CATEGORY_FORMAT: + if (ch == 0x200C || ch == 0x200D) + gb_type = RAQM_GRAPHEM_EXTEND; + else + gb_type = RAQM_GRAPHEM_CONTROL; + break; + + case HB_UNICODE_GENERAL_CATEGORY_CONTROL: + if (ch == 0x000D) + gb_type = RAQM_GRAPHEM_CR; + else if (ch == 0x000A) + gb_type = RAQM_GRAPHEM_LF; + else + gb_type = RAQM_GRAPHEM_CONTROL; + break; + + case HB_UNICODE_GENERAL_CATEGORY_SURROGATE: + case HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR: + case HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR: + case HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED: + if ((ch >= 0xFFF0 && ch <= 0xFFF8) || + (ch >= 0xE0000 && ch <= 0xE0FFF)) + gb_type = RAQM_GRAPHEM_CONTROL; + break; + + case HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK: + case HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK: + case HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK: + if (ch != 0x102B && ch != 0x102C && ch != 0x1038 && + (ch < 0x1062 || ch > 0x1064) && (ch < 0x1067 || ch > 0x106D) && + ch != 0x1083 && (ch < 0x1087 || ch > 0x108C) && ch != 0x108F && + (ch < 0x109A || ch > 0x109C) && ch != 0x1A61 && ch != 0x1A63 && + ch != 0x1A64 && ch != 0xAA7B && ch != 0xAA70 && ch != 0x11720 && + ch != 0x11721) /**/ + gb_type = RAQM_GRAPHEM_SPACING_MARK; + + else if (ch == 0x09BE || ch == 0x09D7 || + ch == 0x0B3E || ch == 0x0B57 || ch == 0x0BBE || ch == 0x0BD7 || + ch == 0x0CC2 || ch == 0x0CD5 || ch == 0x0CD6 || + ch == 0x0D3E || ch == 0x0D57 || ch == 0x0DCF || ch == 0x0DDF || + ch == 0x1D165 || (ch >= 0x1D16E && ch <= 0x1D172)) + gb_type = RAQM_GRAPHEM_EXTEND; + break; + + case HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER: + if (ch == 0x0E33 || ch == 0x0EB3) + gb_type = RAQM_GRAPHEM_SPACING_MARK; + break; + + case HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL: + if (ch >= 0x1F1E6 && ch <= 0x1F1FF) + gb_type = RAQM_GRAPHEM_REGIONAL_INDICATOR; + break; + + default: + gb_type = RAQM_GRAPHEM_OTHER; + break; + } + + if (_raqm_in_hangul_syllable (ch)) + gb_type = RAQM_GRAPHEM_HANGUL_SYLLABLE; + + return gb_type; +} + +static bool +_raqm_in_hangul_syllable (hb_codepoint_t ch) +{ + (void)ch; + return false; +} + +/** + * raqm_version: + * @major: (out): Library major version component. + * @minor: (out): Library minor version component. + * @micro: (out): Library micro version component. + * + * Returns library version as three integer components. + * + * Since: 0.7 + **/ +void +raqm_version (unsigned int *major, + unsigned int *minor, + unsigned int *micro) +{ + *major = RAQM_VERSION_MAJOR; + *minor = RAQM_VERSION_MINOR; + *micro = RAQM_VERSION_MICRO; +} + +/** + * raqm_version_string: + * + * Returns library version as a string with three components. + * + * Return value: library version string. + * + * Since: 0.7 + **/ +const char * +raqm_version_string (void) +{ + return RAQM_VERSION_STRING; +} + +/** + * raqm_version_atleast: + * @major: Library major version component. + * @minor: Library minor version component. + * @micro: Library micro version component. + * + * Checks if library version is less than or equal the specified version. + * + * Return value: + * %true if library version is less than or equal the specfied version, %false + * otherwise. + * + * Since: 0.7 + **/ +bool +raqm_version_atleast (unsigned int major, + unsigned int minor, + unsigned int micro) +{ + return RAQM_VERSION_ATLEAST (major, minor, micro); +} + +/** + * RAQM_VERSION_ATLEAST: + * @major: Library major version component. + * @minor: Library minor version component. + * @micro: Library micro version component. + * + * Checks if library version is less than or equal the specified version. + * + * Return value: + * %true if library version is less than or equal the specfied version, %false + * otherwise. + * + * Since: 0.7 + **/ + +/** + * RAQM_VERSION_STRING: + * + * Library version as a string with three components. + * + * Since: 0.7 + **/ + +/** + * RAQM_VERSION_MAJOR: + * + * Library major version component. + * + * Since: 0.7 + **/ + +/** + * RAQM_VERSION_MINOR: + * + * Library minor version component. + * + * Since: 0.7 + **/ + +/** + * RAQM_VERSION_MICRO: + * + * Library micro version component. + * + * Since: 0.7 + **/ diff --git a/src/libImaging/raqm.h b/src/thirdparty/raqm/raqm.h similarity index 90% rename from src/libImaging/raqm.h rename to src/thirdparty/raqm/raqm.h index eae1f43b7..1a33fe8ba 100644 --- a/src/libImaging/raqm.h +++ b/src/thirdparty/raqm/raqm.h @@ -24,17 +24,14 @@ #ifndef _RAQM_H_ #define _RAQM_H_ +#define _RAQM_H_IN_ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifndef bool -typedef int bool; -#endif -#ifndef uint32_t -typedef UINT32 uint32_t; -#endif +#include +#include #include #include FT_FREETYPE_H @@ -42,6 +39,8 @@ typedef UINT32 uint32_t; extern "C" { #endif +#include "raqm-version.h" + /** * raqm_t: * @@ -94,19 +93,6 @@ typedef struct raqm_glyph_t { FT_Face ftface; } raqm_glyph_t; -/** - * version 0.1 of the raqm_glyph_t structure - */ -typedef struct raqm_glyph_t_01 { - unsigned int index; - int x_advance; - int y_advance; - int x_offset; - int y_offset; - uint32_t cluster; -} raqm_glyph_t_01; - - raqm_t * raqm_create (void); @@ -155,6 +141,10 @@ bool raqm_set_freetype_load_flags (raqm_t *rq, int flags); +bool +raqm_set_invisible_glyph (raqm_t *rq, + int gid); + bool raqm_layout (raqm_t *rq); @@ -174,7 +164,22 @@ raqm_position_to_index (raqm_t *rq, int y, size_t *index); +void +raqm_version (unsigned int *major, + unsigned int *minor, + unsigned int *micro); + +const char * +raqm_version_string (void); + +bool +raqm_version_atleast (unsigned int major, + unsigned int minor, + unsigned int micro); + + #ifdef __cplusplus } #endif +#undef _RAQM_H_IN_ #endif /* _RAQM_H_ */ diff --git a/winbuild/build.rst b/winbuild/build.rst index cd4a45e87..7493c30e5 100644 --- a/winbuild/build.rst +++ b/winbuild/build.rst @@ -87,7 +87,7 @@ and install Pillow in develop mode (instead of ``python3 -m pip install --editab Testing Pillow -------------- -Some binary dependencies (e.g. ``libraqm.dll``) will be stored in the +Some binary dependencies (e.g. ``fribidi.dll``) will be stored in the ``winbuild\build\bin`` directory; this directory should be added to ``PATH`` before running tests. diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index fb52cb4ce..63270d753 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -105,9 +105,9 @@ header = [ # dependencies, listed in order of compilation deps = { "libjpeg": { - "url": SF_MIRROR + "/project/libjpeg-turbo/2.0.6/libjpeg-turbo-2.0.6.tar.gz", - "filename": "libjpeg-turbo-2.0.6.tar.gz", - "dir": "libjpeg-turbo-2.0.6", + "url": SF_MIRROR + "/project/libjpeg-turbo/2.1.0/libjpeg-turbo-2.1.0.tar.gz", + "filename": "libjpeg-turbo-2.1.0.tar.gz", + "dir": "libjpeg-turbo-2.1.0", "build": [ cmd_cmake( [ @@ -141,22 +141,22 @@ deps = { "libs": [r"*.lib"], }, "libtiff": { - "url": "https://download.osgeo.org/libtiff/tiff-4.1.0.tar.gz", - "filename": "tiff-4.1.0.tar.gz", - "dir": "tiff-4.1.0", + "url": "https://download.osgeo.org/libtiff/tiff-4.3.0.tar.gz", + "filename": "tiff-4.3.0.tar.gz", + "dir": "tiff-4.3.0", "build": [ - cmd_copy(r"{winbuild_dir}\tiff.opt", "nmake.opt"), - cmd_nmake("makefile.vc", "clean"), - cmd_nmake("makefile.vc", "lib"), + cmd_cmake("-DBUILD_SHARED_LIBS:BOOL=OFF"), + cmd_nmake(target="clean"), + cmd_nmake(target="tiff"), ], "headers": [r"libtiff\tiff*.h"], "libs": [r"libtiff\*.lib"], # "bins": [r"libtiff\*.dll"], }, "libwebp": { - "url": "http://downloads.webmproject.org/releases/webp/libwebp-1.1.0.tar.gz", - "filename": "libwebp-1.1.0.tar.gz", - "dir": "libwebp-1.1.0", + "url": "http://downloads.webmproject.org/releases/webp/libwebp-1.2.0.tar.gz", + "filename": "libwebp-1.2.0.tar.gz", + "dir": "libwebp-1.2.0", "build": [ cmd_rmdir(r"output\release-static"), # clean cmd_nmake( @@ -219,9 +219,9 @@ deps = { # "bins": [r"objs\{msbuild_arch}\Release\freetype.dll"], }, "lcms2": { - "url": SF_MIRROR + "/project/lcms/lcms/2.11/lcms2-2.11.tar.gz", - "filename": "lcms2-2.11.tar.gz", - "dir": "lcms2-2.11", + "url": SF_MIRROR + "/project/lcms/lcms/2.12/lcms2-2.12.tar.gz", + "filename": "lcms2-2.12.tar.gz", + "dir": "lcms2-2.12", "patch": { r"Projects\VC2017\lcms2_static\lcms2_static.vcxproj": { # default is /MD for x86 and /MT for x64, we need /MD always @@ -236,7 +236,9 @@ deps = { cmd_rmdir("Lib"), cmd_rmdir(r"Projects\VC2017\Release"), cmd_msbuild(r"Projects\VC2017\lcms2.sln", "Release", "Clean"), - cmd_msbuild(r"Projects\VC2017\lcms2.sln", "Release", "lcms2_static"), + cmd_msbuild( + r"Projects\VC2017\lcms2.sln", "Release", "lcms2_static:Rebuild" + ), cmd_xcopy("include", "{inc_dir}"), ], "libs": [r"Lib\MS\*.lib"], @@ -255,10 +257,10 @@ deps = { "libs": [r"bin\*.lib"], }, "libimagequant": { - # e5d454b: Merge tag '2.12.6' into msvc - "url": "https://github.com/ImageOptim/libimagequant/archive/e5d454bc7f5eb63ee50c84a83a7fa5ac94f68ec4.zip", # noqa: E501 - "filename": "libimagequant-e5d454bc7f5eb63ee50c84a83a7fa5ac94f68ec4.zip", - "dir": "libimagequant-e5d454bc7f5eb63ee50c84a83a7fa5ac94f68ec4", + # Merge master into msvc (matches 2.14.1 except for version bump) + "url": "https://github.com/ImageOptim/libimagequant/archive/16adaded22d1f90db5c9154a06d00a8b672ca09a.zip", # noqa: E501 + "filename": "libimagequant-16adaded22d1f90db5c9154a06d00a8b672ca09a.zip", + "dir": "libimagequant-16adaded22d1f90db5c9154a06d00a8b672ca09a", "patch": { "CMakeLists.txt": { "add_library": "add_compile_options(-openmp-)\r\nadd_library", @@ -275,9 +277,9 @@ deps = { "libs": [r"*.lib"], }, "harfbuzz": { - "url": "https://github.com/harfbuzz/harfbuzz/archive/2.7.4.zip", - "filename": "harfbuzz-2.7.4.zip", - "dir": "harfbuzz-2.7.4", + "url": "https://github.com/harfbuzz/harfbuzz/archive/2.8.1.zip", + "filename": "harfbuzz-2.8.1.zip", + "dir": "harfbuzz-2.8.1", "build": [ cmd_cmake("-DHB_HAVE_FREETYPE:BOOL=TRUE"), cmd_nmake(target="clean"), @@ -296,21 +298,7 @@ deps = { cmd_nmake(target="clean"), cmd_nmake(target="fribidi"), ], - "headers": [r"lib\*.h"], - "libs": [r"*.lib"], - }, - "libraqm": { - "url": "https://github.com/HOST-Oman/libraqm/archive/v0.7.1.zip", - "filename": "libraqm-0.7.1.zip", - "dir": "libraqm-0.7.1", - "build": [ - cmd_copy(r"{winbuild_dir}\raqm.cmake", r"CMakeLists.txt"), - cmd_cmake(), - cmd_nmake(target="clean"), - cmd_nmake(target="libraqm"), - ], - "headers": [r"src\*.h"], - "bins": [r"libraqm.dll"], + "bins": [r"*.dll"], }, } @@ -486,7 +474,7 @@ def build_pillow(): cmd_set("DISTUTILS_USE_SDK", "1"), # use same compiler to build Pillow cmd_set("MSSdk", "1"), # for PyPy3.6 cmd_set("py_vcruntime_redist", "true"), # use /MD, not /MT - r'"{python_dir}\{python_exe}" setup.py build_ext %*', + r'"{python_dir}\{python_exe}" setup.py build_ext --vendor-raqm --vendor-fribidi %*', # noqa: E501 ] write_script("build_pillow.cmd", lines) @@ -511,8 +499,8 @@ if __name__ == "__main__": verbose = True elif arg == "--no-imagequant": disabled += ["libimagequant"] - elif arg == "--no-raqm": - disabled += ["fribidi", "libraqm"] + elif arg == "--no-raqm" or arg == "--no-fribidi": + disabled += ["fribidi"] elif arg.startswith("--depends="): depends_dir = arg[10:] elif arg.startswith("--python="): diff --git a/winbuild/fribidi.cmake b/winbuild/fribidi.cmake index 47ab2c329..27b8d17a8 100644 --- a/winbuild/fribidi.cmake +++ b/winbuild/fribidi.cmake @@ -93,10 +93,10 @@ fribidi_tab(brackets-type unidata/BidiBrackets.txt) file(GLOB FRIBIDI_SOURCES lib/*.c) file(GLOB FRIBIDI_HEADERS lib/*.h) -add_library(fribidi STATIC +add_library(fribidi SHARED ${FRIBIDI_SOURCES} ${FRIBIDI_HEADERS} ${FRIBIDI_SOURCES_GENERATED}) fribidi_definitions(fribidi) target_compile_definitions(fribidi - PUBLIC -DFRIBIDI_LIB_STATIC) + PUBLIC "-DFRIBIDI_BUILD") diff --git a/winbuild/tiff.opt b/winbuild/tiff.opt deleted file mode 100644 index 16acabc26..000000000 --- a/winbuild/tiff.opt +++ /dev/null @@ -1,216 +0,0 @@ -# $Id: nmake.opt,v 1.18 2006/06/07 16:33:45 dron Exp $ -# -# Copyright (C) 2004, Andrey Kiselev -# -# Permission to use, copy, modify, distribute, and sell this software and -# its documentation for any purpose is hereby granted without fee, provided -# that (i) the above copyright notices and this permission notice appear in -# all copies of the software and related documentation, and (ii) the names of -# Sam Leffler and Silicon Graphics may not be used in any advertising or -# publicity relating to the software without the specific, prior written -# permission of Sam Leffler and Silicon Graphics. -# -# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, -# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY -# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. -# -# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR -# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, -# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF -# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. - -# Compile time parameters for MS Visual C++ compiler. -# You may edit this file to specify building options. - -# -###### Edit the following lines to choose a feature set you need. ####### -# - -# -# Select WINMODE_CONSOLE to build a library which reports errors to stderr, or -# WINMODE_WINDOWED to build such that errors are reported via MessageBox(). -# -WINMODE_CONSOLE = 1 -#WINMODE_WINDOWED = 1 - -# -# Comment out the following lines to disable internal codecs. -# -# Support for CCITT Group 3 & 4 algorithms -CCITT_SUPPORT = 1 -# Support for Macintosh PackBits algorithm -PACKBITS_SUPPORT = 1 -# Support for LZW algorithm -LZW_SUPPORT = 1 -# Support for ThunderScan 4-bit RLE algorithm -THUNDER_SUPPORT = 1 -# Support for NeXT 2-bit RLE algorithm -NEXT_SUPPORT = 1 -# Support for LogLuv high dynamic range encoding -LOGLUV_SUPPORT = 1 - -# -# Uncomment and edit following lines to enable JPEG support. -# -JPEG_SUPPORT = 1 -JPEG_INCLUDE = -I$(INCLIB) -JPEG_LIB = $(INCLIB)/libjpeg.lib - -# -# Uncomment and edit following lines to enable ZIP support -# (required for Deflate compression and Pixar log-format) -# -ZIP_SUPPORT = 1 -ZLIB_INCLUDE = -I$(INCLIB) -ZLIB_LIB = $(INCLIB)/zlib.lib - -# -# Uncomment and edit following lines to enable ISO JBIG support -# -#JBIG_SUPPORT = 1 -#JBIGDIR = d:/projects/jbigkit -#JBIG_INCLUDE = -I$(JBIGDIR)/libjbig -#JBIG_LIB = $(JBIGDIR)/libjbig/jbig.lib - -# -# Uncomment following line to enable Pixar log-format algorithm -# (Zlib required). -# -#PIXARLOG_SUPPORT = 1 - -# -# Comment out the following lines to disable strip chopping -# (whether or not to convert single-strip uncompressed images to multiple -# strips of specified size to reduce memory usage). Default strip size -# is 8192 bytes, it can be configured via the STRIP_SIZE_DEFAULT parameter -# -STRIPCHOP_SUPPORT = 1 -STRIP_SIZE_DEFAULT = 8192 - -# -# Comment out the following lines to disable treating the fourth sample with -# no EXTRASAMPLE_ value as being ASSOCALPHA. Many packages produce RGBA -# files but don't mark the alpha properly. -# -EXTRASAMPLE_AS_ALPHA_SUPPORT = 1 - -# -# Comment out the following lines to disable picking up YCbCr subsampling -# info from the JPEG data stream to support files lacking the tag. -# See Bug 168 in Bugzilla, and JPEGFixupTestSubsampling() for details. -# -CHECK_JPEG_YCBCR_SUBSAMPLING = 1 - -# -####################### Compiler related options. ####################### -# - -# -# Pick debug or optimized build flags. We default to an optimized build -# with no debugging information. -# NOTE: /EHsc option required if you want to build the C++ stream API -# -OPTFLAGS = /Ox /MD /EHsc /W3 /D_CRT_SECURE_NO_DEPRECATE -#OPTFLAGS = /Zi - -# -# Uncomment following line to enable using Windows Common RunTime Library -# instead of Windows specific system calls. See notes on top of tif_unix.c -# module for details. -# -USE_WIN_CRT_LIB = 1 - -# Compiler specific options. You may probably want to adjust compilation -# parameters in CFLAGS variable. Refer to your compiler documentation -# for the option reference. -# -MAKE = nmake /nologo -CC = cl /nologo -CXX = cl /nologo -AR = lib /nologo -LD = link /nologo - -CFLAGS = $(OPTFLAGS) $(INCL) $(EXTRAFLAGS) -CXXFLAGS = $(OPTFLAGS) $(INCL) $(EXTRAFLAGS) -EXTRAFLAGS = -LIBS = - -# Name of the output shared library -DLLNAME = libtiff.dll - -# -########### There is nothing to edit below this line normally. ########### -# - -# Set the native cpu bit order -EXTRAFLAGS = -DFILLODER_LSB2MSB $(EXTRAFLAGS) - -!IFDEF WINMODE_WINDOWED -EXTRAFLAGS = -DTIF_PLATFORM_WINDOWED $(EXTRAFLAGS) -LIBS = user32.lib $(LIBS) -!ELSE -EXTRAFLAGS = -DTIF_PLATFORM_CONSOLE $(EXTRAFLAGS) -!ENDIF - -# Codec stuff -!IFDEF CCITT_SUPPORT -EXTRAFLAGS = -DCCITT_SUPPORT $(EXTRAFLAGS) -!ENDIF - -!IFDEF PACKBITS_SUPPORT -EXTRAFLAGS = -DPACKBITS_SUPPORT $(EXTRAFLAGS) -!ENDIF - -!IFDEF LZW_SUPPORT -EXTRAFLAGS = -DLZW_SUPPORT $(EXTRAFLAGS) -!ENDIF - -!IFDEF THUNDER_SUPPORT -EXTRAFLAGS = -DTHUNDER_SUPPORT $(EXTRAFLAGS) -!ENDIF - -!IFDEF NEXT_SUPPORT -EXTRAFLAGS = -DNEXT_SUPPORT $(EXTRAFLAGS) -!ENDIF - -!IFDEF LOGLUV_SUPPORT -EXTRAFLAGS = -DLOGLUV_SUPPORT $(EXTRAFLAGS) -!ENDIF - -!IFDEF JPEG_SUPPORT -LIBS = $(LIBS) $(JPEG_LIB) -EXTRAFLAGS = -DJPEG_SUPPORT -DOJPEG_SUPPORT $(EXTRAFLAGS) -!ENDIF - -!IFDEF ZIP_SUPPORT -LIBS = $(LIBS) $(ZLIB_LIB) -EXTRAFLAGS = -DZIP_SUPPORT $(EXTRAFLAGS) -!IFDEF PIXARLOG_SUPPORT -EXTRAFLAGS = -DPIXARLOG_SUPPORT $(EXTRAFLAGS) -!ENDIF -!ENDIF - -!IFDEF JBIG_SUPPORT -LIBS = $(LIBS) $(JBIG_LIB) -EXTRAFLAGS = -DJBIG_SUPPORT $(EXTRAFLAGS) -!ENDIF - -!IFDEF STRIPCHOP_SUPPORT -EXTRAFLAGS = -DSTRIPCHOP_DEFAULT=TIFF_STRIPCHOP -DSTRIP_SIZE_DEFAULT=$(STRIP_SIZE_DEFAULT) $(EXTRAFLAGS) -!ENDIF - -!IFDEF EXTRASAMPLE_AS_ALPHA_SUPPORT -EXTRAFLAGS = -DDEFAULT_EXTRASAMPLE_AS_ALPHA $(EXTRAFLAGS) -!ENDIF - -!IFDEF CHECK_JPEG_YCBCR_SUBSAMPLING -EXTRAFLAGS = -DCHECK_JPEG_YCBCR_SUBSAMPLING $(EXTRAFLAGS) -!ENDIF - -!IFDEF USE_WIN_CRT_LIB -EXTRAFLAGS = -DAVOID_WIN32_FILEIO $(EXTRAFLAGS) -!ELSE -EXTRAFLAGS = -DUSE_WIN32_FILEIO $(EXTRAFLAGS) -!ENDIF