Copilot / AI Agent Instructions for xcfreader
February 11, 2026 · View on GitHub
Summary
- Small Node.js library that parses GIMP
.xcffiles and exposes a TypeScript/JS API to read metadata, layers and render images. - Source is in
src/(TypeScript).dist/contains compiled output (built with TypeScript compilertsc) and is the package target during runtime.
Quick workflow
- Install dev deps:
npm install. - Build TypeScript:
npm run build(runstscto compilesrc/**/*.ts→dist/). - Run examples (uses
node+nodemon):npm run single,npm run multi,npm run map,npm run text,npm run empty.- These commands now build TypeScript first, then execute the compiled JS.
- Run tests:
npm test(builds and runsdist/tests/runner.js). - Watch mode:
npm run watch(continuously recompiles TypeScript as you edit).
Where to look (key files)
- ../src/gimpparser.ts — main parser implementation with
GimpLayer,XCFParserclasses; types and error classes. - ../src/lib/binary-reader.ts — lightweight binary reader for XCF parsing (~1.5 KB minified).
- ../src/lib/xcf-parsers.ts — functional parsers for all XCF structures (headers, layers, properties).
- ../src/node.ts — Node.js entry point; exports
XCFPNGImagefor PNG file output. - ../src/browser.ts — Browser entry point; exports
XCFDataImagefor canvas rendering. - ../src/lib/xcfpngimage.ts — PNG-based image class using
pngjs(Node.js only). - ../src/lib/xcfdataimage.ts — ImageData-based image class for browsers.
- ../src/lib/xcfcompositer.ts — compositing mode implementations (HSV, General, Dissolve).
- ../src/types/index.ts — TypeScript type definitions including
IXCFImageinterface. - ../src/examples/ — TypeScript example scripts (single, multi, map, text, empty) showing public API usage.
- ../src/tests/ — TypeScript test files; tests/runner.ts dynamically imports numbered tests.
- ../tsconfig.json — TypeScript compiler configuration; targets ES2020, declaration files enabled.
- ../readme.md — user-facing API docs with entry points and image class documentation.
Architecture & implementation notes
- Binary parsing: Uses custom
BinaryReaderclass (in lib/binary-reader.ts) for efficient XCF parsing.- Lightweight implementation (~1.5 KB minified) with only XCF-specific operations
- Functional parsers in lib/xcf-parsers.ts for all XCF structures
XCF_PropTypeenum in types/index.ts defines property types.- XCF v011 support: Separate parser functions for v010 (32-bit) and v011 (64-bit pointers):
parseGimpHeaderV10/parseGimpHeaderV11- header with layer/channel pointer listsparseLayerV10/parseLayerV11- layer with hptr/mptr pointersparseHierarchyV10/parseHierarchyV11- hierarchy with lptr pointerparseLevelV10/parseLevelV11- level with tptr tile pointer array
XCFParser.isV11getter detects version;GimpLayerselects correct parser at runtime.- Perfect TypeScript types for all parsed structures
- Buffer management: XCF is a single binary Buffer; offsets/pointers index into it. Use
XCFParser.getBufferForPointer(offset)to slice. - Tiled rendering: Layers use 64×64 tile blocks.
GimpLayer.uncompress()decompresses tile data;copyTile()writes pixels to image. - Compositing:
XCFCompositer.makeCompositer(mode, opacity)returns compositing logic (blend modes); used inGimpLayer.makeImage(). - Image classes: Two implementations of
IXCFImageinterface:XCFPNGImage(Node.js) - wrapspngjs, haswriteImage()for file outputXCFDataImage(Browser) - usesUint8ClampedArray, hasimageDatagetter for canvas
- Entry points: Separate modules for different environments:
gimpparser.ts- base module with parser, no image classesnode.ts- re-exports everything plusXCFPNGImagebrowser.ts- re-exports everything plusXCFDataImage
- Type safety: Full TypeScript with strict mode; interfaces for
ColorRGBA,IXCFImage, Parser result types.
Conventions & patterns
- Edit source in
src/only. TypeScript files (.ts) are compiled todist/bynpm run build. - Do not edit
dist/except to inspect compiled output for debugging transpilation. - Prefer small, focused parser changes; add validation checks for expected field lengths and values.
- Use native Array methods (
filter,map,forEach,find,slice,reverse) for array flows. - Async API:
XCFParser.parseFileAsync(file)returnsPromise<XCFParser>; tests and examples useasync/await. - When adding API features, update readme.md and examples in src/examples/.
Building & running
Build TypeScript:
npm run build
Run examples (auto-builds first):
npm run single # parse and render single.xcf with live reload (nodemon)
npm run multi # parse and render multi.xcf
npm run map # parse and render specific layers from map1.xcf
npm run text # parse text.xcf with parasite inspection
npm run empty # test parsing empty.xcf
npm run grey # parse grayscale v011 file (64-bit pointers)
Run tests (auto-builds first):
npm test
Watch mode (recompile on file changes):
npm run watch
Testing tips
- Tests are in ../src/tests/ and run via
npm test. - Test files are numbered (
01-parse-single.ts, etc.) and auto-imported by runner.ts. - Each test imports from
../node.js(forXCFPNGImage) or../gimpparser.js(parser only). - Add new tests as
src/tests/NN-description.tsand export atestNNFunctionwith signature:async function testNN(): Promise<void>. - Add the test to the imports in runner.ts.
Common edits
Adding a new layer property:
- Add
PROP_MY_THING = NtoXCF_PropTypeenum in types/index.ts. - Create a parser function in lib/xcf-parsers.ts (see existing patterns).
- Add a case in
parseProperty()switch statement forXCF_PropType.PROP_MY_THING. - Access via
layer.getProps(XCF_PropType.PROP_MY_THING)in parsing code.
Updating compositing logic:
- Blending math lives in
XCFCompositerand subclasses in src/lib/xcfcompositer.ts. - Each blend mode is a
caseinGeneralCompositer.chooseFunction(). - Update constants (
PROP_MODE_*) and switch logic; tests verify against test images.
Adding an example:
- Create ../src/examples/myexample.ts.
- Import
{ XCFParser as GimpParser, XCFPNGImage } from '../node.js'. - Use
GimpParser.parseFileAsync(path), createnew XCFPNGImage(w, h), and callparser.createImage(image). - Add script to package.json scripts:
"myexample": "npm run build && nodemon --exec node dist/examples/myexample.js". - Export or log results.
Type system
- Color type:
{ red: number; green: number; blue: number; alpha?: number }(0–255 range). - ColorRGBA type:
{ red; green; blue; alpha: number }(always includes alpha). - XCF_BaseType enum:
RGB = 0,GRAYSCALE = 1,INDEXED = 2- image color mode. - Parser result types: Strongly typed interfaces for all XCF structures (e.g.,
ParsedGimpHeaderV10,ParsedLayerV11). - Full
strict: truein tsconfig.json; be explicit with types or useas unknown as Tfor unavoidable type conversions.
Debugging
- Compile errors: Check tsconfig.json; ensure types match (especially
Parserresult types and null-coalescing). - Runtime errors: Add breakpoints in src/gimpparser.ts and run examples with Node debugger:
node --inspect dist/examples/single.js. - Binary parsing issues: Log parser output at suspicious offsets; use
getBufferForPointer()and inspect raw bytes. - Image rendering bugs: Add debug logs in
GimpLayer.copyTile()or compositing logic in xcfcompositer.ts.
Further reading
- See readme.md for public API and usage examples.
- See CHANGELOG.md for recent changes (ESM migration, Promise-based API, TypeScript port, custom BinaryReader).
- See CONTRIBUTING.md for contribution guidelines.
- See BINARY-READER-MIGRATION.md for details on the custom binary parser implementation.