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

Reading Hex Codes on each layer of a Photoshop Document?

Community Beginner ,
Jul 26, 2023 Jul 26, 2023

Copy link to clipboard

Copied

I have this script (modified a bit) from @jazz-y  that allows me to read all the hex codes in a document into an array which is great. I was wondering if there was a way to push the hexes into their own arrays based off the layers?

 

 

const DE_CIE76 = 0; //color difference: 0-255
const THRESHOLD = 0; //color pixels threshold

var s2t = stringIDToTypeID,
    t2s = typeIDToStringID,
    colorsObj = {},
    colorsArr = [];
(r = new ActionReference()).putProperty(s2t('property'), p = s2t('mode'));
r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
if (t2s(executeActionGet(r).getEnumerationValue(p)) == 'RGBColor') {
    var f = new File(Folder.temp + '/colors.raw');
    (d = new ActionDescriptor()).putBoolean(s2t("channelsInterleaved"), true);
    d.putBoolean(s2t('copy'), true);
    (d1 = new ActionDescriptor()).putObject(s2t("as"), s2t("rawFormat"), d);
    d1.putPath(s2t("in"), f);
    executeAction(s2t("save"), d1, DialogModes.NO);
    f.open('r');
    f.encoding = "BINARY";
    doForcedProgress('Reading colors', 'readColors(f.read(), colorsObj)');
    f.close();
    f.remove();
    for (var a in colorsObj) if (colorsObj[a] > THRESHOLD) colorsArr.push({hex: a });
    if (DE_CIE76) doForcedProgress('Filtering colors by dE = ' + DE_CIE76, 'filterByDE(colorsArr)');
}
        
function readColors(s, colorsObj) {
    for (var i = 0; i < s.length; i += 3) {
        var cur = toHex(s, i, 3)
        updateProgress(i, s.length)
        if (colorsObj[cur]) colorsObj[cur]++; else colorsObj[cur] = 1;
    }
}
function filterByDE(c) {
    for (var i = 0; i < c.length; i++) {
        updateProgress(i, c.length)
        if (c[i] == null) continue;
        var cA = new SolidColor;
        cA.rgb.hexValue = c[i].hex;
        for (var x = i + 1; x < c.length; x++) {
            if (c[x] == null || c[i] == null) continue;
            var cB = new SolidColor;
            cB.rgb.hexValue = c[x].hex;
            if (deltaE(cA, cB) <= 10) {
                if (c[i].pixels > c[x].pixels) {
                    c[i].pixels += c[x].pixels
                    c[x] = null
                } else {
                    c[x].pixels += c[i].pixels
                    c[i] = null
                }
            }
        }
    }
}
function toHex(s, from, bits) {
    var h = '';
    for (var i = from; i < from + bits; i++) h += (('0' + s.charCodeAt(i).toString(16)).slice(-2));
    return h
}
function deltaE(a, b) {
    return Math.sqrt(Math.pow(b.lab.l - a.lab.l, 2) + Math.pow(b.lab.a - a.lab.a, 2) + Math.pow(b.lab.b - a.lab.b, 2))
}

 

Here is my example document:

Zee333_1-1690396026552.png

 

In this example I have four layers named Corgi, Tennis Racquet, Runner, and Bowling Ball and Pin as well as a background layer. The current code generates a list of hex codes which I put in a note. I can shift the background color into it's own array so that my note reads

"Background: Hex1

Hex2

Hex3

Hex4

etc."

But what I really want is a note like this:

"Background: Hex1

Layer 1

Hex2

Hex3

Layer 2

Hex2

Hex4

etc."

I understand that in this code to read the colors a temporary raw file is made and read, ignoring all the layers. Is there a way to read the colors layer by layer or somehow sort the colors after the colors are read?

I really appreciate any help anyone can offer! 

 

TOPICS
Actions and scripting

Views

326

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

correct answers 1 Correct answer

Valorous Hero , Jul 27, 2023 Jul 27, 2023
quote

As far as I can tell the Raw has no transparency, so ....


By @c.pfaffenbichler

 

Untitled-2.jpg

Votes

Translate

Translate
Adobe
Community Expert ,
Jul 26, 2023 Jul 26, 2023

Copy link to clipboard

Copied

You can hide all and show each Layer in turn and run the opration once per Layer.

As far as I can tell the Raw has no transparency, so a background would be introduced and change the quantity of the white pixels. 

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
Valorous Hero ,
Jul 27, 2023 Jul 27, 2023

Copy link to clipboard

Copied

quote

As far as I can tell the Raw has no transparency, so ....


By @c.pfaffenbichler

 

Untitled-2.jpg

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 ,
Jul 27, 2023 Jul 27, 2023

Copy link to clipboard

Copied

Thanks, @r-bin ! 

 

Then the OP should be able to run the operation on each Layer in turn and get meaningul quantities. 

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 ,
Aug 02, 2023 Aug 02, 2023

Copy link to clipboard

Copied

Were you able to Script the necessary steps? 

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 ,
Aug 02, 2023 Aug 02, 2023

Copy link to clipboard

Copied

LATEST

Unfortunately I'm still pretty new at scripting so not yet, I am trying though. I have a script that hides all layers and shows them one at a time but I'm having trouble getting the color reading to work in the context of a plugin or my layer cycling script to work outside the context of a plugin (I don't understand how the color reading code works very well)

const app = require("photoshop").app;
const activeLayers = app.activeDocument.activeLayers;

function circulateLayers() {
    activeLayers.visible = false
//sets all selected layers to hidden
    activeLayers.forEach(layer => {
  //shows one layer at a time
      layer.visible = true; 
  
     //Needs to read document colors and push them into an array named after the layer
     const DE_CIE76 = 0; //color difference: 0-255
     const THRESHOLD = 0; //color pixels threshold
//Modified Color Reading Code

        var s2t = stringIDToTypeID,
            t2s = typeIDToStringID,
            colorsObj = {},
            colorsArr = [],
            tempArr = [];
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('mode'));
        r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
        if (t2s(executeActionGet(r).getEnumerationValue(p)) == 'RGBColor') {
            var f = new File(Folder.temp + '/colors.raw');
            (d = new ActionDescriptor()).putBoolean(s2t("channelsInterleaved"), true);
            d.putBoolean(s2t('copy'), true);
            (d1 = new ActionDescriptor()).putObject(s2t("as"), s2t("rawFormat"), d);
            d1.putPath(s2t("in"), f);
            executeAction(s2t("save"), d1, DialogModes.NO);
            f.open('r');
            f.encoding = "BINARY";
            doForcedProgress('Reading colors', 'readColors(f.read(), colorsObj)');
            f.close();
            f.remove();
            for (var a in colorsObj) if (colorsObj[a] > THRESHOLD) tempArr.push({hex: a });
            if (DE_CIE76) doForcedProgress('Filtering colors by dE = ' + DE_CIE76, 'filterByDE(colorsArr)');
            }
            colorsArr.concat(tempArr);
     
    layer.visible = false; 
    console.log("Here I Go!") 
})
console.log(activeLayers.length)
     activeLayers.forEach(layer => {
      layer.visible = true; 
      console.log("Here I Am Again!") 
     })
 
    }

    function readColors(s, colorsObj) {
      for (var i = 0; i < s.length; i += 3) {
          var cur = toHex(s, i, 3)
          updateProgress(i, s.length)
          if (colorsObj[cur]) colorsObj[cur]++; else colorsObj[cur] = 1;
      }
    }
    function toHex(s, from, bits) {
      var hex = '';
      for (var i = from; i < from + bits; i++) h += (('0' + s.charCodeAt(i).toString(16)).slice(-2));
      return hex
    }

///////////////////////////////////////////////////////////////////////////////////

// Insert text in this created note

///////////////////////////////////////////////////////////////////////////////////

var idsetd = charIDToTypeID( "setd" );

    var desc58 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

        var ref12 = new ActionReference();

        var idannotation = stringIDToTypeID( "annotation" );

        ref12.putIndex( idannotation, 0 ); // the number/index of note

    desc58.putReference( idnull, ref12 );

    var idT = charIDToTypeID( "T   " );

        var desc59 = new ActionDescriptor();

        var idTxtD = charIDToTypeID( "TxtD" );

        desc59.putData( idTxtD, String.fromCharCode( 255, 254, 116, 0, 104, 0, 105, 0, 115, 0, 32, 0, 105, 0, 115, 0, 32, 0, 116, 0, 101, 0, 120, 0, 116, 0, 32, 0, 105, 0, 110, 0, 

32, 0, 97, 0, 32, 0, 110, 0, 111, 0, 116, 0, 101, 0 ) );

        var idtext = stringIDToTypeID( "text" );
       
        desc59.putString( idtext, colorsArr.join("   "));

    var idannotation = stringIDToTypeID( "annotation" );

    desc58.putObject( idT, idannotation, desc59 );

executeAction( idsetd, desc58, DialogModes.NO );

 Here is what I have so far. Right now, it stops at  

activeLayers.forEach(layer => { because the code I wrote for this I wrote in a plugin and it doesn't work when I just run it as a script. Any documentation on how scripting for photoshop differs as straight script vs script in a plugin would be helpful to me. I know it's messy and incomplete but that's where I'm at, thanks for checking 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