Open ai file

Hi,
I have a problem with script that open file and then convert to JPG file, the problem is after the first file open the other file will be opened with the dimension of first file, is possibile to reset data and import file with correct dimensions?

Where have you reached so far?
Can you post the code that doesnā€™t work?
Some errors come out of the debug.

await core.executeAsModal(async () => {
doc = await app.open(mFile); // path to ai file

The second file opened has the first file dimensions

So, it seems with testing that Photoshop uses the settings of the last (successful) Import PDF dialog called via the File > Open menu item. Let me explain what I discoveredā€¦

Test Files:

  • 5x5.ai - Illustrator file sized to 5 inch x 5 inch
  • 10x10.ai - Illustrator file sized to 10 inch x 10 inch

Test Code:

const { app, core } = require("photoshop");
const { storage } = require("uxp");
const fs = storage.localFileSystem;

const entries = await fs.getFileForOpening({
    allowMultiple: true,
    types: storage.fileTypes.all,
});

if (!entries || entries.length === 0) return;

await Promise.all(
    entries.map((entry) =>
        core.executeAsModal(async () => {
            await app.open(entry);
        }, {})
    )
);

Explanation

When I initially ran the script above (selecting both test files), each file was opened at 1-inch square, which left me puzzled. So, after some digging, the last PDF file I opened in Photoshop was sized to 1" x 1", which led me to believe Photoshop was defaulting to the last ā€œsuccessfulā€ Import PDF dialog settings accessed via the File > Open menu item.

To confirm my suspicion, I opened the ā€˜5x5.aiā€™ file via the Photoshop menu, closed it, and then ran the script again (selecting both test files)ā€¦ Both files opened at 5 inches square.

So, using the menu, I opened the ā€˜10x10.aiā€™ file, closed it, and then ran the script again (selecting both test files)ā€¦ As you might guess, both files opened at 10 inches square.

Potential Solutions

This example script above uses the Photoshop API app.open() method but you can also open the files using BatchPlay. The BatchPlay method does allow you to specify the file dimensions (see Alchemist code below), but this would require you to know the dimensions of each file (beforehand) so you can feed them into the BatchPlay command.

const {executeAsModal} = require("photoshop").core;
const {batchPlay} = require("photoshop").action;
const {localFileSystem: fs} = require("uxp").storage;

async function tokenify(url){
    return fs.createSessionToken(await fs.getEntryWithUrl("file:" + url));
}

async function actionCommands() {
    const result = await batchPlay(
        [
            {
                _obj: "open",
                as: {
                    _obj: "PDFGenericFormat",
                    name: "5x5.ai",
                    crop: {
                        _enum: "cropTo",
                        _value: "mediaBox"
                    },
                    resolution: {
                        _unit: "densityUnit",
                        _value: 300
                    },
                    mode: {
                        _enum: "colorSpace",
                        _value: "useICCProfile"
                    },
                    depth: 8,
                    antiAlias: true,
                    width: {
                        _unit: "pixelsUnit",
                        _value: 1500
                    },
                    height: {
                        _unit: "pixelsUnit",
                        _value: 1500
                    },
                    constrainProportions: true,
                    suppressWarnings: false,
                    reverse: true,
                    selection: {
                        _enum: "pdfSelection",
                        _value: "page"
                    },
                    pageNumber: 1
                },
                null: {
                    _path: await tokenify("/Users/jbd/Desktop/5x5.ai"),
                    _kind: "local"
                },
                documentID: 108,
                _options: {
                    dialogOptions: "dontDisplay"
                }
            }
        ],
        {}
    );
}

async function runModalFunction() {
    await executeAsModal(actionCommands, {"commandName": "Action Commands"});
}

await runModalFunction();
1 Like

Yes, this is the exact way to explain it, but if you manually open the Photoshop file it resets the dimensions based on the original file size, Iā€™m looking for a solution to know the file size before opening it. How does Photoshop manually know the file size?

That functionality has been in Ps for a long time but I donā€™t think it is exposed via the API so if you wanted to get the info for your script you would have to do something elseā€¦

Potential Solutions:

  • opening the file in Ai or Acrobat to get the dimensions first
  • use an external tool to get dimensions and put them in the file name
  • maybe trying to force Ps to reset the data by opening a 1px by 1px file

It looks like any solution you find is going to be hacky at best. I did check the ExtendScript reference and you can open a PDF file with defined specs but you must provide those specs so you are right back in the same situationā€¦

The ai size possibly can be taken from the XMP metadata; there is a metadata called MaxPageSize.

<xmpTPg:MaxPageSize rdf:parseType="Resource">
  <stDim:w>209.999994</stDim:w>
  <stDim:h>297.000024</stDim:h>
  <stDim:unit>Millimeters</stDim:unit>
</xmpTPg:MaxPageSize>

This is the size of page not size of image into page

In that case, you could use some PDF library to get the ArtBox of the ai file, or to find the %%BoundingBox or %%HiResBoundingBox in the source code of the ai file.

For now, Iā€™ve written code to open ai/pdf while getting XMPā€™s MaxPageSize, which should work for a simple pdf with one page per file.

const { storage, xmp } = require('uxp') ;
const { localFileSystem } = storage ;
const { XMPConst, XMPFile } = xmp ;
const { app, core, action, constants: Constants } = require('photoshop') ;

async function main() {
  try {
    const srcPath = '/Users/username/Desktop/target.ai' ;
    const dstResolution = 72 ;
    
    await core.executeAsModal(async () => 
      {
        await openPDF(srcPath, dstResolution) ;
      }, 
      
      {commandName: 'Open PDF'}
    ) ;
  } catch(e) {
    app.showAlert(e) ;
  }
}

/**
  * @typedef {Object} XMPDemensions - MaxPageSize value with units
  * @property {number} width
  * @property {number} height
  * @property {string} unit - e.g. 'Pixels' | 'Points' | 'Millimeters' | 'Centimeters' | 'Meters' | 'Ha' | 'Inches' |  'Picas' | 'Feet' | 'Yards'
*/

/**
  * get MaxPageSize of PDF file
  * @param {Entry} entry Entry for target file
  * @return {XMPDemensions?} 
*/
function getMaxPageDemensions(entry) {
  let res ;
  if(!entry.isFile) {return res ;}

  const xmpFile = new XMPFile(entry.nativePath, XMPConst.FILE_PDF, XMPConst.OPEN_FOR_READ) ;
  const xmpMeta = xmpFile.getXMP() ;
  const structName = 'MaxPageSize' ;
  res = {
    width: Number(xmpMeta.getStructField(XMPConst.TYPE_PAGEDFILE, structName, XMPConst.TYPE_DIMENSIONS, 'w').value), 
    height: Number(xmpMeta.getStructField(XMPConst.TYPE_PAGEDFILE, structName, XMPConst.TYPE_DIMENSIONS, 'h').value), 
    unit: xmpMeta.getStructField(XMPConst.TYPE_PAGEDFILE, structName, XMPConst.TYPE_DIMENSIONS, 'unit').value, 
  } ;

  return res ;
}

/**
  * @typedef {Object} PixelDemensions - pixel size value for Photoshop
  * @property {number} width - width (px)
  * @property {number} height - height (px)
*/

/**
  * create PixelDemensions from XMPDemensions
  * @param {XMPDemensions} demensions e.g. {width: 100, height: 100, unit: 'Millimeters'}
  * @param {number} resolution 
  * @return {PixelDemensions} 
*/
function pixelValue(demensions, resolution) {
  const dstUnits = Constants.Units.PIXELS ;
  const srcWidth = demensions.width ;
  const srcHeight = demensions.height ;

  let width, height ;
  switch(demensions.unit) {
    case 'Pixels':
    case 'Points': {
      const scaleFactor = resolution / 72 ;
      width = srcWidth * scaleFactor ;
      height = srcHeight * scaleFactor ;
      break ;
    }
    case 'Millimeters': {
      // mm > px
      width = app.convertUnits(srcWidth, Constants.Units.MM, dstUnits, resolution) ;
      height = app.convertUnits(srcHeight, Constants.Units.MM, dstUnits, resolution) ;
      break ;
    }
    case 'Centimeters': {
      // cm > px
      width = app.convertUnits(srcWidth, Constants.Units.CM, dstUnits, resolution) ;
      height = app.convertUnits(srcHeight, Constants.Units.CM, dstUnits, resolution) ;
      break ;
    }
    case 'Meters': {
      // m > cm > px
      const unitFactor = 100 ;
      width = app.convertUnits(srcWidth * unitFactor, Constants.Units.CM, dstUnits, resolution) ;
      height = app.convertUnits(srcHeight * unitFactor, Constants.Units.CM, dstUnits, resolution) ;
      break ;
    }
    case 'Ha': {
      // h > mm > px
      const unitFactor = 4 ;
      width = app.convertUnits(srcWidth * unitFactor, Constants.Units.MM, dstUnits, resolution) ;
      height = app.convertUnits(srcHeight * unitFactor, Constants.Units.MM, dstUnits, resolution) ;
      break ;
    }
    case 'Inches': {
      // in > px
      width = app.convertUnits(srcWidth, Constants.Units.INCHES, dstUnits, resolution) ;
      height = app.convertUnits(srcHeight, Constants.Units.INCHES, dstUnits, resolution) ;
      break ;
    }
    case 'Picas':
      // pc > px
      width = app.convertUnits(srcWidth, Constants.Units.PICAS, dstUnits, resolution) ;
      height = app.convertUnits(srcHeight, Constants.Units.PICAS, dstUnits, resolution) ;
      break ;
    case 'Feet': {
      // feet > pt > px
      const unitFactor = 864 ;
      width = app.convertUnits(srcWidth * unitFactor, Constants.Units.POINTS, dstUnits, resolution) ;
      height = app.convertUnits(srcHeight * unitFactor, Constants.Units.POINTS, dstUnits, resolution) ;
      break ;
    }
    case 'Yards': {
      // yard > pt > px
      const unitFactor = 2592 ;
      width = app.convertUnits(srcWidth * unitFactor, Constants.Units.POINTS, dstUnits, resolution) ;
      height = app.convertUnits(srcHeight * unitFactor, Constants.Units.POINTS, dstUnits, resolution) ;
      break ;
    }
    default: {
      // otherwise, treat the number as it is as px
      width = srcWidth ; 
      height = srcHeight ;
    }
  }

  return {
    width, 
    height, 
  } ;
}

/**
  * open PDF file in Photoshop
  * @param {string} srcPath PDF file path to open
  * @param {number} dstResolution destination resolution
  * @returns {any?}
*/
async function openPDF(srcPath, dstResolution) {
  let res ;
  const { name: documentName } = path.parse(srcPath) ;
  const entry = await localFileSystem.getEntryWithUrl(srcPath) ;
  const token = await localFileSystem.createSessionToken(entry) ;

  const demensions = getMaxPageDemensions(entry) ;
  if(demensions == null) {return res ;}
  const pixelDemensions = pixelValue(demensions, dstResolution) ;

  res = await action.batchPlay(
    [
      {
        _obj: 'open',
        null: {
          '_kind': 'local',
          '_path': token,
        },
        as: {
          _obj: 'PDFGenericFormat',
          name: documentName,
          crop: {
            _enum: 'cropTo',
            _value: 'trimBox',
          },
          antiAlias: true,
          width: {
            _unit: 'pixelsUnit',
            _value: pixelDemensions.width,
          },
          height: {
            _unit: 'pixelsUnit',
            _value: pixelDemensions.height,
          },
          constrainProportions: false,
          resolution: {
            _unit: 'densityUnit',
            _value: dstResolution,
          },
          mode: {
            _enum: 'colorSpace',
            _value: 'useICCProfile',
          },
          depth: 8,
          suppressWarnings: false,
          reverse: true,
          selection: {
            _enum: 'pdfSelection',
            _value: 'page',
          },
          pageNumber: 1,
        },
      },
    ], 

    {}
  ) ;

  return res[0] ;
}
1 Like

I would say excellent!

1 Like