diff --git a/lib/decoder.js b/lib/decoder.js index 4861357..4452834 100644 --- a/lib/decoder.js +++ b/lib/decoder.js @@ -623,6 +623,7 @@ var JpegImage = (function jpegImage() { var quantizationTables = [], frames = []; var huffmanTablesAC = [], huffmanTablesDC = []; var fileMarker = readUint16(); + var malformedDataOffset = -1; this.comments = []; if (fileMarker != 0xFFD8) { // SOI (Start of Image) throw new Error("SOI not found"); @@ -813,7 +814,6 @@ var JpegImage = (function jpegImage() { offset--; } break; - default: if (data[offset - 3] == 0xFF && data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) { @@ -822,6 +822,19 @@ var JpegImage = (function jpegImage() { offset -= 3; break; } + else if (fileMarker === 0xE0 || fileMarker == 0xE1) { + // Recover from malformed APP1 markers popular in some phone models. + // See https://github.com/eugeneware/jpeg-js/issues/82 + if (malformedDataOffset !== -1) { + throw new Error(`first unknown JPEG marker at offset ${malformedDataOffset.toString(16)}, second unknown JPEG marker ${fileMarker.toString(16)} at offset ${(offset - 1).toString(16)}`); + } + malformedDataOffset = offset - 1; + const nextOffset = readUint16(); + if (data[offset + nextOffset - 2] === 0xFF) { + offset += nextOffset - 2; + break; + } + } throw new Error("unknown JPEG marker " + fileMarker.toString(16)); } fileMarker = readUint16(); diff --git a/test/fixtures/table-with-bad-e1.jpg b/test/fixtures/table-with-bad-e1.jpg new file mode 100644 index 0000000..371b299 Binary files /dev/null and b/test/fixtures/table-with-bad-e1.jpg differ diff --git a/test/fixtures/table-with-good-e1.jpg b/test/fixtures/table-with-good-e1.jpg new file mode 100644 index 0000000..ab04e4a Binary files /dev/null and b/test/fixtures/table-with-good-e1.jpg differ diff --git a/test/index.js b/test/index.js index ed5f1f2..6944449 100644 --- a/test/index.js +++ b/test/index.js @@ -12,6 +12,14 @@ const SUPER_LARGE_JPEG_BASE64 = const SUPER_LARGE_JPEG_BUFFER = Buffer.from(SUPER_LARGE_JPEG_BASE64, 'base64'); +it('should be able read image with a bad e1 marker not preceeded by ff', function () { + var jpegData = fixture('table-with-bad-e1.jpg'); + var rawImageData = jpeg.decode(jpegData); + var expected = fixture('table-with-good-e1.jpg'); + var rawExpectedImageData = jpeg.decode(expected); + expect(rawImageData.data).toEqual(rawExpectedImageData.data); +}); + it('should be able to decode a JPEG', function () { var jpegData = fixture('grumpycat.jpg'); var rawImageData = jpeg.decode(jpegData);