Skip to content

Add new port: imagemagick image manipulation library#51731

Draft
Greisby wants to merge 2 commits into
microsoft:masterfrom
Greisby:new-imagemagick
Draft

Add new port: imagemagick image manipulation library#51731
Greisby wants to merge 2 commits into
microsoft:masterfrom
Greisby:new-imagemagick

Conversation

@Greisby
Copy link
Copy Markdown
Contributor

@Greisby Greisby commented May 13, 2026

ImageMagick is a widely-used, battle-tested C/C++ library and tool suite for creating, editing, composing, and converting digital images.
It supports hundreds of image formats (JPEG, PNG, TIFF, WebP, HEIC, AVIF, OpenEXR, JPEG XL, …), color management, drawing, compositing, and transforms.

It may be used directly by FFmpeg (via the image2 demuxer/muxer and the overlay filter fallback), Ghostscript interop, and countless image-processing pipelines.


Draft notice: this PR depends on PR #51725 - it will stay in Draft until that PR is merged.


Why this new vcpkg port?

There is currently no official imagemagick port in vcpkg.
This PR adds one from scratch, with full autotools support on Linux/macOS/Windows and specific fixes to make the MSVC/cl.exe toolchain work correctly under MSYS2.

Key additions vs. a naive autotools port:

  • CMake IMPORTED targets (ImageMagick::Magick++, ImageMagick::MagickWand, ImageMagick::MagickCore) with compile-definitions automatically propagated to consumers
  • #warning#pragma message fix for MSVC (cl.exe does not accept #warning)
  • Quantum depth (q8 / q16 / q32) and HDRI as first-class vcpkg features
  • Proper delegate library wiring: every optional format dependency is either an unconditional vcpkg dependency or explicitly disabled - no silent system-library probing
  • A cl_wrapper.sh / lib_wrapper.sh pair that translates GCC-style libtool invocations to MSVC-compatible flags so the standard autotools+libtool flow works with cl.exe

Port contents

Features

The port exposes a rich set of vcpkg features, all wired to explicit --with-* / --without-* configure flags so no uncontrolled system-library discovery can occur.
I think that I didn't forgot any of the dependencies already available in vcpkg.

Quantum depth (mutually exclusive, exactly one must be selected):

Feature Configure flag Default
q8 --with-quantum-depth=8 -
q16 --with-quantum-depth=16 Yes
q32 --with-quantum-depth=32 -

Quantum depth is ABI-breaking: q8, q16, and q32 builds produce incompatible library variants (suffix Q8, Q16HDRI, Q32HDRI, …).
Consumers must be compiled with the same depth.

Pixel processing:

Feature Description Default
hdri High Dynamic Range Imaging (floating-point pixels) Yes
zero-configuration Embed XML config in binary; no runtime XML files -
openmp OpenMP parallel processing (MSVC, GCC; not clang) -

Delegate / format libraries:

Feature Description Default
bzip2 BZip2 compression Yes
lzma LZMA compression Yes
zstd Zstandard compression Yes
jpeg JPEG format (libjpeg-turbo) Yes
png PNG format (libpng) Yes
tiff TIFF format Yes
webp WebP format Yes
lcms Little CMS color management Yes
xml2 XML/SVG support Yes
freetype FreeType font rendering -
fontconfig Font discovery -
openexr OpenEXR HDR format -
openjp2 JPEG 2000 format (openjpeg) -
heif HEIF/HEIC/AVIF format -
jxl JPEG XL format -
raw RAW photo format (libraw) -
jbig JBIG lossless compression -
fftw Discrete Fourier Transform (fftw3) -
pango Complex text layout via Pango -
raqm Complex text layout via libraqm -
rsvg SVG rendering via librsvg -
gvc Graphviz support -
zip Zip archive support -
x11 X Window System (Linux/macOS only) -
uhdr Ultra HDR (libultrahdr, not yet in vcpkg) -

Meta-features (convenience bundles):

Feature Pulls in
modern-formats heif, jxl, webp
professional-formats openexr, openjp2, raw

Patches

