Skip to content

Commit 2ed54cd

Browse files
authored
Update decoder to correctly handle grayscale PNGs (#23393)
This PR updates the Squoosh PNG decoder, which fixes #22929 in GoogleChromeLabs/squoosh#971. ## Bug - [x] Fixes #22929 - [x] Integration tests added ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. ## Documentation / Examples - [ ] Make sure the linting passes
1 parent 65c2216 commit 2ed54cd

File tree

4 files changed

+47
-12
lines changed

4 files changed

+47
-12
lines changed

packages/next/next-server/server/lib/squoosh/png/squoosh_png.js

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
1+
import { TextDecoder } from '../text-decoder'
2+
13
let wasm
24

5+
let cachedTextDecoder = new TextDecoder('utf-8', {
6+
ignoreBOM: true,
7+
fatal: true,
8+
})
9+
10+
cachedTextDecoder.decode()
11+
12+
let cachegetUint8Memory0 = null
13+
function getUint8Memory0() {
14+
if (
15+
cachegetUint8Memory0 === null ||
16+
cachegetUint8Memory0.buffer !== wasm.memory.buffer
17+
) {
18+
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer)
19+
}
20+
return cachegetUint8Memory0
21+
}
22+
23+
function getStringFromWasm0(ptr, len) {
24+
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len))
25+
}
26+
327
let cachegetUint8ClampedMemory0 = null
428
function getUint8ClampedMemory0() {
529
if (
@@ -30,17 +54,6 @@ function addHeapObject(obj) {
3054
return idx
3155
}
3256

33-
let cachegetUint8Memory0 = null
34-
function getUint8Memory0() {
35-
if (
36-
cachegetUint8Memory0 === null ||
37-
cachegetUint8Memory0.buffer !== wasm.memory.buffer
38-
) {
39-
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer)
40-
}
41-
return cachegetUint8Memory0
42-
}
43-
4457
let WASM_VECTOR_LEN = 0
4558

4659
function passArray8ToWasm0(arg, malloc) {
@@ -161,7 +174,9 @@ async function init(input) {
161174
var ret = new ImageData(v0, arg2 >>> 0, arg3 >>> 0)
162175
return addHeapObject(ret)
163176
}
164-
177+
imports.wbg.__wbindgen_throw = function (arg0, arg1) {
178+
throw new Error(getStringFromWasm0(arg0, arg1))
179+
}
165180
if (
166181
typeof input === 'string' ||
167182
(typeof Request === 'function' && input instanceof Request) ||
Binary file not shown.
234 Bytes
Loading

test/integration/image-optimizer/test/index.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,26 @@ function runTests({ w, isDev, domains }) {
482482
await expectWidth(res, 400)
483483
})
484484

485+
it('should not change the color type of a png', async () => {
486+
// https://github.com/vercel/next.js/issues/22929
487+
// A grayscaled PNG with transparent pixels.
488+
const query = { url: '/grayscale.png', w: largeSize, q: 80 }
489+
const opts = { headers: { accept: 'image/png' } }
490+
const res = await fetchViaHTTP(appPort, '/_next/image', query, opts)
491+
expect(res.status).toBe(200)
492+
expect(res.headers.get('Content-Type')).toBe('image/png')
493+
expect(res.headers.get('cache-control')).toBe(
494+
'public, max-age=0, must-revalidate'
495+
)
496+
497+
const png = await res.buffer()
498+
499+
// Read the color type byte (offset 9 + magic number 16).
500+
// http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html
501+
const colorType = png.readUIntBE(25, 1)
502+
expect(colorType).toBe(4)
503+
})
504+
485505
it("should error if the resource isn't a valid image", async () => {
486506
const query = { url: '/test.txt', w, q: 80 }
487507
const opts = { headers: { accept: 'image/webp' } }

0 commit comments

Comments
 (0)