Skip to content

CDN optimization: encoder upgrades + format-selection safety guards#2

Open
adityaverm-a wants to merge 6 commits into
mainfrom
ppt-755
Open

CDN optimization: encoder upgrades + format-selection safety guards#2
adityaverm-a wants to merge 6 commits into
mainfrom
ppt-755

Conversation

@adityaverm-a
Copy link
Copy Markdown
Collaborator

@adityaverm-a adityaverm-a commented Jun 1, 2026

Summary

Six commits bundling per-format encoder upgrades (Sharp output options) and two safety guards in the auto-format-selection pipeline. Targets the bandwidth/quality gaps with Cloudinary documented in the internal CDN optimization tracker.

Issue tracker: DIT Migration Issues — Consolidated Log of Image Format Problems and Proposed Solutions

Encoder upgrades — straightforward Sharp option enablement:

  • Issue 4 (7d72a5c): enable mozjpeg for JPEG output (~10–15% smaller files)
  • Issue 5 (c5bac5f): PNG output — palette: true, compressionLevel: 9, adaptiveFiltering: true
  • Issue 6 (6b9cfb4): map generic quality to Sharp GIF options (colours, effort, interFrameMaxError, interPaletteMaxError)
  • Issue 7 (52bfe6d): cap animated WebP at Q50 (motion masking) — closes the +36% gap vs Cloudinary on the 304 GIF→WebP rows

Format-selection safety guards — block visually-broken or size-broken auto-conversions:

  • Issue 2 (812b18c): block transparent PNG/WebP → JPEG auto-selection (drops alpha → broken icons). Two layers: pre-fetch guard in auto-optimizer plus post-fetch override in image-processor after Sharp metadata.
  • Issue 3 (2159153): block lossy → lossless re-encode (JPEG/WebP → PNG/TIFF), which only inflates size — average +164% on JPEG sweep, +307% on vnd.ms-photo. DIT-side half; the CF Function piece (restricting dit-accept normalization to modern formats) is owned by DevOps/AWS and remains open.

Guards compose: an alpha-suspect, lossy source (WebP) falls through both filters; the lossy fallback search honors the alpha guard's no-jpeg rule.

Test plan

  • auto-optimizer.test.ts — 31/31 passing (12 new across alpha + lossy guards, including their composition for WebP sources)
  • edit-applicator.test.ts — 34/34 passing (4 new for the animated WebP quality cap; existing PNG/GIF/JPEG/HEIF cases preserved)
  • image-processor.service.test.ts — 22/22 passing (3 new for the post-fetch alpha override on transparent PNG with varying dit-accept)
  • Smoke-test against a real origin: confirm transparent PNG icon stays transparent on Safari/Chrome; confirm JPEG photo with PNG-only Accept passes through as JPEG (not re-encoded to PNG); confirm an animated WebP comes back smaller than before
  • After deploy, watch the metricType: imageTransformation and new operation: alpha_jpeg_override log lines for unexpected volume

🤖 Generated with Claude Code

adityaverm-a and others added 6 commits June 1, 2026 17:26
Enable mozjpeg encoder for all JPEG transformations in edit-applicator.ts.
This reduces JPEG file size by 10-15% at comparable visual quality compared
to Sharp's default encoder, bringing DIT output in line with Cloudinary's
compression performance.

- Pass { mozjpeg: true } when converting to JPEG format
- Add test coverage to verify mozjpeg option is applied
- Achieves expected 10-15% file size reduction for JPEG output

Fixes: CloudFront DIT CDN Migration - Enable mozjpeg optimization for JPEG output
Co-authored-by: Cursor <cursoragent@cursor.com>
Enable palette quantization with maximum compression and adaptive filtering for PNG output in the Sharp format step to reduce transformed PNG payload size.
Update tests to assert the new PNG output options are applied.

Co-authored-by: Cursor <cursoragent@cursor.com>
Translate generic quality input into Sharp GIF options (colours, effort, inter-frame and inter-palette error) so GIF output uses real compression controls instead of an unsupported quality field. Add tests for mapping behavior and bounds clamping.

Co-authored-by: Cursor <cursoragent@cursor.com>
Two-layer alpha guard so transparent PNG/WebP icons are never flattened
to JPEG.

1. auto-optimizer: when the selected auto format is jpeg and the source
   content-type is image/png or image/webp, fall back to the next non-jpeg
   accepted format from FORMAT_PRIORITY; if none, return [] so the source
   format passes through.

2. image-processor: after sharp(buffer).metadata(), if hasAlpha is true,
   rewrite any format=jpeg transformation to webp (when image/webp is in
   dit-accept) else png. Catches URL-specified jpeg and origins whose
   Content-Type didn't disclose alpha.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Guard against re-encoding jpeg/webp sources into a lossless container
(png, tiff). Lossless can't recover quality the source already discarded,
so it only inflates file size — observed up to +307% on jpeg → png.

In getFormatOptimizations(), if the source content-type is in
LOSSY_SOURCE_CONTENT_TYPES (image/jpeg, image/jpg, image/webp) and the
selected format is in LOSSLESS_TARGET_FORMATS (png, tiff), fall back to
the next accepted non-lossless format. The fallback search keeps the
alpha guard's no-jpeg rule in effect for alpha-suspect sources so the
two guards compose. If no safe fallback is accepted, return [] so the
source format passes through unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Animated WebP can drop quality significantly without perceptual loss —
motion masking lets the eye tolerate compression artifacts between
rapidly changing frames. DIT previously emitted animated WebP at the
same Q80 as static content; on the 304 GIF→WebP rows shared with
Cloudinary, DIT was larger on 100% of rows, average +36%.

Thread the existing isAnimation flag (metadata.pages > 1, already
computed in applyEdits) into applyFormat and cap webp output quality at
ANIMATED_WEBP_QUALITY_CAP=50 when emitting animated content. A
caller-supplied lower quality is honored as-is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves DIT’s CDN image optimization by (1) upgrading Sharp encoder output options for several formats and (2) adding safety guards to prevent visually broken or size-inflating auto format selections (notably alpha → JPEG and lossy → lossless re-encodes).

Changes:

  • Add auto-format-selection guards to avoid transparency loss (alpha → JPEG) and lossy → lossless size bloat (JPEG/WebP → PNG/TIFF).
  • Enhance encoder configuration in the transformation engine (mozjpeg for JPEG, PNG compression settings, GIF quality mapping, and animated WebP quality capping).
  • Expand unit tests to cover the new guards and encoder behaviors.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
source/container/src/services/transformation-resolver/auto-optimization/auto-optimizer.ts Adds pre-fetch format-selection guards for alpha safety and lossy→lossless avoidance.
source/container/src/services/transformation-resolver/auto-optimization/auto-optimizer.test.ts Adds/updates tests validating the new format-selection guard behavior and guard composition.
source/container/src/services/image-processing/transformation-engine/edit-applicator.ts Upgrades Sharp output options across formats and caps animated WebP quality.
source/container/src/services/image-processing/transformation-engine/edit-applicator.test.ts Adds tests validating new encoder options and animated WebP cap behavior.
source/container/src/services/image-processing/image-processor.service.ts Adds post-fetch (metadata-based) alpha→JPEG override for defense in depth.
source/container/src/services/image-processing/image-processor.service.test.ts Adds tests for the post-fetch alpha override logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +82 to +83
const accept = req.header("dit-accept") || "";
console.log("Accept header found as: ", req.header("dit-accept"));
Comment on lines 144 to 146
function getQualityOptimizations(req: Request, qualityConfig: any): Transformation[] {
console.log('getQuality: ', qualityConfig)
console.log("getQuality: ", qualityConfig);
if (!qualityConfig || !Array.isArray(qualityConfig) || qualityConfig.length === 0) {
})
);

const isExpectedToBeAnimated = imageRequest.sourceImageContentType == "image/gif";
Comment on lines +116 to +117
const accept = imageRequest.clientHeaders?.["dit-accept"] || "";
const replacement = accept.includes("image/webp") ? "webp" : "png";
Comment on lines +82 to +83
const accept = req.header("dit-accept") || "";
console.log("Accept header found as: ", req.header("dit-accept"));
Comment on lines +116 to +117
const accept = imageRequest.clientHeaders?.["dit-accept"] || "";
const replacement = accept.includes("image/webp") ? "webp" : "png";
Comment on lines +82 to +83
const accept = req.header("dit-accept") || "";
console.log("Accept header found as: ", req.header("dit-accept"));
Comment on lines 144 to 146
function getQualityOptimizations(req: Request, qualityConfig: any): Transformation[] {
console.log('getQuality: ', qualityConfig)
console.log("getQuality: ", qualityConfig);
if (!qualityConfig || !Array.isArray(qualityConfig) || qualityConfig.length === 0) {
})
);

const isExpectedToBeAnimated = imageRequest.sourceImageContentType == "image/gif";
Comment on lines +116 to +117
const accept = imageRequest.clientHeaders?.["dit-accept"] || "";
const replacement = accept.includes("image/webp") ? "webp" : "png";
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.

2 participants