gb-image-decoder
Advanced tools
+73
-35
@@ -191,2 +191,11 @@ 'use strict'; | ||
| const createCanvasElement = () => { | ||
| try { | ||
| return document.createElement("canvas"); | ||
| } catch (error) { | ||
| throw new Error("cannot create canvas element"); | ||
| } | ||
| }; | ||
| const createImageData = (rawImageData, width, height) => new ImageData(rawImageData, width, height); | ||
| var __defProp$1 = Object.defineProperty; | ||
@@ -210,2 +219,4 @@ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
| __publicField$1(this, "imageStartLine"); | ||
| __publicField$1(this, "canvasCreator"); | ||
| __publicField$1(this, "imageDataCreator"); | ||
| this.canvas = null; | ||
@@ -221,2 +232,4 @@ this.tiles = []; | ||
| this.imageStartLine = 2; | ||
| this.canvasCreator = options?.canvasCreator || createCanvasElement; | ||
| this.imageDataCreator = options?.imageDataCreator || createImageData; | ||
| } | ||
@@ -232,3 +245,4 @@ update({ | ||
| const canvasChanged = canvas ? this.setCanvas(canvas) : false; | ||
| const palettesChanged = this.setPalettes(palette, framePalette); | ||
| const usedFramePalette = this.tilesPerLine === TILES_PER_LINE ? framePalette : palette; | ||
| const palettesChanged = this.setPalettes(palette, usedFramePalette); | ||
| if (startLineChanged || canvasChanged || palettesChanged || !this.tiles.length) { | ||
@@ -239,2 +253,3 @@ this.tiles = []; | ||
| const newHeight = this.getHeight(); | ||
| const newWidth = this.getWidth(); | ||
| if (!this.canvas) { | ||
@@ -247,5 +262,6 @@ return; | ||
| } | ||
| if (this.canvas.height !== newHeight || !this.rawImageData?.length) { | ||
| if (this.canvas.height !== newHeight || this.canvas.width !== newWidth || !this.rawImageData?.length) { | ||
| this.canvas.height = newHeight; | ||
| const newRawImageData = new Uint8ClampedArray(this.tilesPerLine * TILE_PIXEL_WIDTH * newHeight * 4); | ||
| this.canvas.width = newWidth; | ||
| const newRawImageData = new Uint8ClampedArray(newWidth * newHeight * 4); | ||
| this.rawImageData?.forEach((value, index) => { | ||
@@ -259,3 +275,3 @@ newRawImageData[index] = value; | ||
| }); | ||
| this.updateCanvas(newHeight); | ||
| this.updateCanvas(newWidth, newHeight); | ||
| } | ||
@@ -269,3 +285,3 @@ setImageStartLine(imageStartLine) { | ||
| } | ||
| updateCanvas(newHeight) { | ||
| updateCanvas(newWidth, newHeight) { | ||
| if (!this.canvas || !this.rawImageData?.length) { | ||
@@ -275,7 +291,10 @@ return; | ||
| const context = this.canvas.getContext("2d"); | ||
| const imageData = new ImageData(this.rawImageData, this.tilesPerLine * TILE_PIXEL_WIDTH, newHeight); | ||
| const imageData = this.imageDataCreator(this.rawImageData, newWidth, newHeight); | ||
| context?.putImageData(imageData, 0, 0); | ||
| } | ||
| getScaledCanvas(scaleFactor, handleExportFrame = ExportFrameMode.FRAMEMODE_KEEP) { | ||
| const handleFrameMode = this.tiles.length === 360 ? handleExportFrame : ExportFrameMode.FRAMEMODE_KEEP; | ||
| let handleFrameMode = handleExportFrame; | ||
| if ((this.tiles.length !== 360 || this.tilesPerLine !== TILES_PER_LINE) && handleFrameMode !== ExportFrameMode.FRAMEMODE_KEEP) { | ||
| handleFrameMode = ExportFrameMode.FRAMEMODE_KEEP; | ||
| } | ||
| const { | ||
@@ -285,4 +304,4 @@ initialHeight, | ||
| tilesPerLine | ||
| } = this.getScaledCanvasSize(handleFrameMode, this.getHeight()); | ||
| const canvas = document.createElement("canvas"); | ||
| } = this.getScaledCanvasSize(handleFrameMode); | ||
| const canvas = this.canvasCreator(); | ||
| const context = canvas.getContext("2d"); | ||
@@ -295,8 +314,10 @@ if (!context) { | ||
| this.getExportTiles(handleFrameMode).forEach((tile, index) => { | ||
| this.paintTileScaled(decodeTile(tile), index, context, scaleFactor, tilesPerLine, handleExportFrame); | ||
| this.paintTileScaled(decodeTile(tile), index, context, scaleFactor, tilesPerLine, handleFrameMode); | ||
| }); | ||
| return canvas; | ||
| } | ||
| getScaledCanvasSize(handleExportFrame, height) { | ||
| getScaledCanvasSize(handleExportFrame) { | ||
| const FRAME_TILES = 4; | ||
| const width = this.getWidth(); | ||
| const height = this.getHeight(); | ||
| switch (handleExportFrame) { | ||
@@ -306,3 +327,3 @@ case ExportFrameMode.FRAMEMODE_KEEP: | ||
| initialHeight: height, | ||
| initialWidth: this.tilesPerLine * TILE_PIXEL_WIDTH, | ||
| initialWidth: width, | ||
| tilesPerLine: this.tilesPerLine | ||
@@ -313,3 +334,3 @@ }; | ||
| initialHeight: height - TILE_PIXEL_HEIGHT * FRAME_TILES, | ||
| initialWidth: this.tilesPerLine * TILE_PIXEL_WIDTH - TILE_PIXEL_WIDTH * FRAME_TILES, | ||
| initialWidth: width - TILE_PIXEL_WIDTH * FRAME_TILES, | ||
| tilesPerLine: this.tilesPerLine - FRAME_TILES | ||
@@ -321,3 +342,3 @@ }; | ||
| initialHeight: height + 2 * TILE_PIXEL_HEIGHT, | ||
| initialWidth: this.tilesPerLine * TILE_PIXEL_WIDTH, | ||
| initialWidth: width, | ||
| tilesPerLine: this.tilesPerLine | ||
@@ -464,2 +485,5 @@ }; | ||
| } | ||
| getWidth() { | ||
| return TILE_PIXEL_WIDTH * this.tilesPerLine; | ||
| } | ||
| } | ||
@@ -481,5 +505,5 @@ | ||
| }; | ||
| const createChannel = (key, tilesPerLine) => { | ||
| const canvas = document.createElement("canvas"); | ||
| const decoder = new Decoder({ tilesPerLine }); | ||
| const createChannel = (key, decoderOptions) => { | ||
| const canvas = decoderOptions.canvasCreator(); | ||
| const decoder = new Decoder(decoderOptions); | ||
| decoder.update({ | ||
@@ -504,2 +528,4 @@ framePalette: [], | ||
| __publicField(this, "tilesPerLine"); | ||
| __publicField(this, "canvasCreator"); | ||
| __publicField(this, "imageDataCreator"); | ||
| this.canvas = null; | ||
@@ -509,7 +535,14 @@ this.palette = defaultPalette; | ||
| this.tilesPerLine = options?.tilesPerLine || TILES_PER_LINE; | ||
| this.canvasCreator = options?.canvasCreator || createCanvasElement; | ||
| this.imageDataCreator = options?.imageDataCreator || createImageData; | ||
| const channelDecoderOptions = { | ||
| tilesPerLine: this.tilesPerLine, | ||
| canvasCreator: this.canvasCreator, | ||
| imageDataCreator: this.imageDataCreator | ||
| }; | ||
| this.channels = { | ||
| r: createChannel(ChannelKey.R, this.tilesPerLine), | ||
| g: createChannel(ChannelKey.G, this.tilesPerLine), | ||
| b: createChannel(ChannelKey.B, this.tilesPerLine), | ||
| n: createChannel(ChannelKey.N, this.tilesPerLine) | ||
| r: createChannel(ChannelKey.R, channelDecoderOptions), | ||
| g: createChannel(ChannelKey.G, channelDecoderOptions), | ||
| b: createChannel(ChannelKey.B, channelDecoderOptions), | ||
| n: createChannel(ChannelKey.N, channelDecoderOptions) | ||
| }; | ||
@@ -528,3 +561,3 @@ } | ||
| const canvases = this.setTiles(tiles); | ||
| const newHeight = this.getHeight(); | ||
| const { width: newWidth, height: newHeight } = this.getDimensions(canvases); | ||
| if (!shouldUpdate) { | ||
@@ -543,2 +576,5 @@ return; | ||
| } | ||
| if (this.canvas.width !== newWidth) { | ||
| this.canvas.width = newWidth; | ||
| } | ||
| const context = this.canvas?.getContext("2d"); | ||
@@ -618,3 +654,3 @@ if (!context) { | ||
| getScaledCanvas(scaleFactor, handleExportFrame = ExportFrameMode.FRAMEMODE_KEEP) { | ||
| const canvas = document.createElement("canvas"); | ||
| const canvas = this.canvasCreator(); | ||
| const canvases = channels.reduce((acc, key) => { | ||
@@ -628,6 +664,3 @@ const channel = this.channels[key]; | ||
| }, {}); | ||
| const { width, height } = Object.values(canvases).reduce((acc, current) => ({ | ||
| width: Math.max(current.width, acc.width), | ||
| height: Math.max(current.height, acc.height) | ||
| }), { width: 0, height: 0 }); | ||
| const { width, height } = this.getDimensions(canvases); | ||
| canvas.width = width; | ||
@@ -639,14 +672,18 @@ canvas.height = height; | ||
| } | ||
| context.fillStyle = "#000000"; | ||
| context.fillRect(0, 0, 500, 500); | ||
| this.blendCanvases(context, canvases); | ||
| return canvas; | ||
| } | ||
| maxTiles() { | ||
| return channels.reduce((acc, key) => { | ||
| const channel = this.channels[key]; | ||
| return Math.max(acc, channel.tiles?.length || 0); | ||
| }, 0); | ||
| getDimensions(canvases) { | ||
| return Object.values(canvases).reduce((acc, current) => { | ||
| if (current.width === 0 || current.height === 0) { | ||
| return acc; | ||
| } | ||
| return { | ||
| width: Math.max(current.width, acc.width), | ||
| height: Math.max(current.height, acc.height) | ||
| }; | ||
| }, { width: 0, height: 0 }); | ||
| } | ||
| getHeight() { | ||
| return TILE_PIXEL_HEIGHT * Math.ceil(this.maxTiles() / this.tilesPerLine); | ||
| } | ||
| } | ||
@@ -659,2 +696,3 @@ | ||
| exports.BlendMode = BlendMode; | ||
| exports.ChannelKey = ChannelKey; | ||
| exports.Decoder = Decoder; | ||
@@ -661,0 +699,0 @@ exports.ExportFrameMode = ExportFrameMode; |
+11
-3
@@ -41,2 +41,4 @@ declare enum BlendMode { | ||
| type SourceCanvases = Partial<Record<ChannelKey, HTMLCanvasElement>>; | ||
| type CanvasCreator = () => HTMLCanvasElement; | ||
| type ImageDataCreator = (rawImageData: Uint8ClampedArray, width: number, height: number) => ImageData; | ||
| interface ChangedTile { | ||
@@ -67,2 +69,4 @@ index: number; | ||
| tilesPerLine?: number; | ||
| canvasCreator?: CanvasCreator; | ||
| imageDataCreator?: ImageDataCreator; | ||
| } | ||
@@ -94,2 +98,4 @@ interface DecoderUpdateParams { | ||
| private imageStartLine; | ||
| private canvasCreator; | ||
| private imageDataCreator; | ||
| constructor(options?: DecoderOptions); | ||
@@ -109,2 +115,3 @@ update({ canvas, tiles, palette, framePalette, imageStartLine, }: DecoderUpdateParams): void; | ||
| private getHeight; | ||
| private getWidth; | ||
| } | ||
@@ -118,2 +125,4 @@ | ||
| private tilesPerLine; | ||
| private canvasCreator; | ||
| private imageDataCreator; | ||
| constructor(options?: DecoderOptions); | ||
@@ -127,4 +136,3 @@ update({ canvas, tiles, palette, lockFrame, }: RGBNDecoderUpdateParams): void; | ||
| getScaledCanvas(scaleFactor: number, handleExportFrame?: ExportFrameMode): HTMLCanvasElement; | ||
| private maxTiles; | ||
| private getHeight; | ||
| private getDimensions; | ||
| } | ||
@@ -152,2 +160,2 @@ | ||
| export { type BWPalette, BW_PALETTE, BW_PALETTE_HEX, BlendMode, type ChangedTile, type Channel, type Channels, Decoder, type DecoderOptions, type DecoderUpdateParams, ExportFrameMode, type IndexedTilePixels, RGBNDecoder, type RGBNDecoderUpdateParams, type RGBNPalette, type RGBNTiles, type RGBValue, SKIP_LINE, type ScaledCanvasSize, type SourceCanvases, blendModeNewName, decodeTile, getRGBValue, maxTiles, tileIndexIsPartOfFrame }; | ||
| export { type BWPalette, BW_PALETTE, BW_PALETTE_HEX, BlendMode, type CanvasCreator, type ChangedTile, type Channel, ChannelKey, type Channels, Decoder, type DecoderOptions, type DecoderUpdateParams, ExportFrameMode, type ImageDataCreator, type IndexedTilePixels, RGBNDecoder, type RGBNDecoderUpdateParams, type RGBNPalette, type RGBNTiles, type RGBValue, SKIP_LINE, type ScaledCanvasSize, type SourceCanvases, blendModeNewName, decodeTile, getRGBValue, maxTiles, tileIndexIsPartOfFrame }; |
+11
-3
@@ -41,2 +41,4 @@ declare enum BlendMode { | ||
| type SourceCanvases = Partial<Record<ChannelKey, HTMLCanvasElement>>; | ||
| type CanvasCreator = () => HTMLCanvasElement; | ||
| type ImageDataCreator = (rawImageData: Uint8ClampedArray, width: number, height: number) => ImageData; | ||
| interface ChangedTile { | ||
@@ -67,2 +69,4 @@ index: number; | ||
| tilesPerLine?: number; | ||
| canvasCreator?: CanvasCreator; | ||
| imageDataCreator?: ImageDataCreator; | ||
| } | ||
@@ -94,2 +98,4 @@ interface DecoderUpdateParams { | ||
| private imageStartLine; | ||
| private canvasCreator; | ||
| private imageDataCreator; | ||
| constructor(options?: DecoderOptions); | ||
@@ -109,2 +115,3 @@ update({ canvas, tiles, palette, framePalette, imageStartLine, }: DecoderUpdateParams): void; | ||
| private getHeight; | ||
| private getWidth; | ||
| } | ||
@@ -118,2 +125,4 @@ | ||
| private tilesPerLine; | ||
| private canvasCreator; | ||
| private imageDataCreator; | ||
| constructor(options?: DecoderOptions); | ||
@@ -127,4 +136,3 @@ update({ canvas, tiles, palette, lockFrame, }: RGBNDecoderUpdateParams): void; | ||
| getScaledCanvas(scaleFactor: number, handleExportFrame?: ExportFrameMode): HTMLCanvasElement; | ||
| private maxTiles; | ||
| private getHeight; | ||
| private getDimensions; | ||
| } | ||
@@ -152,2 +160,2 @@ | ||
| export { type BWPalette, BW_PALETTE, BW_PALETTE_HEX, BlendMode, type ChangedTile, type Channel, type Channels, Decoder, type DecoderOptions, type DecoderUpdateParams, ExportFrameMode, type IndexedTilePixels, RGBNDecoder, type RGBNDecoderUpdateParams, type RGBNPalette, type RGBNTiles, type RGBValue, SKIP_LINE, type ScaledCanvasSize, type SourceCanvases, blendModeNewName, decodeTile, getRGBValue, maxTiles, tileIndexIsPartOfFrame }; | ||
| export { type BWPalette, BW_PALETTE, BW_PALETTE_HEX, BlendMode, type CanvasCreator, type ChangedTile, type Channel, ChannelKey, type Channels, Decoder, type DecoderOptions, type DecoderUpdateParams, ExportFrameMode, type ImageDataCreator, type IndexedTilePixels, RGBNDecoder, type RGBNDecoderUpdateParams, type RGBNPalette, type RGBNTiles, type RGBValue, SKIP_LINE, type ScaledCanvasSize, type SourceCanvases, blendModeNewName, decodeTile, getRGBValue, maxTiles, tileIndexIsPartOfFrame }; |
+11
-3
@@ -41,2 +41,4 @@ declare enum BlendMode { | ||
| type SourceCanvases = Partial<Record<ChannelKey, HTMLCanvasElement>>; | ||
| type CanvasCreator = () => HTMLCanvasElement; | ||
| type ImageDataCreator = (rawImageData: Uint8ClampedArray, width: number, height: number) => ImageData; | ||
| interface ChangedTile { | ||
@@ -67,2 +69,4 @@ index: number; | ||
| tilesPerLine?: number; | ||
| canvasCreator?: CanvasCreator; | ||
| imageDataCreator?: ImageDataCreator; | ||
| } | ||
@@ -94,2 +98,4 @@ interface DecoderUpdateParams { | ||
| private imageStartLine; | ||
| private canvasCreator; | ||
| private imageDataCreator; | ||
| constructor(options?: DecoderOptions); | ||
@@ -109,2 +115,3 @@ update({ canvas, tiles, palette, framePalette, imageStartLine, }: DecoderUpdateParams): void; | ||
| private getHeight; | ||
| private getWidth; | ||
| } | ||
@@ -118,2 +125,4 @@ | ||
| private tilesPerLine; | ||
| private canvasCreator; | ||
| private imageDataCreator; | ||
| constructor(options?: DecoderOptions); | ||
@@ -127,4 +136,3 @@ update({ canvas, tiles, palette, lockFrame, }: RGBNDecoderUpdateParams): void; | ||
| getScaledCanvas(scaleFactor: number, handleExportFrame?: ExportFrameMode): HTMLCanvasElement; | ||
| private maxTiles; | ||
| private getHeight; | ||
| private getDimensions; | ||
| } | ||
@@ -152,2 +160,2 @@ | ||
| export { type BWPalette, BW_PALETTE, BW_PALETTE_HEX, BlendMode, type ChangedTile, type Channel, type Channels, Decoder, type DecoderOptions, type DecoderUpdateParams, ExportFrameMode, type IndexedTilePixels, RGBNDecoder, type RGBNDecoderUpdateParams, type RGBNPalette, type RGBNTiles, type RGBValue, SKIP_LINE, type ScaledCanvasSize, type SourceCanvases, blendModeNewName, decodeTile, getRGBValue, maxTiles, tileIndexIsPartOfFrame }; | ||
| export { type BWPalette, BW_PALETTE, BW_PALETTE_HEX, BlendMode, type CanvasCreator, type ChangedTile, type Channel, ChannelKey, type Channels, Decoder, type DecoderOptions, type DecoderUpdateParams, ExportFrameMode, type ImageDataCreator, type IndexedTilePixels, RGBNDecoder, type RGBNDecoderUpdateParams, type RGBNPalette, type RGBNTiles, type RGBValue, SKIP_LINE, type ScaledCanvasSize, type SourceCanvases, blendModeNewName, decodeTile, getRGBValue, maxTiles, tileIndexIsPartOfFrame }; |
+73
-36
@@ -189,2 +189,11 @@ var BlendMode = /* @__PURE__ */ ((BlendMode2) => { | ||
| const createCanvasElement = () => { | ||
| try { | ||
| return document.createElement("canvas"); | ||
| } catch (error) { | ||
| throw new Error("cannot create canvas element"); | ||
| } | ||
| }; | ||
| const createImageData = (rawImageData, width, height) => new ImageData(rawImageData, width, height); | ||
| var __defProp$1 = Object.defineProperty; | ||
@@ -208,2 +217,4 @@ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
| __publicField$1(this, "imageStartLine"); | ||
| __publicField$1(this, "canvasCreator"); | ||
| __publicField$1(this, "imageDataCreator"); | ||
| this.canvas = null; | ||
@@ -219,2 +230,4 @@ this.tiles = []; | ||
| this.imageStartLine = 2; | ||
| this.canvasCreator = options?.canvasCreator || createCanvasElement; | ||
| this.imageDataCreator = options?.imageDataCreator || createImageData; | ||
| } | ||
@@ -230,3 +243,4 @@ update({ | ||
| const canvasChanged = canvas ? this.setCanvas(canvas) : false; | ||
| const palettesChanged = this.setPalettes(palette, framePalette); | ||
| const usedFramePalette = this.tilesPerLine === TILES_PER_LINE ? framePalette : palette; | ||
| const palettesChanged = this.setPalettes(palette, usedFramePalette); | ||
| if (startLineChanged || canvasChanged || palettesChanged || !this.tiles.length) { | ||
@@ -237,2 +251,3 @@ this.tiles = []; | ||
| const newHeight = this.getHeight(); | ||
| const newWidth = this.getWidth(); | ||
| if (!this.canvas) { | ||
@@ -245,5 +260,6 @@ return; | ||
| } | ||
| if (this.canvas.height !== newHeight || !this.rawImageData?.length) { | ||
| if (this.canvas.height !== newHeight || this.canvas.width !== newWidth || !this.rawImageData?.length) { | ||
| this.canvas.height = newHeight; | ||
| const newRawImageData = new Uint8ClampedArray(this.tilesPerLine * TILE_PIXEL_WIDTH * newHeight * 4); | ||
| this.canvas.width = newWidth; | ||
| const newRawImageData = new Uint8ClampedArray(newWidth * newHeight * 4); | ||
| this.rawImageData?.forEach((value, index) => { | ||
@@ -257,3 +273,3 @@ newRawImageData[index] = value; | ||
| }); | ||
| this.updateCanvas(newHeight); | ||
| this.updateCanvas(newWidth, newHeight); | ||
| } | ||
@@ -267,3 +283,3 @@ setImageStartLine(imageStartLine) { | ||
| } | ||
| updateCanvas(newHeight) { | ||
| updateCanvas(newWidth, newHeight) { | ||
| if (!this.canvas || !this.rawImageData?.length) { | ||
@@ -273,7 +289,10 @@ return; | ||
| const context = this.canvas.getContext("2d"); | ||
| const imageData = new ImageData(this.rawImageData, this.tilesPerLine * TILE_PIXEL_WIDTH, newHeight); | ||
| const imageData = this.imageDataCreator(this.rawImageData, newWidth, newHeight); | ||
| context?.putImageData(imageData, 0, 0); | ||
| } | ||
| getScaledCanvas(scaleFactor, handleExportFrame = ExportFrameMode.FRAMEMODE_KEEP) { | ||
| const handleFrameMode = this.tiles.length === 360 ? handleExportFrame : ExportFrameMode.FRAMEMODE_KEEP; | ||
| let handleFrameMode = handleExportFrame; | ||
| if ((this.tiles.length !== 360 || this.tilesPerLine !== TILES_PER_LINE) && handleFrameMode !== ExportFrameMode.FRAMEMODE_KEEP) { | ||
| handleFrameMode = ExportFrameMode.FRAMEMODE_KEEP; | ||
| } | ||
| const { | ||
@@ -283,4 +302,4 @@ initialHeight, | ||
| tilesPerLine | ||
| } = this.getScaledCanvasSize(handleFrameMode, this.getHeight()); | ||
| const canvas = document.createElement("canvas"); | ||
| } = this.getScaledCanvasSize(handleFrameMode); | ||
| const canvas = this.canvasCreator(); | ||
| const context = canvas.getContext("2d"); | ||
@@ -293,8 +312,10 @@ if (!context) { | ||
| this.getExportTiles(handleFrameMode).forEach((tile, index) => { | ||
| this.paintTileScaled(decodeTile(tile), index, context, scaleFactor, tilesPerLine, handleExportFrame); | ||
| this.paintTileScaled(decodeTile(tile), index, context, scaleFactor, tilesPerLine, handleFrameMode); | ||
| }); | ||
| return canvas; | ||
| } | ||
| getScaledCanvasSize(handleExportFrame, height) { | ||
| getScaledCanvasSize(handleExportFrame) { | ||
| const FRAME_TILES = 4; | ||
| const width = this.getWidth(); | ||
| const height = this.getHeight(); | ||
| switch (handleExportFrame) { | ||
@@ -304,3 +325,3 @@ case ExportFrameMode.FRAMEMODE_KEEP: | ||
| initialHeight: height, | ||
| initialWidth: this.tilesPerLine * TILE_PIXEL_WIDTH, | ||
| initialWidth: width, | ||
| tilesPerLine: this.tilesPerLine | ||
@@ -311,3 +332,3 @@ }; | ||
| initialHeight: height - TILE_PIXEL_HEIGHT * FRAME_TILES, | ||
| initialWidth: this.tilesPerLine * TILE_PIXEL_WIDTH - TILE_PIXEL_WIDTH * FRAME_TILES, | ||
| initialWidth: width - TILE_PIXEL_WIDTH * FRAME_TILES, | ||
| tilesPerLine: this.tilesPerLine - FRAME_TILES | ||
@@ -319,3 +340,3 @@ }; | ||
| initialHeight: height + 2 * TILE_PIXEL_HEIGHT, | ||
| initialWidth: this.tilesPerLine * TILE_PIXEL_WIDTH, | ||
| initialWidth: width, | ||
| tilesPerLine: this.tilesPerLine | ||
@@ -462,2 +483,5 @@ }; | ||
| } | ||
| getWidth() { | ||
| return TILE_PIXEL_WIDTH * this.tilesPerLine; | ||
| } | ||
| } | ||
@@ -479,5 +503,5 @@ | ||
| }; | ||
| const createChannel = (key, tilesPerLine) => { | ||
| const canvas = document.createElement("canvas"); | ||
| const decoder = new Decoder({ tilesPerLine }); | ||
| const createChannel = (key, decoderOptions) => { | ||
| const canvas = decoderOptions.canvasCreator(); | ||
| const decoder = new Decoder(decoderOptions); | ||
| decoder.update({ | ||
@@ -502,2 +526,4 @@ framePalette: [], | ||
| __publicField(this, "tilesPerLine"); | ||
| __publicField(this, "canvasCreator"); | ||
| __publicField(this, "imageDataCreator"); | ||
| this.canvas = null; | ||
@@ -507,7 +533,14 @@ this.palette = defaultPalette; | ||
| this.tilesPerLine = options?.tilesPerLine || TILES_PER_LINE; | ||
| this.canvasCreator = options?.canvasCreator || createCanvasElement; | ||
| this.imageDataCreator = options?.imageDataCreator || createImageData; | ||
| const channelDecoderOptions = { | ||
| tilesPerLine: this.tilesPerLine, | ||
| canvasCreator: this.canvasCreator, | ||
| imageDataCreator: this.imageDataCreator | ||
| }; | ||
| this.channels = { | ||
| r: createChannel(ChannelKey.R, this.tilesPerLine), | ||
| g: createChannel(ChannelKey.G, this.tilesPerLine), | ||
| b: createChannel(ChannelKey.B, this.tilesPerLine), | ||
| n: createChannel(ChannelKey.N, this.tilesPerLine) | ||
| r: createChannel(ChannelKey.R, channelDecoderOptions), | ||
| g: createChannel(ChannelKey.G, channelDecoderOptions), | ||
| b: createChannel(ChannelKey.B, channelDecoderOptions), | ||
| n: createChannel(ChannelKey.N, channelDecoderOptions) | ||
| }; | ||
@@ -526,3 +559,3 @@ } | ||
| const canvases = this.setTiles(tiles); | ||
| const newHeight = this.getHeight(); | ||
| const { width: newWidth, height: newHeight } = this.getDimensions(canvases); | ||
| if (!shouldUpdate) { | ||
@@ -541,2 +574,5 @@ return; | ||
| } | ||
| if (this.canvas.width !== newWidth) { | ||
| this.canvas.width = newWidth; | ||
| } | ||
| const context = this.canvas?.getContext("2d"); | ||
@@ -616,3 +652,3 @@ if (!context) { | ||
| getScaledCanvas(scaleFactor, handleExportFrame = ExportFrameMode.FRAMEMODE_KEEP) { | ||
| const canvas = document.createElement("canvas"); | ||
| const canvas = this.canvasCreator(); | ||
| const canvases = channels.reduce((acc, key) => { | ||
@@ -626,6 +662,3 @@ const channel = this.channels[key]; | ||
| }, {}); | ||
| const { width, height } = Object.values(canvases).reduce((acc, current) => ({ | ||
| width: Math.max(current.width, acc.width), | ||
| height: Math.max(current.height, acc.height) | ||
| }), { width: 0, height: 0 }); | ||
| const { width, height } = this.getDimensions(canvases); | ||
| canvas.width = width; | ||
@@ -637,14 +670,18 @@ canvas.height = height; | ||
| } | ||
| context.fillStyle = "#000000"; | ||
| context.fillRect(0, 0, 500, 500); | ||
| this.blendCanvases(context, canvases); | ||
| return canvas; | ||
| } | ||
| maxTiles() { | ||
| return channels.reduce((acc, key) => { | ||
| const channel = this.channels[key]; | ||
| return Math.max(acc, channel.tiles?.length || 0); | ||
| }, 0); | ||
| getDimensions(canvases) { | ||
| return Object.values(canvases).reduce((acc, current) => { | ||
| if (current.width === 0 || current.height === 0) { | ||
| return acc; | ||
| } | ||
| return { | ||
| width: Math.max(current.width, acc.width), | ||
| height: Math.max(current.height, acc.height) | ||
| }; | ||
| }, { width: 0, height: 0 }); | ||
| } | ||
| getHeight() { | ||
| return TILE_PIXEL_HEIGHT * Math.ceil(this.maxTiles() / this.tilesPerLine); | ||
| } | ||
| } | ||
@@ -654,2 +691,2 @@ | ||
| export { BW_PALETTE, BW_PALETTE_HEX, BlendMode, Decoder, ExportFrameMode, RGBNDecoder, SKIP_LINE, blendModeNewName, decodeTile, getRGBValue, maxTiles, tileIndexIsPartOfFrame }; | ||
| export { BW_PALETTE, BW_PALETTE_HEX, BlendMode, ChannelKey, Decoder, ExportFrameMode, RGBNDecoder, SKIP_LINE, blendModeNewName, decodeTile, getRGBValue, maxTiles, tileIndexIsPartOfFrame }; |
+11
-4
| { | ||
| "name": "gb-image-decoder", | ||
| "version": "1.2.1", | ||
| "version": "1.3.0", | ||
| "description": "Decoder classes for GameBoy-encoded images", | ||
@@ -18,7 +18,11 @@ "repository": "", | ||
| "types": "./dist/index.d.ts", | ||
| "files": ["dist"], | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "scripts": { | ||
| "prepack": "npm run eslint && npm run build", | ||
| "prepack": "npm run eslint && npm run test && npm run build", | ||
| "build": "unbuild", | ||
| "dev": "vitest dev", | ||
| "test": "rimraf images && vitest run", | ||
| "test:u": "rimraf images && vitest run -u", | ||
| "eslint": "eslint -c .eslintrc --ext .js,.ts ." | ||
@@ -29,2 +33,3 @@ }, | ||
| "@typescript-eslint/eslint-plugin": "^7.9.0", | ||
| "canvas": "^2.11.2", | ||
| "eslint": "^8.57.0", | ||
@@ -34,6 +39,8 @@ "eslint-config-airbnb-base": "^15.0.0", | ||
| "eslint-plugin-import": "^2.29.1", | ||
| "jsdom": "^25.0.1", | ||
| "ohash": "^1.1.4", | ||
| "typescript": "^5.4.5", | ||
| "unbuild": "^2.0.0", | ||
| "vitest": "^1.6.0" | ||
| "vitest": "^2.1.3" | ||
| } | ||
| } |
64932
6.76%1474
5.81%12
33.33%