diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py
index 57b6ae2c8..02893e837 100644
--- a/src/PIL/TgaImagePlugin.py
+++ b/src/PIL/TgaImagePlugin.py
@@ -20,6 +20,8 @@
 from . import Image, ImageFile, ImagePalette
 from ._binary import i8, i16le as i16, o8, o16le as o16
 
+import warnings
+
 __version__ = "0.3"
 
 
@@ -53,7 +55,7 @@ class TgaImageFile(ImageFile.ImageFile):
         # process header
         s = self.fp.read(18)
 
-        idlen = i8(s[0])
+        id_len = i8(s[0])
 
         colormaptype = i8(s[1])
         imagetype = i8(s[2])
@@ -100,8 +102,8 @@ class TgaImageFile(ImageFile.ImageFile):
         if imagetype & 8:
             self.info["compression"] = "tga_rle"
 
-        if idlen:
-            self.info["id_section"] = self.fp.read(idlen)
+        if id_len:
+            self.info["id_section"] = self.fp.read(id_len)
 
         if colormaptype:
             # read palette
@@ -151,11 +153,23 @@ def _save(im, fp, filename):
     except KeyError:
         raise IOError("cannot write mode %s as TGA" % im.mode)
 
-    rle = im.encoderinfo.get("rle", False)
-
+    if "rle" in im.encoderinfo:
+        rle = im.encoderinfo["rle"]
+    else:
+        compression = im.encoderinfo.get("compression",
+                                         im.info.get("compression"))
+        rle = compression == "tga_rle"
     if rle:
         imagetype += 8
 
+    id_section = im.encoderinfo.get("id_section",
+                                    im.info.get("id_section", ""))
+    id_len = len(id_section)
+    if id_len > 255:
+        id_len = 255
+        id_section = id_section[:255]
+        warnings.warn("id_section has been trimmed to 255 characters")
+
     if colormaptype:
         colormapfirst, colormaplength, colormapentry = 0, 256, 24
     else:
@@ -166,11 +180,12 @@ def _save(im, fp, filename):
     else:
         flags = 0
 
-    orientation = im.info.get("orientation", -1)
+    orientation = im.encoderinfo.get("orientation",
+                                     im.info.get("orientation", -1))
     if orientation > 0:
         flags = flags | 0x20
 
