Skip to content

Fix unexpected error when saving zero dimension images#9391

Merged
hugovk merged 1 commit intopython-pillow:mainfrom
radarhere:gif_save
Feb 16, 2026
Merged

Fix unexpected error when saving zero dimension images#9391
hugovk merged 1 commit intopython-pillow:mainfrom
radarhere:gif_save

Conversation

@radarhere
Copy link
Copy Markdown
Member

@radarhere radarhere commented Jan 12, 2026

#9389 has pointed out that

from PIL import Image
img = Image.new('RGB', (0, 50))
img.save('test.gif')

raises

Traceback (most recent call last):
  File "demo.py", line 3, in <module>
    img.save('test.gif')
  File "PIL/Image.py", line 2592, in save
    save_handler(self, fp, filename)
  File "PIL/GifImagePlugin.py", line 808, in _save
    _write_single_frame(im, fp, palette)
  File "PIL/GifImagePlugin.py", line 625, in _write_single_frame
    im_out = _normalize_palette(im_out, palette, im.encoderinfo)
  File "PIL/GifImagePlugin.py", line 599, in _normalize_palette
    optimized_palette_colors = _get_optimize(im, info)
  File "PIL/GifImagePlugin.py", line 959, in _get_optimize
    if optimise or max(used_palette_colors) >= len(used_palette_colors):
ValueError: max() arg is an empty sequence

There is also an unexpected error for SPIDER images.

from PIL import Image
img = Image.new('RGB', (0, 50))
img.save('test', 'SPIDER')

raises

Traceback (most recent call last):
  File "demo.py", line 3, in <module>
    im.save('out', 'SPIDER')
  File "PIL/Image.py", line 2592, in save
    save_handler(self, fp, filename)
  File "PIL/SpiderImagePlugin.py", line 296, in _save_spider
    _save(im, fp, filename)
  File "PIL/SpiderImagePlugin.py", line 279, in _save
    hdr = makeSpiderHeader(im)
  File "PIL/SpiderImagePlugin.py", line 248, in makeSpiderHeader
    labrec = int(1024 / lenbyt)
ZeroDivisionError: division by zero

This fixes thse unexpected errors, instead raising

Traceback (most recent call last):
  File "demo.py", line 3, in <module>
    img.save('test.gif')
  File "PIL/Image.py", line 2592, in save
    save_handler(self, fp, filename)
  File "PIL/GifImagePlugin.py", line 808, in _save
    _write_single_frame(im, fp, palette)
  File "PIL/GifImagePlugin.py", line 637, in _write_single_frame
    ImageFile._save(
  File "PIL/ImageFile.py", line 662, in _save
    _encode_tile(im, fp, tile, bufsize, fh)
  File "PIL/ImageFile.py", line 682, in _encode_tile
    encoder.setimage(im.im, extents)
SystemError: tile cannot extend outside image

There is also an unexpected error for PCX images.

from PIL import Image
img = Image.new('RGB', (0, 50))
img.save('test.pcx')

raises

Traceback (most recent call last):
  File "demo.py", line 15, in <module>
    img.save('test.pcx')
  File "PIL/Image.py", line 2592, in save
    save_handler(self, fp, filename)
  File "PIL/PcxImagePlugin.py", line 185, in _save
    + o16(im.size[0] - 1)
  File "PIL/_binary.py", line 100, in o16le
    return pack("<H", i)
struct.error: ushort format requires 0 <= number <= (32767 * 2 + 1)

This adds a new error, similar to JPEG

Traceback (most recent call last):
  File "demo.py", line 15, in <module>
    img.save('test.pcx')
  File "PIL/Image.py", line 2592, in save
    save_handler(self, fp, filename)
  File "PIL/PcxImagePlugin.py", line 151, in _save
    raise ValueError(msg)
ValueError: Cannot write empty image as PCX

@radarhere radarhere added the GIF label Jan 12, 2026
@radarhere radarhere removed the GIF label Jan 12, 2026
@radarhere radarhere changed the title Fix unexpected error when saving zero dimension GIF Fix unexpected error when saving zero dimension GIF and PCX Jan 12, 2026
@radarhere radarhere force-pushed the gif_save branch 2 times, most recently from 876be85 to 4326110 Compare January 12, 2026 21:48
@radarhere radarhere changed the title Fix unexpected error when saving zero dimension GIF and PCX Fix unexpected error when saving zero dimension images Jan 13, 2026
@hugovk hugovk merged commit a5c9eba into python-pillow:main Feb 16, 2026
56 checks passed
@radarhere radarhere deleted the gif_save branch February 16, 2026 10:59
luketainton pushed a commit to luketainton/repos_webexmemebot that referenced this pull request Apr 1, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pillow](https://github.com/python-pillow/Pillow) ([changelog](https://github.com/python-pillow/Pillow/releases)) | `<12.1.2,>=12.1.1` → `<12.2.1,>=12.2.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/pillow/12.2.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pillow/12.1.1/12.2.0?slim=true) |

---

### Release Notes

<details>
<summary>python-pillow/Pillow (pillow)</summary>

### [`v12.2.0`](https://github.com/python-pillow/Pillow/releases/tag/12.2.0)

[Compare Source](python-pillow/Pillow@12.1.1...12.2.0)

<https://pillow.readthedocs.io/en/stable/releasenotes/12.2.0.html>

#### Documentation

- Update 12.2.0 release notes [#&#8203;9522](python-pillow/Pillow#9522) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Add loader plugins: AMOS abk, Atari Degas, 40+ more obscure formats via Netpbm [#&#8203;9482](python-pillow/Pillow#9482) \[[@&#8203;bitplane](https://github.com/bitplane)]
- Update Python versions [#&#8203;9515](python-pillow/Pillow#9515) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Jeffrey A. Clark -> Jeffrey 'Alex' Clark [#&#8203;9513](python-pillow/Pillow#9513) \[[@&#8203;aclark4life](https://github.com/aclark4life)]
- Add release notes for [#&#8203;9394](python-pillow/Pillow#9394), [#&#8203;9419](python-pillow/Pillow#9419) and [#&#8203;9456](python-pillow/Pillow#9456) [#&#8203;9467](python-pillow/Pillow#9467) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Add Amiga Workbench .info loader to 3rd party plugins list [#&#8203;9459](python-pillow/Pillow#9459) \[[@&#8203;bitplane](https://github.com/bitplane)]
- Merge PFM documentation into PPM [#&#8203;9434](python-pillow/Pillow#9434) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update macOS tested Pillow versions [#&#8203;9431](python-pillow/Pillow#9431) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Fix CVE number [#&#8203;9430](python-pillow/Pillow#9430) \[[@&#8203;hugovk](https://github.com/hugovk)]

#### Dependencies

- Update xz to 5.8.3 [#&#8203;9523](python-pillow/Pillow#9523) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update libjpeg-turbo to 3.1.4.1 [#&#8203;9507](python-pillow/Pillow#9507) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update libpng to 1.6.56 [#&#8203;9499](python-pillow/Pillow#9499) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update freetype to 2.14.3 [#&#8203;9485](python-pillow/Pillow#9485) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Updated libavif to 1.4.1 [#&#8203;9479](python-pillow/Pillow#9479) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Updated harfbuzz to 13.2.1 [#&#8203;9461](python-pillow/Pillow#9461) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update Ghostscript to 10.7.0 [#&#8203;9469](python-pillow/Pillow#9469) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update harfbuzz to 13.0.1 [#&#8203;9453](python-pillow/Pillow#9453) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update libavif to 1.4.0 [#&#8203;9460](python-pillow/Pillow#9460) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update freetype to 2.14.2 [#&#8203;9449](python-pillow/Pillow#9449) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update actions/download-artifact action to v8 [#&#8203;9451](python-pillow/Pillow#9451) \[@&#8203;[renovate\[bot\]](https://github.com/apps/renovate)]
- Updated libpng to 1.6.55 [#&#8203;9425](python-pillow/Pillow#9425) \[[@&#8203;radarhere](https://github.com/radarhere)]

#### Testing

- Cleanup .spider extension in the same test where it is added [#&#8203;9517](python-pillow/Pillow#9517) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Run tests in parallel via tox for 3.5x speedup [#&#8203;9516](python-pillow/Pillow#9516) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Enable colour in CI logs [#&#8203;9486](python-pillow/Pillow#9486) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Update Ghostscript to 10.7.0 [#&#8203;9469](python-pillow/Pillow#9469) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Simplify TGA test code [#&#8203;9477](python-pillow/Pillow#9477) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Update tests to check for ValueError when encoding an empty image [#&#8203;9464](python-pillow/Pillow#9464) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Upgrade CI from `macos-15-intel` to `macos-26-intel` [#&#8203;9454](python-pillow/Pillow#9454) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Add check-case-conflict hook [#&#8203;9446](python-pillow/Pillow#9446) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Specify platform when pulling docker image [#&#8203;9440](python-pillow/Pillow#9440) \[[@&#8203;radarhere](https://github.com/radarhere)]
- GHA: Cache libavif and webp builds for Ubuntu [#&#8203;9437](python-pillow/Pillow#9437) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Update macOS tested Pillow versions [#&#8203;9431](python-pillow/Pillow#9431) \[[@&#8203;radarhere](https://github.com/radarhere)]

#### Other changes

- Check calloc return value [#&#8203;9527](python-pillow/Pillow#9527) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Check all allocs in the Arrow tree [#&#8203;9488](python-pillow/Pillow#9488) \[[@&#8203;wiredfool](https://github.com/wiredfool)]
- Reject non-numeric elements inside list coords [#&#8203;9526](python-pillow/Pillow#9526) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Move variable declaration inside define [#&#8203;9525](python-pillow/Pillow#9525) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Resize tall images vertically first [#&#8203;9524](python-pillow/Pillow#9524) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Avoid overflow by not adding extents together [#&#8203;9520](python-pillow/Pillow#9520) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Use long for glyph position [#&#8203;9518](python-pillow/Pillow#9518) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Raise an error if the trailer chain loops back on itself [#&#8203;9519](python-pillow/Pillow#9519) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Only read as much data from gzip-decompressed data as necessary [#&#8203;9521](python-pillow/Pillow#9521) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Allow None extents in C setimage() [#&#8203;9504](python-pillow/Pillow#9504) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Use critical sections to protect FontObject [#&#8203;9498](python-pillow/Pillow#9498) \[[@&#8203;colesbury](https://github.com/colesbury)]
- Add ImageText.Text.wrap() to wrap text [#&#8203;9286](python-pillow/Pillow#9286) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Always call StubHandler open() when opening StubImageFile [#&#8203;9412](python-pillow/Pillow#9412) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Improved BCn overflow check [#&#8203;9043](python-pillow/Pillow#9043) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Image will never be None [#&#8203;9512](python-pillow/Pillow#9512) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Raise EOFError when seeking too far in PSD [#&#8203;9388](python-pillow/Pillow#9388) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Raise error if ImageGrab subprocess gives non-zero returncode [#&#8203;9321](python-pillow/Pillow#9321) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Allow for different palette entry sizes when correcting BMP pixel data offset [#&#8203;9472](python-pillow/Pillow#9472) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Ignore unspecified extra samples for TIFF separate planar configuration [#&#8203;9514](python-pillow/Pillow#9514) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Add PERF to lint and fix findings [#&#8203;9510](python-pillow/Pillow#9510) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Switch iOS back to macos-15-intel [#&#8203;9509](python-pillow/Pillow#9509) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Catch struct.error [#&#8203;9505](python-pillow/Pillow#9505) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Check PyCapsule\_GetPointer and PyBytes\_FromStringAndSize return values [#&#8203;9508](python-pillow/Pillow#9508) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Fix missing null dereference checks [#&#8203;9489](python-pillow/Pillow#9489) \[[@&#8203;wiredfool](https://github.com/wiredfool)]
- CI: Retry failed downloads [#&#8203;9506](python-pillow/Pillow#9506) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Use PyModule\_AddObjectRef [#&#8203;9503](python-pillow/Pillow#9503) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Release reference to encoder on error [#&#8203;9500](python-pillow/Pillow#9500) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Fixed AVIF and WEBP dealloc [#&#8203;9501](python-pillow/Pillow#9501) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Check PyType\_Ready return values [#&#8203;9502](python-pillow/Pillow#9502) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Check if PyObject\_CallMethod result is NULL [#&#8203;9494](python-pillow/Pillow#9494) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Do not use palette from grayscale or bilevel colorspace when reading JPEG2000 images [#&#8203;9468](python-pillow/Pillow#9468) \[[@&#8203;radarhere](https://github.com/radarhere)]
- If TGA v2 extension area specifies no alpha, fill alpha channel [#&#8203;9478](python-pillow/Pillow#9478) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Set image pixels individually on 32-bit Windows [#&#8203;9492](python-pillow/Pillow#9492) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Add error messages before returning NULL when encoding [#&#8203;9493](python-pillow/Pillow#9493) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Fix `_getxy` refcount leaks [#&#8203;9487](python-pillow/Pillow#9487) \[[@&#8203;hugovk](https://github.com/hugovk)]
- Fix invalid test font [#&#8203;9483](python-pillow/Pillow#9483) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Add Exif tag "FrameRate" [#&#8203;9470](python-pillow/Pillow#9470) \[[@&#8203;zhiyuanouyang](https://github.com/zhiyuanouyang)]
- Support reading JPEG2000 images with CMYK palettes [#&#8203;9456](python-pillow/Pillow#9456) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Simplify `setimage()` by always passing extents [#&#8203;9395](python-pillow/Pillow#9395) \[[@&#8203;radarhere](https://github.com/radarhere)]
- If bitmap buffer is empty, do not render anything [#&#8203;8324](python-pillow/Pillow#8324) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Change to ValueError when encoding an empty image [#&#8203;9394](python-pillow/Pillow#9394) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Add FontFile.to\_imagefont() [#&#8203;9419](python-pillow/Pillow#9419) \[[@&#8203;fjhenigman](https://github.com/fjhenigman)]
- \[pre-commit.ci] pre-commit autoupdate [#&#8203;9450](python-pillow/Pillow#9450) \[@&#8203;[pre-commit-ci\[bot\]](https://github.com/apps/pre-commit-ci)]
- Use walrus operator [#&#8203;9448](python-pillow/Pillow#9448) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Only close file handle in ImagePalette.save() if it was opened internally [#&#8203;9444](python-pillow/Pillow#9444) \[[@&#8203;bysiber](https://github.com/bysiber)]
- Fix `self.decode` typo [#&#8203;9445](python-pillow/Pillow#9445) \[[@&#8203;bysiber](https://github.com/bysiber)]
- Fix BMP RLE delta escape reading from wrong file position [#&#8203;9443](python-pillow/Pillow#9443) \[[@&#8203;bysiber](https://github.com/bysiber)]
- Correct error check when encoding AVIF images [#&#8203;9442](python-pillow/Pillow#9442) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Fix unexpected error when saving zero dimension images [#&#8203;9391](python-pillow/Pillow#9391) \[[@&#8203;radarhere](https://github.com/radarhere)]
- Use uppercase format ID for PALM [#&#8203;9435](python-pillow/Pillow#9435) \[[@&#8203;radarhere](https://github.com/radarhere)]

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDIuNiIsInVwZGF0ZWRJblZlciI6IjQzLjEwMi42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJ0eXBlL2RlcGVuZGVuY2llcyJdfQ==-->

Reviewed-on: https://git.tainton.uk/repos/webexmemebot/pulls/579
Reviewed-by: Luke Tainton <luke@tainton.uk>
Co-authored-by: renovate[bot] <renovate-bot@git.tainton.uk>
Co-committed-by: renovate[bot] <renovate-bot@git.tainton.uk>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants