• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
1

Creating duplicate images for multi-packs on Online Marketplaces within Photoshop

Community Beginner ,
Nov 09, 2021 Nov 09, 2021

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. 

 

s-l1600s-l1600s-l1600s-l1600

 

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.

TOPICS
Actions and scripting , Windows

Views

8.6K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 2 Correct answers

Community Expert , Jan 02, 2022 Jan 02, 2022

*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

...

Votes

Translate

Translate
Community Expert , Oct 29, 2022 Oct 29, 2022

@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 scrip
...

Votes

Translate

Translate
Adobe
Advocate ,
Dec 31, 2021 Dec 31, 2021

Copy link to clipboard

Copied

Hi, do you know how to work with smart objects? maybe that is part of the solution

also you can work with data variable in Photoshop, check this link

https://helpx.adobe.com/photoshop/using/creating-data-driven-graphics.html

My Best

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 31, 2021 Dec 31, 2021

Copy link to clipboard

Copied

Edited to add: Yes, an action can automate this task, but you would need different actions or running the same action multiple times, depending on how the action is built.

 

Scripting provides more flexibility and power.

 

For starters:

 

https://morris-photographics.com/photoshop/scripts/array-generator.html

 

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2022 Jan 01, 2022

Copy link to clipboard

Copied

It appears that the script from Trevor Morris linked above does not work correctly with current versions of Photoshop.

 

Rather than debugging the code, I decided to create my own:

 

gui.png

 

/*
Step & Repeat N Times.jsx
v1.0 - Stephen Marsh, 2nd January 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

/* ScriptUI Dialog */
// Dialog
var dialog = new Window("dialog");
dialog.text = "Step & Repeat N Times";
dialog.preferredSize.width = 280;
dialog.preferredSize.height = 135;
dialog.orientation = "row";
dialog.alignChildren = ["center", "top"];
dialog.spacing = 10;
dialog.margins = 10;

// Copies group
var copiesGroup = dialog.add("group", undefined, {
    name: "copiesGroup"
});
copiesGroup.orientation = "column";
copiesGroup.alignChildren = ["left", "top"];
copiesGroup.spacing = 5;
copiesGroup.margins = 0;

var labelCopiesX = copiesGroup.add("statictext", undefined, undefined, {
    name: "labelCopiesX"
});
labelCopiesX.text = "X Copies:";

// Note: use editnumber instead of edittext for numerical fields!

var copiesX = copiesGroup.add('editnumber {properties: {name: "copiesX"}}');
copiesX.text = "1";
copiesX.preferredSize.width = 50;
copiesX.alignment = ["fill", "top"];
// Preset the first field to be selected/active
copiesX.active = true;

var labelCopiesY = copiesGroup.add("statictext", undefined, undefined, {
    name: "labelCopiesY"
});
labelCopiesY.text = "Y Copies:";

var copiesY = copiesGroup.add('editnumber {properties: {name: "copiesY"}}');
copiesY.text = "1";
copiesY.preferredSize.width = 50;
copiesY.alignment = ["fill", "top"];

// Info footer text
/*
var infoGroup = copiesGroup.add("group", undefined, {name: "infoGroup"}); 
    infoGroup.orientation = "column"; 
    infoGroup.alignChildren = ["left","top"]; 
    infoGroup.spacing = 10; 
    infoGroup.margins = [0,10,0,0]; 
    infoGroup.alignment = ["left","top"]; 
    var infoText = infoGroup.add("statictext", undefined, undefined, {name: "infoText"}); 
    infoText.text = "v1.0 - Stephen Marsh, 2nd January 2022";
*/

// Gap group
var gapGroup = dialog.add("group", undefined, {
    name: "gapGroup"
});
gapGroup.orientation = "column";
gapGroup.alignChildren = ["left", "top"];
gapGroup.spacing = 5;
gapGroup.margins = 0;

var labelGapX = gapGroup.add("statictext", undefined, undefined, {
    name: "labelGapX"
});
labelGapX.text = "X Gap (px):";

var gapX = gapGroup.add('editnumber {properties: {name: "gapX"}}');
gapX.text = "0";
gapX.preferredSize.width = 50;
gapX.alignment = ["fill", "top"];

var labelGapY = gapGroup.add("statictext", undefined, undefined, {
    name: "labelGapY"
});
labelGapY.text = "Y Gap (px):";

var gapY = gapGroup.add('editnumber {properties: {name: "gapY"}}');
gapY.text = "0";
gapY.preferredSize.width = 50;
gapY.alignment = ["fill", "top"];

// Border group
var borderGroup = dialog.add("group", undefined, {
    name: "borderGroup"
});
borderGroup.orientation = "column";
borderGroup.alignChildren = ["left", "top"];
borderGroup.spacing = 5;
borderGroup.margins = 0;

var labelBorder = borderGroup.add("statictext", undefined, undefined, {
    name: "labelBorder"
});
labelBorder.text = "Border (px):";

var border = borderGroup.add('editnumber {properties: {name: "border"}}');
border.text = "0";
border.preferredSize.width = 50;
border.alignment = ["fill", "top"];

var okButton = borderGroup.add("button", undefined, undefined, {
    name: "okButton"
});
okButton.text = "OK";
okButton.alignment = ["fill", "top"];

var cancelButton = borderGroup.add("button", undefined, undefined, {
    name: "cancelButton"
});
cancelButton.text = "Cancel";
cancelButton.alignment = ["fill", "top"];

// Remember, digits entered into fields are strings, not numbers!


/* Main script */
function main() {
    // Ensure that the active layer is not a Background, is only a single layer and that the content is not empty
    if (!app.activeDocument.activeLayer.isBackgroundLayer && app.activeDocument.layers.length === 1) {
        // Render the GUI and OK button logic
        if (dialog.show() === 1) {
            // Call the function
            arrayGenerator();
            // End of script notification
            app.beep();
        }
    } else {
        alert("This script is designed to work only on a non-Background, single layer document!");
    }
}
app.activeDocument.suspendHistory("Step & Repeat N Times", "main()");

/* Main script function */
function arrayGenerator() {

    var doc = app.activeDocument;

    // Convert GUI variable strings to numbers...
    // var copiesX2 = Math.floor(copiesX.text);
    // The “double tilde” (~~) operator is a double NOT Bitwise operator. Use it as a substitute for Math.floor(), since it’s faster.
    var copiesX2 = ~~copiesX.text;
    var copiesY2 = ~~copiesY.text;
    var gapX2 = ~~gapX.text;
    var gapY2 = ~~gapY.text;
    var border2 = ~~border.text;
    /*
    alert(copiesX2.toSource())
    alert(copiesY2.toSource())
    alert(gapX2.toSource())
    alert(gapY2.toSource())
    alert(border2.toSource())
    */

    // Convert to % for relative canvas resize
    var newCanvasX = copiesX2 * 100;
    var newCanvasY = copiesY2 * 100;

    var savedRuler = app.preferences.rulerUnits;
    app.preferences.rulerUnits = Units.PIXELS;

    // Relative % canvas resize
    relativeCanvasSizePercent(true, newCanvasX, newCanvasY);
    // Absolute px canvas resize
    doc.resizeCanvas(doc.width + gapX2 * copiesX2, doc.height + gapY2 * copiesY2, AnchorPosition.TOPLEFT);

    // Dupe X loop
    for (var i = 0; i < copiesX2; i++) {
        doc.activeLayer.duplicate();
    }
    // Align X to right
    align2SelectAll('AdRg');
    app.runMenuItem(stringIDToTypeID('selectAllLayers'));
    if (copiesX2 > 1) {
        // Distribute X: for 3 or more layers
        var iddistort = stringIDToTypeID("distort");
        var desc788 = new ActionDescriptor();
        var idnull = stringIDToTypeID("null");
        var ref298 = new ActionReference();
        var idlayer = stringIDToTypeID("layer");
        var idordinal = stringIDToTypeID("ordinal");
        var idtargetEnum = stringIDToTypeID("targetEnum");
        ref298.putEnumerated(idlayer, idordinal, idtargetEnum);
        desc788.putReference(idnull, ref298);
        var idusing = stringIDToTypeID("using");
        var idalignDistributeSelector = stringIDToTypeID("alignDistributeSelector");
        var idADSDistH = stringIDToTypeID("ADSDistH");
        desc788.putEnumerated(idusing, idalignDistributeSelector, idADSDistH);
        executeAction(iddistort, desc788, DialogModes.NO);
    }

    // Merge visible layers
    if (doc.layers.length > 1) {
        var idmergeVisible = stringIDToTypeID("mergeVisible");
        executeAction(idmergeVisible, undefined, DialogModes.NO);
    }

    // Rename layer
    doc.activeLayer.name = "Step & Repeat";

    // Dupe Y loop
    for (var i = 0; i < copiesY2; i++) {
        doc.activeLayer.duplicate();
    }
    // Align Y to bottom
    align2SelectAll('AdBt');
    app.runMenuItem(stringIDToTypeID('selectAllLayers'));
    if (copiesY2 > 1) {
        // Distribute Y: for 3 or more layers
        var iddistort = stringIDToTypeID("distort");
        var desc2102 = new ActionDescriptor();
        var idnull = stringIDToTypeID("null");
        var ref945 = new ActionReference();
        var idlayer = stringIDToTypeID("layer");
        var idordinal = stringIDToTypeID("ordinal");
        var idtargetEnum = stringIDToTypeID("targetEnum");
        ref945.putEnumerated(idlayer, idordinal, idtargetEnum);
        desc2102.putReference(idnull, ref945);
        var idusing = stringIDToTypeID("using");
        var idalignDistributeSelector = stringIDToTypeID("alignDistributeSelector");
        var idADSDistV = stringIDToTypeID("ADSDistV");
        desc2102.putEnumerated(idusing, idalignDistributeSelector, idADSDistV);
        executeAction(iddistort, desc2102, DialogModes.NO);
    }

    // Merge visible layers
    if (doc.layers.length > 1) {
        var idmergeVisible = stringIDToTypeID("mergeVisible");
        executeAction(idmergeVisible, undefined, DialogModes.NO);
    }

    // Rename layer
    doc.activeLayer.name = "Step & Repeat";

    // Optional outer margin absolute px canvas resize
    doc.resizeCanvas(doc.width + border2 * 2, doc.height + border2 * 2, AnchorPosition.MIDDLECENTER);

    app.preferences.rulerUnits = savedRuler;
}

/* Helper functions for main script */
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);
}

function align2SelectAll(method) {
    /* 
    AdLf = Align Left
    AdRg = Align Right
    AdCH = Align Centre Horizontal
    AdTp = Align Top
    AdBt = Align Bottom
    AdCV = Align Centre Vertical
    */
    app.activeDocument.selection.selectAll();
    var desc = new ActionDescriptor();
    var ref = new ActionReference();
    ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
    desc.putReference(charIDToTypeID("null"), ref);
    desc.putEnumerated(charIDToTypeID("Usng"), charIDToTypeID("ADSt"), charIDToTypeID(method));
    try {
        executeAction(charIDToTypeID("Algn"), desc, DialogModes.NO);
    } catch (e) {}
    app.activeDocument.selection.deselect();
}

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2022 Jan 01, 2022

Copy link to clipboard

Copied

Your script works but its UI is not intuitive.  To get a 12 Pack a 4 x 3 layout I need to enter 3 x 2 and the layout is not scaled for the web. It is 4000 px by 4500 px.

Capture.jpg12large.png

   

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 02, 2022 Jan 02, 2022

Copy link to clipboard

Copied

*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 of the original layer. The user can always resize afterward to their desired size. The script is more general-purpose, this could be used for print output.

 

I agree that "Border (px)" may not be intuitive as that may set the expectation for a "stroke" – it is just an outer canvas margin, which is optional and can be left at the default zero value.

 

I can't agree though that "X copies" or "Y Copies" or "X Gap (px)" or "Y Gap (px)" is unitive. The GUI clearly states that the expectation is the number of copies from the original single layer, so yes, it should be 1 less than the total X or Y count.

 

I have taken your constructive criticism on board and have created a revised version where I have adjusted the GUI and hacked the underlying script code to work on the total desired layout required using "No. Across" and "No. Down" etc where if one types in 3 the total is 3.

gui3.png

 

/*
Layer Step & Repeat.jsx
v1.4 - Stephen Marsh, 8th April 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

/* ScriptUI Dialog */
// Dialog
var dialog = new Window("dialog");
dialog.text = "Layer Step & Repeat (v1.4)";
dialog.preferredSize.width = 280;
dialog.preferredSize.height = 135;
dialog.orientation = "row";
dialog.alignChildren = ["center", "top"];
dialog.spacing = 10;
dialog.margins = 10;

// Copies group
var copiesGroup = dialog.add("group", undefined, {
	name: "copiesGroup"
});
copiesGroup.orientation = "column";
copiesGroup.alignChildren = ["left", "top"];
copiesGroup.spacing = 5;
copiesGroup.margins = 0;

var labelCopiesX = copiesGroup.add("statictext", undefined, undefined, {
	name: "labelCopiesX"
});
labelCopiesX.text = "No. Across:";

/* Note: use editnumber instead of edittext for numerical fields! */

var copiesX = copiesGroup.add('editnumber {properties: {name: "copiesX"}}');
copiesX.text = "1";
copiesX.preferredSize.width = 50;
copiesX.alignment = ["fill", "top"];

// Preset the first field to be selected/active
copiesX.active = true;

var labelCopiesY = copiesGroup.add("statictext", undefined, undefined, {
	name: "labelCopiesY"
});
labelCopiesY.text = "No. Down:";

var copiesY = copiesGroup.add('editnumber {properties: {name: "copiesY"}}');
copiesY.text = "1";
copiesY.preferredSize.width = 50;
copiesY.alignment = ["fill", "top"];

// Info footer text
/*
var infoGroup = copiesGroup.add("group", undefined, {name: "infoGroup"}); 
	infoGroup.orientation = "column"; 
	infoGroup.alignChildren = ["left","top"]; 
	infoGroup.spacing = 10; 
	infoGroup.margins = [0,10,0,0]; 
	infoGroup.alignment = ["left","top"]; 
	var infoText = infoGroup.add("statictext", undefined, undefined, {name: "infoText"}); 
	infoText.text = "Unused placeholder for possible future use";
*/

// Gap group
var gapGroup = dialog.add("group", undefined, {
	name: "gapGroup"
});
gapGroup.orientation = "column";
gapGroup.alignChildren = ["left", "top"];
gapGroup.spacing = 5;
gapGroup.margins = 0;

var labelGapX = gapGroup.add("statictext", undefined, undefined, {
	name: "labelGapX"
});
labelGapX.text = "Gap Across (px):";

var gapX = gapGroup.add('editnumber {properties: {name: "gapX"}}');
gapX.text = "0";
gapX.preferredSize.width = 50;
gapX.alignment = ["fill", "top"];

var labelGapY = gapGroup.add("statictext", undefined, undefined, {
	name: "labelGapY"
});
labelGapY.text = "Gap Down (px):";

var gapY = gapGroup.add('editnumber {properties: {name: "gapY"}}');
gapY.text = "0";
gapY.preferredSize.width = 50;
gapY.alignment = ["fill", "top"];

// Outer margin group
var outerMarginGroup = dialog.add("group", undefined, {
	name: "outerMarginGroup"
});
outerMarginGroup.orientation = "column";
outerMarginGroup.alignChildren = ["left", "top"];
outerMarginGroup.spacing = 5;
outerMarginGroup.margins = 0;

var labelOuterMargin = outerMarginGroup.add("statictext", undefined, undefined, {
	name: "labelOuterMargin"
});
labelOuterMargin.text = "Outer Margin (px):";

var outerMargin = outerMarginGroup.add('editnumber {properties: {name: "outerMargin"}}');
outerMargin.text = "0";
outerMargin.preferredSize.width = 50;
outerMargin.alignment = ["fill", "top"];

var okButton = outerMarginGroup.add("button", undefined, undefined, {
	name: "okButton"
});
okButton.text = "OK";
okButton.alignment = ["fill", "top"];

var cancelButton = outerMarginGroup.add("button", undefined, undefined, {
	name: "cancelButton"
});
cancelButton.text = "Cancel";
cancelButton.alignment = ["fill", "top"];

/* Note: digits entered into fields are strings, not numbers! */


/* Main script */
var doc = activeDocument;
var docWidth = activeDocument.width.value;
var docHeight = activeDocument.height.value;