-    fp.write(b"\000" +
+    fp.write(o8(id_len) +
              o8(colormaptype) +
              o8(imagetype) +
              o16(colormapfirst) +
@@ -183,6 +198,9 @@ def _save(im, fp, filename):
              o8(bits) +
              o8(flags))
 
+    if id_section:
+        fp.write(id_section)
+
     if colormaptype:
         fp.write(im.im.getpalette("RGB", "BGR"))
 

Sanitize TGA Image.info
Currently, the TGA image plugin sets `Image.info` "compression" to "tga_rle" on `load()`, while `save()` takes "rle" (bool) option. Both methods should use the same option for consistency. It probably makes sense to keep "rle" as TGA format doesn't support other compression methods, but "compression" may be more consistent with BMP and TIFF plugins. Neither of the options is documented, so there is no danger of breaking backward compatibility.

Also, it's not very clear whether `save()`  method should "inherit" info like TIFF and PNG plugins do:

https://github.com/python-pillow/Pillow/blob/4407cb65079a7d1150277e3b9a144996f56357c9/src/PIL/TiffImagePlugin.py#L1399-L1400

Currently, TGA plugin only inherits "orientation" but doesn't allow to specify it as a keyword to `save()`, and "id_section" is ignored altogether.
diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py
index 226b899dc..77695f2d1 100644
--- a/Tests/test_file_tga.py
+++ b/Tests/test_file_tga.py
@@ -53,10 +53,10 @@ class TestFileTga(PillowTestCase):
                     # Generate a new test name every time so the
                     # test will not fail with permission error
                     # on Windows.
-                    test_file = self.tempfile("temp.tga")
+                    out = self.tempfile("temp.tga")
 
-                    original_im.save(test_file, rle=rle)
-                    saved_im = Image.open(test_file)
+                    original_im.save(out, rle=rle)
+                    saved_im = Image.open(out)
                     if rle:
                         self.assertEqual(
                             saved_im.info["compression"],
@@ -95,34 +95,93 @@ class TestFileTga(PillowTestCase):
         test_file = "Tests/images/tga_id_field.tga"
         im = Image.open(test_file)
 
-        test_file = self.tempfile("temp.tga")
+        out = self.tempfile("temp.tga")
 
         # Save
-        im.save(test_file)
-        test_im = Image.open(test_file)
+        im.save(out)
+        test_im = Image.open(out)
         self.assertEqual(test_im.size, (100, 100))
+        self.assertEqual(test_im.info["id_section"], im.info["id_section"])
 
         # RGBA save
-        im.convert("RGBA").save(test_file)
-        test_im = Image.open(test_file)
+        im.convert("RGBA").save(out)
+        test_im = Image.open(out)
         self.assertEqual(test_im.size, (100, 100))
 
+    def test_save_id_section(self):
+        test_file = "Tests/images/rgb32rle.tga"
+        im = Image.open(test_file)
+
+        out = self.tempfile("temp.tga")
+
+        # Check there is no id section
+        im.save(out)
+        test_im = Image.open(out)
+        self.assertNotIn("id_section", test_im.info)
+
+        # Save with custom id section
+        im.save(out, id_section=b"Test content")
+        test_im = Image.open(out)
+        self.assertEqual(test_im.info["id_section"], b"Test content")
+
+        # Save with custom id section greater than 255 characters
+        id_section = b"Test content" * 25
+        self.assert_warning(UserWarning,
+                            lambda: im.save(out, id_section=id_section))
+        test_im = Image.open(out)
+        self.assertEqual(test_im.info["id_section"], id_section[:255])
+
+        test_file = "Tests/images/tga_id_field.tga"
+        im = Image.open(test_file)
+
+        # Save with no id section
+        im.save(out, id_section="")
+        test_im = Image.open(out)
+        self.assertNotIn("id_section", test_im.info)
+
+    def test_save_orientation(self):
+        test_file = "Tests/images/rgb32rle.tga"
+        im = Image.open(test_file)
+        self.assertEqual(im.info["orientation"], -1)
+
+        out = self.tempfile("temp.tga")
+
+        im.save(out, orientation=1)
+        test_im = Image.open(out)
+        self.assertEqual(test_im.info["orientation"], 1)
+
     def test_save_rle(self):
         test_file = "Tests/images/rgb32rle.tga"
         im = Image.open(test_file)
+        self.assertEqual(im.info["compression"], "tga_rle")
 
-        test_file = self.tempfile("temp.tga")
+        out = self.tempfile("temp.tga")
 
         # Save
-        im.save(test_file)
-        test_im = Image.open(test_file)
+        im.save(out)
+        test_im = Image.open(out)
         self.assertEqual(test_im.size, (199, 199))
+        self.assertEqual(test_im.info["compression"], "tga_rle")
+
+        # Save without compression
+        im.save(out, compression=None)
+        test_im = Image.open(out)
+        self.assertNotIn("compression", test_im.info)
 
         # RGBA save
-        im.convert("RGBA").save(test_file)
-        test_im = Image.open(test_file)
+        im.convert("RGBA").save(out)
+        test_im = Image.open(out)
         self.assertEqual(test_im.size, (199, 199))
 
+        test_file = "Tests/images/tga_id_field.tga"
+        im = Image.open(test_file)
+        self.assertNotIn("compression", im.info)
+
+        # Save with compression
+        im.save(out, compression="tga_rle")
+        test_im = Image.open(out)
+        self.assertEqual(test_im.info["compression"], "tga_rle")
+
     def test_save_l_transparency(self):
         # There are 559 transparent pixels in la.tga.
         num_transparent = 559
@@ -133,10 +192,10 @@ class TestFileTga(PillowTestCase):
         self.assertEqual(
             im.getchannel("A").getcolors()[0][0], num_transparent)
 
-        test_file = self.tempfile("temp.tga")
-        im.save(test_file)
+        out = self.tempfile("temp.tga")
+        im.save(out)
 
-        test_im = Image.open(test_file)
+        test_im = Image.open(out)
         self.assertEqual(test_im.mode, "LA")
         self.assertEqual(
             test_im.getchannel("A").getcolors()[0][0], num_transparent)

pip install -e .[dev]
parse_log_pytest
requirements.txt
apt-get update apt-get install -y gcc libjpeg-dev zlib1g-dev libtiff5-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev libharfbuzz-dev libfribidi-dev libxcb1-dev
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
babel==2.17.0
blessed==1.20.0
build==1.2.2.post1
certifi==2025.1.31
charset-normalizer==3.4.1
check-manifest==0.50
cov-core==1.15.0
coverage==7.8.0
coveralls==4.0.1
docopt==0.6.2
docutils==0.21.2
exceptiongroup==1.2.2
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
jarn.viewdoc==2.7
Jinja2==3.1.6
MarkupSafe==3.0.2
olefile==0.47
packaging==24.2
-e git+https://github.com/python-pillow/Pillow.git@41954f244705b247667f1ea228e932ca6390bcd6#egg=Pillow
pluggy==1.5.0
pycodestyle==2.13.0
pyflakes==3.3.1
Pygments==2.19.1
pyproject_hooks==1.2.0
pyroma==4.2
pytest==8.3.5
pytest-cov==6.0.0
pytz==2025.2
requests==2.32.3
six==1.17.0
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-rtd-theme==3.0.2
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli==2.2.1
trove-classifiers==2025.3.19.19
urllib3==2.3.0
wcwidth==0.2.13
zipp==3.21.0

name: Pillow
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - babel==2.17.0
      - blessed==1.20.0
      - build==1.2.2.post1
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - check-manifest==0.50
      - cov-core==1.15.0
      - coverage==7.8.0
      - coveralls==4.0.1
      - docopt==0.6.2
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jarn-viewdoc==2.7
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - olefile==0.47
      - packaging==24.2
      - pluggy==1.5.0
      - pycodestyle==2.13.0
      - pyflakes==3.3.1
      - pygments==2.19.1
      - pyproject-hooks==1.2.0
      - pyroma==4.2
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - pytz==2025.2
      - requests==2.32.3
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - trove-classifiers==2025.3.19.19
      - urllib3==2.3.0
      - wcwidth==0.2.13
      - zipp==3.21.0
prefix: /opt/conda/envs/Pillow

Tests/test_file_tga.py::TestFileTga::test_save Tests/test_file_tga.py::TestFileTga::test_save_id_section Tests/test_file_tga.py::TestFileTga::test_save_l_transparency Tests/test_file_tga.py::TestFileTga::test_save_orientation Tests/test_file_tga.py::TestFileTga::test_save_rle
Tests/test_file_tga.py::TestFileTga::test_id_field Tests/test_file_tga.py::TestFileTga::test_id_field_rle Tests/test_file_tga.py::TestFileTga::test_sanity
src/PIL/TgaImagePlugin.py
src/PIL/TgaImagePlugin.py