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
Hi Paul,
yes the smart objects give me access to the layers in each tile, what I'm trying to achieve is a single PSD where instead of say 25 tiles as smart objects each with 8 layers, I have one combined PSD with 8 layers. I can achieve this by going into each smart object and switching on only layer 1 for example, flattening the master file, then repeating the process but switching on only layer 2, etc. but it's a lengthy process, even when I use an action to automate it.
I've attached a link to two files to try and show what I mean, the first file is a combined image made by running your script, the second is a progression of this where I've compiled it into single layered image, what I'm hoping for is a script that gets me to this final layered image. (I've res'd the files down from 4000px x 4000px to 1000px x 1000px just to reduce file size)
As an added challenge, there could be a scenario where I have more than 25 tiles, it will always be a number with a square root but with, for example, 125 tiles, my current method will be almost impossible to use.
Hope that makes sense! Many thanks in anticipation,
Scott
https://www.wetransfer.com/downloads/345744e8a1bd7af8d8c54332551edc3d20130219104843/ac384e
Copy link to clipboard
Copied
Ok Scott, I have got something for you to try ...
This script needs to run on the document with all smart objects tiles.
What it attempts to do is select each SO in turn,
Open it and duplicate all its layers into the original document
Close the SO
Move the layers to the correct location
remove the SO from the main document
Once all SOs have been processed it then selects all layers of the same name, merges them and sets the new layer blendmode.
Hope it's close....
#target photoshop
app.bringToFront();
main();
function main(){
if(!documents.length) return;
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
var SOLayers = getNamesPlusIDs();
//extract all layers and put them into the main document.
//Then remove the SO.
for( var a in SOLayers){
//Only work on SO layers
if(SOLayers[2].toString() != "true") continue;
var layerID = Number(SOLayers[0]);
selectLayerById(layerID);
selectArea();
var LB = getLayerBoundsByIndex( layerID);
openSO();
selectA...[1].toString());
}
//now we should have unique layer names
uniqueName = UniqueSortedList( uniqueNam...//////////////////F U N C T I O N S
function deselectLayers() {
var desc01 = new ActionDescriptor();
var ref01 = new ActionReference();
ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc01.putReference( charIDToTypeID('null'), ref01 );
executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO );
};
function setBlendMode(blendMode) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( charIDToTypeID('Md '), charIDToTypeID('BlnM'), stringIDToTypeID(blendMode) );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Lyr '), desc2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function UniqueSortedList(ArrayName){
var unduped = new Object;
for (var i = 0; i < ArrayName.length; i++) {
unduped[ArrayName] = ArrayName;
}
var uniques = new Array;for (var k in unduped) {
uniques.push(unduped);}
return uniques;
}
function selectLayerById(ID, add) {
add = (add == undefined) ? add = false : add;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
if (add) {
desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
}
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}
function getNamesPlusIDs(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Names=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
if(i == 0) continue;
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if(layerName.match(/^<\/Layer group/) ) continue;
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
desc.hasKey( stringIDToTypeID( 'smartObject' ) ) ? SO = true : SO=false;
var blendmode = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'mode' )));
Names.push([[Id],[layerName],[SO],[blendmode]]);
};
return Names;
};
function deleteLayerByID(ID) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
desc.putReference( charIDToTypeID('null'), ref );
executeAction( charIDToTypeID('Dlt '), desc, DialogModes.NO );
};
function dupLayers(DocName) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putName( charIDToTypeID('Dcmn'), DocName);
desc.putReference( charIDToTypeID('T '), ref2 );
desc.putInteger( charIDToTypeID('Vrsn'), 5 );
executeAction( charIDToTypeID('Dplc'), desc, DialogModes.NO );
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
}
function getLayerBoundsByIndex( ID ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "bounds" ));
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
var bounds = [];
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom')));
return bounds;
};
function selectArea() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function openSO(){
executeAction(stringIDToTypeID( "placedLayerEditContents" ), undefined, DialogModes.NO );
}
Copy link to clipboard
Copied
Paul,
fantastic, I'd just about achieved it with actions but this is much more elegant! I've just got one issue which you might be able to see in the before and after files at this link - the "Background" layer doesn't complete and the "Atmosphere" layer is missing one tile. Then it will be perfect!
Scott
https://www.wetransfer.com/downloads/23e78f902f67449e5877cb0735432c8720130220135239/c0123a
Copy link to clipboard
Copied
Ah the Atmosphere missing tile wasn't missing it was overwritten by the extra layers below the SOs, the script now removes these and the background layer should now complete.
Hope I have done a bit better this time Scott.
#target photoshop
app.bringToFront();
main();
function main(){
if(!documents.length) return;
try{
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
var SOLayers = getNamesPlusIDs();
for( var b in SOLayers){
//Remove non SO layers
if(SOLayers[2].toString() != "false") continue;
deleteLayerByID(Number(SOLayers[0]));
}
activeDocument.activeLayer = activeDocument.layers[activeDocument.layers.length-1];
if(activeDocument.activeLayer.isBackgroundLayer){
activeDocument.activeLayer.name="Background";
}
SOLayers = getNamesPlusIDs();
//extract all layers and put them into the main document.
//Then remove the SO.
for( var a in SOLayers){
//Only work on SO layers
if(SOLayers[2].toString() != "true") continue;
var layerID = Number(SOLayers[0]);
selectLayerById(layerID);
selectArea();
var LB = getLayerBoundsByIndex( layerID);
openSO();
activeD...[1].toString());
}
//now we should have unique layer names
uniqueName = UniqueSortedList( uniqueNam...//////////////////F U N C T I O N S
function deselectLayers() {
var desc01 = new ActionDescriptor();
var ref01 = new ActionReference();
ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc01.putReference( charIDToTypeID('null'), ref01 );
executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO );
};
function setBlendMode(blendMode) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( charIDToTypeID('Md '), charIDToTypeID('BlnM'), stringIDToTypeID(blendMode) );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Lyr '), desc2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function UniqueSortedList(ArrayName){
var unduped = new Object;
for (var i = 0; i < ArrayName.length; i++) {
unduped[ArrayName] = ArrayName;
}
var uniques = new Array;for (var k in unduped) {
uniques.push(unduped);}
return uniques;
}
function selectLayerById(ID, add) {
add = (add == undefined) ? add = false : add;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
if (add) {
desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
}
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}
function getNamesPlusIDs(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Names=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
if(i == 0) continue;
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if(layerName.match(/^<\/Layer group/) ) continue;
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
desc.hasKey( stringIDToTypeID( 'smartObject' ) ) ? SO = true : SO=false;
var blendmode = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'mode' )));
Names.push([[Id],[layerName],[SO],[blendmode]]);
};
return Names;
};
function deleteLayerByID(ID) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
desc.putReference( charIDToTypeID('null'), ref );
executeAction( charIDToTypeID('Dlt '), desc, DialogModes.NO );
};
function dupLayers(DocName) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putName( charIDToTypeID('Dcmn'), DocName);
desc.putReference( charIDToTypeID('T '), ref2 );
desc.putInteger( charIDToTypeID('Vrsn'), 5 );
executeAction( charIDToTypeID('Dplc'), desc, DialogModes.NO );
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
}
function getLayerBoundsByIndex( ID ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "bounds" ));
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
var bounds = [];
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom')));
return bounds;
};
function selectArea() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function openSO(){
executeAction(stringIDToTypeID( "placedLayerEditContents" ), undefined, DialogModes.NO );
}
Copy link to clipboard
Copied
Hi Paul,
this now works perfectly and has been an absolute essential for a big project I've been working on, I can't thank you enough.
I'd really like to share this on some of the Cinema 4D forums and maybe even with Maxon directly if you don't mind?
It could do with a slight tweak if you're up for one more challenge? I've attached a link to a file that's been stitched together using your first script but this one doesn't work with your second script because it now features the full set of multi-pass render layers - there's now a "Caustics" layer, a "Watermark" layer and a 'Watermark (Alpha)" layer and five separate alpha channels (alpha, depth, object buffer 1, 2 and 3). Would you be able to amend your script to incorporate the extra layers and the five alpha channels? - then it really would be perfect!
https://www.wetransfer.com/downloads/5a95b41e6dcf8d9b98a4b6f52a2c762220130307135141/4d46fd
Copy link to clipboard
Copied
Hi Scott, yes it was a bit of a challenge with my tiny Intel Core Duo 2.93GHz with 4GB ram, it did slow down to a crawl but eventually it did complete. It's one of things that you start off then go get a couple of beers at your local pub.
I do hope you have a much better system with tons of ram!
Yes by all means pass the scripts to anyone who may find them useful.
Please could you test this script ...
#target photoshop
app.bringToFront();
main();
function main(){
if(!documents.length) return;
try{
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
var SOLayers = getNamesPlusIDs();
for( var b in SOLayers){
//Remove non SO layers
if(SOLayers[2].toString() != "false") continue;
deleteLayerByID(Number(SOLayers[0]));
}
activeDocument.activeLayer = activeDocument.layers[activeDocument.layers.length-1];
if(activeDocument.activeLayer.isBackgroundLayer){
activeDocument.activeLayer.name="Background";
}
SOLayers = getNamesPlusIDs();
//extract all layers and put them into the main document.
//Then remove the SO.
for( var a in SOLayers){
//Only work on SO layers
if(SOLayers[2].toString() != "true") continue;
var layerID = Number(SOLayers[0]);
selectLayerById(layerID);
selectArea();
var LB = getLayerBoundsByIndex( layerID);
openSO();
//creat...
.name;
app.activeDocument.activeChannels = [app.activeDocument.channels.getByName(cName)];
app...[1].toString());
}
//now we should have unique layer names
uniqueName = UniqueSortedList( uniqueNam....name;
activeDocument.activeLayer = activeDocument.artLayers.getByName(cName);
SelectWhite();
...//////////////////F U N C T I O N S
function hasSelection (doc) {
if(doc == undefined) doc = activeDocument;
var res = false;
var as = doc.activeHistoryState;
doc.selection.deselect();
if (as != doc.activeHistoryState) {
res = true;
doc.activeHistoryState = as;
}
return res;
};
function SelectWhite() {
function cTID(s) { return app.charIDToTypeID(s); };
var desc22 = new ActionDescriptor();
desc22.putInteger( cTID('Fzns'), 100 );
var desc23 = new ActionDescriptor();
desc23.putDouble( cTID('Lmnc'), 100.000000 );
desc23.putDouble( cTID('A '), 0.000000 );
desc23.putDouble( cTID('B '), 0.000000 );
desc22.putObject( cTID('Mnm '), cTID('LbCl'), desc23 );
var desc24 = new ActionDescriptor();
desc24.putDouble( cTID('Lmnc'), 100.000000 );
desc24.putDouble( cTID('A '), 0.000000 );
desc24.putDouble( cTID('B '), 0.000000 );
desc22.putObject( cTID('Mxm '), cTID('LbCl'), desc24 );
try{
executeAction( cTID('ClrR'), desc22, DialogModes.NO );
}catch(e){}
};
function deselectLayers() {
var desc01 = new ActionDescriptor();
var ref01 = new ActionReference();
ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc01.putReference( charIDToTypeID('null'), ref01 );
executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO );
};
function setBlendMode(blendMode) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( charIDToTypeID('Md '), charIDToTypeID('BlnM'), stringIDToTypeID(blendMode) );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Lyr '), desc2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function UniqueSortedList(ArrayName){
var unduped = new Object;
for (var i = 0; i < ArrayName.length; i++) {
unduped[ArrayName] = ArrayName;
}
var uniques = new Array;for (var k in unduped) {
uniques.push(unduped);}
return uniques;
}
function selectLayerById(ID, add) {
add = (add == undefined) ? add = false : add;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
if (add) {
desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
}
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}
function getNamesPlusIDs(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Names=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
if(i == 0) continue;
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if(layerName.match(/^<\/Layer group/) ) continue;
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
desc.hasKey( stringIDToTypeID( 'smartObject' ) ) ? SO = true : SO=false;
var blendmode = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'mode' )));
Names.push([[Id],[layerName],[SO],[blendmode]]);
};
return Names;
};
function deleteLayerByID(ID) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
desc.putReference( charIDToTypeID('null'), ref );
executeAction( charIDToTypeID('Dlt '), desc, DialogModes.NO );
};
function dupLayers(DocName) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putName( charIDToTypeID('Dcmn'), DocName);
desc.putReference( charIDToTypeID('T '), ref2 );
desc.putInteger( charIDToTypeID('Vrsn'), 5 );
executeAction( charIDToTypeID('Dplc'), desc, DialogModes.NO );
};
function WaterMarkHide() {
var desc = new ActionDescriptor();
var list = new ActionList();
var ref = new ActionReference();
ref.putName( charIDToTypeID('Lyr '), "Watermark (Alpha)" );
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
try{executeAction( charIDToTypeID('Hd '), desc, DialogModes.NO );}catch(e){}
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
}
function getLayerBoundsByIndex( ID ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "bounds" ));
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
var bounds = [];
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom')));
return bounds;
};
function selectArea() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function openSO(){
executeAction(stringIDToTypeID( "placedLayerEditContents" ), undefined, DialogModes.NO );
};
function setLayersVisOn(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ))
if(layerName.match(/^<\/Layer group/) ) continue;
if(!desc.getBoolean(stringIDToTypeID('visible'))){
var list = new ActionList();
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
executeAction( charIDToTypeID('Shw '), desc, DialogModes.NO );
}
};
};
Copy link to clipboard
Copied
Paul, once again, many thanks, I've just run it on a basic scene and it works like a dream, if slowly, even with 48GB of RAM which can't be helped. I'll let you know how it works in practice.
If I could, I'd buy you that beer!
Scott
Copy link to clipboard
Copied
So does this script both stitch and unify layers, or do I need to run the "old" stitcher script first and then this one?
Copy link to clipboard
Copied
You need to run the old sticher script first so that the file has all the Smart Objects to convert.
This second script does take a while to run though.
Copy link to clipboard
Copied
Could Scott or Navarro please test this code as I have made a slight adjustment to the code and it seems to be much faster as it now merges every three SOs.
It may now be useful
#target photoshop
app.bringToFront();
main();
function main(){
if(!documents.length) return;
try{
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
var SOLayers = getNamesPlusIDs();
for( var b in SOLayers){
//Remove non SO layers
if(SOLayers[2].toString() != "false") continue;
deleteLayerByID(Number(SOLayers[0]));
}
activeDocument.activeLayer = activeDocument.layers[activeDocument.layers.length-1];
if(activeDocument.activeLayer.isBackgroundLayer){
activeDocument.activeLayer.name="Background";
}
SOLayers = getNamesPlusIDs();
//extract all layers and put them into the main document.
//Then remove the SO.
for( var a in SOLayers){
//Only work on SO layers
if(SOLayers[2].toString() != "true") continue;
var layerID = Number(SOLayers[0]);
selectLayerById(layerID);
selectArea();
var LB = getLayerBoundsByIndex( layerID);
openSO();
//creat....name;
activeDocument.activeLayer = activeDocument.artLayers.getByName(cName);
SelectWhite();
...//////////////////F U N C T I O N S
function mergeSameNamedLayers(){
//Get a list of the layer names
var layerNameList = getNamesPlusIDs();
//create an array for unique layer names
var uniqueName = new Array();
for(var s in layerNameList){
if(layerNameList[2] == "false") uniqueName.push( layerNameList[1].toString());
}
//now we should have unique layer names
uniqueName = UniqueSortedList( uniqueName ).sort();
//select all layers with the same name, merge them and set blendmode
var BlendMode = new String();
for ( var w in uniqueName){
deselectLayers();
for(var z in layerNameList){
if(uniqueName.toString() == layerNameList [1].toString()){
//select these layers and get blendmode.
BlendMode = layerNameList[3].toString();
selectLayerById(Number(layerNameList[0]), true);
}
}
activeDocument.activeLayer.merge();
setBlendMode(BlendMode);
}
};
function hasSelection (doc) {
if(doc == undefined) doc = activeDocument;
var res = false;
var as = doc.activeHistoryState;
doc.selection.deselect();
if (as != doc.activeHistoryState) {
res = true;
doc.activeHistoryState = as;
}
return res;
};
function SelectWhite() {
function cTID(s) { return app.charIDToTypeID(s); };
var desc22 = new ActionDescriptor();
desc22.putInteger( cTID('Fzns'), 100 );
var desc23 = new ActionDescriptor();
desc23.putDouble( cTID('Lmnc'), 100.000000 );
desc23.putDouble( cTID('A '), 0.000000 );
desc23.putDouble( cTID('B '), 0.000000 );
desc22.putObject( cTID('Mnm '), cTID('LbCl'), desc23 );
var desc24 = new ActionDescriptor();
desc24.putDouble( cTID('Lmnc'), 100.000000 );
desc24.putDouble( cTID('A '), 0.000000 );
desc24.putDouble( cTID('B '), 0.000000 );
desc22.putObject( cTID('Mxm '), cTID('LbCl'), desc24 );
try{
executeAction( cTID('ClrR'), desc22, DialogModes.NO );
}catch(e){}
};
function deselectLayers() {
var desc01 = new ActionDescriptor();
var ref01 = new ActionReference();
ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc01.putReference( charIDToTypeID('null'), ref01 );
executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO );
};
function setBlendMode(blendMode) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( charIDToTypeID('Md '), charIDToTypeID('BlnM'), stringIDToTypeID(blendMode) );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Lyr '), desc2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function UniqueSortedList(ArrayName){
var unduped = new Object;
for (var i = 0; i < ArrayName.length; i++) {
unduped[ArrayName] = ArrayName;
}
var uniques = new Array;for (var k in unduped) {
uniques.push(unduped);}
return uniques;
}
function selectLayerById(ID, add) {
add = (add == undefined) ? add = false : add;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
if (add) {
desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
}
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}
function getNamesPlusIDs(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Names=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
if(i == 0) continue;
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if(layerName.match(/^<\/Layer group/) ) continue;
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
desc.hasKey( stringIDToTypeID( 'smartObject' ) ) ? SO = true : SO=false;
var blendmode = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'mode' )));
Names.push([[Id],[layerName],[SO],[blendmode]]);
};
return Names;
};
function deleteLayerByID(ID) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
desc.putReference( charIDToTypeID('null'), ref );
executeAction( charIDToTypeID('Dlt '), desc, DialogModes.NO );
};
function dupLayers(DocName) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putName( charIDToTypeID('Dcmn'), DocName);
desc.putReference( charIDToTypeID('T '), ref2 );
desc.putInteger( charIDToTypeID('Vrsn'), 5 );
executeAction( charIDToTypeID('Dplc'), desc, DialogModes.NO );
};
function WaterMarkHide() {
var desc = new ActionDescriptor();
var list = new ActionList();
var ref = new ActionReference();
ref.putName( charIDToTypeID('Lyr '), "Watermark (Alpha)" );
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
try{executeAction( charIDToTypeID('Hd '), desc, DialogModes.NO );}catch(e){}
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
}
function getLayerBoundsByIndex( ID ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "bounds" ));
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
var bounds = [];
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom')));
return bounds;
};
function selectArea() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function openSO(){
executeAction(stringIDToTypeID( "placedLayerEditContents" ), undefined, DialogModes.NO );
};
function setLayersVisOn(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ))
if(layerName.match(/^<\/Layer group/) ) continue;
if(!desc.getBoolean(stringIDToTypeID('visible'))){
var list = new ActionList();
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
executeAction( charIDToTypeID('Shw '), desc, DialogModes.NO );
}
};
};
Copy link to clipboard
Copied
Seems to work just fine here!
The original stitcher took only a couple minutes and the revised script took about 15 minutes to fuse together 25 tiles of 1024x1024 each with all 24 multi-pass layers turned on in C4D.
Ran into one tiny issue. When running your newly updated Smart Object fusion script, I got this error at the end of merger operation when running it on 32bpc tiles. However, everthing looked fine visually. Running Mac CS6 (13.0.4) here.
Copy link to clipboard
Copied
Thanks for testing, I don't understand how the name has been changed though as it doesn't refer to the filename in any way.
As for the the other error, there was a bug and it was trying to merge single layers, this new script should fix that.
I have increased the number of tiles before it consolidates them, originally it was dealing with nearly 2k of layers, now it should be in the region of 500 layers.
#target photoshop
app.bringToFront();
main();
function main(){
if(!documents.length) return;
try{
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
var SOLayers = getNamesPlusIDs();
for( var b in SOLayers){
//Remove non SO layers
if(SOLayers[2].toString() != "false") continue;
deleteLayerByID(Number(SOLayers[0]));
}
activeDocument.activeLayer = activeDocument.layers[activeDocument.layers.length-1];
if(activeDocument.activeLayer.isBackgroundLayer){
activeDocument.activeLayer.name="Background";
}
SOLayers = getNamesPlusIDs();
//extract all layers and put them into the main document.
//Then remove the SO.
for( var a in SOLayers){
//Only work on SO layers
if(SOLayers[2].toString() != "true") continue;
var layerID = Number(SOLayers[0]);
selectLayerById(layerID);
selectArea();
var LB = getLayerBoundsByIndex( layerID);
openSO();
//creat....name;
activeDocument.activeLayer = activeDocument.artLayers.getByName(cName);
SelectWhite();
...//////////////////F U N C T I O N S
function twoOrMoreSelected(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ) return true;
return false;
}
function mergeSameNamedLayers(){
//Get a list of the layer names
var layerNameList = getNamesPlusIDs();
//create an array for unique layer names
var uniqueName = new Array();
for(var s in layerNameList){
if(layerNameList[2] == "false") uniqueName.push( layerNameList[1].toString());
}
//now we should have unique layer names
uniqueName = UniqueSortedList( uniqueName ).sort();
//select all layers with the same name, merge them and set blendmode
var BlendMode = new String();
for ( var w in uniqueName){
deselectLayers();
for(var z in layerNameList){
if(uniqueName.toString() == layerNameList [1].toString()){
//select these layers and get blendmode.
BlendMode = layerNameList[3].toString();
selectLayerById(Number(layerNameList[0]), true);
}
}
if(twoOrMoreSelected()) activeDocument.activeLayer.merge();
setBlendMode(BlendMode);
}
};
function hasSelection (doc) {
if(doc == undefined) doc = activeDocument;
var res = false;
var as = doc.activeHistoryState;
doc.selection.deselect();
if (as != doc.activeHistoryState) {
res = true;
doc.activeHistoryState = as;
}
return res;
};
function SelectWhite() {
function cTID(s) { return app.charIDToTypeID(s); };
var desc22 = new ActionDescriptor();
desc22.putInteger( cTID('Fzns'), 100 );
var desc23 = new ActionDescriptor();
desc23.putDouble( cTID('Lmnc'), 100.000000 );
desc23.putDouble( cTID('A '), 0.000000 );
desc23.putDouble( cTID('B '), 0.000000 );
desc22.putObject( cTID('Mnm '), cTID('LbCl'), desc23 );
var desc24 = new ActionDescriptor();
desc24.putDouble( cTID('Lmnc'), 100.000000 );
desc24.putDouble( cTID('A '), 0.000000 );
desc24.putDouble( cTID('B '), 0.000000 );
desc22.putObject( cTID('Mxm '), cTID('LbCl'), desc24 );
try{
executeAction( cTID('ClrR'), desc22, DialogModes.NO );
}catch(e){}
};
function deselectLayers() {
var desc01 = new ActionDescriptor();
var ref01 = new ActionReference();
ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc01.putReference( charIDToTypeID('null'), ref01 );
executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO );
};
function setBlendMode(blendMode) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( charIDToTypeID('Md '), charIDToTypeID('BlnM'), stringIDToTypeID(blendMode) );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Lyr '), desc2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function UniqueSortedList(ArrayName){
var unduped = new Object;
for (var i = 0; i < ArrayName.length; i++) {
unduped[ArrayName] = ArrayName;
}
var uniques = new Array;for (var k in unduped) {
uniques.push(unduped);}
return uniques;
}
function selectLayerById(ID, add) {
add = (add == undefined) ? add = false : add;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
if (add) {
desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
}
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}
function getNamesPlusIDs(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Names=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
if(i == 0) continue;
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if(layerName.match(/^<\/Layer group/) ) continue;
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
desc.hasKey( stringIDToTypeID( 'smartObject' ) ) ? SO = true : SO=false;
var blendmode = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'mode' )));
Names.push([[Id],[layerName],[SO],[blendmode]]);
};
return Names;
};
function deleteLayerByID(ID) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
desc.putReference( charIDToTypeID('null'), ref );
executeAction( charIDToTypeID('Dlt '), desc, DialogModes.NO );
};
function dupLayers(DocName) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putName( charIDToTypeID('Dcmn'), DocName);
desc.putReference( charIDToTypeID('T '), ref2 );
desc.putInteger( charIDToTypeID('Vrsn'), 5 );
executeAction( charIDToTypeID('Dplc'), desc, DialogModes.NO );
};
function WaterMarkHide() {
var desc = new ActionDescriptor();
var list = new ActionList();
var ref = new ActionReference();
ref.putName( charIDToTypeID('Lyr '), "Watermark (Alpha)" );
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
try{executeAction( charIDToTypeID('Hd '), desc, DialogModes.NO );}catch(e){}
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
}
function getLayerBoundsByIndex( ID ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "bounds" ));
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
var bounds = [];
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom')));
return bounds;
};
function selectArea() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function openSO(){
executeAction(stringIDToTypeID( "placedLayerEditContents" ), undefined, DialogModes.NO );
};
function setLayersVisOn(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ))
if(layerName.match(/^<\/Layer group/) ) continue;
if(!desc.getBoolean(stringIDToTypeID('visible'))){
var list = new ActionList();
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
executeAction( charIDToTypeID('Shw '), desc, DialogModes.NO );
}
};
};
Copy link to clipboard
Copied
Still getting that same minor error at the end of the job ā but only with 32bpc tiles. 16-bit and 8-bit tiles complete the job without errors.
I've uploaded a render of 32bpc tiles here if you want to try it on your end:
http://www.mediafire.com/file/u2t9dacs5t5tbaw/stitcher_test_tiles.7z
Copy link to clipboard
Copied
Ah, it looks as if the problem is storing the channel. Must find out why it is not selecting the colour range?
Edit: Yes, you can't select colour range in 32bit, so that's why it's failing.
Now to find a way of selecting and storing the Depth alpha, any Ideas Navarro?
Yet another edit:
Do you think if I selected the Alpha layer then duplicated the Red channel, would this work?
Copy link to clipboard
Copied
Acutally, it would be great if you could copy the Depth Alpha channel (and any other extra alpha channels) into normal image layers.
I'm not sure how this is with other compositing apps like Nuke. But as an After Effects user, this would really be helpful. It's actually kind of annoying that Cinema4D uses extra alpha channels to store data other than transparency. (I'm guessing it saves data by using a grayscale alpha rather than a full RGB layer) But there's no way for AE to read more than one alpha channel.
Copy link to clipboard
Copied
Could you please test this version Navarro.
Alpha channels are now avilable as normal layers but they have the visability turned off, they are still stored as Alpha channels as well.
Hopefully it should now work with 8,16 and 32bit documents.
#target photoshop
app.bringToFront();
main();
function main(){
if(!documents.length) return;
try{
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
var SOLayers = getNamesPlusIDs();
for( var b in SOLayers){
//Remove non SO layers
if(SOLayers[2].toString() != "false") continue;
deleteLayerByID(Number(SOLayers[0]));
}
activeDocument.activeLayer = activeDocument.layers[activeDocument.layers.length-1];
if(activeDocument.activeLayer.isBackgroundLayer){
activeDocument.activeLayer.name="Background";
}
SOLayers = getNamesPlusIDs();
//extract all layers and put them into the main document.
//Then remove the SO.
for( var a in SOLayers){
//Only work on SO layers
if(SOLayers[2].toString() != "true") continue;
var layerID = Number(SOLayers[0]);
selectLayerById(layerID);
selectArea();
var LB = getLayerBoundsByIndex( layerID);
openSO();
//creat....name;
activeDocument.activeLayer = activeDocument.artLayers.getByName(cName);
activeDocument.channels...//////////////////F U N C T I O N S
function twoOrMoreSelected(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ) return true;
return false;
}
function mergeSameNamedLayers(){
//Get a list of the layer names
var layerNameList = getNamesPlusIDs();
//create an array for unique layer names
var uniqueName = new Array();
for(var s in layerNameList){
if(layerNameList[2] == "false") uniqueName.push( layerNameList[1].toString());
}
//now we should have unique layer names
uniqueName = UniqueSortedList( uniqueName ).sort();
//select all layers with the same name, merge them and set blendmode
var BlendMode = new String();
for ( var w in uniqueName){
deselectLayers();
for(var z in layerNameList){
if(uniqueName.toString() == layerNameList [1].toString()){
//select these layers and get blendmode.
BlendMode = layerNameList[3].toString();
selectLayerById(Number(layerNameList[0]), true);
}
}
if(twoOrMoreSelected()) activeDocument.activeLayer.merge();
setBlendMode(BlendMode);
}
};
function hasSelection (doc) {
if(doc == undefined) doc = activeDocument;
var res = false;
var as = doc.activeHistoryState;
doc.selection.deselect();
if (as != doc.activeHistoryState) {
res = true;
doc.activeHistoryState = as;
}
return res;
};function deselectLayers() {
var desc01 = new ActionDescriptor();
var ref01 = new ActionReference();
ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc01.putReference( charIDToTypeID('null'), ref01 );
executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO );
};
function setBlendMode(blendMode) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( charIDToTypeID('Md '), charIDToTypeID('BlnM'), stringIDToTypeID(blendMode) );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Lyr '), desc2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function UniqueSortedList(ArrayName){
var unduped = new Object;
for (var i = 0; i < ArrayName.length; i++) {
unduped[ArrayName] = ArrayName;
}
var uniques = new Array;for (var k in unduped) {
uniques.push(unduped);}
return uniques;
}
function selectLayerById(ID, add) {
add = (add == undefined) ? add = false : add;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
if (add) {
desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
}
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}
function getNamesPlusIDs(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Names=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
if(i == 0) continue;
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if(layerName.match(/^<\/Layer group/) ) continue;
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
desc.hasKey( stringIDToTypeID( 'smartObject' ) ) ? SO = true : SO=false;
var blendmode = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'mode' )));
Names.push([[Id],[layerName],[SO],[blendmode]]);
};
return Names;
};
function deleteLayerByID(ID) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
desc.putReference( charIDToTypeID('null'), ref );
executeAction( charIDToTypeID('Dlt '), desc, DialogModes.NO );
};
function dupLayers(DocName) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putName( charIDToTypeID('Dcmn'), DocName);
desc.putReference( charIDToTypeID('T '), ref2 );
desc.putInteger( charIDToTypeID('Vrsn'), 5 );
executeAction( charIDToTypeID('Dplc'), desc, DialogModes.NO );
};
function WaterMarkHide() {
var desc = new ActionDescriptor();
var list = new ActionList();
var ref = new ActionReference();
ref.putName( charIDToTypeID('Lyr '), "Watermark (Alpha)" );
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
try{executeAction( charIDToTypeID('Hd '), desc, DialogModes.NO );}catch(e){}
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
}
function getLayerBoundsByIndex( ID ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "bounds" ));
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
var bounds = [];
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom')));
return bounds;
};
function selectArea() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function openSO(){
executeAction(stringIDToTypeID( "placedLayerEditContents" ), undefined, DialogModes.NO );
};
function setLayersVisOn(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ))
if(layerName.match(/^<\/Layer group/) ) continue;
if(!desc.getBoolean(stringIDToTypeID('visible'))){
var list = new ActionList();
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
executeAction( charIDToTypeID('Shw '), desc, DialogModes.NO );
}
};
};
Copy link to clipboard
Copied
Works great! No errors on 32bit tiles. And the Depth channel is moved to a layer! Cool!
Copy link to clipboard
Copied
Oh wait a sec. I just remembered C4D can also store any number of Object Buffers into the Alpha Channels as well. Yuck.
Copy link to clipboard
Copied
All those channels are created as a normal layer as well with the visibilty turned off. So you can remove any unwanted layers as you wish.
Copy link to clipboard
Copied
Outstanding! You already thought of that.
Copy link to clipboard
Copied
Do you mind if I post this script at the Cinema 4D forums at CGTalk?
Copy link to clipboard
Copied
Please do Navarro, hope it might be of use to others.
Copy link to clipboard
Copied
I am very sorry that I didn't take into account that other countries might want to use this script and there are a couple of lines of code that would make it fail. I am hopeing that this version should address this problem.
#target photoshop
app.bringToFront();
main();
function main(){
if(!documents.length) return;
try{
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
var SOLayers = getNamesPlusIDs();
for( var b in SOLayers){
//Remove non SO layers
if(SOLayers[2].toString() != "false") continue;
deleteLayerByID(Number(SOLayers[0]));
}
activeDocument.activeLayer = activeDocument.layers[activeDocument.layers.length-1];
if(activeDocument.activeLayer.isBackgroundLayer){
activeDocument.activeLayer.name=activeDocument.activeLayer.name;
}
SOLayers = getNamesPlusIDs();
//extract all layers and put them into the main document.
//Then remove the SO.
for( var a in SOLayers){
//Only work on SO layers
if(SOLayers[2].toString() != "true") continue;
var layerID = Number(SOLayers[0]);
selectLayerById(layerID);
selectArea();
var LB = getLayerBoundsByIndex( layerID);
openSO();
//creat....name;
activeDocument.activeLayer = activeDocument.artLayers.getByName(cName);
activeDocument.channels...//////////////////F U N C T I O N S
function twoOrMoreSelected(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ) return true;
return false;
}
function mergeSameNamedLayers(){
//Get a list of the layer names
var layerNameList = getNamesPlusIDs();
//create an array for unique layer names
var uniqueName = new Array();
for(var s in layerNameList){
if(layerNameList[2] == "false") uniqueName.push( layerNameList[1].toString());
}
//now we should have unique layer names
uniqueName = UniqueSortedList( uniqueName ).sort();
//select all layers with the same name, merge them and set blendmode
var BlendMode = new String();
for ( var w in uniqueName){
deselectLayers();
for(var z in layerNameList){
if(uniqueName.toString() == layerNameList [1].toString()){
//select these layers and get blendmode.
BlendMode = layerNameList[3].toString();
selectLayerById(Number(layerNameList[0]), true);
}
}
if(twoOrMoreSelected()) activeDocument.activeLayer.merge();
setBlendMode(BlendMode);
}
};
function hasSelection (doc) {
if(doc == undefined) doc = activeDocument;
var res = false;
var as = doc.activeHistoryState;
doc.selection.deselect();
if (as != doc.activeHistoryState) {
res = true;
doc.activeHistoryState = as;
}
return res;
};function deselectLayers() {
var desc01 = new ActionDescriptor();
var ref01 = new ActionReference();
ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc01.putReference( charIDToTypeID('null'), ref01 );
executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO );
};
function setBlendMode(blendMode) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var desc2 = new ActionDescriptor();
desc2.putEnumerated( charIDToTypeID('Md '), charIDToTypeID('BlnM'), stringIDToTypeID(blendMode) );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Lyr '), desc2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function UniqueSortedList(ArrayName){
var unduped = new Object;
for (var i = 0; i < ArrayName.length; i++) {
unduped[ArrayName] = ArrayName;
}
var uniques = new Array;for (var k in unduped) {
uniques.push(unduped);}
return uniques;
}
function selectLayerById(ID, add) {
add = (add == undefined) ? add = false : add;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID('null'), ref);
if (add) {
desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
}
desc.putBoolean(charIDToTypeID('MkVs'), false);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
}
function getNamesPlusIDs(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Names=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
if(i == 0) continue;
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
if(layerName.match(/^<\/Layer group/) ) continue;
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
desc.hasKey( stringIDToTypeID( 'smartObject' ) ) ? SO = true : SO=false;
var blendmode = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'mode' )));
Names.push([[Id],[layerName],[SO],[blendmode]]);
};
return Names;
};
function deleteLayerByID(ID) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
desc.putReference( charIDToTypeID('null'), ref );
executeAction( charIDToTypeID('Dlt '), desc, DialogModes.NO );
};
function dupLayers(DocName) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putName( charIDToTypeID('Dcmn'), DocName);
desc.putReference( charIDToTypeID('T '), ref2 );
desc.putInteger( charIDToTypeID('Vrsn'), 5 );
executeAction( charIDToTypeID('Dplc'), desc, DialogModes.NO );
};
function WaterMarkHide() {
var desc = new ActionDescriptor();
var list = new ActionList();
var ref = new ActionReference();
ref.putName( charIDToTypeID('Lyr '), "Watermark (Alpha)" );
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
try{executeAction( charIDToTypeID('Hd '), desc, DialogModes.NO );}catch(e){}
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
}
function getLayerBoundsByIndex( ID ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "bounds" ));
ref.putIdentifier(charIDToTypeID('Lyr '), ID);
var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
var bounds = [];
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom')));
return bounds;
};
function selectArea() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref2 );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function openSO(){
executeAction(stringIDToTypeID( "placedLayerEditContents" ), undefined, DialogModes.NO );
};
function setLayersVisOn(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ))
if(layerName.match(/^<\/Layer group/) ) continue;
if(!desc.getBoolean(stringIDToTypeID('visible'))){
var list = new ActionList();
list.putReference( ref );
desc.putList( charIDToTypeID('null'), list );
executeAction( charIDToTypeID('Shw '), desc, DialogModes.NO );
}
};
};
Copy link to clipboard
Copied
A while back I posted a script that also tiles images its operated quite a bit differently then Paul's script.
Paul's script tries to tiles images on to a canvas where there is an equal numbers of rows and columns of tiles. Where the tile size is set to First image size the document width is first Image width time the number of columns and the height the height of the first image time the number of rows. This only works when all image files are the same size and have the same orientation.
My script works quite differently. It tiles your images into a tile size you set into a document that has the a width and DPI resolution you set. The intent is for printing on Roll paper. Images do not have to be the same size or have the same orientation. Image will be Flattened rotated for best fit and resized to to cover the tile area any excess will be masked off. Paste Image Roll Script this script is now in my Photo Collage Toolkit Documentation and Examples Link to script http://www.mouseprints.net/old/dpr/PasteImageRoll.jsx
Copy link to clipboard
Copied