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
[gatsby-plugin-sharp] SVG traced placeholders #2456
[gatsby-plugin-sharp] SVG traced placeholders #2456
Conversation
Using node-potrace (and Jimp…) and SVGO. Only working with `resolutions` right now, also didn’t check SVG size yet.
Deploy preview failed. Built with commit 80e1bd5 https://app.netlify.com/sites/using-glamor/deploys/59e7d078a6188f031e24c654 |
Deploy preview ready! Built with commit 8e32e7b |
Hot dang! That's super cool! Umm wow, @fk we're going to anoint you king graphics wizard or something soon :-) The size is 24kb uncompressed, 16kb gzipped (compared html size on master image-processing vs this). This works shockingly well. Should be really straightforward now to add this as an option to gatsby-image 🎉 |
Specifically:
|
The option would be to choose between blurred image and svg placeholder ? I like this |
@@ -461,10 +466,15 @@ async function resolutions({ file, args = {} }) { | |||
pngCompressionLevel: 9, | |||
grayscale: false, | |||
duotone: false, | |||
trace: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be awesome to implement background
, color
, threshold
config parameters and expose these so user can customize the styling of the svg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 👍 Planning to expose all of those: https://github.com/tooolbox/node-potrace#parameters – background
and color
are already working:
We gotta for sure enable this on all the avatars on gatsbyjs.org :-D |
Does adding
to the current ones sounds good for a first shot? |
Yup! Except we can't add this to Contentful as it doesn't support traced svgs (though in theory someone could add it there too). |
For Contentful, the image GraphQL schema is actually just creating URLs for their image api. |
👍 Thanks for the heads up regarding contentful! Probably would have bitten my teeth off :-D |
🎉🎉🎉 Want to do one from a full color image too real quick? |
Ah sorry didn't see until now. Gimme a minute! |
Will wrap it up for today/night 🤧, but I think this is ready for a first review!
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking super solid! Love how cleanly all these things fit together ❤️
@@ -9,10 +9,15 @@ const imagemin = require(`imagemin`) | |||
const imageminPngquant = require(`imagemin-pngquant`) | |||
const queue = require(`async/queue`) | |||
const path = require(`path`) | |||
const potrace = require(`potrace`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's lazy load these so they're only read off disk if someone is using them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Struggling! 👋 😄 Happy to explain in detail what I'm trying to do, but maybe this is enough to makes sense already: How do I find out if the query contains the tracedSVG
field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just move the requires inside the function for generating the traces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! My problem is determining if the traced SVG should be generated at all – if I set defaultValue
for the "tracedSVG" field, the traced SVG will always be generated; if I don't, tracedSVG will only be returned if one or more "trace" arguments are set. Or am I 🤒 again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me try and explain my issue again (still 😷🤒) – let's see if this amounts to anything more understandable then the previous attempt:
We want to lazy load potrace/SVGO only if needed. In the case of duotone
, this would be easy – if there are duotone options set, apply the duotone effect – the image is always generated, anyway, and duotone options are required to generate a duotone image.
In the case of the "tracedSVG" however, I can't make the decision based on the "tracedSVG" options (trace:{color…}
) being set or not, because that would require the user to always set options. Ideally, I could make the decision based on wether the "tracedSVG" is present in the query at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahhh gotcha. Yeah so what you want to do here is add a resolve function to the actual field which is where you do the require and generate the svg. A field resolve function is only called if that field is actually queried so is the perfect place to put expensive work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😬😊🙏
This reverts commit da19d06. Default color of traced SVG now matches default „backgroundColor“ of the gatsby-image placeholder.
Yes, that makes a lot of sense of course. Was wondering about this when I gave this thing the first shot last weekend. So we would generate the traced SVG based on the Seeing how I struggled to pass those "trace" arguments down to the "tracedSVG" child just now, I wonder how long it would take me … 😳 💔 |
Haha :-) You've got this! So I'm assuming node-potrace needs the file written out? So probably we should wait until a file is written to disk and then trace that. |
node-potrace uses Jimp and also accepts a (Jimp?!) buffer: https://github.com/tooolbox/node-potrace/blob/0e98e95626abda922130e3c3323b3cb2c3e29007/lib/Potrace.js#L1018-L1050 |
module.exports = ({ type, pathPrefix, getNodeAndSavePathDependency }) => { | ||
if (type.name !== `ImageSharp`) { | ||
return {} | ||
} | ||
|
||
const getTracedSVG = parent => { | ||
const promise = traceSVG({ | ||
file: { absolutePath: path.join(process.cwd(), `public`, parent.src) }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I just wondered if what I'm currently doing is actually close to what you suggested …
The reason I wondered about this is that I didn't know how to actually reach the original image path from the subfield, so I just used what was there, namely parent.src
…
And after coincidentally deleting my public
folder, it turns out that parent.src
isn't necessarily available at this point in time, meaning all that I thought would work up to now really isn't ;-/ … so much for "you got this". 😿
@@ -306,14 +306,19 @@ export const pageQuery = graphql` | |||
sizes: imageSharp(id: { regex: "/fecolormatrix-kanye-west.jpg/" }) { | |||
sizes( | |||
duotone: { highlight: "#f00e2e", shadow: "#192550" } | |||
trace: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KyleAMathews Unsure about arg naming – should this rather be traceSVG
or even matching the field name (tracedSVG
… which I dislike for no apparent reason ;-))?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should be a noun — so tracedSVG
. GraphQL is declarative. You say — "I want X!" And X is given to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 (even if in this case it's "I want to configure X"?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my bad — this is the arguments not the field. Yeah, traceSVG
then is right.
… currently generating SVGs up to 1.4MB :/ ;)
Well lookie at that https://deploy-preview-2456--using-gatsby-image.netlify.com/traced-svg/ |
🎉 🎉 🎉 |
|
||
const optimize = svg => { | ||
const SVGO = require(`svgo`) | ||
const svgo = new SVGO() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This resize technique above is super awesome!
It might also be worth looking into multipass, to compress the svg even further:
const svgo = new SVGO({ multipass: true, floatPrecision: 1 })
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awww thanks Emil! 🤗 🙌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Demo images on a diet after that (missed checking one, but here's the before/after for two of the three at https://deploy-preview-2456--using-gatsby-image.netlify.com/traced-svg/):
7.401 -> 4.506 Byte
13.629 -> 8.562 Byte
Thank you again Emil!
(Hey I could swear I didn't see it in https://github.com/EmilTholin/image-trace-loader when I checked … ah yes, only saw the initial version. We're lucky you are watching here!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at image-trace-loader again, I hadn't noticed https://github.com/EmilTholin/image-trace-loader/blob/master/lib/index.js#L32-L57 either 😊 ❤️ … watchu think about that @KyleAMathews? (Been 👀 https://github.com/akfish/node-vibrant btw., uses Jimp too)
Remove unnecessary/confusing options
Looking good indeed!!! Merging and releasing 🎉 |
🙌 |
Congrats |
Thank you @sebastienfi! 🤗 |
(See #2435) Using node-potrace (and Jimp…) and SVGO.
Only working with
resolutions
right now, also didn’t check SVG size yet … and still have to look at gatsby-image too. 🤧turdSize
,optTolerance
andturnPolicy
defaults for potrace follow https://twitter.com/Martin_Adams/status/918481948217049088Todo:
sizes()