GIF: parse Logical Screen Descriptor
This commit is contained in:
parent
c61a57ffbf
commit
025e45f9d2
|
@ -7,6 +7,13 @@ export const GifNodeType = [
|
||||||
"header",
|
"header",
|
||||||
"headerSignature",
|
"headerSignature",
|
||||||
"headerVersion",
|
"headerVersion",
|
||||||
|
|
||||||
|
"logicalScreenDescriptor",
|
||||||
|
"logicalScreenWidth",
|
||||||
|
"logicalScreenHeight",
|
||||||
|
"logicalScreenDescriptorPackedFields",
|
||||||
|
"logicalScreenBackgroundColorIndex",
|
||||||
|
"logicalScreenPixelAspectRatio",
|
||||||
].reduce((result, id) => {
|
].reduce((result, id) => {
|
||||||
result[id] = id;
|
result[id] = id;
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { GifNodeType } from "./constants.js";
|
||||||
import crel, { fragment } from "../common/crel.js";
|
import crel, { fragment } from "../common/crel.js";
|
||||||
import getOwn from "../common/getOwn.js";
|
import getOwn from "../common/getOwn.js";
|
||||||
import { areBytesEqual } from "../common/bytes.js";
|
import { areBytesEqual } from "../common/bytes.js";
|
||||||
|
import pluralize from "../common/pluralize.js";
|
||||||
/** @typedef {import("../../types/gif.d.ts").GifNode} GifNode */
|
/** @typedef {import("../../types/gif.d.ts").GifNode} GifNode */
|
||||||
|
|
||||||
const textEncoder = new TextEncoder();
|
const textEncoder = new TextEncoder();
|
||||||
|
@ -16,6 +17,15 @@ const VERSION_89 = textEncoder.encode("89a");
|
||||||
*/
|
*/
|
||||||
const p = (...children) => crel("p", {}, ...children);
|
const p = (...children) => crel("p", {}, ...children);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Uint8Array} bytes
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
const readGifUint = (bytes) => {
|
||||||
|
if (bytes.length !== 2) throw new Error("Expected 2 bytes");
|
||||||
|
return (bytes[1] << 8) | bytes[0];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {object} NodeUi
|
* @typedef {object} NodeUi
|
||||||
* @prop {string} title
|
* @prop {string} title
|
||||||
|
@ -57,6 +67,43 @@ const NODE_UI_FNS = {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Logical screen descriptor
|
||||||
|
|
||||||
|
[GifNodeType.logicalScreenDescriptor]: () => ({
|
||||||
|
title: "Logical Screen Descriptor",
|
||||||
|
description: p(
|
||||||
|
"The logical screen descriptor contains information about the overall GIF, such as its dimensions.",
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
[GifNodeType.logicalScreenWidth]: ({ bytes }) => ({
|
||||||
|
title: "Logical Screen Width",
|
||||||
|
description: p(
|
||||||
|
`The width of the image stored as a 16-bit little endian unsigned integer. In this case, the width is ${
|
||||||
|
pluralize(readGifUint(bytes), "byte")
|
||||||
|
}.`,
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
[GifNodeType.logicalScreenHeight]: ({ bytes }) => ({
|
||||||
|
title: "Logical Screen Height",
|
||||||
|
description: p(
|
||||||
|
`The height of the image stored as a 16-bit little endian unsigned integer. In this case, the height is ${
|
||||||
|
pluralize(readGifUint(bytes), "byte")
|
||||||
|
}.`,
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
[GifNodeType.logicalScreenDescriptorPackedFields]: () => ({
|
||||||
|
title: "Logical Screen Descriptor packed fields",
|
||||||
|
description: p("TODO"),
|
||||||
|
}),
|
||||||
|
[GifNodeType.logicalScreenBackgroundColorIndex]: () => ({
|
||||||
|
title: "Background Color Index",
|
||||||
|
description: p("TODO"),
|
||||||
|
}),
|
||||||
|
[GifNodeType.logicalScreenPixelAspectRatio]: () => ({
|
||||||
|
title: "Pixel Aspect Ratio",
|
||||||
|
description: p("TODO"),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,6 +112,8 @@ const NODE_UI_FNS = {
|
||||||
*/
|
*/
|
||||||
export default (node) => {
|
export default (node) => {
|
||||||
const uiFn = getOwn(NODE_UI_FNS, node.type);
|
const uiFn = getOwn(NODE_UI_FNS, node.type);
|
||||||
if (!uiFn) throw new Error("Found a node with no matching UI function");
|
if (!uiFn) {
|
||||||
|
throw new Error(`Found a node (${node.type}) with no matching UI function`);
|
||||||
|
}
|
||||||
return uiFn(node);
|
return uiFn(node);
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,33 @@ export default (bytes) => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: GifNodeType.headerVersion,
|
type: GifNodeType.headerVersion,
|
||||||
bytes: bytes.subarray(3, 6),
|
bytes: bytes.subarray(3, 3 + 3),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: GifNodeType.logicalScreenDescriptor,
|
||||||
|
bytes: bytes.subarray(6, 6 + 6),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: GifNodeType.logicalScreenWidth,
|
||||||
|
bytes: bytes.subarray(6, 6 + 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: GifNodeType.logicalScreenHeight,
|
||||||
|
bytes: bytes.subarray(8, 8 + 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: GifNodeType.logicalScreenDescriptorPackedFields,
|
||||||
|
bytes: bytes.subarray(10, 10 + 1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: GifNodeType.logicalScreenBackgroundColorIndex,
|
||||||
|
bytes: bytes.subarray(11, 11 + 1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: GifNodeType.logicalScreenPixelAspectRatio,
|
||||||
|
bytes: bytes.subarray(12, 12 + 1),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue