Skip to content

Freeimage

1. What is FreeImage

FreeImage is an open-source, cross-platform C/C++ library for loading, saving, and lightly processing images. Originally started by Hervé Drolon, it focuses on developer-friendly multi-format image I/O, providing a uniform API across 30+ formats including PNG, JPEG, TIFF, BMP, GIF, JPEG 2000, RAW, and HDR.

The latest stable release is 3.18.0 (2018; the community still publishes patches). This project bundles the official binaries under pub/external/freeimage/ with 32-bit / 64-bit DLLs, import libs, and headers.

Typical use cases:

  • Desktop image loading / thumbnail / format conversion tools.
  • TWAIN / scanner projects (this is exactly what this project does).
  • Texture preprocessing pipelines for games / 3D engines.
  • Lightweight front-ends for scientific / HDR imaging.

2. Features

2.1 Formats

Reads and writes (some are read-only):

  • Raster: BMP, PNG, JPEG, JPEG 2000, GIF, TIFF, TARGA, PCX, PSD, ICO, WebP, etc.
  • Vector / metafile: WBMP, XBM, XPM, PFM.
  • HDR / float: HDR (Radiance), EXR (OpenEXR), TIFF Float.
  • Camera RAW: CR2, NEF, ARW, DNG, etc. (via LibRaw / dcraw).
  • Misc: JBIG, KOALA, IFF, SGI, PICT, PNM, ...

About 30+ formats total.

2.2 Pixel / bit depth

  • 1, 4, 8 bpp (palette / grayscale).
  • 16 bpp (555 / 565 / gray / float).
  • 24, 32 bpp (BGR / BGRA).
  • 48, 64 bpp (16-bit RGB / RGBA).
  • Floating point (32 / 96 / 128 bpp).

Logical types (FREE_IMAGE_TYPE): FIT_BITMAP, FIT_UINT16, FIT_INT16, FIT_UINT32, FIT_INT32, FIT_FLOAT, FIT_DOUBLE, FIT_COMPLEX, FIT_RGB16, FIT_RGBA16, FIT_RGBF, FIT_RGBAF.

2.3 Image processing

Not a full image-processing library, but it ships useful primitives:

  • Geometry: FreeImage_Rescale (multiple filters), FreeImage_Rotate, FreeImage_FlipHorizontal/Vertical, FreeImage_Copy, FreeImage_Paste.
  • Color: FreeImage_ConvertTo24Bits, FreeImage_ConvertTo32Bits, FreeImage_ConvertToGreyscale, FreeImage_ConvertToRGBF.
  • Thresholding / dithering: FreeImage_Threshold, FreeImage_Dither (Floyd-Steinberg, Bayer, ...).
  • Color adjustment: AdjustGamma / Brightness / Contrast, Invert.
  • Channels: GetChannel / SetChannel.
  • Palette: GetPalette / SetPalette.
  • DPI metadata: GetDotsPerMeterX/Y, SetDotsPerMeterX/Y.
  • EXIF / IPTC / XMP / GeoTIFF metadata.
  • Multi-page TIFF / GIF / ICO.
  • Memory I/O via FIMEMORY (no filesystem required).

2.4 Resampling filters

Filter Notes
FILTER_BOX Fastest, lowest quality
FILTER_BILINEAR Smooth but blurry
FILTER_BICUBIC General-purpose, slightly sharper
FILTER_BSPLINE Smooth, low ringing
FILTER_CATMULLROM Sharp
FILTER_LANCZOS3 Highest quality, possible ringing

This project uses FILTER_LANCZOS3 for DPI rescaling (see docs/implement_dpi_design.md §4.3).

2.5 Threading

FreeImage has no built-in threading. The API is re-entrant as long as different threads operate on different FIBITMAP instances; concurrent access to the same FIBITMAP must be synchronized by the caller.

