Sharp: Enhancement: expose libvips magicksave, requires v8.7.0

Created on 5 Sep 2018  路  27Comments  路  Source: lovell/sharp

Currently, there's lack of support of .gif format by the library, but it will be supported by underlying libvips in v8.7.0 (see release notes for https://github.com/jcupitt/libvips/releases/tag/v8.7.0-rc1 and https://github.com/jcupitt/libvips/issues/839 libvips magicsave for .gif output).

We integrated sharp in Ghost lately and would be lovely to have gifs support for our image uploads
(https://github.com/TryGhost/Ghost/issues/9848)

Cheers Lovell! And let me know if I could be helpful in testing etc.

enhancement

Most helpful comment

Okay then I think I would wait for it. Libvips 8.8 has save GIF as WebP feature as well. It would be great to have the same in Sharp as well.

All 27 comments

I expect the forthcoming sharp v0.21.0 to provide a prebuilt libvips v8.7.0.

There will need to be a code change in sharp to support the forthcoming *magick save feature of libvips.

The prebuilt libvips binaries provided by sharp do not include *magick. To take advantage, you will need to compile your own libvips with support for *magick and install it globally before installing sharp.

hi @lovell, since the version already released, there are any apis for manipulating (like adding frames, setting gif options) with gif files?

@hbakhtiyor No, not yet. Happy to accept/help with a PR if you're able.

don't know c++

Does this mean if libvips is compiled with *magick, it will work out of the box with sharp? @lovell it would be great if you can elaborate which features are available out of the box and which features will need some code modification in sharp.

@adityapatadia This issue exists to track the future possible work required to expose libvips' magicksave feature; it will not work "out of the box".

Okay then I think I would wait for it. Libvips 8.8 has save GIF as WebP feature as well. It would be great to have the same in Sharp as well.

@lovell Any news on this?

I can try to create a PR as this is currently a blocker for us. However, a small hint to point us into the right direction could really help 馃槈

A possible API to expose vips_magicksave and vips_magicksave_buffer might look like:

sharp(input)
  .magick(format) // POSSIBLE API, NOT YET AVAILABLE
  .toBuffer()

where format is a string such as GIF, as taken from https://imagemagick.org/script/formats.php

However since everyone commenting here is really after GIF output, then an initial and easier to understand API might be:

sharp(input)
  .gif() // POSSIBLE API, NOT YET AVAILABLE
  .toBuffer()

which might also be a tiny bit easier to implement/test too.

Filesystem-based output would also need to be made possible, so the following would need to be made to work:

sharp(input)
  .toFile('out.gif') // POSSIBLE API, NOT YET AVAILABLE

In terms of implementation hints, start by looking at an existing function that controls output format such as png() and see how it sets options and passes them to the C++ code.

@lovell We implement the basic GIF support. It was necessary to install the vips with imagemagick support.

We decided to test it in our product before we create PR but we need to deploy it into aws-lambda and we have a huge problems to compile it properly. So, we tried to replicate vendor build process from https://github.com/lovell/sharp-libvips but without --without-magick flag.

The problem is that it constantly complains about missing wheezy-backports libraries (we even try it fully manually and sharp still fail to process any files, even pngs because of some missing libraries)

So, as we are going to introduce the GIF support, someone will need to compile vendor libs with magick support.

Do you think that you are able to do it for us before we create the PR into sharp repo? 馃檪

In that case, we will have the support for it in vendor but sharp itself will not use it until we introduce the GIF support?

@deftomat Thanks for investigating and working on this.

https://github.com/lovell/sharp/issues/1372#issuecomment-418820964

The prebuilt libvips binaries provided by sharp do not include *magick. To take advantage, you will need to compile your own libvips with support for *magick and install it globally before installing sharp.

The ability to save via *magick will follow the same pattern as other features requiring a custom libvips such as output options relating to mozjpeg or libimagequant.

Thanks, we will figure it out then 馃槈

@deftomat If you have a work-in-progress branch I could take a look at I would love to see where you are at and maybe hack on a it a bit myself

@raphaeleidus
Sure, but right now, I'm on holiday so I can push it next week. 馃槈

@deftomat hope you had a good holiday. If you are back I would love to take a look at your progress

@raphaeleidus
Here you go: https://github.com/deftomat/sharp/commit/f297c6b04a3abde8b5d3930e56e8912475313cd8

I apologise to everyone, who is waiting for a GIF support, that I was still not able to create a proper PR. We spend a lot of time integrating this into our systems and building a custom VIPS with IM support for AWS Lambda is a real pain 馃槥

Anyway, this works for us quite smoothly but there are a few quirks which you need to keep in mind:

  • you need to have vips installed globally in your system before you hit npm install
  • vips needs to have an imagemagick support (on Mac, brew install vips should be enough)
  • vips had an issue with incorrect gif-loop values and I'm not sure if they already release the fix or if vips installed on your system includes it. For now, we are using the hardcoded workaround.

I need to add tests and then, we should be ready for a proper PR. Hopefully this or next week.

Hi all, thanks for working on this issue.

I'm not really a specialist in terms of compiling libs, will somebody tell me exactly what do I have to do to get fully working support for animated gif (taking modification from @deftomat )?
(potentially with frame resize option)

It would be really great to take as an example scenario with fresh ubuntu 16 installation with node 10 on board.

one more thanks for hard working on this

@wojtekelvis Here is an excerpt from Dockerfile we use for our application:

FROM node:10-slim

# Install libraries and programs
RUN true \
  && apt-get update \
  && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      # needed for building
      automake build-essential \
      # libvips image libraries
      libjpeg-dev libtiff-dev libpng-dev libgif-dev librsvg2-dev libpoppler-glib-dev zlib1g-dev fftw3-dev liblcms2-dev \
      libmagickwand-dev libpango1.0-dev  libexif-dev liborc-0.4-dev libwebp-dev \
      # needed to rebuild sharp against global libvips
      python \
      # custom allocator to preserve rss memory
      libjemalloc1 \
  && apt-get autoremove -y \
  && apt-get autoclean \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
  && true

COPY ./lib/vips-8.7.3.tar.gz /tmp/

# Build libvips
RUN true\
  && cd /tmp \
  && tar zxvf vips-8.7.3.tar.gz \
  && cd /tmp/vips-8.7.3 \
  && ./configure --enable-debug=no $1 \
  && make -j4 \
  && make install \
  && ldconfig \
  && rm -rf /tmp/* /var/tmp/* \
  true

# Change memory allocator to avoid rss leaks
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1

You need to download vips sources from here and put them in ./lib directory relative to Dockerfile:
https://github.com/libvips/libvips/releases
And probably change filename of vips in dockerfile as you want 8.8.x instead of 8.7.3.
Copy or mount your project in that docker container and then sharp installed with npm or yarn should build against system-installed libvips.
Libjemalloc is optional, and you can play around with other library dependencies.

@OJezu thank you very much!
with your dockerfile was able to build without problems image with vips-8.8.0,
using @deftomat version of sharp together with my custom build vips on animated GIF still receiving version not animated, basically same results as with normal sharp version.
try several version of usage but no luck so far.
Add a little logs to pipeline.cc:782 to be sure that gif function is fired, so confirmed that it is really invoked.
Can someone give me hand how to or what to check further? thanks

@wojtekelvis when you create the sharp instance pass in {pages: -1} so it loads all the frames not just the first one. var image = sharp(imageBufferOrFileName, {pages: -1});
at that point it should treat it as an animated gif

Also, keep in mind that VIPS is using ImageMagick to save GIFs. So, ImageMagick must be available before you build the VIPS.

@raphaeleidus thanks for suggests ,but what I'm currently trying to do is to create a readable stream and then pipe it to sharp. In this scenario first param for constructor which is input have to be string or buffer which is not the case. Do you have any solution to this ? or maybe Im missing something really easy.

@deftomat thanks for remind, using dockerfile attached above by @OJezu so from what I see, there is a plenty of dependencies install in first RUN, do I have to add something more to this to be able to get working animated GIF ?

@wojtekelvis
Well, you need to install imagemagick. Probably something like: apt-get install imagemagick.

I'm not sure if libmagickwand-dev is enough (maybe yes 馃槈)

@deftomat
those are libraries installed with image above:
/usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.a
/usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so
/usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.so.3.0.0
/usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.a
/usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.so
/usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.la
/usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.3.0.0
/usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.so.3
/usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.la
/usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.3

hm, was able to create animated gif! hurra

my simple scenario looks like this:

const pipeline = util.promisify(stream.pipeline);
const readStream = fs.createReadStream(file);
const transformer = sharp(undefined, { pages: -1 }); // hacky way to be able to create it with stream.
const write = fs.createWriteStream(out);
await pipeline(readStream, transformer, write);

but
this work well for all exept GIF where its seems that from 700KB GIF after sharp transformation, it has around 1,7MB.
not to mentioned time which increased significantly.

Is there something I can do to speed this up ?
And final question about resizing to @deftomat, as I understand current version of your changes do not support resizing gif's ?
adding .resize({width ,height, fit}) to transformer results in something really wired, like mixing frames.

@wojtekelvis

Well, currently, we are loading the image just like a toilet paper (VIPS limitation). So, frames are joined into one big image.

To do any transformations, you need to extract each frame (sharp.extract), transform/resize it and then join (sharp.composite) them back into one big image.

Then, when you are saving it with a proper pageHeight, the resulting image will look as expected and it will have a proper number of frames.

To be honest, I'm not sure if we even want to support simple resize operation as extract/composite combination provides an infinite amount of flexibility. Even adding/removing the frame is easily doable as you are working with one big image.

After all these discussion, I think we still don't have a reliable way to resize GIF via sharp. It's also hard to convert GIF images to WebP in a reliable way via Sharp. Currently only reliable way to process GIF images is via gifsicle.

We have created this module to resize GIF files: https://www.npmjs.com/package/@gumlet/gif-resize

I think it would still be hugely beneficial if we can properly add support for GIF in sharp. If someone guides us on how to implement it, may be we can spend some time on this.

Support for WEBP & GIF animations: https://github.com/lovell/sharp/pull/2012

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaekunchoi picture jaekunchoi  路  3Comments

tomercagan picture tomercagan  路  3Comments

emmtte picture emmtte  路  3Comments

zhump picture zhump  路  3Comments

natural-law picture natural-law  路  3Comments