diff --git a/.eslintrc.cjs b/.eslintrc.cjs index f8eaaf9..49669a3 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -4,16 +4,16 @@ module.exports = { es2021: true, node: true, }, - extends: ['airbnb-base', 'prettier'], + extends: ["airbnb-base", "prettier"], overrides: [], parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', + ecmaVersion: "latest", + sourceType: "module", }, rules: { - 'import/extensions': [2, 'always'], - 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], - 'no-param-reassign': ['error', { props: false }], - 'no-bitwise': ['error', { allow: ['<<', '&'] }], + "import/extensions": [2, "always"], + "no-plusplus": ["error", { allowForLoopAfterthoughts: true }], + "no-param-reassign": ["error", { props: false }], + "no-bitwise": ["error", { allow: ["<<", "&"] }], }, }; diff --git a/main.js b/main.js index fc1153f..e1e3ed2 100644 --- a/main.js +++ b/main.js @@ -24,14 +24,14 @@ */ -import PBM from './src/pbm.js'; +import PBM from "./src/pbm.js"; -const thumbnailCanvas = document.getElementById('thumbnail-canvas'); -const thumbnailContext = thumbnailCanvas.getContext('2d'); -const imageCanvas = document.getElementById('image-canvas'); -const imageContext = imageCanvas.getContext('2d'); -const paletteCanvas = document.getElementById('palette-canvas'); -const paletteContext = paletteCanvas.getContext('2d'); +const thumbnailCanvas = document.getElementById("thumbnail-canvas"); +const thumbnailContext = thumbnailCanvas.getContext("2d"); +const imageCanvas = document.getElementById("image-canvas"); +const imageContext = imageCanvas.getContext("2d"); +const paletteCanvas = document.getElementById("palette-canvas"); +const paletteContext = paletteCanvas.getContext("2d"); let currentPalettePage = 0; let image = null; @@ -97,8 +97,8 @@ function loadImage(buffer) { return image; } -document.getElementById('imagefile').addEventListener( - 'change', +document.getElementById("imagefile").addEventListener( + "change", (e) => { const imageFile = e.target.files[0]; const reader = new FileReader(); @@ -116,24 +116,24 @@ document.getElementById('imagefile').addEventListener( ); // Palette navigation -document.getElementById('paletteLeft').addEventListener('click', () => { +document.getElementById("paletteLeft").addEventListener("click", () => { if (currentPalettePage === 0) { currentPalettePage = 3; } else { currentPalettePage -= 1; } - document.getElementById('palettePageLabel').innerText = + document.getElementById("palettePageLabel").innerText = currentPalettePage + 1; drawPalette(); }); -document.getElementById('paletteRight').addEventListener('click', () => { +document.getElementById("paletteRight").addEventListener("click", () => { if (currentPalettePage === 3) { currentPalettePage = 0; } else { currentPalettePage += 1; } - document.getElementById('palettePageLabel').innerText = + document.getElementById("palettePageLabel").innerText = currentPalettePage + 1; drawPalette(); }); @@ -145,11 +145,11 @@ function cycleColors(now) { if (!range.lastTime) range.lastTime = now; if (now - range.lastTime > range.rate / cycleSpeed) { - if (range.direction === 'forward') { + if (range.direction === "forward") { // Move last color to first position const lastColor = image.palette.splice(range.high, 1)[0]; image.palette.splice(range.low, 0, lastColor); - } else if (range.direction === 'reverse') { + } else if (range.direction === "reverse") { // Move first color to last position const firstColor = image.palette.splice(range.low, 1)[0]; image.palette.splice(range.high, 0, firstColor); @@ -169,13 +169,13 @@ function animate(now) { } document - .getElementById('cyclingSpeedSlider') - .addEventListener('input', (evt) => { + .getElementById("cyclingSpeedSlider") + .addEventListener("input", (evt) => { cycleSpeed = evt.target.value; - document.getElementById('cyclingSpeedLabel').innerText = cycleSpeed; + document.getElementById("cyclingSpeedLabel").innerText = cycleSpeed; }); -document.getElementById('cycleColors').addEventListener('click', () => { +document.getElementById("cycleColors").addEventListener("click", () => { if (running) { running = false; } else { diff --git a/src/binarystream.js b/src/binarystream.js index 8be328c..8d39753 100644 --- a/src/binarystream.js +++ b/src/binarystream.js @@ -58,7 +58,7 @@ class BinaryStream { } readString(length) { - let string = ''; + let string = ""; for (let i = 0; i < length; i++) { const byte = this.dataView.getUint8(this.index + i); diff --git a/src/pbm.js b/src/pbm.js index 9081ecc..bbcb8a2 100644 --- a/src/pbm.js +++ b/src/pbm.js @@ -24,7 +24,7 @@ */ -import BinaryStream from './binarystream.js'; +import BinaryStream from "./binarystream.js"; class PBM { constructor(arrayBuffer) { @@ -81,7 +81,7 @@ class PBM { const formatId = this.binaryStream.readString(4); // Validate chunk according to notes on https://en.wikipedia.org/wiki/ILBM - if (chunkId !== 'FORM') { + if (chunkId !== "FORM") { throw new Error( `Invalid chunkId: "${chunkId}" at byte ${this.binaryStream.index}. Expected "FORM".` ); @@ -95,7 +95,7 @@ class PBM { ); } - if (formatId !== 'PBM ') { + if (formatId !== "PBM ") { throw new Error(`Invalid formatId: "${formatId}". Expected "PBM ".`); } @@ -105,23 +105,23 @@ class PBM { chunkLength = this.binaryStream.readUint32BE(); switch (chunkId) { - case 'BMHD': + case "BMHD": this.parseBMHD(); break; - case 'CMAP': + case "CMAP": this.parseCMAP(); break; - case 'DPPS': + case "DPPS": // NOTE(m): Ignore unknown DPPS chunk of size 110 bytes this.binaryStream.jump(110); break; - case 'CRNG': + case "CRNG": this.parseCRNG(); break; - case 'TINY': + case "TINY": this.parseTINY(chunkLength); break; - case 'BODY': + case "BODY": this.parseBODY(chunkLength); break; default: @@ -191,7 +191,7 @@ class PBM { this.cyclingRanges.push({ rate, active: (flags & activeBitMask) !== 0, - direction: (flags & directionBitMask) !== 0 ? 'reverse' : 'forward', + direction: (flags & directionBitMask) !== 0 ? "reverse" : "forward", low, high, }); diff --git a/tests/pbm.test.js b/tests/pbm.test.js index 93b435f..d03d86a 100644 --- a/tests/pbm.test.js +++ b/tests/pbm.test.js @@ -25,46 +25,46 @@ */ -import { expect, test } from 'vitest'; +import { expect, test } from "vitest"; -import PBM from '../src/pbm.js'; +import PBM from "../src/pbm.js"; -const fs = require('fs'); +const fs = require("fs"); -test('Successfully parse a PBM file', () => { - const data = fs.readFileSync('./tests/fixtures/VALID.LBM'); +test("Successfully parse a PBM file", () => { + const data = fs.readFileSync("./tests/fixtures/VALID.LBM"); expect(() => { new PBM(data.buffer); }).not.toThrowError(); }); -test('Fail to parse a PBM file with an invalid chunk id', () => { - const data = fs.readFileSync('./tests/fixtures/INVALID_CHUNK_ID.LBM'); +test("Fail to parse a PBM file with an invalid chunk id", () => { + const data = fs.readFileSync("./tests/fixtures/INVALID_CHUNK_ID.LBM"); expect(() => { new PBM(data.buffer); }).toThrowError(/^Invalid chunkId: "FARM" at byte 12. Expected "FORM".$/); }); -test('Fail to parse a PBM file with an invalid chunk length', () => { - const data = fs.readFileSync('./tests/fixtures/INVALID_CHUNK_LENGTH.LBM'); +test("Fail to parse a PBM file with an invalid chunk length", () => { + const data = fs.readFileSync("./tests/fixtures/INVALID_CHUNK_LENGTH.LBM"); expect(() => { new PBM(data.buffer); }).toThrowError(/^Invalid chunk length: 7070 bytes. Expected 7012 bytes.$/); }); -test('Fail to parse an IFF file that is not a PBM file', () => { - const data = fs.readFileSync('./tests/fixtures/SEASCAPE.LBM'); +test("Fail to parse an IFF file that is not a PBM file", () => { + const data = fs.readFileSync("./tests/fixtures/SEASCAPE.LBM"); expect(() => { new PBM(data.buffer); }).toThrowError(/^Invalid formatId: "ILBM". Expected "PBM ".$/); }); -test('Parse a PBM bitmap header', () => { - const data = fs.readFileSync('./tests/fixtures/VALID.LBM'); +test("Parse a PBM bitmap header", () => { + const data = fs.readFileSync("./tests/fixtures/VALID.LBM"); const image = new PBM(data.buffer); expect(image.width).toStrictEqual(640); @@ -82,23 +82,23 @@ test('Parse a PBM bitmap header', () => { expect(image.pageHeight).toStrictEqual(480); }); -test('Parse PBM palette information', () => { - const data = fs.readFileSync('./tests/fixtures/VALID.LBM'); +test("Parse PBM palette information", () => { + const data = fs.readFileSync("./tests/fixtures/VALID.LBM"); const image = new PBM(data.buffer); expect(image.palette.length).toStrictEqual(256); expect(image.palette[10]).toStrictEqual([87, 255, 87]); }); -test('Parse PBM color cycling information', () => { - const data = fs.readFileSync('./tests/fixtures/VALID.LBM'); +test("Parse PBM color cycling information", () => { + const data = fs.readFileSync("./tests/fixtures/VALID.LBM"); const image = new PBM(data.buffer); expect(image.cyclingRanges.length).toStrictEqual(16); }); -test('Parse PBM thumbnail', () => { - const data = fs.readFileSync('./tests/fixtures/VALID.LBM'); +test("Parse PBM thumbnail", () => { + const data = fs.readFileSync("./tests/fixtures/VALID.LBM"); const image = new PBM(data.buffer); expect(image.thumbnail.width).toStrictEqual(80); @@ -106,8 +106,8 @@ test('Parse PBM thumbnail', () => { expect(image.thumbnail.size).toStrictEqual(4800); }); -test('Decode PBM thumbnail pixel data', () => { - const data = fs.readFileSync('./tests/fixtures/VALID.LBM'); +test("Decode PBM thumbnail pixel data", () => { + const data = fs.readFileSync("./tests/fixtures/VALID.LBM"); const image = new PBM(data.buffer); expect(image.thumbnail.pixelData.length).toStrictEqual(4800); @@ -116,8 +116,8 @@ test('Decode PBM thumbnail pixel data', () => { expect(image.palette[14]).toStrictEqual([255, 255, 87]); }); -test('Decode PBM image pixel data', () => { - const data = fs.readFileSync('./tests/fixtures/VALID.LBM'); +test("Decode PBM image pixel data", () => { + const data = fs.readFileSync("./tests/fixtures/VALID.LBM"); const image = new PBM(data.buffer); expect(image.pixelData.length).toStrictEqual(307_200);