Skip to main content
Participant
September 28, 2017
Question

Document saved property not updating when manipulating guides

  • September 28, 2017
  • 5 replies
  • 5665 views

I'm working on a script which among other things removes all guides in an image file. It's meant to run as a batch script, so for speed I don't want to save an image if I didn't actually removed anything.

I'm checking the saved property of the active document, but it doesn't seem to change when removing guides (or adding them). Doing this manually in Photoshop triggers a change in the value, but not when I script it. I'm also removing color samplers via the same script, and that changes the value of the saved property as expected.

The only option right now seems to be to save all images regardless of any change, but that will slow things down a lot. Does anyone know why manipulation of guides doesn't change the saved state?

app.open( new File( 'path/to/image' ) );

var theImg = app.activeDocument;

theImg.guides.removeAll();

if ( ! theImg.saved ) {

    theImg.save();

}

theImg.close();

This topic has been closed for replies.

5 replies

Kukurykus
Legend
March 18, 2018

Although Jarda BerezasuspendHistory() solution is functional I think correct would be to use r-bin Action Manager code. The question is why activeDocument.guides.removeAll() doesn't work for Photoshop same like clear_guides() function if we know DOM is based on AM code? My approach to problem (using AM code though) but with checking guides length:

if ((aD = activeDocument).guides.length) {

    function sTT(v) {return stringIDToTypeID(v)}

    (ref1 = new ActionReference()).putEnumerated

    (sTT('good'), sTT('ordinal'), sTT('allEnum'));

    (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)

    executeAction(sTT('delete'), dsc1, DialogModes.NO), aD.save()

}

aD.close()

Legend
March 18, 2018

Because in AM there is no code to delete one guide.

And the removeAl()l method for guides, as for many other collections, deletes the guides one by one.

Run the script. Then uncomment the clear_guides() and comment removeAll(). Compare the speed.

for (var i = 0; i < 100; i++)

  activeDocument.guides.add(Direction.HORIZONTAL, UnitValue(i, "px"))

activeDocument.guides.removeAll()

//clear_guides()                  

P.S. alert(get_prop_value("document", null, "numberOfGuides"))

Kukurykus
Legend
March 18, 2018

And I think this is a bug, since it is impossible to perform undo.

The same situation with the annotations is working fine.

var r = new ActionReference();

r.putIndex( stringIDToTypeID( "annotation" ), 1 );

var d = new ActionDescriptor();

d.putReference( charIDToTypeID( "null" ), r );

executeAction( charIDToTypeID( "Dlt " ), d, DialogModes.NO );

P.S. Do not you bother with sTT ('good')?

Why not use sTT ('guide')?


Yes, then you are right. Annotations are possibly same kind of accessory like guides are. They should work the same way.

 

 

That there is used 'good', not 'guide' is because it was converted so by my 'AM Replacement' script (Clean SL​) that changes charIDToTypeID to stringIDToTypeID.

 

I noticed it changes 'Gd  ' to first String it finds (alphabetically) so 'good'. 'u' in 'guide' is greater than 'o' in 'good', so it stops at 'good', however for some reason it still works 😕😕

 

That's not single case it happens. I find once for a while other uncorrect convertions that works as well.

 

 

I could ask you the same question why did you use 'paint' instead of 'point' in your code:

 

var d2 = new ActionDescriptor()

 

var anchor = new ActionDescriptor()

anchor.putUnitDouble(stringIDToTypeID("horizontal"), charIDToTypeID("#Rlt"), pp.anchor[0])

anchor.putUnitDouble(stringIDToTypeID("vertical"), charIDToTypeID("#Rlt"), pp.anchor[1])

d2.putObject(stringIDToTypeID("anchor"), stringIDToTypeID("paint"), anchor)

 

So like you see there is 'paint' (that works), but correctly should be 'point' (what works too) Check that in this topic: Add subpath to existing path

 

 

Here's my code I created (before I found yours - so that is not based on code from that topic), where my converter used 'paint' instead of 'point' too (as 'a' ASCII character is smaller than 'o'):

 

function subPaths() {function lar(v) {function pos(v1, v2) {

               (dsc5 = new ActionDescriptor()).putUnitDouble(sTT('horizontal'),

               sTT('pixelsUnit' ), v1[0]), dsc5.putUnitDouble(sTT('vertical'),

               sTT('pixelsUnit'), v1[1]), dsc4.putObject(sTT(v2), sTT('paint'), dsc5)

          }

          dsc4 = new ActionDescriptor(), pos(v[0], 'backward'), pos(v[1], 'anchor')

          pos(v[2], 'forward'), lst3.putObject(sTT('null'), dsc4)

     }

 

     lst3 = new ActionList(); for(i = 0; i < baf.length; i++) lar(baf);

 

     (dsc3 = new ActionDescriptor()).putBoolean(sTT('closedSubpath'), true)

     dsc3.putList(sTT('points'), lst3); (lst2 = new ActionList()).putObject(sTT('null'), dsc3);

     (dsc2 = new ActionDescriptor()).putList(sTT('subpathListKey'), lst2); return dsc2

}

 

