diff --git a/package-lock.json b/package-lock.json index 04eb37e5..baceee02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gb-printer-web", - "version": "1.42.4", + "version": "1.42.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gb-printer-web", - "version": "1.42.4", + "version": "1.42.5", "license": "MIT", "devDependencies": { "@babel/core": "^7.14.3", @@ -58,7 +58,7 @@ "filenamify": "^6.0.0", "filesize": "^6.1.0", "flatten": "^1.0.3", - "gb-image-decoder": "^1.2.0", + "gb-image-decoder": "^1.2.1", "gb-palettes": "^1.0.14", "gbp-decode": "^1.4.1", "github-markdown-css": "^4.0.0", @@ -7127,9 +7127,9 @@ } }, "node_modules/gb-image-decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gb-image-decoder/-/gb-image-decoder-1.2.0.tgz", - "integrity": "sha512-WgUcSONseUz4L0PFTMaQ7YnYJcnH8DHurRH0PLVOM+dQ165h/d8OXDk7Ali39zRb/CCywrn0iM8cgaQ205A8Hw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/gb-image-decoder/-/gb-image-decoder-1.2.1.tgz", + "integrity": "sha512-7YyLEgciywdQV9xlPRLq85thlA03fJgTNw2Eesmk3RaB2Z+5JzZZY8/HfPjt5GFmO8QGRE3ZfZFTbLPdqnLNfw==", "dev": true }, "node_modules/gb-palettes": { diff --git a/package.json b/package.json index 6c34a5fd..9e97beb1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gb-printer-web", - "version": "1.42.4", + "version": "1.42.5", "description": "gb-printer-web", "scripts": { "start": "webpack serve --config ./scripts/webpack.dev.js", @@ -75,7 +75,7 @@ "filenamify": "^6.0.0", "filesize": "^6.1.0", "flatten": "^1.0.3", - "gb-image-decoder": "^1.2.0", + "gb-image-decoder": "^1.2.1", "gb-palettes": "^1.0.14", "gbp-decode": "^1.4.1", "github-markdown-css": "^4.0.0", diff --git a/src/javascript/app/components/ImageRender/useImageRender.ts b/src/javascript/app/components/ImageRender/useImageRender.ts index f51a80da..19cd5f6f 100644 --- a/src/javascript/app/components/ImageRender/useImageRender.ts +++ b/src/javascript/app/components/ImageRender/useImageRender.ts @@ -96,9 +96,6 @@ export const useImageRender = ({ imageStartLine, lockFrame, rotation, - // This must/should be the only place where the `lockFrame`-attribute - // affects the actually used palette and invert option - // it must/should affect also the animation/plugin/save/share features framePalette: lockFrame ? framePalette : (palette as string[]), invertFramePalette: lockFrame ? invertFramePalette : invertPalette, }); diff --git a/src/javascript/app/store/middlewares/animate.ts b/src/javascript/app/store/middlewares/animate.ts index 52bf08cf..8d1bdff2 100644 --- a/src/javascript/app/store/middlewares/animate.ts +++ b/src/javascript/app/store/middlewares/animate.ts @@ -142,7 +142,7 @@ const createAnimation = async (state: State, dispatch: Dispatch) => { const canvases = await (Promise.all(animationFrames.map(async (image: Image): Promise => { const tiles = await tileLoader(image.hash); - const palette = getImagePalette(state, image); + const { palette, framePalette } = getImagePalette(state, image); const frame = state.frames.find(({ id }) => id === image.frame); const frameData = frame ? await loadFrameData(frame.hash) : null; @@ -155,7 +155,6 @@ const createAnimation = async (state: State, dispatch: Dispatch) => { const isRGBN = isRGBNImage(image); let decoder: RGBNDecoder | Decoder; const lockFrame = videoLockFrame || image.lockFrame || false; - const invertPalette = videoInvertPalette || (image as MonochromeImage).invertPalette || false; const rotation = image.rotation || 0; if (isRGBN) { @@ -168,16 +167,16 @@ const createAnimation = async (state: State, dispatch: Dispatch) => { }); } else { decoder = new Decoder(); - const pal = (palette as Palette).palette; - - const invertFramePalette = invertPalette; - const framePalette = lockFrame ? BW_PALETTE_HEX : pal; + const pal = (palette as Palette)?.palette || BW_PALETTE_HEX; + const framePal = (framePalette as Palette)?.palette || BW_PALETTE_HEX; + const invertPalette = videoInvertPalette || (image as MonochromeImage).invertPalette || false; + const invertFramePalette = videoInvertPalette || (image as MonochromeImage).invertFramePalette || false; const updateParams = getDecoderUpdateParams({ palette: pal, - framePalette, invertPalette, - invertFramePalette, + framePalette: lockFrame ? framePal : pal, + invertFramePalette: lockFrame ? invertFramePalette : invertPalette, }); decoder.update({ diff --git a/src/javascript/app/store/middlewares/dropboxStorage/middleware.ts b/src/javascript/app/store/middlewares/dropboxStorage/middleware.ts index e81931c7..ca55733e 100644 --- a/src/javascript/app/store/middlewares/dropboxStorage/middleware.ts +++ b/src/javascript/app/store/middlewares/dropboxStorage/middleware.ts @@ -7,7 +7,6 @@ import DropboxClient from '../../../../tools/DropboxClient'; import { hasher } from '../../../../tools/DropboxClient/dropboxContentHasher'; import parseAuthParams from '../../../../tools/parseAuthParams'; import { getPrepareFiles } from '../../../../tools/download'; -import getImagePalette from '../../../../tools/getImagePalette'; import { loadImageTiles } from '../../../../tools/loadImageTiles'; import replaceDuplicateFilenames from '../../../../tools/replaceDuplicateFilenames'; import getFilteredImages from '../../../../tools/getFilteredImages'; @@ -230,18 +229,17 @@ const middleware = (store: TypedStore): ((action: AnyAction) => Promise) = const downloadInfos = (await Promise.all( images.map(async (image, index): Promise => ( addToQueue('Generate images and hashes')(`${index + 1}/${images.length}`, 10, async () => { - const imagePalette = getImagePalette(state, image); const tiles = await loadTiles(image.hash); const frame = state.frames.find(({ id }) => id === image.frame); const frameData = frame ? await loadFrameData(frame?.hash) : null; const imageStartLine = frameData ? frameData.upper.length / 20 : 2; - if (!imagePalette || !tiles) { - throw new Error('palette or tiles missing'); + if (!tiles) { + throw new Error('tiles missing'); } - const imageBlobs = await prepareFiles(imagePalette, image)(tiles, imageStartLine); + const imageBlobs = await prepareFiles(image)(tiles, imageStartLine); const result = await Promise.all( imageBlobs.map(async (dlInfo: DownloadInfo): Promise => ({ diff --git a/src/javascript/app/store/middlewares/plugins.ts b/src/javascript/app/store/middlewares/plugins.ts index 6571a055..2310dd4a 100644 --- a/src/javascript/app/store/middlewares/plugins.ts +++ b/src/javascript/app/store/middlewares/plugins.ts @@ -1,6 +1,6 @@ import Queue from 'promise-queue'; import { saveAs } from 'file-saver'; -import type { RGBNTiles, RGBNPalette } from 'gb-image-decoder'; +import type { RGBNTiles, RGBNPalette, ExportFrameMode } from 'gb-image-decoder'; import { RGBNDecoder, Decoder, BW_PALETTE_HEX } from 'gb-image-decoder'; import { loadImageTiles } from '../../../tools/loadImageTiles'; import getImagePalette from '../../../tools/getImagePalette'; @@ -30,6 +30,16 @@ declare global { } } +export interface GetCanvasOptions { + scaleFactor?: number, + palette?: Palette | RGBNPalette, + framePalette?: Palette, + lockFrame?: boolean, + invertPalette?: boolean, + invertFramePalette?: boolean, + handleExportFrame?: ExportFrameMode, +} + const pluginsMiddleware: MiddlewareWithState = (store) => { const registeredPlugins: RegisteredPlugins = {}; const queue = new Queue(1, Infinity); @@ -50,7 +60,7 @@ const pluginsMiddleware: MiddlewareWithState = (store) => { throw new Error('image not found'); } - const selectedPalette = getImagePalette(state, meta); + const { palette: selectedPalette, framePalette: selectedFramePalette } = getImagePalette(state, meta); if (!selectedPalette) { throw new Error('selectedPalette not found'); } @@ -59,13 +69,17 @@ const pluginsMiddleware: MiddlewareWithState = (store) => { const isRGBN = isRGBNImage(meta); - const getCanvas = async ({ - scaleFactor = 1, - palette = selectedPalette, - lockFrame = meta.lockFrame || false, - invertPalette = (meta as MonochromeImage).invertPalette || false, - handleExportFrame = handleExportFrameState, - } = {}): Promise => { + const getCanvas = async (options: GetCanvasOptions = {}): Promise => { + const { + scaleFactor = 1, + palette = selectedPalette, + framePalette = selectedFramePalette, + lockFrame = meta.lockFrame || false, + invertPalette = (meta as MonochromeImage).invertPalette || false, + invertFramePalette = (meta as MonochromeImage).invertFramePalette || false, + handleExportFrame = handleExportFrameState, + } = options; + const tiles = await getTiles(); let decoder: RGBNDecoder | Decoder; @@ -83,14 +97,12 @@ const pluginsMiddleware: MiddlewareWithState = (store) => { }); } else { decoder = new Decoder(); - const pal = (palette as Palette).palette; - - const invertFramePalette = invertPalette; - const framePalette = lockFrame ? BW_PALETTE_HEX : pal; + const pal = (palette as Palette)?.palette || BW_PALETTE_HEX; + const framePal = (framePalette as Palette)?.palette || BW_PALETTE_HEX; const updateParams = getDecoderUpdateParams({ palette: pal, - framePalette, + framePalette: framePal, invertPalette, invertFramePalette, }); diff --git a/src/javascript/app/store/middlewares/share.ts b/src/javascript/app/store/middlewares/share.ts index 750c4c2d..d2056955 100644 --- a/src/javascript/app/store/middlewares/share.ts +++ b/src/javascript/app/store/middlewares/share.ts @@ -1,6 +1,5 @@ import { getPrepareFiles } from '../../../tools/download'; import { loadImageTiles } from '../../../tools/loadImageTiles'; -import getImagePalette from '../../../tools/getImagePalette'; import { Actions } from '../actions'; import type { MiddlewareWithState } from '../../../../types/MiddlewareWithState'; import { loadFrameData } from '../../../tools/applyFrame/frameData'; @@ -17,11 +16,6 @@ const batch: MiddlewareWithState = (store) => (next) => async (action) => { const frame = state.frames.find(({ id }) => id === image.frame); - const imagePalette = getImagePalette(state, image); - if (!imagePalette) { - throw new Error('imagePalette not found'); - } - const shareScaleFactor = [...state.exportScaleFactors].pop() || 4; const shareFileType = [...state.exportFileTypes].pop() || 'png'; @@ -37,7 +31,7 @@ const batch: MiddlewareWithState = (store) => (next) => async (action) => { const imageStartLine = frameData ? frameData.upper.length / 20 : 2; - const downloadInfo = await prepareFiles(imagePalette, image)(tiles || [], imageStartLine); + const downloadInfo = await prepareFiles(image)(tiles || [], imageStartLine); const { blob, filename, title } = downloadInfo[0]; diff --git a/src/javascript/app/store/middlewares/startDownload.ts b/src/javascript/app/store/middlewares/startDownload.ts index 859d99ab..2e2bf150 100644 --- a/src/javascript/app/store/middlewares/startDownload.ts +++ b/src/javascript/app/store/middlewares/startDownload.ts @@ -20,7 +20,7 @@ const handleSingleImage = ( const frame = state.frames.find(({ id }) => id === image.frame); - const imagePalette = getImagePalette(state, image); + const { palette: imagePalette } = getImagePalette(state, image); if (!imagePalette) { throw new Error('imagePalette not found'); } @@ -40,7 +40,7 @@ const handleSingleImage = ( throw new Error('no tiles'); } - const files = await prepareFiles(imagePalette, image)(tiles, imageStartLine); + const files = await prepareFiles(image)(tiles, imageStartLine); return download(zipFilename)(files); }; @@ -59,18 +59,13 @@ const handleImageCollection = const frame = state.frames.find(({ id }) => id === image.frame); - const imagePalette = getImagePalette(state, image); - if (!imagePalette) { - throw new Error('imagePalette not found'); - } - const tiles = await loadImageTiles(state)(image.hash); const frameData = frame ? await loadFrameData(frame?.hash) : null; const imageStartLine = frameData ? frameData.upper.length / 20 : 2; - return prepareFiles(imagePalette, image)(tiles || [], imageStartLine); + return prepareFiles(image)(tiles || [], imageStartLine); })) .then((resultImages) => resultImages.flat()) .then(download(zipFilename)); diff --git a/src/javascript/tools/download/getPrepareFiles.ts b/src/javascript/tools/download/getPrepareFiles.ts index 1d862c9a..588910e1 100644 --- a/src/javascript/tools/download/getPrepareFiles.ts +++ b/src/javascript/tools/download/getPrepareFiles.ts @@ -9,12 +9,12 @@ import type { Image, MonochromeImage } from '../../../types/Image'; import { isRGBNImage } from '../isRGBNImage'; import type { DownloadInfo } from '../../../types/Sync'; import { getDecoderUpdateParams } from '../getDecoderUpdateParams'; +import getImagePalette from '../getImagePalette'; const getPrepareFiles = ( state: State, ) => ( - palette: RGBNPalette | Palette, image: Image, ) => async ( tiles: string[] | RGBNTiles, @@ -25,9 +25,13 @@ const getPrepareFiles = let decoder: Decoder | RGBNDecoder; const isRGBN = isRGBNImage(image); const lockFrame = image.lockFrame || false; - const invertPalette = (image as MonochromeImage).invertPalette || false; const rotation = image.rotation || 0; + const { palette, framePalette } = getImagePalette(state, image); + + if (!palette) { + throw new Error('Palette missing?'); + } if (isRGBN) { decoder = new RGBNDecoder(); @@ -39,14 +43,14 @@ const getPrepareFiles = }); } else { decoder = new Decoder(); - const pal = (palette as Palette).palette; - - const invertFramePalette = invertPalette; - const framePalette = lockFrame ? BW_PALETTE_HEX : pal; + const pal = (palette as Palette)?.palette || BW_PALETTE_HEX; + const framePal = (framePalette as Palette)?.palette || BW_PALETTE_HEX; + const invertPalette = (image as MonochromeImage).invertPalette || false; + const invertFramePalette = (image as MonochromeImage).invertFramePalette || false; const updateParams = getDecoderUpdateParams({ palette: pal, - framePalette, + framePalette: framePal, invertPalette, invertFramePalette, }); diff --git a/src/javascript/tools/getImagePalette/index.ts b/src/javascript/tools/getImagePalette/index.ts index 9a56138e..d34ceb86 100644 --- a/src/javascript/tools/getImagePalette/index.ts +++ b/src/javascript/tools/getImagePalette/index.ts @@ -1,14 +1,26 @@ import type { RGBNPalette } from 'gb-image-decoder'; import type { State } from '../../app/store/State'; -import type { Image } from '../../../types/Image'; +import type { Image, MonochromeImage } from '../../../types/Image'; import type { Palette } from '../../../types/Palette'; import { isRGBNImage } from '../isRGBNImage'; -const getImagePalette = ({ palettes }: State, image: Image): RGBNPalette | Palette | undefined => { - const { palette } = image; - return isRGBNImage(image) ? - palette as RGBNPalette : - (palettes.find(({ shortName }) => shortName === palette)); +interface GetImagePalettes { + palette?: RGBNPalette | Palette, + framePalette?: Palette +} + +const getImagePalettes = ({ palettes }: State, image: Image): GetImagePalettes => { + if (isRGBNImage(image)) { + const { palette } = image; + return { + palette: palette as RGBNPalette, + }; + } + + return { + palette: palettes.find(({ shortName }) => shortName === image.palette), + framePalette: palettes.find(({ shortName }) => shortName === (image as MonochromeImage).framePalette), + }; }; -export default getImagePalette; +export default getImagePalettes;