function main() {

	// Ensure that the doc meets the script criteria
	if (!app.activeDocument.activeLayer.isBackgroundLayer) {

		// Render the GUI and OK button logic
		if (dialog.show() === 1) {

			// Call the function
			arrayGenerator();

			// Post script completion option A - call the Fit Image script
			//$.evalFile(File(app.path.fsName + "/Presets/Scripts/Fit Image.jsx"));

			// or

			// Post script completion option B - run the image size command
			//var idimageSize = stringIDToTypeID( "imageSize" );
			//executeAction( idimageSize, undefined, DialogModes.ALL );

			// End of script notification
			app.beep();

		} else {
			//alert("Script cancelled!");
		}

	} else {
		alert("This script is designed to only work on a non Background layer document!");
	}
}

app.activeDocument.suspendHistory("Layer Step & Repeat", "main()");


/* Main script function */
function arrayGenerator() {

	// Convert GUI variable strings to numbers...
	// var copiesX2 = Math.floor(copiesX.text);
	// The “double tilde” (~~) operator is a double NOT Bitwise operator. Use it as a substitute for Math.floor(), since it’s faster.
	var copiesXX = ~~copiesX.text - 1;
	var copiesXX = copiesXX.toString().replace(/^-\d+/, '0').replace(/\.\d+/, '');
	var copiesX2 = ~~copiesXX;
	var copiesYY = ~~copiesY.text - 1;
	var copiesYY = copiesYY.toString().replace(/^-\d+/, '0').replace(/\.\d+/, '');
	var copiesY2 = ~~copiesYY;
	var gapX2 = ~~gapX.text;
	var gapY2 = ~~gapY.text;
	var outerMargin2 = ~~outerMargin.text;

	// Only used for debugging
	$.writeln(copiesX2);
	$.writeln(copiesY2);
	$.writeln(gapX2);
	$.writeln(gapY2);
	$.writeln(outerMargin2);

	// Convert to % for relative canvas resize
	var newCanvasX = copiesX2 * 100;
	var newCanvasY = copiesY2 * 100;

	var savedRuler = app.preferences.rulerUnits;
	app.preferences.rulerUnits = Units.PIXELS;

	// Relative % canvas resize
	relativeCanvasSizePercent(true, newCanvasX, newCanvasY);

	// Select all layers and group (hack to support multi-layered docs)
	app.runMenuItem(stringIDToTypeID('selectAllLayers'));
	app.runMenuItem(stringIDToTypeID('groupLayersEvent'));
	doc.activeLayer.name = "Original Layers";

	// Step & repeat X
	for (var i = 0; i < copiesX2; i++) {
		copyToLayer();
		movePX(docWidth + gapX2, 0);
	}

	// Select all layers
	app.runMenuItem(stringIDToTypeID('selectAllLayers'));

	// Step & repeat Y
	for (var i = 0; i < copiesY2; i++) {
		copyToLayer();
		movePX(0, docHeight + gapY2);
	}

	// Select all layers and group
	app.runMenuItem(stringIDToTypeID('selectAllLayers'));
	app.runMenuItem(stringIDToTypeID('groupLayersEvent'));
	doc.activeLayer.name = "Step & Repeat";
	//renameOriginalLayersCopy();

	// Extract original layers from step & repeat set
	moveOriginalLayersSet();
	deleteLayerSet();

	// Absolute px canvas resize
	doc.resizeCanvas(doc.width + gapX2 * copiesX2, doc.height + gapY2 * copiesY2, AnchorPosition.TOPLEFT);

	// Optional outer margin absolute px canvas resize
	doc.resizeCanvas(doc.width + outerMargin2 * 2, doc.height + outerMargin2 * 2, AnchorPosition.MIDDLECENTER);

	app.preferences.rulerUnits = savedRuler;


	/* Helper functions for main script */

	/*
	function renameOriginalLayersCopy() {
		var s2t = function (s) {
			return app.stringIDToTypeID(s);
		};
		var descriptor = new ActionDescriptor();
		var list = new ActionList();
		var reference = new ActionReference();
		reference.putName(s2t("layer"), "Original Layers copy");
		descriptor.putReference(s2t("null"), reference);
		descriptor.putBoolean(s2t("makeVisible"), false);
		list.putInteger(296);
		descriptor.putList(s2t("layerID"), list);
		executeAction(s2t("select"), descriptor, DialogModes.NO);
		app.activeDocument.activeLayer.name = "Original Layers copy 1";
	}
	*/

	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);
		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);
	}
}

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 12, 2024 Oct 12, 2024

Copy link to clipboard

Copied

LATEST

An updated v1.5 including active layer checks for an unsuitable target layer (adjustment layers, solid fill layers, gradient fill layers, pattern fill layers or Background layer) and GUI options to run Fit Image or Image Size after the step and repeat (previously commented out as hard-coded options).

 

layer-step-and-repeat-v1-5.png

 

/*
Layer Step & Repeat.jsx
v1.5 - 13th October 2024, Stephen Marsh (Updated)
https://community.adobe.com/t5/photoshop-ecosystem-discussions/creating-duplicate-images-for-multi-packs-on-online-marketplaces-within-photoshop/td-p/12511723
*/

#target photoshop

// Check if there's an open document
if (app.documents.length === 0) {
    alert("Please open a document before running this script.");

} else {

    // Main dialog window
    var dialog = new Window("dialog");
    dialog.text = "Layer Step & Repeat (v1.5)";
    dialog.preferredSize.width = 280;
    dialog.preferredSize.height = 165;
    dialog.orientation = "column";
    dialog.alignChildren = ["fill", "top"]; // Changed to fill
    dialog.spacing = 10;
    dialog.margins = 10;

    // Create panel to contain all interface elements except buttons
    var panel = dialog.add("panel");
    panel.orientation = "column";
    panel.alignChildren = ["fill", "top"];
    panel.spacing = 10;
    panel.margins = 10;

    // Main content group (now inside panel)
    var mainGroup = panel.add("group");
    mainGroup.orientation = "row";
    mainGroup.alignChildren = ["left", "top"];
    mainGroup.spacing = 10;
    mainGroup.margins = 0;

    // Copies group
    var copiesGroup = mainGroup.add("group", undefined, {
        name: "copiesGroup"
    });
    copiesGroup.orientation = "column";
    copiesGroup.alignChildren = ["left", "top"];
    copiesGroup.spacing = 5;
    copiesGroup.margins = 0;

    var labelCopiesX = copiesGroup.add("statictext", undefined, undefined, {
        name: "labelCopiesX"
    });
    labelCopiesX.text = "No. Across:";
    labelCopiesX.helpTip = "Total number of horizontal image layers, including the original layer";

    var copiesX = copiesGroup.add('editnumber {properties: {name: "copiesX"}}');
    copiesX.text = "1";
    copiesX.preferredSize.width = 50;
    copiesX.alignment = ["fill", "top"];

    // Preset the first field to be selected/active
    copiesX.active = true;

    var labelCopiesY = copiesGroup.add("statictext", undefined, undefined, {
        name: "labelCopiesY"
    });
    labelCopiesY.text = "No. Down:";
    labelCopiesY.helpTip = "Total number of vertical image layers, including the original layer";

    var copiesY = copiesGroup.add('editnumber {properties: {name: "copiesY"}}');
    copiesY.text = "1";
    copiesY.preferredSize.width = 50;
    copiesY.alignment = ["fill", "top"];

    // Gap group
    var gapGroup = mainGroup.add("group", undefined, {
        name: "gapGroup"
    });
    gapGroup.orientation = "column";
    gapGroup.alignChildren = ["left", "top"];
    gapGroup.spacing = 5;
    gapGroup.margins = 0;

    var labelGapX = gapGroup.add("statictext", undefined, undefined, {
        name: "labelGapX"
    });
    labelGapX.text = "Gap Across (px):";
    labelGapX.helpTip = "Horizontal image layer gap in pixels";

    var gapX = gapGroup.add('editnumber {properties: {name: "gapX"}}');
    gapX.text = "0";
    gapX.preferredSize.width = 50;
    gapX.alignment = ["fill", "top"];

    var labelGapY = gapGroup.add("statictext", undefined, undefined, {
        name: "labelGapY"
    });
    labelGapY.text = "Gap Down (px):";
    labelGapY.helpTip = "Vertical image layer gap in pixels";

    var gapY = gapGroup.add('editnumber {properties: {name: "gapY"}}');
    gapY.text = "0";
    gapY.preferredSize.width = 50;
    gapY.alignment = ["fill", "top"];

    // Outer margin group
    var outerMarginGroup = mainGroup.add("group", undefined, {
        name: "outerMarginGroup"
    });
    outerMarginGroup.orientation = "column";
    outerMarginGroup.alignChildren = ["left", "top"];
    outerMarginGroup.spacing = 5;
    outerMarginGroup.margins = 0;

    var labelOuterMargin = outerMarginGroup.add("statictext", undefined, undefined, {
        name: "labelOuterMargin"
    });
    labelOuterMargin.text = "Outer Margin (px):";
    labelOuterMargin.helpTip = "Optional canvas padding in pixels";

    var outerMargin = outerMarginGroup.add('editnumber {properties: {name: "outerMargin"}}');
    outerMargin.text = "0";
    outerMargin.preferredSize.width = 50;
    outerMargin.alignment = ["fill", "top"];

    // Checkboxes group (now inside panel)
    var checkboxGroup = panel.add("group");
    checkboxGroup.orientation = "row";
    checkboxGroup.alignChildren = ["left", "top"];
    checkboxGroup.alignment = ["fill", "top"];
    checkboxGroup.spacing = 10;
    checkboxGroup.margins = 0;

    var fitImageCheckbox = checkboxGroup.add("checkbox", undefined, "Run Fit Image");
    fitImageCheckbox.helpTip = "Run the File > Automate > Fit Image command";
    var imageSizeCheckbox = checkboxGroup.add("checkbox", undefined, "Run Image Size");
    imageSizeCheckbox.helpTip = "Run the Image > Image Size command";

    // Button group (outside panel)
    var buttonGroup = dialog.add("group");
    buttonGroup.orientation = "row";
    buttonGroup.alignment = ["right", "top"];
    buttonGroup.spacing = 10;
    buttonGroup.margins = 0;

    var cancelButton = buttonGroup.add("button", undefined, undefined, {
        name: "cancelButton"
    });
    cancelButton.text = "Cancel";

    var okButton = buttonGroup.add("button", undefined, undefined, {
        name: "okButton"
    });
    okButton.text = "OK";

    /* Main script */
    var doc = app.activeDocument;
    var docWidth = activeDocument.width.value;
    var docHeight = activeDocument.height.value;

    function main() {

        // Ensure that the doc layer meets the script criteria
        s2t = stringIDToTypeID;
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerKind'));
        r.putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));
        var layerKind = executeActionGet(r).getInteger(p);
        // Adjustment layer || Gradient Fill layer || Pattern Fill layer || Solid Fill layer || Background layer
        if (layerKind == 2 || layerKind == 9 || layerKind == 10 || layerKind == 11 || doc.activeLayer.isBackgroundLayer === true) {
            alert("The current layer category isn't supported! If the layer is a Background layer, convert it to a standard layer.");
        } else {
            // Render the GUI and OK button logic
            if (dialog.show() === 1) {

                if (copiesX.text <= "1" && copiesY.text <= "1") {
                    alert("Script cancelled as both X & Y fields are set to 0 or 1!");
                    return; // Exit the script
                }

                // Call the function
                arrayGenerator();

                // Post script completion options
                if (fitImageCheckbox.value) {
                    // Call the Fit Image script
                    $.evalFile(File(app.path.fsName + "/Presets/Scripts/Fit Image.jsx"));
                }

                if (imageSizeCheckbox.value) {
                    // Run the image size command
                    var idimageSize = stringIDToTypeID("imageSize");
                    executeAction(idimageSize, undefined, DialogModes.ALL);
                }

                // End of script notification
                app.beep();

            } else {
                //alert("Script cancelled!");
            }
        }
    }

    app.activeDocument.suspendHistory("Layer Step & Repeat", "main()");


    /* Main script function */
    function arrayGenerator() {

        // Convert GUI variable strings to numbers...
        // var copiesX2 = Math.floor(copiesX.text);
        // The "double tilde" (~~) operator is a double NOT Bitwise operator. Use it as a substitute for Math.floor(), since it's faster.
        var copiesXX = ~~copiesX.text - 1;
        var copiesXX = copiesXX.toString().replace(/^-\d+/, '0').replace(/\.\d+/, '');
        var copiesX2 = ~~copiesXX;
        var copiesYY = ~~copiesY.text - 1;
        var copiesYY = copiesYY.toString().replace(/^-\d+/, '0').replace(/\.\d+/, '');
        var copiesY2 = ~~copiesYY;
        var gapX2 = ~~gapX.text;
        var gapY2 = ~~gapY.text;
        var outerMargin2 = ~~outerMargin.text;

        // Only used for debugging
        $.writeln(copiesX2);
        $.writeln(copiesY2);
        $.writeln(gapX2);
        $.writeln(gapY2);
        $.writeln(outerMargin2);

        // Convert to % for relative canvas resize
        var newCanvasX = copiesX2 * 100;
        var newCanvasY = copiesY2 * 100;

        var savedRuler = app.preferences.rulerUnits;
        app.preferences.rulerUnits = Units.PIXELS;

        // Relative % canvas resize
        relativeCanvasSizePercent(true, newCanvasX, newCanvasY);

        // Select all layers and group (hack to support multi-layered docs)
        app.runMenuItem(stringIDToTypeID('selectAllLayers'));
        app.runMenuItem(stringIDToTypeID('groupLayersEvent'));
        doc.activeLayer.name = "Original Layers";

        // Step & repeat X
        for (var i = 0; i < copiesX2; i++) {
            copyToLayer();
            movePX(docWidth + gapX2, 0);
        }

        // Select all layers
        app.runMenuItem(stringIDToTypeID('selectAllLayers'));

        // Step & repeat Y
        for (var i = 0; i < copiesY2; i++) {
            copyToLayer();
            movePX(0, docHeight + gapY2);
        }

        // Select all layers and group
        app.runMenuItem(stringIDToTypeID('selectAllLayers'));
        app.runMenuItem(stringIDToTypeID('groupLayersEvent'));
        doc.activeLayer.name = "Step & Repeat";
        // Having issues in later versions...
        //renameOriginalLayersCopy();

        // Extract original layers from step & repeat set
        moveOriginalLayersSet();
        deleteLayerSet();

        // Ungroup the step & repeat layer sets
        app.activeDocument.activeLayer = app.activeDocument.layers["Step & Repeat"];
        ungroupLayers();
        ungroupLayers();

        // Absolute px canvas resize
        doc.resizeCanvas(doc.width + gapX2 * copiesX2, doc.height + gapY2 * copiesY2, AnchorPosition.TOPLEFT);

        // Optional outer margin absolute px canvas resize
        doc.resizeCanvas(doc.width + outerMargin2 * 2, doc.height + outerMargin2 * 2, AnchorPosition.MIDDLECENTER);

        app.preferences.rulerUnits = savedRuler;

    }


    /* Helper functions for main script */

    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);
        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);
    }

    function ungroupLayers() {
        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);
        executeAction(s2t("ungroupLayersEvent"), descriptor, DialogModes.NO);
    }

    /*
    function renameOriginalLayersCopy() {
        var s2t = function (s) {
            return app.stringIDToTypeID(s);
        };
        var descriptor = new ActionDescriptor();
        var list = new ActionList();
        var reference = new ActionReference();
        reference.putName(s2t("layer"), "Original Layers copy");
        descriptor.putReference(s2t("null"), reference);
        descriptor.putBoolean(s2t("makeVisible"), false);
        list.putInteger(296);
        descriptor.putList(s2t("layerID"), list);
        executeAction(s2t("select"), descriptor, DialogModes.NO);
        app.activeDocument.activeLayer.name = "Original Layers copy 1";
    }
    */
}

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 31, 2021 Dec 31, 2021

Copy link to clipboard

Copied

The first thing you would need to do is crop your Image to some known aspect ratio. So you can scale the Images for the Web,   Then  you could Tile the image for your packages for web display.  A one pack, a two pack, .... a twelve pack. Here I cropped your image to have a 2:3 Aspect ratio.   I then wanted to create a 12 Pack for the web.   Displays these days normally have at least a ppi resolution of 100ppi.   So if I want a 12 pack to have 4 column  and 3 rows  4x2" = 8" and 3x3" = 9" at 100 ppi the canvas size would be  800px by 900px and fit on most web devices  displays.  The Image most likely will be smaller the 8"x 9" many displays will have resolutions higher then 100ppi.  So after I crop your image I saved it with its 2:3 Aspect Ratio. Then ran my Paste Image Roll script set to 100ppi 12 copies of images that are scaled to 2" x 3". I selected the saved 2:3 image.

Capture.jpg12Pack.jpg

Paste Image Roll Documentation 

Paste Image Roll Script 

 

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 05, 2022 Jan 05, 2022

Copy link to clipboard

Copied

@defaultc46l0h0jo9o1 - Any feedback?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Jan 05, 2022 Jan 05, 2022

Copy link to clipboard

Copied

First response after almost 2 months is like shouting to emptiness.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 05, 2022 Jan 05, 2022

