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

How to combine images horizontally via batch?

New Here ,
Jan 29, 2022 Jan 29, 2022

Copy link to clipboard

Copied

I want to combine several thousand thin images horizontally into one Photoshop file using Batch.

I have looked at the contract sheet tool and it only goes to 100 and also leaves a 1 pixel gap.

Is there way to automatically add an image to the right of the last resizing the canvas as it goes? I managed to get resizing working but can't work out how to add +X to the width of an image with each new image, place it at the right then repeat. 

Any batch experts know how to do this?

TOPICS
Actions and scripting

Views

1.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 29, 2022 Jan 29, 2022

You can alternatively use the File > Scripts > Load files into stack script to produce a single file with all of the layers, presuming that they sort alphabetically in the correct order.

 

Change the canvas width to the required size.

 

Move the last layer to the right hand side of the canvas edge.

 

Next select all layers in the layers panel and then use the move tool's align/distribute option to distribute all layers horizontally.

 

EDIT: To automate the above, simply run the following script.

...

Votes

Translate

Translate
Community Expert , Jan 29, 2022 Jan 29, 2022

I changed all references from vertical to horizontal and height to width and the alignment options etc... It seems to work as expected, but it has not been extensivly tested:

 

/*
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-combine-images-horizontally-via-batch/m-p/12716190#M619600
Files to Horizontally Stacked Layers.jsx
based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-create-one-big-png-image-from-multiple-png-images/td-p/12359415
Files 
...

Votes

Translate

Translate
Adobe
Community Expert ,
Jan 29, 2022 Jan 29, 2022

Copy link to clipboard

Copied

I believe that you can use a script developed by the late JJMack for this task:

 

http://www.mouseprints.net/old/dpr/PasteImageRoll.html


Edit: I wrote a different script for vertical stacking, should be easy enough to adapt when I have time.

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 29, 2022 Jan 29, 2022

Copy link to clipboard

Copied

I changed all references from vertical to horizontal and height to width and the alignment options etc... It seems to work as expected, but it has not been extensivly tested:

 

/*
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-combine-images-horizontally-via-batch/m-p/12716190#M619600
Files to Horizontally Stacked Layers.jsx
based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-create-one-big-png-image-from-multiple-png-images/td-p/12359415
Files to Vertically Stacked Layers.jsx
*/

#target photoshop

if (app.documents.length === 0) {

    (function () {

        // Save the current dialog display settings
        var savedDisplayDialogs = app.displayDialogs;
        app.displayDialogs = DialogModes.NO;

        // Capture the original ruler units and set the ruler units to pixels
        var origUnits = app.preferences.rulerUnits;
        app.preferences.rulerUnits = Units.PIXELS;

        // Select the input folder
        var inputFolder = Folder.selectDialog('Please select the input folder:');
        // Test if Cancel button returns null, then do nothing
        if (inputFolder === null) {
            app.beep();
            return;
        }

        // Supported file formats
        var inputFiles = inputFolder.getFiles(/\.(jpg|jpeg|tif|tiff|png|psd|psb)$/i);
        // Alpha numeric sort
        // inputFiles.sort().reverse;
        inputFiles.sort();

        // Process the first "base" file
        var firstFile = app.open(File(inputFiles[0]));
        var firstFileName = app.activeDocument.name;
        app.activeDocument.duplicate("Horizontal-Stacker", false);
        firstFile.close(SaveOptions.DONOTSAVECHANGES);
        var docStack = app.documents[0];
        app.activeDocument = docStack;
        docStack.activeLayer.name = firstFileName;
        var baseHeight = app.activeDocument.width.value;

        // Process the remaining file layers to the "base" file
        for (var i = 1; i < inputFiles.length; i++) {
            var remainingFiles = app.open(File(inputFiles[i]));
            var fileName = remainingFiles.name;
            remainingFiles.activeLayer.name = fileName;
            remainingFiles.layers[0].duplicate(docStack, ElementPlacement.PLACEATBEGINNING);
            remainingFiles.close(SaveOptions.DONOTSAVECHANGES);
            relativeCanvasSize(true, baseHeight);
            align2SelectAll('AdCV');
            align2SelectAll('AdLf');
        }

        app.runMenuItem(stringIDToTypeID("selectAllLayers"));
        reverseLayerStack();
        app.activeDocument.flatten();

        app.beep();
        alert(inputFiles.length + ' files horizontally stacked!');

        // Restore the dialogs
        app.displayDialogs = savedDisplayDialogs;

        // Return the original ruler units
        app.preferences.rulerUnits = origUnits;


        // Functions

        function relativeCanvasSize(relative, width) {
            var s2t = function (s) {
                return app.stringIDToTypeID(s);
            };

            var descriptor = new ActionDescriptor();

            descriptor.putBoolean(s2t("relative"), relative);
            descriptor.putUnitDouble(s2t("width"), s2t("pixelsUnit"), width);
            descriptor.putEnumerated(s2t("horizontal"), s2t("horizontalLocation"), s2t("top"));
            executeAction(s2t("canvasSize"), descriptor, DialogModes.NO);
        }

        function align2SelectAll(method) {

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

        }

        function reverseLayerStack() {
            var idreverse = stringIDToTypeID("reverse");
            var desc4653 = new ActionDescriptor();
            var idnull = stringIDToTypeID("null");
            var ref2335 = new ActionReference();
            var idlayer = stringIDToTypeID("layer");
            var idordinal = stringIDToTypeID("ordinal");
            var idtargetEnum = stringIDToTypeID("targetEnum");
            ref2335.putEnumerated(idlayer, idordinal, idtargetEnum);
            desc4653.putReference(idnull, ref2335);
            executeAction(idreverse, desc4653, DialogModes.NO);
        }


    })();

} else {
    alert('Please close all open files before running this script...');
}

 

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 29, 2022 Jan 29, 2022

Copy link to clipboard

Copied

You can alternatively use the File > Scripts > Load files into stack script to produce a single file with all of the layers, presuming that they sort alphabetically in the correct order.

 

Change the canvas width to the required size.

 

Move the last layer to the right hand side of the canvas edge.

 

Next select all layers in the layers panel and then use the move tool's align/distribute option to distribute all layers horizontally.

 

EDIT: To automate the above, simply run the following script. I have updated the code to automatically run the load files into stack script, so it is now fully automated.

 

/*
Combine Images Horizontally.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-combine-images-horizontally-via-batch/td-p/12716190
Stephen Marsh, v1.0 - 31st January 2022
*/

$.evalFile(File(app.path + '/Presets/Scripts/Load Files into Stack.jsx'));
var newWidth = app.activeDocument.layers.length * 100;
canvasSize(newWidth);
align2SelectAll('AdRg');
app.runMenuItem(stringIDToTypeID('selectAllLayers'));
distributeHorizontally();


// Functions

function distributeHorizontally() {
	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.putEnumerated( s2t( "using" ), s2t( "alignDistributeSelector" ), s2t( "ADSDistH" ));
	executeAction( s2t( "distort" ), descriptor, DialogModes.NO );
}

function canvasSize(width) {
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};

	var descriptor = new ActionDescriptor();

	descriptor.putUnitDouble( s2t( "width" ), s2t( "percentUnit" ), width );
	descriptor.putEnumerated( s2t( "horizontal" ), s2t( "horizontalLocation" ), s2t( "left" ));
	executeAction( s2t( "canvasSize" ), descriptor, DialogModes.NO );
}

function align2SelectAll(method) {

   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 29, 2022 Jan 29, 2022

Copy link to clipboard

Copied

You can also try the following scripts here, just use a row value of 1 with a column value as required. You may wish to work in smaller batches, not sure how things would work on "thousands of images" even if they are small:

 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/creating-duplicate-images-for-multi-p...

 

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
New Here ,
Jan 30, 2022 Jan 30, 2022

Copy link to clipboard

Copied

Thank you for giving me multiple options here. I'll give each a go and see which one works the best. This is for a long term art project I've been putting off.  This has been very helpful.

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 30, 2022 Jan 30, 2022

Copy link to clipboard

Copied

Thanks, feedback on each of the proposed solutions would be appreciated. This all presumes that each separate file is the same width. 

P.S. Batch/Action isn't really designed for this task, it may be possible but wouldn't be my preferred approach when scripts are available.

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 ,
Sep 14, 2024 Sep 14, 2024

Copy link to clipboard

Copied

LATEST

The scripts I create on the forum are often for other users, not my personal use. Stacking files in horizontal or vertical layout layers is something that I do quite often. I have combined my previously separate horizontal and vertical stacker scripts into a single script with an interface:

 

2024-09-15_15-05-03.png

Note: It is assumed that the stacked files will create a canvas size below the common 30,000 or 300,000 px limits.  :]

 

/*
Files to Horizontally or Vertically Stacked Layers scriptUI GUI.jsx
v1.0, 15th September 2024
Based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-create-one-big-png-image-from-multiple-png-images/td-p/12359415
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-combine-images-horizontally-via-batch/m-p/12716190#M619600
*/