3. Characteristics

  • Lightweight: ~3 MB DLL with all main decoders; trimmable.
  • Cross-platform: Windows, Linux, macOS, FreeBSD, Solaris.
  • C-style API: FIBITMAP* handle + FreeImage_* functions; easy bindings.
  • C++ wrapper (FreeImagePlus) is available but rarely used.
  • Plugin architecture: formats registered as FREE_IMAGE_FORMAT plugins, custom formats can be added.
  • Uniform palette model: indexed images all expose RGBQUAD palettes.
  • Full metadata (EXIF / IPTC / XMP / Animation / GeoTIFF).
  • Memory I/O through FIMEMORY for streaming / network use.

4. Comparison

4.1 Candidates

Library Form Use
FreeImage C library + DLL Multi-format I/O + light processing
libpng / libjpeg / libtiff per-format C libs Single-format specialists
stb_image header-only C Minimal loading
OpenCV large C++ lib CV + image processing
ImageMagick / GraphicsMagick C/C++ + CLI Full processing suite
WIC COM Native Windows imaging
Pillow (PIL) Python Python ecosystem
Skia C++ 2D rendering (Chrome)
DevIL C lib Multi-format I/O

4.2 Feature matrix

Aspect FreeImage OpenCV stb_image libpng+jpeg+tiff ImageMagick WIC
Formats 30+ tens 6 (load only) 1 each 100+ 10+
Multi-page (TIFF/GIF) yes partial no TIFF yes yes yes
HDR / float yes yes partial TIFF float yes partial
Metadata (EXIF/XMP/IPTC) yes limited no no yes yes
Cross-platform yes yes yes yes yes Windows only
API complexity medium high very low medium high high (COM)
Binary size ~3 MB tens of MB 0 (header) ~1 MB each ~30 MB system
Commercial-friendly nuanced (§5) yes (Apache 2.0) yes (Public Domain / MIT) yes (each permissive) yes yes (system)
Processing basic rich (CV) none none rich basic
Active maintenance low (patches since 2018) high medium high high high

4.3 Choosing for a scanner project

  • Only need a few major formats: stb_image is simplest.
  • Windows-only, OK with COM: WIC is fastest and dependency-free.
  • Need CV / thresholding / edge detection: OpenCV, but heavy.
  • Need many formats + basic processing + cross-platform + small DLL: FreeImage is the best balance — that's why this project uses it.
  • Need 100% safe commercial story: hand-pick libpng + libjpeg-turbo + libtiff (see §5).

4.4 Performance

  • Per-image load/save: comparable to libpng / libjpeg (FreeImage simply wraps them).
  • Resampling: LANCZOS3 is noticeably slower than OpenCV's SIMD; fine for one-image-per-scan workloads.
  • No internal threading; OpenCV uses TBB / OpenMP internally.

5. License analysis

5.1 Dual license

FreeImage is dual-licensed:

  • FreeImage Public License (FIPL), based on Mozilla Public License 1.1 (MPL 1.1).
  • GPL v2 or v3.

Pick either.

5.2 FIPL highlights

MPL 1.1 is a file-level copyleft:

  • Modifications to FreeImage source files must be published.
  • Applications linking FreeImage may stay closed-source.
  • Distribute the FIPL license notice with your product.
  • No endorsement using contributors' names.

Bottom line: using FreeImage without modifying its source allows closed-source commercial use, provided you carry the notice.

5.3 GPL path

Choosing GPL forces your entire application to be GPL-compatible with full source disclosure. Almost no closed-source commercial product picks this path.

5.4 Internal dependencies

FreeImage statically embeds several decoder libraries; these are where most commercial-license risk lives:

Component License Risk
libpng libpng (BSD-like) low
libjpeg / libjpeg-turbo IJG / BSD low
libtiff BSD-like low
zlib zlib low
OpenJPEG BSD 2-clause low
LibRaw LGPL 2.1 / CDDL / commercial medium (LGPL implies dynamic-linking duties)
OpenEXR BSD 3-clause low
LibWebP BSD-like low
jxrlib BSD-like low

