Skip to main content
rickyzg
Participating Frequently
September 2, 2021
Question

How to create one big PNG image from multiple PNG images?

  • September 2, 2021
  • 4 replies
  • 9767 views

I have 453 PNG images and every image is 580x580px.  I need to stack all of the images on 580x262740px.

Doing manually takes too much time, is there any way to do it automatically?

 

 

 

This topic has been closed for replies.

4 replies

Stephen Marsh
Community Expert
Community Expert
September 15, 2024

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:

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

 

Legend
September 2, 2021

you can simply create a document with a size of 580x262740px, drag all the files into it. Place the lowest layer at the top of the frame, the last one at the bottom, select all layers and use distribute function to automatically fill the frame vertically. 

You can do it manually or record an action without any problems. Script not needed.

davescm
Community Expert
Community Expert
September 2, 2021

Good idea @jazz-y 

@rickyzg I've got to ask, what will you be doing with such an image?  🙂

 

Dave

JJMack
Community Expert
Community Expert
September 3, 2021

Dave do you think a 1:453 aspect ratio image is a bit strange? What is strange about 2" by 73'

JJMack
JJMack
Community Expert
Community Expert
September 2, 2021

If you just need to stack them the canvas size would be 580x580 you could use Loads files into a stack.  You seem to want to distribute the layer down a narrow tall canvas that is near Photoshop limit of 30,000px. My script should be able to do that. However,  the way my script works its does a copy and Paste Into Between documents.  The 580x262740  document would have a White Background  layer the Png Image layer would be pasted into the document over the document casvas and masked to appropriate  580x580  px area by "Paste Into". The thing is I believe if a png is copied to the clipboard has any transparent boarders the boarders will not be copied to the clipboard only the PNG subject pixels are copied to the clipboard,  In effect the png is trimmed  to its subject matter.  If I'm right your png images may no align the way you want then aligned by Paste Into. You would need to write a script to place in your 453 pngs and distribute them over the canvas.  Or you may be able to use Load Files into a stack to a stack to stack your Pngs then Add canvas to the height and distribute the stack of png images.

 

I think any png that has any transparend boarder  its subject matter would be centered in that Pasted 580x580px tile area.

 

JJMack
rickyzg
rickyzgAuthor
Participating Frequently
September 3, 2021

Thanks for the info, I will try all the options.

Stephen Marsh
Community Expert
Community Expert
September 2, 2021

Some existing scripts include...

 

You can make an image grid with a single row or column:

 
Or one of the scripts from @JJMack:
 
There are likely many more scripts that may suit your task or can be modified for your task, the two above were just the first that came to mind.
 
Good luck!
 
P.S. lucky this is under the 300,000px limit!
 
rickyzg
rickyzgAuthor
Participating Frequently
September 3, 2021

Thanks I will try!