This document describes structure of the Psd object used in readPsd
and writePsd
functions, you can see instructions on how to use these functions in our main README document
You can see examples of different PSD documents and their corresponding JSON data in our test folder. Each subfolder contains src.psd
document and corresponding data.json
file with object generated by our library. Additionally there is canvas.png
file represending composite image data, thumb.png
file representing thumbnail image data and layer-#.png
files with image data of each layer.
// example psd document structure
const psd: Psd = {
"width": 300,
"height": 200,
"channels": 3,
"bitsPerChannel": 8,
"colorMode": 3,
"canvas": <Canvas>,
"children": [],
};
-
The
width
andheight
properties specify PSD document size in pixels. These values are required when writing a document. -
channels
property specifies number of color channels in the document, it's usually 3 channels (red, green, and blue, when document is in typical RGB color mode) Other color modes will have different channel count (grayscale - 1 channel, CMYK - 4 channels). This property can be ommited when writing, this library only supports RGB color mode with 3 channels at the moment. -
bitsPerChannel
property specifies number of bits per each color channel, this value will ba 1 for one bit bitmap color mode and 8 in all other cases as this library is not supporting 16 or 32 bit color channels at the moment. It can also be ommited when writing a document and default value of 8 will be assumed. -
colorMode
specifies color mode of the PSD document.Value is one of the numbers that can be matched to this enumerable:
enum ColorMode { Bitmap = 0, Grayscale = 1, Indexed = 2, RGB = 3, CMYK = 4, Multichannel = 7, Duotone = 8, Lab = 9, }
The library supports "Bitmap", "Grayscale" and "RGB" color modes at the moment. "Bitmap" and "Grayscale" colors will be converted to "RGB" colors when reading PSD file. Writing is only supported for "RGB" mode. The value can be ommited for writing and "RGB" color mode will be assumed.
-
canvas
(orimageData
) is a property containing bitmap with composite image data for the entire document. PSD file contains this extra bitmap additionally to bitmaps of each layer.canvas
field will be an instance ofHTMLCanvasElement
(in browser environment) orCanvas
object ofnode-canvas
library (in nodejs environment).You can choose to instead use
imageData
field by choosinguseImageData: true
option when reading PSD file. In that canimageData
will be an instance ofImageData
object, containingwidth
,height
anddata
properties. This is useful if you want to use bitmap data directly, and not use it for drawing using canvas. Additionally this will preserve accurate color information as canvas element will premultiply image alpha which will change color values slightly.If you don't need to use this field you can specify
skipCompositeImageData: true
option, while reading PSD file, to skip reading this field and save on processing time and memory usage.This image data is optional in PSD file so it may be missing in some PSD files that opted to skip it.
When writing you can provide either
canvas
orimageData
property and the library will use the one you provide. You can also skip the field entirely and not write this data at all as it's not needed by Photohop to read the file. It might be used in some other application, for thumbnails or by some old versions of Adobe software, so you may want to still provide it to remain compatible with those programs.If you're generating your own PSD file and want to provide this composite image data you will have to generate one yourself by composing all layer image data and effects yourself, this library does not provide any utilities to generate this image data for you.
-
children
list of layers and groups at the root of the document. see Layers and Groups -
imageResources
contains all document-wide parameters see Image Resouces -
linkedFiles
contains list of files linked in smart objects see Smart Objects -
artboards
contains global options for artboards. Artboards is a feature in new versions of Photoshop that lets you have multiple canvases in a single PSD document. The information about positioning, name and color of each artboard is stored inside each layer, inartboard
property. This property will be absent if the document does not have any artboards specified. It can be ommited when writing.type Artboards = { count: number; // number of artboards in the document autoExpandOffset?: { horizontal: number; vertical: number; }; origin?: { horizontal: number; vertical: number; }; autoExpandEnabled?: boolean; autoNestEnabled?: boolean; autoPositionEnabled?: boolean; shrinkwrapOnSaveEnabled?: boolean; docDefaultNewArtboardBackgroundColor?: Color; docDefaultNewArtboardBackgroundType?: number; }
-
annotations
contains array of annotations, this field will be absent if the document does not have any annotations. It can be ommited when writing. Sound annotations are not supported by this library right at the moment.Each annotation object has a following structure:
interface Annotation { type: 'text' | 'sound'; open: boolean; iconLocation: { left: number; top: number; right: number; bottom: number }; popupLocation: { left: number; top: number; right: number; bottom: number }; color: Color; author: string; name: string; date: string; data: string | Uint8Array; // annotation text or sound buffer }
-
globalLayerMaskInfo
don't really know what this is, it can be ommited when writing. -
filterMask
don't really know what this is, it can be ommited when writing.
Image data can be accessed from psd.canvas
or layer.canvas
fields by default. These fields store regular HTMLCanvasElement (or node-canvas object when running in node.js). For 16bit and 32 bit documents image data will be converted to regular 8bit canvas (this will result in a loss of data, use useImageData
option if you want to preserve precission of color data).
If useImageData
option is set to true in read options then the image data will be available in psd.imageData
and layer.imageData
fields instead. Using image data option gives you direct access to pixel data without having to go through the canvas object, which bypasses alpha premultiplication and convertion from 16/32bit image data to 8bit canvas data.
For 16bit documents imageData
fields will contain pixel data as Uint16Array
, the values ranging from 0 to 65535.
For 32bit documents imageData
fields will contain pixel data as Float32Array
, the values ranging from 0 to 1. 32bit values are in linear color space (as oposed to gamma corrected sRGB color). In order to convert the values to regular sRGB color space the values need to be gamma-corrected by using following conversion code (except alpha channel):
// convert 32bit linear to 8bit sRGB
destination[i] = Math.round(Math.pow(source[i], 1.0 / 2.2) * 255);
// convert 8bit sRGB to 32bit linear
destination[i] = Math.pow(source[i] / 255, 2.2);
Psd document object has children
property that contains all root level layers and groups in order from top to bottom as they appear in Photoshop (take note that if you want to draw the layer images to generate document image then you need to draw them in reverse order). The children
property will contain both regular layers and groups. Each group will have children
property, containing all the layers and groups that are inside that group. So the document will have a tree structure like this:
var psd = {
// ... other fields
children: [
{
name: "layer 1",
// ... other fields
}
{
name: "group 1",
// ... other fields
children: [
{
name: "layer 2, inside group 1",
// ... other fields
},
{
name: "group 2, inside group 1",
// ... other fields
children: []
}
]
}
]
}
You can distinguish between different layer types by checking which properties thay have set on them. If a layer has children
property set it meas the it's a group, if it has text
property it's a text layer and so on. If you're only interested in the basic parsing of layers and want to just extract image data or layer parameter a simple parsing like this can be enough:
// simple parsing
function parseLayer(layer) {
if ('children' in layer) {
// group
layer.children.forEach(parseLayer);
} else if (layer.canvas) {
// regular layer with canvas
} else {
// empty or special layer
}
}
If you need to know type of each layer, something like this could be a good approach:
// complex parsing
function parseLayer(layer) {
if ('children' in layer) {
// group
layer.children.forEach(parseLayer);
} else if ('text' in layer) {
// text layer
} else if ('adjustment' in layer) {
// adjustment layer
} else if ('placedLayer' in layer) {
// smart object layer
} else if ('vectorMask' in layer) {
// vector layer
} else {
// bitmap layer
}
}
But thake into account that a lot of properties are shared for different types of layers. Any layer can have a mask
property for example.
Example layer structure:
{
"top": 0,
"left": 0,
"bottom": 200,
"right": 300,
"blendMode": "normal",
"opacity": 1,
"clipping": false,
"timestamp": 1448235572.7235785,
"transparencyProtected": true,
"protected": {
"transparency": true,
"composite": false,
"position": true
},
"hidden": false,
"name": "Background",
"nameSource": "bgnd",
"id": 1,
"layerColor": "none",
"blendClippendElements": true,
"blendInteriorElements": false,
"knockout": false,
"referencePoint": {
"x": 0,
"y": 0
},
"canvas": <Canvas>
},
-
top
,left
,bottom
,right
properties specify location of layer image data withing the document.top
specifies offset in pixel of the top of layer image data from the top edge of the document,bottom
specifies offset of the bottom of the layer image data from the top adge of the document and similar forleft
andright
.This is necessary as layer image data can be smaller or large than the document size. This can cause in some cases the values of these fields to be negative. A value of
left: -100
means that the layer image data starts 100 pixels outside the left document edge. This can happen if you move the layer left beyond document edge in Photoshop.top
andleft
values can be ommited when writing and will be assumed to be 0.bottom
andright
values can be ommited and will always be ignored when writing and will instead be calculated fromcanvas
(orimageData
) width and height. -
blendMode
is a layer blending mode and will be one of the following values:type BlendMode = 'pass through' | 'normal' | 'dissolve' | 'darken' | 'multiply' | 'color burn' | 'linear burn' | 'darker color' | 'lighten'| 'screen' | 'color dodge' | 'linear dodge' | 'lighter color' | 'overlay' | 'soft light' | 'hard light' | 'vivid light' | 'linear light' | 'pin light' | 'hard mix' | 'difference' | 'exclusion' | 'subtract' | 'divide' | 'hue' | 'saturation' | 'color' | 'luminosity'
These values correspond to naming in layer blend mode dropdown. If ommited a value of
normal
will be assumed. -
canvas
(orimageData
) seecanvas
property description in Basic document structureVector, text and smart object layers still have image data with pregenerated bitmap. You also need to provide that image data when writing PSD files.
Reading this property can be skipped if
skipLayerImageData: true
option is passed toreadPsd
function. This can be done to save on memory usage and processing time if layer image data is not needed. -
opacity
specifies level of layer transparency (the value range is from 0 to 1). Can be ommited when writing, a default value of 1 will be assumed. -
clipping
indicates if layer clipping is enabled (if enabled the layer is clipped to the layer below it). Can be ommited when writing, a default value offalse
will be assumed. -
timestamp
timestamp of last time layer was modified (in unix time). Can be ommited when writing. -
transparencyProtected
andprotected
properties specify status of various locks that you can set for each layer.protected.position
indicates if moving layer is lockedprotected.composite
indicates if drawing on the layer is lockedprotected.transparency
indicates if drawing transparent pixels are locked
If the
transparencyProtected
istrue
butprotected.transparency
isfalse
it means that the layer has "lock all" enabled. Both this fields can be ommited when writing, a values offalse
will be assumed for all of the ommited fields. -
hidden
indicates if the layer is hidden. Can be ommited when writing, a value offalse
will be assumed. -
name
name of the layer, can be any unicode string, can be empty. Can be ommited when writing, a value of''
will be assumed. -
nameSource
internal Photoshop information, can be ignored and ommited when writing. -
id
unique ID number for layer, it may be missing in some PSD files. Can be ommited when writing, but if provided it has to be a unique number, if duplicate IDs are found they will be changed to a unique ones when writing the file. -
layerColor
color of the layer in layer list, property will be missing or will be one of the following values:type LayerColor = 'none' | 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'violet' | 'gray'
-
version
unknown functionality -
referencePoint
unknown functionality -
mask
Layer mask, property has the following structure.interface LayerMaskData { top?: number; left?: number; bottom?: number; right?: number; defaultColor?: number; disabled?: boolean; positionRelativeToLayer?: boolean; fromVectorData?: boolean; // set to true if the mask is generated from vector data, false if it's a bitmap provided by user userMaskDensity?: number; userMaskFeather?: number; // px vectorMaskDensity?: number; vectorMaskFeather?: number; canvas?: HTMLCanvasElement; imageData?: ImageData; }
Similar to layer image data this data has
top
,left
,bottom
andright
offsets specified.fromVectorData
Specifies if the mask image data was generated fromvectorMask
, iffromVectorData
is set to false and bothvectorMask
andmask
properties are present it means that the layer has 2 active masks, bitmap mask and a vector mask.mask
property will be missing when layer has no mask, it can be ommited when writing. -
effects
Object describing layer "Blending Options"Effects property follows the following structure:
interface LayerEffectsInfo { disabled?: boolean; // indicates if all effects are disabled scale?: number; dropShadow?: LayerEffectShadow[]; innerShadow?: LayerEffectShadow[]; outerGlow?: LayerEffectsOuterGlow; innerGlow?: LayerEffectInnerGlow; bevel?: LayerEffectBevel; solidFill?: LayerEffectSolidFill[]; satin?: LayerEffectSatin; stroke?: LayerEffectStroke[]; gradientOverlay?: LayerEffectGradientOverlay[]; patternOverlay?: LayerEffectPatternOverlay; // not supported yet }
Some of the effects (specified here as arrays) can be specified multiple times. This is new feature, only supported in more recent versions of Photoshop.
This property is not present if there are not blending options set for the layer. This property can be ommited when writing.
-
text
text properties of text layerTODO
-
patterns
not supported yet -
vectorFill
Fill color, gradient or pattern for the vector mask. Usetype
field to distinguish between different vector fill types, like this:switch (vectorFill.type) { case 'color': // solid color fill ({ color: Color } type) break; case 'solid': // solid gradient fill (EffectSolidGradient type) break; case 'noise': // noise gradient fill (EffectNoiseGradient type) break; case 'pattern': // pattern fill (EffectPattern type) break; }
-
vectorStroke
Vector stroke parameters for the vector mask. This field also contains parameters related tovectorFill
. This property has following structure:type VectorStroke = { strokeEnabled?: boolean; // vector drawing has stroke fillEnabled?: boolean; // vector drawing has fill (specified by vectorFill property) lineWidth?: UnitsValue; lineDashOffset?: UnitsValue; miterLimit?: number; lineCapType?: LineCapType; lineJoinType?: LineJoinType; lineAlignment?: LineAlignment; scaleLock?: boolean; strokeAdjust?: boolean; lineDashSet?: UnitsValue[]; blendMode?: BlendMode; opacity?: number; content?: VectorContent; // stroke color, gradient or pattern (see `vectorFill` field for more information) resolution?: number; }
-
vectorMask
Specifies vector mask used byvectorFill
andvectorStroke
to draw vector images.TODO: expand this description
-
usingAlignedRendering
unknown functionality -
pathList
not supported yet -
adjustment
indicates that the layer is an adjustment layer. Adjustment layer do not have image data. This property is not present on non-adjustment layers.Use
type
field of the adjustment object to distinguish between different adjustment layer types.switch (adjustment.type) { case 'brightness/contrast': // handle BrightnessAdjustment layer break; case 'levels': // handle LevelsAdjustment layer break; // ... other cases ... }
see all Adjustment layer types in psd.ts file
-
placedLayer
indicates that this is smart object layer, see Smart Objects section for more information. This property is only present on smart object layers. -
vectorOrigination
TODO -
compositorUsed
internal photoshop information -
artboard
Artboard location and parameters, this property is only present when using artboards. Artbord is object is following this structure:type Artboard = { rect: { top: number; left: number; bottom: number; right: number; }; guideIndices?: any[]; presetName?: string; color?: Color; backgroundType?: number; }
-
Advanced blending options
-
engineData
internal text information
Example group structure:
{
"top": 0,
"left": 0,
"bottom": 0,
"right": 0,
"blendMode": "normal",
"opacity": 1,
"clipping": false,
"timestamp": 1450198418.5245173,
"transparencyProtected": false,
"hidden": false,
"name": "Group 1",
"nameSource": "lset",
"id": 5,
"sectionDivider": {
"type": 1,
"key": "pass",
"subType": 0
},
"protected": {
"transparency": false,
"composite": false,
"position": false
},
"layerColor": "none",
"referencePoint": {
"x": 0,
"y": 0
},
"opened": true,
"children": [
// layers here
]
}
Groups don't have canvas
/ imageData
property, as you can't draw directly on a group. Groups don't have any other special layer property like text
, vectorFill
, adjustment
or placedLayer
.
Group-only fields:
-
children
contains list of all layers in this group. Cannot be ommited when writing, without this field a group will be assumed to be a regular layer. Use emptychildren
array when writing empty group. -
opened
indicates if the group is expanded or collapsed in the layer list. If ommited a default values oftrue
will be assumed. -
sectionDivider
internal Photoshop property, can be ignored and ommited when writing.
Image resources are global document settings. Any of these settings can be ommited when writing. PSD file can have following global options:
-
versionInfo
Version information of Program that generated the PSD file, example value:versionInfo = { "hasRealMergedData": true, "writerName": "Adobe Photoshop", "readerName": "Adobe Photoshop CS6", "fileVersion": 1 }
-
layerSelectionIds
list of layer IDs of selected layers, these layers will be selected when you open PSD document in Photoshop. -
pixelAspectRatio
Specifies aspect ratio of the PSD document pixels, almost always 1pixelAspectRatio = { "aspect": 1 }
-
gridAndGuidesInformation
Information about document guidesExample value:
gridAndGuidesInformation = { "grid": { "horizontal": 576, "vertical": 576 }, "guides": [ { "location": 531.4375, "direction": "vertical" // "horizontal" or "vertical" }, // ... more guides here ... ] };
-
resolutionInfo
Image resolution info, specifies physical size of the image pixels. Example value:resolutionInfo: { "horizontalResolution": 72, "horizontalResolutionUnit": "PPI", // 'PPI' (pixels per inch) or 'PPCM' (pixels per centimeter) "widthUnit": "Inches", "verticalResolution": 72, "verticalResolutionUnit": "PPI", "heightUnit": "Inches" // 'Inches', 'Centimeters', 'Points', 'Picas' or 'Columns' },
-
thumbnail
Canvas element with thumbnail image for the document, this property can be missing in some PSD files. This property can be ommited when writing if there's no need to support tumbnails, this field can be automatically generated from composite image data ifgenerateThumbnail: true
option is passed towritePsd
function. -
thumbnailRaw
This property will be used instead ifuseRawThumbnail
option is specitied when reading PSD file. -
xmpMetadata
XMP metadata. File info as XML description. See http://www.adobe.com/devnet/xmp/ -
iccUntaggedProfile
ICC Untagged Profile -
printInformation
,printScale
andprintFlags
Specifies options for printing the document. -
layerState
TODO -
layersGroup
TODO -
layerGroupsEnabledId
TODO -
alphaIdentifiers
TODO -
alphaChannelNames
TODO -
globalAngle
TODO -
globalAltitude
TODO -
urlsList
TODO -
captionDigest
TODO -
backgroundColor
TODO -
idsSeedNumber
TODO -
pathSelectionState
TODO -
imageReadyVariables
TODO -
imageReadyDataSets
TODO
Layers with placedLayer
property are smart object layers. placedLayer
property has the following structure:
interface PlacedLayer {
id: string; // id of linked image file (psd.linkedFiles)
placed?: string; // unique id
type: PlacedLayerType;
transform: number[]; // x, y of 4 corners of the transform
nonAffineTransform?: number[]; // x, y of 4 corners of the transform
width?: number;
height?: number;
resolution?: UnitsValue;
warp?: Warp;
crop?: number;
}
The Psd object has linkedFiles
property, that specifies list of all files linked in smart objects. Each linked file has following structure:
interface LinkedFile {
id: string;
name: string;
type?: string;
creator?: string;
data?: Uint8Array;
time?: Date; // for external files
childDocumentID?: string;
assetModTime?: number;
assetLockedState?: number;
}
id
field in PlacedLayer
refers to the id
in LinkedFile
. Example values:
layer.placedLayer = {
"id": "20953ddb-9391-11ec-b4f1-c15674f50bc4", // id that matches linkedFiles ID
"placed": "20953dda-9391-11ec-b4f1-c15674f50bc4", // unique id for this object
"type": "raster", // one of the 'unknown', 'vector', 'raster' or 'image stack'
"transform": [ // x, y of 4 corners of the transform box
29,
28,
83,
28,
83,
82,
29,
82
],
"width": 32, // width and height of the target image
"height": 32,
"resolution": {
"value": 299.99940490722656,
"units": "Density"
}
};
psd.linkedFiles = [
{
"id": "20953ddb-9391-11ec-b4f1-c15674f50bc4",
"name": "cat.png"
"data": fileContentsAsUint8Array,
}
];
Some fields in the PSD document specity a value with units, those fields use UnitsValue
type:
interface UnitsValue {
units: Units;
value: number;
}
value
fields can be any number value, units
fields has to be one of the supported units: "Pixels", "Points", "Picas", "Millimeters", "Centimeters", "Inches", "None", "Density". Some fields only support some of the units, check with Photoshop for supported units.
Example values:
var distance = { value: 5, units: "Pixels" };
var lineWidth = { value: 3, units: "Points" };
Many fields in PSD file support passing color in different color formats (RGBA, RGB, HSB, CMYK, LAB, Grayscale) Those fields will use Color
type which is a union of all of these color formats. The color types have following structure:
type RGBA = { r: number; g: number; b: number; a: number; }; // values from 0 to 255
type RGB = { r: number; g: number; b: number; }; // values from 0 to 255
type FRGB = { fr: number; fg: number; fb: number; }; // values from 0 to 1 (can be above 1)
type HSB = { h: number; s: number; b: number; }; // values from 0 to 1
type CMYK = { c: number; m: number; y: number; k: number; }; // values from 0 to 255
type LAB = { l: number; a: number; b: number; }; // values `l` from 0 to 1; `a` and `b` from -1 to 1
type Grayscale = { k: number }; // values from 0 to 255
type Color = RGBA | RGB | FRGB | HSB | CMYK | LAB | Grayscale;
When you want to set field with a Color
type, it's pretty straightforward, you can just choose any of the formats you like and set it on the field:
strokeEffect.color = { h: 0.79, s: 0.54, b: 0.93 };
Reading a color field is more complicated, you need to check what color format the field is in and then run correct code to handle it, here's how to do it for all color types:
if ('l' in color) {
// color is LAB
} else if ('c' in color) {
// color is CMYK
} else if ('h' in color) {
// color is HSB
} else if ('k' in color) {
// color is Grayscale
} else if ('a' in color) {
// color is RGBA
} else if ('rf' in color) {
// color is FRGB
} else {
// color is RGB
}
If you expect the fields to be in one specific format you can just verify that it's correct and throw an error if it's a format that you didn't expect:
// handle only RGB colors
if ('r' in color && !('a' in color)) {
// color is RGB
} else {
throw new Error('Invalid color');
}