Copy link to clipboard

Copied

Hah, didn't see the date stamp! Another hit and run...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 21, 2022 Oct 21, 2022

Copy link to clipboard

Copied

Hi Stephen, I created this thread and completely forgot about it, apologies!

 

Thanks for creating the script, although there are a few things which I would like to add, 

 

Firstly, online - all images should be 1000 x 1000 px (marketplace guidelines), therefore it would be great to have that be a part of the script, (that the canvas size is set to 1000 x 1000 px). 

 

It would also make workflow / effeciancy much better if it was possible to open one image (of the product), and have the script run, but to create multiple versions with essentially one click (I have had actions set up in the past that are quite similar but im unsure as to how to integrate them into a script). It would mean that once you run the script on the image it exports multiple images, outputing a 2 pack, 3 pack, 4 pack, 6 pack, 12 pack main image and so on, into a folder, without having to run the script for each individual pack size. 

 

It would be great if "trim" was added to the start of the script so that once the image is open as an object it removes the background, leaving just the content (product). 

 

All pack sizes also need to be aligned centre to the 1000 x 1000 px canvas, with space around the edges, this would look more aesthetically pleasing than having each product ride along the edges. 

 

some products would be more horizontally dominant than others, meaning that the space between each product should be vertically spaced more (the end result being a collection of products / pack size being more squared than rectangular and thus more suitable to be resized and aligned to the square canvas), ideally this could be split up into presets such as, extremely horizontal (a very narrow image vertically, but long horizontally), horizontal, neutral (square, neither horizontally or vertically dominant), vertical and extremely vertical. 

 

I've attached an example of a product that is extremely horizontal. 

 

Thanks

John

 

 

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 21, 2022 Oct 21, 2022

Copy link to clipboard

Copied

Hi John,

 

There is /*commented out*/ placeholder code to call the fit image or image size command. If the final step and repeat output of the script is required to be 1000x1000px with a white background, this could be hard-coded into the script.

 

The script is already providing more efficiency, however, I understand about workflow. You want it all automated for you with a single button press. The script was designed for user input and interactivity, while you are now stating that it should all be automated. Do you always need the same combination of 2 pack, 3 pack, 4 pack, 6 pack, 12 pack automatically generated? Or does the mix vary?

 

For the initial trim step, are the backgrounds transparent or *pure* white?

 

So how big would the stepped image be in px on the longest side? Say 900px, with a 50px margin either side for the 1000px total? Your original image samples were 1600px.

 

Ideally, you would supply before and after image examples for square, portrait and landscape products (3 x 2 before/after examples of a 6 pack). This way it is 100% clear what you require.

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 22, 2022 Oct 22, 2022

Copy link to clipboard

Copied

Hi Stephen,

Thanks for your reply.

I have checked out more of the combination/composite images from my competitor and it seems that they are arranging the layout of each of the packs dependent on orientation of the products.

For example:

6 Pack:

Extremely vertical: 6 across, 0 down

Vertical: 3 across, 2 down

Neutral: 3 across, 2 down

Horizontal: 3 across, 2 down

Extremely Horizontal: 0 across, 6 down.

It would make sense to have the initial product/object be resized within the 1000px canvas to the largest size as it will be more visible in the search results (the thumbnail of the image). Then leaving a gap/margin of about 50px around the edges.

All images (single packs) have a pure white background and the product sometimes has a drop shadow (nothing too extreme in terms of the shadow in most cases). In most cases the product images are downloaded/webscraped from other websites. All images would need to be trimmed down using the white pixels as the reference.

It depends on the shape of the product if the margins around the product/canvas should be 50px (see example of the bacofoil – 2 pack).

2 Pack,

No. Down 2, Gap down: 400px, canvas then resized to 1000x1000px, the gaps on the Y (top/bottom) are more suitable then if they we set to 50px (the products looked better arranged like this rather than having the vertical gap too much between the two).

3 Pack,

No. Down 3, Gap down: 200px, canvas then resized to 1000px and any transparent sections on the canvas filled with white.

4 Pack,

No. Down 4, Gap down: 50px canvas then resized to 1000px and any transparent sections on the canvas filled with white.

6 Pack,

No. Down 6, gap down: 0. Canvas then resized to 1000px (stack had to be resized down) and any transparent sections on the canvas filled were with white.

12 Pack,

I tried putting a gap of 100px between each product but the output was incorrect (some form of bug / error with the script?), I’ve attached the output jpg.

 

Coke Bottle (Vertical),

2 Pack,

No. Across: 2, Gap Across 100px, canvas resized to 1000x1000px, transparent filled with white.

3 Pack,

No. Across: 3, Gap Across 50px, canvas resized to 1000x1000px, transparent filled with white.

4 Pack,

No. Across 4, Gap Across 0. canvas resized to 1000x1000px, transparent filled with white. Products had to be resized and centred.

6 Pack,

No. Across 6, Gap Across 0, canvas resized to 1000x1000px and the product stack resized and centred.

