@defaultc46l0h0jo9o1
The following “Multi Pack Generator" script offers the following features:
- Trims the input image to the upper left & lower right pixel colour
- Creates six different PNG output files in a user-adjustable array for 1, 2, 3, 4, 6, and 12 pack combinations. PNG versions are saved to the same location as the input image. If the input image has not been previously saved, you will be prompted to select an output location.
- Output is 1000px square with white background
- The script can be recorded into an Action, then used via File > Automate > Batch to bulk process an input folder of multiple images.
/*
Multi Pack Generator.jsx
v1.0 - Stephen Marsh, 30th October 2022
https://community.adobe.com/t5/photoshop-ecosystem-discussions/creating-duplicate-images-for-multi-packs-on-online-marketplaces-within-photoshop/td-p/12511723
*/
#target photoshop
if (app.documents.length) {
var savedRuler = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var doc = activeDocument;
var docName = activeDocument.name.replace(/\.[^\.]+$/, '');
// Prepare for step and repeat
trim(true, true, true, true, "topLeftPixelColor");
trim(true, true, true, true, "bottomRightPixelColor");
layerFromBackground(docName);
var docWidth = activeDocument.width.value;
var docHeight = activeDocument.height.value;
try {
// Use the previously saved directory path
var docPath = activeDocument.path;
} catch (e) {
// If unsaved, prompt for the save path
var docPath = Folder.selectDialog('Unsaved file, select the save directory:');
}
////////// 1 pack //////////
arrayGenerator(1, 1);
var saveFile = new File(docPath + '/' + docName + '_1-pack.png');
saveAsPNG(saveFile, 9);
executeAction(stringIDToTypeID("revert"), undefined, DialogModes.NO);
trim(true, true, true, true, "topLeftPixelColor");
trim(true, true, true, true, "bottomRightPixelColor");
layerFromBackground(docName);
////////////////////////////
////////// 2 pack //////////
arrayGenerator(2, 1);
var saveFile = new File(docPath + '/' + docName + '_2-pack.png');
saveAsPNG(saveFile, 9);
executeAction(stringIDToTypeID("revert"), undefined, DialogModes.NO);
trim(true, true, true, true, "topLeftPixelColor");
trim(true, true, true, true, "bottomRightPixelColor");
layerFromBackground(docName);
////////////////////////////
////////// 3 pack //////////
arrayGenerator(3, 1);
var saveFile = new File(docPath + '/' + docName + '_3-pack.png');
saveAsPNG(saveFile, 9);
executeAction(stringIDToTypeID("revert"), undefined, DialogModes.NO);
trim(true, true, true, true, "topLeftPixelColor");
trim(true, true, true, true, "bottomRightPixelColor");
layerFromBackground(docName);
////////////////////////////
////////// 4 pack //////////
arrayGenerator(2, 2);
var saveFile = new File(docPath + '/' + docName + '_4-pack.png');
saveAsPNG(saveFile, 9);
executeAction(stringIDToTypeID("revert"), undefined, DialogModes.NO);
trim(true, true, true, true, "topLeftPixelColor");
trim(true, true, true, true, "bottomRightPixelColor");
layerFromBackground(docName);
////////////////////////////
////////// 6 pack //////////
arrayGenerator(3, 2);
var saveFile = new File(docPath + '/' + docName + '_6-pack.png');
saveAsPNG(saveFile, 9);
executeAction(stringIDToTypeID("revert"), undefined, DialogModes.NO);
trim(true, true, true, true, "topLeftPixelColor");
trim(true, true, true, true, "bottomRightPixelColor");
layerFromBackground(docName);
////////////////////////////
////////// 12 pack //////////
arrayGenerator(4, 3);
var saveFile = new File(docPath + '/' + docName + '_12-pack.png');
saveAsPNG(saveFile, 9);
executeAction(stringIDToTypeID("revert"), undefined, DialogModes.NO);
////////////////////////////
app.preferences.rulerUnits = savedRuler;
} else {
alert("A document must be open to use this script!");
}
/* Functions */
function fitImage(fWidth, fHeight) {
if (doc.height > doc.width) {
doc.resizeImage(null, UnitValue(fHeight, "px"), null, ResampleMethod.BICUBIC);
} else {
doc.resizeImage(UnitValue(fWidth, "px"), null, null, ResampleMethod.BICUBIC);
}
}
function layerFromBackground(layerName) {
if (activeDocument.activeLayer.isBackgroundLayer && activeDocument.layers.length === 1) {
function s2t(s) {
return app.stringIDToTypeID(s);
}
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var reference = new ActionReference();
reference.putProperty(s2t("layer"), s2t("background"));
descriptor.putReference(s2t("null"), reference);
descriptor2.putString(s2t("name"), layerName);
descriptor2.putUnitDouble(s2t("opacity"), s2t("percentUnit"), 100);
descriptor2.putEnumerated(s2t("mode"), s2t("blendMode"), s2t("normal"));
descriptor.putObject(s2t("to"), s2t("layer"), descriptor2);
executeAction(s2t("set"), descriptor, DialogModes.NO);
}
}
function trim(top, bottom, left, right, refPoint) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
descriptor.putEnumerated(s2t("trimBasedOn"), s2t("trimBasedOn"), s2t(refPoint));
descriptor.putBoolean(s2t("top"), top);
descriptor.putBoolean(s2t("bottom"), bottom);
descriptor.putBoolean(s2t("left"), left);
descriptor.putBoolean(s2t("right"), right);
executeAction(s2t("trim"), descriptor, DialogModes.NO);
}
function saveAsPNG(saveFile, quality) {
pngOpts = new PNGSaveOptions();
pngOpts.compression = quality; //0-9
pngOpts.interlaced = false;
activeDocument.saveAs(File(saveFile), pngOpts, true);
}
//////////
function arrayGenerator(paramX, paramY) {
var copiesX = paramX - 1;
var copiesY = paramY - 1;
// Convert to % for relative canvas resize
var newCanvasX = copiesX * 100;
var newCanvasY = copiesY * 100;
// Relative % canvas resize
relativeCanvasSizePercent(true, newCanvasX, newCanvasY);
// Select all layers and group (hack to support multi-layered docs)
layerFromBackground(docName);
app.runMenuItem(stringIDToTypeID('selectAllLayers'));
app.runMenuItem(stringIDToTypeID('groupLayersEvent'));
doc.activeLayer.name = "Original Layers";
// Step & repeat X
for (var i = 0; i < copiesX; i++) {
copyToLayer();
movePX(docWidth, 0);
}
// Select all layers
app.runMenuItem(stringIDToTypeID('selectAllLayers'));
// Step & repeat Y
for (var i = 0; i < copiesY; i++) {
copyToLayer();
movePX(0, docHeight);
}
// Select all layers and group
app.runMenuItem(stringIDToTypeID('selectAllLayers'));
app.runMenuItem(stringIDToTypeID('groupLayersEvent'));
doc.activeLayer.name = "Step & Repeat";
// Extract original layers from step & repeat set
moveOriginalLayersSet();
deleteLayerSet();
/* Helper functions for the array generator */
function moveOriginalLayersSet() {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var list = new ActionList();
var reference = new ActionReference();
var reference2 = new ActionReference();
reference.putName(s2t("layer"), "Original Layers");
descriptor.putReference(s2t("null"), reference);
reference2.putIndex(s2t("layer"), 0);
descriptor.putReference(s2t("to"), reference2);
descriptor.putBoolean(s2t("adjustment"), false);
descriptor.putInteger(s2t("version"), 5);
list.putInteger(3);
descriptor.putList(s2t("layerID"), list);
executeAction(s2t("move"), descriptor, DialogModes.NO);
}
function deleteLayerSet() {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
descriptor.putReference(s2t("null"), reference);
descriptor.putBoolean(s2t("deleteContained"), false); // delete set contents
executeAction(s2t("delete"), descriptor, DialogModes.NO);
}
function movePX(horizontal, vertical) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
descriptor.putReference(s2t("null"), reference);
descriptor2.putUnitDouble(s2t("horizontal"), s2t("pixelsUnit"), horizontal);
descriptor2.putUnitDouble(s2t("vertical"), s2t("pixelsUnit"), vertical);
descriptor.putObject(s2t("to"), s2t("offset"), descriptor2);
executeAction(s2t("move"), descriptor, DialogModes.NO);
}
function copyToLayer() {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
executeAction(s2t("copyToLayer"), undefined, DialogModes.NO);
}
function relativeCanvasSizePercent(relative, width, height) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
descriptor.putBoolean(s2t("relative"), relative);
descriptor.putUnitDouble(s2t("width"), s2t("percentUnit"), width);
descriptor.putUnitDouble(s2t("height"), s2t("percentUnit"), height);
descriptor.putEnumerated(s2t("horizontal"), s2t("horizontalLocation"), s2t("left"));
descriptor.putEnumerated(s2t("vertical"), s2t("verticalLocation"), s2t("top"));
executeAction(s2t("canvasSize"), descriptor, DialogModes.NO);
}
fitImage(950, 950); // pixel value
doc.resizeCanvas(1000, 1000, AnchorPosition.MIDDLECENTER); // pixel value
activeDocument.flatten();
}