The notable concern is LibRaw: linking it statically may impose LGPL obligations (provide object files for relinking, or link dynamically). If RAW support is not required, build FreeImage from source with LibRaw disabled.

5.5 Commercial checklist

  1. Keep notices: include the FIPL text and FreeImage copyright in About / docs / LICENSE.
    This software uses the FreeImage open source image library.
    See http://freeimage.sourceforge.net for details.
    FreeImage is used under the FreeImage Public License (FIPL), version 1.0.
    
  2. Do not modify FreeImage source if you want to skip publishing changes.
  3. Publish patches if you modify FreeImage.
  4. Decide on LibRaw: disable it if you do not need RAW decoding.
  5. Ship as a DLL: keep FreeImage as a clearly separated dynamic library to avoid boundary debates.
  6. Track updates: FreeImage has slowed since 2018; maintain a private fork for CVE follow-ups if compliance is strict.

5.6 Common misconceptions

  • "FreeImage is free so it's safe commercially" — true if you respect the notice and do not modify source.
  • "I can static-link it into my EXE" — technically possible, but file-level copyleft interpretation is contested; this project uses dynamic linking + notice for safety.
  • "GPL is safer" — no, GPL forces source disclosure of your whole product.

6. Usage in this project

The official prebuilt DLLs live in pub/external/freeimage/. CMakeLists.txt wires them via find_library / target_link_libraries. At runtime FreeImage.dll ships next to the .ds file (see README "Installed files").

Key call sites:

  • Load source image: FreeImage_GetFileTypeU + FreeImage_LoadU.
  • Color / depth: FreeImage_ConvertTo24Bits / FreeImage_ConvertToGreyscale / FreeImage_Threshold.
  • Resize: FreeImage_Rescale(..., FILTER_LANCZOS3).
  • DPI metadata: FreeImage_SetDotsPerMeterX / Y.
  • Save: FreeImage_Save(FIF_PNG | FIF_JPEG | FIF_BMP | FIF_TIFF, ...).
  • Native Transfer DIB: FreeImage_GetWidth / GetHeight / GetBPP / GetScanLine / GetPalette feed directly into BITMAPINFOHEADER.

7. Code samples

Minimal runnable snippets; production code should add full error-handling and resource release.

7.1 Init / shutdown

#include <FreeImage.h>

int main() {
  // Static build needs explicit init; DLL version auto-inits at load.
  // FreeImage_Initialise();

  // ... work ...

  // FreeImage_DeInitialise();
  return 0;
}

7.2 Load an image

FIBITMAP* LoadImage(const wchar_t* path) {
  FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeU(path, 0);
  if (fif == FIF_UNKNOWN) fif = FreeImage_GetFIFFromFilenameU(path);
  if (fif == FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif)) return nullptr;
  return FreeImage_LoadU(fif, path, 0);  // caller frees via FreeImage_Unload
}

7.3 Upscale 2x (Lanczos3)

FIBITMAP* RescaleTwoTimes(FIBITMAP* src) {
  if (!src) return nullptr;
  int w = FreeImage_GetWidth(src);
  int h = FreeImage_GetHeight(src);
  return FreeImage_Rescale(src, w * 2, h * 2, FILTER_LANCZOS3);
}

7.4 Save an image

bool SaveImage(FIBITMAP* bmp, const wchar_t* path, FREE_IMAGE_FORMAT fif) {
  if (!bmp) return false;
  int flags = 0;
  if (fif == FIF_JPEG) flags = JPEG_QUALITYGOOD;  // ~85
  if (fif == FIF_TIFF) flags = TIFF_LZW;
  if (fif == FIF_PNG)  flags = PNG_DEFAULT;
  return FreeImage_SaveU(fif, bmp, path, flags) == TRUE;
}

