Sun raster files with RLE encoding and odd-width rows decode shifted

未关闭 适合新手
#10,370 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@PerryLink 已经在做这个了。

开始于 2026年11月1日。

  • #10375 来自 @PerryLink —— 未关闭

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
72/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
python
领域
tooling

调研方向

从 Image.open() 的复现脚本开始,定位处理类型 2 Sun 栅格数据的 sun_rle 解码器。跟踪存储的行跨度是如何计算的,并将 RLE 路径与已经接收填充跨度的原始路径进行比较。当奇数宽度的 RLE 图像解码每一行时不再包含填充字节,并且回归测试覆盖已报告的 3x2 灰度案例时,工作即告完成。

由索引模型根据 Issue 内容生成。

描述

What did you do?

I opened a run-length-encoded (type 2) Sun raster image whose rows hold an odd number of bytes (an 8-bit grayscale image 3 pixels wide) using Image.open() on an in-memory file created by the self-contained script below.

In this format every stored row is padded to an even number of bytes, and the RLE stream encodes the padding bytes too (SUN_RAS.TXT: "Regardless of width, the stored scanlines are rounded up to multiples of 16 bits", "A run is not terminated at the end of a scan line").

What did you expect to happen?
row 0: 16 32 48
row 1: 64 80 96
What actually happened?

The padding byte at the end of row 0 was decoded as the first pixel of row 1, and every following row is shifted one more byte, without any error:

row 0: 16 32 48
row 1: 0 64 80

Any image whose pixels take an odd number of bytes per row is affected (8-bit and 24-bit images of odd width; 1-bit images 1–8, 17–24, … pixels wide; 4-bit images 1–2, 5–6, … pixels wide). Images with even-length rows decode correctly as well as uncompressed (type 1) Sun raster files.

What are your OS, Python and Pillow versions?
  • OS: Ubuntu 24.04, x86_64
  • Python: 3.12.3
  • Pillow: 13.0.0; also reproduced with 12.3.0 and current main (13.1.0.dev0, 1c5bdeb2c)
--------------------------------------------------------------------
Pillow 13.0.0
Python 3.12.3 (main, Aug 31 2026, 10:18:26) [GCC 13.3.0]
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 13.0.0
*** TKINTER support not installed
--- FREETYPE2 support ok, loaded 2.14.3
--- LITTLECMS2 support ok, loaded 2.19
--- WEBP support ok, loaded 1.6.0
--- AVIF support ok, loaded 1.4.2
--- JPEG support ok, compiled for libjpeg-turbo 3.2.0
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.4
--- ZLIB (PNG/ZIP) support ok, loaded 1.3, compiled for zlib-ng 2.3.3
--- LIBTIFF support ok, loaded 4.7.2
--- RAQM (Bidirectional Text) support ok, loaded 0.11.0, fribidi 1.0.13, harfbuzz 14.5.0
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------
import io
import struct

from PIL import Image

# 8-bit grayscale, 3x2 pixels, type 2 (run-length encoded).
# Each stored row is 3 pixel bytes + 1 padding byte.
header = struct.pack(">8I", 0x59A66A95, 3, 2, 8, 8, 2, 0, 0)
data = bytes([0x10, 0x20, 0x30, 0x00,  # row 0: pixels 16 32 48, padding
              0x40, 0x50, 0x60, 0x00])  # row 1: pixels 64 80 96, padding

with Image.open(io.BytesIO(header + data)) as im:
    rows = [[im.getpixel((x, y)) for x in range(3)] for y in range(2)]

print("decoded :", rows)
print("expected:", [[0x10, 0x20, 0x30], [0x40, 0x50, 0x60]])

Output:

decoded : [[16, 32, 48], [0, 64, 80]]
expected: [[16, 32, 48], [64, 80, 96]]

Passing the padded stride to the sun_rle decoder (the same stride the raw path already computes) fixes it in my testing — happy to send a PR.

Found by genproof.com Formal Verification Agent. Reviewed and approved by a human.

主要语言
Python
星标
13.9k
派生
2.6k
平均合并
1 天 2 小时
30 天内合并 PR
176

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

python-pillow/Pillow 的其他 Issue

查看 python-pillow/Pillow 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。