24 Replies Latest reply on Feb 10, 2018 8:33 AM by Jarda Bereza

    How to get an annotation's position ?

    Evergreen Level 1

      I would like to find the position of an annotation among multi-annotations.

       

      Does someone know if it's possible ?

        • 1. Re: How to get an annotation's position ?
          Jarda Bereza Level 4

          If I remember correctly... only known posibility is read PSD file as binary with custom file parser.

          • 2. Re: How to get an annotation's position ?
            Evergreen Level 1

            Thanks for sharing a possible way to do it.

             

            As my scripting skills are very limited (almost only the very basic, ), I was hopping for a simplier solution based on action descriptor code.

            I will have a look at your solution, even if it seems way too much complicated for me.

            • 4. Re: How to get an annotation's position ?
              c.pfaffenbichler Level 9

              Can you explain in more detail what you are trying to achieve?

              Could you use something other than notes for the task or do you have to process existing notes?

              • 5. Re: How to get an annotation's position ?
                r-bin Level 5

                And why do you need to know the position of the annotation?

                You can set any property for the annotation, but you can not read it.

                This is a bug of Photoshop. You can specify the position for any annotation.

                 

                var i = 0;
                
                while (1)
                    {
                    if (has_annotation(i)) { set_annot_position(i, 10, 10+i*10); i++ }
                    else break;
                    }
                
                function has_annotation(idx)
                    {
                    try
                        {
                        var r = new ActionReference();
                        r.putIndex( stringIDToTypeID( "annotation" ), idx );
                
                        var d = new ActionDescriptor();
                        d.putReference( charIDToTypeID( "null" ), r );
                
                        var d1 = new ActionDescriptor();
                        d1.putObject( charIDToTypeID( "Sz  " ), charIDToTypeID( "Ofst" ), new ActionDescriptor());
                        d.putObject( charIDToTypeID( "T   " ), stringIDToTypeID( "annotation" ), d1 );
                
                        executeAction( charIDToTypeID( "setd" ), d, DialogModes.NO );
                
                        return true;
                        }
                    catch (e) { return false; }
                    }
                
                function set_annot_position(idx, x, y)
                    {
                    try
                        {
                        var r = new ActionReference();
                        r.putIndex( stringIDToTypeID( "annotation" ), idx );
                
                        var d = new ActionDescriptor();
                        d.putReference( charIDToTypeID( "null" ), r );
                
                        var d2 = new ActionDescriptor();
                        d2.putUnitDouble( charIDToTypeID( "Hrzn" ), charIDToTypeID( "#Pxl" ), x );
                        d2.putUnitDouble( charIDToTypeID( "Vrtc" ), charIDToTypeID( "#Pxl" ), y );
                
                        var d1 = new ActionDescriptor();
                        d1.putObject( charIDToTypeID( "Lctn" ), charIDToTypeID( "Pnt " ), d2 );
                
                        d.putObject( charIDToTypeID( "T   " ), stringIDToTypeID( "annotation" ), d1 );
                
                        executeAction( charIDToTypeID( "setd" ), d, DialogModes.NO );
                
                        return true;
                        }
                    catch (e) { return false; }
                    }
                
                
                1 person found this helpful
                • 6. Re: How to get an annotation's position ?
                  Evergreen Level 1

                  I would like to use annotations as remplacement for color samplers which number is limited to 4.

                  I thought it could be a good way of storing the position of the samples inside the file.

                  • 7. Re: How to get an annotation's position ?
                    c.pfaffenbichler Level 9

                    Have you tried using the Count Tool?

                    • 8. Re: How to get an annotation's position ?
                      Evergreen Level 1

                      Sorry, I don't own the extended version.

                      • 9. Re: How to get an annotation's position ?
                        c.pfaffenbichler Level 9

                        Another option might be using the Pen Tool to create pathPoints.

                         

                        Also: Which version are you using that makes you mention »Extended«?

                        • 10. Re: How to get an annotation's position ?
                          Evergreen Level 1

                          Using pathPoints... well it seems a good idea, I should had to think about it ! I will try something with that.

                           

                          From what I have read, maybe storing the data I need inside metadata and then parsing the data could be also a solution , but this one I will have to learn.

                           

                           

                          My PS version is 13.01. The count tool menu option is always greyed out.

                           

                          I have never used the Count Tool. Isn't it only available inside PS extended ?

                          • 11. Re: How to get an annotation's position ?
                            Jarda Bereza Level 4

                            There is no difference "extended" vs "non-extended" in PS CC

                            CS6 had last extended version.

                            • 12. Re: How to get an annotation's position ?
                              Evergreen Level 1

                              Perpetual Design Standard doesn't have the extended features !

                              • 13. Re: How to get an annotation's position ?
                                Kukurykus Adobe Community Professional

                                That doesn't return positions of samplers bet let you use more than default 4 to make average Color Range selection basing on 1 quater pixels (point samplers) histogram: Unlimited Point Samplers - PS-SCRIPTS.COM / works together with Bridge.

                                • 14. Re: How to get an annotation's position ?
                                  Evergreen Level 1

                                  @Kukurykus

                                  Ok, thanks for the sharing! I think I can read and understand your code (but I would have not been able to write it ).

                                  Eventhough if your script has some drawbacks for totaly suiting my needs, I will see if I am able to do something with your script.

                                   

                                  I have also to find some info about the $setenv and $getenv part...

                                   

                                  @all other contributors,

                                  Thanks for you help.

                                  • 15. Re: How to get an annotation's position ?
                                    Kukurykus Adobe Community Professional

                                    I filled a little a lack of annotations scripts. Proabably this one is original as I haven't found any that would retrieve positions of notes. To use it (after you save it in your Presets/Scripts folder of your Photoshop, which you reopen) click any annotation there's (amongst others) to make it active and run script. It will tell you selected note exact horizontal & vertical position

                                     

                                    function bin(v) {function anno(v) {
                                              var wh = v.match(/(.{4})(.{4})$/)
                                              for(pos = '', i = 1; i < wh.length; i++) {
                                                   for(var h = '', b = wh[i], j = 0; j < b.length; j++) {
                                                        if (b[j]) h += b[j].charCodeAt().toString(16)
                                                   }
                                                   pos += eval('0x' + h) + ', '
                                              }
                                              return pos.slice(0, -2)
                                         }
                                    
                                         notes = [], v.open('r'), v.encoding = 'binary'
                                         var arr = v.read().match(/txtA.{28}/g); v.close()
                                         for(k = 0; k < arr.length; k++) notes.push(anno(arr[k]))
                                         return notes
                                    }
                                    
                                    function sTT(v) {return stringIDToTypeID(v)}
                                    
                                    function dN() {
                                         (ref1 = new ActionReference()).putEnumerated(sTT('annotation'),
                                         sTT('ordinal'), sTT('targetEnum'));(dsc1 = new ActionDescriptor())
                                         .putReference(sTT('null'), ref1), executeAction(sTT('delete'), dsc1, DialogModes.NO);
                                    }
                                    
                                    function pHS(v) {
                                         (ref1 = new ActionReference()).putEnumerated(sTT('historyState'),
                                         sTT('ordinal'), sTT('previous')); (dsc1 = new ActionDescriptor()).putReference
                                         (sTT('null'), ref1), executeAction(sTT('select'), dsc1, DialogModes.NO)
                                    }
                                    
                                    with(psd = new PhotoshopSaveOptions()) {
                                         annotations = !(alphaChannels = embedColorProfile = layers = spotColors = false)
                                    }
                                    
                                    if ($.level = 0, documents.length) {try{
                                              (aD = activeDocument).suspendHistory('Notes', '')
                                              dN(), executeAction(sTT('undoEvent'))
                                              for(m = l = 0; l < (Nn = ['N', 'n']).length; l++) {
                                                   aD.saveAs(fle = File('~/desktop/.psd'), psd, true)
                                                   if (!l || N.length > 1) eval(Nn[l] + ' = bin(fle)')
                                                   !l ? dN() : fle.remove()
                                              }
                                              pHS(); while(typeof n != 'undefined' && N[m] == n[m]) m++; alert(N[m])
                                         }
                                    
                                         catch(err) {executeAction(sTT('undoEvent')), alert('No selected annotation!')}
                                    }
                                    

                                     

                                    It works quite fast. Poisition is alerted after few miliseconds. I did not try it much, but it does not work slower even with 100 annotations. It reads slower really big documents or with many stuff, but I didn't focus what exactly. Still that was 2 - 3 secs. So with a 'normal' documents probably up to one second. It fails for over 8 bits depth version as I had to use other regex to match the hex chars what I was not interested to do at this moment. Test it - perhaps you find something more to be fixed.

                                    1 person found this helpful
                                    • 16. Re: How to get an annotation's position ?
                                      Evergreen Level 1

                                      Well played !

                                       

                                      I'm far of fully understand the code (except that you used Jarda's solution).

                                       

                                      After testing, I found that the script returns inverted x,y results. Tried a few things (like reversing) but unsuccessfully...

                                       

                                      I'm also enable to separate the x from the y !!

                                       

                                      I also found that after moving or deleting an annotation, then running the script returns wrong results ( it's like if old values was kept in memory).

                                      • 17. Re: How to get an annotation's position ?
                                        Kukurykus Adobe Community Professional

                                        I didn't use Jarda solution. I even don't know what you mean as he didn't share any code like this. I checked now his posts of this and related topic and see he just mentioned about binary parsing but thats all and its common knowledge to get things they can't be taken other way - unfortunatelly it's not so easy after all and needs a lot of patience.

                                         

                                        Code may fail. It was rather given for testings as I don't have experience in reading binary yet so strange things may happen. Thanks for letting me know of disordered coordinates. I did it intentionally though, as they had other order in binary record, but it seems I could be wrong and shouldn't change their order (later I'll restore it).

                                         

                                        I don't get what you want to say by beeing enable to separate x from y?

                                         

                                        I'll take a look at those wrong results. As I said I didn't test it much, so there is much possibility it doesn't work correctly yet..

                                        • 18. Re: How to get an annotation's position ?
                                          Evergreen Level 1

                                          "I don't get what you want to say by beeing enable to separate x from y?"

                                           

                                          At the moment   alert (N[m])    returns something like ( theX,  theY ) ;

                                          If I want to use the annot's position values, I need to have something like :    alert (the X) +  alert (theY).

                                          Maybe the solution is simple, but until now I have failed at trying to solve this.

                                          • 19. Re: How to get an annotation's position ?
                                            Kukurykus Adobe Community Professional

                                            Okey so this is first script on this forum that does such thing! Regarding reverted coordinates they were displayed right way, so like written in binary's. I said that I changed their order but true is I had but forgot, and to your post I was sure I did so Now it works as it should. That's not only problem with annotations, the other order of coordinates, I noticed it also in other parts like in path(Item)s. But that's other story.

                                             

                                            In current 13th line I changed 28 value to 12. That caused (re)moved notes positions could still be read, but that happened in some not specified cases like only 1 note or some custom. Originally I used 28 value as it seemed range of binary characters can't be match of regular expresion's.

                                             

                                            I put resultant coordinates into array. They are alerted the sama way, but with chance to match one of them by N[m][0/*1*/].

                                             

                                            I tested it again. Now it works a little slower (I checked old & new script for the same document). Then it was about 225 ms, now 250). For 1*1*1 document it was 130 ms with one note, but with 100 of them it was not slower for any kind of document, however when I tried it with written annotations, many layer(Sets), channels, paths and big dimmension & resolution it was slower of course, but not much for some reason, just 350 ms ?!

                                             

                                            Putting note vertically/horizontally under 0, that is on top/left side of document will give 4294967278, so Math.pow(256, 4)!

                                             

                                            function bin(v) {function anno(v) {
                                                      var wh = v.match(/(.{4})(.{4})$/)
                                                      for(pos = '', i = wh.length - 1; i > 0; i--) {
                                                           for(var h = '', b = wh[i], j = 0; j < b.length; j++) {
                                                                if (b[j]) h += b[j].charCodeAt().toString(16)
                                                           }
                                                           pos += eval('0x' + h) + ', '
                                                      }
                                                      return pos.slice(0, -2)
                                                 }
                                            
                                                 notes = [], v.open('r'), v.encoding = 'binary'
                                                 var arr = v.read().match(/txtA.{12}/g); v.close()
                                                 for(k = 0; k < arr.length; k++) notes.push(anno(arr[k]))
                                                 return notes
                                            }
                                            
                                            function sTT(v) {return stringIDToTypeID(v)} function uN() {executeAction(sTT('undoEvent'))}
                                            
                                            function dN() {
                                                 (ref1 = new ActionReference()).putEnumerated(sTT('annotation'),
                                                 sTT('ordinal'), sTT('targetEnum')); (dsc1 = new ActionDescriptor())
                                                 .putReference(sTT('null'), ref1), executeAction(sTT('delete'), dsc1, DialogModes.NO)
                                            }
                                            
                                            function pHS(v) {
                                                 (ref1 = new ActionReference()).putEnumerated(sTT('historyState'),
                                                 sTT('ordinal'), sTT('previous')); (dsc1 = new ActionDescriptor()).putReference
                                                 (sTT('null'), ref1), executeAction(sTT('select'), dsc1, DialogModes.NO)
                                            }
                                            
                                            function dHS() {
                                                 (ref1 = new ActionReference()).putProperty(sTT('historyState'),
                                                 sTT('currentHistoryState')); (dsc1 = new ActionDescriptor())
                                                 .putReference(sTT('null'), ref1), executeAction(sTT('delete'), dsc1, DialogModes.NO)
                                            }
                                            
                                            with(psd = new PhotoshopSaveOptions()) {
                                                 annotations = !(alphaChannels = embedColorProfile = layers = spotColors = false)
                                            }
                                            
                                            if ($.level = 0, documents.length) {try{
                                                      (aD = activeDocument).suspendHistory('Notes', '')
                                                      for(dN(), pHS(), m = l = 0; l < (Nn = ['N', 'n']).length; l++) {
                                                           aD.saveAs(fle = File('~/desktop/.psd'), psd, true)
                                                           if (!l || N.length > 1) eval(Nn[l] + ' = bin(fle)')
                                                           !l ? dN() : fle.remove()
                                                      }
                                                      dHS(); while(typeof n != 'undefined' && N[m] == n[m]) m++; alert(N[m].split(','))
                                                 }
                                                 catch(err) {uN(), alert('No selected annotation!')}
                                            }
                                            

                                             

                                            A regex I thought to use for over 8 bits depth documents wouldn't be probably different than I used. I found problem is with sole writing/reading 16 and 32 bits deepth documents with .txt file I had to use to study binary record. With annotations that would not be problem to change deepth to 8 bits for time of script work, but if we had to read binary for other goals for not only 8 bits document then I have no idea how we could do it. I wonder why for so many years noone met this problem on Adobe forums? Once Michael L Hale mentioned "out of memory" issue. I tried to do the same with .tif which can store annotations information but some lines covering bitmap data were too long comparing with psd to be read. Any ideas?

                                            1 person found this helpful
                                            • 20. Re: How to get an annotation's position ?
                                              Jarda Bereza Level 4

                                              Best way how to read binaries is read only things you need and skip others.

                                              You can use

                                              File.seek() - set position for reading

                                              File.read() - with parameter how many bytes

                                              File.teel() - to know from which point you would read.

                                               

                                              And according format spec you will read file header and in header is section length. So you will skip in section you want. And there are informations about other sections and subsections. https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/

                                              Adobe Photoshop File Formats Specification

                                               

                                              So maybe you are interested in Layer and Mask section > Additional Layer Information > Annotations

                                              So you would read how long is "Image resources section" and then just skip it with File.read(offset)

                                              Same for color data section. And header has fixed width.

                                              1 person found this helpful
                                              • 21. Re: How to get an annotation's position ?
                                                Kukurykus Adobe Community Professional

                                                That is very useful. Honestley 1st time ever I used seek & tell was a week ago when I was writing this script. Like mentioned I tried to do the same task with .tif, but then it came impossible to read file skipping some lines using seek and tell, however I could do more than without it. I used reandch and readln as I had no idea read may be used with parameter! If that is going to work like I imagine, then I can divide longest lines into chunks. But if I guess right I have to read some exact line of some file few times, I mean opnening file to read it if I won't to avoid file was been reading endlessing. I'll try and see that works, because there must be some way to do it... It's interesting documentation I even didn't think it may exist I were in those sections now and wonder how fast I would get alerted notes coordinates if to read binaries I used strictly proper method.

                                                • 22. Re: How to get an annotation's position ?
                                                  Jarda Bereza Level 4

                                                  I did a mistake. It should be: and then just skip it with File.seek(offset)

                                                  The difference is that you will read smallest possible part of document. Only things you really need instead of full document.

                                                  So reading 0.2% of document should be faster than reading 100% of document.

                                                  • 23. Re: How to get an annotation's position ?
                                                    Kukurykus Adobe Community Professional

                                                    You changed well to will, but still my eyes saw that word as will, because of context Only now I see that was different

                                                     

                                                    You say I can read directly part of binaries by header. So if there is key word 'Anno' how to start reading binaries from/only for this section? For now before I can know it I have to read whole file, then with tell I'm getting to know position of 'Anno', and only then when I read a file second time I can use seek to point where from I want to start reading binaries. Bad way ! So question is how to start reading binaries for/from 'Anno' position without reading entire file earlier to check its position?

                                                    • 24. Re: How to get an annotation's position ?
                                                      Jarda Bereza Level 4

                                                      You can skip Header section. It has fixed length of 26bytes.

                                                      So you could set "File.seek(27)" or similar number :-D

                                                      Here is color mode lenght. You will read it, then you convert it into decimal number and use "seek(someNumber)" again.

                                                      So you will be at "Image resources section lenght" you will use read(4) and same as before "seek(someNumber)"

                                                      finally you will be in "layer and mask section"  4-8 bytes in this section is lenght of Layer info. You can skip it. And same for global layer mask info. And finaly you will be in "Additional layer information" I am not sure how excatly continue... anyway area for searching will be much smaller.