new favicon script

This commit is contained in:
Matthias Kretschmann 2022-11-16 19:04:06 +00:00
parent 7814e36b65
commit 4bed995812
Signed by: m
GPG Key ID: 606EEEF3C479A91F
19 changed files with 428 additions and 194 deletions

4
.gitignore vendored
View File

@ -37,4 +37,6 @@ yarn-error.log*
.swc
coverage
public/matomo.js
public/favicon/
# public/favicon*
# public/apple-touch-icon*
# public/manifest*

View File

@ -25,10 +25,12 @@
- [📇 Client-side vCard creation](#-client-side-vcard-creation)
- [💎 Importing SVG assets](#-importing-svg-assets)
- [🍬 Typekit component](#-typekit-component)
- [🤓 Scripts](#-scripts)
- [🎈 Add a new project](#-add-a-new-project)
- [🌄 Favicon generation](#-favicon-generation)
- [✨ Development](#-development)
- [🔮 Linting](#-linting)
- [👩‍🔬 Testing](#-testing)
- [🎈 Add a new project](#-add-a-new-project)
- [🚚 Deployment](#-deployment)
- [🏛 Licenses](#-licenses)
@ -124,6 +126,38 @@ If you want to know how, have a look at the respective component:
- [`src/components/Typekit/index.tsx`](src/components/Typekit/index.tsx)
## 🤓 Scripts
### 🎈 Add a new project
To add a new project, run the following command. This adds a new item to the top of the `projects.yml` file, creating the title & slug from the argument:
```bash
npm run new -- "Hello"
```
Then continue modifying the new entry in [`_content/projects.yml`](_content/projects.yml).
Finally, add as many images as needed with the file name format and put into `public/images/`:
```text
SLUG-01.png
SLUG-02.png
SLUG-03.png
...
```
### 🌄 Favicon generation
This generates all required favcion sizes from:
- `src/images/favicon-512.png`
- `src/images/favicon.svg`
```bash
npm run favicon
```
## ✨ Development
```bash
@ -165,25 +199,6 @@ npm test
Most test files live beside the respective component. Testing setup, fixtures, and mocks can be found in the `tests/` folder.
### 🎈 Add a new project
To add a new project, run the following command. This adds a new item to the top of the `projects.yml` file, creating the title & slug from the argument:
```bash
npm run new -- "Hello"
```
Then continue modifying the new entry in [`_content/projects.yml`](_content/projects.yml).
Finally, add as many images as needed with the file name format and put into `public/images/`:
```text
SLUG-01.png
SLUG-02.png
SLUG-03.png
...
```
## 🚚 Deployment
Every branch or Pull Request is automatically deployed by [Vercel](https://vercel.com) with their GitHub integration, where the `main` branch is automatically aliased to `matthiaskretschmann.com`. A link to a preview deployment will appear under each Pull Request.

View File

@ -7,7 +7,7 @@
"available": "👔 Available for new projects. <a href=\"mailto:m@kretschmann.io\">Lets talk</a>!",
"unavailable": "Not available for new projects."
},
"gpg": "https://kretschmann.io/pub.gpg",
"gpg": "/gpg.txt",
"addressbook": "/matthias-kretschmann.vcf",
"bugs": "https://github.com/kremalicious/portfolio/issues/new",
"matomoUrl": "https://analytics.kremalicious.com",

View File

@ -23,7 +23,9 @@ const next = (phase, { defaultConfig }) => {
return typeof defaultConfig.webpack === 'function'
? defaultConfig.webpack(config, options)
: config
}
},
// https://nextjs.org/docs/api-reference/next.config.js/react-strict-mode
reactStrictMode: true
}
return nextConfig

57
package-lock.json generated
View File

@ -42,6 +42,7 @@
"prepend": "^1.0.2",
"prettier": "^2.7.1",
"sharp": "^0.31.2",
"sharp-ico": "^0.1.5",
"slugify": "^1.6.5",
"stylelint": "^14.14.1",
"stylelint-config-prettier": "^9.0.4",
@ -1933,6 +1934,12 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
"node_modules/@canvas/image-data": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.0.0.tgz",
"integrity": "sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==",
"dev": true
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@ -5008,6 +5015,33 @@
"integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==",
"dev": true
},
"node_modules/decode-bmp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.2.1.tgz",
"integrity": "sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==",
"dev": true,
"dependencies": {
"@canvas/image-data": "^1.0.0",
"to-data-view": "^1.1.0"
},
"engines": {
"node": ">=8.6.0"
}
},
"node_modules/decode-ico": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/decode-ico/-/decode-ico-0.4.1.tgz",
"integrity": "sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==",
"dev": true,
"dependencies": {
"@canvas/image-data": "^1.0.0",
"decode-bmp": "^0.2.0",
"to-data-view": "^1.1.0"
},
"engines": {
"node": ">=8.6"
}
},
"node_modules/decode-named-character-reference": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz",
@ -6797,6 +6831,12 @@
"node": ">=10.17.0"
}
},
"node_modules/ico-endec": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/ico-endec/-/ico-endec-0.1.6.tgz",
"integrity": "sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==",
"dev": true
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@ -11406,6 +11446,17 @@
"url": "https://opencollective.com/libvips"
}
},
"node_modules/sharp-ico": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/sharp-ico/-/sharp-ico-0.1.5.tgz",
"integrity": "sha512-a3jODQl82NPp1d5OYb0wY+oFaPk7AvyxipIowCHk7pBsZCWgbe0yAkU2OOXdoH0ENyANhyOQbs9xkAiRHcF02Q==",
"dev": true,
"dependencies": {
"decode-ico": "*",
"ico-endec": "*",
"sharp": "*"
}
},
"node_modules/sharp/node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
@ -12202,6 +12253,12 @@
"integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
"dev": true
},
"node_modules/to-data-view": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz",
"integrity": "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==",
"dev": true
},
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",

View File

@ -8,10 +8,10 @@
"author": "Matthias Kretschmann <m@kretschmann.io>",
"type": "module",
"scripts": {
"start": "npm run pregenerate && next",
"build": "npm run pregenerate && next build",
"start": "next",
"build": "next build",
"preview": "npm run build && next start",
"export": "npm run pregenerate && next export",
"export": "next export",
"typecheck": "tsc",
"lint:js": "next lint",
"lint:css": "stylelint ./src/**/*.css",
@ -21,8 +21,7 @@
"test": "NODE_ENV=test npm run lint && npm run typecheck && npm run jest",
"deploy:s3": "./scripts/deploy-s3.sh",
"new": "ts-node-esm ./scripts/new.ts",
"favicon": "ts-node-esm ./scripts/favicon.ts",
"pregenerate": "npm run favicon"
"favicon": "ts-node-esm ./scripts/favicon.ts"
},
"dependencies": {
"@giphy/js-fetch-api": "^4.4.0",

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

27
public/favicon.svg Normal file
View File

@ -0,0 +1,27 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="512"
height="512"
viewBox="0 0 512 512"
>
<style>
#background {
fill: #e7eef4;
}
#logomark {
fill: #6b7f88;
}
@media (prefers-color-scheme: dark) {
#background {
fill: #161a1b;
}
}
</style>
<g fill="none" fill-rule="evenodd">
<rect id="background" width="512" height="512" />
<path
id="logomark"
d="M397,91 L421,115 L114,421 L91,398 L397,91 Z M397,182 L421,206 L205,421 L182,398 L397,182 Z M307,91 L330,115 L114,330 L91,307 L307,91 Z"
/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 593 B

185
public/gpg.txt Normal file
View File

@ -0,0 +1,185 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
YXMgS3JldHNjaG1hbm4gPGtyZW1hQGpwYmVybGluLmRlPokCVAQTAQoAPgIbAwUL
CQgHAwUVCgkICwUWAgMBAAIeAQIXgBYhBJrA95Du12SgGDjIKb08Hz7deDH8BQJj
YcUIBQkUsaQDAAoJEL08Hz7deDH8PysP/jN45LeLMjiiGAr090sRtRNqmvljvWC4
v1DlXxuLwCJFhB0U8cZMvx7uUU2PDJodecGiKunNBYAuz98WjMCTxMNnfT+cgkxv
lSmfa2wjz3l/otHWaeyLTfn48SBbSd/RoFF8sH2OaqWIde8iJ6n6OvGVluNboL8g
+ZL+O28Du+tsnZ4v7WNNJGBHJBOupaB19/ConKR/fUC8WlFV8WTC/6egWB6TbNjU
RUt/EPsc4hieU/bodJKmzYSVQcVoR/7x+wAnMNJrGS34tJN+2O1O9JobJVBCHsk5
yMhs2XLrSIys5Xby1qFWk7zmdKP1NZaSeIh+4xXtbzURtO28Xqmry76s0tznqfss
uy323+Hdp8ynXP6MuDE/nlPQVI2BMbfCvMQzSp3dSRhq2+siYg2qoL0QNAaXAPUU
OxdH2ee84Hzx60s9kdnw5EHHQ6KZiCvuSABog0kldDAdIl8I2Kc8DtzZVBLPSWp3
FPR7V4X8722tk6ZsZIMADJeslcSlnscRFPYh6gDrbzJCSj6IcG/wb8fHyUgMrLZb
3E8rZceWXa5fiIPtb6z4LcPS3dRWD7iK52Uqg+8N6IuG/OvlmY9+6X6OseUm+qq6
FZrXQONGC09mPGGvCKCfEZYKITO2m1Rd2SWPh5UXop8277q3botsOhMnjaTiVQVf
xv37UFfGkdXBtC5NYXR0aGlhcyBLcmV0c2NobWFubiA8bWF0dGhpYXNAYmlnY2hh
aW5kYi5jb20+iQJUBBMBCgA+AhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAFiEE
msD3kO7XZKAYOMgpvTwfPt14MfwFAmNhxQgFCRSxpAMACgkQvTwfPt14Mfy2mQ//
QQMn8nGbGNovHBpOq/AehCNeQlrtY4ln6k09kLZ+Xyy7BNB3xR6zLbyl6uLgbQKk
d9q3/JFEPU8ZP/fH22AxR66R8vzcxWKeoow8EVpYLttyTl/JGFiFyv33xbhKynFC
zhHfOpPdpMu4oJf78kAUT/OTuiRQFMlpIXGLKbhwkikGXWuejGuRXKF2v7Fxc+6y
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
=DXwP
-----END PGP PUBLIC KEY BLOCK-----

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1 @@
{"name":"matthias kretschmann","shortName":"mk","icons":[{"src":"/manifest/favicon-192.png","type":"image/png","sizes":"192x192"},{"src":"/manifest/favicon-512.png","type":"image/png","sizes":"512x512"}]}

View File

@ -1,87 +1,83 @@
import { favicons, FaviconImage } from 'favicons'
import path from 'path'
import fs from 'fs'
import sharp from 'sharp'
import ico from 'sharp-ico'
const imagesDirectory = path.resolve(path.join(process.cwd(), 'src', 'images'))
const source = `${imagesDirectory}/favicon.png`
const output = path.resolve(path.join(process.cwd(), 'public', 'favicon'))
const imagesSourcePath = path.resolve(path.join(process.cwd(), 'src', 'images'))
const faviconSource = `${imagesSourcePath}/favicon-512.png`
const faviconSourceSvg = `${imagesSourcePath}/favicon.svg`
const configuration = {
path: '/favicon', // Path for overriding default icons path. `string`
appName: 'matthias kretschmann',
appShortName: 'mk',
appDescription: null,
developerName: null,
developerURL: null,
dir: 'auto',
lang: 'en-US',
appleStatusBarStyle: 'black-translucent', // Style for Apple status bar: "black-translucent", "default", "black". `string`
display: 'minimal-ui', // Preferred display mode: "fullscreen", "standalone", "minimal-ui" or "browser". `string`
orientation: 'any', // Default orientation: "any", "natural", "portrait" or "landscape". `string`
scope: '/', // set of URLs that the browser considers within your app
start_url: '/?homescreen=1',
background_color: '#e7eef4',
theme_color: '#e7eef4',
preferRelatedApplications: false,
relatedApplications: undefined,
version: '1.0',
pixel_art: false, // Keeps pixels "sharp" when scaling up, for pixel art. Only supported in offline mode.
loadManifestWithCredentials: false,
manifestMaskable: `${imagesDirectory}/logo.svg`, // Maskable source image(s) for manifest.json. "true" to use default source. More information at https://web.dev/maskable-icon/. `boolean`, `string`, `buffer` or array of `string`
icons: {
android: true,
appleIcon: true,
appleStartup: false,
favicons: true,
windows: true,
yandex: false
const outputWebRoot = path.resolve(path.join(process.cwd(), 'public'))
const outputManifest = path.resolve(
path.join(process.cwd(), 'public', 'manifest')
)
// All the sizes and meta we'll need
// https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs
const sizes = [32, 180, 192, 512]
const outputMeta = `
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/manifest/manifest.webmanifest">
`
function createManifest(iconsizes: number[]) {
const manifest = {
name: 'matthias kretschmann',
shortName: 'mk',
icons: iconsizes.map((size) => ({
src: `/manifest/favicon-${size}.png`,
type: 'image/png',
sizes: `${size}x${size}`
}))
}
fs.writeFileSync(
`${outputManifest}/manifest.webmanifest`,
JSON.stringify(manifest)
)
}
async function buildFavicons() {
try {
const response = await favicons(source, configuration)
const allFilesToWrite = response.images.concat(response.files as any)
// Nuke all & create output folder first
fs.rmSync(outputManifest, { recursive: true, force: true })
fs.rmSync(`${outputWebRoot}/apple-touch-icon.png`, { force: true })
fs.rmSync(`${outputWebRoot}/favicon.ico`, { force: true })
fs.mkdirSync(outputManifest, { recursive: true })
fs.rmSync(output, { recursive: true, force: true })
// copy over the svg, as it's handcrafted
fs.copyFileSync(faviconSourceSvg, `${outputWebRoot}/favicon.svg`)
allFilesToWrite.forEach((file) => {
const { name, contents } = file
const destination = `${output}/${name}`
// generate all the rest
await Promise.all(
sizes.map(async (size) => {
let destination = `${outputManifest}/favicon-${size}.png`
if (size === 180) destination = `${outputWebRoot}/apple-touch-icon.png`
try {
fs.readFileSync(destination, 'utf8')
} catch (error) {
// if there is no file, get data and write a fresh file
if (error.code === 'ENOENT') {
try {
fs.mkdirSync(output, { recursive: true })
fs.writeFileSync(destination, contents)
} catch (error) {
throw new Error("Couldn't write favicon file")
}
}
}
})
const destinationHtml = `${output}/_meta.html`
try {
fs.readFileSync(destinationHtml, 'utf8')
} catch (error) {
// if there is no file, get data and write a fresh file
if (error.code === 'ENOENT') {
try {
fs.mkdirSync(output, { recursive: true })
fs.writeFileSync(
destinationHtml,
response.html.reverse().toString().replaceAll(',', '')
if (size === 32) {
await ico.sharpsToIco(
[sharp(faviconSource)],
`${outputWebRoot}/favicon.ico`,
{ sizes: [32, 24, 16], resizeOptions: {} }
)
} catch (error) {
throw new Error("Couldn't write favicon file")
fs.rmSync(destination, { force: true })
} else {
await sharp(faviconSource).resize(size, size).toFile(destination)
}
}
}
})
)
// write out manifest
createManifest([192, 512])
console.log(`
-----------------------------
Favicon generation complete!
-----------------------------
Add this to src/components/Meta/Favicon.tsx:
${outputMeta}
`)
} catch (error) {
console.error(error.message)
}

View File

@ -3,100 +3,14 @@ import Head from 'next/head'
const MetaFavicons = () => {
return (
<Head>
<meta name="msapplication-config" content="/favicon/browserconfig.xml" />
<meta
name="msapplication-TileImage"
content="/favicon/mstile-144x144.png"
/>
<meta name="apple-mobile-web-app-title" content="mk" />
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link
rel="apple-touch-icon"
sizes="1024x1024"
href="/favicon/apple-touch-icon-1024x1024.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-touch-icon-180x180.png"
/>
<link
rel="apple-touch-icon"
sizes="167x167"
href="/favicon/apple-touch-icon-167x167.png"
/>
<link
rel="apple-touch-icon"
sizes="152x152"
href="/favicon/apple-touch-icon-152x152.png"
/>
<link
rel="apple-touch-icon"
sizes="144x144"
href="/favicon/apple-touch-icon-144x144.png"
/>
<link
rel="apple-touch-icon"
sizes="120x120"
href="/favicon/apple-touch-icon-120x120.png"
/>
<link
rel="apple-touch-icon"
sizes="114x114"
href="/favicon/apple-touch-icon-114x114.png"
/>
<link
rel="apple-touch-icon"
sizes="76x76"
href="/favicon/apple-touch-icon-76x76.png"
/>
<link
rel="apple-touch-icon"
sizes="72x72"
href="/favicon/apple-touch-icon-72x72.png"
/>
<link
rel="apple-touch-icon"
sizes="60x60"
href="/favicon/apple-touch-icon-60x60.png"
/>
<link
rel="apple-touch-icon"
sizes="57x57"
href="/favicon/apple-touch-icon-57x57.png"
/>
<meta name="application-name" content="matthias kretschmann" />
<meta name="mobile-web-app-capable" content="yes" />
<link rel="manifest" href="/favicon/manifest.webmanifest" />
<link
rel="icon"
type="image/png"
sizes="48x48"
href="/favicon/favicon-48x48.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon/favicon-16x16.png"
/>
{/* <link
rel="mask-icon"
href="/favicon/safari-pinned-tab.svg"
color="#000000"
/> */}
<link rel="shortcut icon" href="/favicon/favicon.ico" />
{/*
Stop the favicon madness
https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs
*/}
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="manifest" href="/favicon/manifest.webmanifest"></link>
</Head>
)
}

BIN
src/images/favicon-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

27
src/images/favicon.svg Normal file
View File

@ -0,0 +1,27 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="512"
height="512"
viewBox="0 0 512 512"
>
<style>
#background {
fill: #e7eef4;
}
#logomark {
fill: #6b7f88;
}
@media (prefers-color-scheme: dark) {
#background {
fill: #161a1b;
}
}
</style>
<g fill="none" fill-rule="evenodd">
<rect id="background" width="512" height="512" />
<path
id="logomark"
d="M397,91 L421,115 L114,421 L91,398 L397,91 Z M397,182 L421,206 L205,421 L182,398 L397,182 Z M307,91 L330,115 L114,330 L91,307 L307,91 Z"
/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 593 B

View File

@ -1,3 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="146" viewBox="0 0 146 146">
<path d="M307.015625,177.53125 L317.421875,188.078125 L182.421875,322.515625 L172.4375,312.390625 L307.015625,177.53125 Z M307.015625,217.328125 L317.421875,227.875 L222.21875,322.515625 L212.234375,312.390625 L307.015625,217.328125 Z M267.359375,177.53125 L277.625,188.078125 L182.421875,282.71875 L172.4375,272.59375 L267.359375,177.53125 Z" transform="translate(-172 -177)"/>
<svg
xmlns="http://www.w3.org/2000/svg"
width="330"
height="330"
viewBox="0 0 330 330"
>
<path
fill-rule="evenodd"
d="M408,226 L432,250 L125,556 L102,533 L408,226 Z M408,317 L432,341 L216,556 L193,533 L408,317 Z M318,226 L341,250 L125,465 L102,442 L318,226 Z"
transform="translate(-102 -226)"
/>
</svg>

Before

Width:  |  Height:  |  Size: 476 B

After

Width:  |  Height:  |  Size: 327 B