From 0d7f5077a75341b6af35636541e97299a1c5af69 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 21 Mar 2026 00:58:27 +1100 Subject: [PATCH] If v2 extension area specifies no alpha, fill alpha channel --- Tests/test_file_tga.py | 22 +++++++++++++++++++++- src/PIL/TgaImagePlugin.py | 16 ++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py index 277515fd425..7ec562342e1 100644 --- a/Tests/test_file_tga.py +++ b/Tests/test_file_tga.py @@ -1,11 +1,12 @@ from __future__ import annotations import os +from io import BytesIO from pathlib import Path import pytest -from PIL import Image, UnidentifiedImageError +from PIL import Image, UnidentifiedImageError, _binary from .helper import assert_image_equal, assert_image_equal_tofile, hopper @@ -92,6 +93,25 @@ def test_rgba_16() -> None: assert im.getpixel((1, 0)) == (0, 255, 82, 0) +def test_v2_no_alpha() -> None: + test_file = "Tests/images/tga/common/200x32_rgba_tl_rle.tga" + with open(test_file, "rb") as fp: + data = fp.read() + data += ( + b"\x00" * 495 + + _binary.o32le(len(data)) + + _binary.o32le(0) + + b"TRUEVISION-XFILE.\x00" + ) + with Image.open(BytesIO(data)) as im: + with Image.open(test_file) as im2: + r, g, b = im2.split()[:3] + a = Image.new("L", im2.size, 255) + expected = Image.merge("RGBA", (r, g, b, a)) + + assert_image_equal(im, expected) + + def test_id_field() -> None: # tga file with id field test_file = "Tests/images/tga_id_field.tga" diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py index 90d5b5cf4ee..b2989a4b764 100644 --- a/src/PIL/TgaImagePlugin.py +++ b/src/PIL/TgaImagePlugin.py @@ -17,11 +17,13 @@ # from __future__ import annotations +import os import warnings from typing import IO from . import Image, ImageFile, ImagePalette from ._binary import i16le as i16 +from ._binary import i32le as i32 from ._binary import o8 from ._binary import o16le as o16 @@ -157,6 +159,20 @@ def _open(self) -> None: pass # cannot decode def load_end(self) -> None: + if self.mode == "RGBA": + assert self.fp is not None + self.fp.seek(-26, os.SEEK_END) + footer = self.fp.read(26) + if footer.endswith(b"TRUEVISION-XFILE.\x00"): + # version 2 + extension_offset = i32(footer) + if extension_offset: + self.fp.seek(extension_offset + 494) + attributes_type = self.fp.read(1) + if attributes_type == b"\x00": + # No alpha + self.im.fillband(3, 255) + if self._flip_horizontally: self.im = self.im.transpose(Image.Transpose.FLIP_LEFT_RIGHT)