Patch Purpose
0001-fix-zstd-pkgconfig-prefix.patch Fix zstd pkg-config prefix so autoconf finds it correctly
0002-fix-fallthrough-msvc-c-mode.patch Force C++ compilation for EMF coder (uses [[fallthrough]])
0003-fix-cppflags-crt-conflict.patch Prevent CRT flags from leaking into CPPFLAGS on MSVC
0004-fix-uhdr-cpp-compat.patch C++ compatibility fix for Ultra HDR delegate
0005-fix-warning-directive-msvc.patch Replace #warning with #pragma message (cl.exe requirement)
0006-fix-winpathscript-init-order.patch Fix Windows path-script initialization order in autotools

CMake integration

The port installs a hand-crafted imagemagick-config.cmake that exposes:

find_package(imagemagick CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE ImageMagick::Magick++)
# Automatically propagates:
#   MAGICKCORE_QUANTUM_DEPTH=16  (or 8/32 from selected feature)
#   MAGICKCORE_HDRI_ENABLE=1     (when hdri feature is on)

Available targets: ImageMagick::MagickCore, ImageMagick::MagickWand, ImageMagick::Magick++.

Platform support

Platform Status Notes
Windows x64 MSVC v143 ✅ tested cl_wrapper.sh + lib_wrapper.sh bridge libtool ↔ cl.exe/lib.exe
Windows x64 clang-cl ✅ tested cl_wrapper.sh + lib_wrapper.sh bridge libtool ↔ cl.exe/lib.exe
Linux x64 gcc. ✅ tested Standard autotools flow
Linux x64 clang. ✅ tested Standard autotools flow
macOS arm64 ✅ tested Standard autotools flow

I rely on the CIs of vcpkg to test the others…


  • Changes comply with the maintainer guide.
  • The packaged project shows strong association with the chosen port name. Check this box if at least one of the following criteria is met:
    • The project is in Repology: https://repology.org/project//versions
    • The project is amongst the first web search results for "" or " C++". Include a screenshot of the search engine results in the PR.
    • The port name follows the 'GitHubOrg-GitHubRepo' form or equivalent Owner-Project form.
  • Optional dependencies of the build are all controlled by the port. A dependency is controlled if it is declared an unconditional dependency in vcpkg.json, or explicitly disabled through patches or build system arguments such as CMAKE_DISABLE_FIND_PACKAGE_Xxx or VCPKG_LOCK_FIND_PACKAGE
  • The versioning scheme in vcpkg.json matches what upstream says.
  • The license declaration in vcpkg.json matches what upstream says.
  • The installed as the "copyright" file matches what upstream says.
  • The source code of the component installed comes from an authoritative source.
  • The generated "usage text" is brief and accurate. See adding-usage for context. Don't add a usage file if the automatically generated usage is correct.
  • The version database is fixed by rerunning ./vcpkg x-add-version --all and committing the result.
  • Exactly one version is added in each modified versions file.

@talregev
Copy link
Copy Markdown
Contributor

talregev commented May 13, 2026

We have GraphicsMagick port.
These ports can coexist? Are they both have the same libraries files names?

Note for maintainers to check that.

@dg0yt
Copy link
Copy Markdown
Contributor

dg0yt commented May 13, 2026

Are these PRs assisted by AI? Too many at once may discourage good reviews.

@Greisby
Copy link
Copy Markdown
Contributor Author

Greisby commented May 13, 2026

Are these PRs assisted by AI? Too many at once may discourage good reviews.

For this one, yes, heavily.
Getting it to build successfully on every platform was quite painful, and I leaned on AI assistance to navigate the autotools/libtool/MSVC interaction.

Some context on the timing: I've been maintaining a private overlay of these dependencies for over a month to get my project's full dependency chain building cleanly on both Windows and Linux.
Now that everything is stable, it felt right to upstream the work so others can benefit rather than keep it siloed in my overlay. Hence the burst of PRs.

I've already submitted all the PRs, except the FFmpeg one, with change to enable the twolame and libzvbi options.
I'll send that one after the related ports land, so it doesn't block on missing dependencies.

@Greisby
Copy link
Copy Markdown
Contributor Author

Greisby commented May 13, 2026

We have GraphicsMagick port. These ports can coexist? Are they both have the same libraries files names?

