Skip to main content
Participating Frequently
October 8, 2013
Answered

How to change the angle of a gradient layer without changing anything else?

  • October 8, 2013
  • 2 replies
  • 1588 views

How to change the angle of a gradient layer without changing anything else?

When I try it myself my whole gradient turns black.

This topic has been closed for replies.
Correct answer Michael_L_Hale

To add to the above, you can not just set the angle. If you want to use other existing settings you need to get them from the layer. The code in that other thread shows one way to get them.

But if you do not need the existing values for any other reason you can get the descriptor for the layer, make a duplicate of it with all the settings and just overwrite the ones you want to change.

This is one way to just change the angle while keeping the other existing settings.

// helper function for working with descriptors

function getProperty( psClass, psKey, index ){// integer:Class, integer:key

    var ref = new ActionReference();

    if( psKey != undefined ) ref.putProperty( charIDToTypeID( "Prpr" ), psKey );

    if(index != undefined ){

        ref.putIndex( psClass, index );

    }else{

        ref.putEnumerated( psClass , charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );

    }

    try{

        var desc = executeActionGet(ref);

    }catch(e){ return; }// return on error

    if(desc.count == 0) return;// return undefined if property doesn't exists

    var dataType = desc.getType(psKey);

    switch(dataType){// not all types supported - returns undefined if not supported

        case DescValueType.INTEGERTYPE:

            return desc.getInteger(psKey);

            break;

        case DescValueType.ALIASTYPE:

            return desc.getPath(psKey);

            break;

        case DescValueType.BOOLEANTYPE:

            return desc.getBoolean(psKey);

            break;

        case DescValueType.BOOLEANTYPE:

            return desc.getBoolean(psKey);

            break;

        case DescValueType.UNITDOUBLE:

            return desc.getUnitDoubleValue(psKey);

            break;

        case DescValueType.STRINGTYPE:

            return desc.getString(psKey);

            break;

        case  DescValueType.OBJECTTYPE:

            return desc.getObjectValue(psKey);

            break;

        case  DescValueType.LISTTYPE:

            return desc.getList(psKey);

            break;

        case  DescValueType.ENUMERATEDTYPE:

            return desc.getEnumerationValue(psKey);

            break;

    }

};

function duplicateDescriptor( descriptor ) {

    var newDescriptor = new ActionDescriptor;

    newDescriptor.fromStream( descriptor.toStream() );

    return newDescriptor;

};

function localizeDescriptor( desc ) {

    var stream, pointer, zStringLength, zstring, localized_string, newZStringLength, previousStream, followingStream, newDesc;

    stream = desc.toStream();

    while( true ) {

        pointer = stream.search(/TEXT....\x00\$\x00\$\x00\$/);

        if( pointer === -1 ) {

            break;

        }

        zStringLength = getLongFromStream( stream, pointer + 4 );

        zstring = readUnicode( stream.substr( pointer + 8, ( zStringLength - 1 ) * 2) );

        localized_string = ( localize( zstring ) ) + '\u0000';

        newZStringLength = localized_string.length;

        previousStream = stream.slice( 0, pointer);

        followingStream = stream.slice( pointer + 8 + zStringLength * 2);

        stream = previousStream.concat( 'TEXT', longToString( newZStringLength ), bytesToUnicode( localized_string ), followingStream );

    }

    newDesc = new ActionDescriptor();

    newDesc.fromStream( stream );

    return newDesc;

};

function getShortFromStream( stream, pointer ) {

    var hi, low;

    hi = stream.charCodeAt( pointer ) << 8 ;

    low = stream.charCodeAt( pointer + 1 );

    return hi + low;

};

function getLongFromStream( stream, pointer ) {

    var hi, low;

    hi = getShortFromStream( stream, pointer) << 16;

    low = getShortFromStream( stream, pointer + 2);

    return hi + low;

};

function readUnicode( unicode ) {

    var string = "";

    for( i = pointer = 0; pointer < unicode.length; i = pointer += 2) {

        string +=String.fromCharCode( getShortFromStream( unicode, pointer ) );

    }

    return string;

};

