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

determine if layer is black and white (or desaturated)

Community Beginner ,
Mar 19, 2011 Mar 19, 2011

Copy link to clipboard

Copied

Is there a way to programmatically determine if a layer of a PSD is black and white?

TOPICS
Actions and scripting

Views

1.5K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe
Guru ,
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

I can think of several ways. Here is one.

function newDocFromLayer(newDocName,newLayerName){
    var desc = new ActionDescriptor();
        var ref = new ActionReference();
        ref.putClass( charIDToTypeID( "Dcmn" ) );
    desc.putReference( charIDToTypeID( "null" ), ref );
    desc.putString( charIDToTypeID( "Nm  " ), newDocName );
        var ref2 = new ActionReference();
        ref2.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
    desc.putReference( charIDToTypeID( "Usng" ), ref2 );
    desc.putString( charIDToTypeID( "LyrN" ), newLayerName );
     executeAction( charIDToTypeID( "Mk  " ), desc, DialogModes.NO );
     return app.activeDocument;
};
var tempDoc = newDocFromLayer('newDocName','newLayerName');
tempDoc.changeMode(ChangeMode.LAB);
if(!tempDoc.activeLayer.isBackgroundLayer) tempDoc.trim(TrimType.TRANSPARENT);
var h = tempDoc.height.as('px');
var w = tempDoc.width.as('px');
var totalPixels = w*h;
var aMidCount = tempDoc.channels[1].histogram[128];
var bMidCount = tempDoc.channels[2].histogram[128];
var isGrayscale = ((totalPixels == aMidCount)&&(totalPixels==bMidCount));
tempDoc.close(SaveOptions.DONOTSAVECHANGES);
alert(isGrayscale);

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

What mode are the images you want to check in anyway? CMYK, RGB …?

I suppose there are several options to achieve it.

• Iterating through the pixels with a ColorSampler would take too long for larger images, I guess.

• The Histogram would be unreliable because the numbers for each value in each Channel could accidentally be identical.

• But hiding other Layers, duplicating the image (mergeLayersOnly), changing to L*a*b, reading the a- and b-Histograms, closing the copy, un-hiding other Layers should work.

If the a- and b-Histograms are all bunched up around 127 (some tolerance could be set) it should be a desaturated Layer.

// check layer for 0 saturation;

// 2011, use it at your own risk;

#target photoshop;

if (app.documents.length > 0) {

var myDocument = app.activeDocument;

hideShowOthers ();

// duplicate;

var theCopy = myDocument.duplicate("copy", true);

theCopy.changeMode(ChangeMode.LAB);

// get histograms;

var theA = theCopy.channels[1].histogram;

var theB = theCopy.channels[2].histogram;

// check histrograms;

var check = true;

check = checkHistogram (theA, check, 0);

check = checkHistogram (theB, check, 0);

// close;

theCopy.close(SaveOptions.DONOTSAVECHANGES);

// re-show;

hideShowOthers ();

if (check == true) {alert ("layer is desaturated")}

else{alert ("layer contains color")}

};

////// check histogram for cumulation around 227 //////

function checkHistogram (histogram, check, tolerance) {

     for (var m = 0; m < 126 - tolerance; m++) {

          if (histogram != 0) {check =  false}

          };

     for (var n = 255; m > 127 + tolerance; m--) {

          if (histogram != 0) {check =  false}

          };

     return check

     };

////// hide/show all others //////

function hideShowOthers () {

// =======================================================

var idShw = charIDToTypeID( "Shw " );

    var desc2 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

        var list1 = new ActionList();

            var ref1 = new ActionReference();

            var idLyr = charIDToTypeID( "Lyr " );

            var idOrdn = charIDToTypeID( "Ordn" );

            var idTrgt = charIDToTypeID( "Trgt" );

            ref1.putEnumerated( idLyr, idOrdn, idTrgt );

        list1.putReference( ref1 );

    desc2.putList( idnull, list1 );

    var idTglO = charIDToTypeID( "TglO" );

    desc2.putBoolean( idTglO, true );

executeAction( idShw, desc2, DialogModes.NO );

};

But someone else may have a better solution ready.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guru ,
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

Here is another way that seems to be a little faster.

function isGrayscale(){
     var redHist = activeDocument.channels[0].histogram;
     var greenHist = activeDocument.channels[1].histogram;
     var blueHist = activeDocument.channels[2].histogram;
     for(var h = 0;h < 256; h++){
          if(!(redHist==greenHist && greenHist==blueHist)) return false;
     }
     return true;
};
function toggleOtherLayers(){//activeLayer
    var desc = new ActionDescriptor();
            var ref = new ActionReference();
            var list = new ActionList();
            ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID("Ordn" ), charIDToTypeID( "Trgt" ) );
        list.putReference( ref );
    desc.putList( charIDToTypeID( "null" ), list );
    desc.putBoolean( charIDToTypeID( "TglO" ), true );
     executeAction( charIDToTypeID( "Shw " ), desc, DialogModes.NO );
};
toggleOtherLayers();
var isGray = isGrayscale();
toggleOtherLayers();
alert(isGray);

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

Hadn’t noticed your first post (as it took me some time to write my post).

I think your second method could theoretically produce incorrect results with some images.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guru ,
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

I could be wrong but I would think that an image would have to be contrived for the histogram of all three channels to match and still not be grayscale.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

True, with photographic or painted images the probability of identical numbers for colorful content seems very low indeed …

One issue I noticed is that the toggling of the Layers should maybe better be wrapped in an if- or try-clause as files with only a Background Layer might pose a problem otherwise.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

Here is another conceptual way to do this leveraging the approaches already mentioned.  This works for RGB

This checks for R=G=B for all pixels quickly

1) Do a difference blend between R channel and G channel

2) Check histogram to verify all values are at histogram location 0  (meaning all R and G pixels are identical)

3) Do same as steps 1 for G and B channels

4) If this too has all histograms values in location 0, then R=G=B at all pixels.

Now, if you want to check for low saturation instead of exact R=G=B (especially in 16 bit color mode) then you test for values in the historgram are all in the "lower bins" set by some arbitrary threshold.

Leveraging the power of Blends

Of course, I am assuming that the OP did not just want to know if the color mode was grayscale.  They have not checked back in.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

Thanks Michael, c.pfaffenbichler, and thebestcpu. Your ideas are all very helpful, and just goes to show "there's more than one way to skin a cat" . As I'm planning for my particular application, I was thinking along the lines of what c.pfaffenbichler guessed would not be a good idea; iterating through the pixels of an image. But, each of the ideas you three have offered would be much more efficient.

I should have clarified in the original post that the images could be RBG or grayscale, and the test would be performed on both 8-bit and 16-bit images. Even without much experience with ES, I imagine determing if an image is in grayscale color mode is far less complex than determing if an image in RGB color mode is a black and white image, though, correct?

Thanks again, I sincerely appreciate the examples.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guru ,
Mar 20, 2011 Mar 20, 2011

Copy link to clipboard

Copied

LATEST

Yes, you can use document.mode to determine the color mode of a document.  It is only when the image only appears grayscale in one of the color modes do you need the kinds of tests that are in this thread.

But I agree that, unless your images are very small, testing the color of each pixel is not something you want to do with javascript.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines