photoshopphotoshop-scriptadobe-javascript

Adobe Photoshop JS Scripting Question: inserting vector masks from JSON to Photoshop Image, but pathItems.add() method not working


I created a bunch of vector masks for deep learning image training in photoshop a while back. To save space, I deleted all the annotated photoshop images.

But, I transferred the vector masks into a JSON file so I could recreate the annotations if needed. The JSON file details all the point positions and which layer it was attached to.

Now, I want to recreate the annotated images for a sanity check and presentation, but I am having trouble doing so. Specifically, I am running into trouble with one line:

doc.pathItems.add(name, spiArray) with the error: "the property was not initialized".

This is the 4th-to-last line in the utils.js in the function addPathItem() which is called in the last line in main.js

Looking at the latest 2020 Adobe scripting guide documentation, pathItems indeed has the .add() method, so I don't know what the issue is. I have checked previously that doc, doc.pathItems, name, and spiArray are properly initialized, properly initialized, string, and Array containing SubPathInfo objects, respectively.

Here is the full code for the main.js file:

The utils.js file is one I created and contains the functions for readJSONFile() and addPathItem(). The code for the utils.js file is below this code block.

// description: photoshop script for parsing json files to image
#include utils.js
#include json2.js

// initialize doc reference
var doc = app.activeDocument

// read in json and save info into dictionary
var dataPath = "~/Desktop/workingdir/jsonFiles/"
var jsonFilePath = dataPath + doc.name.slice(0, -4) + ".json" // find by replacing .png with .json
var jsonShapeData = readJsonFile(jsonFilePath)["shapes"]

// grab all the paths from json
var shapesDict = {"normal": [], "kogg": []}  // value is a list of shapes; shape is a list of points; 3D tensor-like shape
for (var i = 0; i < jsonShapeData.length; i++) {
  var shapeData = jsonShapeData[i]
  var layer = shapeData["label"]
  var shape = shapeData["points"]

  shapesDict[layer].push(shape)
}

// Add paths to each layer
addPathItem(doc, "kogg", shapesDict) // for the "kogg" layer

The utils.js file I created:

No issues for any of the functions until the 4th-to-last line: var pathItem = doc.pathItems.add(name, spiArray)

// read json file and return json object
function readJsonFile(jsonFilePath) {
  var file = File(jsonFilePath)

  // check if file exists
  if (!file.exists) {
    alert("File does not exist")
    return
  }

  // open file and read content
  file.open("r")
  var content = file.read()
  file.close()

  // attempt to parse and return json content
  try {
    return JSON.parse(content)
  } catch (e) {
    alert("Error parsing json file")
    return
  }
}

// function to create pathPointInfo object
function getPathPointInfo(pointPosition) {
  var ppi = new PathPointInfo()
  ppi.kind = PointKind.CORNERPOINT
  ppi.anchor = pointPosition
  ppi.leftDirection = pointPosition
  ppi.RightDirection = pointPosition
  return ppi
}

// function to create subpathInfo object
function getSubPathInfo(shape) {
  var entireSubPath = []

  for (i = 0; i < shape.length; i++) {
    var point = shape[i]
    var ppi = getPathPointInfo(point)

    // add to subpath
    entireSubPath.push(ppi)
    alert("adding point to subpath")
  }

  // define SubPathInfo as an object
  var spi = new SubPathInfo()
  spi.entireSubPath = entireSubPath
  spi.closed = true
  return spi
}

// function to create and add PathItem
function addPathItem(doc, name, shapesDict) {
  // create layer for vector mask and set active layer
  var layer = doc.artLayers.add()
  layer.name = name
  doc.activeLayer = layer

  // get all shapes (array of subpathinfo objects)
  var spiArray = []
  var shapes = shapesDict[name]
  for (var i = 0; i < shapes.length; i++) {
    var shape = shapes[i]
    var spi = getSubPathInfo(shape)
    spiArray.push(spi)
    alert("added subpath info to spiArray")
    if (spiArray.length == 2) {
      break // get two shapes
    }
  }

  alert("checking spiArray contains subpath info")
  var pathItem = doc.pathItems.add(name, spiArray)
  alert(2)
  pathItem.PathKind = PathKind.VECTORMASK

  // add stroke to visualize
  pathItem.strokePath(ToolType.PENCIL)
}

At this point, it seems like the built-in property .add() for pathItems is bugging out on me. However, this seems strange since no one else has commented on this, and it would be very hard for me to fix this bug if it is the case.

Having a built-in issue like this still seems unlikely, so I am wondering if I am missing something. I can provide a sample json and png file if needed!


Solution

  • Two things:

    1. Add the operation (ShapeOperation) field during your SubPathInfo object construction. It doesn't have a default value, so it is probably looking for it but can't find it, which is causing your error.

    2. ppi.RightDirection should be ppi.rightDirection, with a lowercase "r".

    Hopefully, this fixes your problem!