ProjectMirador / mirador-annotations

a Mirador 3 plugin that adds annotation creation tools to the user interface
https://mirador-annotations.netlify.app/
38 stars 37 forks source link

Exporting/importing annotations: alternative to parsing/generating SVG? #35

Closed benjamingeer closed 3 years ago

benjamingeer commented 3 years ago

Hello, I have a follow-up question to #34. After trying the approach described there, I realised that most of the information about each annotation in localStorage is in the SvgSelector. For example, if I draw a six-sided polygon, it looks like this:

{
  "body":{
     "type":"TextualBody",
     "value":"<p>polygon</p>"
  },
  "id":"cb7f9b79-c940-4a5a-bf50-196a5bd2b6f0",
  "motivation":"commenting",
  "target":{
     "source":"https://cudl.lib.cam.ac.uk/iiif/MS-ADD-03970/canvas/1",
     "selector":[
        {
           "type":"FragmentSelector",
           "value":"xywh=1090,1216,2440,1801"
        },
        {
           "type":"SvgSelector",
           "value":"<svg xmlns='http://www.w3.org/2000/svg'><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M2327.27956,1216.80442l129.15801,6.79779l1074.05083,564.21657l-312.69834,1080.84862l-1210.00663,149.55138l-917.70166,-849.72376l475.8453,-666.18343l543.8232,-197.13591z\" data-paper-data=\"{&quot;state&quot;:null}\" fill=\"none\" fill-rule=\"nonzero\" stroke=\"#ff002c\" stroke-width=\"10\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" style=\"mix-blend-mode: normal\"/><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M2320.27956,1216.80442c0,-3.86599 3.13401,-7 7,-7c3.86599,0 7,3.13401 7,7c0,3.86599 -3.13401,7 -7,7c-3.86599,0 -7,-3.13401 -7,-7z\" fill=\"#ffffff\" fill-rule=\"nonzero\" stroke=\"none\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" opacity=\"0\" style=\"mix-blend-mode: normal\"/><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M2449.43757,1223.60221c0,-3.86599 3.13401,-7 7,-7c3.86599,0 7,3.13401 7,7c0,3.86599 -3.13401,7 -7,7c-3.86599,0 -7,-3.13401 -7,-7z\" fill=\"#ffffff\" fill-rule=\"nonzero\" stroke=\"none\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" opacity=\"0\" style=\"mix-blend-mode: normal\"/><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M3523.4884,1787.81878c0,-3.86599 3.13401,-7 7,-7c3.86599,0 7,3.13401 7,7c0,3.86599 -3.13401,7 -7,7c-3.86599,0 -7,-3.13401 -7,-7z\" fill=\"#ffffff\" fill-rule=\"nonzero\" stroke=\"none\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" opacity=\"0\" style=\"mix-blend-mode: normal\"/><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M3210.79006,2868.6674c0,-3.86599 3.13401,-7 7,-7c3.86599,0 7,3.13401 7,7c0,3.86599 -3.13401,7 -7,7c-3.86599,0 -7,-3.13401 -7,-7z\" fill=\"#ffffff\" fill-rule=\"nonzero\" stroke=\"none\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" opacity=\"0\" style=\"mix-blend-mode: normal\"/><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M2000.78343,3018.21878c0,-3.86599 3.13401,-7 7,-7c3.86599,0 7,3.13401 7,7c0,3.86599 -3.13401,7 -7,7c-3.86599,0 -7,-3.13401 -7,-7z\" fill=\"#ffffff\" fill-rule=\"nonzero\" stroke=\"none\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" opacity=\"0\" style=\"mix-blend-mode: normal\"/><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M1083.08177,2168.49503c0,-3.86599 3.13401,-7 7,-7c3.86599,0 7,3.13401 7,7c0,3.86599 -3.13401,7 -7,7c-3.86599,0 -7,-3.13401 -7,-7z\" fill=\"#ffffff\" fill-rule=\"nonzero\" stroke=\"none\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" opacity=\"0\" style=\"mix-blend-mode: normal\"/><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M1558.92707,1502.3116c0,-3.86599 3.13401,-7 7,-7c3.86599,0 7,3.13401 7,7c0,3.86599 -3.13401,7 -7,7c-3.86599,0 -7,-3.13401 -7,-7z\" fill=\"#ffffff\" fill-rule=\"nonzero\" stroke=\"none\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" opacity=\"0\" style=\"mix-blend-mode: normal\"/><path xmlns=\"http://www.w3.org/2000/svg\" d=\"M2102.75028,1305.17569c0,-3.86599 3.13401,-7 7,-7c3.86599,0 7,3.13401 7,7c0,3.86599 -3.13401,7 -7,7c-3.86599,0 -7,-3.13401 -7,-7z\" fill=\"#ffffff\" fill-rule=\"nonzero\" stroke=\"none\" stroke-width=\"1\" stroke-linecap=\"butt\" stroke-linejoin=\"miter\" stroke-miterlimit=\"10\" stroke-dasharray=\"\" stroke-dashoffset=\"0\" font-family=\"none\" font-weight=\"none\" font-size=\"none\" text-anchor=\"none\" opacity=\"0\" style=\"mix-blend-mode: normal\"/></svg>"
        }
     ]
  },
  "type":"Annotation"
}

I just want to get the coordinates of the points, the line colour, and the line width. Is parsing the SVG the only way to do this? Also, to import an annotation like this back into Mirador, will I have to generate the same SVG? Or does Mirador have an API for this?

benjamingeer commented 3 years ago

cc @mejackreed

benjamingeer commented 3 years ago

To put this another way: does Mirador just represent annotations internally as SVG? Or does it have another, simpler internal representation in JavaScript?

mejackreed commented 3 years ago

Mirador represents annotations internally as using Open Annotation or Web Annotation. There is not currently a representation that you are describing which would provide those needed attributes.

Internally in AnnotationDrawing annotations have an internal state that has some of these attributes and are paper.js objects, but we do not provide hooks for what you are asking for.

Importing annotations with svg paths: https://github.com/ProjectMirador/mirador-annotations/blob/d0c607f9c2b7786933a24da9a0303cbf6d5f5197/src/AnnotationDrawing.js#L116-L121

Exporting to an annotation: https://github.com/ProjectMirador/mirador-annotations/blob/d0c607f9c2b7786933a24da9a0303cbf6d5f5197/src/AnnotationDrawing.js#L116-L121

Are you looking to create a different editing interface or trying to store these attributes differently?

benjamingeer commented 3 years ago

We store annotation shapes in our database, and we'd like to use Mirador to edit them. Currently we store these shapes in a very simple JSON format like this:

{
   "lineColor":"#ff3333",
   "lineWidth":2,
   "points":[
      {
         "x":0.24285714285714285,
         "y":0.1712962962962963
      },
      {
         "x":0.8678571428571429,
         "y":0.16666666666666666
      },
      {
         "x":0.8892857142857142,
         "y":0.7222222222222222
      },
      {
         "x":0.25,
         "y":0.7361111111111112
      },
      {
         "x":0.2392857142857143,
         "y":0.16898148148148148
      }
   ],
   "type":"polygon"
}

(The coordinates are expressed as fractions of image width and image height.)

We're new to Web Annotation, and we're thinking that maybe we should switch to it for storing annotation shapes. If I understand correctly, in Web Annotation, if I want a non-rectangular shape, I have to express it as SVG. That would explain why Mirador is only providing those shapes in SVG format. Is that right?

mejackreed commented 3 years ago

That would explain why Mirador is only providing those shapes in SVG format. Is that right?

Correct. Mirador relies on Web Annotation selectors SVGSelector and FragmentSelector https://www.w3.org/TR/annotation-model/#selectors

While I agree that this is a bit difficult to work with internally, we did not want to specify yet another alternative.

PaperJS has an exportJSON method, but once again this is a library specific format. We have looked into something like GeoJSON as that may offer a similar coordinate geometry and may help with better defining shapes, but then you are doing coordinate transformations.

There are a few libraries that can do SVG parsing / conversions that might help here.

benjamingeer commented 3 years ago

Thanks very much, this helps a lot. I think we're going to do the same thing as Mirador and just store the SVG, that seems like the simplest approach.