Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: expose libvips magicksave, requires v8.7.0 #1372

Open
gargol opened this issue Sep 5, 2018 · 25 comments
Labels

Comments

@gargol
Copy link

@gargol gargol commented Sep 5, 2018

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
(TryGhost/Ghost#9848)

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

@lovell

This comment has been minimized.

Copy link
Owner

@lovell lovell commented Sep 5, 2018

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.

@lovell lovell added the enhancement label Sep 5, 2018
@lovell lovell changed the title Update libvips to 8.7.0 when it comes out of RC Enhancement: expose libvips magicksave, requires v8.7.0 Sep 5, 2018
@hbakhtiyor

This comment has been minimized.

Copy link

@hbakhtiyor hbakhtiyor commented Oct 25, 2018

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

@lovell

This comment has been minimized.

Copy link
Owner

@lovell lovell commented Oct 26, 2018

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

@hbakhtiyor

This comment has been minimized.

Copy link

@hbakhtiyor hbakhtiyor commented Oct 26, 2018

don't know c++

@adityapatadia

This comment has been minimized.

Copy link

@adityapatadia adityapatadia commented Feb 10, 2019

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.

@lovell

This comment has been minimized.

Copy link
Owner

@lovell lovell commented Feb 10, 2019

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

@adityapatadia

This comment has been minimized.

Copy link

@adityapatadia adityapatadia commented Feb 11, 2019

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.

@deftomat

This comment has been minimized.

Copy link

@deftomat deftomat commented Apr 23, 2019

@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 😉

@lovell

This comment has been minimized.

Copy link
Owner

@lovell lovell commented Apr 23, 2019

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.

@deftomat

This comment has been minimized.

Copy link

@deftomat deftomat commented May 8, 2019

@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?

@lovell

This comment has been minimized.

Copy link
Owner

@lovell lovell commented May 8, 2019

@deftomat Thanks for investigating and working on this.

#1372 (comment)

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.

@deftomat

This comment has been minimized.

Copy link

@deftomat deftomat commented May 8, 2019

Thanks, we will figure it out then 😉

@raphaeleidus

This comment has been minimized.

Copy link

@raphaeleidus raphaeleidus commented May 20, 2019

@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

@deftomat

This comment has been minimized.

Copy link

@deftomat deftomat commented May 20, 2019

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

@raphaeleidus

This comment has been minimized.

Copy link

@raphaeleidus raphaeleidus commented May 28, 2019

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

@deftomat

This comment has been minimized.

Copy link

@deftomat deftomat commented May 29, 2019

@raphaeleidus
Here you go: deftomat@f297c6b

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.

@wojtekelvis

This comment has been minimized.

Copy link

@wojtekelvis wojtekelvis commented May 30, 2019

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

@OJezu

This comment has been minimized.

Copy link

@OJezu OJezu commented May 30, 2019

@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.

@wojtekelvis

This comment has been minimized.

Copy link

@wojtekelvis wojtekelvis commented May 30, 2019

@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

@raphaeleidus

This comment has been minimized.

Copy link

@raphaeleidus raphaeleidus commented May 30, 2019

@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

@deftomat

This comment has been minimized.

Copy link

@deftomat deftomat commented May 31, 2019

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

@wojtekelvis

This comment has been minimized.

Copy link

@wojtekelvis wojtekelvis commented May 31, 2019

@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 ?

@deftomat

This comment has been minimized.

Copy link

@deftomat deftomat commented May 31, 2019

@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 😉)

@wojtekelvis

This comment has been minimized.

Copy link

@wojtekelvis wojtekelvis commented May 31, 2019

@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.

@deftomat

This comment has been minimized.

Copy link

@deftomat deftomat commented Jun 4, 2019

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.