Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

ag-psd

Agamnentzar23.1kMIT28.2.2TypeScript support: included

Library for reading and writing PSD files

psd, photoshop

readme

ag-psd

Build Status npm version

JavaScript library for reading and writing PSD files (Photoshop Document files)

Implemented according to official documentation , fileformat.info and a lot of trial and error.

Limitations

  • Does not support reading Indexed, CMYK, Multichannel, Duotone and LAB color modes (all supported color modes are converted to RGB mode when reading)
  • Does not support writing any color modes other than RGB
  • Does not support 16 bits per channel
  • Does not support The Large Document Format (8BPB/PSB)
  • Does not support color palettes
  • Does not support animations
  • Does not support patterns (or "Pattern Overlay" layer effect)
  • Does not support some metadata fields
  • Does not support 3d effects
  • Does not support some new features from latest versions of Photoshop
  • Does not support all filters on smart layers (please report if you need a filter support added)
  • Text layers implementation is incomplete
    • Writing text layer with "vertical" orientation may result in broken PSD file
    • Does not support writing or reading predefined "Paragraph Styles" or "Character Styles"
    • The library does not redraw bitmap data for the text layer, so files with updated/written text layers will result in a warning prompt when opening the file in Photoshop. see more below
  • This library does not handle redrawing layer and composite image data by itself when blending options, vector data or text options are changed. Any updates to image data have to be done by the user or updated by opening and re-saving the file in Photoshop.

Installation

npm install ag-psd

Usage

Description of the structure of Psd object used by readPsd and writePsd functions can be found in our PSD Readme document

Functions

// read PSD from ArrayBuffer, typed array or Node.js Buffer object
export function readPsd(buffer: Buffer | ArrayBuffer | BufferLike, options?: ReadOptions): Psd;

// write PSD to ArrayBuffer
export function writePsd(psd: Psd, options?: WriteOptions): ArrayBuffer;

// write PSD to Uint8Array (avoids some memory allocation)
export function writePsdUint8Array(psd: Psd, options?: WriteOptions): Uint8Array;

// write PSD to Node.js Buffer object
export function writePsdBuffer(psd: Psd, options?: WriteOptions): Buffer;

Node.js

Reading

Needs node-canvas to read image data and thumbnails.

import * as fs from 'fs';
import 'ag-psd/initialize-canvas'; // only needed for reading image data and thumbnails
import { readPsd } from 'ag-psd';

const buffer = fs.readFileSync('my-file.psd');

// read only document structure
const psd1 = readPsd(buffer, { skipLayerImageData: true, skipCompositeImageData: true, skipThumbnail: true });
console.log(psd1);

// read document structure and image data
const psd2 = readPsd(buffer);
console.log(psd2);
// by defaults `canvas` field type is HTMLCanvasElement, so it needs to be cast to `any`
// or node-canvas `Canvas` type, in order to call `toBuffer` method
fs.writeFileSync('layer-1.png', (psd2.children[0].canvas as any).toBuffer());

Writing

import * as fs from 'fs';
import 'ag-psd/initialize-canvas'; // only needed for writing image data and thumbnails
import { writePsdBuffer } from 'ag-psd';

const psd = {
  width: 300,
  height: 200,
  children: [
    {
      name: 'Layer #1',
    }
  ]
};

const buffer = writePsdBuffer(psd);
fs.writeFileSync('my-file.psd', buffer);

Browser

Reading

import { readPsd } from 'ag-psd';

const xhr = new XMLHttpRequest();
xhr.open('GET', 'my-file.psd', true);
xhr.responseType = 'arraybuffer';
xhr.addEventListener('load', function () {
  const buffer = xhr.response;
  const psd = readPsd(buffer);

  console.log(psd);

  document.body.appendChild(psd.children[0].canvas);
}, false);
xhr.send();

Writing

saveAs function from FileSaver.js

import { writePsd } from 'ag-psd';

const psd = {
  width: 300,
  height: 200,
  children: [
    {
      name: 'Layer #1',
    }
  ]
};

const buffer = writePsd(psd);
const blob = new Blob([buffer], { type: 'application/octet-stream' });
saveAs(blob, 'my-file.psd');

Browser (bundle)

<script src="node_modules/ag-psd/dist/bundle.js"></script>
<script>
  var readPsd = agPsd.readPsd;
  // rest the same as above
</script>

Browser in Web Worker

Reading

Browser has to support OffscreenCanvas and bitmaprenderer context.

// worker.js

importScripts('bundle.js');

const createCanvas = (width, height) => {
  return new OffscreenCanvas(width, height);
};

const createCanvasFromData = (data) => {
  const image = new Image();
  image.src = 'data:image/jpeg;base64,' + agPsd.byteArrayToBase64(data);
  const canvas = new OffscreenCanvas(image.width, image.height);
  canvas.getContext('2d').drawImage(image, 0, 0);
  return canvas;
};

agPsd.initializeCanvas(createCanvas, createCanvasFromData);

onmessage = message => {
  // skipping thumbnail and layer images here so we don't have to clear and convert them all
  // before posting data back
  const psd = agPsd.readPsd(message.data, { skipLayerImageData: true, skipThumbnail: true });
  const bmp = psd.canvas.transferToImageBitmap();
  delete psd.canvas; // can't post canvases back from workers
  postMessage({ psd: psd, image: bmp }, [bmp]); // need to mark bitmap for transfer
};


// main script (assumes using bundle)

const worker = new Worker('worker.js');
worker.onmessage = message => {
  const psd = message.data.psd;
  const image = message.data.image;

  // convert image back to canvas
  const canvas = document.createElement('canvas');
  canvas.width = image.width;
  canvas.height = image.height;
  canvas.getContext('bitmaprenderer').transferFromImageBitmap(image);

  document.body.appendChild(canvas);
  console.log('psd:', psd);
};

const xhr = new XMLHttpRequest();
xhr.open('GET', 'src.psd', true);
xhr.responseType = 'arraybuffer';
xhr.addEventListener('load', function () {
  // read using worker
  worker.postMessage(buffer, [buffer]);
}, false);
xhr.send();

Writing

// worker.js

importScripts('bundle.js');

const createCanvas = (width, height) => {
  return OffscreenCanvas(width, height);
};

const createCanvasFromData = (data) => {
  const image = new Image();
  image.src = 'data:image/jpeg;base64,' + agPsd.byteArrayToBase64(data);
  const canvas = new OffscreenCanvas(image.width, image.height);
  canvas.getContext('2d').drawImage(image, 0, 0);
  return canvas;
};

agPsd.initializeCanvas(createCanvas, createCanvasFromData);

onmessage = message => {
  const psd = message.data.psd;
  const image = message.data.image;

  // convert bitmap back to canvas
  const canvas = new OffscreenCanvas(image.width, image.height);
  canvas.getContext('bitmaprenderer').transferFromImageBitmap(image);
  // need to draw onto new canvas because single canvas can't use both '2d' and 'bitmaprenderer' contexts
  const canvas2 = new OffscreenCanvas(canvas.width, canvas.height);
  canvas2.getContext('2d').drawImage(canvas, 0, 0);

  console.log(psd, canvas2);
  psd.children[0].canvas = canvas2;
  psd.canvas = canvas2;
  const data = agPsd.writePsd(psd);
  postMessage(data, [data]); // mark data as transferable
};


// main script (assumes using bundle)

const worker = new Worker('/test/worker-write.js');
worker.onmessage = message => {
  const blob = new Blob([message.data]);
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.textContent = 'Download generated PSD';
  a.download = 'example_psd.psd';
  document.body.appendChild(a);
};

const canvas = new OffscreenCanvas(200, 200);
const context = canvas.getContext('2d');
context.fillStyle = 'white';
context.fillRect(0, 0, 200, 200);
context.fillStyle = 'red';
context.fillRect(50, 50, 120, 110);
const bmp = canvas.transferToImageBitmap(); // convert canvas to image bitmap for transfering to worker
const psd = {
  width: 200,
  height: 200,
  children: [
    {
      name: 'Layer 1',
    }
  ]
};
worker.postMessage({ psd: psd, image: bmp }, [bmp]);

You can see working example in test/index.html, test/worker-read.js and test/worker-write.js.

Options

interface ReadOptions {
  /** Does not load layer image data. */
  skipLayerImageData?: boolean;
  /** Does not load composite image data. */
  skipCompositeImageData?: boolean;
  /** Does not load thumbnail. */
  skipThumbnail?: boolean;
  /** Does not load linked files (used in smart-objects). */
  skipLinkedFilesData?: boolean;
  /** Throws exception if features are missing. */
  throwForMissingFeatures?: boolean;
  /** Logs if features are missing. */
  logMissingFeatures?: boolean;
  /** Keep image data as byte array instead of canvas.
   * (image data will appear in `imageData` fields instead of `canvas` fields)
   * This avoids issues with canvas premultiplied alpha corrupting image data. */
  useImageData?: boolean;
  /** Loads thumbnail raw data instead of decoding it's content into canvas.
   * `thumnailRaw` field is used instead of `thumbnail` field. */
  useRawThumbnail?: boolean;
  /** Usend only for development */
  logDevFeatures?: boolean;
}

interface WriteOptions {
  /** Automatically generates thumbnail from composite image. */
  generateThumbnail?: boolean;
  /** Trims transparent pixels from layer image data. */
  trimImageData?: boolean;
  /** Invalidates text layer data, forcing Photoshop to redraw them on load.
   *  Use this option if you're updating loaded text layer properties. */
  invalidateTextLayers?: boolean;
  /** Logs if features are missing. */
  logMissingFeatures?: boolean;
  /** Forces bottom layer to be treated as layer and not background even when it's missing any transparency
   *  (by default Photoshop treats bottom layer as background if it doesn't have any transparent pixels) */
  noBackground?: boolean;
}

Sample PSD document

Below is a simple example of document structure returned from readPsd. You can see full document structure in psd.ts file

{
  "width": 300,
  "height": 200,
  "channels": 3,
  "bitsPerChannel": 8,
  "colorMode": 3,
  "children": [
    {
      "top": 0,
      "left": 0,
      "bottom": 200,
      "right": 300,
      "blendMode": "normal",
      "opacity": 1,
      "transparencyProtected": false,
      "hidden": true,
      "clipping": false,
      "name": "Layer 0",
      "canvas": [Canvas]
    },
    {
      "top": 0,
      "left": 0,
      "bottom": 0,
      "right": 0,
      "blendMode": "multiply",
      "opacity": 1,
      "transparencyProtected": true,
      "hidden": false,
      "clipping": false,
      "name": "Layer 3",
      "canvas": [Canvas]
    }
  ],
  "canvas": [Canvas]
}

Modifying documents

General approach with ag-psd to modifying documents is to read the document, apply the updates and write the document back.

If you read and write the same document, image data can get corrupted by automatic alpha channel pre-multiplication that happens when you load data into the canvas element. To avoid that, use raw image data, set useImageData option to true in ReadOptions. You can also use useRawThumbnail option to avoid any changes to thumbnail image.

const psd = readPsd(inputBuffer, { useImageData: true });

// TODO: update psd document here

const outuptBuffer = writePsd(psd); 

Updating general properties that don't have visual impact on the canvas, like printing info or layer name will work correctly without any extra work.

This library does NOT generate new composite canvas based on the layer data, so changing layer order, adding or removing layers or changing layer canvas data, or blending mode, or any other property that has visual impact on the canvas will cause the composite image and thumbnail to not be valid anymore. If you need composite image or thumbnail to be correct you need to update them yourself by updating psd.canvas or psd.imageData and psd.imageResources.thumbnail or psd.imageResources.thumbnailRaw fields. Composite image data is not required for PSD file to be readble in Photoshop so leaving old version or removing it completely may be good option. Thumbnail is only necessary for file preview in programs like Adobe Bridge or File Explorer, if you don't need to support that you can skip thumbnail as well.

This library also does NOT generate new layer canvas based on layer settings, so if you're changing any layer properties, that impact layer bitmap, you also need to update layer.canvas or layer.imageData. This includes: text layer properties, vector layer properties, smart object, etc. (this does not include layer blending options)

Writing text layers

// simple example
const psd = {
  width: 200,
  height: 200,
  children: [
    {
      name: 'text layer',
      text: {
        text: 'Hello world', // text you want to draw
        transform: [1, 0, 0, 1, 50, 50], // move text 50px horizontally and 50px vertically
        style: {
          font: { name: 'ArialMT' }, // need to provide full name here
          fontSize: 30,
          fillColor: { r: 255, g: 0, b: 0 }, // opaque red
        },
      },
    }, 
  ],
};

const buffer = writePsd(psd);
// advanced example
const psd = {
  width: 200,
  height: 200,
  children: [
    {  
      name: 'text layer',
      text: {
        text: 'Hello world\nanother line', // text you want to draw
        transform: [1, 0, 0, 1, 50, 50], // move text 50px horizontally and 50px vertically
        style: {
          font: { name: 'ArialMT' }, // need to provide full name here
          fontSize: 30,
        },
        styleRuns: [
          {
            length: 5, // length of 'Hello'
            style: { fillColor: { r: 255, g: 0, b: 0 } }, // make 'Hello' red
          },
          {
            length: 7, // length of ' world\n'
            style: { fillColor: { r: 0, g: 0, b: 255 } }, // make 'world' blue
          },
          {
            length: 12, // length of 'another line'
            style: { fillColor: { r: 0, g: 255, b: 0 }, underline: true }, // make 'another line' green and underlined
          },
        ],
        paragraphStyle: {
          justification: 'center', // center justify whole block of text
        },
      },
    },
  ],
};

const buffer = writePsd(psd);

Updating text layers

const psd = readPsd(inputBuffer);

// assuming first layer is the one you want to update and has text already present
psd.children[0].text.text = 'New text here';

// optionally remove outdated image data
psd.children[0].canvas = undefined;

// needs `invalidateTextLayers` option to force Photoshop to redraw text layer on load,
// otherwise it will keep the old image data
const outuptBuffer = writePsd(psd, { invalidateTextLayers: true }); 

When you add text layer to PSD file it is missing image data and additional text engine information. When you open file created this way in Photoshop it will display this error message, prompting you to update layer image data. You should choose "Update" which will force Photoshop to redraw text layers from text data. Clicking "No" will result in text layers being left in broken state.

Text layer issues

Writing or updating layer orientation to vertical can end up creating broken PSD file that will crash Photoshop on opening. This is result of incomplete text layer implementation.

Development

Building

gulp build

Testing

gulp test            # run tests
gulp cov             # run tests & coverage

Coding

Watch task with building, testing and code coverage

gulp dev             # run with build watch task
gulp dev --coverage  # run with build & tests & coverage watch tasks
npm run lint         # run tslint

changelog

Changelog

v28.1.0

  • Added support for reading and writing choke parameter for layer effects

v28.0.0

  • BREAKING CHANGE: Removed layersGroup and layerGroupsEnabledId properties from imageResources and instead added linkGroup and linkGroupEnabled fields to layers.

v27.0.0

  • Added support for read-only field text.textPath with text path information for text layers. This field is extracted from psd.engineData, which is not fully supported yet.

v26.0.0

  • Added support for realMask section

v25.0.0

  • Added support for blendingRanges section
  • Added support for interpolationMethod for gradients

v24.0.0

  • Added support for curves smart object filter
  • Added support for reading and writing palette field
  • Added support for reading PSD file with palette color mode
  • Fixed parsing for filterEffectsMasks section
  • Fixed padding for section data
  • Fixed reading some fields in compositorUsed section
  • Fixed incorrect writing for some smart object filters

v23.1.0

  • Added support for perspective warp filter

v23.0.0

  • Fixed handling externally linked files in smart object layers

v22.0.0

  • Fixed parsing path smooth gradient interpolation method
  • Changed PsdReader type

v21.0.0

  • Fixed parsing path operation field to handle empty value

v20.2.1

  • Fixed invalid value of globalAngle when the value is negative

v20.2.0

  • Fixed missing handling for justified paragraphs
  • Fixed reading slice names

v20.1.0

  • Improve performance of encoding and decoding large text fields.
  • Added initial support for 32bit image data.
  • Fixed handling compressed encoding mode by switching to better compression library.

v20.0.0

  • Added support for reading 16bit image data, when reading PSD width default settings 16bit data will be converted to regular 8bit canvases, when useImageData: true is passed in read options the image data will be of type Uint16Array for 16bit images. Because of that type of layer.imageData and psd.imageData and layer.mask.imageData can be of different types depending on PSD file bitDepth.
  • Added support for reading image data compressed with zip with prediction mode.
  • Added support for layer comps (psd.imageResources.layerComps and layer.comps fields)

v19.0.1

  • Fixed incorrect layer trimming when using layer.imageData property instead of layer.canvas

v19.0.0

  • Added brush type to ABR
  • Fixed importing smudge and mixer brushes from ABR
  • Fixed saving mask without canvas/imageData
  • Fixed rare issue with saving files resulting in corrupted file

v18.0.1

  • Fixed incorrect writing of fillRule field for vector paths

v18.0.0

  • Added fillRule field to vector paths

v17.0.6

  • Fixed broken file after saving with layer name longer than 255 characters

v17.0.5

  • Fixed incorrect parsing of external linked files
  • Fixed incorrect parsing of compositorUsed section when some fields are missing

v17.0.4

  • Fixed saving smart layers without placedLayer.warp field present for newer versions of photoshop

v17.0.3

  • Added extra error checks and fixed writing PSD without placedLayer.warp field present

v17.0.2

  • Fixed issues with writing some layer effects

v17.0.1

  • Fixed incorrect reading and writing of slice bounds
  • Fixed missing bounds and boundingBox fields on layer.text

v17.0.0

  • Added effectsOpen field to layers
  • Added support for basic set of smart layer filters
  • Changed the way smart layer filters are typed (placedLayer.filter)

v16.0.0

  • Added support for different color modes in text layer colors
  • Added option for other smart layer filter types

v15.3.0

  • Added support for smart layer puppet filter (placedLayer.filter)

v15.2.0

  • Added handling missing font in text layer style by assuming first font on the list

v15.1.0

  • Added support for float color in effects, new color type was added
    export type FRGB = { fr: number; fg: number; fb: number; }; // values from 0 to 1 (can be above 1)
  • Changed time field on LinkedFile from Date to string type

v15.0.0

  • Added support for frame and timeline animations

v14.5.0

  • Added support for zip compression without prediction of image data
  • Added support for compress option when writing

v14.4.0

  • Added support for layerMaskAsGlobalMask flag
  • Added support for interpolationMethod for gradient overlay layer blending mode

v14.3.13

  • Fixed handling files with incorrect channel image data length

v14.3.11

  • Fixed corrupted file when passing non-integer values to layer.left, .top, .right, .bottom

v14.3.9

  • Fixed reading some corrupted files

v14.3.8

  • Fixed handling files with incorrect section sizes

v14.3.6

  • Fixed incorrect writing of vogk section in some cases resulting in a broken file

v14.3.6

  • Fixed incorrect writing of vogk section in some cases resulting in a broken file

v14.3.2

  • Added nonAffineTransform field to smart object transform when nonAffineTransform is diferent than regular transform

v14.3.1

  • Fixed writing paragraphStyle autoLeading property (previous it was writing incorrectly for whole values, like 1.0 or 2.0)

v14.3.0

  • Added support for fillOpacity and transparencyShapesLayer
  • Fixed error in some cases when reading files with deeply nested layers

v14.2.0

  • Added readCsh function for reading photoshop custom shape files

v14.1.0

  • Added support for imageReadyVariables and imageReadyDataSets image resources
  • Fix missing support for alternative image resource block signatures

v14.0.1

  • Added missing handling for new platform and platformLCD text anti-aliasing modes

v14.0.0

  • Added handling for annotations
  • BREAKING CHANGE: Fixed reading and writing non-RGB colors and documented value ranges (value ranger for HSB, CMYK, Lab and Grayscale colors different from previous versions)
    export type RGBA = { r: number; g: number; b: number; a: number; }; // values from 0 to 255
    export type RGB = { r: number; g: number; b: number; }; // values from 0 to 255
    export type HSB = { h: number; s: number; b: number; }; // values from 0 to 1
    export type CMYK = { c: number; m: number; y: number; k: number; }; // values from 0 to 255
    export type LAB = { l: number; a: number; b: number; }; // values `l` from 0 to 1; `a` and `b` from -1 to 1
    export type Grayscale = { k: number }; // values from 0 to 255
    export type Color = RGBA | RGB | HSB | CMYK | LAB | Grayscale;
  • Fixed not handling correct value for text gridding

v13.0.2

  • Fixed error when opening PSB file with smart objects

v13.0.1

  • Fixed reading layer groups with missing section divider info

v13.0.0

  • BREAKING CHANGE: Changed how meshPoints are represented in warps `ts // old representation interface Warp { meshPoints: { type: 'horizontal' | 'vertical'; values: number[]; }[]; }

// new representation interface Warp { meshPoints: { x: number; y: number; }[]; }

- Fixed handling for complex warps

## v12.2.0
- Fixed incorrect length of style and paragraph style runs when reading or writing
- Added handling for `pathSelectionState`

## v12.1.0
- Added support for reading and writing PSB files (Large Document Format)

  Use `psb: true` in write options to write file in PSB format)

  The sizes are still limited by 32bit integer number range and will throw an error if you attempt to read any file larger than 2GB.
- Fixed some fields not handled in `vectorOrigination`

## v12.0.0
- **BREAKING CHANGE:** Added support for multiples of the same layer blending effect, these `layer.effects` keys are now arrays:
    - `dropShadow`
    - `innerShadow`
    - `solidFill`
    - `stroke`
    - `gradientOverlay`

  WARNING: adding more than one of effect in these arrays will result in file being saved with new version of effects section that is not readable on older versions of Photoshop.

## v11.6.2
- Fixed smart layer block info not parsing correctly in some cases
- Added automatic deduplication of layer IDs

## v11.6.1
- Fixed group blending modes not writing correctly

## v11.6.0
- Added `fromVectorData` field to `mask` object that indicates if mask image data comes from vector data attached to the layer
- Added handling `globalLayerMaskInfo` field
- Fixed vector and bitmap masks not writing correctly when used at the same time on one layer

## v11.5.1
- Added missing field `operation` to paths in vector layers

## v11.5.0
- Added `noBackground` write option to force treating bottom layer as layer instead of background when it doesn't have any transparent pixels

## v11.4.0
- Added handling for artboards
- Fixed issues with handling smart objects
- Fixed issues with handling vector layers

## v11.3.0
- Added handling for *Vector Origination Data* and *Compositor Used*
- Added handling for *ICC Untagged Profile*
- Added handling for *Lock Artbords* layer option

## v11.2.0
- Added handling for smart objects
- Changed types for text warp

## v11.1.0
- Added handling for text shape (point, box)
- Fixed incorrect parsing of utf-16 strings

## v11.0.0
- **BREAKING CHANGE:** Changed all color fields from r, g, b, a array to color mode specific objects
  ```js
  // old
  var color = [red, green, blue, alpha];

  // new
  var rgbColor = { r: red, g: green, b: blue };
  var hsbColor = { h: hue, s: saturation, b: brightness };
  var labColor = { l: L, a: A, b: B };
  var cmykColor = { c: cyan, m: magenta, y: yellow, k: black };
  var grayscaleColor = { k: grayscaleValue };

  // reading new colors
  if ('r' in color) {
    // read RGB color
  } else if ('h' in color) {
    // read HSB color
  } else if ('l' in color) {
    // read Lab color
  } else if ('c' in color) {
    // read CMYK color
  } else {
    // read grayscale color
  }

  // almost all color in PSD document follow main document color mode, so you can use this shortcut in your code
  if ('r' in color) {
    // read RGB color
  } else {
    // error or use default
  }

v10.0.0

  • BREAKING CHANGE: Removed unicodeAlphaNames image resource (use alphaChannelNames instead)
  • BREAKING CHANGE: Replaced sheetColors layer field with layerColor field
  • BREAKING CHANGE: Changed mask density fields to be in 0-1 range (instead of 0-255)
  • Removed metadata field from layers
  • Fixed incorrectly writing layer masks information in some cases
  • Added handling for adjustment layers
  • Added timestamp field to layers
  • Added printInformation image resource

v9.1.1

  • Fixed saved PSD files broken in some cases

v9.1.0

  • Added missing support for "stroke" blending option

v9.0.0

  • BREAKING CHANGE: Changed some numerical fields in effects objects to value+units fields
  • Added handling for vector layers
  • Added option for reading and writing raw image data using imageData fields corresponding to canvas fields on layer objects. (use useImageData option for reading raw data instead of using canvas objects, for writing initialize imageData fields instead of canvas fields)
  • Added option for reading and writing raw, compressed thumbnail image data using thumbnailRaw field. (use useRawThumbnail option for reading raw data instead of using canvas object)
  • Added backgroundColor image resource
  • Added xmpMetadata image resource
  • Added printFlags image resource
  • Added idsSeedNumber image resource
  • Added typescript type for blendModes
  • Fixed writing incorrect binary data in some cases
  • Fixed field name for sectionDivider.subType
  • Fixed reading mask parameters

v8.0.0

  • Added handling for reading and writing text layer data (with some limitations)
  • Added invalidateTextLayers write options for forcing Photoshop to redraw updated text layer.
  • Removed unnecessary version fields from pixelAspectRatio and versionInfo image resources.

v7.0.0

  • BREAKING CHANGE: Normalized handling of opacity (now all opacity fields are in 0-1 range, instead of 0-255)
  • BREAKING CHANGE: Fixed handling for colors (colors are now represented by an array of 4 values in 0-255 range as [R, G, B, A], for example: [255, 0, 0, 255] for opaque red color)
  • Added handling for layer effects (blending options) (supports all effects except "Pattern Overlay")
  • Added writePsdUint8Array function for saving to Uint8Array (this avoids double memory allocation)
  • Removed unnecessary version field from gridAndGuidesInformation field

v6.3.0

  • Added exported byteArrayToBase64 function
  • Updated readme with exampla of usage in web worker

v6.2.0

  • Added print scale image resource handling
  • Added caption digest image resource handling

v6.1.0

  • Added loading and saving layer masks

v6.0.0

  • Changed reading to ignore not implemented features by default instead of throwing
  • Removed logging missing handling for layer info
  • Added throwForMissingFeatures and logMissingFeatures read options for previous behavior

v5.0.0

  • Simplified canvas initialization on NodeJS

    before:

    import { createCanvas } from 'canvas';
    import { readPsd, initializeCanvas } from 'ag-psd';
    
    initializeCanvas(createCanvas);

    after:

    import 'ag-psd/initialize-canvas';
    import { readPsd } from 'ag-psd';
  • Changed writePsd() method to always return ArrayBuffer. If you need Buffer as a result use writePsdBuffer() method instead.
  • Simplified script import on browser, now import is the same on both platforms.

    before:

    // node
    import { readPsd } from 'ag-psd';
    
    // browser
    import { readPsd } from 'ag-psd/dist/browser';

    after:

    // node or browser
    import { readPsd } from 'ag-psd';