Library / SDK
syoyo/tinyexr avatar
syoyo/tinyexr

tinyexr: OpenEXR reading and writing as a small embeddable C library

Tiny EXR image loader/saver library

837 stars172 forksCBSD-3-Clause

At a glance

What is it?
tinyexr exists so you can load and save .exr files without pulling in the full OpenEXR library, and its v3 line is a pure C11 rewrite with streaming I/O, a freestanding build and spectral images. The catch is that the project runs on a sponsorship gate for pull requests, and the newer v3 API is not the battle-tested one.
Who is it for?
Adopt tinyexr v3 if you are embedding EXR reading and writing into a C or C++ application and you need a small dependency footprint, bounded memory, or a freestanding build. Do not adopt it if you need DWAA or DWAB compression, which are intentionally unsupported, or if you need a community to review your changes quickly, because the project accepts pull requests only from one-time sponsors of US$5,000 or more.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Two versions, and the project tells you which one to use

tinyexr is a small library to load and save OpenEXR images, intended to be embedded into your application. It comes in two flavours, and the README is explicit about the direction of travel. v3 is a pure-C11 rewrite with an include/exr.h header and a src/*.c library, described as the current main development line and the recommended version going forward, and it will be the next major release. v1 is the original single-header C++ version, built around tinyexr.h, which the README calls a solid but sunsetting option and, in the comparison table, stable and battle-tested. The tension between those two descriptions is the most important thing to understand before you commit. The v3 line is where the work is going and it has the features you want, including streaming, freestanding support and HTJ2K. The v1 line is what most existing integrations use and it is the one with years of field use behind it. Picking between them is a judgement about risk, not about features.

The codec list explains where the library stops

Both versions read and write NONE, RLE, ZIP, ZIPS, PIZ, PXR24 and B44/B44A. The v3 line adds ZSTD and HTJ2K, and the v1 line instead offers ZFP. Two limits are worth internalising. DWAA and DWAB are intentionally unsupported in v3, which closes off a path to high compression on large files that some production pipelines rely on. And the write codec list is the same as the read list, so if you can read a format you can also write it, which is not true of every EXR library. The dependency story is where v3 pulls ahead. The core has no dependencies, with vendored zstd and libdeflate, and libdeflate is the default on hosted builds and dropped in freestanding and WASM builds. v1 bundles miniz and takes zfp as optional. The zlib backend for ZIP, ZIPS and PXR24 is chosen at build time with DEFLATE=auto, libdeflate or intree, where auto means the vendored libdeflate, and intree builds the dependency-free pure-C codec only. Both codecs link under auto, so exr_zlib_set_backend() can switch at runtime.

Streaming block I/O is the feature v1 simply does not have

The v3 line supports streaming block I/O for bounded working memory, and the comparison table marks it as absent in v1. This is the single most consequential difference for a real application, and it is worth thinking about concretely. An EXR file can be very large, and a deep or tiled image in particular is not something you want to hold entirely in RAM. With block-at-a-time I/O and a callback file I/O interface, a library that embeds tinyexr can work on a file far larger than its own memory budget, which is the difference between a viewer that works on a workstation and one that works on a device. The freestanding and no-libc support follows from the same design, since the core is pure C11 with callback file I/O rather than depending on stdio. That in turn makes the WASM build practical, which is what powers the browser viewer the README links. A C++ library built around a single header with a miniz dependency inside it is simply not going to compile to a freestanding target.

Building it is a make target, not a package manager step

There is no install command to copy from the README, because the project is a source library built with make or CMake, and the repository root carries both a Makefile and a CMakeLists.txt alongside a premake4.lua, a Makefile.gcc-mingw, a Makefile.llvm-mingw and vcbuild.bat for the Windows toolchains. The Makefile documents its own targets in a header comment:

bash
#   make lib        - build the pure-C11 v3 library (build/libtinyexr3.a)
#   make test-c     - build + run the pure-C11 v3 reader unit test (ASan+UBSan)
#   make c11-gate   - compile every src/*.c as strict C11 -Werror (no C++)
#   make fuzz-corpus - replay regression corpus under ASan+UBSan+LSan

The c11-gate target is the interesting one, because it enforces the claim that the library contains no C++. It compiles every file under src/ as strict C11 with warnings as errors, which is a mechanical guarantee rather than a promise in a readme. The unit tests live in test/unit/test_exr_v3.c and run under the sanitizers via make test-c, and make fuzz-corpus replays a regression corpus. There are many more gates in the .PHONY list, including freestanding and WASM targets, several texcomp gates for GPU texture compression, and arm-smoke and host-smoke targets. The project also ships a CI workflow on the release branch, a gitleaks configuration, a clang-format file and an AGENTS.md.

The performance claims are honest about where it loses

The README benchmarks against the reference OpenEXR library, version 4.0-dev, on an idle AMD Ryzen 9 3950X with an asakusa.exr file of 660 by 440, fully in memory, with both libraries pinned to the same thread count, and throughput is measured in megapixels per second. The numbers are not uniformly flattering to tinyexr, which is unusual and worth reading closely. With the dependency-free decode path, tinyexr is faster on the cheap codecs, uncompressed at about 3.4 times and RLE at about 2.5 times, but OpenEXR leads on the compressed family, ZIP at around 1.2 times, PXR24 around 1.8, ZIPS around 2.1, PIZ around 2.7 and HTJ2K between 2.5 and 3 times, because of its libdeflate, tuned PIZ and OpenJPH backends. On encode, tinyexr ties or wins on RLE, PIZ and B44, while OpenEXR is about 1.5 times on ZIP and ZIPS and about 4 times on HTJ2K. The default decode uses libdeflate, and the README states that with the same backend tinyexr meets or beats OpenEXR on the deflate family. On ARM64 the single-thread numbers reach parity with OpenEXR and OpenJPH for HTJ2K with the opt-in M1 scheduler tuning. The full numbers, including multi-threaded cases, are in doc/performance-vs-openexr.md.

Spectral, deep and custom attributes go beyond plain EXR

The v3 line handles far more than a conventional RGB file, and this is where a small library starts to look like a serious one. Image kinds include scanline and tiled in ONE_LEVEL, MIPMAP and RIPMAP form, plus multipart and deep. Deep images are read and written in both scanline and tiled form, where v1 only reads scanline deep data. Spectral images following the JCGT 2021 work and the afichet spectral-exr reference are supported for emissive, reflective and polarised data, with a wavelength-cube load and save API, and the browser viewer adds a wavelength scrubber with CIE to sRGB colour and a per-pixel spectrum plot. Custom header attributes can be read and written and round-trip through a save. Tiled and multipart are supported on both sides. The practical use of this is for film and VFX pipelines and for scientific tools, where an EXR file carries more than colour, and where a library that drops unknown attributes is not usable at all.

Pull requests need a five thousand dollar sponsorship

The pull request policy sits at the top of the README and it is unusual enough that it belongs in an evaluation. Only those who have made a one-time sponsorship contribution of US$5,000 or more are eligible to submit pull requests. That is a paid gate on contributing to an open source project, and it has direct consequences for anyone planning to build on tinyexr. If your plan depends on getting a fix or a feature upstreamed, you cannot do it through a pull request unless you meet the sponsorship threshold. You can still report issues and use the library. There is also a licensing wrinkle in the repository itself, with a LICENSE file, a NOTICE file, a deps/ directory and a third_party/ directory, and a .gitleaks.toml configuration, so the vendored components such as miniz, zstd and libdeflate carry their own terms that the project maintains separately from its BSD-3-Clause grant. The repository is not archived and the last push was on 2026-10-17, with v3.2.0 released on 2026-07-08 after v3.1.0 and v3.0.0 in June 2026.

Editorial conclusion

Adopt tinyexr v3 if you are embedding EXR reading and writing into a C or C++ application and you need a small dependency footprint, bounded memory, or a freestanding build. Do not adopt it if you need DWAA or DWAB compression, which are intentionally unsupported, or if you need a community to review your changes quickly, because the project accepts pull requests only from one-time sponsors of US$5,000 or more. Before you commit, decide between the v3 pure-C11 line and the older single-header C++ version, check that the codec you need is in the read and write list, and read doc/performance-vs-openexr.md, because the benchmark numbers in the README show tinyexr losing to OpenEXR on the compressed codecs when both use the same backend.

Frequently asked questions

What is tinyexr?

It is a small library to load and save OpenEXR (.exr) images, good to embed into your application. It is BSD-3-Clause licensed and comes in two flavours: a v3 pure-C11 rewrite and an older v1 single-header C++ version described as stable and sunsetting.

Which EXR compression formats does tinyexr support?

Both versions read and write NONE, RLE, ZIP, ZIPS, PIZ, PXR24 and B44/B44A. The v3 line adds ZSTD and HTJ2K while v1 offers ZFP, and DWAA and DWAB are intentionally unsupported in v3.

How do I build the tinyexr v3 library?

Run make lib to build build/libtinyexr3.a from the pure-C11 sources, with make test-c running the reader unit test under ASan and UBSan and make c11-gate compiling every src/*.c as strict C11 with warnings as errors.

Can I contribute changes to tinyexr?

The pull request policy states that only those who have made a one-time sponsorship contribution of US$5,000 or more are eligible to submit pull requests. Issues and use of the library are not subject to that condition.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. README
  4. Releases
  5. syoyo/tinyexr on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/syoyo-tinyexr.svg)](https://hysenlabs.com/projects/syoyo-tinyexr)

Was this useful?