Copy link to clipboard
Copied
I originally posted this in the Photoshop Mac forum and it was suggested I post here for some help.
I'm rendering out a large-ish print piece (7500x5000pixel HDR) in my 3D app, Cinema 4D. It has a feature called Tiled Camera that chops the scene into a number of tiles and sends each one to a network render client. This is considerably faster than one machine doing the entire frame.
The problem is that I have to manually combine all the image tiles in Photoshop once its done. Yeah, it's kinda clunky. The tile camera doesn't have any overlap between adjacent tiles, so Photomerge doesn't have any pixels to line up.
Depending on the project, there might be 9 tiles or there might be 1000. The number of rows and columns always = ā"total # of images". All tiles are the same size. The final image length would be (ā"total # of images" * "one tile X width in pixels"). Likewise, height would be (ā"total # of images" * "one tile Y height in pixels"). The Tile Camera renders across first then down, so it seems like the process would be "easy" to automate.
It would be cool if the script would auto recognize the number of images and calculate the final canvas size using the above math. But even if a user has to manually input those variables, that would still save hours of hand assembly work.
If anyone feels exceptionally generous and daring, I attached a folder of JPEGs rendered out by the Tile Camera.
Here's how it should look when assembled:
I'd really appreciate any time someone could devote to this.
I have just tried with Photoshop CS3 and Tiger and no prompts/errors.
I wonder if you have tried resetting your preferences?
If that doesn't work you could try adding this line at the top of the script..
app.displayDialogs = DialogModes.NO;
Copy link to clipboard
Copied
Let me ask to make sure I understand what you're looking for.
You only need something to calculate the final dimensions of the assembled image file, correct? Or, are you looking for a script that can reassemble the smaller images into the larger image?
Copy link to clipboard
Copied
In the meantime, here is a script that will get you the overall image size information....
var inputFolder=new Folder();
infold=inputFolder.selectDlg("Select Folder for conversion");
var inputFiles = infold.getFiles("*.jpg");
var numf = inputFiles.length;
var row = Math.sqrt(numf);
var imageArray=File(inputFiles[0]);
open(imageArray);
var im=app.activeDocument;
var w=im.width*row;
var h=im.height*row;
im.close(SaveOptions.DONOTSAVECHANGES);
alert(w);
alert(h);
From here, it would be nothing more than a looping routine to stick the pieces into a main image. Especially since you have them numbered in order.
Copy link to clipboard
Copied
You could give this a try:
// tries to assemble fragmented renderings of equal size and strict order;
// 2009, use it at your own risk;
#target photoshop
// selection-dialog;
var theFolder = Folder.selectDialog();
if (theFolder) {
var origUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.POINTS;
var theFiles = theFolder.getFiles(/\.(jpg|tif|eps|psd)$/i);
theFiles.sort();
var theNumberPerSide = Math.sqrt(theFiles.length);
// open first file;
var theOFile = app.open(File(theFiles[0]));
var theWidth = theOFile.width;
var theHeight = theOFile.height;
theOFile.layers[theOFile.layers.length - 1].isBackgroundLayer = false;
theOFile.resizeCanvas(theOFile.width * theNumberPerSide, theOFile.height * theNumberPerSide, AnchorPosition.TOPLEFT);
var thePos = [0,0];
var horCount = 0;
var verCount = 0;
// transfer layers and offset them;
for (var m = 1; m < theFiles.length; m++) {
var theAddFile = app.open(File(theFiles
if (theAddFile.layers.length > 1) {
theAddFile.flatten()
};
theAddFile.layers[0].duplicate(theOFile, ElementPlacement.PLACEATBEGINNING);
theAddFile.close(SaveOptions.DONOTSAVECHANGES);
var theLayer = theOFile.layers[0];
theLayer.name = theFiles
var horStartPos = theLayer.bounds[0];
var verStartPos = theLayer.bounds[1];
// set the horicontal count;
if (horCount < theNumberPerSide - 1) {
horCount = horCount + 1
}
else {
horCount = 0
};
// set the vertical count;
var verCount = Math.floor(m / theNumberPerSide);
// calculate the offsets;
var horOffset = (horStartPos * (-1)) + (theWidth * horCount);
var verOffset = (verStartPos * (-1)) + (theHeight * verCount);
theLayer.translate(horOffset, verOffset)
};
// save as new file, thanks to xbytor;
var basename = theOFile.name.match(/(.*)\.[^\.]+$/)[1];
var docPath = theOFile.path;
psdOpts = new PhotoshopSaveOptions();
psdOpts.embedColorProfile = true;
psdOpts.alphaChannels = false;
psdOpts.layers = true;
psdOpts.spotColors = true;
theOFile.saveAs((new File(docPath+'/'+basename.slice(0,-4)+"_comb.psd")),psdOpts,false);
app.preferences.rulerUnits = origUnits;
};
Copy link to clipboard
Copied
Christoph, you are completely amazing!! Do you have a PayPal tip jar?
I've tested it out with different numbers of cameras, different resolutions, and aspect ratios and it works perfectly! I'm knocked out!
I've run into two speed bumps that might be out of the scope of scripting.
First, if I render HDR OpenEXR files (my favorite format) and try to reassemble them with your script, I get this error. I thought CS4 supported EXR natively.
If I render out HDR 32-bit per channel TIFFs or PSDs, I get this missing profile for each image. (I don't get the error with 8-bit or 16-bit images). Is there a way to suppress the warning in the script?
Copy link to clipboard
Copied
I think you need the OpenEXR plugin to open EXR files in Photoshop.
You should be able to suppress the profile dialog by editing your Color Management Policies in the Color Settings preference
Copy link to clipboard
Copied
Yeah, I open EXR files all the time in CS4. So I'm curious why the script is throwing up an error message.
Copy link to clipboard
Copied
It may be that EXR files need open arguments when scripting like PDF does.
It may also be that the file type is not the issue. The error says the file referenced does not exists. So maybe the issue is the way the file is referenced.
Copy link to clipboard
Copied
Here is another version that you could try....
By the way, why is it that zip files are corrupted when downloaded on a windows machine? I had to download on one of my Macs(shudder!).
#target photoshop
function main(){
var dlg=
"dialog{text:'Script Interface',bounds:[100,100,500,280],"+
"panel0:Panel{bounds:[10,10,390,170] , text:'' ,properties:{borderStyle:'etched',su1PanelCoordinates:true},"+
"title:StaticText{bounds:[50,10,320,40] , text:'Tile Camera Maker' ,properties:{scrolling:undefined,multiline:undefined}},"+
"panel1:Panel{bounds:[10,50,370,120] , text:'' ,properties:{borderStyle:'etched',su1PanelCoordinates:true},"+
"folder1:EditText{bounds:[10,10,300,30] , text:'' ,properties:{multiline:false,noecho:false,readonly:false}},"+
"Browse:IconButton{bounds:[310,10,350,30] , icon:'SourceFolderIcon',properties:{style:'button'}},"+
"smart:Checkbox{bounds:[10,40,200,61] , text:'Smart Objects?' },"+
"flatten:Checkbox{bounds:[210,40,380,61] , text:'Flatten File?' }},"+
"process:Button{bounds:[10,130,180,151] , text:'Process' },"+
"button1:Button{bounds:[200,130,370,151] , text:'Cancel' }}};";
var win = new Window(dlg,'Tile Camera Maker');
if(version.substr(0,version.indexOf('.'))>9){
win.panel0.title.graphics.font = ScriptUI.newFont("Times","BOLDITALIC",20);
g = win.graphics;
var myBrush = g.newBrush(g.BrushType.SOLID_COLOR, [1.00, 1.00, 1.00, 1]);
g.backgroundColor = myBrush;
var myPen =g.newPen (g.PenType.SOLID_COLOR, [1.00, 0.00, 0.00, 1],lineWidth=1);
}
win.panel0.panel1.folder1.enabled=false;
win.center();
//var inputFolder = Folder.selectDialog("Please select the folder with Files to process");
win.panel0.panel1.Browse.onClick = function() {
inputFolder = Folder.selectDialog("Please select the folder with Files to process");
if(inputFolder !=null){
win.panel0.panel1.folder1.text = decodeURI(inputFolder.fsName);
}
}
win.panel0.process.onClick = function() {
if(win.panel0.panel1.folder1.text == '') {
alert("No input folder selected!");
return;
}
win.close(1);
ProcessFiles();
}
win.show();
function ProcessFiles(){
var fileList = inputFolder.getFiles(/\.(jpg|tif|eps|psd|exr)$/i);
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
var Down = Math.sqrt(fileList.length);
fileList = fileList.sort();
var Across = Down;
open(fileList[0]);
app.activeDocument.duplicate(fileList[0].name.match(/(.*)\.[^\.]+$/)[1]+"-combined");
app.documents[0].close(SaveOptions.DONOTSAVECHANGES);
var FillColor = new SolidColor;
FillColor.rgb.hexValue = 'ffffff';
activeDocument.selection.selectAll();
activeDocument.selection.fill(FillColor);
activeDocument.selection.deselect();
var w=app.activeDocument.width*Down;
var h=app.activeDocument.height*Down;
var offsetX = app.activeDocument.width.value;
var offsetY = app.activeDocument.height.value;
app.activeDocument.resizeCanvas(w, h, AnchorPosition.TOPLEFT);
TLX = 0; TLY = 0; TRX = offsetX; TRY = 0;
BRX = offsetX; BRY = offsetY; BLX = 0; BLY = offsetY;
var z =0;
for(var a = 0; a < Down; a++){
for(var i = 0;i <Across; i++){
activeDocument.selection.select([[TLX,TLY],[TRX,TRY],[BRX,BRY],[BLX,BLY]], SelectionType.REPLACE, 0, false);
placeFile(fileList
if(!win.panel0.panel1.smart.value){
rasterLayer();
}
activeDocument.activeLayer.name = fileList
app.activeDocument.selection.deselect();
z++;
TLX = offsetX * (i+1) ; TRX = TLX + offsetX; BRX = TRX; BLX = TLX;
}
TLX = 0; TLY = offsetY * (a +1); TRX = offsetX; TRY = offsetY * (a +1);
BRX = offsetX; BRY = TRY + offsetY; BLX = 0; BLY = (offsetY * (a +1)+offsetY);
}
if(win.panel0.panel1.flatten.value){
activeDocument.flatten();
}
app.preferences.rulerUnits = startRulerUnits;
}
}
main();
function placeFile(placeFile) {
function cTID(s) { return app.charIDToTypeID(s); };
var desc21 = new ActionDescriptor();
desc21.putPath( cTID('null'), new File(placeFile) );
desc21.putEnumerated( cTID('FTcs'), cTID('QCSt'), cTID('Qcsa') );
var desc22 = new ActionDescriptor();
desc22.putUnitDouble( cTID('Hrzn'), cTID('#Pxl'), 0.000000 );
desc22.putUnitDouble( cTID('Vrtc'), cTID('#Pxl'), 0.000000 );
desc21.putObject( cTID('Ofst'), cTID('Ofst'), desc22 );
executeAction( cTID('Plc '), desc21, DialogModes.NO );
};
function rasterLayer() {
var desc9 = new ActionDescriptor();
var ref4 = new ActionReference();
ref4.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc9.putReference( charIDToTypeID('null'), ref4 );
executeAction( stringIDToTypeID('rasterizeLayer'), desc9, DialogModes.NO );
};
Copy link to clipboard
Copied
Wow Paul, simply incredible! UI dialog and all... Mr. Fancy!
Sorry about the ZIP. Don't know why it wasn't Windows friendly. They usually are.
Your script works great with HDR EXRs and TIFFs! The only weird thing is that Photoshop acts likes it's frozen until the script is complete.
But your script just stitched together a 5GB image composed of almost 1000 tiles in 10 minutes! Wow.
And PSD CS4 really doesn't like HDR images without color profiles. It keeps bonking me for every image. But I guess that's an issue for another thread.
Copy link to clipboard
Copied
Have You tried adjusting Your Color Settings like Michael recommended?
I suppose one could include that in the Script and reset it again, but unless the warning is important to Your work-flow it should be easier simply turning it off.
Copy link to clipboard
Copied
Yeah, I'm familiar with Adobe Color Settings. And I've checked to make sure the settings match yours about missing profiles.
However there's something unique about 32bpc files that makes Photoshop display "missing profile" error even though I told it to ignore it. It correctly ignores missing profiles in 8bpc and 16bpc images. Maybe this is a bug?
Can anyone else confirm?
Try opening this EXR with Photoshop.
(Posting as Gzip TAR because of the funky Mac ZIP errors Windows users were getting)
Copy link to clipboard
Copied
I've tried opening the exr, and then saving as tif/psd/psb and no prompts/errors at all. That was with CS3 and CS4 using Windows Vista
Oh by the way still have problems Gzip Tar on windows, had to download and unzip it on the Mac.
Copy link to clipboard
Copied
Geez Paul! I'm using open source libraries to compress these files. (Tried uploading 7z and XAR, but the forums wouldn't allow it) Maybe the problem is on your end? Or the Adobe Forum isn't properly uploading compressed files?
So anywho - let's all assume this is a Mac bug. How would you supress the color warning within the stitch script?
(I'm going to file a bug report for the Mac version. (Really wish another Mac user would try to open it to confirm))
Copy link to clipboard
Copied
I have just tried with Photoshop CS3 and Tiger and no prompts/errors.
I wonder if you have tried resetting your preferences?
If that doesn't work you could try adding this line at the top of the script..
app.displayDialogs = DialogModes.NO;
Copy link to clipboard
Copied
Resetting seems to have done the trick! Using North America General Purpose 2, I no longer get missing profile messages!
Previously, I was using Monitor Color and Color Management Off... which surprisingly gave me color profile warnings (even when turned off)!
So thanks for all your help! Would you mind if I posted this script to the Cinema 4D forum on CGTalk?
Copy link to clipboard
Copied
I'm glad you have sorted the problem, and please share the script whereever you feel it will be of use.
Copy link to clipboard
Copied
Thanks Paul! Oh, one last thing I just thought of. Will this script automatically switch the .PSD to .PSB Large Document format if the reassembly canvas exceed 30,000 pixels?
Also, what would happen if I used multi-layer PSDs? Would it just grab the top most layer?
Copy link to clipboard
Copied
The script just assembles the tiles so file type just doesn't come into the equation, you can save the file as whatever the filesize/format will allow.
As for multi-layered pdf/tifs it should be fine as the script uses the "place command" and the files are brought in as a smart objects, if the smart object checkbox is left un-ticked the smart object is rasterized.
Copy link to clipboard
Copied
Hey Paul!
I posted the script here and it's gotten very positive reaction!
http://forums.cgsociety.org/showthread.php?f=94&t=808343
Thanks so much for your help!
Copy link to clipboard
Copied
Hey Paul and Navarro!!
Thanks a lot for the script! All Cinema 4D / Photoshop users would like to thank you for this!
Copy link to clipboard
Copied
Hi Paul, I know this is old but hopefully you are still responding. Maybe it is a software release issue since it has been quite some time, but when I run your script in photoshop CC 2020, i get the UI box and can select the folder of images I want to stitch but when I hit process nothing happens. Any thoughts? Many thanks.
Copy link to clipboard
Copied
Ok first of all thanks to Navarro for requesting script (which I was prepared to do) and to the Paul Riggot for writing the script.
I have been maintaining the map files for an online game which I have to generate from approx. 1600 terrain directories, each containing 25 128x128 pixel .png images. (I had to change the script to look for .png files in the target directory and i had to change the font Times in the dialog which apparently isn't one the fonts included with Windows version of Photoshop).
I recently upgraded to Windows 7 and the 32-bit program I previously used stopped passing information for opening multple files to an application.
Again Thank you
Copy link to clipboard
Copied
Great Script Paul, if you fancy a challenge, I'd like to achieve the same result with a multi-pass render from Cinema 4D. Basically that means each tile is a PSD which has a load of layers that I'd like to come together in the assembled image. Do you think that's feasible?
Copy link to clipboard
Copied
I am not sure what you mean, as it is psd files are supported and brought in as smart objects, if left as so, you will be able to access all the layers for each tile.