From c164c3dbcd500d591903b2f15a8d18e58bcc12f8 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 16 Apr 2023 03:21:15 -0400 Subject: [PATCH] cef --- .../01-installation/05-extendscript.md | 20 +- .../03-demos/10-extensions/01-extendscript.md | 253 +++++++++++++----- docz/static/extendscript/esidparse.jsx | 35 +++ docz/static/extendscript/esidwrite.jsx | 48 ++++ docz/static/{live => extendscript}/parse.jsx | 0 docz/static/{live => extendscript}/write.jsx | 0 6 files changed, 279 insertions(+), 77 deletions(-) create mode 100644 docz/static/extendscript/esidparse.jsx create mode 100644 docz/static/extendscript/esidwrite.jsx rename docz/static/{live => extendscript}/parse.jsx (100%) rename docz/static/{live => extendscript}/write.jsx (100%) diff --git a/docz/docs/02-getting-started/01-installation/05-extendscript.md b/docz/docs/02-getting-started/01-installation/05-extendscript.md index 2d7fd3f..63a02a1 100644 --- a/docz/docs/02-getting-started/01-installation/05-extendscript.md +++ b/docz/docs/02-getting-started/01-installation/05-extendscript.md @@ -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. + +::: \ No newline at end of file diff --git a/docz/docs/03-demos/10-extensions/01-extendscript.md b/docz/docs/03-demos/10-extensions/01-extendscript.md index ec99b64..28193f3 100644 --- a/docz/docs/03-demos/10-extensions/01-extendscript.md +++ b/docz/docs/03-demos/10-extensions/01-extendscript.md @@ -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);
Complete Example (click to hide) + + + 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... + + + + +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. + + +
@@ -121,46 +145,19 @@ XLSX.writeFile(workbook, thisFile.absoluteURI);
Complete Example (click to hide) + + + 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 + + + + +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. + + +
## 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 + + --allow-file-access + --allow-file-access-from-files + +``` + +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 }); +``` diff --git a/docz/static/extendscript/esidparse.jsx b/docz/static/extendscript/esidparse.jsx new file mode 100644 index 0000000..8fb2802 --- /dev/null +++ b/docz/static/extendscript/esidparse.jsx @@ -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(); \ No newline at end of file diff --git a/docz/static/extendscript/esidwrite.jsx b/docz/static/extendscript/esidwrite.jsx new file mode 100644 index 0000000..28cc0fd --- /dev/null +++ b/docz/static/extendscript/esidwrite.jsx @@ -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(); \ No newline at end of file diff --git a/docz/static/live/parse.jsx b/docz/static/extendscript/parse.jsx similarity index 100% rename from docz/static/live/parse.jsx rename to docz/static/extendscript/parse.jsx diff --git a/docz/static/live/write.jsx b/docz/static/extendscript/write.jsx similarity index 100% rename from docz/static/live/write.jsx rename to docz/static/extendscript/write.jsx