Copy link to clipboard
Copied
Hi all,
I have quite an intermediate understanding of Photoshop, but can't figure out an action or method for quickly creating duplicates of a product within a canvas to then be uploaded to online marketplaces, for example, I have the potential to sell products in multi-packs, there are quite a few sellers online that sell this way and they also create duplicate images of the product for these multi-pack variation ads.
Please see below for an example of multi-pack images that are used for the main image of the advertisements online.
As you can see, all of these seem to be created in photoshop using some form of action to quickly do this in bulk - does anyone have specific knowledge as to how to recreate this process quickly?
Many thanks.
*EDIT – 8th April 2022: I have updated the code to a 1.4 version. Version 1.3 was updated to work with vector layer content. Version 1.2 includes the optional ability to call the Fit Image script or the Image Size command. Simply remove the // double slash comments. If enabled, these options will bring up a second dialog after script completion.
@JJMack - thank you for the feedback.
No, it was not designed to resize for web, all it does is create N amount of horizontal and vertical copies
...
The following “Multi Pack Generator" script offers the following features:
Copy link to clipboard
Copied
The following “Multi Pack Generator" script offers the following features:
/*
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();
}