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

[gatsby-plugin-sharp] SVG traced placeholders #2456

Merged
merged 34 commits into from Oct 20, 2017

Conversation

fk
Copy link
Contributor

@fk fk commented Oct 14, 2017

(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 and turnPolicy defaults for potrace follow https://twitter.com/Martin_Adams/status/918481948217049088

Todo:

Using node-potrace (and Jimp…) and SVGO.
Only working with `resolutions` right now, also didn’t check SVG size yet.
@KyleAMathews
Copy link
Contributor

KyleAMathews commented Oct 14, 2017

Deploy preview failed.

Built with commit 80e1bd5

https://app.netlify.com/sites/using-glamor/deploys/59e7d078a6188f031e24c654

@gatsbybot
Copy link
Collaborator

gatsbybot commented Oct 14, 2017

Deploy preview ready!

Built with commit 8e32e7b

https://deploy-preview-2456--gatsbygram.netlify.com

@KyleAMathews
Copy link
Contributor

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 🎉

@KyleAMathews
Copy link
Contributor

Specifically:

  1. Add it as a fragment option
  2. In gatsby-image, check for the key and use it instead of base64/backgroundColor

@sebastienfi
Copy link
Contributor

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: {
Copy link
Contributor

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.

Copy link
Contributor Author

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#parametersbackground and color are already working:

pastedgraphic-1

@KyleAMathews
Copy link
Contributor

We gotta for sure enable this on all the avatars on gatsbyjs.org :-D

@fk
Copy link
Contributor Author

fk commented Oct 14, 2017

  1. Add it as a fragment option

Does adding

  • GatsbyImageSharpResolutions_tracedSVG
  • GatsbyImageSharpSizes_tracedSVG
  • GatsbyContentfulResolutions_tracedSVG
  • GatsbyContentfulSizes_tracedSVG

to the current ones sounds good for a first shot?

@KyleAMathews
Copy link
Contributor

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

@KyleAMathews
Copy link
Contributor

For Contentful, the image GraphQL schema is actually just creating URLs for their image api.

@fk
Copy link
Contributor Author

fk commented Oct 14, 2017

👍 Thanks for the heads up regarding contentful! Probably would have bitten my teeth off :-D

@fk
Copy link
Contributor Author

fk commented Oct 14, 2017

potrace

@KyleAMathews
Copy link
Contributor

🎉🎉🎉

Want to do one from a full color image too real quick?

@fk
Copy link
Contributor Author

fk commented Oct 14, 2017

Ah sorry didn't see until now. Gimme a minute!

@fk
Copy link
Contributor Author

fk commented Oct 14, 2017

… so much for "a minute": cheers

@fk
Copy link
Contributor Author

fk commented Oct 15, 2017

Will wrap it up for today/night 🤧, but I think this is ready for a first review!

  • only updated the gatsby-image README with very basic info for now
  • the exposed Potrace options (trace: { … }) aren't mentioned anywhere yet
  • GraphQL types for some Potrace option fields aren't super thorough (threshold, color, background)
  • examples/image-processing features a little too much "tracedSVG"

Copy link
Contributor

@KyleAMathews KyleAMathews left a 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`)
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😬😊🙏

@fk
Copy link
Contributor Author

fk commented Oct 19, 2017

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 maxWidth for sizes() and width for resolutions()?

Seeing how I struggled to pass those "trace" arguments down to the "tracedSVG" child just now, I wonder how long it would take me … 😳 💔

noob_tn

@KyleAMathews
Copy link
Contributor

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.

@fk
Copy link
Contributor Author

fk commented Oct 19, 2017

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) },
Copy link
Contributor Author

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: {
Copy link
Contributor Author

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 ;-))?

Copy link
Contributor

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.

Copy link
Contributor Author

@fk fk Oct 19, 2017

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"?)

Copy link
Contributor

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.

@KyleAMathews
Copy link
Contributor

@fk
Copy link
Contributor Author

fk commented Oct 20, 2017

🎉 🎉 🎉


const optimize = svg => {
const SVGO = require(`svgo`)
const svgo = new SVGO()
Copy link
Contributor

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 })

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awww thanks Emil! 🤗 🙌

Copy link
Contributor Author

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!)

Copy link
Contributor Author

@fk fk Oct 20, 2017

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)

@fk
Copy link
Contributor Author

fk commented Oct 20, 2017

Looking gooood: https://deploy-preview-2456--using-gatsby-image.netlify.com/traced-svg/
https://deploy-preview-2456--image-processing.netlify.com/

@KyleAMathews KyleAMathews changed the title [WIP][gatsby-plugin-sharp] SVG traced placeholders [gatsby-plugin-sharp] SVG traced placeholders Oct 20, 2017
@KyleAMathews
Copy link
Contributor

Looking good indeed!!!

Merging and releasing 🎉

@KyleAMathews KyleAMathews merged commit 0906635 into gatsbyjs:master Oct 20, 2017
@fk
Copy link
Contributor Author

fk commented Oct 20, 2017

🙌

@sebastienfi
Copy link
Contributor

Congrats

@fk
Copy link
Contributor Author

fk commented Oct 27, 2017

Thank you @sebastienfi! 🤗

@fk fk deleted the topics/2435-traced-placeholder branch November 14, 2017 01:21
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

Successfully merging this pull request may close these issues.

None yet

5 participants