PS Script to switch Content-Aware vs Proximity Match in Spot Heal Tool and Patch tool question

Explorer ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

I wrote a script to switch source sampling type for spot healing tool and patch tool between content-aware and proximity match.
It does switch the setting, but for some reason also turns on scattering for those tools.
And if i write a script that switches some tool setting the same way it switches some other stuff as well.
It's not visible on other tools, but spot healing tool.
I can add a line to set scattering to off manually, but i'd rather know why it happens and how to avoid it.
So what am i doing wrong here?

function checkCTOoption(charString){
    var ref = new ActionReference();
        ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("tool"));
        ref.putEnumerated(stringIDToTypeID("application"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
    if (app.currentTool=="spotHealingBrushTool"){
        return executeActionGet(ref).getObjectValue(stringIDToTypeID("currentToolOptions")).getEnumerationValue(charIDToTypeID(charString));
    } else if ( app.currentTool=="patchSelection" ){
        return executeActionGet(ref).getObjectValue(stringIDToTypeID("currentToolOptions")).getBoolean(stringIDToTypeID(charString));
    } else {}
}
// get current tool options object
function getCTO(){
    var ref = new ActionReference();
        ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("tool"));
        ref.putEnumerated(stringIDToTypeID("application"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        return executeActionGet(ref).getObjectValue(stringIDToTypeID("currentToolOptions"));
}
// setting currentToolOptions with options array
function setCTO( options ){
    var desc = new ActionDescriptor();
        var ref = new ActionReference();
            ref.putClass( stringIDToTypeID( app.currentTool ) );
        desc.putReference( stringIDToTypeID( "target" ), ref );
        // getting current tool options
        var ctoObj = getCTO();
            if ( app.currentTool=="spotHealingBrushTool" ){
                ctoObj.putEnumerated( charIDToTypeID( options[0] ), charIDToTypeID( "SmmT" ), charIDToTypeID( options[1] ) );
            } else if ( app.currentTool=="patchSelection" ) {
                ctoObj.putBoolean( stringIDToTypeID( options[0] ), options[1] );
            } else {}
            // fix i need to add cause it turnes on by itself for some reason:
            // ctoObj.putBoolean( stringIDToTypeID( "useScatter" ), false ); 
        desc.putObject( stringIDToTypeID( "to" ), stringIDToTypeID( "currentToolOptions" ), ctoObj );
    executeAction( stringIDToTypeID( "set" ), desc, DialogModes.NO );
}
// switching currentToolOptions if it's one of the tools, ignoring otherwise
function switchCTO (){
    if ( app.currentTool=="spotHealingBrushTool" ){
        if ( checkCTOoption("SmmS")==(charIDToTypeID("CntW")) ){
            setCTO( ["SmmS","PrxM"] );
        } else {
            setCTO( ["SmmS","CntW"] );
        }
    }
    else if ( app.currentTool=="patchSelection" ){
        if ( checkCTOoption("contentAware", true)==false ){
            setCTO( ["contentAware", true] );
        } else {
            setCTO( ["contentAware", false] );
        }
    }
    else {
        // if other tools, do nothing
    }
}
switchCTO();
TOPICS
Actions and scripting

Views

288

Likes

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

Adobe Community Professional , Oct 19, 2021 Oct 19, 2021
A workaround is to check if the tool has the "useScatter" and "brush" parameters. If there is no "useScatter", but there is a "brush," then it is one of the painting tools potentially affected by this bug. You can safely write useScatter = false to its descriptor and everything will be fine. You can delete that topic in the "bugs" section and put this one there. Although I tried to describe the problem there in as much detail as possible (as @r-bin noticed, it concerns not only scripts, but al...

Likes

Translate

Translate
Adobe Community Professional ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

I have met such a problem. Now, not at the computer, to remember what I did in the end, but, it seems, I just saved descriptor with all the tool settings to a variable, changed a separate parameter inside this desc, then assigned it (with all the settings) to the tool.

Likes

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
Explorer ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

Well, i kinda do the same thing with 

 

var ctoObj = getCTO();
ctoObj.put...

 

but the problem here is - Spot Healing Tool doesn't have scattering setting, and the currentToolOptions actionDescriptor i am getting with that function should not have it either.
So scattering must be added there from somewhere else and i have no idea where, cause i have it turned off on every tool and i have no tool presets with it.
I will try to log that descriptor and read through it to see what it actually has inside.
Really strange stuff.

 

 

Just logged the Descriptor that is getting sent to executeAction set function and it does not have scattering, but when action executes, it's (scattering) turned on under the hood, but still no sign of it in the currentToolOptions descriptor.
I am logging full descriptor into a txt file with everything inside (apart from raw data and file path that can be there), so if it's there somewhere, i have no idea where.
Once i manually add scattering = false, all works fine, but it's not a good solution cause there might be other stuff turned on or off as well that i can't see and i don't want anything random there.

Likes

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 Community Professional ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

I found my script. There is the same problem. I have not been able to solve it. The most interesting thing is that if you change the tool settings once, then scattering stays with it forever (until you manually assign useScatter = false). It looks like a bug.

Likes

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
Explorer ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

Thanks. I guess, we should be the ones who solve it 😄

Likes

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 Community Professional ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

for jazz-y

 

Привет. Только что заметил, что ты ACP-шник. Поздравляю!

useScatter = false -это вообще где? В упор не нашёл.

 

Можете смело оформлять как баг, т.к. не работают пресеты для спотхелинг бращ, т.е. они тупо всключают эту фигню. Проверял на 2018. Кстати, на CS6 такой ерунды с пресетами нет, но там, правда, и тулз опшин менять нельзя скриптами.

Likes

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 Community Professional ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

Так в том-то и прикол, что этой опции нет в настройках инструмента. Видимо при записи используется какой-то прототип объекта в котором она есть (как и у большинства других инструментов рисования).

 

#target photoshop
s2t = stringIDToTypeID;

var r = new ActionReference();
r.putProperty(s2t("property"), s2t("tool"));
r.putEnumerated(s2t("application"), s2t("ordinal"), s2t("targetEnum"));
var d = executeActionGet(r).getObjectValue(s2t("currentToolOptions"));

try { d.getBoolean(s2t('useScatter')) } catch (e) { alert(e) } // error

d.putBoolean(s2t('useScatter'), false) //but we can put it in desc

var d1 = new ActionDescriptor(),
    r = new ActionReference();
r.putClass(s2t(app.currentTool));
d1.putReference(s2t("target"), r);
d1.putObject(s2t("to"), s2t("currentToolOptions"), d);
executeAction(s2t("set"), d1, DialogModes.NO);

 

Проблема есть как минимум у двух инструментов: spotHealingBrushTool и colorReplacementBrushTool. Также есть backgroundEraserTool или artBrushTool, у которых в опциях тоже нет useScatter, но проверить ее влияние сложно (в силу особенностей работы инструмента).

 

Bug: spotHealingBrushTool: when the tool preset is activated, useScattering is enabled

Likes

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
Explorer ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

@jazz-y и от меня поздравления с ACP титулом 😄

Likes

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
Explorer ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

@r-bin @jazz-y если знаете как, можете попробовать через batchPlay это проделать?
Оно также будет себя вести или вдруг правильно?
А то я пока не умею.
Спасибо 🙂

Likes

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 Community Professional ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

Проблема в том как ведёт себя сам объект, а не в коде который его модифицирует.

Батч плей и AM - это просто два разных способа доступа к одним и тем же объектам. Т.е разницы не будет.

Пока в UXP нет всего того, что я люблю в ExtendScript (хоткеи, запись в экшены и т.п.) особо ковыряться в нем желания нет.

Likes

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
Explorer ,
Oct 18, 2021 Oct 18, 2021

Copy link to clipboard

Copied

но тут может быть как в той сценке с лифтом, который управляется голосом - на AM он фигню творит, а на батчПлей сделает что нужно.

Likes

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 Community Professional ,
Oct 19, 2021 Oct 19, 2021

Copy link to clipboard

Copied

Нет. Всё то же самое. Проверил.

 

const app = window.require("photoshop").app;
const batchPlay = window.require("photoshop").action.batchPlay;

const currentOptions = batchPlay([{
  _obj: 'get',
  _target: [{
    _property: 'tool'
  },
  {
    _ref: 'application',
    _enum: 'ordinal',
    _value: 'targetEnum'
  }
  ]
}],
  { synchronousExecution: true }
)[0].currentToolOptions

batchPlay([{
  _obj: 'set',
  _target:
  {
    _ref: app.currentTool.id
  },
  to:
    currentOptions
}], {})

 

 

 

 

2021-10-19_13-04-14.png
П.С. с получением и изменением параметров через batchPlay всё понятно и удобно (функция возвращает обычный js объект), а вот при назначении параметров пришлось прибегнуть к помощи forums.creativeclouddeveloper.com - структура объектов и порядок написания аргументов отличаются от аналогичных функций на AM. Подозреваю, что batchPlay в UXP ждет примерно та же участь, что и AM в ExtendSdcript - три абзаца в документации, разбирайтесь как хотите.

Likes

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
Explorer ,
Oct 19, 2021 Oct 19, 2021

Copy link to clipboard

Copied

Ну, Davide Barranca сделал десяток видео по UXP. Может в итоге и курс сделает.
А с Alchemist от Ярослава Берёзы код получать несложно. Хотя и нужно понимать структуру этого всего.
я скрипт написал, который логит Application, ActiveDocument, ActiveLayer и CurrentToolOptions и там много всего можно почитать, но всё же, официального курса, а лучше стримов по этому всему нехватает.
Там диск нужно указать существующий, а дальше он сам, ну и можно другие объекты вытаскивать и отправлять функции что логит.
Там ещё нужно много всего дописывать, и может переписывать, но пока это в таком виде.
Я никаких комментариев не добавлял, кпотому что не закончил его, но может пригодится

/*
<javascriptresource>
<name>Get Descriptors</name>
<enableinfo>true</enableinfo>
<category>Hirlin Scripts</category>
</javascriptresource>
// Oleksii Hirlin 2021
*/
function getCTO(innerObj){
    var ref = new ActionReference();
        ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("tool"));
        ref.putEnumerated(stringIDToTypeID("application"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
    if (innerObj!=undefined){
        return executeActionGet(ref).getObjectValue(stringIDToTypeID("currentToolOptions")).getObjectValue(innerObj);
    } else {
        return executeActionGet(ref).getObjectValue(stringIDToTypeID("currentToolOptions"));
    }
}
function getApp(innerObj){
    var ref = new ActionReference();
    ref.putEnumerated(stringIDToTypeID("application"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
    if (innerObj!=undefined){
        return executeActionGet(ref).getObjectValue(innerObj);
    } else {
        return executeActionGet(ref);
    }
}
function getLyr(innerObj){
    var ref = new ActionReference();
    ref.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
    if (innerObj!=undefined){
        return executeActionGet(ref).getObjectValue(innerObj);
    } else {
        return executeActionGet(ref);
    }
}
function getDoc(innerObj){
    var ref = new ActionReference();
    ref.putEnumerated(stringIDToTypeID("document"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
    if (innerObj!=undefined){
        return executeActionGet(ref).getObjectValue(innerObj);
    } else {
        return executeActionGet(ref);
    }
}
var dateFolderName = Date.parse( new Date() );
function logObj ( desc, descName, parent, type, curFeatures ){
    eval( "var loggFolder = new Folder(\"s:/PhotoshopLog/" + dateFolderName + "\");" );
    loggFolder.create();
    eval( "var logg = new File(\"" + loggFolder.fullName + "/" + descName + ".txt\");" );
    // eval( "var logg = new File(\"s:/PhotoshopLog/" + Date.parse( new Date() ) + "/" + descName + ".txt\");" );
    logg.open("w");
    logg.write(descName + "\n" + type + "\t" + desc.count + "\n");
    if ( curFeatures!=undefined ) { logg.write(curFeatures + "\n"); } else { logg.write("\n"); }
    for (var i=0; i<desc.count; i++) {
        if ( type == "LIST") {
            var key_i = i;
        } else {
            var key_i = desc.getKey(i);
        }
        logg.write(i +"\t");
        //id number
        var keyIdNumber = key_i.toString();
        // while ( keyIdNumber.length<10 ) {keyIdNumber+=" ";};
        logg.write( keyIdNumber +"\t" );
        // type
        var typeOfKey = desc.getType( key_i ).toString().replace("DescValueType.", "").replace("TYPE","");
        var typeOfKey12 = typeOfKey;
        // while ( typeOfKey12.length<12 ) {typeOfKey12 += " ";};
        logg.write( typeOfKey12 + "\t" );
        if (type=="OBJECT"){
            // char
            var charId = typeIDToCharID ( key_i );
            logg.write( "c\"" + charId + "\"\t");
            if ( charId.length < 1 ){ charId = "~"; }
            // string
            var stringId = typeIDToStringID ( key_i );
            logg.write( "s\""+ stringId + "\"\t" );
            if ( stringId.length < 1 ){ stringId = "~"; }
        } else {}
        // data
        if ( typeOfKey == "BOOLEAN" ) { logg.write( "value[ " + desc.getBoolean( key_i ) + " ]"); }
        if ( typeOfKey == "CLASS" ) { logg.write( "value[ " + desc.getClass( key_i ) + " ]"); }
        if ( typeOfKey == "DOUBLE" ) { logg.write( "value[ " + desc.getDouble( key_i ) + " ]"); }
        if ( typeOfKey == "INTEGER" ) { logg.write( "value[ " + desc.getInteger( key_i ) + " ]"); }
        if ( typeOfKey == "STRING" ) { logg.write( "value[ " + desc.getString( key_i ) + " ]"); }
        if ( typeOfKey == "LARGEINTEGER" ) { logg.write("value[ " + desc.getLargeInteger( key_i ) + " ]"); }
        if ( typeOfKey == "RAW" ) { logg.write("data[ " + desc.getData( key_i ) + " ]"); }
        
        if ( typeOfKey == "ENUMERATED" ) { logg.write( "type[ c\"" + typeIDToCharID( desc.getEnumerationType( key_i ) ) + "\"\ts\""+ typeIDToStringID( desc.getEnumerationType( key_i ) ) + "\" ]\t"); }
        if ( typeOfKey == "ENUMERATED" ) { logg.write( "value[ c\"" + typeIDToCharID( desc.getEnumerationValue( key_i ) ) + "\"\ts\""+ typeIDToStringID( desc.getEnumerationValue( key_i ) ) + "\" ]"); }
        
        if ( typeOfKey == "UNITDOUBLE" ) { logg.write( "type[ c\"" + typeIDToCharID( desc.getUnitDoubleType( key_i ) ) + "\"\ts\""+ typeIDToStringID( desc.getUnitDoubleType( key_i ) ) + "\" ]\t"); }
        if ( typeOfKey == "UNITDOUBLE" ) { logg.write( "value[ " + desc.getUnitDoubleValue( key_i ) + " ]\""); }
        
        if ( typeOfKey == "OBJECT" ) { logg.write( "class[ c\"" + typeIDToCharID( desc.getObjectType( key_i ) )+"\"\ts\""+ typeIDToStringID( desc.getObjectType( key_i ) ) + "\" ]\t"); }
        if ( typeOfKey == "OBJECT" ) { logg.write( "type[ " + desc.getObjectValue( key_i ).typename + " ]"); }
        if ( typeOfKey == "OBJECT" ) {
            var logName = parent + "_" + typeOfKey + "[" + charId + "_" + stringId + "]";
            var curFeatures = "class[ c\"" + typeIDToCharID( desc.getObjectType( key_i ) ) + "\"\ts\"" + typeIDToStringID( desc.getObjectType( key_i ) ) + "\" ]";
            logObj( desc.getObjectValue( key_i ), logName, logName, typeOfKey, curFeatures );
        }
        
        if ( typeOfKey == "LIST" ) { logg.write( "type[ " + desc.getList( key_i ).typename + " ]" + "\t"); }
        if ( typeOfKey == "LIST" ) {
            var logName = parent + "_" + typeOfKey + "[" + charId + "_" + stringId + "]";
            logObj( desc.getList( key_i ), logName, logName, typeOfKey );
        }
        
        if ( typeOfKey == "REFERENCE" ) { logg.write( "type" + desc.getReference( key_i ) ); }
        // new line
        logg.write("\n");
    }
    logg.close();
}
function logList (){

}
logObj( getCTO(), "cto", "cto", "OBJECT" );
logObj( getDoc(), "actDoc", "actDoc", "OBJECT" );
logObj( getLyr(), "actLyr", "actLyr", "OBJECT" );
logObj( getApp(), "app", "app", "OBJECT" );

Likes

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 Community Professional ,
Oct 19, 2021 Oct 19, 2021

Copy link to clipboard

Copied

I wanted to move this thread to Bugs but then I thought maybe you'll show up and find some workaround. You came indeed 🙂 (Un)fortunately jazz-y already made a topic in bugs section.

Likes

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
Explorer ,
Oct 19, 2021 Oct 19, 2021

Copy link to clipboard

Copied

Why does reporting bugs feels to me like snitching on the programmers to their bosses? 😄 😄

Likes

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 Community Professional ,
Oct 19, 2021 Oct 19, 2021

Copy link to clipboard

Copied

A workaround is to check if the tool has the "useScatter" and "brush" parameters. If there is no "useScatter", but there is a "brush," then it is one of the painting tools potentially affected by this bug. You can safely write useScatter = false to its descriptor and everything will be fine.

You can delete that topic in the "bugs" section and put this one there. Although I tried to describe the problem there in as much detail as possible (as @r-bin noticed, it concerns not only scripts, but also presets, i.e. ordinary users also face it). I analyzed my old scripts and found I had this problem already. Previously, the bug was related to more tools. This has been fixed at the moment.

Likes

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 Community Professional ,
Oct 19, 2021 Oct 19, 2021

Copy link to clipboard

Copied

LATEST

In that other 'introduction' topic there's a link to this one, that's more descriptive.

Likes

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