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

Plugin to optimize embedded images ? #971

Open
Zulko opened this issue Jun 1, 2018 · 23 comments
Open

Plugin to optimize embedded images ? #971

Zulko opened this issue Jun 1, 2018 · 23 comments

Comments

@Zulko
Copy link

Zulko commented Jun 1, 2018

Hi and thanks for a super-useful project. I have SVGs embedding PNG images (they are represented inline as base64 in the XML) and I want to convert them to JPG to reduce the size of my SVGs. It doesn't seem that thereis a plugin for this. Would you be interested by one ? has this been tried already ?

@paperboyo
Copy link

Just a user here. Images without transparency should be converted to JPGs, but the ones with transparency have to be converted by pngquant to PNG8. This may not be trivial as you would need to be able to tell one from the other and maybe provide options to control both compression levels.

Would be very useful, though!

@GreLI
Copy link
Member

GreLI commented Jun 1, 2018

Yeah, it would be nice, but it's a complex topic. There a lot of optimizers with different optimizations degree and execution time, also they're a hardly depend on image type (low-color graphics compress differently from photo-like, dealing with semitransparency has its own tricks, etc).

Also, it would add extra dependencies, optimizers are binary, so you have to deal with different platforms, bloating dependencies even more, which I'd prefer to avoid, since far not everyone needs it. It more like a constructor for image optimization than a single format optimization like SVGO, so I believe it's out of SVGO's scope.

@Zulko
Copy link
Author

Zulko commented Jun 1, 2018

jimp is a pure-javascript library that can do JPG. My intention is to just try some simple PNG -> JPG optimizer for my own SVG needs. Is it possible to make "external" plugins for SVGO or do plugins have to be hosted in this repository ?

@GreLI
Copy link
Member

GreLI commented Jun 1, 2018

There is no special interface for external plugins, except you can pass functions within config object like

{
    "plugins": [
        /* ... list of SVGO plugin options ... */
        {
            "mySpecialPlugin": {
                "fn": function(data) { /* ... plugin body ... */ }
            }
        }
    ]
}

@paperboyo
Copy link

some simple PNG -> JPG

Related to know where to NOT convert (if there is transparency): jimp-dev/jimp#271. By having a very cursory look at jimp, I can’t tell if it supports pngquant-like PNG8 with 8-bit transparency (PNG32 is too weighty, PNG8 with 1-bit transparency is useless).

@julienboulay
Copy link

Hi, I created a new plugin to optimise png and jpeg embedded in the svg as base64.
It works well for me, decreasing the size of the svg by 50%.
Let me know if it fits your needs

@Zulko
Copy link
Author

Zulko commented Jun 13, 2018

I went with my own solution (upstream of SVGO) and it works well for me too, but I'd still be interested in seing your solution (and even better if it comes included in SVGO), as a SVGO plugin would be cleaner.

@julienboulay
Copy link

You can try it by using
npm i -g git+ssh://[email protected]/julienboulay/svgo.git
then
svgo [OPTIONS] [ARGS]
Some options can be passed to svgo to configure pngquant and jpegtran

@Zulko
Copy link
Author

Zulko commented Jun 13, 2018

It seems that your solution relies on external non-JS software though, which I really want to avoid in my project. The ideal solution would be pure-js, but also synchronous so that it can be a SVGO plugin. So far I couldn't find any library that does that.

@GreLI
Copy link
Member

GreLI commented Jun 13, 2018

There is no JS-based bitmap image optimizers I'm aware of. It's even doesn't make sense. It'd same as binary optimizers but with drawbacks.

@julienboulay
Copy link

@Zulko : why do you want to avoid non-JS solution ?
imagemin, pngquant and jpegtran are very powerful projects and are multi-platforms.

@Zulko
Copy link
Author

Zulko commented Jun 13, 2018

There is jimp, which is the solution I use in my project (see two messages above).

