Compare commits

..

No commits in common. "5089cceec708cb36d8d4ea369f97e1449c1df475" and "81c9a34fd30f64404738fbdf567a8d429f051be8" have entirely different histories.

View File

@ -17,6 +17,7 @@ import { assert, BaseException, warn } from "../shared/util.js";
import { ColorSpaceUtils } from "./colorspace_utils.js"; import { ColorSpaceUtils } from "./colorspace_utils.js";
import { DeviceCmykCS } from "./colorspace.js"; import { DeviceCmykCS } from "./colorspace.js";
import { grayToRGBA } from "../shared/image_utils.js"; import { grayToRGBA } from "../shared/image_utils.js";
import { readUint16 } from "./core_utils.js";
class JpegError extends BaseException { class JpegError extends BaseException {
constructor(msg) { constructor(msg) {
@ -121,7 +122,6 @@ function getBlockBufferOffset(component, row, col) {
function decodeScan( function decodeScan(
data, data,
view,
offset, offset,
frame, frame,
components, components,
@ -151,7 +151,7 @@ function decodeScan(
if (nextByte === /* DNL = */ 0xdc && parseDNLMarker) { if (nextByte === /* DNL = */ 0xdc && parseDNLMarker) {
offset += 2; // Skip marker length. offset += 2; // Skip marker length.
const scanLines = view.getUint16(offset); const scanLines = readUint16(data, offset);
offset += 2; offset += 2;
if (scanLines > 0 && scanLines !== frame.scanLines) { if (scanLines > 0 && scanLines !== frame.scanLines) {
throw new DNLMarkerError( throw new DNLMarkerError(
@ -434,7 +434,7 @@ function decodeScan(
// find marker // find marker
bitsCount = 0; bitsCount = 0;
fileMarker = findNextFileMarker(data, view, offset); fileMarker = findNextFileMarker(data, offset);
if (!fileMarker) { if (!fileMarker) {
break; // Reached the end of the image data without finding any marker. break; // Reached the end of the image data without finding any marker.
} }
@ -717,14 +717,14 @@ function buildComponentData(frame, component) {
return component.blockData; return component.blockData;
} }
function findNextFileMarker(data, view, currentPos, startPos = currentPos) { function findNextFileMarker(data, currentPos, startPos = currentPos) {
const maxPos = data.length - 1; const maxPos = data.length - 1;
let newPos = startPos < currentPos ? startPos : currentPos; let newPos = startPos < currentPos ? startPos : currentPos;
if (currentPos >= maxPos) { if (currentPos >= maxPos) {
return null; // Don't attempt to read non-existent data and just return. return null; // Don't attempt to read non-existent data and just return.
} }
const currentMarker = view.getUint16(currentPos); const currentMarker = readUint16(data, currentPos);
if (currentMarker >= 0xffc0 && currentMarker <= 0xfffe) { if (currentMarker >= 0xffc0 && currentMarker <= 0xfffe) {
return { return {
invalid: null, invalid: null,
@ -732,12 +732,12 @@ function findNextFileMarker(data, view, currentPos, startPos = currentPos) {
offset: currentPos, offset: currentPos,
}; };
} }
let newMarker = view.getUint16(newPos); let newMarker = readUint16(data, newPos);
while (!(newMarker >= 0xffc0 && newMarker <= 0xfffe)) { while (!(newMarker >= 0xffc0 && newMarker <= 0xfffe)) {
if (++newPos >= maxPos) { if (++newPos >= maxPos) {
return null; // Don't attempt to read non-existent data and just return. return null; // Don't attempt to read non-existent data and just return.
} }
newMarker = view.getUint16(newPos); newMarker = readUint16(data, newPos);
} }
return { return {
invalid: currentMarker.toString(16), invalid: currentMarker.toString(16),
@ -769,12 +769,12 @@ function prepareComponents(frame) {
frame.mcusPerColumn = mcusPerColumn; frame.mcusPerColumn = mcusPerColumn;
} }
function readDataBlock(data, view, offset) { function readDataBlock(data, offset) {
const length = view.getUint16(offset); const length = readUint16(data, offset);
offset += 2; offset += 2;
let endOffset = offset + length - 2; let endOffset = offset + length - 2;
const fileMarker = findNextFileMarker(data, view, endOffset, offset); const fileMarker = findNextFileMarker(data, endOffset, offset);
if (fileMarker?.invalid) { if (fileMarker?.invalid) {
warn( warn(
"readDataBlock - incorrect length, current marker is: " + "readDataBlock - incorrect length, current marker is: " +
@ -791,12 +791,12 @@ function readDataBlock(data, view, offset) {
}; };
} }
function skipData(data, view, offset) { function skipData(data, offset) {
const length = view.getUint16(offset); const length = readUint16(data, offset);
offset += 2; offset += 2;
const endOffset = offset + length - 2; const endOffset = offset + length - 2;
const fileMarker = findNextFileMarker(data, view, endOffset, offset); const fileMarker = findNextFileMarker(data, endOffset, offset);
if (fileMarker?.invalid) { if (fileMarker?.invalid) {
return fileMarker.offset; return fileMarker.offset;
} }
@ -810,16 +810,15 @@ class JpegImage {
} }
static canUseImageDecoder(data, colorTransform = -1) { static canUseImageDecoder(data, colorTransform = -1) {
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
let exifOffsets = null; let exifOffsets = null;
let offset = 0; let offset = 0;
let numComponents = null; let numComponents = null;
let fileMarker = view.getUint16(offset); let fileMarker = readUint16(data, offset);
offset += 2; offset += 2;
if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) { if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) {
throw new JpegError("SOI not found"); throw new JpegError("SOI not found");
} }
fileMarker = view.getUint16(offset); fileMarker = readUint16(data, offset);
offset += 2; offset += 2;
markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) { markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) {
@ -827,11 +826,7 @@ class JpegImage {
case 0xffe1: // APP1 - Exif case 0xffe1: // APP1 - Exif
// TODO: Remove this once https://github.com/w3c/webcodecs/issues/870 // TODO: Remove this once https://github.com/w3c/webcodecs/issues/870
// is fixed. // is fixed.
const { appData, oldOffset, newOffset } = readDataBlock( const { appData, oldOffset, newOffset } = readDataBlock(data, offset);
data,
view,
offset
);
offset = newOffset; offset = newOffset;
// 'Exif\x00\x00' // 'Exif\x00\x00'
@ -850,7 +845,7 @@ class JpegImage {
// since that can modify the original PDF document. // since that can modify the original PDF document.
exifOffsets = { exifStart: oldOffset + 6, exifEnd: newOffset }; exifOffsets = { exifStart: oldOffset + 6, exifEnd: newOffset };
} }
fileMarker = view.getUint16(offset); fileMarker = readUint16(data, offset);
offset += 2; offset += 2;
continue; continue;
case 0xffc0: // SOF0 (Start of Frame, Baseline DCT) case 0xffc0: // SOF0 (Start of Frame, Baseline DCT)
@ -869,8 +864,8 @@ class JpegImage {
} }
break; break;
} }
offset = skipData(data, view, offset); offset = skipData(data, offset);
fileMarker = view.getUint16(offset); fileMarker = readUint16(data, offset);
offset += 2; offset += 2;
} }
if (numComponents === 4) { if (numComponents === 4) {
@ -883,8 +878,6 @@ class JpegImage {
} }
parse(data, { dnlScanLines = null } = {}) { parse(data, { dnlScanLines = null } = {}) {
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
const maxOffset = data.length - 1;
let offset = 0; let offset = 0;
let jfif = null; let jfif = null;
let adobe = null; let adobe = null;
@ -894,12 +887,12 @@ class JpegImage {
const huffmanTablesAC = [], const huffmanTablesAC = [],
huffmanTablesDC = []; huffmanTablesDC = [];
let fileMarker = view.getUint16(offset); let fileMarker = readUint16(data, offset);
offset += 2; offset += 2;
if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) { if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) {
throw new JpegError("SOI not found"); throw new JpegError("SOI not found");
} }
fileMarker = view.getUint16(offset); fileMarker = readUint16(data, offset);
offset += 2; offset += 2;
markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) { markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) {
@ -922,7 +915,7 @@ class JpegImage {
case 0xffee: // APP14 case 0xffee: // APP14
case 0xffef: // APP15 case 0xffef: // APP15
case 0xfffe: // COM (Comment) case 0xfffe: // COM (Comment)
const { appData, newOffset } = readDataBlock(data, view, offset); const { appData, newOffset } = readDataBlock(data, offset);
offset = newOffset; offset = newOffset;
if (fileMarker === 0xffe0) { if (fileMarker === 0xffe0) {
@ -969,7 +962,7 @@ class JpegImage {
break; break;
case 0xffdb: // DQT (Define Quantization Tables) case 0xffdb: // DQT (Define Quantization Tables)
const quantizationTablesLength = view.getUint16(offset); const quantizationTablesLength = readUint16(data, offset);
offset += 2; offset += 2;
const quantizationTablesEnd = quantizationTablesLength + offset - 2; const quantizationTablesEnd = quantizationTablesLength + offset - 2;
let z; let z;
@ -986,7 +979,7 @@ class JpegImage {
// 16 bit values // 16 bit values
for (j = 0; j < 64; j++) { for (j = 0; j < 64; j++) {
z = dctZigZag[j]; z = dctZigZag[j];
tableData[z] = view.getUint16(offset); tableData[z] = readUint16(data, offset);
offset += 2; offset += 2;
} }
} else { } else {
@ -1008,10 +1001,10 @@ class JpegImage {
frame.extended = fileMarker === 0xffc1; frame.extended = fileMarker === 0xffc1;
frame.progressive = fileMarker === 0xffc2; frame.progressive = fileMarker === 0xffc2;
frame.precision = data[offset++]; frame.precision = data[offset++];
const sofScanLines = view.getUint16(offset); const sofScanLines = readUint16(data, offset);
offset += 2; offset += 2;
frame.scanLines = dnlScanLines || sofScanLines; frame.scanLines = dnlScanLines || sofScanLines;
frame.samplesPerLine = view.getUint16(offset); frame.samplesPerLine = readUint16(data, offset);
offset += 2; offset += 2;
frame.components = []; frame.components = [];
frame.componentIds = {}; frame.componentIds = {};
@ -1044,7 +1037,7 @@ class JpegImage {
break; break;
case 0xffc4: // DHT (Define Huffman Tables) case 0xffc4: // DHT (Define Huffman Tables)
const huffmanLength = view.getUint16(offset); const huffmanLength = readUint16(data, offset);
offset += 2; offset += 2;
for (i = 2; i < huffmanLength; ) { for (i = 2; i < huffmanLength; ) {
const huffmanTableSpec = data[offset++]; const huffmanTableSpec = data[offset++];
@ -1068,7 +1061,7 @@ class JpegImage {
case 0xffdd: // DRI (Define Restart Interval) case 0xffdd: // DRI (Define Restart Interval)
offset += 2; // Skip marker length. offset += 2; // Skip marker length.
resetInterval = view.getUint16(offset); resetInterval = readUint16(data, offset);
offset += 2; offset += 2;
break; break;
@ -1099,7 +1092,6 @@ class JpegImage {
try { try {
const processed = decodeScan( const processed = decodeScan(
data, data,
view,
offset, offset,
frame, frame,
components, components,
@ -1141,7 +1133,6 @@ class JpegImage {
// `startPos = offset - 3` when looking for the next valid marker. // `startPos = offset - 3` when looking for the next valid marker.
const nextFileMarker = findNextFileMarker( const nextFileMarker = findNextFileMarker(
data, data,
view,
/* currentPos = */ offset - 2, /* currentPos = */ offset - 2,
/* startPos = */ offset - 3 /* startPos = */ offset - 3
); );
@ -1153,7 +1144,7 @@ class JpegImage {
offset = nextFileMarker.offset; offset = nextFileMarker.offset;
break; break;
} }
if (!nextFileMarker || offset >= maxOffset) { if (!nextFileMarker || offset >= data.length - 1) {
warn( warn(
"JpegImage.parse - reached the end of the image data " + "JpegImage.parse - reached the end of the image data " +
"without finding an EOI marker (0xFFD9)." "without finding an EOI marker (0xFFD9)."
@ -1164,13 +1155,8 @@ class JpegImage {
"JpegImage.parse - unknown marker: " + fileMarker.toString(16) "JpegImage.parse - unknown marker: " + fileMarker.toString(16)
); );
} }
fileMarker = readUint16(data, offset);
if (offset < maxOffset) { offset += 2;
fileMarker = view.getUint16(offset);
offset += 2;
} else {
fileMarker = 0;
}
} }
if (!frame) { if (!frame) {