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 defaultImage.zip 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:
${defaultImage}.xml
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:
${defaultImage}.xml
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.
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.
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?
Would it be accurate to say that you are dealing with some kind of entity and that each of the entities has an image associated with it? I believe that in an ideal world you'd like to have your data collectors select an entity and then that would make the corresponding image available for annotation.
It would mean delivering the entire reference image library for the dataset with the form as opposed to the subset which in some cases might be impractical (thousands of drawings vs hundreds) but I'm sure there's a way to handle that.
Thinking through different use cases, sometimes it would be desirable to assign tasks to a particular user, at other times anyone in the pool of users could complete them.
If you are suggesting that Form 123 has a QR code that will only deliver media for location 123.A and another code that will deliver media for location 123.B, etc, I can see that working, the same users can use the same device at different locations, but they would just have to delete and add the form when they change location.