function longToString( longInteger ) {

    var string;

    string = String.fromCharCode( longInteger >>> 24 );

    string += String.fromCharCode( longInteger << 8 >>> 24 );

    string += String.fromCharCode( longInteger << 16 >>> 24 );

    string += String.fromCharCode( longInteger << 24 >>> 24 );

    return string;

};

function bytesToUnicode( bytes ) {

    var unicode = "", char_code, charIndex;

    for( charIndex  = 0; charIndex < bytes.length; charIndex ++ ) {

        char_code = bytes.charCodeAt( charIndex );

        unicode += String.fromCharCode(char_code >> 8 ) +  String.fromCharCode( char_code & 0xff );

    }

    return unicode;

};

function setGradientAdjustmentAngle( angle ) {

    var adjustmentDesc = getProperty( charIDToTypeID("Lyr "), charIDToTypeID( 'Adjs' ) ).getObjectValue(0);

    var newAdjustmentDesc = duplicateDescriptor( adjustmentDesc );

    newAdjustmentDesc.putUnitDouble( charIDToTypeID('Angl'), charIDToTypeID('#Ang'), angle );

   

    var desc = new ActionDescriptor();

        var ref = new ActionReference();

        ref.putEnumerated( stringIDToTypeID('contentLayer'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );

    desc.putReference( charIDToTypeID('null'), ref );

    desc.putObject( charIDToTypeID('T   '), stringIDToTypeID('gradientLayer'), newAdjustmentDesc);

    executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );

};

var newAngle = 45;

setGradientAdjustmentAngle( newAngle );

2 replies

Michael_L_HaleCorrect answer
Inspiring
October 9, 2013

To add to the above, you can not just set the angle. If you want to use other existing settings you need to get them from the layer. The code in that other thread shows one way to get them.

But if you do not need the existing values for any other reason you can get the descriptor for the layer, make a duplicate of it with all the settings and just overwrite the ones you want to change.

This is one way to just change the angle while keeping the other existing settings.

// helper function for working with descriptors

function getProperty( psClass, psKey, index ){// integer:Class, integer:key

    var ref = new ActionReference();

    if( psKey != undefined ) ref.putProperty( charIDToTypeID( "Prpr" ), psKey );

    if(index != undefined ){

        ref.putIndex( psClass, index );

    }else{

        ref.putEnumerated( psClass , charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );

    }

    try{

        var desc = executeActionGet(ref);

    }catch(e){ return; }// return on error

    if(desc.count == 0) return;// return undefined if property doesn't exists

    var dataType = desc.getType(psKey);

    switch(dataType){// not all types supported - returns undefined if not supported

        case DescValueType.INTEGERTYPE:

            return desc.getInteger(psKey);

            break;

        case DescValueType.ALIASTYPE:

            return desc.getPath(psKey);

            break;

        case DescValueType.BOOLEANTYPE:

            return desc.getBoolean(psKey);

            break;

        case DescValueType.BOOLEANTYPE:

            return desc.getBoolean(psKey);

            break;

        case DescValueType.UNITDOUBLE:

            return desc.getUnitDoubleValue(psKey);

            break;

        case DescValueType.STRINGTYPE:

            return desc.getString(psKey);

            break;

        case  DescValueType.OBJECTTYPE:

            return desc.getObjectValue(psKey);

            break;

        case  DescValueType.LISTTYPE:

            return desc.getList(psKey);

            break;

        case  DescValueType.ENUMERATEDTYPE:

            return desc.getEnumerationValue(psKey);

            break;

    }

};

function duplicateDescriptor( descriptor ) {

    var newDescriptor = new ActionDescriptor;

    newDescriptor.fromStream( descriptor.toStream() );

    return newDescriptor;

};

