Skip to content

Commit

Permalink
Fixes #105, adds formatFiltering option
Browse files Browse the repository at this point in the history
  • Loading branch information
zachleat committed Jan 4, 2025
1 parent 7a62a97 commit f97b3ca
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/global-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const DEFAULTS = {
widths: ["auto"],
formats: ["webp", "jpeg"], // "png", "svg", "avif"

formatFiltering: ["transparent", "animated"],

// Via https://github.com/11ty/eleventy-img/issues/258
concurrency: Math.min(Math.max(8, os.availableParallelism()), 16),

Expand Down
37 changes: 34 additions & 3 deletions src/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ const ANIMATED_TYPES = [
"gif",
];

const TRANSPARENCY_TYPES = [
"avif",
"png",
"webp",
"gif",
"svg",
];

const MINIMUM_TRANSPARENCY_TYPES = [
"png",
"gif",
"svg",
];

class Image {
#input;
Expand Down Expand Up @@ -191,7 +204,7 @@ class Image {
return valid.sort((a, b) => a - b);
}

static getFormatsArray(formats, autoFormat, svgShortCircuit, isAnimated) {
static getFormatsArray(formats, autoFormat, svgShortCircuit, isAnimated, hasTransparency) {
if(formats && formats.length) {
if(typeof formats === "string") {
formats = formats.split(",");
Expand Down Expand Up @@ -233,6 +246,18 @@ class Image {
}
}

if(hasTransparency) {
let minimumValidTransparencyFormats = formats.filter(f => MINIMUM_TRANSPARENCY_TYPES.includes(f));
// override formats if a valid animated format is found, otherwise leave as-is
if(minimumValidTransparencyFormats.length > 0) {
let validTransparencyFormats = formats.filter(f => TRANSPARENCY_TYPES.includes(f));
debug("Filtering non-transparency-friendly formats from output: from %o to %o", formats, validTransparencyFormats);
formats = validTransparencyFormats;
} else {
debug("At least one transparency-friendly output format of %o must be included if the source image has an alpha channel, skipping formatFiltering and using original formats.", MINIMUM_TRANSPARENCY_TYPES);
}
}

// Remove duplicates (e.g., if null happens to coincide with an explicit format
// or a user passes in multiple duplicate values)
formats = [...new Set(formats)];
Expand Down Expand Up @@ -477,6 +502,11 @@ class Image {
return metadata?.pages > 1;
}

hasAlpha(metadata) {
console.log( {metadata} );
return true;
}

getEntryFormat(metadata) {
return metadata.format || this.options.overrideInputFormat;
}
Expand All @@ -485,9 +515,10 @@ class Image {
// src is used to calculate the output file names
getFullStats(metadata) {
let results = [];
let isImageAnimated = this.isAnimated(metadata);
let isImageAnimated = this.isAnimated(metadata) && Array.isArray(this.options.formatFiltering) && this.options.formatFiltering.includes("animated");
let hasAlpha = metadata.hasAlpha && Array.isArray(this.options.formatFiltering) && this.options.formatFiltering.includes("transparent");
let entryFormat = this.getEntryFormat(metadata);
let outputFormats = Image.getFormatsArray(this.options.formats, entryFormat, this.options.svgShortCircuit, isImageAnimated);
let outputFormats = Image.getFormatsArray(this.options.formats, entryFormat, this.options.svgShortCircuit, isImageAnimated, hasAlpha);

if (this.needsRotation(metadata.orientation)) {
[metadata.height, metadata.width] = [metadata.width, metadata.height];
Expand Down
Binary file added test/david-mascot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1256,3 +1256,24 @@ test("Keep ICC Profiles by default #244 test image from Sharp repo", async t =>
t.true(Buffer.isBuffer(outputMetadata.icc));
t.true(outputMetadata.hasProfile);
});

test("#105 Transparent format output filtering", async t => {
let stats = await eleventyImage("./test/david-mascot.png", {
dryRun: true,
formats: ["png", "avif", "jpeg"],
useCache: false,
});

t.deepEqual(Object.keys(stats), ["png", "avif"]);
});

test("#105 Transparent format output filtering (no minimum transparency formats found)", async t => {
let stats = await eleventyImage("./test/david-mascot.png", {
dryRun: true,
useCache: false,
});

// even though webp is transparency-friendly, we still use the full originally formats because webp is not a sufficiently minimum format for transparency
// must include one of: svg, png, or gif
t.deepEqual(Object.keys(stats), ["webp", "jpeg"]);
});

0 comments on commit f97b3ca

Please sign in to comment.