It makes plenty of sense to have a pure-JS image library, it is more accessible (it doesn't complicate the installation of your JS project) and it can run in a web application. It's fast enough.

@julienboulay
Copy link

There is no complication for installing imagemin, pngquant and jpegtran.
You just need to use npm as any other node dependency

@Zulko
Copy link
Author

Zulko commented Jun 13, 2018

@julienboulay I am making this project which, even though it is written in javascript and distributed via npm, is aimed at the general public (not just front-end specialists). I am trying to avoid any binary because these can cause platform-related problems (see for instance the imagemin issues page, but pngquant and jpegtran also have open installation issues)

@julienboulay
Copy link

@Zulko, I understand, now, why you don't want external libraries.

I had a look to jimp and it looks powerful.
It might be hard to integrate to the svgo plugin system as the plugins doesn't work asynchronously.

I can see that you use node-sass in your project, which depends on native libraries.
Did you have any users complaining about installation issues regarding node-sass ?
If not, you might give a try to pngquant and jpegtran.

@schmod
Copy link

schmod commented Mar 19, 2019

I wonder if we could re-envision this as a command-line argument (or JS option) that will pipe embedded images to an external program (making the management of binary dependencies "somebody else's problem").

@strarsis
Copy link
Contributor

strarsis commented May 18, 2019

Also mozjpeg for JPEG files.

Isn't there a framework for CLI/tools like SVGO that offers configurable piping or callbacks to
other "processors", like image file data?

Edit: After some thought it comes to mind that webpack actually solved this already:
Using the input SVG as "source" and loaders for the resources that are embedded inside or
referenced by the SVG, like images, fonts, styles, etc.

@BrainSlugs83
Copy link

BrainSlugs83 commented Mar 10, 2020

Apologies all, I know this isn't the best place for it -- but @julienboulay -- I tried to use your version today, but it fails on the minifyImages plugin. -- I'd log this as an issue on your fork, but I can't seem to find the button for it. (Is that not a thing? or maybe I'm just going blind...)

I did install imagemin, pngquant, pngquant-bin, and jpegtran globally, and it looks like it's getting back the buffer of bytes from pngquant.exe, but it's treating them as an error.

npm -g install imagemin
npm -g install pngquant
npm -g install pngquant-bin
npm -g install jpegtran
npm i -g https://github.com/julienboulay/svgo.git

svgo -i Home3.svg -o Home5.svg

It prints out a bunch of garbage characters to the console and fails with this message (garbage omitted):

at makeError (C:\[...]\npm\node_modules\svgo\node_modules\execa\index.js:172:9)
    at Function.module.exports.sync (C:\[...]\npm\node_modules\svgo\node_modules\execa\index.js:341:15)
    at minifyPng (C:\[...]\npm\node_modules\svgo\plugins\minifyImages.js:109:22)
    at Object.exports.fn (C:\[...]\npm\node_modules\svgo\plugins\minifyImages.js:53:32)
    at C:\[...]\npm\node_modules\svgo\lib\svgo\plugins.js:61:45
    at Array.filter (<anonymous>)
    at monkeys (C:\Users\[...]\npm\node_modules\svgo\lib\svgo\plugins.js:48:39)
    at C:\Users\[...]\npm\node_modules\svgo\lib\svgo\plugins.js:68:17
    at Array.filter (<anonymous>)
    at monkeys (C:\Users\[...]\npm\node_modules\svgo\lib\svgo\plugins.js:48:39) {
  code: 99,
  stdout: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 01 18 00 00 01 18 08 06 00 00 00 87 8e e9 8c 00 00 00 04 67 41 4d 41 00 00 b1 8f 0b fc 61 05 00 ... 104857 more bytes>,
  stderr: <Buffer >,
  failed: true,
  signal: null,
  cmd: 'C:\\Users\\[...]\\npm\\node_modules\\svgo\\node_modules\\pngquant-bin\\vendor\\pngquant.exe - --floyd=1 --quality 70-90 --speed 1',
  timedOut: false

@julienboulay
Copy link

Hi @BrainSlugs83 ,

Thank you for your post. I enabled issues on my repo, so you might be able to create new issues now.

I think your issue comes from the installation process. The version of imagemin, pngquant, pngquant-bin jpegtran might not be the right versions required for this plugin.

If you want to try with the right dependencies version :

git clone https://github.com/julienboulay/svgo.git
npm install
./bin/svgo -i Home3.svg -o Home5.svg

@Christopher-Hayes
Copy link
Contributor

@julienboulay wow, that worked great! So hard to find an SVG minimizer that also handles embedded images. It cut my SVG size in half with no visible loss in quality.

@TPS
Copy link

TPS commented May 30, 2023

It might even be worth converting, e.g., an embedded PNG → lossless WebP

Btw, #1246 duplicates this?

@GreLI
Copy link
Member

GreLI commented Sep 23, 2023

Thinking it over, SVGO could use some already known optimizers like pngout and mozjpeg. It could search them in standard places (platform-specific) and some side plugins could add formats and binaries. However, I don't think it's a good idea to add binaries to SVGO core or add extra dependencies to compile them on installation.

@TrySound
Copy link
Member

A good case for external plugin actually. No support for async plugins though I remember somebody used atomics to make async code synchronous.

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

No branches or pull requests

10 participants