diff --git a/Tests/check_j2k_overflow.py b/Tests/check_j2k_overflow.py
index dbdd5a4f5..58566c4b2 100644
--- a/Tests/check_j2k_overflow.py
+++ b/Tests/check_j2k_overflow.py
@@ -9,6 +9,6 @@ from PIL import Image
 
 def test_j2k_overflow(tmp_path: Path) -> None:
     im = Image.new("RGBA", (1024, 131584))
-    target = str(tmp_path / "temp.jpc")
+    target = tmp_path / "temp.jpc"
     with pytest.raises(OSError):
         im.save(target)
diff --git a/Tests/check_large_memory.py b/Tests/check_large_memory.py
index a9ce79e57..c9feda3b1 100644
--- a/Tests/check_large_memory.py
+++ b/Tests/check_large_memory.py
@@ -32,7 +32,7 @@ pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit sy
 
 
 def _write_png(tmp_path: Path, xdim: int, ydim: int) -> None:
-    f = str(tmp_path / "temp.png")
+    f = tmp_path / "temp.png"
     im = Image.new("L", (xdim, ydim), 0)
     im.save(f)
 
diff --git a/Tests/check_large_memory_numpy.py b/Tests/check_large_memory_numpy.py
index f4ca8d0aa..458b0ab72 100644
--- a/Tests/check_large_memory_numpy.py
+++ b/Tests/check_large_memory_numpy.py
@@ -28,7 +28,7 @@ pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit sy
 def _write_png(tmp_path: Path, xdim: int, ydim: int) -> None:
     dtype = np.uint8
     a = np.zeros((xdim, ydim), dtype=dtype)
-    f = str(tmp_path / "temp.png")
+    f = tmp_path / "temp.png"
     im = Image.fromarray(a, "L")
     im.save(f)
 
diff --git a/Tests/helper.py b/Tests/helper.py
index f55d2ca17..8a54ca242 100644
--- a/Tests/helper.py
+++ b/Tests/helper.py
@@ -13,6 +13,7 @@ import tempfile
 from collections.abc import Sequence
 from functools import lru_cache
 from io import BytesIO
+from pathlib import Path
 from typing import Any, Callable
 
 import pytest
@@ -95,7 +96,10 @@ def assert_image_equal(a: Image.Image, b: Image.Image, msg: str | None = None) -
 
 
 def assert_image_equal_tofile(
-    a: Image.Image, filename: str, msg: str | None = None, mode: str | None = None
+    a: Image.Image,
+    filename: str | Path,
+    msg: str | None = None,
+    mode: str | None = None,
 ) -> None:
     img: Image.Image
     with Image.open(filename) as img:
@@ -137,7 +141,7 @@ def assert_image_similar(
 
 def assert_image_similar_tofile(
     a: Image.Image,
-    filename: str,
+    filename: str | Path,
     epsilon: float,
     msg: str | None = None,
 ) -> None:
diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py
index 1f5add7b0..761bf1589 100644
--- a/Tests/test_file_apng.py
+++ b/Tests/test_file_apng.py
@@ -383,7 +383,7 @@ def test_apng_sequence_errors(test_file: str) -> None:
 
 def test_apng_save(tmp_path: Path) -> None:
     with Image.open("Tests/images/apng/single_frame.png") as im:
-        test_file = str(tmp_path / "temp.png")
+        test_file = tmp_path / "temp.png"
         im.save(test_file, save_all=True)
 
     with Image.open(test_file) as im:
@@ -417,7 +417,7 @@ def test_apng_save(tmp_path: Path) -> None:
 
 
 def test_apng_save_alpha(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
 
     im = Image.new("RGBA", (1, 1), (255, 0, 0, 255))
     im2 = Image.new("RGBA", (1, 1), (255, 0, 0, 127))
@@ -435,7 +435,7 @@ def test_apng_save_split_fdat(tmp_path: Path) -> None:
     # frames with image data spanning multiple fdAT chunks (in this case
     # both the default image and first animation frame will span multiple
     # data chunks)
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
     with Image.open("Tests/images/old-style-jpeg-compression.png") as im:
         frames = [im.copy(), Image.new("RGBA", im.size, (255, 0, 0, 255))]
         im.save(
@@ -451,7 +451,7 @@ def test_apng_save_split_fdat(tmp_path: Path) -> None:
 
 
 def test_apng_save_duration_loop(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
     with Image.open("Tests/images/apng/delay.png") as im:
         frames = []
         durations = []
@@ -517,7 +517,7 @@ def test_apng_save_duration_loop(tmp_path: Path) -> None:
 
 
 def test_apng_save_disposal(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
     size = (128, 64)
     red = Image.new("RGBA", size, (255, 0, 0, 255))
     green = Image.new("RGBA", size, (0, 255, 0, 255))
@@ -618,7 +618,7 @@ def test_apng_save_disposal(tmp_path: Path) -> None:
 
 
 def test_apng_save_disposal_previous(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
     size = (128, 64)
     blue = Image.new("RGBA", size, (0, 0, 255, 255))
     red = Image.new("RGBA", size, (255, 0, 0, 255))
@@ -640,7 +640,7 @@ def test_apng_save_disposal_previous(tmp_path: Path) -> None:
 
 
 def test_apng_save_blend(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
     size = (128, 64)
     red = Image.new("RGBA", size, (255, 0, 0, 255))
     green = Image.new("RGBA", size, (0, 255, 0, 255))
@@ -708,7 +708,7 @@ def test_apng_save_blend(tmp_path: Path) -> None:
 
 
 def test_apng_save_size(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
 
     im = Image.new("L", (100, 100))
     im.save(test_file, save_all=True, append_images=[Image.new("L", (200, 200))])
@@ -732,7 +732,7 @@ def test_seek_after_close() -> None:
 def test_different_modes_in_later_frames(
     mode: str, default_image: bool, duplicate: bool, tmp_path: Path
 ) -> None:
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
 
     im = Image.new("L", (1, 1))
     im.save(
@@ -746,7 +746,7 @@ def test_different_modes_in_later_frames(
 
 
 def test_different_durations(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.png")
+    test_file = tmp_path / "temp.png"
 
     with Image.open("Tests/images/apng/different_durations.png") as im:
         for _ in range(3):
diff --git a/Tests/test_file_blp.py b/Tests/test_file_blp.py
index 9f2de8f98..9f50df22d 100644
--- a/Tests/test_file_blp.py
+++ b/Tests/test_file_blp.py
@@ -46,7 +46,7 @@ def test_invalid_file() -> None:
 
 
 def test_save(tmp_path: Path) -> None:
-    f = str(tmp_path / "temp.blp")
+    f = tmp_path / "temp.blp"
 
     for version in ("BLP1", "BLP2"):
         im = hopper("P")
@@ -56,7 +56,7 @@ def test_save(tmp_path: Path) -> None:
             assert_image_equal(im.convert("RGB"), reloaded)
 
         with Image.open("Tests/images/transparent.png") as im:
-            f = str(tmp_path / "temp.blp")
+            f = tmp_path / "temp.blp"
             im.convert("P").save(f, blp_version=version)
 
             with Image.open(f) as reloaded:
diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py
index 4aafd5eb8..39046c281 100644
--- a/Tests/test_file_bmp.py
+++ b/Tests/test_file_bmp.py
@@ -17,7 +17,7 @@ from .helper import (
 
 def test_sanity(tmp_path: Path) -> None:
     def roundtrip(im: Image.Image) -> None:
-        outfile = str(tmp_path / "temp.bmp")
+        outfile = tmp_path / "temp.bmp"
 
         im.save(outfile, "BMP")
 
@@ -66,7 +66,7 @@ def test_small_palette(tmp_path: Path) -> None:
     colors = [0, 0, 0, 125, 125, 125, 255, 255, 255]
     im.putpalette(colors)
 
-    out = str(tmp_path / "temp.bmp")
+    out = tmp_path / "temp.bmp"
     im.save(out)
 
     with Image.open(out) as reloaded:
@@ -74,7 +74,7 @@ def test_small_palette(tmp_path: Path) -> None:
 
 
 def test_save_too_large(tmp_path: Path) -> None:
-    outfile = str(tmp_path / "temp.bmp")
+    outfile = tmp_path / "temp.bmp"
     with Image.new("RGB", (1, 1)) as im:
         im._size = (37838, 37838)
         with pytest.raises(ValueError):
@@ -96,7 +96,7 @@ def test_dpi() -> None:
 def test_save_bmp_with_dpi(tmp_path: Path) -> None:
     # Test for #1301
     # Arrange
-    outfile = str(tmp_path / "temp.jpg")
+    outfile = tmp_path / "temp.jpg"
     with Image.open("Tests/images/hopper.bmp") as im:
         assert im.info["dpi"] == (95.98654816726399, 95.98654816726399)
 
@@ -112,7 +112,7 @@ def test_save_bmp_with_dpi(tmp_path: Path) -> None:
 
 
 def test_save_float_dpi(tmp_path: Path) -> None:
-    outfile = str(tmp_path / "temp.bmp")
+    outfile = tmp_path / "temp.bmp"
     with Image.open("Tests/images/hopper.bmp") as im:
         im.save(outfile, dpi=(72.21216100543306, 72.21216100543306))
         with Image.open(outfile) as reloaded:
@@ -152,7 +152,7 @@ def test_dib_header_size(header_size: int, path: str) -> None:
 
 
 def test_save_dib(tmp_path: Path) -> None:
-    outfile = str(tmp_path / "temp.dib")
+    outfile = tmp_path / "temp.dib"
 
     with Image.open("Tests/images/clipboard.dib") as im:
         im.save(outfile)
diff --git a/Tests/test_file_bufrstub.py b/Tests/test_file_bufrstub.py
index fa0d33927..8c6bb1a69 100644
--- a/Tests/test_file_bufrstub.py
+++ b/Tests/test_file_bufrstub.py
@@ -43,7 +43,7 @@ def test_load() -> None:
 def test_save(tmp_path: Path) -> None:
     # Arrange
     im = hopper()
-    tmpfile = str(tmp_path / "temp.bufr")
+    tmpfile = tmp_path / "temp.bufr"
 
     # Act / Assert: stub cannot save without an implemented handler
     with pytest.raises(OSError):
@@ -80,7 +80,7 @@ def test_handler(tmp_path: Path) -> None:
         im.load()
         assert handler.is_loaded()
 
-        temp_file = str(tmp_path / "temp.bufr")
+        temp_file = tmp_path / "temp.bufr"
         im.save(temp_file)
         assert handler.saved
 
diff --git a/Tests/test_file_dds.py b/Tests/test_file_dds.py
index d81b3f8f3..3a1aab00c 100644
--- a/Tests/test_file_dds.py
+++ b/Tests/test_file_dds.py
@@ -9,7 +9,13 @@ import pytest
 
 from PIL import DdsImagePlugin, Image
 
-from .helper import assert_image_equal, assert_image_equal_tofile, hopper
+from .helper import (
+    assert_image_equal,
+    assert_image_equal_tofile,
+    assert_image_similar,
+    assert_image_similar_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"
@@ -110,6 +116,32 @@ def test_sanity_ati1_bc4u(image_path: str) -> None:
         assert_image_equal_tofile(im, TEST_FILE_ATI1.replace(".dds", ".png"))
 
 
+def test_dx10_bc2(tmp_path: Path) -> None:
+    out = tmp_path / "temp.dds"
+    with Image.open(TEST_FILE_DXT3) as im:
+        im.save(out, pixel_format="BC2")
+
+    with Image.open(out) as reloaded:
+        assert reloaded.format == "DDS"
+        assert reloaded.mode == "RGBA"
+        assert reloaded.size == (256, 256)
+
+        assert_image_similar(im, reloaded, 3.81)
+
+
+def test_dx10_bc3(tmp_path: Path) -> None:
+    out = tmp_path / "temp.dds"
+    with Image.open(TEST_FILE_DXT5) as im:
+        im.save(out, pixel_format="BC3")
+
+    with Image.open(out) as reloaded:
+        assert reloaded.format == "DDS"
+        assert reloaded.mode == "RGBA"
+        assert reloaded.size == (256, 256)
+
+        assert_image_similar(im, reloaded, 3.69)
+
+
 @pytest.mark.parametrize(
     "image_path",
     (
@@ -369,9 +401,9 @@ def test_not_implemented(test_file: str) -> None:
 
 
 def test_save_unsupported_mode(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.dds")
+    out = tmp_path / "temp.dds"
     im = hopper("HSV")
-    with pytest.raises(OSError):
+    with pytest.raises(OSError, match="cannot write mode HSV as DDS"):
         im.save(out)
 
 
@@ -385,10 +417,98 @@ def test_save_unsupported_mode(tmp_path: Path) -> None:
     ],
 )
 def test_save(mode: str, test_file: str, tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.dds")
+    out = 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)
+        assert_image_equal_tofile(im, out)
+
+
+def test_save_unsupported_pixel_format(tmp_path: Path) -> None:
+    out = tmp_path / "temp.dds"
+    im = hopper()
+    with pytest.raises(OSError, match="cannot write pixel format UNKNOWN"):
+        im.save(out, pixel_format="UNKNOWN")
+
+
+def test_save_dxt1(tmp_path: Path) -> None:
+    # RGB
+    out = tmp_path / "temp.dds"
+    with Image.open(TEST_FILE_DXT1) as im:
+        im.convert("RGB").save(out, pixel_format="DXT1")
+    assert_image_similar_tofile(im, out, 1.84)
+
+    # RGBA
+    im_alpha = im.copy()
+    im_alpha.putpixel((0, 0), (0, 0, 0, 0))
+    im_alpha.save(out, pixel_format="DXT1")
+    with Image.open(out) as reloaded:
+        assert reloaded.getpixel((0, 0)) == (0, 0, 0, 0)
+
+    # L
+    im_l = im.convert("L")
+    im_l.save(out, pixel_format="DXT1")
+    assert_image_similar_tofile(im_l.convert("RGBA"), out, 6.07)
+
+    # LA
+    im_alpha.convert("LA").save(out, pixel_format="DXT1")
+    with Image.open(out) as reloaded:
+        assert reloaded.getpixel((0, 0)) == (0, 0, 0, 0)
+
+
+def test_save_dxt3(tmp_path: Path) -> None:
+    # RGB
+    out = tmp_path / "temp.dds"
+    with Image.open(TEST_FILE_DXT3) as im:
+        im_rgb = im.convert("RGB")
+    im_rgb.save(out, pixel_format="DXT3")
+    assert_image_similar_tofile(im_rgb.convert("RGBA"), out, 1.26)
+
+    # RGBA
+    im.save(out, pixel_format="DXT3")
+    assert_image_similar_tofile(im, out, 3.81)
+
+    # L
+    im_l = im.convert("L")
+    im_l.save(out, pixel_format="DXT3")
+    assert_image_similar_tofile(im_l.convert("RGBA"), out, 5.89)
+
+    # LA
+    im_la = im.convert("LA")
+    im_la.save(out, pixel_format="DXT3")
+    assert_image_similar_tofile(im_la.convert("RGBA"), out, 8.44)
+
+
+def test_save_dxt5(tmp_path: Path) -> None:
+    # RGB
+    out = tmp_path / "temp.dds"
+    with Image.open(TEST_FILE_DXT1) as im:
+        im.convert("RGB").save(out, pixel_format="DXT5")
+    assert_image_similar_tofile(im, out, 1.84)
+
+    # RGBA
+    with Image.open(TEST_FILE_DXT5) as im_rgba:
+        im_rgba.save(out, pixel_format="DXT5")
+    assert_image_similar_tofile(im_rgba, out, 3.69)
+
+    # L
+    im_l = im.convert("L")
+    im_l.save(out, pixel_format="DXT5")
+    assert_image_similar_tofile(im_l.convert("RGBA"), out, 6.07)
+
+    # LA
+    im_la = im_rgba.convert("LA")
+    im_la.save(out, pixel_format="DXT5")
+    assert_image_similar_tofile(im_la.convert("RGBA"), out, 8.32)
+
+
+def test_save_dx10_bc5(tmp_path: Path) -> None:
+    out = tmp_path / "temp.dds"
+    with Image.open(TEST_FILE_DX10_BC5_TYPELESS) as im:
+        im.save(out, pixel_format="BC5")
+    assert_image_similar_tofile(im, out, 9.56)
+
+    im = hopper("L")
+    with pytest.raises(OSError, match="only RGB mode can be written as BC5"):
+        im.save(out, pixel_format="BC5")
diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py
index 506e36e7d..e406f9472 100644
--- a/Tests/test_file_eps.py
+++ b/Tests/test_file_eps.py
@@ -243,7 +243,7 @@ def test_transparency() -> None:
 def test_file_object(tmp_path: Path) -> None:
     # issue 479
     with Image.open(FILE1) as image1:
-        with open(str(tmp_path / "temp.eps"), "wb") as fh:
+        with open(tmp_path / "temp.eps", "wb") as fh:
             image1.save(fh, "EPS")
 
 
@@ -278,7 +278,7 @@ def test_1(filename: str) -> None:
 
 def test_image_mode_not_supported(tmp_path: Path) -> None:
     im = hopper("RGBA")
-    tmpfile = str(tmp_path / "temp.eps")
+    tmpfile = tmp_path / "temp.eps"
     with pytest.raises(ValueError):
         im.save(tmpfile)
 
diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py
index f64017118..4cf087951 100644
--- a/Tests/test_file_gif.py
+++ b/Tests/test_file_gif.py
@@ -229,7 +229,7 @@ def test_optimize_if_palette_can_be_reduced_by_half() -> None:
 
 
 def test_full_palette_second_frame(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("P", (1, 256))
 
     full_palette_im = Image.new("P", (1, 256))
@@ -250,7 +250,7 @@ def test_full_palette_second_frame(tmp_path: Path) -> None:
 
 
 def test_roundtrip(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = hopper()
     im.save(out)
     with Image.open(out) as reread:
@@ -259,7 +259,7 @@ def test_roundtrip(tmp_path: Path) -> None:
 
 def test_roundtrip2(tmp_path: Path) -> None:
     # see https://github.com/python-pillow/Pillow/issues/403
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     with Image.open(TEST_GIF) as im:
         im2 = im.copy()
         im2.save(out)
@@ -269,7 +269,7 @@ def test_roundtrip2(tmp_path: Path) -> None:
 
 def test_roundtrip_save_all(tmp_path: Path) -> None:
     # Single frame image
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = hopper()
     im.save(out, save_all=True)
     with Image.open(out) as reread:
@@ -277,7 +277,7 @@ def test_roundtrip_save_all(tmp_path: Path) -> None:
 
     # Multiframe image
     with Image.open("Tests/images/dispose_bgnd.gif") as im:
-        out = str(tmp_path / "temp.gif")
+        out = tmp_path / "temp.gif"
         im.save(out, save_all=True)
 
     with Image.open(out) as reread:
@@ -286,7 +286,7 @@ def test_roundtrip_save_all(tmp_path: Path) -> None:
 
 
 def test_roundtrip_save_all_1(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("1", (1, 1))
     im2 = Image.new("1", (1, 1), 1)
     im.save(out, save_all=True, append_images=[im2])
@@ -332,7 +332,7 @@ def test_headers_saving_for_animated_gifs(tmp_path: Path) -> None:
     with Image.open("Tests/images/dispose_bgnd.gif") as im:
         info = im.info.copy()
 
-        out = str(tmp_path / "temp.gif")
+        out = tmp_path / "temp.gif"
         im.save(out, save_all=True)
     with Image.open(out) as reread:
         for header in important_headers:
@@ -348,7 +348,7 @@ def test_palette_handling(tmp_path: Path) -> None:
         im = im.resize((100, 100), Image.Resampling.LANCZOS)
         im2 = im.convert("P", palette=Image.Palette.ADAPTIVE, colors=256)
 
-        f = str(tmp_path / "temp.gif")
+        f = tmp_path / "temp.gif"
         im2.save(f, optimize=True)
 
     with Image.open(f) as reloaded:
@@ -359,7 +359,7 @@ def test_palette_434(tmp_path: Path) -> None:
     # see https://github.com/python-pillow/Pillow/issues/434
 
     def roundtrip(im: Image.Image, **kwargs: bool) -> Image.Image:
-        out = str(tmp_path / "temp.gif")
+        out = tmp_path / "temp.gif"
         im.copy().save(out, "GIF", **kwargs)
         reloaded = Image.open(out)
 
@@ -616,7 +616,7 @@ def test_previous_frame_loaded() -> None:
 
 
 def test_save_dispose(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im_list = [
         Image.new("L", (100, 100), "#000"),
         Image.new("L", (100, 100), "#111"),
@@ -646,7 +646,7 @@ def test_save_dispose(tmp_path: Path) -> None:
 
 
 def test_dispose2_palette(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     # Four colors: white, gray, black, red
     circles = [(255, 255, 255), (153, 153, 153), (0, 0, 0), (255, 0, 0)]
@@ -680,7 +680,7 @@ def test_dispose2_palette(tmp_path: Path) -> None:
 
 
 def test_dispose2_diff(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     # 4 frames: red/blue, red/red, blue/blue, red/blue
     circles = [
@@ -722,7 +722,7 @@ def test_dispose2_diff(tmp_path: Path) -> None:
 
 
 def test_dispose2_background(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im_list = []
 
@@ -748,7 +748,7 @@ def test_dispose2_background(tmp_path: Path) -> None:
 
 
 def test_dispose2_background_frame(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im_list = [Image.new("RGBA", (1, 20))]
 
@@ -767,7 +767,7 @@ def test_dispose2_background_frame(tmp_path: Path) -> None:
 
 
 def test_dispose2_previous_frame(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im = Image.new("P", (100, 100))
     im.info["transparency"] = 0
@@ -786,7 +786,7 @@ def test_dispose2_previous_frame(tmp_path: Path) -> None:
 
 
 def test_dispose2_without_transparency(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im = Image.new("P", (100, 100))
 
@@ -801,7 +801,7 @@ def test_dispose2_without_transparency(tmp_path: Path) -> None:
 
 
 def test_transparency_in_second_frame(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     with Image.open("Tests/images/different_transparency.gif") as im:
         assert im.info["transparency"] == 0
 
@@ -831,7 +831,7 @@ def test_no_transparency_in_second_frame() -> None:
 
 
 def test_remapped_transparency(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im = Image.new("P", (1, 2))
     im2 = im.copy()
@@ -849,7 +849,7 @@ def test_remapped_transparency(tmp_path: Path) -> None:
 def test_duration(tmp_path: Path) -> None:
     duration = 1000
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("L", (100, 100), "#000")
 
     # Check that the argument has priority over the info settings
@@ -863,7 +863,7 @@ def test_duration(tmp_path: Path) -> None:
 def test_multiple_duration(tmp_path: Path) -> None:
     duration_list = [1000, 2000, 3000]
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im_list = [
         Image.new("L", (100, 100), "#000"),
         Image.new("L", (100, 100), "#111"),
@@ -898,7 +898,7 @@ def test_multiple_duration(tmp_path: Path) -> None:
 def test_roundtrip_info_duration(tmp_path: Path) -> None:
     duration_list = [100, 500, 500]
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     with Image.open("Tests/images/transparent_dispose.gif") as im:
         assert [
             frame.info["duration"] for frame in ImageSequence.Iterator(im)
@@ -913,7 +913,7 @@ def test_roundtrip_info_duration(tmp_path: Path) -> None:
 
 
 def test_roundtrip_info_duration_combined(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     with Image.open("Tests/images/duplicate_frame.gif") as im:
         assert [frame.info["duration"] for frame in ImageSequence.Iterator(im)] == [
             1000,
@@ -931,7 +931,7 @@ def test_roundtrip_info_duration_combined(tmp_path: Path) -> None:
 def test_identical_frames(tmp_path: Path) -> None:
     duration_list = [1000, 1500, 2000, 4000]
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im_list = [
         Image.new("L", (100, 100), "#000"),
         Image.new("L", (100, 100), "#000"),
@@ -966,7 +966,7 @@ def test_identical_frames(tmp_path: Path) -> None:
 def test_identical_frames_to_single_frame(
     duration: int | list[int], tmp_path: Path
 ) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im_list = [
         Image.new("L", (100, 100), "#000"),
         Image.new("L", (100, 100), "#000"),
@@ -985,7 +985,7 @@ def test_identical_frames_to_single_frame(
 
 
 def test_loop_none(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("L", (100, 100), "#000")
     im.save(out, loop=None)
     with Image.open(out) as reread:
@@ -995,7 +995,7 @@ def test_loop_none(tmp_path: Path) -> None:
 def test_number_of_loops(tmp_path: Path) -> None:
     number_of_loops = 2
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("L", (100, 100), "#000")
     im.save(out, loop=number_of_loops)
     with Image.open(out) as reread:
@@ -1011,7 +1011,7 @@ def test_number_of_loops(tmp_path: Path) -> None:
 
 
 def test_background(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("L", (100, 100), "#000")
     im.info["background"] = 1
     im.save(out)
@@ -1020,7 +1020,7 @@ def test_background(tmp_path: Path) -> None:
 
 
 def test_webp_background(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     # Test opaque WebP background
     if features.check("webp"):
@@ -1039,7 +1039,7 @@ def test_comment(tmp_path: Path) -> None:
     with Image.open(TEST_GIF) as im:
         assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0"
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("L", (100, 100), "#000")
     im.info["comment"] = b"Test comment text"
     im.save(out)
@@ -1056,7 +1056,7 @@ def test_comment(tmp_path: Path) -> None:
 
 
 def test_comment_over_255(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("L", (100, 100), "#000")
     comment = b"Test comment text"
     while len(comment) < 256:
@@ -1082,7 +1082,7 @@ def test_read_multiple_comment_blocks() -> None:
 
 
 def test_empty_string_comment(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     with Image.open("Tests/images/chi.gif") as im:
         assert "comment" in im.info
 
@@ -1116,7 +1116,7 @@ def test_retain_comment_in_subsequent_frames(tmp_path: Path) -> None:
         assert "comment" not in im.info
 
     # Test that a saved image keeps the comment
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     with Image.open("Tests/images/dispose_prev.gif") as im:
         im.save(out, save_all=True, comment="Test")
 
@@ -1126,7 +1126,7 @@ def test_retain_comment_in_subsequent_frames(tmp_path: Path) -> None:
 
 
 def test_version(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     def assert_version_after_save(im: Image.Image, version: bytes) -> None:
         im.save(out)
@@ -1156,7 +1156,7 @@ def test_version(tmp_path: Path) -> None:
 
 
 def test_append_images(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     # Test appending single frame images
     im = Image.new("RGB", (100, 100), "#f00")
@@ -1188,7 +1188,7 @@ def test_append_images(tmp_path: Path) -> None:
 
 
 def test_append_different_size_image(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im = Image.new("RGB", (100, 100))
     bigger_im = Image.new("RGB", (200, 200), "#f00")
@@ -1215,7 +1215,7 @@ def test_transparent_optimize(tmp_path: Path) -> None:
     im.frombytes(data)
     im.putpalette(palette)
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im.save(out, transparency=im.getpixel((252, 0)))
 
     with Image.open(out) as reloaded:
@@ -1223,7 +1223,7 @@ def test_transparent_optimize(tmp_path: Path) -> None:
 
 
 def test_removed_transparency(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im = Image.new("RGB", (256, 1))
 
     for x in range(256):
@@ -1238,7 +1238,7 @@ def test_removed_transparency(tmp_path: Path) -> None:
 
 
 def test_rgb_transparency(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     # Single frame
     im = Image.new("RGB", (1, 1))
@@ -1260,7 +1260,7 @@ def test_rgb_transparency(tmp_path: Path) -> None:
 
 
 def test_rgba_transparency(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im = hopper("P")
     im.save(out, save_all=True, append_images=[Image.new("RGBA", im.size)])
@@ -1270,14 +1270,14 @@ def test_rgba_transparency(tmp_path: Path) -> None:
         assert_image_equal(hopper("P").convert("RGB"), reloaded)
 
 
-def test_background_outside_palettte(tmp_path: Path) -> None:
+def test_background_outside_palettte() -> None:
     with Image.open("Tests/images/background_outside_palette.gif") as im:
         im.seek(1)
         assert im.info["background"] == 255
 
 
 def test_bbox(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im = Image.new("RGB", (100, 100), "#fff")
     ims = [Image.new("RGB", (100, 100), "#000")]
@@ -1289,7 +1289,7 @@ def test_bbox(tmp_path: Path) -> None:
 
 
 def test_bbox_alpha(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im = Image.new("RGBA", (1, 2), (255, 0, 0, 255))
     im.putpixel((0, 1), (255, 0, 0, 0))
@@ -1309,7 +1309,7 @@ def test_palette_save_L(tmp_path: Path) -> None:
     palette = im.getpalette()
     assert palette is not None
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im_l.save(out, palette=bytes(palette))
 
     with Image.open(out) as reloaded:
@@ -1320,7 +1320,7 @@ def test_palette_save_P(tmp_path: Path) -> None:
     im = Image.new("P", (1, 2))
     im.putpixel((0, 1), 1)
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im.save(out, palette=bytes((1, 2, 3, 4, 5, 6)))
 
     with Image.open(out) as reloaded:
@@ -1336,7 +1336,7 @@ def test_palette_save_duplicate_entries(tmp_path: Path) -> None:
 
     im.putpalette((0, 0, 0, 0, 0, 0))
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im.save(out, palette=[0, 0, 0, 0, 0, 0, 1, 1, 1])
 
     with Image.open(out) as reloaded:
@@ -1351,7 +1351,7 @@ def test_palette_save_all_P(tmp_path: Path) -> None:
         frame.putpalette(color)
         frames.append(frame)
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     frames[0].save(
         out, save_all=True, palette=[255, 0, 0, 0, 255, 0], append_images=frames[1:]
     )
@@ -1376,7 +1376,7 @@ def test_palette_save_ImagePalette(tmp_path: Path) -> None:
     im = hopper("P")
     palette = ImagePalette.ImagePalette("RGB", list(range(256))[::-1] * 3)
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im.save(out, palette=palette)
 
     with Image.open(out) as reloaded:
@@ -1389,7 +1389,7 @@ def test_save_I(tmp_path: Path) -> None:
 
     im = hopper("I")
 
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     im.save(out)
 
     with Image.open(out) as reloaded:
@@ -1476,7 +1476,7 @@ def test_missing_background() -> None:
 
 
 def test_saving_rgba(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
     with Image.open("Tests/images/transparent.png") as im:
         im.save(out)
 
@@ -1491,7 +1491,7 @@ def test_saving_rgba(tmp_path: Path) -> None:
 
 @pytest.mark.parametrize("params", ({}, {"disposal": 2, "optimize": False}))
 def test_p_rgba(tmp_path: Path, params: dict[str, Any]) -> None:
-    out = str(tmp_path / "temp.gif")
+    out = tmp_path / "temp.gif"
 
     im1 = Image.new("P", (100, 100))
     d = ImageDraw.Draw(im1)
diff --git a/Tests/test_file_gimppalette.py b/Tests/test_file_gimppalette.py
index e8d5f1705..ff9cc91c5 100644
--- a/Tests/test_file_gimppalette.py
+++ b/Tests/test_file_gimppalette.py
@@ -32,3 +32,4 @@ def test_get_palette() -> None:
 
     # Assert
     assert mode == "RGB"
+    assert len(palette) / 3 == 8
diff --git a/Tests/test_file_gribstub.py b/Tests/test_file_gribstub.py
index feb1a77f2..05925d502 100644
--- a/Tests/test_file_gribstub.py
+++ b/Tests/test_file_gribstub.py
@@ -43,7 +43,7 @@ def test_load() -> None:
 def test_save(tmp_path: Path) -> None:
     # Arrange
     im = hopper()
-    tmpfile = str(tmp_path / "temp.grib")
+    tmpfile = tmp_path / "temp.grib"
 
     # Act / Assert: stub cannot save without an implemented handler
     with pytest.raises(OSError):
@@ -80,7 +80,7 @@ def test_handler(tmp_path: Path) -> None:
         im.load()
         assert handler.is_loaded()
 
-        temp_file = str(tmp_path / "temp.grib")
+        temp_file = tmp_path / "temp.grib"
         im.save(temp_file)
         assert handler.saved
 
diff --git a/Tests/test_file_hdf5stub.py b/Tests/test_file_hdf5stub.py
index c58dce7ee..aae54affa 100644
--- a/Tests/test_file_hdf5stub.py
+++ b/Tests/test_file_hdf5stub.py
@@ -82,7 +82,7 @@ def test_handler(tmp_path: Path) -> None:
         im.load()
         assert handler.is_loaded()
 
-        temp_file = str(tmp_path / "temp.h5")
+        temp_file = tmp_path / "temp.h5"
         im.save(temp_file)
         assert handler.saved
 
diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py
index c40daaf9e..2dabfd2f3 100644
--- a/Tests/test_file_icns.py
+++ b/Tests/test_file_icns.py
@@ -43,7 +43,7 @@ def test_load() -> None:
 
 
 def test_save(tmp_path: Path) -> None:
-    temp_file = str(tmp_path / "temp.icns")
+    temp_file = tmp_path / "temp.icns"
 
     with Image.open(TEST_FILE) as im:
         im.save(temp_file)
@@ -60,7 +60,7 @@ def test_save(tmp_path: Path) -> None:
 
 
 def test_save_append_images(tmp_path: Path) -> None:
-    temp_file = str(tmp_path / "temp.icns")
+    temp_file = tmp_path / "temp.icns"
     provided_im = Image.new("RGBA", (32, 32), (255, 0, 0, 128))
 
     with Image.open(TEST_FILE) as im:
diff --git a/Tests/test_file_ico.py b/Tests/test_file_ico.py
index aec39bf91..5d2ace35e 100644
--- a/Tests/test_file_ico.py
+++ b/Tests/test_file_ico.py
@@ -41,7 +41,7 @@ def test_black_and_white() -> None:
 
 
 def test_palette(tmp_path: Path) -> None:
-    temp_file = str(tmp_path / "temp.ico")
+    temp_file = tmp_path / "temp.ico"
 
     im = Image.new("P", (16, 16))
     im.save(temp_file)
@@ -89,7 +89,7 @@ def test_save_to_bytes() -> None:
 
 
 def test_getpixel(tmp_path: Path) -> None:
-    temp_file = str(tmp_path / "temp.ico")
+    temp_file = tmp_path / "temp.ico"
 
     im = hopper()
     im.save(temp_file, "ico", sizes=[(32, 32), (64, 64)])
@@ -103,8 +103,8 @@ def test_getpixel(tmp_path: Path) -> None:
 
 
 def test_no_duplicates(tmp_path: Path) -> None:
-    temp_file = str(tmp_path / "temp.ico")
-    temp_file2 = str(tmp_path / "temp2.ico")
+    temp_file = tmp_path / "temp.ico"
+    temp_file2 = tmp_path / "temp2.ico"
 
     im = hopper()
     sizes = [(32, 32), (64, 64)]
@@ -117,8 +117,8 @@ def test_no_duplicates(tmp_path: Path) -> None:
 
 
 def test_different_bit_depths(tmp_path: Path) -> None:
-    temp_file = str(tmp_path / "temp.ico")
-    temp_file2 = str(tmp_path / "temp2.ico")
+    temp_file = tmp_path / "temp.ico"
+    temp_file2 = tmp_path / "temp2.ico"
 
     im = hopper()
     im.save(temp_file, "ico", bitmap_format="bmp", sizes=[(128, 128)])
@@ -134,8 +134,8 @@ def test_different_bit_depths(tmp_path: Path) -> None:
     assert os.path.getsize(temp_file) != os.path.getsize(temp_file2)
 
     # Test that only matching sizes of different bit depths are saved
-    temp_file3 = str(tmp_path / "temp3.ico")
-    temp_file4 = str(tmp_path / "temp4.ico")
+    temp_file3 = tmp_path / "temp3.ico"
+    temp_file4 = tmp_path / "temp4.ico"
 
     im.save(temp_file3, "ico", bitmap_format="bmp", sizes=[(128, 128)])
     im.save(
@@ -190,7 +190,7 @@ def test_save_256x256(tmp_path: Path) -> None:
     """Issue #2264 https://github.com/python-pillow/Pillow/issues/2264"""
     # Arrange
     with Image.open("Tests/images/hopper_256x256.ico") as im:
-        outfile = str(tmp_path / "temp_saved_hopper_256x256.ico")
+        outfile = tmp_path / "temp_saved_hopper_256x256.ico"
 
         # Act
         im.save(outfile)
@@ -206,7 +206,7 @@ def test_only_save_relevant_sizes(tmp_path: Path) -> None:
     """
     # Arrange
     with Image.open("Tests/images/python.ico") as im:  # 16x16, 32x32, 48x48
-        outfile = str(tmp_path / "temp_saved_python.ico")
+        outfile = tmp_path / "temp_saved_python.ico"
         # Act
         im.save(outfile)
 
@@ -219,7 +219,7 @@ def test_save_append_images(tmp_path: Path) -> None:
     # append_images should be used for scaled down versions of the image
     im = hopper("RGBA")
     provided_im = Image.new("RGBA", (32, 32), (255, 0, 0))
-    outfile = str(tmp_path / "temp_saved_multi_icon.ico")
+    outfile = tmp_path / "temp_saved_multi_icon.ico"
     im.save(outfile, sizes=[(32, 32), (128, 128)], append_images=[provided_im])
 
     with Image.open(outfile) as reread:
@@ -240,7 +240,7 @@ def test_unexpected_size() -> None:
 
 def test_draw_reloaded(tmp_path: Path) -> None:
     with Image.open(TEST_ICO_FILE) as im:
-        outfile = str(tmp_path / "temp_saved_hopper_draw.ico")
+        outfile = tmp_path / "temp_saved_hopper_draw.ico"
 
         draw = ImageDraw.Draw(im)
         draw.line((0, 0) + im.size, "#f00")
diff --git a/Tests/test_file_im.py b/Tests/test_file_im.py
index 8d465970d..55c6b7305 100644
--- a/Tests/test_file_im.py
+++ b/Tests/test_file_im.py
@@ -23,7 +23,7 @@ def test_sanity() -> None:
 
 
 def test_name_limit(tmp_path: Path) -> None:
-    out = str(tmp_path / ("name_limit_test" * 7 + ".im"))
+    out = tmp_path / ("name_limit_test" * 7 + ".im")
     with Image.open(TEST_IM) as im:
         im.save(out)
     assert filecmp.cmp(out, "Tests/images/hopper_long_name.im")
@@ -89,7 +89,7 @@ def test_eoferror() -> None:
 
 @pytest.mark.parametrize("mode", ("RGB", "P", "PA"))
 def test_roundtrip(mode: str, tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.im")
+    out = tmp_path / "temp.im"
     im = hopper(mode)
     im.save(out)
     assert_image_equal_tofile(im, out)
@@ -100,7 +100,7 @@ def test_small_palette(tmp_path: Path) -> None:
     colors = [0, 1, 2]
     im.putpalette(colors)
 
-    out = str(tmp_path / "temp.im")
+    out = tmp_path / "temp.im"
     im.save(out)
 
     with Image.open(out) as reloaded:
@@ -108,7 +108,7 @@ def test_small_palette(tmp_path: Path) -> None:
 
 
 def test_save_unsupported_mode(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.im")
+    out = tmp_path / "temp.im"
     im = hopper("HSV")
     with pytest.raises(ValueError):
         im.save(out)
diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py
index e5deb1c7a..6281e07c2 100644
--- a/Tests/test_file_jpeg.py
+++ b/Tests/test_file_jpeg.py
@@ -83,7 +83,7 @@ class TestFileJpeg:
 
     @pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
     def test_zero(self, size: tuple[int, int], tmp_path: Path) -> None:
-        f = str(tmp_path / "temp.jpg")
+        f = tmp_path / "temp.jpg"
         im = Image.new("RGB", size)
         with pytest.raises(ValueError):
             im.save(f)
@@ -199,7 +199,7 @@ class TestFileJpeg:
             icc_profile = im1.info["icc_profile"]
             assert len(icc_profile) == 3144
             # Roundtrip via physical file.
-            f = str(tmp_path / "temp.jpg")
+            f = tmp_path / "temp.jpg"
             im1.save(f, icc_profile=icc_profile)
         with Image.open(f) as im2:
             assert im2.info.get("icc_profile") == icc_profile
@@ -243,7 +243,7 @@ class TestFileJpeg:
         # Sometimes the meta data on the icc_profile block is bigger than
         # Image.MAXBLOCK or the image size.
         with Image.open("Tests/images/icc_profile_big.jpg") as im:
-            f = str(tmp_path / "temp.jpg")
+            f = tmp_path / "temp.jpg"
             icc_profile = im.info["icc_profile"]
             # Should not raise OSError for image with icc larger than image size.
             im.save(
@@ -255,11 +255,11 @@ class TestFileJpeg:
             )
 
         with Image.open("Tests/images/flower2.jpg") as im:
-            f = str(tmp_path / "temp2.jpg")
+            f = tmp_path / "temp2.jpg"
             im.save(f, progressive=True, quality=94, icc_profile=b" " * 53955)
 
         with Image.open("Tests/images/flower2.jpg") as im:
-            f = str(tmp_path / "temp3.jpg")
+            f = tmp_path / "temp3.jpg"
             im.save(f, progressive=True, quality=94, exif=b" " * 43668)
 
     def test_optimize(self) -> None:
@@ -273,7 +273,7 @@ class TestFileJpeg:
 
     def test_optimize_large_buffer(self, tmp_path: Path) -> None:
         # https://github.com/python-pillow/Pillow/issues/148
-        f = str(tmp_path / "temp.jpg")
+        f = tmp_path / "temp.jpg"
         # this requires ~ 1.5x Image.MAXBLOCK
         im = Image.new("RGB", (4096, 4096), 0xFF3333)
         im.save(f, format="JPEG", optimize=True)
@@ -293,13 +293,13 @@ class TestFileJpeg:
         assert im1_bytes >= im3_bytes
 
     def test_progressive_large_buffer(self, tmp_path: Path) -> None:
-        f = str(tmp_path / "temp.jpg")
+        f = tmp_path / "temp.jpg"
         # this requires ~ 1.5x Image.MAXBLOCK
         im = Image.new("RGB", (4096, 4096), 0xFF3333)
         im.save(f, format="JPEG", progressive=True)
 
     def test_progressive_large_buffer_highest_quality(self, tmp_path: Path) -> None:
-        f = str(tmp_path / "temp.jpg")
+        f = tmp_path / "temp.jpg"
         im = self.gen_random_image((255, 255))
         # this requires more bytes than pixels in the image
         im.save(f, format="JPEG", progressive=True, quality=100)
@@ -312,7 +312,7 @@ class TestFileJpeg:
 
     def test_large_exif(self, tmp_path: Path) -> None:
         # https://github.com/python-pillow/Pillow/issues/148
-        f = str(tmp_path / "temp.jpg")
+        f = tmp_path / "temp.jpg"
         im = hopper()
         im.save(f, "JPEG", quality=90, exif=b"1" * 65533)
 
@@ -344,7 +344,7 @@ class TestFileJpeg:
             assert exif_data[gps_index] == expected_exif_gps
 
         # Writing
-        f = str(tmp_path / "temp.jpg")
+        f = tmp_path / "temp.jpg"
         exif = Image.Exif()
         exif[gps_index] = expected_exif_gps
         hopper().save(f, exif=exif)
@@ -525,15 +525,15 @@ class TestFileJpeg:
     def test_quality_keep(self, tmp_path: Path) -> None:
         # RGB
         with Image.open("Tests/images/hopper.jpg") as im:
-            f = str(tmp_path / "temp.jpg")
+            f = tmp_path / "temp.jpg"
             im.save(f, quality="keep")
         # Grayscale
         with Image.open("Tests/images/hopper_gray.jpg") as im:
-            f = str(tmp_path / "temp.jpg")
+            f = tmp_path / "temp.jpg"
             im.save(f, quality="keep")
         # CMYK
         with Image.open("Tests/images/pil_sample_cmyk.jpg") as im:
-            f = str(tmp_path / "temp.jpg")
+            f = tmp_path / "temp.jpg"
             im.save(f, quality="keep")
 
     def test_junk_jpeg_header(self) -> None:
@@ -752,7 +752,7 @@ class TestFileJpeg:
 
     def test_MAXBLOCK_scaling(self, tmp_path: Path) -> None:
         im = self.gen_random_image((512, 512))
-        f = str(tmp_path / "temp.jpeg")
+        f = tmp_path / "temp.jpeg"
         im.save(f, quality=100, optimize=True)
 
         with Image.open(f) as reloaded:
@@ -788,7 +788,7 @@ class TestFileJpeg:
 
     def test_save_tiff_with_dpi(self, tmp_path: Path) -> None:
         # Arrange
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         with Image.open("Tests/images/hopper.tif") as im:
             # Act
             im.save(outfile, "JPEG", dpi=im.info["dpi"])
@@ -799,7 +799,7 @@ class TestFileJpeg:
                 assert im.info["dpi"] == reloaded.info["dpi"]
 
     def test_save_dpi_rounding(self, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.jpg")
+        outfile = tmp_path / "temp.jpg"
         with Image.open("Tests/images/hopper.jpg") as im:
             im.save(outfile, dpi=(72.2, 72.2))
 
@@ -885,7 +885,7 @@ class TestFileJpeg:
             exif = im.getexif()
             assert exif[282] == 180
 
-            out = str(tmp_path / "out.jpg")
+            out = tmp_path / "out.jpg"
             with warnings.catch_warnings():
                 warnings.simplefilter("error")
 
@@ -1035,7 +1035,7 @@ class TestFileJpeg:
                 assert im.getxmp() == {"xmpmeta": None}
 
     def test_save_xmp(self, tmp_path: Path) -> None:
-        f = str(tmp_path / "temp.jpg")
+        f = tmp_path / "temp.jpg"
         im = hopper()
         im.save(f, xmp=b"XMP test")
         with Image.open(f) as reloaded:
@@ -1125,7 +1125,7 @@ class TestFileJpeg:
 @skip_unless_feature("jpg")
 class TestFileCloseW32:
     def test_fd_leak(self, tmp_path: Path) -> None:
-        tmpfile = str(tmp_path / "temp.jpg")
+        tmpfile = tmp_path / "temp.jpg"
 
         with Image.open("Tests/images/hopper.jpg") as im:
             im.save(tmpfile)
diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py
index 97cdf5ce6..5b85829c0 100644
--- a/Tests/test_file_jpeg2k.py
+++ b/Tests/test_file_jpeg2k.py
@@ -99,7 +99,7 @@ def test_bytesio(card: ImageFile.ImageFile) -> None:
 def test_lossless(card: ImageFile.ImageFile, tmp_path: Path) -> None:
     with Image.open("Tests/images/test-card-lossless.jp2") as im:
         im.load()
-        outfile = str(tmp_path / "temp_test-card.png")
+        outfile = tmp_path / "temp_test-card.png"
         im.save(outfile)
     assert_image_similar(im, card, 1.0e-3)
 
@@ -213,7 +213,7 @@ def test_header_errors() -> None:
 
 
 def test_layers_type(card: ImageFile.ImageFile, tmp_path: Path) -> None:
-    outfile = str(tmp_path / "temp_layers.jp2")
+    outfile = tmp_path / "temp_layers.jp2"
     for quality_layers in [[100, 50, 10], (100, 50, 10), None]:
         card.save(outfile, quality_layers=quality_layers)
 
@@ -291,7 +291,7 @@ def test_mct(card: ImageFile.ImageFile) -> None:
 
 
 def test_sgnd(tmp_path: Path) -> None:
-    outfile = str(tmp_path / "temp.jp2")
+    outfile = tmp_path / "temp.jp2"
 
     im = Image.new("L", (1, 1))
     im.save(outfile)
diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py
index ba3edc6f2..c13aad1ea 100644
--- a/Tests/test_file_libtiff.py
+++ b/Tests/test_file_libtiff.py
@@ -48,7 +48,7 @@ class LibTiffTestCase:
         assert im._compression == "group4"
 
         # can we write it back out, in a different form.
-        out = str(tmp_path / "temp.png")
+        out = tmp_path / "temp.png"
         im.save(out)
 
         out_bytes = io.BytesIO()
@@ -132,7 +132,7 @@ class TestFileLibTiff(LibTiffTestCase):
         """Checking to see that the saved image is the same as what we wrote"""
         test_file = "Tests/images/hopper_g4_500.tif"
         with Image.open(test_file) as orig:
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
             rot = orig.transpose(Image.Transpose.ROTATE_90)
             assert rot.size == (500, 500)
             rot.save(out)
@@ -160,7 +160,7 @@ class TestFileLibTiff(LibTiffTestCase):
     @pytest.mark.parametrize("legacy_api", (False, True))
     def test_write_metadata(self, legacy_api: bool, tmp_path: Path) -> None:
         """Test metadata writing through libtiff"""
-        f = str(tmp_path / "temp.tiff")
+        f = tmp_path / "temp.tiff"
         with Image.open("Tests/images/hopper_g4.tif") as img:
             assert isinstance(img, TiffImagePlugin.TiffImageFile)
             img.save(f, tiffinfo=img.tag)
@@ -259,7 +259,7 @@ class TestFileLibTiff(LibTiffTestCase):
             # Extra samples really doesn't make sense in this application.
             del new_ifd[338]
 
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
             monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True)
 
             im.save(out, tiffinfo=new_ifd)
@@ -325,7 +325,7 @@ class TestFileLibTiff(LibTiffTestCase):
         ) -> None:
             im = hopper()
 
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
             im.save(out, tiffinfo=tiffinfo)
 
             with Image.open(out) as reloaded:
@@ -360,14 +360,14 @@ class TestFileLibTiff(LibTiffTestCase):
         )
 
     def test_osubfiletype(self, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         with Image.open("Tests/images/g4_orientation_6.tif") as im:
             assert isinstance(im, TiffImagePlugin.TiffImageFile)
             im.tag_v2[OSUBFILETYPE] = 1
             im.save(outfile)
 
     def test_subifd(self, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         with Image.open("Tests/images/g4_orientation_6.tif") as im:
             assert isinstance(im, TiffImagePlugin.TiffImageFile)
             im.tag_v2[SUBIFD] = 10000
@@ -380,7 +380,7 @@ class TestFileLibTiff(LibTiffTestCase):
     ) -> None:
         monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True)
 
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         hopper().save(out, tiffinfo={700: b"xmlpacket tag"})
 
         with Image.open(out) as reloaded:
@@ -391,7 +391,7 @@ class TestFileLibTiff(LibTiffTestCase):
     def test_int_dpi(self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
         # issue #1765
         im = hopper("RGB")
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True)
         im.save(out, dpi=(72, 72))
         with Image.open(out) as reloaded:
@@ -399,7 +399,7 @@ class TestFileLibTiff(LibTiffTestCase):
 
     def test_g3_compression(self, tmp_path: Path) -> None:
         with Image.open("Tests/images/hopper_g4_500.tif") as i:
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
             i.save(out, compression="group3")
 
             with Image.open(out) as reread:
@@ -416,7 +416,7 @@ class TestFileLibTiff(LibTiffTestCase):
             assert b[0] == ord(b"\xe0")
             assert b[1] == ord(b"\x01")
 
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
             # out = "temp.le.tif"
             im.save(out)
         with Image.open(out) as reread:
@@ -436,7 +436,7 @@ class TestFileLibTiff(LibTiffTestCase):
             assert b[0] == ord(b"\x01")
             assert b[1] == ord(b"\xe0")
 
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
             im.save(out)
             with Image.open(out) as reread:
                 assert reread.info["compression"] == im.info["compression"]
@@ -448,7 +448,7 @@ class TestFileLibTiff(LibTiffTestCase):
         with Image.open(test_file) as orig:
             assert isinstance(orig, TiffImagePlugin.TiffImageFile)
 
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
             orig.tag[269] = "temp.tif"
             orig.save(out)
 
@@ -475,7 +475,7 @@ class TestFileLibTiff(LibTiffTestCase):
     def test_blur(self, tmp_path: Path) -> None:
         # test case from irc, how to do blur on b/w image
         # and save to compressed tif.
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         with Image.open("Tests/images/pport_g4.tif") as img:
             im = img.convert("L")
 
@@ -488,7 +488,7 @@ class TestFileLibTiff(LibTiffTestCase):
         # Test various tiff compressions and assert similar image content but reduced
         # file sizes.
         im = hopper("RGB")
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         im.save(out)
         size_raw = os.path.getsize(out)
 
@@ -512,7 +512,7 @@ class TestFileLibTiff(LibTiffTestCase):
 
     def test_tiff_jpeg_compression(self, tmp_path: Path) -> None:
         im = hopper("RGB")
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         im.save(out, compression="tiff_jpeg")
 
         with Image.open(out) as reloaded:
@@ -520,7 +520,7 @@ class TestFileLibTiff(LibTiffTestCase):
 
     def test_tiff_deflate_compression(self, tmp_path: Path) -> None:
         im = hopper("RGB")
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         im.save(out, compression="tiff_deflate")
 
         with Image.open(out) as reloaded:
@@ -528,7 +528,7 @@ class TestFileLibTiff(LibTiffTestCase):
 
     def test_quality(self, tmp_path: Path) -> None:
         im = hopper("RGB")
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
 
         with pytest.raises(ValueError):
             im.save(out, compression="tiff_lzw", quality=50)
@@ -543,7 +543,7 @@ class TestFileLibTiff(LibTiffTestCase):
 
     def test_cmyk_save(self, tmp_path: Path) -> None:
         im = hopper("CMYK")
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
 
         im.save(out, compression="tiff_adobe_deflate")
         assert_image_equal_tofile(im, out)
@@ -552,7 +552,7 @@ class TestFileLibTiff(LibTiffTestCase):
     def test_palette_save(
         self, im: Image.Image, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
     ) -> None:
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
 
         monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True)
         im.save(out)
@@ -565,7 +565,7 @@ class TestFileLibTiff(LibTiffTestCase):
     @pytest.mark.parametrize("compression", ("tiff_ccitt", "group3", "group4"))
     def test_bw_compression_w_rgb(self, compression: str, tmp_path: Path) -> None:
         im = hopper("RGB")
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
 
         with pytest.raises(OSError):
             im.save(out, compression=compression)
@@ -709,7 +709,7 @@ class TestFileLibTiff(LibTiffTestCase):
 
     def test_save_ycbcr(self, tmp_path: Path) -> None:
         im = hopper("YCbCr")
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         im.save(outfile, compression="jpeg")
 
         with Image.open(outfile) as reloaded:
@@ -740,7 +740,7 @@ class TestFileLibTiff(LibTiffTestCase):
     ) -> None:
         # issue 1597
         with Image.open("Tests/images/rdf.tif") as im:
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
 
             monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True)
             # this shouldn't crash
@@ -751,7 +751,7 @@ class TestFileLibTiff(LibTiffTestCase):
         # Test TIFF with tag 297 (Page Number) having value of 0 0.
         # The first number is the current page number.
         # The second is the total number of pages, zero means not available.
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         # Created by printing a page in Chrome to PDF, then:
         # /usr/bin/gs -q -sDEVICE=tiffg3 -sOutputFile=total-pages-zero.tif
         # -dNOPAUSE /tmp/test.pdf -c quit
@@ -763,7 +763,7 @@ class TestFileLibTiff(LibTiffTestCase):
     def test_fd_duplication(self, tmp_path: Path) -> None:
         # https://github.com/python-pillow/Pillow/issues/1651
 
-        tmpfile = str(tmp_path / "temp.tif")
+        tmpfile = tmp_path / "temp.tif"
         with open(tmpfile, "wb") as f:
             with open("Tests/images/g4-multi.tiff", "rb") as src:
                 f.write(src.read())
@@ -806,7 +806,7 @@ class TestFileLibTiff(LibTiffTestCase):
         with Image.open("Tests/images/hopper.iccprofile.tif") as img:
             icc_profile = img.info["icc_profile"]
 
-            out = str(tmp_path / "temp.tif")
+            out = tmp_path / "temp.tif"
             img.save(out, icc_profile=icc_profile)
         with Image.open(out) as reloaded:
             assert icc_profile == reloaded.info["icc_profile"]
@@ -831,7 +831,7 @@ class TestFileLibTiff(LibTiffTestCase):
 
     def test_save_tiff_with_jpegtables(self, tmp_path: Path) -> None:
         # Arrange
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
 
         # Created with ImageMagick: convert hopper.jpg hopper_jpg.tif
         # Contains JPEGTables (347) tag
@@ -893,7 +893,7 @@ class TestFileLibTiff(LibTiffTestCase):
         self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
     ) -> None:
         im = Image.new("F", (1, 1))
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True)
         im.save(out)
 
@@ -1037,7 +1037,7 @@ class TestFileLibTiff(LibTiffTestCase):
     @pytest.mark.parametrize("compression", (None, "jpeg"))
     def test_block_tile_tags(self, compression: str | None, tmp_path: Path) -> None:
         im = hopper()
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
 
         tags = {
             TiffImagePlugin.TILEWIDTH: 256,
@@ -1176,7 +1176,7 @@ class TestFileLibTiff(LibTiffTestCase):
     @pytest.mark.parametrize("compression", ("tiff_adobe_deflate", "jpeg"))
     def test_save_multistrip(self, compression: str, tmp_path: Path) -> None:
         im = hopper("RGB").resize((256, 256))
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         im.save(out, compression=compression)
 
         with Image.open(out) as im:
@@ -1189,7 +1189,7 @@ class TestFileLibTiff(LibTiffTestCase):
         self, argument: bool, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
     ) -> None:
         im = hopper("RGB").resize((256, 256))
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
 
         if not argument:
             monkeypatch.setattr(TiffImagePlugin, "STRIP_SIZE", 2**18)
@@ -1205,13 +1205,13 @@ class TestFileLibTiff(LibTiffTestCase):
     @pytest.mark.parametrize("compression", ("tiff_adobe_deflate", None))
     def test_save_zero(self, compression: str | None, tmp_path: Path) -> None:
         im = Image.new("RGB", (0, 0))
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         with pytest.raises(SystemError):
             im.save(out, compression=compression)
 
     def test_save_many_compressed(self, tmp_path: Path) -> None:
         im = hopper()
-        out = str(tmp_path / "temp.tif")
+        out = tmp_path / "temp.tif"
         for _ in range(10000):
             im.save(out, compression="jpeg")
 
diff --git a/Tests/test_file_msp.py b/Tests/test_file_msp.py
index b0964aabe..8c91922bd 100644
--- a/Tests/test_file_msp.py
+++ b/Tests/test_file_msp.py
@@ -15,7 +15,7 @@ YA_EXTRA_DIR = "Tests/images/msp"
 
 
 def test_sanity(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.msp")
+    test_file = tmp_path / "temp.msp"
 
     hopper("1").save(test_file)
 
@@ -84,7 +84,7 @@ def test_msp_v2() -> None:
 def test_cannot_save_wrong_mode(tmp_path: Path) -> None:
     # Arrange
     im = hopper()
-    filename = str(tmp_path / "temp.msp")
+    filename = tmp_path / "temp.msp"
 
     # Act/Assert
     with pytest.raises(OSError):
diff --git a/Tests/test_file_palm.py b/Tests/test_file_palm.py
index 194f39b30..a1859bc33 100644
--- a/Tests/test_file_palm.py
+++ b/Tests/test_file_palm.py
@@ -14,7 +14,7 @@ from .helper import assert_image_equal, hopper, magick_command
 def helper_save_as_palm(tmp_path: Path, mode: str) -> None:
     # Arrange
     im = hopper(mode)
-    outfile = str(tmp_path / ("temp_" + mode + ".palm"))
+    outfile = tmp_path / ("temp_" + mode + ".palm")
 
     # Act
     im.save(outfile)
@@ -25,7 +25,7 @@ def helper_save_as_palm(tmp_path: Path, mode: str) -> None:
 
 
 def open_with_magick(magick: list[str], tmp_path: Path, f: str) -> Image.Image:
-    outfile = str(tmp_path / "temp.png")
+    outfile = tmp_path / "temp.png"
     rc = subprocess.call(
         magick + [f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
     )
diff --git a/Tests/test_file_pcx.py b/Tests/test_file_pcx.py
index 21c32268c..5d7fd1c1b 100644
--- a/Tests/test_file_pcx.py
+++ b/Tests/test_file_pcx.py
@@ -11,7 +11,7 @@ from .helper import assert_image_equal, hopper
 
 
 def _roundtrip(tmp_path: Path, im: Image.Image) -> None:
-    f = str(tmp_path / "temp.pcx")
+    f = tmp_path / "temp.pcx"
     im.save(f)
     with Image.open(f) as im2:
         assert im2.mode == im.mode
@@ -31,7 +31,7 @@ def test_sanity(tmp_path: Path) -> None:
     _roundtrip(tmp_path, im)
 
     # Test an unsupported mode
-    f = str(tmp_path / "temp.pcx")
+    f = tmp_path / "temp.pcx"
     im = hopper("RGBA")
     with pytest.raises(ValueError):
         im.save(f)
diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py
index 815686a52..bde1e3ab8 100644
--- a/Tests/test_file_pdf.py
+++ b/Tests/test_file_pdf.py
@@ -55,7 +55,7 @@ def test_save_alpha(tmp_path: Path, mode: str) -> None:
 
 def test_p_alpha(tmp_path: Path) -> None:
     # Arrange
-    outfile = str(tmp_path / "temp.pdf")
+    outfile = tmp_path / "temp.pdf"
     with Image.open("Tests/images/pil123p.png") as im:
         assert im.mode == "P"
         assert isinstance(im.info["transparency"], bytes)
@@ -80,7 +80,7 @@ def test_monochrome(tmp_path: Path) -> None:
 
 def test_unsupported_mode(tmp_path: Path) -> None:
     im = hopper("PA")
-    outfile = str(tmp_path / "temp_PA.pdf")
+    outfile = tmp_path / "temp_PA.pdf"
 
     with pytest.raises(ValueError):
         im.save(outfile)
@@ -89,7 +89,7 @@ def test_unsupported_mode(tmp_path: Path) -> None:
 def test_resolution(tmp_path: Path) -> None:
     im = hopper()
 
-    outfile = str(tmp_path / "temp.pdf")
+    outfile = tmp_path / "temp.pdf"
     im.save(outfile, resolution=150)
 
     with open(outfile, "rb") as fp:
@@ -117,7 +117,7 @@ def test_resolution(tmp_path: Path) -> None:
 def test_dpi(params: dict[str, int | tuple[int, int]], tmp_path: Path) -> None:
     im = hopper()
 
-    outfile = str(tmp_path / "temp.pdf")
+    outfile = tmp_path / "temp.pdf"
     im.save(outfile, "PDF", **params)
 
     with open(outfile, "rb") as fp:
@@ -144,7 +144,7 @@ def test_save_all(tmp_path: Path) -> None:
 
     # Multiframe image
     with Image.open("Tests/images/dispose_bgnd.gif") as im:
-        outfile = str(tmp_path / "temp.pdf")
+        outfile = tmp_path / "temp.pdf"
         im.save(outfile, save_all=True)
 
         assert os.path.isfile(outfile)
@@ -177,7 +177,7 @@ def test_save_all(tmp_path: Path) -> None:
 def test_multiframe_normal_save(tmp_path: Path) -> None:
     # Test saving a multiframe image without save_all
     with Image.open("Tests/images/dispose_bgnd.gif") as im:
-        outfile = str(tmp_path / "temp.pdf")
+        outfile = tmp_path / "temp.pdf"
         im.save(outfile)
 
     assert os.path.isfile(outfile)
diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py
index 89233f41e..4714699b9 100644
--- a/Tests/test_file_png.py
+++ b/Tests/test_file_png.py
@@ -68,7 +68,7 @@ def roundtrip(im: Image.Image, **options: Any) -> PngImagePlugin.PngImageFile:
 
 @skip_unless_feature("zlib")
 class TestFilePng:
-    def get_chunks(self, filename: str) -> list[bytes]:
+    def get_chunks(self, filename: Path) -> list[bytes]:
         chunks = []
         with open(filename, "rb") as fp:
             fp.read(8)
@@ -89,7 +89,7 @@ class TestFilePng:
         assert version is not None
         assert re.search(r"\d+(\.\d+){1,3}(\.zlib\-ng)?$", version)
 
-        test_file = str(tmp_path / "temp.png")
+        test_file = tmp_path / "temp.png"
 
         hopper("RGB").save(test_file)
 
@@ -257,7 +257,7 @@ class TestFilePng:
             # each palette entry
             assert len(im.info["transparency"]) == 256
 
-            test_file = str(tmp_path / "temp.png")
+            test_file = tmp_path / "temp.png"
             im.save(test_file)
 
         # check if saved image contains same transparency
@@ -280,7 +280,7 @@ class TestFilePng:
             assert im.info["transparency"] == 164
             assert im.getpixel((31, 31)) == 164
 
-            test_file = str(tmp_path / "temp.png")
+            test_file = tmp_path / "temp.png"
             im.save(test_file)
 
         # check if saved image contains same transparency
@@ -305,7 +305,7 @@ class TestFilePng:
         assert im.getcolors() == [(100, (0, 0, 0, 0))]
 
         im = im.convert("P")
-        test_file = str(tmp_path / "temp.png")
+        test_file = tmp_path / "temp.png"
         im.save(test_file)
 
         # check if saved image contains same transparency
@@ -328,7 +328,7 @@ class TestFilePng:
             assert colors is not None
             assert colors[0][0] == num_transparent
 
-            test_file = str(tmp_path / "temp.png")
+            test_file = tmp_path / "temp.png"
             im.save(test_file)
 
             with Image.open(test_file) as test_im:
@@ -344,7 +344,7 @@ class TestFilePng:
     def test_save_rgb_single_transparency(self, tmp_path: Path) -> None:
         in_file = "Tests/images/caption_6_33_22.png"
         with Image.open(in_file) as im:
-            test_file = str(tmp_path / "temp.png")
+            test_file = tmp_path / "temp.png"
             im.save(test_file)
 
     def test_load_verify(self) -> None:
@@ -503,7 +503,7 @@ class TestFilePng:
         im = hopper("P")
         im.info["transparency"] = 0
 
-        f = str(tmp_path / "temp.png")
+        f = tmp_path / "temp.png"
         im.save(f)
 
         with Image.open(f) as im2:
@@ -564,7 +564,7 @@ class TestFilePng:
 
     def test_chunk_order(self, tmp_path: Path) -> None:
         with Image.open("Tests/images/icc_profile.png") as im:
-            test_file = str(tmp_path / "temp.png")
+            test_file = tmp_path / "temp.png"
             im.convert("P").save(test_file, dpi=(100, 100))
 
         chunks = self.get_chunks(test_file)
@@ -682,7 +682,7 @@ class TestFilePng:
     def test_specify_bits(self, save_all: bool, tmp_path: Path) -> None:
         im = hopper("P")
 
-        out = str(tmp_path / "temp.png")
+        out = tmp_path / "temp.png"
         im.save(out, bits=4, save_all=save_all)
 
         with Image.open(out) as reloaded:
@@ -695,8 +695,8 @@ class TestFilePng:
         im = Image.new("P", (1, 1))
         im.putpalette((1, 1, 1))
 
-        out = str(tmp_path / "temp.png")
-        im.save(str(tmp_path / "temp.png"))
+        out = tmp_path / "temp.png"
+        im.save(out)
 
         with Image.open(out) as reloaded:
             assert isinstance(reloaded, PngImagePlugin.PngImageFile)
@@ -754,7 +754,7 @@ class TestFilePng:
 
     def test_exif_save(self, tmp_path: Path) -> None:
         # Test exif is not saved from info
-        test_file = str(tmp_path / "temp.png")
+        test_file = tmp_path / "temp.png"
         with Image.open("Tests/images/exif.png") as im:
             im.save(test_file)
 
@@ -777,7 +777,7 @@ class TestFilePng:
     )
     def test_exif_from_jpg(self, tmp_path: Path) -> None:
         with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
-            test_file = str(tmp_path / "temp.png")
+            test_file = tmp_path / "temp.png"
             im.save(test_file, exif=im.getexif())
 
         with Image.open(test_file) as reloaded:
@@ -788,7 +788,7 @@ class TestFilePng:
 
     def test_exif_argument(self, tmp_path: Path) -> None:
         with Image.open(TEST_PNG_FILE) as im:
-            test_file = str(tmp_path / "temp.png")
+            test_file = tmp_path / "temp.png"
             im.save(test_file, exif=b"exifstring")
 
         with Image.open(test_file) as reloaded:
diff --git a/Tests/test_file_ppm.py b/Tests/test_file_ppm.py
index 1280d4524..d399c0e95 100644
--- a/Tests/test_file_ppm.py
+++ b/Tests/test_file_ppm.py
@@ -94,7 +94,7 @@ def test_16bit_pgm() -> None:
 
 def test_16bit_pgm_write(tmp_path: Path) -> None:
     with Image.open("Tests/images/16_bit_binary.pgm") as im:
-        filename = str(tmp_path / "temp.pgm")
+        filename = tmp_path / "temp.pgm"
         im.save(filename, "PPM")
         assert_image_equal_tofile(im, filename)
 
@@ -106,7 +106,7 @@ def test_pnm(tmp_path: Path) -> None:
     with Image.open("Tests/images/hopper.pnm") as im:
         assert_image_similar(im, hopper(), 0.0001)
 
-        filename = str(tmp_path / "temp.pnm")
+        filename = tmp_path / "temp.pnm"
         im.save(filename)
 
         assert_image_equal_tofile(im, filename)
@@ -117,7 +117,7 @@ def test_pfm(tmp_path: Path) -> None:
         assert im.info["scale"] == 1.0
         assert_image_equal(im, hopper("F"))
 
-        filename = str(tmp_path / "tmp.pfm")
+        filename = tmp_path / "tmp.pfm"
         im.save(filename)
 
         assert_image_equal_tofile(im, filename)
@@ -128,7 +128,7 @@ def test_pfm_big_endian(tmp_path: Path) -> None:
         assert im.info["scale"] == 2.5
         assert_image_equal(im, hopper("F"))
 
-        filename = str(tmp_path / "tmp.pfm")
+        filename = tmp_path / "tmp.pfm"
         im.save(filename)
 
         assert_image_equal_tofile(im, filename)
@@ -194,8 +194,8 @@ def test_16bit_plain_pgm() -> None:
 def test_plain_data_with_comment(
     tmp_path: Path, header: bytes, data: bytes, comment_count: int
 ) -> None:
-    path1 = str(tmp_path / "temp1.ppm")
-    path2 = str(tmp_path / "temp2.ppm")
+    path1 = tmp_path / "temp1.ppm"
+    path2 = tmp_path / "temp2.ppm"
     comment = b"# comment" * comment_count
     with open(path1, "wb") as f1, open(path2, "wb") as f2:
         f1.write(header + b"\n\n" + data)
@@ -207,7 +207,7 @@ def test_plain_data_with_comment(
 
 @pytest.mark.parametrize("data", (b"P1\n128 128\n", b"P3\n128 128\n255\n"))
 def test_plain_truncated_data(tmp_path: Path, data: bytes) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(data)
 
@@ -218,7 +218,7 @@ def test_plain_truncated_data(tmp_path: Path, data: bytes) -> None:
 
 @pytest.mark.parametrize("data", (b"P1\n128 128\n1009", b"P3\n128 128\n255\n100A"))
 def test_plain_invalid_data(tmp_path: Path, data: bytes) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(data)
 
@@ -235,7 +235,7 @@ def test_plain_invalid_data(tmp_path: Path, data: bytes) -> None:
     ),
 )
 def test_plain_ppm_token_too_long(tmp_path: Path, data: bytes) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(data)
 
@@ -245,7 +245,7 @@ def test_plain_ppm_token_too_long(tmp_path: Path, data: bytes) -> None:
 
 
 def test_plain_ppm_value_negative(tmp_path: Path) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(b"P3\n128 128\n255\n-1")
 
@@ -255,7 +255,7 @@ def test_plain_ppm_value_negative(tmp_path: Path) -> None:
 
 
 def test_plain_ppm_value_too_large(tmp_path: Path) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(b"P3\n128 128\n255\n256")
 
@@ -270,7 +270,7 @@ def test_magic() -> None:
 
 
 def test_header_with_comments(tmp_path: Path) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(b"P6 #comment\n#comment\r12#comment\r8\n128 #comment\n255\n")
 
@@ -279,7 +279,7 @@ def test_header_with_comments(tmp_path: Path) -> None:
 
 
 def test_non_integer_token(tmp_path: Path) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(b"P6\nTEST")
 
@@ -289,7 +289,7 @@ def test_non_integer_token(tmp_path: Path) -> None:
 
 
 def test_header_token_too_long(tmp_path: Path) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(b"P6\n 01234567890")
 
@@ -300,7 +300,7 @@ def test_header_token_too_long(tmp_path: Path) -> None:
 
 def test_truncated_file(tmp_path: Path) -> None:
     # Test EOF in header
-    path = str(tmp_path / "temp.pgm")
+    path = tmp_path / "temp.pgm"
     with open(path, "wb") as f:
         f.write(b"P6")
 
@@ -316,7 +316,7 @@ def test_truncated_file(tmp_path: Path) -> None:
 
 
 def test_not_enough_image_data(tmp_path: Path) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(b"P2 1 2 255 255")
 
@@ -327,7 +327,7 @@ def test_not_enough_image_data(tmp_path: Path) -> None:
 
 @pytest.mark.parametrize("maxval", (b"0", b"65536"))
 def test_invalid_maxval(maxval: bytes, tmp_path: Path) -> None:
-    path = str(tmp_path / "temp.ppm")
+    path = tmp_path / "temp.ppm"
     with open(path, "wb") as f:
         f.write(b"P6\n3 1 " + maxval)
 
@@ -350,7 +350,7 @@ def test_neg_ppm() -> None:
 
 
 def test_mimetypes(tmp_path: Path) -> None:
-    path = str(tmp_path / "temp.pgm")
+    path = tmp_path / "temp.pgm"
 
     with open(path, "wb") as f:
         f.write(b"P4\n128 128\n255")
diff --git a/Tests/test_file_sgi.py b/Tests/test_file_sgi.py
index e13a8019e..7d34fa4b5 100644
--- a/Tests/test_file_sgi.py
+++ b/Tests/test_file_sgi.py
@@ -73,11 +73,11 @@ def test_invalid_file() -> None:
 
 def test_write(tmp_path: Path) -> None:
     def roundtrip(img: Image.Image) -> None:
-        out = str(tmp_path / "temp.sgi")
+        out = tmp_path / "temp.sgi"
         img.save(out, format="sgi")
         assert_image_equal_tofile(img, out)
 
-        out = str(tmp_path / "fp.sgi")
+        out = tmp_path / "fp.sgi"
         with open(out, "wb") as fp:
             img.save(fp)
             assert_image_equal_tofile(img, out)
@@ -95,7 +95,7 @@ def test_write16(tmp_path: Path) -> None:
     test_file = "Tests/images/hopper16.rgb"
 
     with Image.open(test_file) as im:
-        out = str(tmp_path / "temp.sgi")
+        out = tmp_path / "temp.sgi"
         im.save(out, format="sgi", bpc=2)
 
         assert_image_equal_tofile(im, out)
@@ -103,7 +103,7 @@ def test_write16(tmp_path: Path) -> None:
 
 def test_unsupported_mode(tmp_path: Path) -> None:
     im = hopper("LA")
-    out = str(tmp_path / "temp.sgi")
+    out = tmp_path / "temp.sgi"
 
     with pytest.raises(ValueError):
         im.save(out, format="sgi")
diff --git a/Tests/test_file_spider.py b/Tests/test_file_spider.py
index 82254b03a..3b3c3b4a5 100644
--- a/Tests/test_file_spider.py
+++ b/Tests/test_file_spider.py
@@ -51,7 +51,7 @@ def test_context_manager() -> None:
 
 def test_save(tmp_path: Path) -> None:
     # Arrange
-    temp = str(tmp_path / "temp.spider")
+    temp = tmp_path / "temp.spider"
     im = hopper()
 
     # Act
diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py
index 25dbeaea6..c9989fb09 100644
--- a/Tests/test_file_tga.py
+++ b/Tests/test_file_tga.py
@@ -24,7 +24,7 @@ _ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1}
 @pytest.mark.parametrize("mode", _MODES)
 def test_sanity(mode: str, tmp_path: Path) -> None:
     def roundtrip(original_im: Image.Image) -> None:
-        out = str(tmp_path / "temp.tga")
+        out = tmp_path / "temp.tga"
 
         original_im.save(out, rle=rle)
         with Image.open(out) as saved_im:
@@ -65,7 +65,7 @@ def test_sanity(mode: str, tmp_path: Path) -> None:
                     roundtrip(original_im)
 
 
-def test_palette_depth_8(tmp_path: Path) -> None:
+def test_palette_depth_8() -> None:
     with pytest.raises(UnidentifiedImageError):
         Image.open("Tests/images/p_8.tga")
 
@@ -76,7 +76,7 @@ def test_palette_depth_16(tmp_path: Path) -> None:
         assert im.palette.mode == "RGBA"
         assert_image_equal_tofile(im.convert("RGBA"), "Tests/images/p_16.png")
 
-        out = str(tmp_path / "temp.png")
+        out = tmp_path / "temp.png"
         im.save(out)
         with Image.open(out) as reloaded:
             assert_image_equal_tofile(reloaded.convert("RGBA"), "Tests/images/p_16.png")
@@ -122,7 +122,7 @@ def test_cross_scan_line() -> None:
 def test_save(tmp_path: Path) -> None:
     test_file = "Tests/images/tga_id_field.tga"
     with Image.open(test_file) as im:
-        out = str(tmp_path / "temp.tga")
+        out = tmp_path / "temp.tga"
 
         # Save
         im.save(out)
@@ -141,7 +141,7 @@ def test_small_palette(tmp_path: Path) -> None:
     colors = [0, 0, 0]
     im.putpalette(colors)
 
-    out = str(tmp_path / "temp.tga")
+    out = tmp_path / "temp.tga"
     im.save(out)
 
     with Image.open(out) as reloaded:
@@ -155,7 +155,7 @@ def test_missing_palette() -> None:
 
 def test_save_wrong_mode(tmp_path: Path) -> None:
     im = hopper("PA")
-    out = str(tmp_path / "temp.tga")
+    out = tmp_path / "temp.tga"
 
     with pytest.raises(OSError):
         im.save(out)
@@ -172,7 +172,7 @@ def test_save_mapdepth() -> None:
 def test_save_id_section(tmp_path: Path) -> None:
     test_file = "Tests/images/rgb32rle.tga"
     with Image.open(test_file) as im:
-        out = str(tmp_path / "temp.tga")
+        out = tmp_path / "temp.tga"
 
         # Check there is no id section
         im.save(out)
@@ -202,7 +202,7 @@ def test_save_id_section(tmp_path: Path) -> None:
 
 def test_save_orientation(tmp_path: Path) -> None:
     test_file = "Tests/images/rgb32rle.tga"
-    out = str(tmp_path / "temp.tga")
+    out = tmp_path / "temp.tga"
     with Image.open(test_file) as im:
         assert im.info["orientation"] == -1
 
@@ -233,7 +233,7 @@ def test_save_rle(tmp_path: Path) -> None:
     with Image.open(test_file) as im:
         assert im.info["compression"] == "tga_rle"
 
-        out = str(tmp_path / "temp.tga")
+        out = tmp_path / "temp.tga"
 
         # Save
         im.save(out)
@@ -272,7 +272,7 @@ def test_save_l_transparency(tmp_path: Path) -> None:
         assert colors is not None
         assert colors[0][0] == num_transparent
 
-        out = str(tmp_path / "temp.tga")
+        out = tmp_path / "temp.tga"
         im.save(out)
 
     with Image.open(out) as test_im:
diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py
index a8b331035..ee77c61a7 100644
--- a/Tests/test_file_tiff.py
+++ b/Tests/test_file_tiff.py
@@ -37,7 +37,7 @@ except ImportError:
 
 class TestFileTiff:
     def test_sanity(self, tmp_path: Path) -> None:
-        filename = str(tmp_path / "temp.tif")
+        filename = tmp_path / "temp.tif"
 
         hopper("RGB").save(filename)
 
@@ -120,11 +120,11 @@ class TestFileTiff:
         with Image.open("Tests/images/hopper_bigtiff.tif") as im:
             assert isinstance(im, TiffImagePlugin.TiffImageFile)
 
-            outfile = str(tmp_path / "temp.tif")
+            outfile = tmp_path / "temp.tif"
             im.save(outfile, save_all=True, append_images=[im], tiffinfo=im.tag_v2)
 
     def test_bigtiff_save(self, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         im = hopper()
         im.save(outfile, big_tiff=True)
 
@@ -202,7 +202,7 @@ class TestFileTiff:
             assert im.info["dpi"] == (dpi, dpi)
 
     def test_save_float_dpi(self, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         with Image.open("Tests/images/hopper.tif") as im:
             dpi = (72.2, 72.2)
             im.save(outfile, dpi=dpi)
@@ -240,12 +240,12 @@ class TestFileTiff:
 
     def test_save_rgba(self, tmp_path: Path) -> None:
         im = hopper("RGBA")
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         im.save(outfile)
 
     def test_save_unsupported_mode(self, tmp_path: Path) -> None:
         im = hopper("HSV")
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         with pytest.raises(OSError):
             im.save(outfile)
 
@@ -515,14 +515,14 @@ class TestFileTiff:
             assert gps[0] == b"\x03\x02\x00\x00"
             assert gps[18] == "WGS-84"
 
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         with Image.open("Tests/images/ifd_tag_type.tiff") as im:
             exif = im.getexif()
             check_exif(exif)
 
             im.save(outfile, exif=exif)
 
-        outfile2 = str(tmp_path / "temp2.tif")
+        outfile2 = tmp_path / "temp2.tif"
         with Image.open(outfile) as im:
             exif = im.getexif()
             check_exif(exif)
@@ -534,7 +534,7 @@ class TestFileTiff:
             check_exif(exif)
 
     def test_modify_exif(self, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         with Image.open("Tests/images/ifd_tag_type.tiff") as im:
             exif = im.getexif()
             exif[264] = 100
@@ -563,7 +563,7 @@ class TestFileTiff:
 
     @pytest.mark.parametrize("mode", ("1", "L"))
     def test_photometric(self, mode: str, tmp_path: Path) -> None:
-        filename = str(tmp_path / "temp.tif")
+        filename = tmp_path / "temp.tif"
         im = hopper(mode)
         im.save(filename, tiffinfo={262: 0})
         with Image.open(filename) as reloaded:
@@ -643,7 +643,7 @@ class TestFileTiff:
 
     def test_with_underscores(self, tmp_path: Path) -> None:
         kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36}
-        filename = str(tmp_path / "temp.tif")
+        filename = tmp_path / "temp.tif"
         hopper("RGB").save(filename, "TIFF", **kwargs)
         with Image.open(filename) as im:
             assert isinstance(im, TiffImagePlugin.TiffImageFile)
@@ -663,14 +663,14 @@ class TestFileTiff:
         with Image.open(infile) as im:
             assert im.getpixel((0, 0)) == pixel_value
 
-            tmpfile = str(tmp_path / "temp.tif")
+            tmpfile = tmp_path / "temp.tif"
             im.save(tmpfile)
 
             assert_image_equal_tofile(im, tmpfile)
 
     def test_iptc(self, tmp_path: Path) -> None:
         # Do not preserve IPTC_NAA_CHUNK by default if type is LONG
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         with Image.open("Tests/images/hopper.tif") as im:
             im.load()
             assert isinstance(im, TiffImagePlugin.TiffImageFile)
@@ -685,7 +685,7 @@ class TestFileTiff:
             assert 33723 not in im.tag_v2
 
     def test_rowsperstrip(self, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         im = hopper()
         im.save(outfile, tiffinfo={278: 256})
 
@@ -737,7 +737,7 @@ class TestFileTiff:
             assert isinstance(im, TiffImagePlugin.TiffImageFile)
             assert im._planar_configuration == 2
 
-            outfile = str(tmp_path / "temp.tif")
+            outfile = tmp_path / "temp.tif"
             im.save(outfile)
 
             with Image.open(outfile) as reloaded:
@@ -752,7 +752,7 @@ class TestFileTiff:
 
     @pytest.mark.parametrize("mode", ("P", "PA"))
     def test_palette(self, mode: str, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
 
         im = hopper(mode)
         im.save(outfile)
@@ -849,7 +849,7 @@ class TestFileTiff:
         im.info["icc_profile"] = "Dummy value"
 
         # Try save-load round trip to make sure both handle icc_profile.
-        tmpfile = str(tmp_path / "temp.tif")
+        tmpfile = tmp_path / "temp.tif"
         im.save(tmpfile, "TIFF", compression="raw")
         with Image.open(tmpfile) as reloaded:
             assert b"Dummy value" == reloaded.info["icc_profile"]
@@ -858,7 +858,7 @@ class TestFileTiff:
         im = hopper()
         assert "icc_profile" not in im.info
 
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
         icc_profile = b"Dummy value"
         im.save(outfile, icc_profile=icc_profile)
 
@@ -869,11 +869,11 @@ class TestFileTiff:
         with Image.open("Tests/images/hopper.bmp") as im:
             assert im.info["compression"] == 0
 
-            outfile = str(tmp_path / "temp.tif")
+            outfile = tmp_path / "temp.tif"
             im.save(outfile)
 
     def test_discard_icc_profile(self, tmp_path: Path) -> None:
-        outfile = str(tmp_path / "temp.tif")
+        outfile = tmp_path / "temp.tif"
 
         with Image.open("Tests/images/icc_profile.png") as im:
             assert "icc_profile" in im.info
@@ -927,7 +927,7 @@ class TestFileTiff:
             ]
 
     def test_tiff_chunks(self, tmp_path: Path) -> None:
-        tmpfile = str(tmp_path / "temp.tif")
+        tmpfile = tmp_path / "temp.tif"
 
         im = hopper()
         with open(tmpfile, "wb") as fp:
@@ -949,7 +949,7 @@ class TestFileTiff:
 
     def test_close_on_load_exclusive(self, tmp_path: Path) -> None:
         # similar to test_fd_leak, but runs on unixlike os
-        tmpfile = str(tmp_path / "temp.tif")
+        tmpfile = tmp_path / "temp.tif"
 
         with Image.open("Tests/images/uint16_1_4660.tif") as im:
             im.save(tmpfile)
@@ -962,7 +962,7 @@ class TestFileTiff:
         assert fp.closed
 
     def test_close_on_load_nonexclusive(self, tmp_path: Path) -> None:
-        tmpfile = str(tmp_path / "temp.tif")
+        tmpfile = tmp_path / "temp.tif"
 
         with Image.open("Tests/images/uint16_1_4660.tif") as im:
             im.save(tmpfile)
@@ -1014,7 +1014,7 @@ class TestFileTiff:
 @pytest.mark.skipif(not is_win32(), reason="Windows only")
 class TestFileTiffW32:
     def test_fd_leak(self, tmp_path: Path) -> None:
-        tmpfile = str(tmp_path / "temp.tif")
+        tmpfile = tmp_path / "temp.tif"
 
         # this is an mmaped file.
         with Image.open("Tests/images/uint16_1_4660.tif") as im:
diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py
index 8a9f10d98..3d4b2cb35 100644
--- a/Tests/test_file_tiff_metadata.py
+++ b/Tests/test_file_tiff_metadata.py
@@ -56,7 +56,7 @@ def test_rt_metadata(tmp_path: Path) -> None:
 
     info[ImageDescription] = text_data
 
-    f = str(tmp_path / "temp.tif")
+    f = tmp_path / "temp.tif"
 
     img.save(f, tiffinfo=info)
 
@@ -133,7 +133,7 @@ def test_write_metadata(tmp_path: Path) -> None:
     with Image.open("Tests/images/hopper.tif") as img:
         assert isinstance(img, TiffImagePlugin.TiffImageFile)
 
-        f = str(tmp_path / "temp.tiff")
+        f = tmp_path / "temp.tiff"
         del img.tag[278]
         img.save(f, tiffinfo=img.tag)
 
@@ -169,7 +169,7 @@ def test_write_metadata(tmp_path: Path) -> None:
 
 
 def test_change_stripbytecounts_tag_type(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     with Image.open("Tests/images/hopper.tif") as im:
         assert isinstance(im, TiffImagePlugin.TiffImageFile)
         info = im.tag_v2
@@ -218,7 +218,7 @@ def test_no_duplicate_50741_tag() -> None:
 
 
 def test_iptc(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     with Image.open("Tests/images/hopper.Lab.tif") as im:
         im.save(out)
 
@@ -235,7 +235,7 @@ def test_writing_other_types_to_ascii(
     info[271] = value
 
     im = hopper()
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info)
 
     with Image.open(out) as reloaded:
@@ -253,7 +253,7 @@ def test_writing_other_types_to_bytes(value: int | IFDRational, tmp_path: Path)
 
     info[700] = value
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info)
 
     with Image.open(out) as reloaded:
@@ -273,7 +273,7 @@ def test_writing_other_types_to_undefined(
 
     info[33723] = value
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info)
 
     with Image.open(out) as reloaded:
@@ -307,7 +307,7 @@ def test_empty_metadata() -> None:
 
 def test_iccprofile(tmp_path: Path) -> None:
     # https://github.com/python-pillow/Pillow/issues/1462
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     with Image.open("Tests/images/hopper.iccprofile.tif") as im:
         im.save(out)
 
@@ -329,13 +329,13 @@ def test_iccprofile_binary() -> None:
 
 def test_iccprofile_save_png(tmp_path: Path) -> None:
     with Image.open("Tests/images/hopper.iccprofile.tif") as im:
-        outfile = str(tmp_path / "temp.png")
+        outfile = tmp_path / "temp.png"
         im.save(outfile)
 
 
 def test_iccprofile_binary_save_png(tmp_path: Path) -> None:
     with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
-        outfile = str(tmp_path / "temp.png")
+        outfile = tmp_path / "temp.png"
         im.save(outfile)
 
 
@@ -344,7 +344,7 @@ def test_exif_div_zero(tmp_path: Path) -> None:
     info = TiffImagePlugin.ImageFileDirectory_v2()
     info[41988] = TiffImagePlugin.IFDRational(0, 0)
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info, compression="raw")
 
     with Image.open(out) as reloaded:
@@ -364,7 +364,7 @@ def test_ifd_unsigned_rational(tmp_path: Path) -> None:
 
     info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info, compression="raw")
 
     with Image.open(out) as reloaded:
@@ -377,7 +377,7 @@ def test_ifd_unsigned_rational(tmp_path: Path) -> None:
 
     info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info, compression="raw")
 
     with Image.open(out) as reloaded:
@@ -396,7 +396,7 @@ def test_ifd_signed_rational(tmp_path: Path) -> None:
 
     info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info, compression="raw")
 
     with Image.open(out) as reloaded:
@@ -409,7 +409,7 @@ def test_ifd_signed_rational(tmp_path: Path) -> None:
 
     info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info, compression="raw")
 
     with Image.open(out) as reloaded:
@@ -423,7 +423,7 @@ def test_ifd_signed_rational(tmp_path: Path) -> None:
 
     info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info, compression="raw")
 
     with Image.open(out) as reloaded:
@@ -438,7 +438,7 @@ def test_ifd_signed_long(tmp_path: Path) -> None:
 
     info[37000] = -60000
 
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     im.save(out, tiffinfo=info, compression="raw")
 
     with Image.open(out) as reloaded:
@@ -466,7 +466,7 @@ def test_photoshop_info(tmp_path: Path) -> None:
         assert isinstance(im, TiffImagePlugin.TiffImageFile)
         assert len(im.tag_v2[34377]) == 70
         assert isinstance(im.tag_v2[34377], bytes)
-        out = str(tmp_path / "temp.tiff")
+        out = tmp_path / "temp.tiff"
         im.save(out)
     with Image.open(out) as reloaded:
         assert isinstance(reloaded, TiffImagePlugin.TiffImageFile)
@@ -501,7 +501,7 @@ def test_tag_group_data() -> None:
 
 
 def test_empty_subifd(tmp_path: Path) -> None:
-    out = str(tmp_path / "temp.jpg")
+    out = tmp_path / "temp.jpg"
 
     im = hopper()
     exif = im.getexif()
diff --git a/Tests/test_file_webp_alpha.py b/Tests/test_file_webp_alpha.py
index c88fe3589..c573390c4 100644
--- a/Tests/test_file_webp_alpha.py
+++ b/Tests/test_file_webp_alpha.py
@@ -42,7 +42,7 @@ def test_write_lossless_rgb(tmp_path: Path) -> None:
     Does it have the bits we expect?
     """
 
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
     # temp_file = "temp.webp"
 
     pil_image = hopper("RGBA")
@@ -71,7 +71,7 @@ def test_write_rgba(tmp_path: Path) -> None:
     Does it have the bits we expect?
     """
 
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
 
     pil_image = Image.new("RGBA", (10, 10), (255, 0, 0, 20))
     pil_image.save(temp_file)
@@ -104,7 +104,7 @@ def test_keep_rgb_values_when_transparent(tmp_path: Path) -> None:
     half_transparent_image.putalpha(new_alpha)
 
     # save with transparent area preserved
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
     half_transparent_image.save(temp_file, exact=True, lossless=True)
 
     with Image.open(temp_file) as reloaded:
@@ -123,7 +123,7 @@ def test_write_unsupported_mode_PA(tmp_path: Path) -> None:
     should work, and be similar to the original file.
     """
 
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
     file_path = "Tests/images/transparent.gif"
     with Image.open(file_path) as im:
         im.save(temp_file)
@@ -142,10 +142,10 @@ def test_write_unsupported_mode_PA(tmp_path: Path) -> None:
 
 def test_alpha_quality(tmp_path: Path) -> None:
     with Image.open("Tests/images/transparent.png") as im:
-        out = str(tmp_path / "temp.webp")
+        out = tmp_path / "temp.webp"
         im.save(out)
 
-        out_quality = str(tmp_path / "quality.webp")
+        out_quality = tmp_path / "quality.webp"
         im.save(out_quality, alpha_quality=50)
         with Image.open(out) as reloaded:
             with Image.open(out_quality) as reloaded_quality:
diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py
index 9035d9057..503761374 100644
--- a/Tests/test_file_webp_animated.py
+++ b/Tests/test_file_webp_animated.py
@@ -42,7 +42,7 @@ def test_write_animation_L(tmp_path: Path) -> None:
         assert isinstance(orig, GifImagePlugin.GifImageFile)
         assert orig.n_frames > 1
 
-        temp_file = str(tmp_path / "temp.webp")
+        temp_file = tmp_path / "temp.webp"
         orig.save(temp_file, save_all=True)
         with Image.open(temp_file) as im:
             assert isinstance(im, WebPImagePlugin.WebPImageFile)
@@ -71,7 +71,7 @@ def test_write_animation_RGB(tmp_path: Path) -> None:
     are visually similar to the originals.
     """
 
-    def check(temp_file: str) -> None:
+    def check(temp_file: Path) -> None:
         with Image.open(temp_file) as im:
             assert isinstance(im, WebPImagePlugin.WebPImageFile)
             assert im.n_frames == 2
@@ -92,7 +92,7 @@ def test_write_animation_RGB(tmp_path: Path) -> None:
 
     with Image.open("Tests/images/anim_frame1.webp") as frame1:
         with Image.open("Tests/images/anim_frame2.webp") as frame2:
-            temp_file1 = str(tmp_path / "temp.webp")
+            temp_file1 = tmp_path / "temp.webp"
             frame1.copy().save(
                 temp_file1, save_all=True, append_images=[frame2], lossless=True
             )
@@ -104,7 +104,7 @@ def test_write_animation_RGB(tmp_path: Path) -> None:
             ) -> Generator[Image.Image, None, None]:
                 yield from ims
 
-            temp_file2 = str(tmp_path / "temp_generator.webp")
+            temp_file2 = tmp_path / "temp_generator.webp"
             frame1.copy().save(
                 temp_file2,
                 save_all=True,
@@ -121,7 +121,7 @@ def test_timestamp_and_duration(tmp_path: Path) -> None:
     """
 
     durations = [0, 10, 20, 30, 40]
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
     with Image.open("Tests/images/anim_frame1.webp") as frame1:
         with Image.open("Tests/images/anim_frame2.webp") as frame2:
             frame1.save(
@@ -147,7 +147,7 @@ def test_timestamp_and_duration(tmp_path: Path) -> None:
 
 
 def test_float_duration(tmp_path: Path) -> None:
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
     with Image.open("Tests/images/iss634.apng") as im:
         assert im.info["duration"] == 70.0
 
@@ -165,7 +165,7 @@ def test_seeking(tmp_path: Path) -> None:
     """
 
     dur = 33
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
     with Image.open("Tests/images/anim_frame1.webp") as frame1:
         with Image.open("Tests/images/anim_frame2.webp") as frame2:
             frame1.save(
@@ -203,10 +203,10 @@ def test_alpha_quality(tmp_path: Path) -> None:
     with Image.open("Tests/images/transparent.png") as im:
         first_frame = Image.new("L", im.size)
 
-        out = str(tmp_path / "temp.webp")
+        out = tmp_path / "temp.webp"
         first_frame.save(out, save_all=True, append_images=[im])
 
-        out_quality = str(tmp_path / "quality.webp")
+        out_quality = tmp_path / "quality.webp"
         first_frame.save(
             out_quality, save_all=True, append_images=[im], alpha_quality=50
         )
diff --git a/Tests/test_file_webp_lossless.py b/Tests/test_file_webp_lossless.py
index 80429715e..5eaa4f599 100644
--- a/Tests/test_file_webp_lossless.py
+++ b/Tests/test_file_webp_lossless.py
@@ -13,7 +13,7 @@ RGB_MODE = "RGB"
 
 
 def test_write_lossless_rgb(tmp_path: Path) -> None:
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
 
     hopper(RGB_MODE).save(temp_file, lossless=True)
 
diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py
index 565824687..3de412b83 100644
--- a/Tests/test_file_webp_metadata.py
+++ b/Tests/test_file_webp_metadata.py
@@ -149,7 +149,7 @@ def test_write_animated_metadata(tmp_path: Path) -> None:
     exif_data = b"<exif_data>"
     xmp_data = b"<xmp_data>"
 
-    temp_file = str(tmp_path / "temp.webp")
+    temp_file = tmp_path / "temp.webp"
     with Image.open("Tests/images/anim_frame1.webp") as frame1:
         with Image.open("Tests/images/anim_frame2.webp") as frame2:
             frame1.save(
diff --git a/Tests/test_file_wmf.py b/Tests/test_file_wmf.py
index 6a5cb69dd..ecef89fdb 100644
--- a/Tests/test_file_wmf.py
+++ b/Tests/test_file_wmf.py
@@ -59,7 +59,7 @@ def test_register_handler(tmp_path: Path) -> None:
     WmfImagePlugin.register_handler(handler)
 
     im = hopper()
-    tmpfile = str(tmp_path / "temp.wmf")
+    tmpfile = tmp_path / "temp.wmf"
     im.save(tmpfile)
     assert handler.methodCalled
 
@@ -94,6 +94,6 @@ def test_load_set_dpi() -> None:
 def test_save(ext: str, tmp_path: Path) -> None:
     im = hopper()
 
-    tmpfile = str(tmp_path / ("temp" + ext))
+    tmpfile = tmp_path / ("temp" + ext)
     with pytest.raises(OSError):
         im.save(tmpfile)
diff --git a/Tests/test_file_xbm.py b/Tests/test_file_xbm.py
index 44dd2541f..154f3dcc0 100644
--- a/Tests/test_file_xbm.py
+++ b/Tests/test_file_xbm.py
@@ -73,7 +73,7 @@ def test_invalid_file() -> None:
 
 def test_save_wrong_mode(tmp_path: Path) -> None:
     im = hopper()
-    out = str(tmp_path / "temp.xbm")
+    out = tmp_path / "temp.xbm"
 
     with pytest.raises(OSError):
         im.save(out)
@@ -81,7 +81,7 @@ def test_save_wrong_mode(tmp_path: Path) -> None:
 
 def test_hotspot(tmp_path: Path) -> None:
     im = hopper("1")
-    out = str(tmp_path / "temp.xbm")
+    out = tmp_path / "temp.xbm"
 
     hotspot = (0, 7)
     im.save(out, hotspot=hotspot)
diff --git a/Tests/test_image.py b/Tests/test_image.py
index 7dfc1d396..26709f407 100644
--- a/Tests/test_image.py
+++ b/Tests/test_image.py
@@ -175,6 +175,13 @@ class TestImage:
             with Image.open(io.StringIO()):  # type: ignore[arg-type]
                 pass
 
+    def test_string(self, tmp_path: Path) -> None:
+        out = str(tmp_path / "temp.png")
+        im = hopper()
+        im.save(out)
+        with Image.open(out) as reloaded:
+            assert_image_equal(im, reloaded)
+
     def test_pathlib(self, tmp_path: Path) -> None:
         with Image.open(Path("Tests/images/multipage-mmap.tiff")) as im:
             assert im.mode == "P"
@@ -187,14 +194,13 @@ class TestImage:
             for ext in (".jpg", ".jp2"):
                 if ext == ".jp2" and not features.check_codec("jpg_2000"):
                     pytest.skip("jpg_2000 not available")
-                temp_file = str(tmp_path / ("temp." + ext))
-                im.save(Path(temp_file))
+                im.save(tmp_path / ("temp." + ext))
 
     def test_fp_name(self, tmp_path: Path) -> None:
-        temp_file = str(tmp_path / "temp.jpg")
+        temp_file = tmp_path / "temp.jpg"
 
         class FP(io.BytesIO):
-            name: str
+            name: Path
 
             if sys.version_info >= (3, 12):
                 from collections.abc import Buffer
@@ -225,7 +231,7 @@ class TestImage:
 
     def test_unknown_extension(self, tmp_path: Path) -> None:
         im = hopper()
-        temp_file = str(tmp_path / "temp.unknown")
+        temp_file = tmp_path / "temp.unknown"
         with pytest.raises(ValueError):
             im.save(temp_file)
 
@@ -245,7 +251,7 @@ class TestImage:
         reason="Test requires opening an mmaped file for writing",
     )
     def test_readonly_save(self, tmp_path: Path) -> None:
-        temp_file = str(tmp_path / "temp.bmp")
+        temp_file = tmp_path / "temp.bmp"
         shutil.copy("Tests/images/rgb32bf-rgba.bmp", temp_file)
 
         with Image.open(temp_file) as im:
@@ -729,7 +735,7 @@ class TestImage:
         # https://github.com/python-pillow/Pillow/issues/835
         # Arrange
         test_file = "Tests/images/hopper.png"
-        temp_file = str(tmp_path / "temp.jpg")
+        temp_file = tmp_path / "temp.jpg"
 
         # Act/Assert
         with Image.open(test_file) as im:
@@ -739,7 +745,7 @@ class TestImage:
                 im.save(temp_file)
 
     def test_no_new_file_on_error(self, tmp_path: Path) -> None:
-        temp_file = str(tmp_path / "temp.jpg")
+        temp_file = tmp_path / "temp.jpg"
 
         im = Image.new("RGB", (0, 0))
         with pytest.raises(ValueError):
@@ -806,7 +812,7 @@ class TestImage:
             assert exif[296] == 2
             assert exif[11] == "gThumb 3.0.1"
 
-            out = str(tmp_path / "temp.jpg")
+            out = tmp_path / "temp.jpg"
             exif[258] = 8
             del exif[274]
             del exif[282]
@@ -828,7 +834,7 @@ class TestImage:
             assert exif[274] == 1
             assert exif[305] == "Adobe Photoshop CC 2017 (Macintosh)"
 
-            out = str(tmp_path / "temp.jpg")
+            out = tmp_path / "temp.jpg"
             exif[258] = 8
             del exif[306]
             exif[274] = 455
@@ -847,7 +853,7 @@ class TestImage:
             exif = im.getexif()
             assert exif == {}
 
-            out = str(tmp_path / "temp.webp")
+            out = tmp_path / "temp.webp"
             exif[258] = 8
             exif[40963] = 455
             exif[305] = "Pillow test"
@@ -869,7 +875,7 @@ class TestImage:
             exif = im.getexif()
             assert exif == {274: 1}
 
-            out = str(tmp_path / "temp.png")
+            out = tmp_path / "temp.png"
             exif[258] = 8
             del exif[274]
             exif[40963] = 455
diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py
index ab2bb7625..1f9ac41fc 100644
--- a/Tests/test_image_convert.py
+++ b/Tests/test_image_convert.py
@@ -118,7 +118,7 @@ def test_trns_p(tmp_path: Path) -> None:
     im = hopper("P")
     im.info["transparency"] = 0
 
-    f = str(tmp_path / "temp.png")
+    f = tmp_path / "temp.png"
 
     im_l = im.convert("L")
     assert im_l.info["transparency"] == 0
@@ -154,7 +154,7 @@ def test_trns_l(tmp_path: Path) -> None:
     im = hopper("L")
     im.info["transparency"] = 128
 
-    f = str(tmp_path / "temp.png")
+    f = tmp_path / "temp.png"
 
     im_la = im.convert("LA")
     assert "transparency" not in im_la.info
@@ -177,7 +177,7 @@ def test_trns_RGB(tmp_path: Path) -> None:
     im = hopper("RGB")
     im.info["transparency"] = im.getpixel((0, 0))
 
-    f = str(tmp_path / "temp.png")
+    f = tmp_path / "temp.png"
 
     im_l = im.convert("L")
     assert im_l.info["transparency"] == im_l.getpixel((0, 0))  # undone
diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py
index 5ff8d5d20..63a372ff4 100644
--- a/Tests/test_image_resize.py
+++ b/Tests/test_image_resize.py
@@ -171,7 +171,7 @@ class TestImagingCoreResize:
         # 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")
+        temp_file = tmp_path / "temp.gif"
         im.save(temp_file)
 
         with Image.open(temp_file) as reloaded:
diff --git a/Tests/test_image_split.py b/Tests/test_image_split.py
index 3385f81f5..43068535e 100644
--- a/Tests/test_image_split.py
+++ b/Tests/test_image_split.py
@@ -45,9 +45,9 @@ def test_split_merge(mode: str) -> None:
 
 def test_split_open(tmp_path: Path) -> None:
     if features.check("zlib"):
-        test_file = str(tmp_path / "temp.png")
+        test_file = tmp_path / "temp.png"
     else:
-        test_file = str(tmp_path / "temp.pcx")
+        test_file = tmp_path / "temp.pcx"
 
     def split_open(mode: str) -> int:
         hopper(mode).save(test_file)
diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py
index 4cce8f180..69533c2f8 100644
--- a/Tests/test_imagefont.py
+++ b/Tests/test_imagefont.py
@@ -124,7 +124,7 @@ def test_render_equal(layout_engine: ImageFont.Layout) -> None:
 
 
 def test_non_ascii_path(tmp_path: Path, layout_engine: ImageFont.Layout) -> None:
-    tempfile = str(tmp_path / ("temp_" + chr(128) + ".ttf"))
+    tempfile = tmp_path / ("temp_" + chr(128) + ".ttf")
     try:
         shutil.copy(FONT_PATH, tempfile)
     except UnicodeEncodeError:
diff --git a/Tests/test_imagesequence.py b/Tests/test_imagesequence.py
index 62f5d50fe..7ae9ea84c 100644
--- a/Tests/test_imagesequence.py
+++ b/Tests/test_imagesequence.py
@@ -10,7 +10,7 @@ from .helper import assert_image_equal, hopper, skip_unless_feature
 
 
 def test_sanity(tmp_path: Path) -> None:
-    test_file = str(tmp_path / "temp.im")
+    test_file = tmp_path / "temp.im"
 
     im = hopper("RGB")
     im.save(test_file)
diff --git a/Tests/test_imagewin_pointers.py b/Tests/test_imagewin_pointers.py
index c23a5c690..e8468e59f 100644
--- a/Tests/test_imagewin_pointers.py
+++ b/Tests/test_imagewin_pointers.py
@@ -88,7 +88,7 @@ if is_win32():
     def test_pointer(tmp_path: Path) -> None:
         im = hopper()
         (width, height) = im.size
-        opath = str(tmp_path / "temp.png")
+        opath = tmp_path / "temp.png"
         imdib = ImageWin.Dib(im)
 
         hdr = BITMAPINFOHEADER()
diff --git a/Tests/test_mode_i16.py b/Tests/test_mode_i16.py
index e26f5d283..b78b7984f 100644
--- a/Tests/test_mode_i16.py
+++ b/Tests/test_mode_i16.py
@@ -44,7 +44,7 @@ def test_basic(tmp_path: Path, mode: str) -> None:
     im_out = im_in.transform((w, h), Image.Transform.EXTENT, (0, 0, w, h))
     verify(im_out)  # transform
 
-    filename = str(tmp_path / "temp.im")
+    filename = tmp_path / "temp.im"
     im_in.save(filename)
 
     with Image.open(filename) as im_out:
diff --git a/Tests/test_pickle.py b/Tests/test_pickle.py
index 2f3e862f5..dde12d80a 100644
--- a/Tests/test_pickle.py
+++ b/Tests/test_pickle.py
@@ -19,7 +19,7 @@ def helper_pickle_file(
     # Arrange
     im: Image.Image
     with Image.open(test_file) as im:
-        filename = str(tmp_path / "temp.pkl")
+        filename = tmp_path / "temp.pkl"
         if mode:
             im = im.convert(mode)
 
@@ -89,7 +89,7 @@ def test_pickle_jpeg() -> None:
 
 def test_pickle_la_mode_with_palette(tmp_path: Path) -> None:
     # Arrange
-    filename = str(tmp_path / "temp.pkl")
+    filename = tmp_path / "temp.pkl"
     with Image.open("Tests/images/hopper.jpg") as img:
         im = img.convert("PA")
 
@@ -153,7 +153,7 @@ def test_pickle_font_string(protocol: int) -> None:
 def test_pickle_font_file(tmp_path: Path, protocol: int) -> None:
     # Arrange
     font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
-    filename = str(tmp_path / "temp.pkl")
+    filename = tmp_path / "temp.pkl"
 
     # Act: roundtrip
     with open(filename, "wb") as f:
diff --git a/Tests/test_psdraw.py b/Tests/test_psdraw.py
index a743d831f..78f5632c5 100644
--- a/Tests/test_psdraw.py
+++ b/Tests/test_psdraw.py
@@ -35,7 +35,7 @@ def test_draw_postscript(tmp_path: Path) -> None:
     # https://pillow.readthedocs.io/en/latest/handbook/tutorial.html#drawing-postscript
 
     # Arrange
-    tempfile = str(tmp_path / "temp.ps")
+    tempfile = tmp_path / "temp.ps"
     with open(tempfile, "wb") as fp:
         # Act
         ps = PSDraw.PSDraw(fp)
diff --git a/Tests/test_shell_injection.py b/Tests/test_shell_injection.py
index 508d89352..f49153f3e 100644
--- a/Tests/test_shell_injection.py
+++ b/Tests/test_shell_injection.py
@@ -35,7 +35,7 @@ class TestShellInjection:
     @pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
     def test_load_djpeg_filename(self, tmp_path: Path) -> None:
         for filename in test_filenames:
-            src_file = str(tmp_path / filename)
+            src_file = tmp_path / filename
             shutil.copy(TEST_JPG, src_file)
 
             with Image.open(src_file) as im:
diff --git a/Tests/test_tiff_ifdrational.py b/Tests/test_tiff_ifdrational.py
index 6df1e4557..42d06b896 100644
--- a/Tests/test_tiff_ifdrational.py
+++ b/Tests/test_tiff_ifdrational.py
@@ -65,7 +65,7 @@ def test_ifd_rational_save(
     monkeypatch: pytest.MonkeyPatch, tmp_path: Path, libtiff: bool
 ) -> None:
     im = hopper()
-    out = str(tmp_path / "temp.tiff")
+    out = tmp_path / "temp.tiff"
     res = IFDRational(301, 1)
 
     monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", libtiff)
diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst
index b0e20fa84..97599ace5 100644
--- a/docs/handbook/image-file-formats.rst
+++ b/docs/handbook/image-file-formats.rst
@@ -93,6 +93,12 @@ DXT1 and DXT5 pixel formats can be read, only in ``RGBA`` mode.
    in ``P`` mode.
 
 
+.. versionadded:: 11.2.0
+   DXT1, DXT3, DXT5, BC2, BC3 and BC5 pixel formats can be saved::
+
+       im.save(out, pixel_format="DXT1")
+
+
 DIB
 ^^^
 
diff --git a/docs/releasenotes/11.2.0.rst b/docs/releasenotes/11.2.0.rst
index f7e644cf3..3e977221e 100644
--- a/docs/releasenotes/11.2.0.rst
+++ b/docs/releasenotes/11.2.0.rst
@@ -66,6 +66,14 @@ libjpeg library, and what version of MozJPEG is being used::
     features.check_feature("mozjpeg")  # True or False
     features.version_feature("mozjpeg")  # "4.1.1" for example, or None
 
+Saving compressed DDS images
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Compressed DDS images can now be saved using a ``pixel_format`` argument. DXT1, DXT3,
+DXT5, BC2, BC3 and BC5 are supported::
+
+    im.save("out.dds", pixel_format="DXT1")
+
 Other Changes
 =============
 
diff --git a/setup.py b/setup.py
index a85731db9..9fac993b1 100644
--- a/setup.py
+++ b/setup.py
@@ -68,6 +68,7 @@ _LIB_IMAGING = (
     "Reduce",
     "Bands",
     "BcnDecode",
+    "BcnEncode",
     "BitDecode",
     "Blend",
     "Chops",
diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py
index be1c7ad5a..a2ae9b148 100644
--- a/src/PIL/DdsImagePlugin.py
+++ b/src/PIL/DdsImagePlugin.py
@@ -420,6 +420,14 @@ class DdsImageFile(ImageFile.ImageFile):
                     self._mode = "RGBA"
                     self.pixel_format = "BC1"
                     n = 1
+                elif dxgi_format in (DXGI_FORMAT.BC2_TYPELESS, DXGI_FORMAT.BC2_UNORM):
+                    self._mode = "RGBA"
+                    self.pixel_format = "BC2"
+                    n = 2
+                elif dxgi_format in (DXGI_FORMAT.BC3_TYPELESS, DXGI_FORMAT.BC3_UNORM):
+                    self._mode = "RGBA"
+                    self.pixel_format = "BC3"
+                    n = 3
                 elif dxgi_format in (DXGI_FORMAT.BC4_TYPELESS, DXGI_FORMAT.BC4_UNORM):
                     self._mode = "L"
                     self.pixel_format = "BC4"
@@ -519,30 +527,68 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
         msg = f"cannot write mode {im.mode} as DDS"
         raise OSError(msg)
 
-    alpha = im.mode[-1] == "A"
-    if im.mode[0] == "L":
-        pixel_flags = DDPF.LUMINANCE
-        rawmode = im.mode
-        if alpha:
-            rgba_mask = [0x000000FF, 0x000000FF, 0x000000FF]
-        else:
-            rgba_mask = [0xFF000000, 0xFF000000, 0xFF000000]
-    else:
-        pixel_flags = DDPF.RGB
-        rawmode = im.mode[::-1]
-        rgba_mask = [0x00FF0000, 0x0000FF00, 0x000000FF]
-
-        if alpha:
-            r, g, b, a = im.split()
-            im = Image.merge("RGBA", (a, r, g, b))
-    if alpha:
-        pixel_flags |= DDPF.ALPHAPIXELS
-    rgba_mask.append(0xFF000000 if alpha else 0)
-
-    flags = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PITCH | DDSD.PIXELFORMAT
+    flags = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT
     bitcount = len(im.getbands()) * 8
-    pitch = (im.width * bitcount + 7) // 8
+    pixel_format = im.encoderinfo.get("pixel_format")
+    args: tuple[int] | str
+    if pixel_format:
+        codec_name = "bcn"
+        flags |= DDSD.LINEARSIZE
+        pitch = (im.width + 3) * 4
+        rgba_mask = [0, 0, 0, 0]
+        pixel_flags = DDPF.FOURCC
+        if pixel_format == "DXT1":
+            fourcc = D3DFMT.DXT1
+            args = (1,)
+        elif pixel_format == "DXT3":
+            fourcc = D3DFMT.DXT3
+            args = (2,)
+        elif pixel_format == "DXT5":
+            fourcc = D3DFMT.DXT5
+            args = (3,)
+        else:
+            fourcc = D3DFMT.DX10
+            if pixel_format == "BC2":
+                args = (2,)
+                dxgi_format = DXGI_FORMAT.BC2_TYPELESS
+            elif pixel_format == "BC3":
+                args = (3,)
+                dxgi_format = DXGI_FORMAT.BC3_TYPELESS
+            elif pixel_format == "BC5":
+                args = (5,)
+                dxgi_format = DXGI_FORMAT.BC5_TYPELESS
+                if im.mode != "RGB":
+                    msg = "only RGB mode can be written as BC5"
+                    raise OSError(msg)
+            else:
+                msg = f"cannot write pixel format {pixel_format}"
+                raise OSError(msg)
+    else:
+        codec_name = "raw"
+        flags |= DDSD.PITCH
+        pitch = (im.width * bitcount + 7) // 8
 
+        alpha = im.mode[-1] == "A"
+        if im.mode[0] == "L":
+            pixel_flags = DDPF.LUMINANCE
+            args = im.mode
+            if alpha:
+                rgba_mask = [0x000000FF, 0x000000FF, 0x000000FF]
+            else:
+                rgba_mask = [0xFF000000, 0xFF000000, 0xFF000000]
+        else:
+            pixel_flags = DDPF.RGB
+            args = im.mode[::-1]
+            rgba_mask = [0x00FF0000, 0x0000FF00, 0x000000FF]
+
+            if alpha:
+                r, g, b, a = im.split()
+                im = Image.merge("RGBA", (a, r, g, b))
+        if alpha:
+            pixel_flags |= DDPF.ALPHAPIXELS
+        rgba_mask.append(0xFF000000 if alpha else 0)
+
+        fourcc = D3DFMT.UNKNOWN
     fp.write(
         o32(DDS_MAGIC)
         + struct.pack(
@@ -557,11 +603,16 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
         )
         + struct.pack("11I", *((0,) * 11))  # reserved
         # pfsize, pfflags, fourcc, bitcount
-        + struct.pack("<4I", 32, pixel_flags, 0, bitcount)
+        + struct.pack("<4I", 32, pixel_flags, fourcc, bitcount)
         + struct.pack("<4I", *rgba_mask)  # dwRGBABitMask
         + struct.pack("<5I", DDSCAPS.TEXTURE, 0, 0, 0, 0)
     )
-    ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, rawmode)])
+    if fourcc == D3DFMT.DX10:
+        fp.write(
+            # dxgi_format, 2D resource, misc, array size, straight alpha
+            struct.pack("<5I", dxgi_format, 3, 0, 0, 1)
+        )
+    ImageFile._save(im, fp, [ImageFile._Tile(codec_name, (0, 0) + im.size, 0, args)])
 
 
 def _accept(prefix: bytes) -> bool:
diff --git a/src/PIL/GimpPaletteFile.py b/src/PIL/GimpPaletteFile.py
index 1b7a394c0..0f079f457 100644
--- a/src/PIL/GimpPaletteFile.py
+++ b/src/PIL/GimpPaletteFile.py
@@ -18,8 +18,6 @@ from __future__ import annotations
 import re
 from typing import IO
 
-from ._binary import o8
-
 
 class GimpPaletteFile:
     """File handler for GIMP's palette format."""
@@ -27,13 +25,12 @@ class GimpPaletteFile:
     rawmode = "RGB"
 
     def __init__(self, fp: IO[bytes]) -> None:
-        palette = [o8(i) * 3 for i in range(256)]
-
         if not fp.readline().startswith(b"GIMP Palette"):
             msg = "not a GIMP palette file"
             raise SyntaxError(msg)
 
-        for i in range(256):
+        palette: list[int] = []
+        for _ in range(256):
             s = fp.readline()
             if not s:
                 break
@@ -45,14 +42,14 @@ class GimpPaletteFile:
                 msg = "bad palette file"
                 raise SyntaxError(msg)
 
-            v = tuple(map(int, s.split()[:3]))
-            if len(v) != 3:
+            v = s.split(maxsplit=3)
+            if len(v) < 3:
                 msg = "bad palette entry"
                 raise ValueError(msg)
 
-            palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2])
+            palette += (int(v[i]) for i in range(3))
 
-        self.palette = b"".join(palette)
+        self.palette = bytes(palette)
 
     def getpalette(self) -> tuple[bytes, str]:
         return self.palette, self.rawmode
diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py
index a751038c3..1cdf835b4 100644
--- a/src/PIL/TiffImagePlugin.py
+++ b/src/PIL/TiffImagePlugin.py
@@ -1612,6 +1612,10 @@ class TiffImageFile(ImageFile.ImageFile):
                     raise ValueError(msg)
                 w = tilewidth
 
+            if w == xsize and h == ysize and self._planar_configuration != 2:
+                # Every tile covers the image. Only use the last offset
+                offsets = offsets[-1:]
+
             for offset in offsets:
                 if x + w > xsize:
                     stride = w * sum(bps_tuple) / 8  # bytes per line
@@ -1634,11 +1638,11 @@ class TiffImageFile(ImageFile.ImageFile):
                         args,
                     )
                 )
-                x = x + w
+                x += w
                 if x >= xsize:
                     x, y = 0, y + h
                     if y >= ysize:
-                        x = y = 0
+                        y = 0
                         layer += 1
         else:
             logger.debug("- unsupported data organization")
diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py
index 9e204e5bb..f09ed9191 100644
--- a/src/PIL/WebPImagePlugin.py
+++ b/src/PIL/WebPImagePlugin.py
@@ -239,7 +239,7 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
     cur_idx = im.tell()
     try:
         for ims in [im] + append_images:
-            # Get # of frames in this image
+            # Get number of frames in this image
             nfr = getattr(ims, "n_frames", 1)
 
             for idx in range(nfr):
diff --git a/src/_imaging.c b/src/_imaging.c
index fa38dcc05..330a7eef4 100644
--- a/src/_imaging.c
+++ b/src/_imaging.c
@@ -4041,6 +4041,8 @@ PyImaging_ZipDecoderNew(PyObject *self, PyObject *args);
 
 /* Encoders (in encode.c) */
 extern PyObject *
+PyImaging_BcnEncoderNew(PyObject *self, PyObject *args);
+extern PyObject *
 PyImaging_EpsEncoderNew(PyObject *self, PyObject *args);
 extern PyObject *
 PyImaging_GifEncoderNew(PyObject *self, PyObject *args);
@@ -4109,6 +4111,7 @@ static PyMethodDef functions[] = {
 
     /* Codecs */
     {"bcn_decoder", (PyCFunction)PyImaging_BcnDecoderNew, METH_VARARGS},
+    {"bcn_encoder", (PyCFunction)PyImaging_BcnEncoderNew, METH_VARARGS},
     {"bit_decoder", (PyCFunction)PyImaging_BitDecoderNew, METH_VARARGS},
     {"eps_encoder", (PyCFunction)PyImaging_EpsEncoderNew, METH_VARARGS},
     {"fli_decoder", (PyCFunction)PyImaging_FliDecoderNew, METH_VARARGS},
diff --git a/src/encode.c b/src/encode.c
index 13d5cdaf7..7c365a74f 100644
--- a/src/encode.c
+++ b/src/encode.c
@@ -27,6 +27,7 @@
 
 #include "thirdparty/pythoncapi_compat.h"
 #include "libImaging/Imaging.h"
+#include "libImaging/Bcn.h"
 #include "libImaging/Gif.h"
 
 #ifdef HAVE_UNISTD_H
@@ -350,6 +351,31 @@ get_packer(ImagingEncoderObject *encoder, const char *mode, const char *rawmode)
     return 0;
 }
 
+/* -------------------------------------------------------------------- */
+/* BCN                                                                  */
+/* -------------------------------------------------------------------- */
+
+PyObject *
+PyImaging_BcnEncoderNew(PyObject *self, PyObject *args) {
+    ImagingEncoderObject *encoder;
+
+    char *mode;
+    int n;
+    if (!PyArg_ParseTuple(args, "si", &mode, &n)) {
+        return NULL;
+    }
+
+    encoder = PyImaging_EncoderNew(0);
+    if (encoder == NULL) {
+        return NULL;
+    }
+
+    encoder->encode = ImagingBcnEncode;
+    encoder->state.state = n;
+
+    return (PyObject *)encoder;
+}
+
 /* -------------------------------------------------------------------- */
 /* EPS                                                                  */
 /* -------------------------------------------------------------------- */
diff --git a/src/libImaging/BcnEncode.c b/src/libImaging/BcnEncode.c
new file mode 100644
index 000000000..2bad73b92
--- /dev/null
+++ b/src/libImaging/BcnEncode.c
@@ -0,0 +1,298 @@
+/*
+ * The Python Imaging Library
+ *
+ * encoder for DXT1-compressed data
+ *
+ * Format documentation:
+ *   https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt
+ *
+ */
+
+#include "Imaging.h"
+
+typedef struct {
+    UINT8 color[3];
+} rgb;
+
+typedef struct {
+    UINT8 color[4];
+} rgba;
+
+static rgb
+decode_565(UINT16 x) {
+    rgb item;
+    int r, g, b;
+    r = (x & 0xf800) >> 8;
+    r |= r >> 5;
+    item.color[0] = r;
+    g = (x & 0x7e0) >> 3;
+    g |= g >> 6;
+    item.color[1] = g;
+    b = (x & 0x1f) << 3;
+    b |= b >> 5;
+    item.color[2] = b;
+    return item;
+}
+
+static UINT16
+encode_565(rgba item) {
+    UINT8 r, g, b;
+    r = item.color[0] >> (8 - 5);
+    g = item.color[1] >> (8 - 6);
+    b = item.color[2] >> (8 - 5);
+    return (r << (5 + 6)) | (g << 5) | b;
+}
+
+static void
+encode_bc1_color(Imaging im, ImagingCodecState state, UINT8 *dst, int separate_alpha) {
+    int i, j, k;
+    UINT16 color_min = 0, color_max = 0;
+    rgb color_min_rgb, color_max_rgb;
+    rgba block[16], *current_rgba;
+
+    // Determine the min and max colors in this 4x4 block
+    int first = 1;
+    int transparency = 0;
+    for (i = 0; i < 4; i++) {
+        for (j = 0; j < 4; j++) {
+            current_rgba = &block[i + j * 4];
+
+            int x = state->x + i * im->pixelsize;
+            int y = state->y + j;
+            if (x >= state->xsize * im->pixelsize || y >= state->ysize) {
+                // The 4x4 block extends past the edge of the image
+                for (k = 0; k < 3; k++) {
+                    current_rgba->color[k] = 0;
+                }
+                continue;
+            }
+
+            for (k = 0; k < 3; k++) {
+                current_rgba->color[k] =
+                    (UINT8)im->image[y][x + (im->pixelsize == 1 ? 0 : k)];
+            }
+            if (separate_alpha) {
+                if ((UINT8)im->image[y][x + 3] == 0) {
+                    current_rgba->color[3] = 0;
+                    transparency = 1;
+                    continue;
+                } else {
+                    current_rgba->color[3] = 1;
+                }
+            }
+
+            UINT16 color = encode_565(*current_rgba);
+            if (first || color < color_min) {
+                color_min = color;
+            }
+            if (first || color > color_max) {
+                color_max = color;
+            }
+            first = 0;
+        }
+    }
+
+    if (transparency) {
+        *dst++ = color_min;
+        *dst++ = color_min >> 8;
+    }
+    *dst++ = color_max;
+    *dst++ = color_max >> 8;
+    if (!transparency) {
+        *dst++ = color_min;
+        *dst++ = color_min >> 8;
+    }
+
+    color_min_rgb = decode_565(color_min);
+    color_max_rgb = decode_565(color_max);
+    for (i = 0; i < 4; i++) {
+        UINT8 l = 0;
+        for (j = 3; j > -1; j--) {
+            current_rgba = &block[i * 4 + j];
+            if (transparency && !current_rgba->color[3]) {
+                l |= 3 << (j * 2);
+                continue;
+            }
+
+            float distance = 0;
+            int total = 0;
+            for (k = 0; k < 3; k++) {
+                float denom =
+                    (float)abs(color_max_rgb.color[k] - color_min_rgb.color[k]);
+                if (denom != 0) {
+                    distance +=
+                        abs(current_rgba->color[k] - color_min_rgb.color[k]) / denom;
+                    total += 1;
+                }
+            }
+            if (total == 0) {
+                continue;
+            }
+            if (transparency) {
+                distance *= 4 / total;
+                if (distance < 1) {
+                    // color_max
+                } else if (distance < 3) {
+                    l |= 2 << (j * 2);  // 1/2 * color_min + 1/2 * color_max
+                } else {
+                    l |= 1 << (j * 2);  // color_min
+                }
+            } else {
+                distance *= 6 / total;
+                if (distance < 1) {
+                    l |= 1 << (j * 2);  // color_min
+                } else if (distance < 3) {
+                    l |= 3 << (j * 2);  // 1/3 * color_min + 2/3 * color_max
+                } else if (distance < 5) {
+                    l |= 2 << (j * 2);  // 2/3 * color_min + 1/3 * color_max
+                } else {
+                    // color_max
+                }
+            }
+        }
+        *dst++ = l;
+    }
+}
+
+static void
+encode_bc2_block(Imaging im, ImagingCodecState state, UINT8 *dst) {
+    int i, j;
+    UINT8 block[16], current_alpha;
+    for (i = 0; i < 4; i++) {
+        for (j = 0; j < 4; j++) {
+            int x = state->x + i * im->pixelsize;
+            int y = state->y + j;
+            if (x >= state->xsize * im->pixelsize || y >= state->ysize) {
+                // The 4x4 block extends past the edge of the image
+                block[i + j * 4] = 0;
+                continue;
+            }
+
+            current_alpha = (UINT8)im->image[y][x + 3];
+            block[i + j * 4] = current_alpha;
+        }
+    }
+
+    for (i = 0; i < 4; i++) {
+        UINT16 l = 0;
+        for (j = 3; j > -1; j--) {
+            current_alpha = block[i * 4 + j];
+            l |= current_alpha << (j * 4);
+        }
+        *dst++ = l;
+        *dst++ = l >> 8;
+    }
+}
+
+static void
+encode_bc3_alpha(Imaging im, ImagingCodecState state, UINT8 *dst, int o) {
+    int i, j;
+    UINT8 alpha_min = 0, alpha_max = 0;
+    UINT8 block[16], current_alpha;
+
+    // Determine the min and max colors in this 4x4 block
+    int first = 1;
+    for (i = 0; i < 4; i++) {
+        for (j = 0; j < 4; j++) {
+            int x = state->x + i * im->pixelsize;
+            int y = state->y + j;
+            if (x >= state->xsize * im->pixelsize || y >= state->ysize) {
+                // The 4x4 block extends past the edge of the image
+                block[i + j * 4] = 0;
+                continue;
+            }
+
+            current_alpha = (UINT8)im->image[y][x + o];
+            block[i + j * 4] = current_alpha;
+
+            if (first || current_alpha < alpha_min) {
+                alpha_min = current_alpha;
+            }
+            if (first || current_alpha > alpha_max) {
+                alpha_max = current_alpha;
+            }
+            first = 0;
+        }
+    }
+
+    *dst++ = alpha_min;
+    *dst++ = alpha_max;
+
+    float denom = (float)abs(alpha_max - alpha_min);
+    for (i = 0; i < 2; i++) {
+        UINT32 l = 0;
+        for (j = 7; j > -1; j--) {
+            current_alpha = block[i * 8 + j];
+            if (!current_alpha) {
+                l |= 6 << (j * 3);
+                continue;
+            } else if (current_alpha == 255) {
+                l |= 7 << (j * 3);
+                continue;
+            }
+
+            float distance =
+                denom == 0 ? 0 : abs(current_alpha - alpha_min) / denom * 10;
+            if (distance < 3) {
+                l |= 2 << (j * 3);  // 4/5 * alpha_min + 1/5 * alpha_max
+            } else if (distance < 5) {
+                l |= 3 << (j * 3);  // 3/5 * alpha_min + 2/5 * alpha_max
+            } else if (distance < 7) {
+                l |= 4 << (j * 3);  // 2/5 * alpha_min + 3/5 * alpha_max
+            } else {
+                l |= 5 << (j * 3);  // 1/5 * alpha_min + 4/5 * alpha_max
+            }
+        }
+        *dst++ = l;
+        *dst++ = l >> 8;
+        *dst++ = l >> 16;
+    }
+}
+
+int
+ImagingBcnEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+    int n = state->state;
+    int has_alpha_channel =
+        strcmp(im->mode, "RGBA") == 0 || strcmp(im->mode, "LA") == 0;
+
+    UINT8 *dst = buf;
+
+    for (;;) {
+        if (n == 5) {
+            encode_bc3_alpha(im, state, dst, 0);
+            dst += 8;
+
+            encode_bc3_alpha(im, state, dst, 1);
+        } else {
+            if (n == 2 || n == 3) {
+                if (has_alpha_channel) {
+                    if (n == 2) {
+                        encode_bc2_block(im, state, dst);
+                    } else {
+                        encode_bc3_alpha(im, state, dst, 3);
+                    }
+                    dst += 8;
+                } else {
+                    for (int i = 0; i < 8; i++) {
+                        *dst++ = 0xff;
+                    }
+                }
+            }
+            encode_bc1_color(im, state, dst, n == 1 && has_alpha_channel);
+        }
+        dst += 8;
+
+        state->x += im->pixelsize * 4;
+
+        if (state->x >= state->xsize * im->pixelsize) {
+            state->x = 0;
+            state->y += 4;
+            if (state->y >= state->ysize) {
+                state->errcode = IMAGING_CODEC_END;
+                break;
+            }
+        }
+    }
+
+    return dst - buf;
+}
diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h
index 0c2d3fc2e..0fc191d15 100644
--- a/src/libImaging/Imaging.h
+++ b/src/libImaging/Imaging.h
@@ -567,6 +567,8 @@ typedef int (*ImagingCodec)(
 extern int
 ImagingBcnDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
 extern int
+ImagingBcnEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int 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);