JavaScript: tomar foto con cualquier cámara (frontal y trasera)

Publicado por parzibyte en

Introducción

Ya estamos aquí con un tercer post sobre tomar fotos con JavaScript. Este tutorial ofrece una nueva característica y es la de dar al usuario elegir cuál cámara usar para tomar la foto. En los posts anteriores únicamente tomaba de la cámara por defecto, y en algunos navegadores (Chrome, cof cof) no permite cambiar la cámara con la que se toma.

Afortunadamente eso no importa, porque podemos obtener la lista de dispositivos y cambiarlos como se nos dé la gana.

Por cierto, este post está más actualizado; usa constantes, querySelector y otras cosas que los anteriores no. Si bien esto no afecta el funcionamiento, nos da un código más bonito y entendible.

Pero basta de hablar, que hablar es de mal gusto; vamos a ver el código.

Versiones anteriores

En caso de que se me haya pasado explicar algo, puedes revisar las versiones anteriores de este post.

Tomar foto con cámara y JavaScript

Tomar foto con cámara y JavaScript v2

Compatibilidad

Compatible y probado con Edge, Firefox y Chrome en la fecha 22 de octubre del 2018. Puedes probarlo tú mismo y dejar en los comentarios si sigue funcionando (debería hacerlo por mucho tiempo).

En las siguientes imágenes he probado este código en el navegador, cubriendo obviamente mi cámara. Pruébalo tú si quieres y verás que funciona como un encanto.

 

Tomar foto con cámara trasera en Android usando Chrome

Tomar foto con cámara trasera en Android usando Chrome

Tomar foto con JavaScript en Firefox

Tomar foto con JavaScript en Firefox

 

Tomar foto con JavaScript en Edge

Tomar foto con JavaScript en Edge

 

Tomar foto con JavaScript en Chrome

Tomar foto con JavaScript en Chrome

Versión en línea

Como siempre, aquí dejo un link en donde puedes probar el proyecto. Recuerda ignorar las advertencias del navegador y permitir acceso, si realmente no confías simplemente cubre tu cámara.

Por cierto, puedes descargar el código y probarlo en localhost o en un servidor con https.

Código fuente

Si lo deseas, puedes explorar el código de ejemplo en GitHub. Si más tarde hago actualizaciones podrás verlas directamente ahí. El repositorio está aquí.

Aquí está el código del script:

Es casi igual que el anterior, la lógica no cambia mucho.

Listar dispositivos y poder elegir cámara

Para poder listar los dispositivos llamamos a navigator.mediaDevices.enumerateDevices, lo que devuelve una lista de los mismos, que pueden ser micrófonos y otras cosas.

Si te fijas, estamos llamando dos veces a ese método, ¿por qué? bueno, primero lo llamamos para ver si hay algún dispositivo para comenzar el stream, pero para ese tiempo el usuario no ha dado permisos, por lo que este método únicamente devuelve el id de los dispositivos, más no el nombre. Si no nos da el nombre, no podremos llenar el select de una buena manera.

Una vez que el usuario da permisos, volvemos a llamar a ese método para que nos  dé los dispositivos. Como en este caso ya tenemos permisos, también devolverá el nombre de los mismos. Esto es más que nada por la seguridad.

Cuando hay más de un dispositivo, el select los muestra y al cambiarlos se usa esa cámara.

Seleccionar cámara para tomar foto

Seleccionar cámara para tomar foto

Fetch en lugar de XMLHttpRequest

XMLHttpRequest es una API que ya tiene años. Claro, es el estándar y los frameworks que usamos para hacer peticiones AJAX simplemente son una capa que nos permite interactuar con esta API.

Sin embargo, nosotros no estamos usando ningún framework, así que teníamos que usar XMLHttpRequest, pero ya no más, ahora usamos fetch (pronto escribiré sobre ello), ya que estamos explotando las nuevas características de JS.

Silenciar vídeo

En el código HTML también se hicieron cambios. Se movieron algunos elementos pero lo más importante es que se agregó el atributo muted al elemento <video> por las políticas del navegador Chrome (y tal vez todos lo hagan así). Esto no afecta en nada porque nosotros únicamente mostramos vídeo y no audio, pero igual se tiene que especificar.

El código queda así:

Por cierto, puse unos estilos para que en móviles el vídeo ocupe el ancho de la pantalla pero no se pase más allá.

Código PHP

El código se queda intacto, pero aquí lo pego igualmente.

Conclusión

El código se encuentra comentado para explicarse por sí mismo. Si tienes una duda, comentario o sugerencia puedes usar los comentarios.

Te invito a explorar el código en GitHub, recuerda que dejé el link arriba.


