Skip to content

Commit

Permalink
Avoid issues with blurred images and transparency. Correctly handle P…
Browse files Browse the repository at this point in the history
…NG source images (google#121)

- Removes the race condition where memory cached images may keep their blurred images in the background which shine through with transparent foreground images.
- Fallback to PNG instead of JPEG if the input image is a PNG. Keeps AVIF and WEBP lossy compression as they do support transparency.

Fixes google#120
  • Loading branch information
cramforce authored Jan 3, 2022
1 parent 00e31b3 commit b18419e
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 22 deletions.
15 changes: 10 additions & 5 deletions _11ty/img-dim.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ const processImage = async (img, outputPath) => {
img.setAttribute("width", dimensions.width);
img.setAttribute("height", dimensions.height);
}
if (dimensions.type == "svg") {
const inputType = dimensions.type;
if (inputType == "svg") {
return;
}
if (dimensions.type == "gif") {
if (inputType == "gif") {
const videoSrc = await gif2mp4(src);
const video = img.ownerDocument.createElement(
/AMP/i.test(img.tagName) ? "amp-video" : "video"
Expand All @@ -81,6 +82,10 @@ const processImage = async (img, outputPath) => {
img.parentElement.replaceChild(video, img);
return;
}
// When the input is a PNG, we keep the fallback image a PNG because JPEG does
// not support transparency. However, we still optimize to AVIF/WEBP in a lossy
// fashion. It may be worth adding a feature to opt-out of lossy optimization.
const fallbackType = inputType == "png" ? "png" : "jpeg";
if (img.tagName == "IMG") {
img.setAttribute("decoding", "async");
img.setAttribute("loading", "lazy");
Expand All @@ -98,16 +103,16 @@ const processImage = async (img, outputPath) => {
avif.setAttribute("type", "image/avif");
await setSrcset(webp, src, "webp");
webp.setAttribute("type", "image/webp");
const fallback = await setSrcset(jpeg, src, "jpeg");
jpeg.setAttribute("type", "image/jpeg");
const fallback = await setSrcset(jpeg, src, fallbackType);
jpeg.setAttribute("type", `image/${fallbackType}`);
picture.appendChild(avif);
picture.appendChild(webp);
picture.appendChild(jpeg);
img.parentElement.replaceChild(picture, img);
picture.appendChild(img);
img.setAttribute("src", fallback);
} else if (!img.getAttribute("srcset")) {
const fallback = await setSrcset(img, src, "jpeg");
const fallback = await setSrcset(img, src, fallbackType);
img.setAttribute("src", fallback);
}
};
Expand Down
1 change: 1 addition & 0 deletions _11ty/srcset.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const extension = {
jpeg: "jpg",
webp: "webp",
avif: "avif",
png: "png",
};

const quality = {
Expand Down
7 changes: 6 additions & 1 deletion posts/secondpost.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tags:
- number-2
layout: layouts/post.njk
---

Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.

## Section Header
Expand All @@ -24,4 +25,8 @@ Capitalize on low hanging fruit to identify a ballpark value added activity to b

# Test Relative Local Image

![Test Share SVG](../../img/doener.jpg)
![Test Share SVG](../../img/doener.jpg)

# Test PNG

![Png By @clipartmax.com](https://www.clipartmax.com/png/full/0-9896_film-clipart-free-to-use-public-domain-movie-clip-art-directors-board.png)
37 changes: 21 additions & 16 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ function prefetch(e) {
* @return {string} url without fragment
*/
const removeUrlFragment = (url) => url.split("#")[0];
if (removeUrlFragment(window.location.href) === removeUrlFragment(e.target.href)) {
if (
removeUrlFragment(window.location.href) === removeUrlFragment(e.target.href)
) {
return;
}
var l = document.createElement("link");
Expand Down Expand Up @@ -152,14 +154,14 @@ const sendWebVitals = document.currentScript.getAttribute("data-cwv-src");

if (/web-vitals.js/.test(sendWebVitals)) {
dynamicScriptInject(`${window.location.origin}/js/web-vitals.js`)
.then(() => {
webVitals.getCLS(sendToGoogleAnalytics);
webVitals.getFID(sendToGoogleAnalytics);
webVitals.getLCP(sendToGoogleAnalytics);
})
.catch((error) => {
console.error(error);
});
.then(() => {
webVitals.getCLS(sendToGoogleAnalytics);
webVitals.getFID(sendToGoogleAnalytics);
webVitals.getLCP(sendToGoogleAnalytics);
})
.catch((error) => {
console.error(error);
});
}

addEventListener(
Expand Down Expand Up @@ -253,19 +255,22 @@ addEventListener("click", (e) => {
fn(handler);
});

// There is a race condition here if an image loads faster than this JS file. But
// - that is unlikely
// - it only means potentially more costly layouts for that image.
// - And so it isn't worth the querySelectorAll it would cost to synchronously check
// load state.
function removeBlurredImage(img) {
// Ensure the browser doesn't try to draw the placeholder when the real image is present.
img.style.backgroundImage = "none";
}
document.body.addEventListener(
"load",
(e) => {
if (e.target.tagName != "IMG") {
return;
}
// Ensure the browser doesn't try to draw the placeholder when the real image is present.
e.target.style.backgroundImage = "none";
removeBlurredImage(e.target);
},
/* capture */ "true"
);
for (let img of document.querySelectorAll("img")) {
if (img.complete) {
removeBlurredImage(img);
}
}

0 comments on commit b18419e

Please sign in to comment.