Problem/Motivation

Upload fields already allow camera capture and video capture functionality. However, for more restrictive fields, like image fields, where the allowed input is limited to images only, allowing video capture is not useful. Users could capture a video and then denied on upload.

We can limit this with the 'accept' attribute, using specific filename extensions in that attribute causes (at least some versions of) Android to propose using any available capture app (camera, camcorder, sound recorder) and to completely ignore the permitted filename extensions (but Drupal's validation of course still stops non-permitted files from being uploaded). So at the moment, only the generic 'image/*' value is useful in the 'accept' attribute, which also suffices to solve the problem thankfully.

Proposed resolution

A new '#accept' property is added to the field widget, which is rendered by adding the 'accept' attribute to the file input tag, with the value 'image/*'.

Remaining tasks

  • Review patch
  • Manually test: attempt to upload file in image field from mobile device without patch (should get both image and video creation possibility), attempt to upload file from mobile device in image field with patch (should only get image capture capability, not video capture or audio capture)

User interface changes

Mobile devices will limit input for image fields.

API changes

API addition of the #accept key on ManagedFile elements.

Data model changes

None.

Comments

swentel’s picture

Component: field system » image.module
slashrsm’s picture

Would it make sense to add support for this to file element and then use it in field widgets?

swentel’s picture

Component: image.module » file system

That probably makes more sense yes. Tentatively moving to file system - not sure whether it belongs there or file.module.

giorgio79’s picture

Filefield Sources has a great way of handling various sources https://www.drupal.org/project/filefield_sources

slashrsm’s picture

Component: file system » file.module
Issue tags: +Media Initiative

Let's say file.module. "file_managed" element lives there while it's simplified version "file" lives in system.module AFAIK. It would make sense to add this feature to both.

We already acomplished similar task with "multiple" attribute: #625958: Support Uploading Multiple Files for HTML5 Browsers via #multiple attribute

iantresman’s picture

I think this is a very desirable feature for its simplicity and multitude of uses.

Being able to take a photo with your mobile (or select one from your camera's gallery), check it, perhaps re-take the photo, and then upload it to Drupal, would make for a great new feature. See also:

dave reid’s picture

Version: 8.0.x-dev » 8.1.x-dev
dave reid’s picture

Opened new contrib module to write this for D7/D8: https://www.drupal.org/project/file_capture

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

martin_q’s picture

Assigned: Unassigned » martin_q
Issue tags: +DevDaysMilan

@Saphyel and I have been looking at this in #2753457: Accept photos from mobile devices directly in image file form widget.

@Dave Reid suggested using the following type of tag instead of the general 'image/*' form:
<input type="file" accept=".jpg,.png,.jpeg,.gif;capture=camera">
(taking the filename extensions from the field's permitted extensions setting).

A quick google suggests that this is not how the attribute is intended to be used: https://mobilehtml5.org/ts/?id=23 and http://www.wufoo.com/html5/attributes/20-accept.html talk only of 'image/*', 'audio/*' and 'video/*'.

Further, our quick tests on our two Android phones suggest that the 'capture' value doesn't seem to add anything either. If we put a non-standard value (such as the string ".jpg,.png" or even the string ".gif") then the device offers the choice of using camera, camcorder and (where installed) sound recorder apps to capture a file to upload. The fact that the camera captures .jpg files does not seem to affect the choices offered, but of course Drupal's validation then rejects the file. Whilst this is mildly annoying (a user is invited to capture a photo with their camera but then the phone cannot upload it), it seems existing validation already prevents this opening the door to unwanted filetypes.

This is making me start to see a possible use-case for switching off the image capture option, because if I have a field that only accepts .gif files, and I know that phone cameras typically create .jpg files, I might want to disable image capture, to improve the user experience.

More generally, a plain file field might also be used to upload images - for example, I uploaded an image in the duplicate issue. So the image capture option shouldn't only be available to the image field widget. We should implement it for all file fields. Now it seems much more sensible to have a checkbox for any file field, labelled "Accept direct image capture" (or similar). ...And what about also adding "direct video capture" and "direct audio capture" as options as well (for the three possible values of the 'accept' attribute)? Then, for example for images, we would set the "image capture" checkbox by default, and disable the other two options.

martin_q’s picture

Current state of patch from the duplicate issue is
https://www.drupal.org/files/issues/accept_photos_from-2753457-7.patch
as submitted by @Saphyel.

wim leers’s picture

dave reid’s picture

There's a bit more to enabling this on file fields (making sure the capture type corresponds to a matching file extension, not a simple checkbox for UI), so I think a good first step is just going with image fields for now.

dave reid’s picture

I just read up on the W3C spec (https://www.w3.org/TR/html-media-capture/#the-capture-attribute) and other referencing docs (http://www.wufoo.com/html5/attributes/20-accept.html) that indicate we should change how the capture information is added to the input. With HTML5 we only need to add a boolean capture attribute:

<input type="file" name="image" accept="image/*" capture>

To do this, I think we should still be putting the allowed extensions in the accept attribute (and not using image/*), but this definitely simplifies implementations for file fields (not having to pick between camera/camcorder/microphone capture values), and we could bring that into scope here.

dave reid’s picture

Yeah, I'm seeing that just by defining accept=".jpg,.jpeg,.png,.gif" I get offered a camera upload version, even without a capture attribute. I'm torn now if we should actually make this a UI when it's something that if the user unchecks, gets ignored by browsers anyway.

martin_q’s picture

Thanks @Dave Reid for looking this up. I too had just come across documentation indicating that the filename extensions are definitely valid according to the spec. But the problem I see is that even if I set the input tag with the attribute accept='.pdf' my phone offers me camera, camcorder and sound recorder capture options. And it will allow me to take a photo and attempt to upload it as jpg (which is only prevented if jpg is not a permitted filename extension for the field). I don't see that, in practice, specifying the filename extension has any benefit at all, and in fact on the Android phone I'm looking at here, it leads to spurious options being offered. In contrast, using the 'image/*' value still doesn't provide any validation of the filename extension and still doesn't block Drupal's validation of the same... but it does successfully hint to my phone which capture app to offer, which is something at least.

I agree that this is evidently not how the standard is designed to work, but it seems to be how it does work. I'm in favour of accepting the de facto standard (subject to establishing that my phone's behaviour is typical), but mine is just one voice.

Thanks, @Wim Leers for the link to the D7 code. I think this will be useful in the generalised approach for all file fields, if/when we get that far. The one thing I would propose doing differently is allowing multiple capture types rather than a four-way 'audio/video/image/none' choice. Generic file fields that can accept any file type should correspondingly be able to access any capture device.

martin_q’s picture

Status: Active » Needs review
StatusFileSize
new4.26 KB

I've ended up reworking this, in a way which hopefully will more easily be extensible if/when we come to expanding it to other file fields. By the way, the use of accept='image/*' is not final, and can easily be changed to use the contents of $extensions should that be the preferred way to proceed.

Status: Needs review » Needs work

The last submitted patch, 18: option_to_enable-2307451-18.patch, failed testing.

Bojhan’s picture

Why is this an option that should be exposed in the UI?

martin_q’s picture

Status: Needs work » Needs review
StatusFileSize
new5.96 KB

Schema change and default field values added.

martin_q’s picture

@Bojhan: @Saphyel and I weren't sure about exposing the option to the user either, but as we started to explore the wider future application of this - namely, to allow camera, camcorder or sound recorder capture for any file field, I started to see that it makes sense to make this optional. In theory the permitted filename extensions on a field would dictate which kinds of capture app a device should offer when a user tries to upload a file (which in fact would remove the need to have these options selectable in the UI), but in practice that doesn't seem to work - on some versions of Android at least - so making this configurable should improve the UX for users of devices that don't intelligently deal with specifiic filename extensions in the 'accept' attribute.

A concrete example, in the case that we have implemented all three capture types for all file types: we need to ensure that my phone doesn't offer 'Sound Recorder' as an app that could fulfil the requirements of the user profile image field. At present, limiting filename extensions to .jpeg, .jpg, .gif and .png doesn't do that.

Status: Needs review » Needs work

The last submitted patch, 21: option_to_enable-2307451-21.patch, failed testing.

xjm credited Gábor Hojtsy.

xjm credited Saphyel.

xjm’s picture

(Adding contributors from the duplicate issue. Thanks!)

martin_q’s picture

Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new11.67 KB

New patch which manually updates the field type in line with the schema change, and includes a test for that update also.

gábor hojtsy’s picture

Status: Needs review » Needs work
+++ b/core/modules/image/config/schema/image.schema.yml
@@ -123,6 +123,9 @@ field.field_settings.image:
+    image_capture:
+      type: boolean
+      label: 'Mobile device camera capture permitted'

+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -198,6 +199,13 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
+    $element['image_capture'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Allow mobile device capture from camera'),

Please use the same label in the UI and schema. Otherwise translators need to translate two different things for what is in fact the same :)

Bojhan’s picture

@martin_q Makes sense, I am not sure if users are able to make this judgement call though. Feels like we are just moving a technology problem, and making it a user problem. It feels better to just keep it a technology problem and see if this is fixed in due time.

martin_q’s picture

Status: Needs work » Needs review
StatusFileSize
new11.67 KB

@Gábor Hojtsy: good call. Thanks for the tip.

@Bojhan: I agree with the principle but in this case I think there's a strong argument for not doing as you suggest.

Whereas: Having a checkbox to permit image capture (and - future potential - sound capture and video capture checkboxes also) for a field is something that (a) we can provide a sensible default for (e.g. for images, only image capture is set to TRUE) and (b) is open to site builders (whom we must credit with some understanding of what they're trying to achieve) and developers to optionally control whether mobile device users are invited to direct-upload an image, a video or an audio clip, if they really want to alter the defaults we give. And we allow them to undo it again if they don't like what they've done.
In contrast: If we just assume the accept attribute should/will soon work with filename extensions, relying on an HTML5 standard that we know is currently incompletely implemented could give all Android-using site visitors (whom we may assume do not always know what they're doing) the poor UX of being invited by their device to submit sound clips for image fields and then having those clips rejected by Drupal's field validation. And neither they nor the site builders and devs have any control over whether that happens. I don't think this is in any sense (other than purely theoretical) a gain over the current proposal.

We could, alternatively, not depend on/assume HTML5's being implemented correctly, but instead use the permitted filename extensions to establish whether audio/video/image capture is appropriate and then set the accept attribute to accept those file types (see code in comment #12). But I suggest this is an advanced step and, to begin with, manually configurable capture settings with sensible defaults will provide the best UX for site visitors and an optimal balance of simplicity and control for site builders and devs.

tstoeckler’s picture

+    // Add mobile device image capture acceptance.
+    if ($field_settings['image_capture']) {
+      $element['#accept'] = 'image/*';
+    }

Seems this part in ImageWidget is the crucial part for enabling this feature for image fields, right? So would it make sense to make this a widget setting instead? It seems this setting is actually not really related to the storing or processing of the field data itself, but purely about input. So it seems a widget setting would fit quite well conceptually.

gábor hojtsy’s picture

StatusFileSize
new133.45 KB

Sidenote: I wanted to go promote this issue and take a shot on my phone to support it, but when the popup appears on my Nexus 5x, it asks me about whether I want to deny or approve the operation it does not let me approve it only deny it. Nothing happens when I tap on approve, the dialog keeps being open. I fully expect that not to be a problem with the patch but some obscure Chrome/Android bug. At least I can confirm it works up to this screen ;)

martin_q’s picture

Status: Needs review » Needs work

@tstoeckler: When you put it like that, I think I agree with you. This really is a widget thing, not a field thing per se. I was really only acting on suggestions and advice I was given during the DDD Milan sprint, and I quickly became overwhelmed with all the things to think about (I'm still new to D8 and there's a lot to pick up all at once). So after initially getting it to work in the widget (see my first patch, on the duplicate issue #2753457: Accept photos from mobile devices directly in image file form widget, I moved it all to the field, which required a schema change, schema update, and tests on the schema update. Moving it back to the widget will make most of that work unnecessary (huh, great use of my time on the sprint! :/ ), but I think you're right nonetheless.

@gabor: Thanks very much for the intention of promoting the issue, and for this testing report! I suspect it is in some way related to the patch, because we still have not ultimately resolved the question of how exactly to implement the HTML specification for the accept attribute and which approach will actually make all/most/some current devices give a good UX. Once this has been moved back to the widget (I'll wait a little longer to see if anyone disagrees with tstoeckler's advice) I'll maybe produce a few different versions of the patch and folks with different phones can test it.

iantresman’s picture

Does the widget approach offer the option of the source of the image? If I'm writing a post and want to add an image, I'd want the option of choosing the source of that image, eg. a file (saved image), perhaps remote URL, and perhaps a camera photo. So I'd want to make sure that a widget does not necessarily preclude other sources.

In this respect, it is similar to FileField Sources.

gábor hojtsy’s picture

Issue tags: +Media Initiaitve
gábor hojtsy’s picture

Issue tags: -Media Initiative, -Media Initiaitve +D8Media

Fixing tags.

rymo’s picture

I'm at DrupalCorn looking at this issue.

rymo’s picture

I spent some time testing permutations of accept and capture attributes here: https://codepen.io/vml-rmott/debug/bZQVLd

On all Android and iOS devices I tested, neither accept nor capture were required to enable the mobile camera for file input; the prompt appears for even the most basic <input type="file"> as far back as Android 4.3. Can someone point to an OS/browser combination where this isn't the case?

For improved user-experience in guiding file type selection (greying out/hiding non-image files), accept="image/*" seems to enjoy broad support in mobile and desktop browsers alike (including IE 11). More specific MIME types such as accept="image/jpeg" mostly work, but the filtering isn't consistent across all browsers.

Support for individual file extensions in accept varies too widely. They work well in many desktop browsers and in mobile Firefox. They're safely ignored in mobile Safari but Chrome on Android skips any accept containing extensions to the extent of negating any useful MIME types that were used in combination as a backup.

I found capture to be useless except for one configuration on Android (no. 8 in the codepen linked above) where it would actually force the user to take a new photo, disallowing access to existing images on the file system. This might be an interesting use-case for some sort of security-related app, but it doesn't belong in core and is definitely not something to have enabled by default.

I recommend removing all use of capture and adding accept="image/*" to the widget. There should be no reason to make it configurable.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

gábor hojtsy’s picture

Issue summary: View changes
StatusFileSize
new109.05 KB

@rymo: thanks for testing on various platforms!

Trying Drupal 8.1.8 as-is on my Android 6.0.1, I get a selection of Camera (take photo), Camcorder (take video) and Documents (browse existing files) on the default image field on articles. That field should clearly not instruct me to record a video as it would not accept that:

I can confirm your suggestion on my phone based on your codepen. Where it says accept="image/*" it does not offer to take video. Where it says accept="image/*" capture it only allows me to take a photo and uploading existing files is not possible. So the later is definitely not what we want I think, but the former is a nice usability improvement, so invalid feature combinations are not offered. Its akin to a telephone field popping up a number keypad or an email field popping up a keypad with an @ and .com on it.

gábor hojtsy’s picture

Title: Option to enable - capture="camera" - for image file field » Image file fields do not limit accepted file types in HTML
Status: Needs work » Needs review
Issue tags: +Needs issue summary update
StatusFileSize
new2.51 KB

So I think based on that, this would be down to the attached patch, which is a subset of the #30 patch from @martin_q.

yoroy’s picture

Issue tags: +Usability
gábor hojtsy’s picture

Category: Feature request » Bug report

Now a bug not a feature.

yoroy’s picture

Manual testing should now confirm that you can not record a video to an image field

gábor hojtsy’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

Updated issue summary with current status.

gábor hojtsy’s picture

Any concerns with the current patch? IMHO its fully ready to get in core, but obviously cannot RTBC myself :)

gábor hojtsy’s picture

Issue tags: +sprint
martin_q’s picture

Well, I'm happy with it. But as it's a subset of my patch, am I able to RTBC it or am I in the same situation as you, @gábor-hojtsy?

manjit.singh’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new77.61 KB
new72.05 KB

I have tested on my android. Here are the before and after screenshots.

sdf

Only local images are allowed.

gábor hojtsy’s picture

Assigned: martin_q » Unassigned
webchick’s picture

Credit.

  • webchick committed b714d00 on 8.3.x
    Issue #2307451 by martin_q, Gábor Hojtsy, Manjit.Singh, Dave Reid,...
webchick’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed to 8.3.x! Thanks a lot for all the great work on this!

xjm’s picture

Issue tags: +8.3.0 release notes

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

gábor hojtsy’s picture

Issue tags: -sprint