Note for maintainers to check that.

Good question.
Short answer: yes, they can coexist, the library file names are different.
Long answer follows...


Library file names

Component GraphicsMagick ImageMagick
Core GraphicsMagick MagickCore-7.Q(8|16|32)[HDRI]
Wand C API GraphicsMagickWand MagickWand-7.Q(8|16|32)[HDRI]
C++ API GraphicsMagick++ Magick++-7.Q(8|16|32)[HDRI]
pkg-config GraphicsMagick.pc, GraphicsMagickWand.pc, GraphicsMagick++.pc MagickCore.pc, MagickWand.pc, Magick++.pc
CMake target prefix (none upstream) ImageMagick:: (this port)

ImageMagick versions its libraries (-7) and embeds the quantum depth + HDRI flavor in the SONAME (Q16HDRI). GraphicsMagick uses unversioned base names.
There is no file-name collision in lib/, bin/, or lib/pkgconfig/. Headers also live in distinct subdirectories (<GraphicsMagick/...> vs. <MagickCore/...>, <MagickWand/...>, <Magick++/...>).

GraphicsMagick is a fork of ImageMagick (based on ImageMagick 5.5.2), the two diverged in 2002.

  • GraphicsMagick focused on stability, performance, and a smaller, more conservative codebase.
  • ImageMagick has continued evolving aggressively since then, adding many more supported formats, and over the last ~10 years has put significant effort into hardening (~500 CVEs fixed)

ABI/source-level note: although both projects share a common ancestor, their C API symbols are similar but not ABI-compatible.
A single executable should link to one or the other, not both.
As ports installed side-by-side in vcpkg, however, they don't conflict.

Why add ImageMagick when GraphicsMagick already exists?

In short: ImageMagick supports many more formats, and ships configurable runtime policies to reduce attack surface (e.g. disabling scripted/risky coders).


I asked Copilot to put together a detailed argument and side-by-side comparison so the rationale and trade-offs are spelled out clearly.


Capability GraphicsMagick ImageMagick (this port)
Last release cadence Slow (2-3 / year) Frequent (multiple per month)
Modern formats: HEIF/HEIC, AVIF partial (read-only) ✅ (heif feature)
JPEG XL ✅ (jxl feature)
WebP Limited ✅ (webp feature)
RAW ✅ (raw feature)
Ultra HDR (uhdr) ✅ (not yet in the port, libultrahdr missing in vcpkg)
HDRI (floating-point pixels) ✅ (hdri feature)
Quantum depth selection Compile-time global Per-build feature (q8/q16/q32) with ABI suffix
OpenMP parallelism Limited ✅ (openmp feature)
Pango / Raqm complex text ✅ (pango, raqm features)
librsvg-based SVG rendering ✅ (rsvg feature)
Ghostscript / EMF / EPS coders Partial
C++ API (Magick++) Older API surface Modern, actively maintained
FFmpeg image2 interop n/a Used by FFmpeg consumers

Security posture

ImageMagick has been one of the most heavily audited C image libraries since the "ImageTragick" disclosures of 2016 (CVE-2016-3714 and follow-ups).
The project has since:

  • Established a dedicated security team and a formal disclosure policy
  • Integrated continuous fuzzing via OSS-Fuzz (since 2017)
  • Introduced policy.xml to let deployments restrict coders, resource limits, and risky operations at runtime
  • Rewritten core parsers and the pixel cache in the 7.x branch, eliminating many legacy issue classes

The result is a steady downward trend in published CVEs: from ~80 in 2016 down to fewer than 10/year over the last couple of years, despite the codebase growing and supporting more formats than ever.

This sustained hardening effort is one of the main reasons ImageMagick remains the de-facto choice for server-side image processing.

Personal context

I originally based my project on the existing graphicsmagick port.
I switched to ImageMagick because I hit several of the limitations above (modern format support and HDRI being the main ones).

The migration of my application code was painless - almost everything compiled unchanged once I switched the include paths and link targets, because the high-level Magick++ API is very close to GraphicsMagick's equivalent. Producing the port itself, on the other hand, was the hard part (autotools + libtool + MSVC was a long fight).

So users currently on graphicsmagick who need newer formats can switch with minimal friction, and those who don't need them can stay on the leaner graphicsmagick port.

In short: the two ports serve overlapping but distinct audiences, and they install cleanly side-by-side.

@dg0yt
Copy link
Copy Markdown
Contributor

dg0yt commented May 14, 2026

It is not enough to have different library names. vcpkg also demands different symbol names due to msbuild "autolinking".
https://learn.microsoft.com/en-us/vcpkg/contributing/maintainer-guide#ports-must-install-simultaneously

@dg0yt
Copy link
Copy Markdown
Contributor

dg0yt commented May 14, 2026

For this one, yes, heavily.
Getting it to build successfully on every platform was quite painful, and I leaned on AI assistance to navigate the autotools/libtool/MSVC interaction.

Thanks for context.

@Greisby
Copy link
Copy Markdown
Contributor Author

Greisby commented May 14, 2026

It is not enough to have different library names. vcpkg also demands different symbol names due to msbuild "autolinking". https://learn.microsoft.com/en-us/vcpkg/contributing/maintainer-guide#ports-must-install-simultaneously

I must say that I don't understand this point.
They don't have any conflicting files, and there are no #pragma comment(lib,...) in the headers either. None of them would anyway pull the libraries of the other.
You mean that, right? - Install symbols and definitions owned by another package
Can you explain, please?

@dg0yt
Copy link
Copy Markdown
Contributor

dg0yt commented May 14, 2026

Detailed explanations left to Microsoft, but: there is autolinking (everything), and there is conflicting libs being pulled in as transitive usage requirements in a top-level project. (Note that in vcpkg CI, dynamic library linkage only exists for Windows 🙈)

@Greisby
Copy link
Copy Markdown
Contributor Author

Greisby commented May 14, 2026

@dg0yt Thanks for pointing this out.
Linking all the libraries at once will never work.

I ran a full symbol comparison on macOS arm64 (all libs from both packages):

GraphicsMagick ImageMagick
Total exported symbols 4,455 6,292
Direct collisions 2,807
C-API collisions 801
C++ (Magick::) collisions ~2,000

This confirms a real symbol-level conflict - the two ports cannot coexist in the same link domain.

I'd like to raise the question of whether the "successor project" exception could apply here.
While GraphicsMagick is the fork (2002) and ImageMagick the original, the two have diverged to the point where they now serve distinct use cases, but share historical API surface.
I'd like to ask whether a precedent or exception exists for this situation.

Key capabilities exclusive to ImageMagick 7:

  • HDRI pixel pipeline (floating-point quantum) — required for proper HDR tone-mapping workflows
  • Camera RAW support via libraw
  • Ultra HDR / Gain Map (Android 14+ camera output) - not yet in this port
  • HEIF/AVIF/JXL writing (GraphicsMagick supports reading these formats, but not writing)
  • Configurable runtime security & resource usage policies (policy.xml)
  • Broader OpenMP parallelism

I want to be clear: I'm not arguing that GraphicsMagick is unmaintained!
1.3.47 was released just yesterday and the project is impressively active for what is effectively a one-person effort.
But that single-maintainer situation (acknowledged in every release note) does mean the feature gap is structural rather than temporary.
Personally, I wouldn't like to see GraphicsMagick be thrown out in favor of ImageMagick.
I'm really impressed by people that keep a project alive nearly alone, and GM has its own strengths. Until recently, I was happy with it.

I acknowledge the policy issue is real.
I see a few possible paths forward:

  1. Accept ImageMagick under the "successor" exception, noting that users must choose one or the other (which is already the reality at link time)
  2. Publish as a custom registry port (pragmatic, but less discoverable for the community).
    Btw, I didn't even know that custom registries were possible.
    Is there something like a registry of custom vcpkg registries?
  3. (off topic) Discuss whether the policy could allow mutually-exclusive ports with a "conflicts" mechanism (longer-term)

Happy to go with whatever the maintainers prefer.

If the answer is (2), I'll just continue working with my local overlay.
But I don't think I'll set up a custom registry that nobody knows about.

I just wanted to surface the discussion since ImageMagick is arguably the most complete and widely-used image processing library in the C/C++ ecosystem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants