Imaging API Beta
The Imaging API Beta allows JavaScript to work directly with image data in Photoshop documents.
These APIs are currently beta which means that they are not complete and may change in the future. We present them here as a testing ground for this new capability. Please send comments, questions or bugs via the Beta Feedback panel (under the Windows menu) or directly at the Beta forum.
The functionality has the following known issues:
- The API is only available in Photoshop (Beta) builds
- Support is limited to RGB, gray scale, and Lab data
- When using
applyAlpha
to matte the retrieved region's pixels on white, those pixels will still have had the empty pixels at the edges trimmed before the matte is applied. Be sure to check the returnedsourceBounds
.
The Imaging API are exposed on the imaging_beta
sub-module under "photoshop". You can access these APIs by using the follow code:
Copied to your clipboardconst imaging = require("photoshop").imaging_beta;
Terminology and data types
Image data is expressed as a collection of pixels
. A pixel represents all color information for a single point in the image. A pixel consists of one or more components of color values and alpha information.
An RGB pixel with alpha information has four components: "red", "green", "blue", and "alpha". An opaque RGB pixel has only three components. Including an alpha channel as a fourth yields RGBA. An opaque gray scale pixel has one component. A gray scale pixel with alpha has two components.
In order to properly interpret pixel data, Photoshop needs to know which color profile the data is expressed in. An example of a color profile is "Adobe RGB (1998)"
. All image data here will include the associated profile, and Photoshop will perform color conversions when needed. You can get the list of available color profiles by invoking [[Photoshop.getColorProfiles]] on the app object:
Copied to your clipboard1const rgbProfiles = await require("photoshop").app.getColorProfiles("RGB");23const grayProfiles = await require("photoshop").app.getColorProfiles("Gray");
When working with 32 bit images, Photoshop will return color profile names that include the description 'Linear Profile'. An example is "(Linear RGB Profile)"
. This text should not be included when specifying a profile. If a document profile is listed as Adobe RGB (1998) (Linear RGB Profile)
, then you would use the string Adobe RGB (1998)
when specifying a profile with a method such as createImageDataFromBuffer.
Photoshop supports two ways to store pixel information in memory:
chunky
: Components of a single pixels are stored consecutively in memory. If you have two opaque RGB pixels (pixel 1 and pixel 2), then they will be stored as:[R1, G1, B1, R2, G2, B2]
.planar
: Similar components are stored consecutively in memory. Components for a single pixel may not appear consecutively in memory. If you have two opaque RGB pixels, then they will be stored as:[R1, R2, G1, G2, B1, B2]
.
JavaScript APIs use the chunky format by default.
Image data is represented by a PhotoshopImageData
instance. This instance has the following methods and properties:
PhotoshopImageData
Name | Type | 描述 |
---|---|---|
width | Number | The width of the image data in pixels. |
height | Number | The height of the image data in pixels. |
colorSpace | String | The color space (or mode) for the image data. This can be "RGB" , "Grayscale" , "Lab" . |
colorProfile | String | The color profile for the image data. For example, "sRGB IEC61966-2.1" . |
hasAlpha | Boolean | True if the image data includes an alpha channel. Only available with RGB. |
components | Number | Number of components per pixel. This is 3 for RGB, 4 for RGBA and so forth. |
componentSize | Number | Number of bits per component. This can be 8, 16, or 32. |
pixelFormat | String | Memory layout (order) of components in a pixel. Could be "RGB" , "RGBA" , "Gray" , or "LAB" . |
chunky | Boolean | True if the image data internally is using the chunky format. |
type | String | Type of contained data. At the moment only "image/uncompressed" is supported. |
getData | Method | See documentation below. |
dispose | Method | See documentation below. |
When specifying bounds in the Imaging API, the resulting region will include the left and top locations up to the right and bottom locations. As an example: {left: 0, top: 0, right: 10, bottom: 10}
will target ten pixels from location 0 to 9 in both directions (not including pixels from location 10). You can specify height and width instead of right and bottom - doing so can make the code easier to read: {left: 0, top: 0, width: 10, height: 10}
.
The value range for pixel components depend on the componentSize.
Component Size | Value range | Comments |
---|---|---|
8 | 0..255 | |
16 | 0..32768 | |
32 | 0..1+ | High dynamic range images may have component values that are below 0 or above 1.0 |
Instances of PhotoshopImageData
cannot be created explicitly by JavaScript, but are returned from Imaging API methods.
Performance considerations
Photoshop images can be (very) large. It is therefore important to manage the image data carefully in JavaScript. If you use a large amount of JavaScript memory, then you may see warnings in the UDT debugger console such as the following:
Copied to your clipboard1Plugin memory usage increased to: 600MB.2Plugin exceeds memory limit. Currently used memory 600.
The potential large data space has a number of implications.
First off, all Imaging API methods that return pixels are asynchronous. This is needed because modifying and even querying pixel data may incur disk I/O.
When requesting pixels, use the smallest possible target size. Specifying a small target size allows Photoshop to optimize the retrieval (and possibly document compositing) of the source region.
When you are done working with image data, then you should call dispose
on the PhotoshopImageData
instance. This allow Photoshop to release memory immediately rather than waiting for garbage collection.
Converting image data between different color spaces or color profiles is somewhat time consuming. Whenever possible, work with a color space and color profile that match the document that you are operating on.
APIs
PhotoshopImageData
getData
Return pixel information from an PhotoshopImageData
instance as a typed array. The return type depends on the componentSize
of the image.
Component Size | Return type |
---|---|
8 | Uint8Array |
16 | Uint16Array |
32 | Float32Array |
The method takes an options argument. This argument can be used to specify attributes of the returned data. Possible options include:
chunky
| Boolean - Optional. If true then the data is returned as chunky data. If false, then data is returned in the planar format. The default value is true.
Return value: Promise<Uint8Array | Uint16Array | FloatArray>
The method is asynchronous, and thus returns a promise with the described data type.
Example:
Copied to your clipboardconst pixelData = await imageObj.imageData.getData()
dispose
Calling this synchronous method will release the contained image data. Doing so will reduce memory usage faster then waiting for the JavaScript garbage collector to run.
Copied to your clipboardpixelData.dispose();
getPixels
This API allows JavaScript to obtain pixel data from a Photoshop document. You can request pixels from an individual layer, or from the full document composite.
Copied to your clipboardconst imageObj = await imaging.getPixels(options);
- options | Object - Required
Options describing the operation.
documentID
| Number - Optional. The id of the source document. If missing, or negative, then the source is the active document.layerID
| Number - Optional. The id of the source layer. If the value is not provided then the API returns pixels from the composite document image.sourceBounds
| Object - Optional. The region whose pixels should be returned. If the value is not provided, then pixels from the entire layer or document are is returned. The provided bounds will be trimmed to only that region that contains pixel data. In this event, the returnedsourceBounds
will reflect this smaller region. The provided object must describe a rectangle using one the following number-value property sets:left
,top
,right
, andbottom
left
,top
,width
, andheight
targetSize
| Object - Optional. The dimensions of the returned image. If this value is not provided then the returned size will match the requested size. That is, no scaling will be performed on the returned pixels. The provided object must have one or more of the following attributes:width
andheight
. If only one dimension is included, then the returned image data is scaled proportionally to match the requested dimension.
colorSpace
| String - Optional. Requested color space of the returned pixels. If omitted, then the color space of the source document is used to convert colors.colorProfile
| String - Optional. The name of a color profile to apply to the returned pixels. If omitted, then the resulting color profile depends on the requested color space:- If the requested color space matches the source document, then the returned data will use the color profile of the source document.
- If the requested color space is different from the source document, then the working color profile for that color space is used to convert colors.
componentSize
| Number - Optional. The requestedcomponentSize
of the returned image data. If this property is omitted then thecomponentSize
of the source pixel data is used. The value can be: -1 (for using the source document's depth), 8 , 16, or 32.applyAlpha
| Boolean - Optional. If true, then RGBA pixels will be converted to RGB by matting on white.- a possible alpha channel is applied to the pixels before returning. The returned imageData property will not contain an alpha channel.
Return value: Promise<Object>
The returned object has the following properties:
imageData
| PhotoshopImageData. APhotoshopImageData
instance describing the returned pixel data.sourceBounds
| Object. The actual bounds used when obtaining pixels (see note regarding pyramid levels below).level
| Number. The pyramid level that was used when obtaining pixels.
Note: the components
property of the image data depends on whether or not the pixel source includes an alpha channel, e.g., 4 for RGBA.
If the targetSize is smaller than the requested region, then the resulting image data will be scaled down. When scaling, Photoshop may use a smaller (cached) version of the image canvas. This is known as a pyramid level. The number of pyramid levels that are available in a document is determined by the preference: "Performance Cache Levels". Using a cache level may result in dramatic performance improvements. The returned level indicates which level that was used. Level 0 indicates the full resolution canvas. Level 1 indicates a cache that is half of the size of the full resolution, and so forth. The returned sourceBounds
are relative to the bounds of the source cache level (not relative to the full resolution bounds).
The valid bounds for the sourceBounds
depend on the pixel source. The origin of the composite image is (0, 0)
,and the size is given by the properties width
and height
on the DOM object for the source document. The origin of a pixel layer can be different from (0, 0)
. You can get the valid pixel bounds for a layer by calling boundsNoEffects
on the DOM object corresponding to the source layer.
Example - create a thumbnail of an region of the target document that is 100 pixels tall.
Copied to your clipboard1const thumbnail = await imaging.getPixels({2 sourceBounds: { left: 0, top: 0, right: 300, bottom: 300 },3 targetSize: { height: 100 }4});
putPixels
This API allows JavaScript to change pixel data in a layer. You can replace all pixels in a layer or a region of the layer.
Copied to your clipboardawait imaging.putPixels(options);
- options | Object - Required
Options describing the operation.
documentID
| Number - Optional. The id of the source document. If missing, or negative, then the source is the active document.layerID
| Number - Required. The id of the target layer. The target layer must be a pixel layer.imageData
| PhotoshopImageData - Required. Value describing the pixel data.replace
| Boolean - Optional. Describes how pixels are added to the layer. If true, then exising pixels in the layer are discarded before adding new pixels. If false, then the new pixels are added to the existing pixel content in the layer. The default value is true.targetBounds
| Object - Optional. The region where the pixels should be inserted. If the value is not provided, then pixels are inserted at the origin(0, 0)
of the document. The provided object must include the following values:left
,top
. (Dimension keyswidth
andheight
are not used.)commandName
| String - Optional. If provided then this name is used when creating an entry in the history panel.
Example:
Copied to your clipboard1await imaging.putPixels({2 layerID: 1233 imageData: imageData4});
getLayerMask
This API allows JavaScript to retrieve the pixel data representing a layer's mask.
Copied to your clipboardconst imageObj = await imaging.getLayerMask(options);
- options | Object - Required
Options describing the operation.
documentID
| Number - Optional. The id of the source document. If the number is missing or negative, then the source will be the active document.layerID
| Number - Required. The id of the source layer.kind
| String - Optional. The kind of mask to return. There are two options:"user"
or"vector"
. The default value is"user"
which is the kind (pixel) applied by "Add Layer Mask" button.sourceBounds
| Object - Optional. The region whose pixels should be returned. If the value is not provided, then pixels from the entire mask are returned. The provided object must describe a rectangle using the following number properties:left
,top
,right
, andbottom
targetSize
| Object - Optional. The dimensions of the returned image. If this value is not provided then the returned size will match the requested size (i.e. no scaling is performed on the returned pixels). The provided object must have one or more of the following attributes:width
andheight
. If only one dimension is provided then the returned image data is scaled proportionally to match the requested dimension.
Return value: Promise<Object>
The returned object has the following properties:
imageData
| PhotoshopImageData. APhotoshopImageData
instance representing the pixels in the requested user mask. A user mask is represented as a single channel (gray scale image).sourceBounds
| Object. The actual bounds used when obtaining the mask pixels.
Example - get the user mask for a layer
Copied to your clipboard1const imageObj = await imaging.getLayerMask({2 documentID: 123,3 layerID: 5,4 kind: "user"5 sourceBounds: { left: 0, top: 0, right: 300, bottom: 300 },6 targetSize: { height: 100 }7});
putLayerMask
This API allows JavaScript to edit the pixels of a layer's mask. At this time, only pixel masks are editable. In the UI, they are what is referred to as a "Layer Mask".
Copied to your clipboardawait imaging.putLayerMask(options);
- options | Object - Required
Options describing the operation.
documentID
| Number - Optional. The id of the source document. If the number is missing or negative, then the source will be the active document.layerID
| Number - Required. The id of the target layer.kind
| String - Optional. The kind of mask to change. Only"user"
is accepted at this time. The default value is"user"
.imageData
| PhotoshopImageData - Required. Value describing the mask data. This must be image data with a single component using the grayscale color model.replace
| Boolean - Optional. Describes how mask pixels are added. If true, then the exising mask in the layer is discarded before creating a new mask. If false, then the new image data is placed into to the existing mask in the layer. The default value is true.targetBounds
| Object - Optional. The region where the pixels should be inserted. If the value is not provided, then pixels are inserted at the origin(0, 0)
. The provided object must include the following values:left
,top
. (Dimension keyswidth
andheight
are not used here.)commandName
| String - Optional. If provided, then this name is used when creating an entry in the history panel.
Example:
Copied to your clipboard1await imaging.putLayerMask({2 layerID: 1233 imageData: grayImageData4});
getSelection
This API allows JavaScript to obtain a pixel representation of the active selection. Think of it like entering Quick Mask mode.
Copied to your clipboardconst imageObj = await imaging.getSelection(options);
- options | Object - Required
Options describing the operation.
documentID
| Number - Optional. The id of the source document. If missing, or negative, then the source is the active document.sourceBounds
| Object - Optional. The region whose pixels should be returned. If the value is not provided, then pixels from the entire selection are returned. The provided object must describe a rectangle using the following number properties:left
,top
,right
, andbottom
targetSize
| Object - Optional. The dimensions of the returned image. If this value is not provided, then the returned size will match the requested size (i.e. no scaling is performed on the returned pixels). The provided object must have one or more of the following attributes:width
andheight
. If only one dimension is provided, then the returned image data is scaled proportionally to match the requested dimension.
Return value: Promise<Object>
The returned object has the following properties:
imageData
| PhotoshopImageData. APhotoshopImageData
instance representing the selection.sourceBounds
| Object. The actual bounds used when obtaining the selection pixels.
Example - get the document selection
Copied to your clipboard1const imageObj = await imaging.getSelection({2 documentID: 123,3 sourceBounds: { left: 0, top: 0, right: 300, bottom: 300 }4});
putSelection
This API allows JavaScript to change the selection itself using a provided pixel data representation. Think of it like exiting Quick Mask mode.
Copied to your clipboardawait imaging.putSelection(options);
- options | Object - Required
Options describing the operation.
documentID
| Number - Optional. The id of the source document. If missing, or negative, then the source is the active document.replace
| Boolean - Optional. Describes how selection is modified. If true, then the exising document selection is discarded before creating a new selection. If false, then the new image data is added to the existing document selection. The default value is true.targetBounds
| Object - Optional. The region where the selection should be inserted. If the value is not provided, then selection pixels are inserted at the origin(0, 0)
. The provided object must include the following values:left
,top
. (Dimension keyswidth
andheight
are not used here.)commandName
| String - Optional. If provided, then this name is used when creating an entry in the history panel.
Example:
Copied to your clipboardawait imaging.putSelection({ imageData: grayImageData });
createImageDataFromBuffer
This API allows JavaScript to create arbitrary image data from a memory buffer.
Copied to your clipboardconst imageData = await imaging.createImageDataFromBuffer(arrayBuffer, options);
imageData
| Typed array - Required | Desc ribes the image data. Accepted types are:Uint8Array
,Uint16Array
, andFloatArray
. The used type will indicate the componentSize of the provided data. See table above.- options | Object - Required
Options describing the operation.
width
| Number - Required. The width of the image.height
| Number - Required. The height of the image.components
| Number - Required. Number of components per pixel.chunky
| Boolean - Optional. Describes pixel layout. See discussion above. The default value is true.colorProfile
| String - Required. Describes the color profile associated with the image data. See note regarding color profiles and 32 bit pixel data at the beginning of this document.colorSpace
| String - Required. Describes the color space associated with the image data. Can be"RGB"
or"Grayscale"
Return value: Promise<PhotoshopImageData>
The number of elements in imageData must be equal to: width * height * components
.
Example:
Copied to your clipboard1const width = 30;2const height = 40;3const components = 4; // RGBA4const componentCount = width * height;5const dataSize = componentCount * components;6const arrayBuffer = new Uint8Array(dataSize);78// Add some (chunky) data to the buffer9for (let i = 0 ; i < componentCount; i += components) {10 arrayBuffer[index] = 255; // red11 arrayBuffer[index+1] = 0; // green12 arrayBuffer[index+2] = 0; // blue13 arrayBuffer[index+3] = 127; // alpha14}1516const options = {17 width: width,18 height: height,19 components: components,20 colorProfile: "sRGB IEC61966-2.1",21 colorSpace: "RGB"22};23const imageData = await imaging.createImageDataFromBuffer(arrayBuffer, options)
Image data that is used for layer masks or document selections uses a single grayscale component. When creating such data, use components: 1
, colorSpace: "Grayscale"
and colorProfile: "Generic Gray Profile"
as shown in the following example:
Copied to your clipboard1const width = 30;2const height = 40;3const componentCount = width * height;4const arrayBuffer = new Uint8Array(componentCount);56for (let i = 0 ; i < componentCount; ++i) {7 arrayBuffer[i] = 127; // all set to the median value8}910const options = {11 width: width,12 height: height,13 components: 1, // masks are grayscale14 chunky: false,15 colorProfile: "Generic Gray Profile",16 colorSpace: "Grayscale"17};18const maskData = await imaging.createImageDataFromBuffer(arrayBuffer, options)
encodeImageData
This API is exposed to allow image data to be used with UXP image elements. With the current version of UXP you must use jpeg/base64 encoding when assigning to an image element.
Copied to your clipboardconst dataImage = await imaging.encodeImageData(options);
- options | Object - Required
Options describing the operation.
- imageData | PhotoshopImageData - Required. Value describing the pixel data.
- base64 | Boolean - Optional. If provided, then the returned value will be a string that is base64 encoded.
Return value: Promise<Number[] | string>
Example:
Copied to your clipboard1const imageElement = document.createElement('img');23const jpegData = await imaging.encodeImageData({"imageData": imgObj.imageData, "base64": true});45const dataUrl = "data:image/jpeg;base64," + jpegData;6imageElement.src = dataUrl;7document.body.appendChild(imageElement);
Sample files
Here you will find a sample plugin (how to load) and UXP JavaScript file (.psjs) that exercise most of the above.
UXP plugin - imaging-test
UXP script - imaging.js