Sign or annotate a fixed image specified in the form definition

What is the general goal of the feature?
As a survey designer, I would like to be able to specify an image to be annotated in an annotate question or an image to be signed in a signature question.

@Grzesiek2010 has prepared a demo of what this might look like:

What are some example use cases for this feature?

  • Annotate a standard human body outline to indicate, for example, regions of pain (a similar thing can be done with image-map but it specifies touch zones whereas this allows for any part(s) of the body to be indicated, perhaps with arrows and the like)
  • Annotate a standard building plan like a joint between two pieces of lumber
  • Previously from a user: Annotate media embedded in form
  • Sign next to agreement text so it's clear what is being signed for

What can you contribute to making this feature a reality?
Spec and implementation guidance. As is often the case with these things, the tricky part is coming up with a consistent, clean way for the ODK XForms and XLSForm specification to provide this behavior. I have started Proposal: specify a fixed image to be annotated or signed to discuss this.

that's exactly that i need
i want to suite on a plan specifics points to know where measurements have been done
i need to preload the plan and after that put some mark on it

This would be a really neat feature!

@danbjoseph Perhaps something to bring up with the TSC? Once there's agreement on the specification side, this should be really quick to ship. That discussion has started here. I strongly favor the "defaults" approach but am open to alternatives if there's strong consensus. In particular, I'd really like to see an example form for what @martijnr was describing on that thread.

thank you to @LN (via Slack)

Currently this is implemented and pending pyxform and docs

If you need it today, you can just put jr://images/<image filename> in the default column and that should be passed through and work.

| type  |    name    |         label         | appearance |        default         |
| image | annotating | Circle things please. | annotate   | jr://images/aerial.png |

Central will ask you to add the image.

And it will be loaded in when you complete the survey.

1 Like


Is there a way to use this feature when outputting to Google sheets ?

Using a default image would be perfect for a few of my existing projects and likely future ones.

Thanks in advance


I have a question about this feature (which is super useful!).

Is it possible to dynamically set the default image based on a prior question?

eg: a select_one widget asks "which map/drawing do you want to markup" and then deliver its filename as the default for the image annotation / signature capture. This would be very efficient to be able to have the images delivered with the form and chosen from a question instead of sideloading to the device manually and selecting the image to use.

I took the example from #3579 and added a select_one for 'which_image', then replaced filename.ext & jr://images/filename.ext in the default column with ${which_image} but it failed validation in Central 1.3.3 for all rows as :

The XLSForm could not be converted: ODK Validate Errors:
>> XForm is invalid. See above for the errors.
: Invalid XPath in value set action declaration: 'jr://images/ ${which_image} '
    Problem found at nodeset: ${model}[@xforms-version=1.0.0]/setvalue
    With element <setvalue event="odk-instance-first-load" ref="${signature_widget2}" value="jr://images/ ${which_image} "/>

The following files failed validation:

Result: Invalid

Edit: default filenames with a '-' in them will also fail on validation

The XLSForm could not be converted: ODK Validate Errors:
>> XForm is invalid. See above for the errors.
: Invalid XPath in value set action declaration: 'jr:/${abc-123}.png'
    Problem found at nodeset: ${model}[@xforms-version=1.0.0]/setvalue
    With element <setvalue event="odk-instance-first-load" ref="${signature_widget2}" value="jr:/${abc-123}.png"/>

The following files failed validation:

Result: Invalid

How many different images do you have - can you have a question for each image and use relevance to pick which question to show the user (instead of picking which image to show for the one question)?

I thought about that, (and tested it), however in some cases there could be 10, others could have a few hundred. Syncing the PNGs to the device is ok (small files created from CAD DWGs), but I would prefer the submission to have a single 'annotated drawing' field, and not a few hundred with only one populated.

Perhaps I could have all the different rows and display with relevance, and then a final calculate row that pulls the value (annotated filename.ext) from whichever one is used?

I've been testing this further, I have ~130 rows of default images all with relevance, and a final calculate that concatenates all of them to get the filename in a single location. It's not pretty, but it works, and avoids sideloading the images and having the user select it. Took a few tries to realise that -, &, + and spaces in the filename weren't allowed and the defaults cannot be in a group.

One issue I found, if the default image is not marked up, it doesn't get uploaded with the submission, I get this error in Central when trying to download it:

{"message":"Could not find the resource you were looking for.","code":404.1}

Looking at the media folder in the zip download, instead of the marked up image file name (13 digit string.jpg on Collect, annotation-#####.png on Enketo), the field has jr://images/filename.ext instead, and AttachmentsPresent < AttachmentsExpected.

Is there a solution for a default image that's not marked up? Or, is there a way to force markup? Otherwise I'll probably strip jr://images/ and replace it with a path to the images elsewhere.

@ahblake I took an initial look at this but unfortunately haven’t had a chance to come back to it. We hadn’t explicitly considered dynamic defaults for images but what you’ve described makes sense! Thanks for sharing the use case and following up on what you’ve tried.

There’s at least one bug triggered by your initial attempt. The form converter (pyxform) always prepends jr://images even if there’s an expression in the default column. I’ll explore more deeply and file an issue with more details in the new year if no one beats me to it. @KeynesYouDigIt you might be interested in checking this out since you added support for image defaults (thanks!). I think you already look to see if there’s an explicit jr://images prefix and this may just be a matter of looking for the dynamic default regex as well.

You use the default column to set the value? I think using those characters hits a form conversion bug related to how dynamic defaults are identified.

This case didn’t seem like it would ever be desired so we didn’t handle it. Admittedly we could give more help there. From what you write it sounds like it would be an enumerator error not to annotate, as we expect. Two ideas to handle it better are to put a constraint to reject values that start with jr://images and/or to first show the image and ask a question like “do you have annotations to make? yes/no”.

I would find dynamic defaults really useful, so if there's a way to get there that would really clean up some forms instead of having a relevant line for every option

Yes, when I created all the possible default entries with static default filenames, some filenames I was working with had these characters caused errors on upload. I renamed everything and just need to remember that in future

There are cases where it's desirable to have a reference drawing included with the submission, even without markup, but for now I'll try the constraint first to force markup (even saving with no markup would be enough), as I should be able to import the drawing outside ODK as needed.

Appreciate the help! I have many other questions and things I'm butting up against as I explore different ways of working with ODK, it's a truly fantastic tool.

1 Like

Update six months on...
Default image markup works nicely and allows me to show the right map/layout drawing to the enumerator based on their previous selection. The constraint works fine and doesn't allow progression without markup, or at least open/save.

It does require a physically large large/high resolution device to return a legible image, 10"/WQXGA or above is generally acceptable.

As I have so many images (~250 in one, ~300 in another) in my current forms, I create name, label, relevant, constraint with excel formulae, and only populate the default column with the media filename from the directory listing.

eg for the constraint
="not(contains(${"&B328&"}, 'jr://'))"

Then at the end of this block I use another excel formula to build the concat in a calculate that collects the annotated image filename, as only one of the block can be true/populated.
eg ="concat(${"&TEXTJOIN("}, ${",TRUE,B29:B325)&"})"

At the submission side, it does mean there are hundreds of columns to discard from a queried table of data, but you can't actually discard them if querying via other methods that will retrieve the image as one will have the image blob.

Being able to dynamically set the default would remove all this, however the set of default images would need to be referenced somewhere else so that they were required in the media upload. is this the point where I submit a feature request for this functionality?

1 Like