Skip to main content
Participant
May 20, 2021
Beantwortet

Photoshop script to invert curves

  • May 20, 2021
  • 1 Antwort
  • 4902 Ansichten

I want to create a script that will invert/swap the input and output values of all the points in each channel of a selected curves adjustment layer.

 

For example, the script should turn this curve:

 

 

into this:


 

This adjustment should be applied to all channels in the curves (RGB, Red, Green, Blue) and to all existing points. I don't have a lot of experience with photoshop scripting but i tried to write it myself and i couldn't figure out where photoshop stores the existing point input and output values. Any help would be appreciated.

Dieses Thema wurde für Antworten geschlossen.
Beste Antwort von r-bin
var raw = get_prop_value("layer", null, "adjustment", 0, "legacyContentData");

var d = get_curves_desc(raw);

edit_adjustment_layer("curves", d, false);

////////////////////////////////////////////////////////////////////////////////////////////
function edit_adjustment_layer(type, data, dlg)
    {
    try { 
        if (type == null || type == undefined) type = get_prop_value("layer", null, "adjustment").getClass(0);

        if (typeof(type) == "string") type = (type.length==4)?charIDToTypeID(type):stringIDToTypeID(type);

        var d = new ActionDescriptor();
        var r = new ActionReference();
        r.putEnumerated(stringIDToTypeID("adjustmentLayer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        d.putReference(stringIDToTypeID("null"), r);

        if (data == null || data == undefined) data = new ActionDescriptor();

        d.putObject(stringIDToTypeID("to"), type, data);
    
        var ret = executeAction(stringIDToTypeID("set"), d, dlg==false?DialogModes.NO:DialogModes.ALL);

        if (ret.hasKey(stringIDToTypeID("to"))) 
            ret = ret.getObjectValue(stringIDToTypeID("to"));
        else 
            ret = null;

        return ret;
        }
    catch (e) { alert(e); return null; }
    }

////////////////////////////////////////////////////////////////////////////////////////////
function get_prop_value(class_key, id, prop_key)
    {
    try
        {
        if (typeof(class_key) == "string") class_key = stringIDToTypeID(class_key);
        if (typeof(prop_key)  == "string") prop_key  = stringIDToTypeID(prop_key);

        var r = new ActionReference();    

        if (prop_key != undefined) r.putProperty(stringIDToTypeID("property"), prop_key);

        if (id == undefined || id == null) r.putEnumerated(class_key, stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        else if (typeof(id) == "string")   r.putName(class_key, id);
        else                               r.putIdentifier(class_key, id);

        var desc;

        if (prop_key == undefined)
            {
            try { return executeActionGet(r); } catch (e) { return undefined; }
            }

        try { desc = executeActionGet(r); } catch (e) { return undefined; }     

        if (!desc.hasKey(prop_key)) return undefined;

        var ret = get_value(desc, prop_key);

        for (var i = 3; i < arguments.length; i++) 
            if (arguments[i] != undefined) ret = get_value(ret, arguments[i]);  

        return ret;

        function get_type(obj, key)
            {
            try 
                {
                if (obj == undefined) return undefined;            

                if (typeof(key) == "string") key = stringIDToTypeID(key);
        
                switch (obj.typename)
                    {
                    case "ActionDescriptor":  
                    case "ActionList"      : return obj.getType(key);
        
                    case "ActionReference" : return obj.getForm();
                    }
                }
            catch (e) { throw(e); }
            }
        
        function get_value(obj, key)
            {
            try 
                {
                if (obj == undefined) return undefined;            

                if (typeof(key) == "string") key = stringIDToTypeID(key);
        
                switch (obj.typename)
                    {
                    case "ActionDescriptor":  
                    case "ActionList"      : return get_desc_value(obj, key);
        
                    case "ActionReference" : return get_ref_value(obj);
                    }
                }
            catch (e) { throw(e); }
            }
        
        function get_desc_value(d, key)
            {
            try 
                {
                if (d == undefined) return undefined;            

                if (typeof(key) == "string") key = stringIDToTypeID(key);
        
                var val; 

                if (d instanceof ActionDescriptor && !d.hasKey(key)) return undefined;

                else if (d instanceof ActionList && key >= d.count) return undefined;

                var type = d.getType(key);
        
                switch (type) 
                    {
                    case DescValueType.ALIASTYPE:        val = d.getPath(key);             break;
                    case DescValueType.BOOLEANTYPE:      val = d.getBoolean(key);          break;
                    case DescValueType.CLASSTYPE:        val = d.getClass(key);            break;
                    case DescValueType.DOUBLETYPE:       val = d.getDouble(key);           break;  
                    case DescValueType.INTEGERTYPE:      val = d.getInteger(key);          break;
                    case DescValueType.LISTTYPE:         val = d.getList(key);             break;
                    case DescValueType.RAWTYPE:          val = d.getData(key);             break;
                    case DescValueType.STRINGTYPE:       val = d.getString(key);           break;
                    case DescValueType.LARGEINTEGERTYPE: val = d.getLargeInteger(key);     break;
                    case DescValueType.REFERENCETYPE:    val = d.getReference(key);        break;
                    case DescValueType.OBJECTTYPE:       val = d.getObjectValue(key);      break;
                    case DescValueType.UNITDOUBLE:       val = d.getUnitDoubleValue(key);  break;
                    case DescValueType.ENUMERATEDTYPE:   val = d.getEnumerationValue(key); break;
                    }
        
                return val;
                }
            catch (e) { throw(e); }
            }
        
        function get_ref_value(r)
            {
            try 
                {
                var val; 
        
                switch (r.getForm())
                    {
                    case ReferenceFormType.CLASSTYPE:  val = r.getDesiredClass();    break;
                    case ReferenceFormType.IDENTIFIER: val = r.getIdentifier();      break;
                    case ReferenceFormType.INDEX:      val = r.getIndex();           break;
                    case ReferenceFormType.NAME:       val = r.getName();            break;
                    case ReferenceFormType.OFFSET:     val = r.getOffset();          break;
                    case ReferenceFormType.ENUMERATED: val = r.getEnumeratedValue(); break;
                    case ReferenceFormType.PROPERTY:   val = r.getProperty();        break;  
                    }
        
                return val;
                }
            catch (e) { throw(e); }
            }
        }   
    catch (e) { throw(e); }
    }

////////////////////////////////////////////////////////////////////////////////////////////
function get_curves_desc(raw)
    {
    try {
        var channels = new Array();

        var type = raw.charCodeAt(0)?"mapping":"curve";

        var ch_bit = raw.charCodeAt(6);

        if (type == "curve")
            {
            var off = 7;

            for (var i = 0; i < 5; i++) 
                {
                if (ch_bit & (1<<i)) 
                    {
                    var len = get_short(raw.substr(off));                
                    channels[i] = get_short(raw.substr(off+2), len*2);
                    off += len*4 + 2;
                    }
                }
            }
        else
            {
            var off = 7;

            for (var i = 0; i < 5; i++) 
                {
                if (ch_bit & (1<<i)) 
                    {
                    channels[i] = new Array();
                    for (var n = 0; n < 256; n++) channels[i].push(raw.charCodeAt(off+n));
                    off += 256;
                    }
                }
            }

        var d = new ActionDescriptor();
        var list = new ActionList();

        function set_chnl(name, m, type)
            {
            if (m == undefined || m == null) return;

            var d = new ActionDescriptor();
            var r = new ActionReference();
            r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID(name));
            d.putReference(stringIDToTypeID("channel"), r);

            var lst = new ActionList();

            if (type == "curve")
                {
                for (var i = 0; i < m.length; i+=2)
                    {
                    var d1 = new ActionDescriptor();

                    //d1.putDouble(stringIDToTypeID("horizontal"), m[i+1]);
                    //d1.putDouble(stringIDToTypeID("vertical"),   m[i]);

                    // SWAP X and Y for THIS CASE

                    d1.putDouble(stringIDToTypeID("horizontal"), m[i]);
                    d1.putDouble(stringIDToTypeID("vertical"),   m[i+1]);


                    lst.putObject(stringIDToTypeID("point"), d1);
                    }

                d.putList(stringIDToTypeID("curve"), lst);
                }
            else
                {
                for (var i = 0; i < m.length; i++)
                    {
                    lst.putInteger(m[i]); 
                    }

                d.putList(stringIDToTypeID("mapping"), lst);
                }

            list.putObject(stringIDToTypeID("curvesAdjustment"), d);
            }

        if (app.activeDocument.mode == DocumentMode.RGB)
            {         
            var ch_list = ["composite", "red", "green", "blue"];
    
            for (var i = 0; i < 4; i++) if (ch_bit & (1<<i)) set_chnl(ch_list[i], channels[i], type);    
            }
        else if (app.activeDocument.mode == DocumentMode.LAB)
            {               
            var ch_list = ["", "lightness", "a", "b"];

            for (var i = 0; i < 4; i++) if (ch_bit & (1<<i)) set_chnl(ch_list[i], channels[i], type);    
            }
        else if (app.activeDocument.mode == DocumentMode.CMYK)
            {               
            var ch_list = ["composite", "cyan", "magenta", "yellow", "black"];

            for (var i = 0; i < 5; i++) if (ch_bit & (1<<i)) set_chnl(ch_list[i], channels[i], type);    
            }
        else if (app.activeDocument.mode == DocumentMode.GRAYSCALE)
            {               
            if (ch_bit & 2) set_chnl("black", channels[1], type);
            }
        else if (app.activeDocument.mode == DocumentMode.DUOTONE)
            {               
            if (ch_bit & 2) set_chnl(app.activeDocument.componentChannels[0].name.toLowerCase(), channels[1], type);
            }
        else { alert("Unsupported color mode", "Error", true); return null; }

        d.putList(stringIDToTypeID("adjustment"), list);

        return d;
        } 
    catch (e) { throw(e); }
    }

////////////////////////////////////////////////////////////////////////////////////////////
function get_short(s, len)
    {
    try { 
        if (len == undefined) len = 1;

        var ret = [];

        for (var i = 0; i < 2*len; i += 2)
            {
            var c0 = s.charCodeAt(0+i);
            var c1 = s.charCodeAt(1+i);

            var val = c1 + 256*c0;
            
            if (c0 & 0x80) val = -(0xFFFF - val + 1);
            
            ret.push(val);
            }

        if (len == 1) return ret[0];

        return ret;
        }
    catch (e) { throw(e); }
    }

1 Antwort

r-binAntwort
Legend
May 20, 2021
var raw = get_prop_value("layer", null, "adjustment", 0, "legacyContentData");

var d = get_curves_desc(raw);

edit_adjustment_layer("curves", d, false);

////////////////////////////////////////////////////////////////////////////////////////////
function edit_adjustment_layer(type, data, dlg)
    {
    try { 
        if (type == null || type == undefined) type = get_prop_value("layer", null, "adjustment").getClass(0);

        if (typeof(type) == "string") type = (type.length==4)?charIDToTypeID(type):stringIDToTypeID(type);

        var d = new ActionDescriptor();
        var r = new ActionReference();
        r.putEnumerated(stringIDToTypeID("adjustmentLayer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        d.putReference(stringIDToTypeID("null"), r);

        if (data == null || data == undefined) data = new ActionDescriptor();

        d.putObject(stringIDToTypeID("to"), type, data);
    
        var ret = executeAction(stringIDToTypeID("set"), d, dlg==false?DialogModes.NO:DialogModes.ALL);

        if (ret.hasKey(stringIDToTypeID("to"))) 
            ret = ret.getObjectValue(stringIDToTypeID("to"));
        else 
            ret = null;

        return ret;
        }
    catch (e) { alert(e); return null; }
    }

////////////////////////////////////////////////////////////////////////////////////////////
function get_prop_value(class_key, id, prop_key)
    {
    try
        {
        if (typeof(class_key) == "string") class_key = stringIDToTypeID(class_key);
        if (typeof(prop_key)  == "string") prop_key  = stringIDToTypeID(prop_key);

        var r = new ActionReference();    

        if (prop_key != undefined) r.putProperty(stringIDToTypeID("property"), prop_key);

        if (id == undefined || id == null) r.putEnumerated(class_key, stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        else if (typeof(id) == "string")   r.putName(class_key, id);
        else                               r.putIdentifier(class_key, id);

        var desc;

        if (prop_key == undefined)
            {
            try { return executeActionGet(r); } catch (e) { return undefined; }
            }

        try { desc = executeActionGet(r); } catch (e) { return undefined; }     

        if (!desc.hasKey(prop_key)) return undefined;

        var ret = get_value(desc, prop_key);

        for (var i = 3; i < arguments.length; i++) 
            if (arguments[i] != undefined) ret = get_value(ret, arguments[i]);  

        return ret;

        function get_type(obj, key)
            {
            try 
                {
                if (obj == undefined) return undefined;            

                if (typeof(key) == "string") key = stringIDToTypeID(key);
        
                switch (obj.typename)
                    {
                    case "ActionDescriptor":  
                    case "ActionList"      : return obj.getType(key);
        
                    case "ActionReference" : return obj.getForm();
                    }
                }
            catch (e) { throw(e); }
            }
        
        function get_value(obj, key)
            {
            try 
                {
                if (obj == undefined) return undefined;            

                if (typeof(key) == "string") key = stringIDToTypeID(key);
        
                switch (obj.typename)
                    {
                    case "ActionDescriptor":  
                    case "ActionList"      : return get_desc_value(obj, key);
        
                    case "ActionReference" : return get_ref_value(obj);
                    }
                }
            catch (e) { throw(e); }
            }
        
        function get_desc_value(d, key)
            {
            try 
                {
                if (d == undefined) return undefined;            

                if (typeof(key) == "string") key = stringIDToTypeID(key);
        
                var val; 

                if (d instanceof ActionDescriptor && !d.hasKey(key)) return undefined;

                else if (d instanceof ActionList && key >= d.count) return undefined;

                var type = d.getType(key);
        
                switch (type) 
                    {
                    case DescValueType.ALIASTYPE:        val = d.getPath(key);             break;
                    case DescValueType.BOOLEANTYPE:      val = d.getBoolean(key);          break;
                    case DescValueType.CLASSTYPE:        val = d.getClass(key);            break;
                    case DescValueType.DOUBLETYPE:       val = d.getDouble(key);           break;  
                    case DescValueType.INTEGERTYPE:      val = d.getInteger(key);          break;
                    case DescValueType.LISTTYPE:         val = d.getList(key);             break;
                    case DescValueType.RAWTYPE:          val = d.getData(key);             break;
                    case DescValueType.STRINGTYPE:       val = d.getString(key);           break;
                    case DescValueType.LARGEINTEGERTYPE: val = d.getLargeInteger(key);     break;
                    case DescValueType.REFERENCETYPE:    val = d.getReference(key);        break;
                    case DescValueType.OBJECTTYPE:       val = d.getObjectValue(key);      break;
                    case DescValueType.UNITDOUBLE:       val = d.getUnitDoubleValue(key);  break;
                    case DescValueType.ENUMERATEDTYPE:   val = d.getEnumerationValue(key); break;
                    }
        
                return val;
                }
            catch (e) { throw(e); }
            }
        
        function get_ref_value(r)
            {
            try 
                {
                var val; 
        
                switch (r.getForm())
                    {
                    case ReferenceFormType.CLASSTYPE:  val = r.getDesiredClass();    break;
                    case ReferenceFormType.IDENTIFIER: val = r.getIdentifier();      break;
                    case ReferenceFormType.INDEX:      val = r.getIndex();           break;
                    case ReferenceFormType.NAME:       val = r.getName();            break;
                    case ReferenceFormType.OFFSET:     val = r.getOffset();          break;
                    case ReferenceFormType.ENUMERATED: val = r.getEnumeratedValue(); break;
                    case ReferenceFormType.PROPERTY:   val = r.getProperty();        break;  
                    }
        
                return val;
                }
            catch (e) { throw(e); }
            }
        }   
    catch (e) { throw(e); }
    }

////////////////////////////////////////////////////////////////////////////////////////////
function get_curves_desc(raw)
    {
    try {
        var channels = new Array();

        var type = raw.charCodeAt(0)?"mapping":"curve";

        var ch_bit = raw.charCodeAt(6);

        if (type == "curve")
            {
            var off = 7;

            for (var i = 0; i < 5; i++) 
                {
                if (ch_bit & (1<<i)) 
                    {
                    var len = get_short(raw.substr(off));                
                    channels[i] = get_short(raw.substr(off+2), len*2);
                    off += len*4 + 2;
                    }
                }
            }
        else
            {
            var off = 7;

            for (var i = 0; i < 5; i++) 
                {
                if (ch_bit & (1<<i)) 
                    {
                    channels[i] = new Array();
                    for (var n = 0; n < 256; n++) channels[i].push(raw.charCodeAt(off+n));
                    off += 256;
                    }
                }
            }

        var d = new ActionDescriptor();
        var list = new ActionList();

        function set_chnl(name, m, type)
            {
            if (m == undefined || m == null) return;

            var d = new ActionDescriptor();
            var r = new ActionReference();
            r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID(name));
            d.putReference(stringIDToTypeID("channel"), r);

            var lst = new ActionList();

            if (type == "curve")
                {
                for (var i = 0; i < m.length; i+=2)
                    {
                    var d1 = new ActionDescriptor();

                    //d1.putDouble(stringIDToTypeID("horizontal"), m[i+1]);
                    //d1.putDouble(stringIDToTypeID("vertical"),   m[i]);

                    // SWAP X and Y for THIS CASE

                    d1.putDouble(stringIDToTypeID("horizontal"), m[i]);
                    d1.putDouble(stringIDToTypeID("vertical"),   m[i+1]);


                    lst.putObject(stringIDToTypeID("point"), d1);
                    }

                d.putList(stringIDToTypeID("curve"), lst);
                }
            else
                {
                for (var i = 0; i < m.length; i++)
                    {
                    lst.putInteger(m[i]); 
                    }

                d.putList(stringIDToTypeID("mapping"), lst);
                }

            list.putObject(stringIDToTypeID("curvesAdjustment"), d);
            }

        if (app.activeDocument.mode == DocumentMode.RGB)
            {         
            var ch_list = ["composite", "red", "green", "blue"];
    
            for (var i = 0; i < 4; i++) if (ch_bit & (1<<i)) set_chnl(ch_list[i], channels[i], type);    
            }
        else if (app.activeDocument.mode == DocumentMode.LAB)
            {               
            var ch_list = ["", "lightness", "a", "b"];

            for (var i = 0; i < 4; i++) if (ch_bit & (1<<i)) set_chnl(ch_list[i], channels[i], type);    
            }
        else if (app.activeDocument.mode == DocumentMode.CMYK)
            {               
            var ch_list = ["composite", "cyan", "magenta", "yellow", "black"];

            for (var i = 0; i < 5; i++) if (ch_bit & (1<<i)) set_chnl(ch_list[i], channels[i], type);    
            }
        else if (app.activeDocument.mode == DocumentMode.GRAYSCALE)
            {               
            if (ch_bit & 2) set_chnl("black", channels[1], type);
            }
        else if (app.activeDocument.mode == DocumentMode.DUOTONE)
            {               
            if (ch_bit & 2) set_chnl(app.activeDocument.componentChannels[0].name.toLowerCase(), channels[1], type);
            }
        else { alert("Unsupported color mode", "Error", true); return null; }

        d.putList(stringIDToTypeID("adjustment"), list);

        return d;
        } 
    catch (e) { throw(e); }
    }

////////////////////////////////////////////////////////////////////////////////////////////
function get_short(s, len)
    {
    try { 
        if (len == undefined) len = 1;

        var ret = [];

        for (var i = 0; i < 2*len; i += 2)
            {
            var c0 = s.charCodeAt(0+i);
            var c1 = s.charCodeAt(1+i);

            var val = c1 + 256*c0;
            
            if (c0 & 0x80) val = -(0xFFFF - val + 1);
            
            ret.push(val);
            }

        if (len == 1) return ret[0];

        return ret;
        }
    catch (e) { throw(e); }
    }

UNFOTONY
Known Participant
July 20, 2023

This script worked fine in Photoshop 2020, but now in Photoshop Beta it gives an error. Tell me, please, how can I fix it?

 

Legend
July 20, 2023
Change the code on line 289
catch(e) { throw(e); }
with
catch (e) { alert(e.line + "\n\n" + e); throw(e); }
 
And show a screenshot of the error message. I have no way to test on newer versions.