
Champion
•
626 Messages
•
14.6K Points
Thu, Jun 7, 2018 4:30 PM
Answered
Photoshop: How to check if document has background layer with jsx javascript script
I am going to answer my own question here. Sorry for the keyword soup in the title, but I wanted to make this very searchable for later, in case someone else has this question.
For context, when scripting in photoshop, the index of a layer it is offset by +1 if there is a background layer present. This can cause hard to track bugs if you don't realize it. Lot's of "It works on my file..." issues.
So far, I've discovered 4 methods to check for the presence of a background layer in order to account for that offset. I was curious about performance, so I wrote a quick test and results are... interesting.
Usually action manager code is lighting fast compared to the API, but in this case, when no background is present, the AM code is way slower!
In my case output with background:
Without background:
From now on, I will be using
For context, when scripting in photoshop, the index of a layer it is offset by +1 if there is a background layer present. This can cause hard to track bugs if you don't realize it. Lot's of "It works on my file..." issues.
So far, I've discovered 4 methods to check for the presence of a background layer in order to account for that offset. I was curious about performance, so I wrote a quick test and results are... interesting.
Usually action manager code is lighting fast compared to the API, but in this case, when no background is present, the AM code is way slower!
#target photoshop var timeStart = 0; var activeDocBGLyr = function() { try{ activeDocument.backgroundLayer; return true; }catch(e){ return false; } } var activeDocHasPropBGLyr = function() { return activeDocument.hasOwnProperty("backgroundLayer"); } var artLyrIsBG = function() { return activeDocument.artLayers[activeDocument.artLayers.length - 1].isBackgroundLayer ? 0 : 1; } var hasBackgroundAM = function () { var res = undefined;// jshint ignore:line try { var ref = new ActionReference(); ref.putProperty( 1349677170, 1315774496 ); ref.putIndex( 1283027488, 0 ); executeActionGet( ref ).getString( 1315774496 ); res = true; } catch ( e ) { res = false } return res; } timestart = $.hiresTimer; for (i=0;i<1000;i++) { activeDocBGLyr(); } $.writeln ("activeDocBGLyr(): "+ $.hiresTimer/1000000); timestart = $.hiresTimer; for (i=0;i<1000;i++) { activeDocHasPropBGLyr(); } $.writeln ("activeDocHasPropBGLyr(): "+ $.hiresTimer/1000000); timestart = $.hiresTimer; for (i=0;i<1000;i++) { artLyrIsBG(); } $.writeln ("artLyrIsBG(): "+ $.hiresTimer/1000000) timestart = $.hiresTimer; for (i=0;i<1000;i++) { hasBackgroundAM(); } $.writeln ("hasBackgroundAM(): "+ $.hiresTimer/1000000)
In my case output with background:
activeDocBGLyr(): 0.139192
activeDocHasPropBGLyr(): 0.106644
artLyrIsBG(): 5.53341
hasBackgroundAM(): 0.067161
Without background:
activeDocBGLyr(): 0.301541So for ease of use, legibility, and efficiency, the "hasOwnProperty" version seems to be the clear winner!
activeDocHasPropBGLyr(): 0.143729
artLyrIsBG(): 5.452488
hasBackgroundAM(): 5.955047
From now on, I will be using
activeDocument.hasOwnProperty("backgroundLayer")either wrapped as a function or just in-line.
Question
•
Updated
3 years ago
139
5
Helpful Widget
How can we improve?
Tags
No tags available
Responses
max_johnson_7790531
Champion
•
626 Messages
•
14.6K Points
3 years ago
0
0
paul_riggott
361 Messages
•
6.9K Points
3 years ago
function hasBackground() {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr"), charIDToTypeID( "Bckg" ));
ref.putEnumerated(charIDToTypeID( "Lyr " ),charIDToTypeID( "Ordn" ),charIDToTypeID( "Back" ));
var desc = executeActionGet(ref);
var res = desc.getBoolean(charIDToTypeID( "Bckg" ));
return res;
};
3
0
max_johnson_7790531
Champion
•
626 Messages
•
14.6K Points
3 years ago
Because I assumed things and was lazy, I didn't catch something...
activeDocument.hasOwnProperty("backgroundLayer") ALWAYS RETURNS TRUE. *facepalm*
Below is updated to remove that as an option and to add @Paul's snippet in the test.
With bg:
activeDocBGLyr(): 0.150941= true
artLyrIsBG(): 6.665813= true
hasBackgroundAM(): 0.080708= true
hasBackground(): 0.086598= true
No BG:
activeDocBGLyr(): 0.321263= false
artLyrIsBG(): 6.0933= false
hasBackgroundAM(): 5.796047= false
hasBackground(): 0.083114= false
The new code from @Paul is the clear and uncontested winner!
3
max_johnson_7790531
Champion
•
626 Messages
•
14.6K Points
3 years ago
With a little fiddling, the code Paul Riggott, and digging into document properties, I have a thing! Note, this works on the active document, not the active layer.
Gives us
BG:
hasBackgroundLayerAM(): 0.06694= true
No BG:
hasBackgroundLayerAM(): 0.066474= false
And has the added advantage of being almost human readable...
3
0
ronald_chambers
125 Messages
•
2K Points
3 years ago
Excellent article.
I have been searching about why some scripts run with a BG layer and others don't. I think you answered it with :
So with a BG layer active the first regular active layer will be at index 2 and others after follow as if two layers for BG. This same problem is present when one builds a script and testing with BG layer but not having in other data. Usually get an error about some option in JSX is not available on this machine. The BG layer has to be in slot 0 also????
This is a bigger problem than the runtime to find whether BG is there. I'd use any option to not have a failed run.
Champion a bunch more of these. The documentation for JSX is pretty slim and going nowhere. TOO BAD!!!! If only we could use C/C++ code to directly modify pixels within JSX we could basically forget plugins and just run JSX.
Thanks,
RONC
0
0