lovell / sharp

High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, AVIF and TIFF images. Uses the libvips library.
https://sharp.pixelplumbing.com
Apache License 2.0
29.23k stars 1.29k forks source link

Improve density/resolution of vector input images #110

Closed lovell closed 8 years ago

lovell commented 10 years ago

(As originally suggested by @bradisbell in #105.)

libmagick is able to parse vector SVG files as bitmaps but the resolution is poor due to the default 72 (96?) DPI/density setting.

lovell commented 9 years ago

I've added support for density to libvips via https://github.com/jcupitt/libvips/commit/14c8aa33fc0d474c128418e36ef20a04ad3869d5 and will revisit this once it's included in a 7.42.x release.

jcupitt commented 9 years ago

Hi, 7.42 is out now with this feature.

lovell commented 9 years ago

Thanks John, I'll expose this feature after moving to libvips' new C++ bindings.

lookfirst commented 8 years ago

I think I totally need this, or at least something like this. I've got an Adobe Illustrator file that I'm converting to PNG. I need the ability to specify the density for the output PNG.

lookfirst commented 8 years ago

@lovell To be clear, it is a .ai file, not .eps. =) Conversion is done with ghostscript+graphicsmagick

lovell commented 8 years ago

@lookfirst Thanks, I've updated the title accordingly.

lovell commented 8 years ago

Commit fdb27e1 on the mind branch (v0.13.0) adds much-improved support for vector images.

lookfirst commented 8 years ago

@lovell This looks really nice!

jcupitt commented 8 years ago

There's an interesting related issue here: https://github.com/jcupitt/libvips/issues/379

I'll have a stab at a libpoppler loader.

jcupitt commented 8 years ago

... jcupitt/libvips#379 has some benchmarks now, it's up to about 500x (!!???!?!) faster.

What features do you need in a vector graphics loader? Please feel free to add any ideas to the TODO on that issue.

lovell commented 8 years ago

@jcupitt Wow, that's quite an improvement.

SVG is the vector format that has generated the most questions from sharp users. Given poppler's dependency on cairo, would support for loading via librsvg also make sense here?

jcupitt commented 8 years ago

Sure, I think that's a good idea. It should be a fairly simple copy-paste job to make pdfload.c into svgload.c. These dependencies are all optional so I have no problem adding more.

jcupitt commented 8 years ago

... I guess better GIF support is also asked for a lot. I don't know what the best gif library is.

lovell commented 8 years ago

@jcupitt The public domain STB library provides a common API for decoding GIF, PSD and a few others at https://github.com/nothings/stb/blob/master/stb_image.h

jcupitt commented 8 years ago

I don't like the STB stuff, it seems broken by design to me. It makes my skin crawl!

I'll add a note about finding a gif library to the TODO.

jcupitt commented 8 years ago

I had a quick hack at a librsvg reader. This is a simple copy-paste from the new pdfload operator:

https://github.com/jcupitt/libvips/tree/add-librsvg

It's fast! I see:

$ time vipsthumbnail vips-profile.svg 
real    0m0.101s
user    0m0.092s
sys 0m0.012s

vs. git master, still using the libMagick pathway:

$ time vipsthumbnail vips-profile.svg 
real    0m0.207s
user    0m0.252s
sys 0m0.036s

It's not correctly loading from a memory buffer yet, I'm not sure why.

jcupitt commented 8 years ago

OK, fixed it, it seems to work well now.

I think the remaining issue is file type sniffing. At the moment it relies on files ending in .svg and buffers being valid SVG files (it just calls rsvg_handle_new_from_data() on the memory area).

Files not called .svg will be missed, and memory buffers will be very slow to detect, since it will (I think?) parse the whole buffer.

Do you know a good detect-svg rule? I guess first line starts <?xml, second line starts <svg, but that seems rather fragile. The code needs to go in here:

https://github.com/jcupitt/libvips/blob/add-librsvg/libvips/foreign/svgload.c#L366

lovell commented 8 years ago

@jcupitt That's fast, and that's fast!

The <?xml ... declaration is optional in SVG (and in XML at large, although very much recommended). https://github.com/sindresorhus/is-svg/blob/master/index.js provides some hints, e.g. not binary, contains <svg and </svg>

jcupitt commented 8 years ago

Thanks @lovell, I've put something better in. I'll merge to master as soon as CMYK PDFs are sorted out.

lovell commented 8 years ago

v0.13.0 now available, thanks everyone for the comments and help with this.

I'll create a separate issue to take advantage of libvips' new SVG and GIF loaders when v8.3.0 is available.

jcupitt commented 8 years ago

One more related thing: the magickload in git master libvips now has a page parameter you can use to select the page to load of a multi-page document (or the gif frame to load of an animated gif). It gives a very nice speedup for things like PDF.

By default it always picks page zero, I don't know if sharp would need to expose this.

lookfirst commented 8 years ago

@lovell I'm playing with this and I'm a bit confused. I'm trying to read in a .ai file and output a .png file. I'd like the png to be output as 300dpi. Right now, I'm getting 25 dpi for the png file with sharp 0.13.0. Any ideas? Thanks!

    let transform = (width, height, density, toFormat) => {
        return sharp(null, {density: density})
            .resize(width, height)
            .max()
            .withoutEnlargement()
            .toFormat(toFormat);
    };
lovell commented 8 years ago

@lookfirst density refers to *magick's rendering of a bitmap from a vector input.

In your example, this bitmap is then resized. Perhaps temporarily remove the resize operation to see more clearly what *magick is doing.

"I'd like the png to be output as 300dpi"

Once an image is in bitmap form, the DPI is mostly arbitrary - see #96 for why there are only "25" of them :)