parzibyte

He trabajado por más de 4 años en el desarrollo de software con experiencia en Java, PHP, JavaScript, HTML, Node.JS, Python, Android y Go. También he trabajado con bases de datos SQL como MySQL y SQLite, así como con bases de datos NoSQL usando MongoDB.Soy bueno utilizando algunos frameworks y herramientas como Firebase, jQuery, AngularJS, VueJS, CodeIgniter, Laravel, BulmaCSS, Bootstrap y Electron.Otros términos que conozco son: Arduino, GraphQL, API's, REST, AJAX, PouchDB, CouchDB, Experiencia de usuario, buenas prácticas de programación, Webpack, NPM, Administración de servidores y programación de scriptsLa plataforma en la que tengo más experiencia es la web, pero en mis ratos libres realizo unos pequeños ejercicios en C# y C.Estoy aquí para ayudarte a resolver tus problemas de programación y depuración :-)

26 Comments

Luis Fernando · octubre 25, 2018 a las 9:23 pm

Como seria para pasar la imagen tomada a un input de tipo file?

    parzibyte · octubre 26, 2018 a las 12:05 pm

    Hola, no lo sé, sería de investigar aunque no le encuentro utilidad. Si deseas que se envíe como si fuera un formulario usa la API de FormData en donde puedes añadir muchos valores y enviarlos por AJAX

      Dawud · enero 10, 2019 a las 7:10 pm

      Hola, no se puede asignar una imagen a un elemento input file…

        parzibyte · enero 10, 2019 a las 8:06 pm

        No lo sé, pero si se desea que se envíe en el formulario, se podría codificar como base64 y luego asignarlo a un elemento de tipo hidden para más tarde decodificarlo del otro lado

Luis · noviembre 24, 2018 a las 1:57 pm

Gracias por el aporte, consulta como puedo aumentar la resolución de la foto, por defecto lo deja en 640×480, me gustaria fueran unos 800×600 además de hacer un zoom y porque la camara es un “escanner con brazo”, que es realizada es un dispositivo de imagen modificado.

Gracias

    parzibyte · noviembre 25, 2018 a las 9:34 pm

    Hola, no lo sé, pero la resolución depende de la cámara. Lo que podrías hacer sería acercar la imagen o agrandar el vídeo

Alexis · diciembre 11, 2018 a las 8:42 am

Hola tengo una duda si le incluyo dos input tipo text y quiero que el archivo se guarde con lo que ingresé en los cuadro de texto que método debo emplear?

    parzibyte · diciembre 11, 2018 a las 9:23 am

    Hola, crea tu formulario normalmente y añade en él un input de tipo hidden. En los eventos de la cámara, toma el base64 del canvas y ponlo como cadena en el input que mencioné anteriormente; en el lado del servidor simplemente decodifica esa cadena y listo.

Zeusjef · febrero 8, 2019 a las 12:58 pm

hombre, tengo un problema, en pc esta funcionando perfectamente, pero si lo pasamos al móvil no carga y no puedo darle permisos al dispositivo para acceder a la cámara local mente por tu link de ejemplo se puede pero no en mi localhost, no se si tengo que poner certificado o algo quiero que me aclares que es lo que falta para que funciona

sino otro particular de agradecerte tu atención.

    parzibyte · febrero 8, 2019 a las 1:26 pm

    Hola, la página a la que accedes debe ser localhost o una página con HTTPS. Cuando accedes a localhost desde tu PC (la cual actúa como servidor), es localhost; pero cuando accedes desde tu móvil (incluso si es una LAN) accedes a otra IP (la de tu máquina) que no tiene HTTPS ni es localhost así que no tiene acceso. Por otro lado, si accedes al link que yo pongo, sí te lo permite porque tiene HTTPS.
    En resumen, no puedes conectar a otro lugar que no tenga https o no sea “localhost”, puedes instalar un certificado SSL en localhost (cosa que a mi parecer es un poco compleja), rentar un dominio en internet con https o montar directamente la app en el móvil (suponiendo que es Android) como se ve aquí: http://sublime-pos.parzibyte.me/blog/2018/11/14/aplicacion-web-php-mysql-sobre-android/
    Saludos 🙂

      Zeusjef · febrero 14, 2019 a las 9:31 am

      pues sep hombre con un poco de esfuerzo pude lograr hacerlo andar en un servidor local con ssl autofirmados y funciona perfectamente

Daniel · abril 23, 2019 a las 4:54 pm

Hola, he probado el código y en versión PC no hay problema, en Android tampoco pero en IOS no va, usando Safari o el Chrome no deja seleccionar. Me he dado cuenta que es la detención de las cámaras, que no lo hace. Si se quita la opción de las cámaras si funciona. Es IOS 12, ¿ Alguna idea ?

    parzibyte · abril 23, 2019 a las 5:01 pm

    Tendríamos que analizar el mensaje de error que aparece. Me parece raro que no funcione incluso con Chrome, pero como te digo, la única pista que podemos obtener es a través del mensaje de error que lance el navegador. ¿Has dado acceso a los navegadores para acceder a la cámara? (no sé cómo maneja la privacidad iOs por eso pregunto), por otro lado, tal vez sea el propio navegador con eso de los prefijos

      Daniel · abril 23, 2019 a las 5:09 pm

      La cuestión es que no da error, simplemente el cuadro de selección de la cámara aparece vacío y deja sin efecto el botón de “tomar foto”. En Safari y en chrome está habilitado el uso de la cámara y funciona con otros ejemplos pero sólo sin seleccionar cámara, coge la frontal. Además, he quitado navigator.webkitGetUserMedia y detecta y muestra que el navegador no es compatible. He probado con ipod, ipad y iphone y da lo mismo el navegador por lo que interpreto que es del sistema pero no se me ocurre el qué. Gracias

Sisco · abril 30, 2019 a las 3:33 am

Hola, el blog perfecto.
La versión 3 funcionar perfectamente.
Puedes indicarme que debo hacer para que por defecto utilizemos la cámara posterior del móvil.

Gracias

    parzibyte · abril 30, 2019 a las 12:35 pm

    Hola. Los dispositivos están en un arreglo, normalmente el primero es el de la cámara frontal (arreglo[0]) y por lo tanto, en caso de existir, el segundo está en arreglo[1]; basta con tomar el segundo elemento del arreglo en lugar del primero al llamar por primera vez a getUserMedia

      Sisco · abril 30, 2019 a las 1:26 pm

      perfecto, he modificado la línea:
      mostrarStream(dispositivosDeVideo[0].deviceId);
      Al poner un [1] me ha mostrado la cámara trasera.
      Muchas gracias
      Un saludo

Sisco · abril 30, 2019 a las 4:31 am

Hola de nuevo, no veo el comentario que he hecho esta mañana…
Que debo hacer para que salga por defecto la cámara posterior ?

Un saludo y gracias por la información que nos facilitas.

    parzibyte · abril 30, 2019 a las 12:36 pm

    Hola, siento la espera, pero como todo ser humano necesito dormir y como usted se ha de imaginar nadie me paga para mantener el blog, todo lo hago cuando tengo tiempo libre. Saludos 🙂

    Pd: ya respondí la cuestión técnica en su anterior pregunta

emmanuel ramirez · abril 30, 2019 a las 9:13 pm

tengo conectada una cámara FUL HD, pero aun así las fotos salen con poca calidad, como podemos agrandar el tamaño de la imagen para ver si se puede mejorar la calidad.
por cierto, batalle demasiado para que me guardara la imagen una ves tomada, el error me salia en los headers, y esto provocaba un error 403 en el js, la solución es la siguiente:

headers: {
“Content-Type”: ‘text/plain; charset=”utf-8″‘,
“Content-type”: “application/x-www-form-urlencoded”,
}

Saludos un fuerte abrazo

Tomar foto de cámara web con Javascript, actualizado - Parzibyte's blog · octubre 22, 2018 a las 10:21 am

[…] Nota: ya hay una versión 3 de este código. En ese nuevo post explico cómo dar la posibilidad de que el usuario cambie la cámara, además de que introduzco otras mejoras y actualizaciones. Míralo aquí. […]

Tomar foto con Javascript y cámara para guardarla en servidor PHP - Parzibyte's blog · octubre 22, 2018 a las 10:21 am

[…] Nota: ya hay una versión 3 de este código. En ese nuevo post explico cómo dar la posibilidad de que el usuario cambie la cámara, además de que introduzco otras mejoras y actualizaciones. Míralo aquí. […]

Tomar foto de cámara web con JavaScript y descargarla como imagen - Parzibyte's blog · mayo 6, 2019 a las 10:52 am

[…] mi blog he hecho varios posts sobre tomar fotos con la cámara web desde JavaScript, para enviarlas a PHP; pero nunca he hecho un ejemplo sin usar […]

Grabar vídeo de cámara con JavaScript - Parzibyte's blog · junio 3, 2019 a las 5:57 pm

[…] través del tiempo hemos visto cómo tomar fotos con JavaScript (así como enviarlas a un servidor con PHP) y cómo grabar el audio del micrófono (o guardarlo en un […]

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

A %d blogueros les gusta esto: