This commit is contained in:
SheetJS 2023-04-16 03:21:15 -04:00
parent 866ebabc68
commit c164c3dbcd
6 changed files with 279 additions and 77 deletions

@ -22,6 +22,20 @@ After downloading the script, it can be directly referenced with `#include`:
#include "xlsx.extendscript.js"
```
For local deployments, the scripts can be placed in the `Scripts` folder. For
Photoshop CS6 on Windows 10, the path is typically
`C:\Program Files\Adobe\Adobe Photoshop CS6 (64 Bit)\Presets\Scripts`
For local deployments, the scripts can be placed in the `Scripts` folder. The
path is application-specific.
| App | Location |
|:----------|:-----------------------------------------------------------------|
| Photoshop | `\Presets\Scripts` within the Application folder |
| InDesign | Windows > Utilities > Scripts, click `☰` > "Reveal in Explorer" |
:::note CEP usage
The ExtendScript build should be used when performing spreadsheet operations
from the host context (within a `jsx` script file).
[The standalone scripts](/docs/getting-started/installation/standalone) should
be added to CEP extension HTML.
:::

@ -1,5 +1,5 @@
---
title: Photoshop and Creative Suite
title: Photoshop and InDesign
pagination_prev: demos/cloud/index
pagination_next: demos/bigdata/index
---
@ -21,10 +21,27 @@ This demo intends to cover parts relevant to SheetJS. General setup as well as
general Adobe considerations are not covered here. A basic familiarity with
extension development is assumed.
## ExtendScript Scripts
:::note
[Installation is straightforward:](/docs/getting-started/installation/extendscript) download a
script and move it to your project directory.
This demo was verified in the following deployments:
| App | Platform | Date |
|:----------|:-------------|:-----------|
| Photoshop | ExtendScript | 2023-04-15 |
| InDesign | ExtendScript | 2023-04-15 |
| InDesign | CEP | 2023-04-15 |
| InDesign | UXP | 2023-04-15 |
:::
## ExtendScript
[The "ExtendScript" build](/docs/getting-started/installation/extendscript) can
be included from a script in the same directory:
```js
#include "xlsx.extendscript.js"
```
### Reading Files
@ -47,46 +64,20 @@ var workbook = XLSX.readFile(thisFile.absoluteURI);
<details open><summary><b>Complete Example</b> (click to hide)</summary>
<Tabs groupId="ccapp">
<TabItem value="photoshop" label="Photoshop">
In this example, the script will show a dialog to select a file. After reading
the file, the workbook Author property will be extracted and the Photoshop doc
author (`activeDocument.info.author`) will be changed accordingly.
This demo was verified in Photoshop CS6 64-bit on Windows 10.
```js
#target photoshop
#include "xlsx.extendscript.js";
function main_parse() {
/* Show File Picker */
var thisFile = File.openDialog("Select a spreadsheet");
if(!thisFile) { alert("File not found!"); return; }
/* Read file from disk */
var workbook = XLSX.readFile(thisFile.absoluteURI);
/* Get Workbook Author */
var Props = workbook.Props; if(!Props) { alert("Missing Author!"); return; }
var Author = Props.Author; if(!Author) { alert("Missing Author!"); return; }
/* Change Document Author to Workbook Author */
var info = activeDocument.info;
alert("Changing Author from |" + info.author + "| to |" + Author + "|");
info.author = Author;
}
main_parse();
```
0) Download the [test workbook](pathname:///files/SheetJS.xlsb).
1) Download the following scripts:
- [`xlsx.extendscript.js`](https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.extendscript.js)
- [`parse.jsx`](pathname:///live/parse.jsx)
- [`parse.jsx`](pathname:///extendscript/parse.jsx)
and place in the scripts directory. For CS6 Windows 10 the path is typically
`C:\Program Files\Adobe\Adobe Photoshop CS6 (64 Bit)\Presets\Scripts`
and place in the scripts directory.
2) Restart Photoshop and open a file (or create a new one)
@ -96,7 +87,40 @@ and place in the scripts directory. For CS6 Windows 10 the path is typically
!["Changing Author" popup](pathname:///files/psparse.png)
5) File > File Info... should show the updated Author field!
5) Check the Author field of the document in File > File Info...
</TabItem>
<TabItem value="indesign" label="InDesign">
In this example, the script will show a dialog to select a file. After reading
the file, the script will store data in the document:
- The first Text object in the "Title" TextFrame (the name of the TextFrame in
the Layers window is "Title") will be set to the name of the first worksheet.
- The data from the first sheet will be added to the "Table Frame" TextFrame.
0) Download the [test workbook](https://sheetjs.com/pres.xlsx) and
[InDesign template](pathname:///extendscript/Template.indd)
1) Download the following scripts:
- [`xlsx.extendscript.js`](https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.extendscript.js)
- [`esidparse.jsx`](pathname:///extendscript/esidparse.jsx)
Move to the scripts directory. To find the directory, activate Scripts panel
(Windows > Utilities > Scripts), click `☰`, and select "Reveal in Explorer".
2) Open the template
3) Activate the Scripts panel. Expand the "User" folder and double-click
`esidparse` in the list.
4) In the "Select a spreadsheet" file picker, select the test file `pres.xlsx`
A new table will be added and the title will be the name of the first worksheet.
</TabItem>
</Tabs>
</details>
@ -121,46 +145,19 @@ XLSX.writeFile(workbook, thisFile.absoluteURI);
<details open><summary><b>Complete Example</b> (click to hide)</summary>
<Tabs groupId="ccapp">
<TabItem value="photoshop" label="Photoshop">
In this example, the script will show a dialog to select an output file. Once
selected, the library will create a new workbook with one worksheet. Cell `A1`
will be "Author" and cell `B1` will be the active Photoshop document Author.
The PS author is available as `activeDocument.info.author`.
This demo was verified in Photoshop CS6 64-bit on Windows 10.
```js
#target photoshop
#include "xlsx.extendscript.js";
function main_write() {
/* Show File Picker */
var thisFile = File.saveDialog("Select an output file", "*.xlsx;*.xls");
if(!thisFile) { alert("File not found!"); return; }
/* Create new Worksheet */
var ws = XLSX.utils.aoa_to_sheet([
["Author", activeDocument.info.author]
]);
/* Create new Workbook and add worksheet */
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
/* Write file to disk */
XLSX.writeFile(wb, thisFile.absoluteURI);
alert("Created File " + thisFile.absoluteURI);
}
main_write();
```
1) Download the following scripts:
- [`xlsx.extendscript.js`](https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.extendscript.js)
- [`write.jsx`](pathname:///live/write.jsx)
- [`write.jsx`](pathname:///extendscript/write.jsx)
and place in the scripts directory. For CS6 Windows 10 the path is typically
`C:\Program Files\Adobe\Adobe Photoshop CS6 (64 Bit)\Presets\Scripts`
and place in the scripts directory.
2) Restart Photoshop and open a file (or create a new one)
@ -169,21 +166,129 @@ and place in the scripts directory. For CS6 Windows 10 the path is typically
4) File > Scripts > write and use the popup to select the Documents folder.
Enter `SheetJSPSTest.xlsx` and press "Save"
4) An alert will confirm that the file was created:
5) An alert will confirm that the file was created:
!["Created File" popup](pathname:///files/pswrite.png)
5) Open the generated `SheetJSPSTest.xlsx` file and compare to Photoshop author
6) Open the generated `SheetJSPSTest.xlsx` file and compare to Photoshop author
</TabItem>
<TabItem value="indesign" label="InDesign">
In this example, the script will show a dialog to select an output file. Once
selected, the library will scan all text frames for table objects. Each table
object will be scanned and a new worksheet will be created.
0) Download the [InDesign document](pathname:///extendscript/Filled.indd)
1) Download the following scripts:
- [`xlsx.extendscript.js`](https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.extendscript.js)
- [`esidwrite.jsx`](pathname:///extendscript/esidwrite.jsx)
Move to the scripts directory. To find the directory, activate Scripts panel
(Windows > Utilities > Scripts), click `☰`, and select "Reveal in Explorer".
2) Open the document.
3) Activate the Scripts panel. Expand the "User" folder and double-click
`esidwrite` in the list. Use the popup to select the Documents folder. Enter
`SheetJSIDTest.xlsx` and press "Save"
4) An alert will confirm that the file was created. Open `SheetJSIDTest.xlsx`
and compare to the InDesign doc.
</TabItem>
</Tabs>
</details>
## CEP
[The standalone scripts](/docs/getting-started/installation/standalone) can be added to CEP
extension HTML
[The standalone scripts](/docs/getting-started/installation/standalone) can be
added to CEP extension HTML. It should be downloaded from the CDN and included
in the extension.
For performing file operations in CEP extensions, NodeJS is not required! The
manifest must include the following flags to enable `cep.fs`:
```xml
<CEFCommandLine>
<Parameter>--allow-file-access</Parameter>
<Parameter>--allow-file-access-from-files</Parameter>
</CEFCommandLine>
```
The Base64 encoding is compatible with `type: "base64"`.
**Reading Files**
The typical flow is to read data from CEP and pass the data into the host
ExtendScript context. The following snippet parses a workbook:
```js
/* show file picker (single file, no folders) */
const fn = cep.fs.showOpenDialogEx(false, false, "Select File", "", ["xlsx"]);
/* read data as Base64 string */
const data = cep.fs.readFile(fn.data[0], cep.encoding.Base64);
/* parse with SheetJS */
const wb = XLSX.read(data.data, { type: "base64" });
```
**Writing Files**
The typical flow is to invoke a function with `CSInterface#evalScript` that
returns data from the host ExtendScript context. The callback should build the
workbook and initiate a file save. The following snippet saves a workbook:
```js
/* generate XLSX as base64 string */
const b64 = XLSX.write(wb, {type:"base64", bookType: "xlsx"})
/* show file picker */
const fn = cep.fs.showSaveDialogEx("Save File","",["xlsx"],"SheetJSIDCEP.xlsx");
/* write file */
cep.fs.writeFile(fn.data, b64, cep.encoding.Base64);
```
## UXP
UXP officially recommends `require` and NodeJS Modules for third party support.
UXP uses bundled scripts with `.psjs` (PS) or `.idjs` (InDesign) extension. The
official samples use `webpack` to build bundles.
[Use the "Frameworks" instructions to download.](/docs/getting-started/installation/frameworks)
[The "Frameworks" instructions](/docs/getting-started/installation/frameworks)
describe installation steps for traditional `webpack` projects.
Filesystem access is provided by the UXP storage module:
```js
const storage = require("uxp").storage;
const ufs = storage.localFileSystem;
```
**Reading Files**
The `getFileForOpening` method resolves to a `File` object. Reading the file
with the `binary` format returns an `ArrayBuffer` object that can be parsed:
```js
/* show file picker (single file, no folders) */
const file = await ufs.getFileForOpening({ types: ["xlsx", "xls", "xlsb"] });
/* read data into an ArrayBuffer */
const ab = await file.read({ format: storage.formats.binary });
/* parse with SheetJS */
const wb = XLSX.read(ab);
```
**Writing Files**
The `getFileForSaving` method resolves to a `File` object. The workbook should
be written with `type: "buffer"` for compatibility with the `binary` format:
```js
/* generate XLSX with type: "buffer" */
const buf = XLSX.write(wb, { type: "buffer", bookType: "xlsx" });
/* show file picker */
const file = await ufs.getFileForSaving("SheetJSUXP.xlsx");
/* write data */
await file.write(buf, { data: storage.formats.binary });
```

@ -0,0 +1,35 @@
#include "xlsx.extendscript.js";
function main_parse() {
/* Show File Picker */
var thisFile = File.openDialog("Select a spreadsheet");
if(!thisFile) { alert("File not found!"); return; }
/* Read file from disk */
var workbook = XLSX.readFile(thisFile.absoluteURI);
var wsname = workbook.SheetNames[0];
var data = XLSX.utils.sheet_to_json(workbook.Sheets[wsname], { header: 1, raw: false });
/* Set title */
app.activeDocument.textFrames.itemByName("Title").texts[0].contents = wsname;
/* Set table */
var tabeller = app.activeDocument.textFrames.itemByName("Table Frame");
var columns = data[0].length;
for(var R = 0; R < data.length; ++R) columns = Math.max(columns, data[R].length);
var table = tabeller.tables.add({
headerRowCount: 1,
bodyRowCount: data.length - 1,
columnCount: columns
});
for(R = 0; R < data.length; ++R) {
if(data[R] == null) continue;
for(var C = 0; C < data[R].length; ++C) {
if(data[R][C] == null) continue;
table.rows.item(R).cells.item(C).contents = data[R][C];
}
}
}
main_parse();

@ -0,0 +1,48 @@
#include "xlsx.extendscript.js";
function workbook_add_table(wb, table) {
/* Collect Data */
var data = [];
var cnt = table.rows.count();
for(var R = 0; R < cnt; ++R) {
var row = table.rows.item(R);
data[R] = [];
var ccnt = row.cells.count();
for(var C = 0; C < ccnt; ++C) {
var value = row.cells.item(C).contents;
data[R][C] = value;
}
}
if(data.length == 0) return;
/* Create Worksheet */
var ws = XLSX.utils.aoa_to_sheet(data);
/* Create new Workbook and add worksheet */
XLSX.utils.book_append_sheet(wb, ws);
}
function main_write() {
/* Show File Picker */
var thisFile = File.saveDialog("Select an output file", "*.xlsx;*.xls");
if(!thisFile) { alert("File not found!"); return; }
/* Create new Workbook */
var wb = XLSX.utils.book_new();
/* Find all tables and add them to workbook */
var tfcnt = app.activeDocument.textFrames.count();
for(var i = 0; i < tfcnt; ++i) {
var tf = app.activeDocument.textFrames.item(i);
var tcnt = tf.tables.count();
if(tcnt == 0) continue;
for(var j = 0; j < tcnt; ++j) workbook_add_table(wb, tf.tables.item(j));
}
/* Write file to disk */
XLSX.writeFile(wb, thisFile.absoluteURI);
alert("Created File " + thisFile.absoluteURI);
}
main_write();