Skip to content

Commit

Permalink
fix(gatsby-plugin-manifest): improve SVG->PNG fidelity (#11608)
Browse files Browse the repository at this point in the history
## Description

`gatsby-plugin-manifest` resizes a user-provided icon to PNGs of various resolutions required for favicons using Sharp. This change allows SVGs to be usable as the user-provided icon.

Sharp is already capable of ingesting an SVG and rasterizing it to PNGs; however, in its default configuration, it first rasterizes the provided SVG to a pixel image of default density (e.g. 72dpi) and then upscales it to the desired size (e.g. 512x512), which can create really poor upscaling artifacts.

This change instructs Sharp to use a rasterizing density equal to the size of the desired output image which eliminates the upscaling problems.
  • Loading branch information
rgiese authored and pieh committed Feb 19, 2019
1 parent a82682c commit e9345cd
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/gatsby-plugin-manifest/README.md
Expand Up @@ -27,7 +27,7 @@ This plugin configures Gatsby to create a `manifest.webmanifest` file on every s

## Generating icons

It can be tedious creating the multitude of icon sizes required by different devices and browsers. This plugin includes code to auto-generate smaller icons from a larger src image.
It can be tedious creating the multitude of icon sizes required by different devices and browsers. This plugin includes code to auto-generate smaller icons from a larger src image (which can also be an SVG).

There are three modes in which icon generation can function: automatic, hybrid, and manual. These three modes are explained below. Icon generation functions differently depending on which of the three you choose.

Expand Down
5 changes: 3 additions & 2 deletions packages/gatsby-plugin-manifest/src/__tests__/gatsby-node.js
Expand Up @@ -57,6 +57,7 @@ describe(`Test plugin manifest options`, () => {
fs.statSync.mockReturnValueOnce({ isFile: () => true })

const icon = `pretend/this/exists.png`
const size = 48

await onPostBootstrap([], {
name: `GatsbyJS`,
Expand All @@ -69,13 +70,13 @@ describe(`Test plugin manifest options`, () => {
icons: [
{
src: `icons/icon-48x48.png`,
sizes: `48x48`,
sizes: `${size}x${size}`,
type: `image/png`,
},
],
})

expect(sharp).toHaveBeenCalledWith(icon)
expect(sharp).toHaveBeenCalledWith(icon, { density: size })
})

it(`fails on non existing icon`, done => {
Expand Down
7 changes: 6 additions & 1 deletion packages/gatsby-plugin-manifest/src/gatsby-node.js
Expand Up @@ -11,7 +11,12 @@ function generateIcons(icons, srcIcon) {
const size = parseInt(icon.sizes.substring(0, icon.sizes.lastIndexOf(`x`)))
const imgPath = path.join(`public`, icon.src)

return sharp(srcIcon)
// For vector graphics, instruct sharp to use a pixel density
// suitable for the resolution we're rasterizing to.
// For pixel graphics sources this has no effect.
// Sharp accept density from 1 to 2400
const density = Math.min(2400, Math.max(1, size))
return sharp(srcIcon, { density })
.resize(size)
.toFile(imgPath)
.then(() => {})
Expand Down

0 comments on commit e9345cd

Please sign in to comment.