7.5 Full example: BMP → PNG with 2x upscale and DPI metadata

#include <FreeImage.h>
#include <cstdio>

int wmain(int argc, wchar_t** argv) {
  if (argc < 3) {
    std::wprintf(L"usage: bmp2png <in.bmp> <out.png>\n");
    return 1;
  }
  const wchar_t* in_path  = argv[1];
  const wchar_t* out_path = argv[2];

  // 1. Load BMP. FreeImage detects format by signature; extension is a hint.
  FREE_IMAGE_FORMAT in_fif = FreeImage_GetFileTypeU(in_path, 0);
  if (in_fif == FIF_UNKNOWN) in_fif = FreeImage_GetFIFFromFilenameU(in_path);
  FIBITMAP* src = FreeImage_LoadU(in_fif, in_path, 0);
  if (!src) { std::wprintf(L"failed to load: %ls\n", in_path); return 2; }

  // 2. Normalize to 24-bit BGR to avoid surprises after rescaling.
  FIBITMAP* rgb24 = FreeImage_ConvertTo24Bits(src);
  FreeImage_Unload(src);
  if (!rgb24) { std::wprintf(L"convert to 24-bit failed\n"); return 3; }

  // 3. Upscale 2x with Lanczos3.
  int src_w = FreeImage_GetWidth(rgb24);
  int src_h = FreeImage_GetHeight(rgb24);
  FIBITMAP* scaled = FreeImage_Rescale(rgb24, src_w * 2, src_h * 2,
                                       FILTER_LANCZOS3);
  FreeImage_Unload(rgb24);
  if (!scaled) { std::wprintf(L"rescale failed\n"); return 4; }

  // 4. Write DPI metadata: 300 DPI ~= 300 * 39.37 pixels per meter.
  unsigned ppm = static_cast<unsigned>(300.0 * 39.37);
  FreeImage_SetDotsPerMeterX(scaled, ppm);
  FreeImage_SetDotsPerMeterY(scaled, ppm);

  // 5. Save as PNG.
  BOOL ok = FreeImage_SaveU(FIF_PNG, scaled, out_path, PNG_DEFAULT);
  FreeImage_Unload(scaled);
  if (!ok) { std::wprintf(L"failed to save: %ls\n", out_path); return 5; }

  std::wprintf(L"ok: %ls -> %ls (2x, 300dpi)\n", in_path, out_path);
  return 0;
}

Build (MSVC):

cl /EHsc /W4 bmp2png.cpp /link FreeImage.lib
bmp2png in.bmp out.png

The resulting out.png is the input BMP at 2x size with 300 DPI metadata.

7.6 Memory I/O variant (no filesystem)

FIMEMORY* SaveToMemory(FIBITMAP* bmp, FREE_IMAGE_FORMAT fif) {
  FIMEMORY* mem = FreeImage_OpenMemory();
  FreeImage_SaveToMemory(fif, bmp, mem, 0);
  return mem;  // caller frees with FreeImage_CloseMemory
}

void ReadFromMemory(BYTE* buffer, DWORD size) {
  FIMEMORY* mem = FreeImage_OpenMemory(buffer, size);
  FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(mem, 0);
  FIBITMAP* bmp = FreeImage_LoadFromMemory(fif, mem, 0);
  // ...
  FreeImage_Unload(bmp);
  FreeImage_CloseMemory(mem);
}

Useful for HTTP uploads / database BLOBs.

8. Summary

  • Pros: clean API, many formats, small binary, cross-platform, near-zero ceremony for scanner-style projects.
  • Cons: slow release cadence, no SIMD filters, commercial licensing requires care around LibRaw.
  • In BN Tech Virtual Scanner, FreeImage is the foundation of VirtualScanner: loading, DPI rescaling, pixel-type conversion, and final DIB / file output all run through it. Outside the TWAIN protocol layer, virtually every pixel operation is delegated to FreeImage.