diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..e82a59a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Media/ +SetupData/* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100755 index 0000000..6102dbe --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,10 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "extendscript-debug", + "request": "attach", + "name": "extendScript-Debug attach" + } + ] +} diff --git a/Build/Panel Splitter for Adobe Photoshop.exe b/Build/Panel Splitter for Adobe Photoshop.exe new file mode 100755 index 0000000..7262de7 Binary files /dev/null and b/Build/Panel Splitter for Adobe Photoshop.exe differ diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..dd14741 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Dilshan-H + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Panel Splitter.jsx b/Panel Splitter.jsx new file mode 100755 index 0000000..8cf2178 --- /dev/null +++ b/Panel Splitter.jsx @@ -0,0 +1,224 @@ +/* + Project: Panel Splitter for Adobe Photoshop + Author: dilshan-h [https://github.com/dilshan-h] + Description: Split your image/canvas into cells using rows, columns & save them as high quality PDFs. + Copyright (c) [2024] - MIT License +*/ + +// flag to control script execution +var continueScript = true; +// Save the current preferences +var startDisplayDialogs = app.displayDialogs; +// Set Adobe Photoshop to display no dialogs +app.displayDialogs = DialogModes.NO; +// Store the state of the document before changes +var doc = app.activeDocument; +var initialState = doc.activeHistoryState; + +var dialog = new Window("dialog", "Confirmation - Panel Splitter"); +dialog.alignChildren = "left"; +var fontText = ScriptUI.newFont("Segoe UI", "Regular", 14); +var fontBtns = ScriptUI.newFont("Segoe UI", "Regular", 14); + +// Add a message label +var messageLine1 = dialog.add( + "statictext", + undefined, + "IMPORTANT: Make sure that;" +); +messageLine1.graphics.font = fontText; +var messageLine2 = dialog.add( + "statictext", + undefined, + "1. You have saved your file." +); +messageLine2.graphics.font = fontText; +var messageLine3 = dialog.add( + "statictext", + undefined, + "2. You have a backup of this document." +); +messageLine3.graphics.font = fontText; +var messageLine4 = dialog.add( + "statictext", + undefined, + "Do you want to proceed?" +); +messageLine4.graphics.font = fontText; + +// Add a group to contain buttons +var buttonGroup = dialog.add("group"); +buttonGroup.alignment = "center"; +buttonGroup.alignChildren = "center"; + +// Add Yes and No buttons +var yesButton = buttonGroup.add("button", undefined, "Yes"); +yesButton.graphics.font = fontBtns; +var noButton = buttonGroup.add("button", undefined, "No"); +noButton.graphics.font = fontBtns; + +var bottomText = dialog.add( + "statictext", + undefined, + "Panel Splitter • Made with ❤ by dilshan-h • github.com/dilshan-h" +); + +// Functions to handle button click events +yesButton.onClick = function () { + alert("On the next dialog box, select a location to save the panels."); + dialog.close(); +}; + +noButton.onClick = function () { + alert("Script will be stopped now. Run again to continue."); + dialog.close(); + continueScript = false; +}; + +dialog.show(); + +if (continueScript) { + // ask the user for the output folders + var outputFolder = Folder.selectDialog( + "Select a folder for the output files" + ); + if (outputFolder == null) { + alert( + "An output directory is required!\nScript will be stopped now. Run again to continue." + ); + continueScript = false; + } +} + +if (continueScript) { + cropAndSavePDFs(); + + // Reset the application preferences + app.displayDialogs = startDisplayDialogs; + + // Undo changes to revert the document state + doc.activeHistoryState = initialState; + + app.activeDocument.close(SaveOptions.DONOTSAVECHANGES); + alert("Files successfully saved!"); +} + +// Function to prompt user for rows and columns +function promptRowsColumns() { + var rows = parseInt(prompt("Enter the number of rows:", "")); + var columns = parseInt(prompt("Enter the number of columns:", "")); + return [rows, columns]; +} + +// Function to clear existing guides +function clearGuides() { + var doc = app.activeDocument; + doc.guides.removeAll(); +} + +// Function to add outer guides +function setOuterGuides() { + var doc = app.activeDocument; + var width = doc.width.value; + var height = doc.height.value; + + doc.guides.add(Direction.HORIZONTAL, 0); + doc.guides.add(Direction.HORIZONTAL, height); + doc.guides.add(Direction.VERTICAL, 0); + doc.guides.add(Direction.VERTICAL, width); +} + +// Function to add new guides based on rows and columns +function addGuides(rows, columns) { + var doc = app.activeDocument; + var width = doc.width.value; + var height = doc.height.value; + + var horizontalSpacing = width / columns; + var verticalSpacing = height / rows; + + for (var i = 1; i < rows; i++) { + doc.guides.add(Direction.HORIZONTAL, verticalSpacing * i); + } + + for (var j = 1; j < columns; j++) { + doc.guides.add(Direction.VERTICAL, horizontalSpacing * j); + } +} + +// Function to save selection as PDF +function saveAsPDF(selectionBounds, outputPath) { + var doc = app.activeDocument; + var bounds = selectionBounds; + + doc.crop(bounds); + var saveOptions = new PDFSaveOptions(); + saveOptions.compatibility = PDFCompatibility.PDF14; + saveOptions.embedThumbnail = true; + saveOptions.encoding = PDFEncoding.JPEG; + saveOptions.jpegQuality = 12; + saveOptions.layers = false; + saveOptions.preserveEditing = false; + saveOptions.view = false; + doc.saveAs(new File(outputFolder + outputPath), saveOptions); +} + +// Main function +function cropAndSavePDFs() { + var rowsColumns = promptRowsColumns(); + if (!rowsColumns || rowsColumns.length !== 2) return; + + var rows = rowsColumns[0]; + var columns = rowsColumns[1]; + + var doc = app.activeDocument; + + clearGuides(); + setOuterGuides(); + addGuides(rows, columns); + + // Merge visible layers + doc.flatten(); + + var guides = doc.guides; + + var pdfCounter = 1; + + var horizontalGuides = []; + var verticalGuides = []; + + // Group guides based on orientation + for (var i = 0; i < guides.length; i++) { + if (guides[i].direction === Direction.HORIZONTAL) { + horizontalGuides.push(guides[i]); + } else if (guides[i].direction === Direction.VERTICAL) { + verticalGuides.push(guides[i]); + } + } + + // Sort guides based on their coordinates + horizontalGuides.sort(function (a, b) { + return a.coordinate - b.coordinate; + }); + + verticalGuides.sort(function (a, b) { + return a.coordinate - b.coordinate; + }); + + for (var i = 0; i < rows; i++) { + for (var j = 0; j < columns; j++) { + var top = horizontalGuides[i].coordinate; + var bottom = horizontalGuides[i + 1].coordinate; + + var left = verticalGuides[j].coordinate; + var right = verticalGuides[j + 1].coordinate; + + var selectionBounds = [left, top, right, bottom]; + var outputPath = "/Panel_" + pdfCounter + ".pdf"; + + saveAsPDF(selectionBounds, outputPath); + doc.activeHistoryState = doc.historyStates[doc.historyStates.length - 2]; + pdfCounter++; + } + } +} diff --git a/README.md b/README.md new file mode 100755 index 0000000..e888011 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# Panel Splitter for Adobe Photoshop + +![GitHub license](https://img.shields.io/github/license/Dilshan-H/Panel-Splitter?style=for-the-badge) +![GitHub last commit](https://img.shields.io/github/last-commit/Dilshan-H/Panel-Splitter?style=for-the-badge) +![GitHub issues](https://img.shields.io/github/issues/Dilshan-H/Panel-Splitter?style=for-the-badge) +![GitHub pull requests](https://img.shields.io/github/issues-pr/Dilshan-H/Panel-Splitter?style=for-the-badge) + + + +## What is Panel Splitter? + +Panel Splitter is a script that helps you to instantly crop images/canvas along the guides in Photoshop and export them as high quality PDFs. All you need to provide is how many rows and columns that are needed. Panel Splitter will prepare the guides, crop each panel and save them as PDFs for you! + +## Simple Demo + +Here's a example of what this tool can do: + +## Why use Panel Splitter? + +There is an alternative option that already available in Adobe Photoshop named `Slices from Guides`. But, it lacks the ability to export each panel in high quality state. (the `Export` feature is deprecated in modern versions as well). This tools helps in this situation by filling those gaps. + +## How to use this tool? + +1. If your Photoshop application is already opened, close and restart it. (First time only - to load the script to PS) +2. Open the image/canvas/panel +3. Please make sure to **save your document** and **keep a backup copy** for safety. +4. Go to `File > Scripts > Panel Splitter` +5. Provide a location to export the processed panels. +6. Input amount of rows and columns respectively in the next dialogs. +7. That's it.. After a moment, the script will show a message saying that the process is complete. Check the output location for PDF files. + +## [ICYMI]: Important Notes for Users + +- Always save your document before running this script! +- Make sure to keep a backup copy just in case, if something goes wrong. + +## Contributing + +Got an idea? Found a bug? Feel free to [open an issue](https://github.com/dilshan-h/Panel-Splitter/issues/new) or submit a pull request. For major changes, please open an issue first to discuss what you would like to change. + +1. Clone/Fork this repository. +2. Setup your development environment as discussed in here: https://extendscript.docsforadobe.dev/index.html +3. There are additional resources available within `References` folder - you can check them out as well. +4. Make your changes to the script and test it with `Adobe ExtendScript extension` for Visual Studio Code. + +## License & Copyrights + +**The MIT License** + +• This program is free software: you can redistribute it and/or modify it under the terms of the MIT License. Attribution is required by leaving the author name and license info intact. +Please refer to the LICENSE file for more details. + +• Adobe, Photoshop, ExtendScript, Visual Studio Code are copyrights and/or trademarks of their respective owners. + +• Image Credits: [Andrea Piacquadio from Pexels](https://www.pexels.com/photo/photo-of-woman-looking-at-the-mirror-774866/) diff --git a/References/photoshop-javascript-ref-2020.pdf b/References/photoshop-javascript-ref-2020.pdf new file mode 100755 index 0000000..002c369 Binary files /dev/null and b/References/photoshop-javascript-ref-2020.pdf differ diff --git a/References/photoshop-scripting-guide-2020_unlocked.pdf b/References/photoshop-scripting-guide-2020_unlocked.pdf new file mode 100755 index 0000000..7ca77f0 Binary files /dev/null and b/References/photoshop-scripting-guide-2020_unlocked.pdf differ diff --git a/cspell.config.yaml b/cspell.config.yaml new file mode 100755 index 0000000..5e1e837 --- /dev/null +++ b/cspell.config.yaml @@ -0,0 +1,15 @@ +version: "0.2" +ignorePaths: [] +dictionaryDefinitions: [] +dictionaries: [] +words: + - Btns + - dilshan + - DONOTSAVECHANGES + - ICYMI + - Pexels + - Photoshop + - Piacquadio + - statictext +ignoreWords: [] +import: []