a=[t = 300, t], b=[f = 400, t], c=[f, f], d=[t, f]

function sTT(v) {return stringIDToTypeID(v)}

baf =  [[a, a, a], [b, b, b], [c, c, c], [d, d, d]];

 

(ref1 = new ActionReference()).putProperty(sTT('path'), sTT('workPath'));

(dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1);

(lst1 = new ActionList()).putObject(sTT('pathComponent'), subPaths())

dsc1.putList(sTT('to'), lst1), executeAction(sTT('set'), dsc1, DialogModes.NO)

 

End of 4th line:

 

sTT('pixelsUnit'), v1[1]), dsc4.putObject(sTT(v2), sTT('paint'), dsc5) // sTT('point')

 

 

How that happened you used 'paint', not 'point' (that is equivalent to 4-char ID 'Pnt ')? Do you use some wrongly working converter too like me? (however I have noticed you prefer to use - working faster? - Chars instead of Strings in your scripts)

Legend
October 20, 2017

use such function instead of guides.removeAll()

function clear_guides()

    {

    try {

        var d = new ActionDescriptor();

        var r = new ActionReference();

        r.putEnumerated( charIDToTypeID( "Gd  " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Al  " ) );

        d.putReference( charIDToTypeID( "null" ), r );

        executeAction( charIDToTypeID( "Dlt " ), d, DialogModes.NO );

        d = null;

        r = null;

        }

    catch (e) { alert(e); throw(e); }

    }

Jarda Bereza
Inspiring
September 30, 2017

I would try "suspendHistory" so you can force photoshop to create new history step. Even if nothing happens.

app.refresh() can be slow ;-)

Davide_Barranca12040269
Legend
October 1, 2017

app.refresh is one of those all-purpose medicaments :-) True, it's slow.

In my case, I already had a complex routine within a suspendHistory, but I had to store a history status in a variable, and in some cases, it didn't stick unless I app.refresh. Go figure.

Davide Barranca - PS developer and authorwww.ps-scripting.com
Jarda Bereza
Inspiring
October 1, 2017

That is possible. Anyway I would try first this. This should create history step everytime. So we probably want add condition if there was one or more guides and in this case create history step. Which means we don't need history step. We just need save document if there was one or more guides.

  1. app.open( new File( 'path/to/image' ) ); 
  2. var theImg = app.activeDocument; 
  3. theImg.guides.removeAll(); 
  4. app.activeDocument.suspendHistory("Make it dirty",function(){});
  5. if ( ! theImg.saved ) { 
  6.     theImg.save(); 
  7. theImg.close(); 
JJMack
Community Expert
Community Expert
September 28, 2017

If a  File has saved guide and you remove the  files need to be resaved.   Photoshop internally  has a Dirty bit for documents and if you try to close a document with its dirty bit set Photoshop will let you know the documnebt has unsaved changes with a prompt to save or not.   However  I do not know if there is a way to test this bit in a script.

If I open a psd the does not have saved canvas guides. If I look in menu View the item Clear Canvas Guides will be grayed out unavailable.    Most of the time in Action or Script if is has coded something like that and it is currently unavailable the script or action will through an error.  However not always some commands Photoshop scripts and actions ignore.  Like arrange layer to the front or back when they are the front or back and the function is not available the command is just ignored in actions and scripts. So it must be the same for View Clear Canvas guides your scripts are not throwing  an error.  So you can not tell if the was available or not. If it were the guides would be removed and the dirty bit set.

I do not know if Photoshop Scripting exposes this dirty bit to the script writer.  That is what your script would need to test to see if a save is requited or not.

A document opened from a file would for sure have a backing file a saved file it is what you opened. The document opened in Photoshop may be dirty or not and would need to be saved again to save the current changes.

JJMack
LP-LuddeAuthor
Participant
September 29, 2017

That's the problem. The dirty state doesn't change when removing or adding guides via the script. I expect it to work just like you describe, but it doesn't.

JJMack
Community Expert
Community Expert
September 29, 2017

How does one test the dirty state?

JJMack
c.pfaffenbichler
Community Expert
Community Expert
September 28, 2017

Does anyone know why manipulation of guides doesn't change the saved state?

I at least don’t.

But instead of relying of the saved-property you could use an if-clause to first check if a file has guides.

if (activeDocument.guides.length > 0) {/*do one thing*/}

else {/*do another thing*/}

LP-LuddeAuthor
Participant
September 29, 2017

Yes, I think this is the way I'm going to have to do it. Thanks!