Skip to main content
Inspiring
January 29, 2018
Answered

How to get an annotation's position ?

  • January 29, 2018
  • 4 replies
  • 3684 views

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

Does someone know if it's possible ?

This topic has been closed for replies.
Correct answer Kukurykus

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

At the moment   alert (N)    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.


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[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, j = 0; j < b.length; j++) {

                    if (b) h += b.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))

     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 + ' = bin(fle)')

               !l ? dN() : fle.remove()

          }

          dHS(); while(typeof n != 'undefined' && N == n) m++; alert(N.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?

4 replies

Jarda Bereza
Inspiring
February 10, 2018

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.

Jarda Bereza
Inspiring
February 10, 2018

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.

Kukurykus
Legend
February 10, 2018

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?

Legend
January 30, 2018

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; }

    }

Jarda Bereza
Inspiring
January 29, 2018

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

Inspiring
January 30, 2018

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.

Kukurykus
Legend
January 30, 2018

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.


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.