function localizeDescriptor( desc ) {

    var stream, pointer, zStringLength, zstring, localized_string, newZStringLength, previousStream, followingStream, newDesc;

    stream = desc.toStream();

    while( true ) {

        pointer = stream.search(/TEXT....\x00\$\x00\$\x00\$/);

        if( pointer === -1 ) {

            break;

        }

        zStringLength = getLongFromStream( stream, pointer + 4 );

        zstring = readUnicode( stream.substr( pointer + 8, ( zStringLength - 1 ) * 2) );

        localized_string = ( localize( zstring ) ) + '\u0000';

        newZStringLength = localized_string.length;

        previousStream = stream.slice( 0, pointer);

        followingStream = stream.slice( pointer + 8 + zStringLength * 2);

        stream = previousStream.concat( 'TEXT', longToString( newZStringLength ), bytesToUnicode( localized_string ), followingStream );

    }

    newDesc = new ActionDescriptor();

    newDesc.fromStream( stream );

    return newDesc;

};

function getShortFromStream( stream, pointer ) {

    var hi, low;

    hi = stream.charCodeAt( pointer ) << 8 ;

    low = stream.charCodeAt( pointer + 1 );

    return hi + low;

};

function getLongFromStream( stream, pointer ) {

    var hi, low;

    hi = getShortFromStream( stream, pointer) << 16;

    low = getShortFromStream( stream, pointer + 2);

    return hi + low;

};

function readUnicode( unicode ) {

    var string = "";

    for( i = pointer = 0; pointer < unicode.length; i = pointer += 2) {

        string +=String.fromCharCode( getShortFromStream( unicode, pointer ) );

    }

    return string;

};

function longToString( longInteger ) {

    var string;

    string = String.fromCharCode( longInteger >>> 24 );

    string += String.fromCharCode( longInteger << 8 >>> 24 );

    string += String.fromCharCode( longInteger << 16 >>> 24 );

    string += String.fromCharCode( longInteger << 24 >>> 24 );

    return string;

};

function bytesToUnicode( bytes ) {

    var unicode = "", char_code, charIndex;

    for( charIndex  = 0; charIndex < bytes.length; charIndex ++ ) {

        char_code = bytes.charCodeAt( charIndex );

        unicode += String.fromCharCode(char_code >> 8 ) +  String.fromCharCode( char_code & 0xff );

    }

    return unicode;

};

function setGradientAdjustmentAngle( angle ) {

    var adjustmentDesc = getProperty( charIDToTypeID("Lyr "), charIDToTypeID( 'Adjs' ) ).getObjectValue(0);

    var newAdjustmentDesc = duplicateDescriptor( adjustmentDesc );

    newAdjustmentDesc.putUnitDouble( charIDToTypeID('Angl'), charIDToTypeID('#Ang'), angle );

   

    var desc = new ActionDescriptor();

        var ref = new ActionReference();

        ref.putEnumerated( stringIDToTypeID('contentLayer'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );

    desc.putReference( charIDToTypeID('null'), ref );

    desc.putObject( charIDToTypeID('T   '), stringIDToTypeID('gradientLayer'), newAdjustmentDesc);

    executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );

};

var newAngle = 45;

setGradientAdjustmentAngle( newAngle );

c.pfaffenbichler
Community Expert
Community Expert
October 9, 2013

Did you include the »Align with layer« setting?

Edit: Excuse me, I see your new code is very much different from the one in the old thread.

c.pfaffenbichler
Community Expert
Community Expert
October 8, 2013
Participating Frequently
October 8, 2013

How exactly could I use this?

c.pfaffenbichler
Community Expert
Community Expert
October 9, 2013

If you want to add to the current gradient angle you could use Mike Hale’s code and instead of »45« use something like this (the function is lifted from Mike’s code).

var newAngle = getGradientAngle()+10;

function getGradientAngle(){

    if(app.documents.length==0 || app.activeDocument.activeLayer.kind != LayerKind.GRADIENTFILL ) return;

    var ref = new ActionReference();

    ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );

    var desc = executeActionGet(ref).getList(charIDToTypeID("Adjs")).getObjectValue(0);

    if(desc.hasKey(charIDToTypeID("Angl"))) theAngle = desc.getDouble(charIDToTypeID("Angl"));

    return theAngle;

};