diff --git a/packages/core/src/utils/request-tokenizer/imageTokenizer.test.ts b/packages/core/src/utils/request-tokenizer/imageTokenizer.test.ts index cdb5f35f5c9..57f8994ee0a 100644 --- a/packages/core/src/utils/request-tokenizer/imageTokenizer.test.ts +++ b/packages/core/src/utils/request-tokenizer/imageTokenizer.test.ts @@ -102,6 +102,31 @@ describe('ImageTokenizer', () => { }); }); + describe('WebP dimension extraction', () => { + it('should extract canvas dimensions from VP8X', async () => { + const width = 100; + const height = 80; + + const buf = Buffer.alloc(30); + buf.write('RIFF', 0, 'ascii'); + buf.writeUInt32LE(22, 4); + buf.write('WEBP', 8, 'ascii'); + buf.write('VP8X', 12, 'ascii'); + buf.writeUInt32LE(10, 16); // VP8X chunk size + buf.writeUInt8(0, 20); // flags + buf.writeUIntLE(width - 1, 24, 3); // canvas width minus one (24-bit LE) + buf.writeUIntLE(height - 1, 27, 3); // canvas height minus one (24-bit LE) + + const metadata = await tokenizer.extractImageMetadata( + buf.toString('base64'), + 'image/webp', + ); + + expect(metadata.width).toBe(width); + expect(metadata.height).toBe(height); + }); + }); + describe('batch processing', () => { it('should process multiple images serially', async () => { const pngBase64 = diff --git a/packages/core/src/utils/request-tokenizer/imageTokenizer.ts b/packages/core/src/utils/request-tokenizer/imageTokenizer.ts index 76933a0c80d..bf9dc20996f 100644 --- a/packages/core/src/utils/request-tokenizer/imageTokenizer.ts +++ b/packages/core/src/utils/request-tokenizer/imageTokenizer.ts @@ -213,17 +213,20 @@ export class ImageTokenizer { const format = buffer.subarray(12, 16).toString('ascii'); if (format === 'VP8 ') { + // Lossy: 14-bit width/height at bytes 26-27 and 28-29 (little-endian) const width = buffer.readUInt16LE(26) & 0x3fff; const height = buffer.readUInt16LE(28) & 0x3fff; return { width, height }; } else if (format === 'VP8L') { + // Lossless: 14-bit (width-1) then (height-1) packed from byte 21 (little-endian) const bits = buffer.readUInt32LE(21); const width = (bits & 0x3fff) + 1; const height = ((bits >> 14) & 0x3fff) + 1; return { width, height }; } else if (format === 'VP8X') { - const width = (buffer.readUInt32LE(24) & 0xffffff) + 1; - const height = (buffer.readUInt32LE(26) & 0xffffff) + 1; + // Extended: 24-bit (canvas width-1) at bytes 24-26 and (height-1) at bytes 27-29 (little-endian) + const width = buffer.readUIntLE(24, 3) + 1; + const height = buffer.readUIntLE(27, 3) + 1; return { width, height }; }