Repository: python-pillow/Pillow

Issue:
Current Windows Build/Testing process
What is the current best practices for building and testing Pillow on Windows?
- What compiler works with the precompiled official python releases?
- What versions of the dependencies -- the official tar/zipballs, or installerified versions, or something from cygwin?
- Does buildout or something similar work?
- Are there prebuild images (on azure or aws) that already have the appropriate version of VS installed (assuming that it's the correct compiler)?

@cgohlke?



Discussion:
You can compile on Windows if you download the appropriate SDK: http://msdn.microsoft.com/en-us/dn369240.aspx

And configure these settings:

```
C:\Program Files\Microsoft SDKs\Windows\v7.0>set DISTUTILS_USE_SDK=1
C:\Program Files\Microsoft SDKs\Windows\v7.0>setenv /x64 /release
```

> What compiler works with the precompiled official python releases?

The same compilers used to build the official CPython binaries, i.e. Visual Studio Pro 2008 for versions 2.6 to 3.2 and Visual Studio Pro 2010 for versions 3.3 and 3.4. The compilers are also part of the Microsoft Windows SDK for Windows 7 and .NET Framework 4 and 3.5 SP1. 
Mingw32/64 might work but might require patching Python distutils, creating missing link libraries, and additional build flags.

http://hg.python.org/cpython/file/95fff5a6a276/PCbuild/readme.txt
http://hg.python.org/cpython/file/df2dbeef46da/PCbuild/readme.txt
http://www.microsoft.com/en-us/download/details.aspx?id=3138
http://www.microsoft.com/en-us/download/details.aspx?id=8279

> What versions of the dependencies -- the official tar/zipballs, or installerified versions, or something from cygwin?

Build from source using the official source tar/zipballs and compiler settings compatible with the ones used by Python distutils (/MD, Release)

> Does buildout or something similar work?
> Are there prebuild images (on azure or aws) that already have the appropriate version of VS installed (assuming that it's the correct compiler)?

Don't know.

I was somewhat worried that would be the compiler answer. @cgohlke, I assume that you've got a MSDN or academic license to VS?

It appears that the VS Expresses can compile the 32 bit versions, but unfortunately, 2008 doesn't appear to be available anymore. 

I am almost certain that Pillow and all its C dependencies can be built with the free (and available) Windows SDKs. Visual Studio's IDE is not needed.
This might help: https://github.com/matplotlib/matplotlib/issues/1717#issuecomment-13343859

That's a very helpful thread. When I first looked at the SDKs, it looked like they required VS, but now I see that they do include the compilers. I'll give that a shot. 

I've made some progress following these directions.  So far, I've build for 2.7/x64, just to make sure that I'm getting the build process working end to end for one of the pillow iterations before I bury the poor machine for an hour. 

I'm running on Windows server 2012 x64, the base AMI on amazon EC2, with the 2 sdks installed. Also installed are emacs, setuptools, pip, virtualenv, 4 pythons so far and the github client. The plan is to be able to build/install/test in a virtualenv, or do a windows bdist if desired. 
- lcms2 isn't building, the .sln is coming back as being the wrong version on 2.5 and 2.6. 
- I haven't tried webp yet. 
- some BMP tests are failing, and shouldn't be
- the ghostscript test is failing, and shouldn't be. (it should be skipped)
- cffi, numpy, and the webp tests are skipped due to missing dependencies. 

Hey guys, I am on Windows 8.1 Pro and I have severe difficulties getting it to work.

So I downloaded the [Windows SDK für Windows 8.1](http://msdn.microsoft.com/de-DE/windows/desktop/aa904949.aspx) and installed it with the following settings to `C:\Program Files (x86)\Windows Kits\8.1`

![sdk](https://f.cloud.github.com/assets/2971735/2473913/f546bbf0-b045-11e3-8b53-c54a18730b36.PNG)

I searched the folder and there is no `vcvarsall.bat`, let alone any `.bat` file. :confounded: 

The SDK you need depends on which python you're compiling with, not the OS you're running. 

Python 2.6, 2.7, and 3.2 require Win7 + .NET 3.5,  3.3 requires the Win7 + .NET 4.
I haven't checked on 3.4 yet. 

Looks like 3.4 takes the VC2010 SDK, which is Win7 + .NET 4:  http://www.microsoft.com/en-us/download/details.aspx?id=8279

Status update, based on https://github.com/wiredfool/Pillow/tree/winbuild :
- only slightly closer to having a reproducible windows build process that can run as a CI server for windows. 
- I've got openjpeg 2.0 compiling, but not linking with pillow. Was attempting to get 2.0 running prior to trying 2.1.
- Libz, tiff, jpeg and freetype compile and work fine with pillow. 
- Lcms doesn't compile at all. An error is reported that the solution file is not the correct version. 

I've got the beginnings of a Windows CI at https://ci.appveyor.com/project/wiredfool/pillow/build/2.9.pre.18 .  So far it's only one Python and not all the libraries but it is CI, on windows, and the tests are almost passing. This is based on my winbuild branch which is now merged up to current master. 

I think i'm going to clean up this first and then try to get all the other pythons  and dependencies to build so that we can get at least basic windows CI going as soon as possible.

Great news!

@wiredfool Is it possible to move the main Pillow builds to a python-pillow account, rather than on your own account?

The reason is free plans have only [one concurrent job](http://www.appveyor.com/pricing), which means there can be a bigger backlog for builds coming from both your repo and the main repo.

Two accounts = two build queues.

Here's how:
http://help.appveyor.com/discussions/questions/1154-appveyor-account-for-github-organizations

I'll take a look at that. Another build queue would be good. 

https://ci.appveyor.com/project/Pythonpillow/pillow/history

Remind me why 3.3 isn't activated in AppVeyor? If it was initially disabled for speed, that would have made perfect sense at the time, but the builds are much faster now, consistently outperforming TravisCI.

I guess we just wanted to get the main ones working and merged.

AppVeyor accounts are free: how about just branching and giving it a shot?

Probably speed, and I was working on maximal coverage with minimal implementations.  Now that we're working, mostly, we should go towards more completeness. 

It passes - https://ci.appveyor.com/project/radarhere/pillow/build/3.0.pre.173 - and so I've created a PR.

At the end of [an AppVeyor build](https://ci.appveyor.com/project/python-pillow/pillow/build/job/q5w7sd5cvgqjwm1w), it outputs

> Uploading artifact Pillow-6.1.0.dev0-cp37-cp37m-win32.whl (1,064,340 bytes)...100%
> Uploading artifact Pillow-6.1.0.dev0-py3.7-win32.egg (1,469,913 bytes)...100%
> Deploying using S3 provider
> Uploading artifact "Pillow-6.1.0.dev0-py3.7-win32.egg" (0 bytes) to S3 bucket "pillow-nightly" as "win/5171/Pillow-6.1.0.dev0-py3.7-win32.egg"...

Is the only thing stopping us from using these as our Windows releases the fact that we are missing some dependencies?
I think so, as long as we’re  covering all the windows python versions.  At the time this was done, we were covering a much smaller part of the matrix.
Just to link, #4084 and #4495 improve the situation quite a bit, with the former adding testing and wheel-building support for all optional libraries on GitHub Actions, and the latter making the build script portable and using it on AppVeyor.
@nulano given that #4495 has [significantly improved](https://github.com/python-pillow/Pillow/pull/4495#pullrequestreview-395900016) compiling Pillow on Windows, do you think there's anything left to do here?

Resolving patch:
diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py
--- a/winbuild/build_prepare.py
+++ b/winbuild/build_prepare.py
@@ -1,5 +1,6 @@
 import os
 import platform
+import re
 import shutil
 import struct
 import subprocess
@@ -111,6 +112,11 @@ def cmd_msbuild(
         + "/libjpeg-turbo/files/2.1.4/libjpeg-turbo-2.1.4.tar.gz/download",
         "filename": "libjpeg-turbo-2.1.4.tar.gz",
         "dir": "libjpeg-turbo-2.1.4",
+        "license": ["README.ijg", "LICENSE.md"],
+        "license_pattern": (
+            "(LEGAL ISSUES\n============\n\n.+?)\n\nREFERENCES\n=========="
+            ".+(libjpeg-turbo Licenses\n======================\n\n.+)$"
+        ),
         "build": [
             cmd_cmake(
                 [
@@ -135,6 +141,8 @@ def cmd_msbuild(
         "url": "https://zlib.net/zlib1213.zip",
         "filename": "zlib1213.zip",
         "dir": "zlib-1.2.13",
+        "license": "README",
+        "license_pattern": "Copyright notice:\n\n(.+)$",
         "build": [
             cmd_nmake(r"win32\Makefile.msc", "clean"),
             cmd_nmake(r"win32\Makefile.msc", "zlib.lib"),
@@ -143,39 +151,87 @@ def cmd_msbuild(
         "headers": [r"z*.h"],
         "libs": [r"*.lib"],
     },
-    "libtiff": {
-        "url": "https://download.osgeo.org/libtiff/tiff-4.4.0.tar.gz",
-        "filename": "tiff-4.4.0.tar.gz",
-        "dir": "tiff-4.4.0",
+    "xz": {
+        "url": SF_PROJECTS + "/lzmautils/files/xz-5.2.7.tar.gz/download",
+        "filename": "xz-5.2.7.tar.gz",
+        "dir": "xz-5.2.7",
+        "license": "COPYING",
+        "patch": {
+            r"src\liblzma\api\lzma.h": {
+                "#ifndef LZMA_API_IMPORT": "#ifndef LZMA_API_IMPORT\n#define LZMA_API_STATIC",  # noqa: E501
+            },
+            r"windows\vs2019\liblzma.vcxproj": {
+                # retarget to default toolset (selected by vcvarsall.bat)
+                "<PlatformToolset>v142</PlatformToolset>": "<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>",  # noqa: E501
+                # retarget to latest (selected by vcvarsall.bat)
+                "<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>": "<WindowsTargetPlatformVersion>$(WindowsSDKVersion)</WindowsTargetPlatformVersion>",  # noqa: E501
+            },
+        },
         "build": [
-            cmd_cmake("-DBUILD_SHARED_LIBS:BOOL=OFF"),
-            cmd_nmake(target="clean"),
-            cmd_nmake(target="tiff"),
+            cmd_msbuild(r"windows\vs2019\liblzma.vcxproj", "Release", "Clean"),
+            cmd_msbuild(r"windows\vs2019\liblzma.vcxproj", "Release", "Build"),
+            cmd_mkdir(r"{inc_dir}\lzma"),
+            cmd_copy(r"src\liblzma\api\lzma\*.h", r"{inc_dir}\lzma"),
         ],
-        "headers": [r"libtiff\tiff*.h"],
-        "libs": [r"libtiff\*.lib"],
-        # "bins": [r"libtiff\*.dll"],
+        "headers": [r"src\liblzma\api\lzma.h"],
+        "libs": [r"windows\vs2019\Release\{msbuild_arch}\liblzma\liblzma.lib"],
     },
     "libwebp": {
         "url": "http://downloads.webmproject.org/releases/webp/libwebp-1.2.4.tar.gz",
         "filename": "libwebp-1.2.4.tar.gz",
         "dir": "libwebp-1.2.4",
+        "license": "COPYING",
         "build": [
             cmd_rmdir(r"output\release-static"),  # clean
             cmd_nmake(
                 "Makefile.vc",
                 "all",
-                ["CFG=release-static", "OBJDIR=output", "ARCH={architecture}"],
+                [
+                    "CFG=release-static",
+                    "RTLIBCFG=dynamic",
+                    "OBJDIR=output",
+                    "ARCH={architecture}",
+                    "LIBWEBP_BASENAME=webp",
+                ],
             ),
             cmd_mkdir(r"{inc_dir}\webp"),
             cmd_copy(r"src\webp\*.h", r"{inc_dir}\webp"),
         ],
         "libs": [r"output\release-static\{architecture}\lib\*.lib"],
     },
+    "libtiff": {
+        "url": "https://download.osgeo.org/libtiff/tiff-4.4.0.tar.gz",
+        "filename": "tiff-4.4.0.tar.gz",
+        "dir": "tiff-4.4.0",
+        "license": "COPYRIGHT",
+        "patch": {
+            r"cmake\LZMACodec.cmake": {
+                # fix typo
+                "${{LZMA_FOUND}}": "${{LIBLZMA_FOUND}}",
+            },
+            r"libtiff\tif_lzma.c": {
+                # link against liblzma.lib
+                "#ifdef LZMA_SUPPORT": '#ifdef LZMA_SUPPORT\n#pragma comment(lib, "liblzma.lib")',  # noqa: E501
+            },
+            r"libtiff\tif_webp.c": {
+                # link against webp.lib
+                "#ifdef WEBP_SUPPORT": '#ifdef WEBP_SUPPORT\n#pragma comment(lib, "webp.lib")',  # noqa: E501
+            },
+        },
+        "build": [
+            cmd_cmake("-DBUILD_SHARED_LIBS:BOOL=OFF"),
+            cmd_nmake(target="clean"),
+            cmd_nmake(target="tiff"),
+        ],
+        "headers": [r"libtiff\tiff*.h"],
+        "libs": [r"libtiff\*.lib"],
+        # "bins": [r"libtiff\*.dll"],
+    },
     "libpng": {
-        "url": SF_PROJECTS + "/libpng/files/libpng16/1.6.37/lpng1637.zip/download",
-        "filename": "lpng1637.zip",
-        "dir": "lpng1637",
+        "url": SF_PROJECTS + "/libpng/files/libpng16/1.6.38/lpng1638.zip/download",
+        "filename": "lpng1638.zip",
+        "dir": "lpng1638",
+        "license": "LICENSE",
         "build": [
             # lint: do not inline
             cmd_cmake(("-DPNG_SHARED:BOOL=OFF", "-DPNG_TESTS:BOOL=OFF")),
@@ -186,10 +242,25 @@ def cmd_msbuild(
         "headers": [r"png*.h"],
         "libs": [r"libpng16.lib"],
     },
+    "brotli": {
+        "url": "https://github.com/google/brotli/archive/refs/tags/v1.0.9.tar.gz",
+        "filename": "brotli-1.0.9.tar.gz",
+        "dir": "brotli-1.0.9",
+        "license": "LICENSE",
+        "build": [
+            cmd_cmake(),
+            cmd_nmake(target="clean"),
+            cmd_nmake(target="brotlicommon-static"),
+            cmd_nmake(target="brotlidec-static"),
+            cmd_xcopy(r"c\include", "{inc_dir}"),
+        ],
+        "libs": ["*.lib"],
+    },
     "freetype": {
         "url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.12.1.tar.gz",  # noqa: E501
         "filename": "freetype-2.12.1.tar.gz",
         "dir": "freetype-2.12.1",
+        "license": ["LICENSE.TXT", r"docs\FTL.TXT", r"docs\GPLv2.TXT"],
         "patch": {
             r"builds\windows\vc2010\freetype.vcxproj": {
                 # freetype setting is /MD for .dll and /MT for .lib, we need /MD
@@ -198,13 +269,13 @@ def cmd_msbuild(
                 '<PropertyGroup Label="Globals">': '<PropertyGroup Label="Globals">\n    <WindowsTargetPlatformVersion>$(WindowsSDKVersion)</WindowsTargetPlatformVersion>',  # noqa: E501
             },
             r"builds\windows\vc2010\freetype.user.props": {
-                "<UserDefines></UserDefines>": "<UserDefines>FT_CONFIG_OPTION_SYSTEM_ZLIB;FT_CONFIG_OPTION_USE_PNG;FT_CONFIG_OPTION_USE_HARFBUZZ</UserDefines>",  # noqa: E501
+                "<UserDefines></UserDefines>": "<UserDefines>FT_CONFIG_OPTION_SYSTEM_ZLIB;FT_CONFIG_OPTION_USE_PNG;FT_CONFIG_OPTION_USE_HARFBUZZ;FT_CONFIG_OPTION_USE_BROTLI</UserDefines>",  # noqa: E501
                 "<UserIncludeDirectories></UserIncludeDirectories>": r"<UserIncludeDirectories>{dir_harfbuzz}\src;{inc_dir}</UserIncludeDirectories>",  # noqa: E501
                 "<UserLibraryDirectories></UserLibraryDirectories>": "<UserLibraryDirectories>{lib_dir}</UserLibraryDirectories>",  # noqa: E501
-                "<UserDependencies></UserDependencies>": "<UserDependencies>zlib.lib;libpng16.lib</UserDependencies>",  # noqa: E501
+                "<UserDependencies></UserDependencies>": "<UserDependencies>zlib.lib;libpng16.lib;brotlicommon-static.lib;brotlidec-static.lib</UserDependencies>",  # noqa: E501
             },
             r"src/autofit/afshaper.c": {
-                # link against harfbuzz.lib once it becomes available
+                # link against harfbuzz.lib
                 "#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ": '#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ\n#pragma comment(lib, "harfbuzz.lib")',  # noqa: E501
             },
         },
@@ -225,6 +296,7 @@ def cmd_msbuild(
         "url": SF_PROJECTS + "/lcms/files/lcms/2.13/lcms2-2.13.1.tar.gz/download",
         "filename": "lcms2-2.13.1.tar.gz",
         "dir": "lcms2-2.13.1",
+        "license": "COPYING",
         "patch": {
             r"Projects\VC2022\lcms2_static\lcms2_static.vcxproj": {
                 # default is /MD for x86 and /MT for x64, we need /MD always
@@ -250,8 +322,9 @@ def cmd_msbuild(
         "url": "https://github.com/uclouvain/openjpeg/archive/v2.5.0.tar.gz",
         "filename": "openjpeg-2.5.0.tar.gz",
         "dir": "openjpeg-2.5.0",
+        "license": "LICENSE",
         "build": [
-            cmd_cmake(("-DBUILD_THIRDPARTY:BOOL=OFF", "-DBUILD_SHARED_LIBS:BOOL=OFF")),
+            cmd_cmake(("-DBUILD_CODEC:BOOL=OFF", "-DBUILD_SHARED_LIBS:BOOL=OFF")),
             cmd_nmake(target="clean"),
             cmd_nmake(target="openjp2"),
             cmd_mkdir(r"{inc_dir}\openjpeg-2.5.0"),
@@ -264,6 +337,7 @@ def cmd_msbuild(
         "url": "https://github.com/ImageOptim/libimagequant/archive/e4c1334be0eff290af5e2b4155057c2953a313ab.zip",  # noqa: E501
         "filename": "libimagequant-e4c1334be0eff290af5e2b4155057c2953a313ab.zip",
         "dir": "libimagequant-e4c1334be0eff290af5e2b4155057c2953a313ab",
+        "license": "COPYRIGHT",
         "patch": {
             "CMakeLists.txt": {
                 "if(OPENMP_FOUND)": "if(false)",
@@ -284,6 +358,7 @@ def cmd_msbuild(
         "url": "https://github.com/harfbuzz/harfbuzz/archive/5.3.1.zip",
         "filename": "harfbuzz-5.3.1.zip",
         "dir": "harfbuzz-5.3.1",
+        "license": "COPYING",
         "build": [
             cmd_cmake("-DHB_HAVE_FREETYPE:BOOL=TRUE"),
             cmd_nmake(target="clean"),
@@ -296,6 +371,7 @@ def cmd_msbuild(
         "url": "https://github.com/fribidi/fribidi/archive/v1.0.12.zip",
         "filename": "fribidi-1.0.12.zip",
         "dir": "fribidi-1.0.12",
+        "license": "COPYING",
         "build": [
             cmd_copy(r"{winbuild_dir}\fribidi.cmake", r"CMakeLists.txt"),
             cmd_cmake(),
@@ -406,8 +482,8 @@ def write_script(name, lines):
     name = os.path.join(build_dir, name)
     lines = [line.format(**prefs) for line in lines]
     print("Writing " + name)
-    with open(name, "w") as f:
-        f.write("\n\r".join(lines))
+    with open(name, "w", newline="") as f:
+        f.write(os.linesep.join(lines))
     if verbose:
         for line in lines:
             print("    " + line)
@@ -431,6 +507,21 @@ def build_dep(name):
 
     extract_dep(dep["url"], dep["filename"])
 
+    licenses = dep["license"]
+    if isinstance(licenses, str):
+        licenses = [licenses]
+    license_text = ""
+    for license_file in licenses:
+        with open(os.path.join(sources_dir, dir, license_file)) as f:
+            license_text += f.read()
+    if "license_pattern" in dep:
+        match = re.search(dep["license_pattern"], license_text, re.DOTALL)
+        license_text = "\n".join(match.groups())
+    assert len(license_text) > 50
+    with open(os.path.join(license_dir, f"{dir}.txt"), "w") as f:
+        print(f"Writing license {dir}.txt")
+        f.write(license_text)
+
     for patch_file, patch_list in dep.get("patch", {}).items():
         patch_file = os.path.join(sources_dir, dir, patch_file.format(**prefs))
         with open(patch_file) as f:
@@ -477,6 +568,7 @@ def build_pillow():
         cmd_cd("{pillow_dir}"),
         *prefs["header"],
         cmd_set("DISTUTILS_USE_SDK", "1"),  # use same compiler to build Pillow
+        cmd_set("py_vcruntime_redist", "true"),  # always use /MD, never /MT
         r'"{python_dir}\{python_exe}" setup.py build_ext --vendor-raqm --vendor-fribidi %*',  # noqa: E501
     ]
 
@@ -551,10 +643,12 @@ def build_pillow():
     bin_dir = os.path.join(build_dir, "bin")
     # directory for storing project files
     sources_dir = build_dir + sources_dir
+    # copy dependency licenses to this directory
+    license_dir = os.path.join(build_dir, "license")
 
     shutil.rmtree(build_dir, ignore_errors=True)
     os.makedirs(build_dir, exist_ok=False)
-    for path in [inc_dir, lib_dir, bin_dir, sources_dir]:
+    for path in [inc_dir, lib_dir, bin_dir, sources_dir, license_dir]:
         os.makedirs(path, exist_ok=True)
 
     prefs = {
@@ -572,6 +666,7 @@ def build_pillow():
         "lib_dir": lib_dir,
         "bin_dir": bin_dir,
         "src_dir": sources_dir,
+        "license_dir": license_dir,
         # Compilers / Tools
         **msvs,
         "cmake": "cmake.exe",  # TODO find CMAKE automatically


Test patch:
diff --git a/Tests/fonts/LICENSE.txt b/Tests/fonts/LICENSE.txt
--- a/Tests/fonts/LICENSE.txt
+++ b/Tests/fonts/LICENSE.txt
@@ -8,6 +8,7 @@ TINY5x3GX.ttf, from http://velvetyne.fr/fonts/tiny
 ArefRuqaa-Regular.ttf, from https://github.com/google/fonts/tree/master/ofl/arefruqaa
 ter-x20b.pcf, from http://terminus-font.sourceforge.net/
 BungeeColor-Regular_colr_Windows.ttf, from https://github.com/djrrb/bungee
+OpenSans.woff2, from https://fonts.googleapis.com/css?family=Open+Sans
 
 All of the above fonts are published under the SIL Open Font License (OFL) v1.1 (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL), which allows you to copy, modify, and redistribute them if you need to.
 
diff --git a/Tests/fonts/OpenSans.woff2 b/Tests/fonts/OpenSans.woff2
new file mode 100644
Binary files /dev/null and b/Tests/fonts/OpenSans.woff2 differ
diff --git a/Tests/images/hopper_lzma.tif b/Tests/images/hopper_lzma.tif
new file mode 100644
Binary files /dev/null and b/Tests/images/hopper_lzma.tif differ
diff --git a/Tests/images/hopper_webp.png b/Tests/images/hopper_webp.png
new file mode 100644
Binary files /dev/null and b/Tests/images/hopper_webp.png differ
diff --git a/Tests/images/hopper_webp.tif b/Tests/images/hopper_webp.tif
new file mode 100644
Binary files /dev/null and b/Tests/images/hopper_webp.tif differ
diff --git a/Tests/images/test_woff2.png b/Tests/images/test_woff2.png
new file mode 100644
Binary files /dev/null and b/Tests/images/test_woff2.png differ
diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py
--- a/Tests/test_file_libtiff.py
+++ b/Tests/test_file_libtiff.py
@@ -3,6 +3,7 @@
 import itertools
 import os
 import re
+import sys
 from collections import namedtuple
 
 import pytest
@@ -825,6 +826,44 @@ def test_sampleformat_write(self, tmp_path):
             assert reloaded.mode == "F"
             assert reloaded.getexif()[SAMPLEFORMAT] == 3
 
+    def test_lzma(self, capfd):
+        try:
+            with Image.open("Tests/images/hopper_lzma.tif") as im:
+                assert im.mode == "RGB"
+                assert im.size == (128, 128)
+                assert im.format == "TIFF"
+                im2 = hopper()
+                assert_image_similar(im, im2, 5)
+        except OSError:
+            captured = capfd.readouterr()
+            if "LZMA compression support is not configured" in captured.err:
+                pytest.skip("LZMA compression support is not configured")
+            sys.stdout.write(captured.out)
+            sys.stderr.write(captured.err)
+            raise
+
+    def test_webp(self, capfd):
+        try:
+            with Image.open("Tests/images/hopper_webp.tif") as im:
+                assert im.mode == "RGB"
+                assert im.size == (128, 128)
+                assert im.format == "TIFF"
+                assert_image_similar_tofile(im, "Tests/images/hopper_webp.png", 1)
+        except OSError:
+            captured = capfd.readouterr()
+            if "WEBP compression support is not configured" in captured.err:
+                pytest.skip("WEBP compression support is not configured")
+            if (
+                "Compression scheme 50001 strip decoding is not implemented"
+                in captured.err
+            ):
+                pytest.skip(
+                    "Compression scheme 50001 strip decoding is not implemented"
+                )
+            sys.stdout.write(captured.out)
+            sys.stderr.write(captured.err)
+            raise
+
     def test_lzw(self):
         with Image.open("Tests/images/hopper_lzw.tif") as im:
             assert im.mode == "RGB"
diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py
--- a/Tests/test_imagefont.py
+++ b/Tests/test_imagefont.py
@@ -1063,6 +1063,25 @@ def test_colr_mask(layout_engine):
     assert_image_similar_tofile(im, "Tests/images/colr_bungee_mask.png", 22)
 
 
+def test_woff2(layout_engine):
+    try:
+        font = ImageFont.truetype(
+            "Tests/fonts/OpenSans.woff2",
+            size=64,
+            layout_engine=layout_engine,
+        )
+    except OSError as e:
+        assert str(e) in ("unimplemented feature", "unknown file format")
+        pytest.skip("FreeType compiled without brotli or WOFF2 support")
+
+    im = Image.new("RGB", (350, 100), "white")
+    d = ImageDraw.Draw(im)
+
+    d.text((15, 5), "OpenSans", "black", font=font)
+
+    assert_image_similar_tofile(im, "Tests/images/test_woff2.png", 5)
+
+
 def test_fill_deprecation(font):
     with pytest.warns(DeprecationWarning):
         font.getmask2("Hello world", fill=Image.core.fill)