#target photoshop

function showGUI() {
    var dlg = new Window('dialog', 'Horizontal or Vertical File Stacker (v1.0)');
    dlg.preferredSize = [300, 250];
    dlg.orientation = 'column';
    dlg.alignChildren = 'center';

    // Stack Direction Dropdown
    var dropdown = dlg.add('dropdownlist', undefined, ['Horizontal Stack', 'Vertical Stack']);
    dropdown.selection = 0; // Default to Horizontal Stack

    // Horizontal Alignment Radio Buttons
    dlg.add('statictext', undefined, 'Horizontal Stack Alignment:');
    var hAlignmentGroup = dlg.add('group');
    hAlignmentGroup.orientation = 'row';
    var rbtnHCenter = hAlignmentGroup.add('radiobutton', undefined, 'Center Vertical');
    var rbtnHTopLeft = hAlignmentGroup.add('radiobutton', undefined, 'Top Left');
    rbtnHCenter.value = true; // Default to Center Vertical alignment

    // Vertical Alignment Radio Buttons
    dlg.add('statictext', undefined, 'Vertical Stack Alignment:');
    var vAlignmentGroup = dlg.add('group');
    vAlignmentGroup.orientation = 'row';
    var rbtnVCenter = vAlignmentGroup.add('radiobutton', undefined, 'Center Horizontal');
    var rbtnVTopLeft = vAlignmentGroup.add('radiobutton', undefined, 'Top Left');
    rbtnVCenter.value = true; // Default to Center Horizontal alignment

    // Reverse Layer Stack Checkbox
    var reverseCheckbox = dlg.add('checkbox', undefined, 'Reverse Layer Stack');
    reverseCheckbox.value = false; // Default to unchecked

    // OK and Cancel Button Group
    var buttonGroup = dlg.add('group');
    buttonGroup.orientation = 'row';
    buttonGroup.alignChildren = 'center';
    buttonGroup.margins = 5;

    // OK Button
    var btnOK = buttonGroup.add('button', undefined, 'OK');
    btnOK.onClick = function () {
        var inputFiles = selectMultipleFiles();
        if (inputFiles) {
            dlg.close();
            var stackDirection = dropdown.selection.text;
            var reverseLayers = reverseCheckbox.value;

            if (stackDirection === 'Horizontal Stack') {
                var hAlignment = rbtnHCenter.value ? 'center' : 'topLeft';
                hStacker(inputFiles, hAlignment, reverseLayers);
            } else {
                var vAlignment = rbtnVCenter.value ? 'center' : 'topLeft';
                vStacker(inputFiles, vAlignment, reverseLayers);
            }
        }
    };

    // Cancel Button
    var btnCancel = buttonGroup.add('button', undefined, 'Cancel', { name: 'cancel' });
    btnCancel.onClick = function () {
        dlg.close();
    };

    // Disable/Enable Alignment Options based on Stack Selection
    dropdown.onChange = function () {
        if (dropdown.selection.text === 'Horizontal Stack') {
            hAlignmentGroup.enabled = true;
            vAlignmentGroup.enabled = false;
        } else {
            hAlignmentGroup.enabled = false;
            vAlignmentGroup.enabled = true;
        }
    };

    // Initially disable vertical alignment radio buttons
    vAlignmentGroup.enabled = false;

    dlg.show();
}

function selectMultipleFiles() {
    var inputFiles = File.openDialog('Select image files', true);
    if (!inputFiles || inputFiles.length === 0) {
        alert('No files selected.');
        return null;
    }
    return inputFiles;
}

if (app.documents.length === 0) {
    showGUI();
} else {
    alert('Please close all open files before running this script...');
}

function hStacker(inputFiles, alignment, reverseLayers) {
    (function () {
        var savedDisplayDialogs = app.displayDialogs;
        app.displayDialogs = DialogModes.NO;
        var origUnits = app.preferences.rulerUnits;
        app.preferences.rulerUnits = Units.PIXELS;

        // Sort files alphabetically
        inputFiles.sort().reverse();

        // Process the first "base" file
        var firstFile = app.open(File(inputFiles[0]));
        var firstFileName = app.activeDocument.name;
        app.activeDocument.duplicate("Horizontal-Stacker", false);
        firstFile.close(SaveOptions.DONOTSAVECHANGES);
        var docStack = app.documents[0];
        app.activeDocument = docStack;
        docStack.activeLayer.name = firstFileName;
        var baseWidth = app.activeDocument.width.value;

        // Process the remaining file layers to the "base" file
        for (var i = 1; i < inputFiles.length; i++) {
            var remainingFiles = app.open(File(inputFiles[i]));
            var fileName = remainingFiles.name;
            remainingFiles.activeLayer.name = fileName;
            remainingFiles.layers[0].duplicate(docStack, ElementPlacement.PLACEATBEGINNING);
            remainingFiles.close(SaveOptions.DONOTSAVECHANGES);
            relativeCanvasSizeW(true, baseWidth);

            if (alignment === 'center') {
                align2SelectAll('AdCV'); // Center Vertical
            } else {
                align2SelectAll('AdTp'); // Align to Top
            }
            align2SelectAll('AdLf'); // Left
        }

        app.runMenuItem(stringIDToTypeID("selectAllLayers"));
        if (reverseLayers) {
            reverseLayerStack();
        }
        app.activeDocument.revealAll();
        app.beep();
        alert(inputFiles.length + ' files stacked horizontally!');
        app.displayDialogs = savedDisplayDialogs;
        app.preferences.rulerUnits = origUnits;

        function relativeCanvasSizeW(relative, width) {
            var s2t = function (s) {
                return app.stringIDToTypeID(s);
            };
            var descriptor = new ActionDescriptor();
            descriptor.putBoolean(s2t("relative"), relative);
            descriptor.putUnitDouble(s2t("width"), s2t("pixelsUnit"), width);
            descriptor.putEnumerated(s2t("horizontal"), s2t("horizontalLocation"), s2t("top"));
            executeAction(s2t("canvasSize"), descriptor, DialogModes.NO);
        }
    })();
}

function vStacker(inputFiles, alignment, reverseLayers) {
    (function () {
        var savedDisplayDialogs = app.displayDialogs;
        app.displayDialogs = DialogModes.NO;
        var origUnits = app.preferences.rulerUnits;
        app.preferences.rulerUnits = Units.PIXELS;

        // Sort files alphabetically
        inputFiles.sort().reverse();

        // Process the first "base" file
        var firstFile = app.open(File(inputFiles[0]));
        var firstFileName = app.activeDocument.name;
        app.activeDocument.duplicate("Vertical-Stacker", false);
        firstFile.close(SaveOptions.DONOTSAVECHANGES);
        var docStack = app.documents[0];
        app.activeDocument = docStack;
        docStack.activeLayer.name = firstFileName;

        // Process the remaining file layers to the "base" file
        for (var i = 1; i < inputFiles.length; i++) {
            var remainingFiles = app.open(File(inputFiles[i]));
            var fileName = remainingFiles.name;
            var baseHeight = activeDocument.height.value;
            remainingFiles.activeLayer.name = fileName;
            remainingFiles.layers[0].duplicate(docStack, ElementPlacement.PLACEATBEGINNING);
            remainingFiles.close(SaveOptions.DONOTSAVECHANGES);
            relativeCanvasSizeH(true, baseHeight);

            if (alignment === 'center') {
                align2SelectAll('AdCH'); // Center Horizontal
            } else {
                align2SelectAll('AdLf'); // Align to Left
            }
            align2SelectAll('AdBt'); // Bottom
        }

        app.runMenuItem(stringIDToTypeID("selectAllLayers"));
        if (reverseLayers) {
            reverseLayerStack();
        }
        app.activeDocument.revealAll();
        app.beep();
        alert(inputFiles.length + ' files stacked vertically!');
        app.displayDialogs = savedDisplayDialogs;
        app.preferences.rulerUnits = origUnits;

        function relativeCanvasSizeH(relative, height) {
            var s2t = function (s) {
                return app.stringIDToTypeID(s);
            };
            var descriptor = new ActionDescriptor();
            descriptor.putBoolean(s2t("relative"), relative);
            descriptor.putUnitDouble(s2t("height"), s2t("pixelsUnit"), height);
            descriptor.putEnumerated(s2t("vertical"), s2t("verticalLocation"), s2t("top"));
            executeAction(s2t("canvasSize"), descriptor, DialogModes.NO);
        }
    })();
}

// Common Helper functions
function reverseLayerStack() {
    var idreverse = stringIDToTypeID("reverse");
    var desc = new ActionDescriptor();
    var ref = new ActionReference();
    ref.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
    desc.putReference(stringIDToTypeID("null"), ref);
    executeAction(idreverse, desc, DialogModes.NO);
}

function align2SelectAll(method) {
    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