/imagick

Running ImageMagick wand lib in WASM

Primary LanguageC

imagick

Image Magick Logo

Running ImageMagick wand library in WASM.

Try it here ppyne.github.io/imagick.

Requirements

  • ImageMagick Legacy version 6.9.12-66 (tar.gz present in the repo)
  • libwebp 1.2.4 (optional, tar.gz present in the repo)
  • libjpeg v8c (optional, tar.gz present in the repo)
  • openjpeg 2.5.0 (optional, tar.gz present in the repo)
  • zlib 1.2.12 (optional, tar.gz present in the repo)
  • libpng 1.6.37 (optional, tar.gz present in the repo)
  • for avif and heic support libheif 1.13.0, aom 1.0.0, dav1d 0.7.1, x265 3.4, libde265 1.0.9 (all this is optional, tar.gz archives are present in the repo)
  • FFTW 3.3.10 (optional, tar.gz present in the repo)
  • Emscripten SDK version 3.1.20
  • A Unix like environment (Mac or Linux is fine) with bash
  • Essential GNU building tools like make, cmake, meson, ninja, gcc and pkg-config (and many more...)
  • A web server like Apache2

How to build

Create a directory in the path served by your web server.

Of course, don't forget to run the Emscripten SDK evironment script before doing anything (emsdk/emsdk_env.sh).

Review the content of the script make.sh and adapt it to your project or your environment.

Make the script make.sh executable (chmod +x ./make.sh).

Feel free to add new functions to imagick.c and index.html, and ask for a pull request to make your work available to as many people as possible (MagickWand Image API for C documentation is available here).

And enjoy.

Notes

For conversions, we link ImageMagick against libwepb for full webp support, zlib and libpng for full png support, libjpeg for full jpeg support, openjpeg for full jpeg2000 support and libheif to support avif files. Also it is possible to convert formats like PNG, WEBP or JPEG with JS directly, thanks to the native browser support (See below for an explanation).

Fast Fourier transform is now supported.

We use the Emscripten filesystem (FS) to exchange data between JS and ImageMagick.

For the data exchanges between the browser and the magickwand library, we found convenient to use the native raw ".rgba" ImageMagick file format, which has the same byte order as the JS ImageData.

The imagick.html file present is not very usefull, the most important files are imagick.wasm, imagick.js and index.html.

Since the JS Canvas permits shapes and text drawings natively, we don't see the need to use ImageMagick for this purpose, and we didn't compile IM with the freetype lib.

And yes for many years now we use pure browser JS and jquery, and still do, we are not much exited by the use of Nodejs, or TypeScript... sorry. But feel free to contribute on this part.

Here are the options overview set at compliation time for ImageMagick:

                  Option                        Value
------------------------------------------------------------------------------
Shared libraries  --enable-shared=no  no
Static libraries  --enable-static=yes  yes
Module support    --with-modules=no   no
GNU ld            --with-gnu-ld=yes      yes
Quantum depth     --with-quantum-depth=16       16
High Dynamic Range Imagery
                  --enable-hdri=yes             yes

Install documentation:                          no

Memory allocation library:
  JEMalloc          --with-jemalloc=no          no
  TCMalloc          --with-tcmalloc=no          no
  UMem              --with-umem=no              no

Delegate library configuration:
  BZLIB             --with-bzlib=no             no
  Autotrace         --with-autotrace=no         no
  DJVU              --with-djvu=no              no
  DPS               --with-dps=no               no
  FFTW              --with-fftw=yes             yes
  FLIF              --with-flif=no              no
  FlashPIX          --with-fpx=no               no
  FontConfig        --with-fontconfig=no        no
  FreeType          --with-freetype=no          no
  Ghostscript lib   --with-gslib=no             no
  Graphviz          --with-gvc=no
  HEIC              --with-heic=yes             yes
  JBIG              --with-jbig=no              no
  JPEG v1           --with-jpeg=yes             yes
  JPEG XL           --with-jxl=no               no
  LCMS              --with-lcms=no              no
  LQR               --with-lqr=no               no
  LTDL              --with-ltdl=no              no
  LZMA              --with-lzma=no              no
  Magick++          --with-magick-plus-plus=no  no
  OpenEXR           --with-openexr=no           no
  OpenJP2           --with-openjp2=yes          yes
  PANGO             --with-pango=no             no
  PERL              --with-perl=no              no
  PNG               --with-png=yes              yes
  RAQM              --with-raqm=no              no
  RAW               --with-raw=no               no
  RSVG              --with-rsvg=no              no
  TIFF              --with-tiff=no              no
  WEBP              --with-webp=yes             yes
  WMF               --with-wmf=no               no
  X11               --with-x=no                 no
  XML               --with-xml=no               no
  ZLIB              --with-zlib=yes             yes
  ZSTD              --with-zstd=no              no

wasm-ld is warning us about a function in the x265 library :

wasm-ld: warning: function signature mismatch: x265_cpu_xgetbv
>>> defined as (i32) -> i64 in /opt/local/www/apache2/html/imagick/image_magick/lib/libx265.a(cpu.cpp.o)
>>> defined as (i32, i32, i32) -> void in /opt/local/www/apache2/html/imagick/image_magick/lib/libx265.a(primitives.cpp.o)

It doesn't seem to affect anything about the AVIF format, but may affect HEIC, we haven't done any test yet. Let me know if you found something.

Native browser image format conversion

Here is an example of convertion to PNG thanks to the canvas.

let img = document.querySelector('#my_image');
let canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
img.src = canvas.toDataURL('image/png');

Thanks to this process, you can convert any PNG, JPEG or even WEBP format to another.

The last line can be replaced with this one for JPEG:

img.src = canvas.toDataURL('image/jpeg', 0.8);

where 0.8 is the image quality (0 to 1).

Or with this one for WEBP (with recent browsers only):

img.src = canvas.toDataURL('image/webp', 0.7);

where 0.7 is the image quality (0 to 1).

See the documentation here to learn more.