12 Pack,

No. Across 6, No. Down 2, Gap 0, canvas resized 1000x1000px, products resized to fit.

 

Finish Powerball,

2 Pack,

No. Across 2, Gap 0, canvas/stack resized.

3 Pack,

No. Across 3, Gap 0, Canvas/stack resized.

4 Pack,

No. Across 2, No. Down 2, Canvas/stack resized.

6 Pack,

No. Across 3, No. Down 2, Canvas/stack resized.

12 Pack,

No. Across 4, No. Down 3, Canvas/stack resized.

 

I've attached the rest of the images in the next replies/comments. 

 

Thanks,

John

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 22, 2022 Oct 22, 2022

Copy link to clipboard

Copied

Coke bottle images. 

(Note above I mentioned that the competitors horizontal product stacks are 3 across, 2 down, its actually 2 across, 3 down.) 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 22, 2022 Oct 22, 2022

Copy link to clipboard

Copied

Finish Products, neutral product shape. 

 

Thanks,

John. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 22, 2022 Oct 22, 2022

Copy link to clipboard

Copied

All pack sizes would be 1, 2, 3, 4, 6, and 12. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 28, 2022 Oct 28, 2022

Copy link to clipboard

Copied

@defaultc46l0h0jo9o1 – John, this is a very bespoke workflow and there are many variables. The scope and requirements have changed from the initial brief way too much for my liking. I apologise, but I have to be honest and blunt. Scripting is just a hobby for me, this feels too much like hard work, hard work that I wouldn't wish to do for money, let alone for free.

 

I might look into automating preset step/repeat combinations with hard-coded values, no GUI. This would be an extension of the initial work that I did previously based on the initial brief.

 

EDIT: John, please compare this 6up version attached to the Finish 6up sample that you provided. I can see this working, providing preset combinations of step and repeat. The source image would always have to be cropped correctly before being processed by the script. The script would basically just step and repeat with no margins/gutters, fit to 950px on the longest edge, then make the canvas square to 1000px resulting in an approx 25px outer margin. No variables, it is what it is, but it would automatically create the various 1, 2, 3, 4, 6, and 12 combinations with no variation.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 28, 2022 Oct 28, 2022

Copy link to clipboard

Copied

@Stephen, your script works as intended, then it is just a matter to scale to the desired size.

Could the OP lauch your script via an action, set the number of copies, and then scale to size.

It always surprises me how demanding some can be with someone else's time, and they intend to make money out of it!!!

 

@defaultc46l0h0jo9o1  An action can do it as well: jump to new layer, set to percentage, canvas size, alt-drag a copy, repeat as desired, scale down as wanted. You'll learn a lot while experimenting!

Again from Trevor Morris: https://morris-photographics.com/photoshop/tutorials/actions.html

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 28, 2022 Oct 28, 2022

Copy link to clipboard

Copied

quote

@defaultc46l0h0jo9o1  An action can do it as well: jump to new layer, set to percentage, canvas size, alt-drag a copy, repeat as desired, scale down as wanted. You'll learn a lot while experimenting!

Again from Trevor Morris: https://morris-photographics.com/photoshop/tutorials/actions.html

 


By @PECourtejoie

 

Agreed, it would only take 6 actions... Then a single action could play all 6 actions, and this could be batched or run from Image Processor or other batch scripts.

 

Probably quicker to just make the 6 actions than to code this as a script. The actions can be duped, so the 2up could be modified into the 3up etc. All one needs to do is use relative % sizing, transforms etc. so that the action is "generic" and not specific to absolute values, except for the fit image and canvas size which do need to be absolute px values.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 28, 2022 Oct 28, 2022

Copy link to clipboard

Copied

Sometimes, the magic spells of half-god sorcerer-scripters can be replicated by the barbarian's simple actions 😉

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 28, 2022 Oct 28, 2022

Copy link to clipboard

Copied

Haha, but we both know that Actions aren't always simple, they can have hundreds of steps. They are just linear and lack the ability to use logic, variables, maths etc. I love it when an Action can do something creative that one may have thought was solely in the domain of scripting.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 28, 2022 Oct 28, 2022

Copy link to clipboard

Copied

Hi Stephen, 

 

Many thanks for that, 

 

yes this would work, do you have the updated script for this? 

 

Please check your PM, I'd like to send a few quid for the time. 

 

@PECourtejoie I'm not intending to take the mick with anyones time here, if anyone doesn't want to do it I'm not forcing them, just FYI I did mention to Stephen prior to commenting that I would be happy to send a dew quid for his time. 

 

Thanks 

John

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 28, 2022 Oct 28, 2022

Copy link to clipboard

Copied

quote

yes this would work, do you have the updated script for this? 

By @defaultc46l0h0jo9o1

 

No, I don't have the updated script John.

 

Before expending any time and effort, I wanted you to compare my proposed 6up vs. your 6up example. They are not exactly the same, but pretty close. As you have stated that this would work, I now know that you would be willing for this to be the basis of creating automated versions for 1, 2, 3, 4, 6, and 12 up combinations.

 

P.S. Thank you for your multiple private and public offers of remuneration, it is truly appreciated. This is just a hobby – I don't want it to feel like work. What I can do, I will, when I'm able.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 28, 2022 Oct 28, 2022

Copy link to clipboard

Copied

Hi Stephen,


regarding your question, as you mentioned in your response re: the 6up version, a fully automated process albeit with no variables would definitely suffice. 

I would suspect that both this new script and version 1.4 could be used in different circumstances, although I can see this new version becoming a valuable contribution to my business. So again, many thanks for your efforts.

 

John

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines