Curso Android: Trabajado con imágenes (cámara y galería)
En el primer capítulo del curso aprendimos a construir un lector de feeds simple; el segundo capítulo fue sobre UI en Android y aumentar la funcionalidad de un lector de feeds; en el tercer capítulo trabajaremos con el hardware de los teléfonos y empezaremos con el manejo de la cámara.
Mostrar una imagen de la cámara o de la galería
La aplicación que realizaremos nos permitirá mostrar una imagen, podemos obtenerla desde la cámara o desde la galería del teléfono. Queremos que al finalizar se vea así:
Con una imagen cargada se verá de la siguiente forma:
Disposición inicial
Empezaremos descargando el código que debe importarse hacia un proyecto nuevo. Trabajaremos sobre un teléfono con Android y cámara para desarrollar el ejemplo de este artículo. Para el deployment hacia el teléfono es necesario que el sistema operativo lo reconozca y además debe colocarse en el manifest como una propiedad de la etiqueta <application>
el valor android:debuggable="true"
.
La etiqueta debe lucir de la siguiente forma:
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
En la parte de diseño vamos a empezar con un RelativeLayout
, el archivo /res/layout/main.xml
debe estar así:
<!--?xml version="1.0" encoding="utf-8"?-->
Diseño
Trabajaremos con otra disposición de elementos para el diseño llamado RelativeLayout
y agregaremos otros elementos de interfaz de usuario.
- RelativeLayout: con este esquema los elementos se colocan en posición relativa a otros elementos o hacia el padre.
- RadioButton: es un botón de dos estados (marcado y des-marcado) a diferencia del CheckButton este no permite des-marcarlo y cuando se encuentra en grupo solo uno de los botones del grupo puede estar marcado a la vez.
- RadioGroup: permite agrupar un conjunto de RadioButtons para que solo uno a la vez esté seleccionado.
Nuestro diseño tendrá un botón para adquirir la imagen un RadioGroup que contendrá a 3 botones y un ImageView. Los 3 botones serán seleccionar de donde proviene la imagen ya sea de la cámara (como vista previa o como imagen completa) o de la galería.
El código completo del layout es el siguente:
<!--?xml version="1.0" encoding="utf-8"?--> <button> </button>
Hemos orientado el botón hacia la derecha y el RadioGroup hacia la izquierda. Luego el ImageView abajo del RadioGroup.
El diseño de interfaces de usuario en ocasiones se vuelve complicado con eclipse por ello utilizaremos la herramienta gratuita DroidDraw que permite exportar e importar archivos XML para luego solo colocarlos en el archivo de diseño en eclipse, además tiene ejecutables para Windows, Linux y OS X.
Agregando código para funcionalidad
Definimos 3 constantes, con dos de ellas vamos a identificar la acción realizada (tomar una fotografía o bien seleccionarla de la galería) y con la otra estableceremos un nombre para el archivo donde escribiremos la fotografía de tamaño completo al tomarla.
private static int TAKE_PICTURE = 1; private static int SELECT_PICTURE = 2; private String name = "";
La forma más sencilla de tomar fotografías es utilizar un intent con ACTION_IMAGE_CAPTURE
, acción que pertenece al Media Store y luego sobrecargar el método onActivityResult
para realizar algo con el archivo recibido de la cámara.
Dentro del método onCreate
asignaremos a la variable de instancia name y luego vamos a trabajar sobre la acción al click del botón. Este nombre, inicializado con una llamada a getExternalStorageDirectory()
guardará un archivo en la tarjeta SD del teléfono y el archivo se llamará test.jpg
cada vez que grabemos una fotografía de tamaño completo se sobre escribe.
name = Environment.getExternalStorageDirectory() + "/test.jpg"; Button btnAction = (Button)findViewById(R.id.btnPic); btnAction.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ... } } }
Primero obtenemos los botones de imagen completa y de galería para revisar su estatus más adelante. Luego construimos un intent que es necesario si accesamos la cámara con la acción ACTION_IMAGE_CAPTURE
, si accesamos la galería con la acción ACTION_PICK
. En el caso de la vista previa (thumbnail) no se necesita más que el intent, el código e iniciar la Activity correspondiente. Por eso inicializamos las variables intent y code con los valores necesarios para el caso del thumbnail así de ser el botón seleccionado no validamos nada en un if.
RadioButton rbtnFull = (RadioButton)findViewById(R.id.radbtnFull); RadioButton rbtnGallery = (RadioButton)findViewById(R.id.radbtnGall); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Asignamos el código a tomar fotografía, este código junto al intent se utilizarán adelante para iniciar la Activity.
int code = TAKE_PICTURE;
Si el chequeado es el botón de vista previa no necesitamos agregar nada más. Si el chequeado es el botón de imagen completa, además del intent y código agregamos un URI para guardar allí el resultado. Si el chequeado es el de la galería necesitamos un intent y código distintos que asignamos en la consecuencia del if.
if (rbtnFull.isChecked()) { Uri output = Uri.fromFile(new File(name)); intent.putExtra(MediaStore.EXTRA_OUTPUT, output); } else if (rbtnGallery.isChecked()){ intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI); code = SELECT_PICTURE; }
Luego, con todo preparado iniciamos la Activity correspondiente.
startActivityForResult(intent, code);
Además, es necesario sobrecargar la función onActivityResult
para indicar que queremos hacer con la imagen recibida (ya sea de la cámara o de la galería) una vez ha sido seleccionada. Es necesario revisar si la imagen viene de la cámara TAKE_PICTURE
o de la galería SELECT_PICTURE
.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == TAKE_PICTURE) { … } else if (requestCode == SELECT_PICTURE){ … } }
Si viene de la cámara, verificamos si es una vista previa o una foto completa:
if (data != null) { … } else { … }
En el caso de una vista previa, obtenemos el extra “data” del intent y lo mostramos en el ImageView
:
if (data.hasExtra("data")) { ImageView iv = (ImageView)findViewById(R.id.imgView); iv.setImageBitmap((Bitmap) data.getParcelableExtra("data")); }
En el caso de una fotografía completa, a partir del nombre del archivo ya definido lo buscamos y creamos el bitmap para el ImageView
:
ImageView iv = (ImageView)findViewById(R.id.imgView); iv.setImageBitmap(BitmapFactory.decodeFile(name));
Si quisiéramos incluir esa imagen en nuestra galería, utilizamos un MediaScannerConnectionClient.
new MediaScannerConnectionClient() { private MediaScannerConnection msc = null; { msc = new MediaScannerConnection(getApplicationContext(), this); msc.connect(); } public void onMediaScannerConnected() { msc.scanFile(fileName, null); } public void onScanCompleted(String path, Uri uri) { msc.disconnect(); } };
Si viene de la galería recibimos el URI de la imagen y construimos un Bitmap a partir de un stream de bytes:
Uri selectedImage = data.getData(); InputStream is; try { is = getContentResolver().openInputStream(selectedImage); BufferedInputStream bis = new BufferedInputStream(is); Bitmap bitmap = BitmapFactory.decodeStream(bis); ImageView iv = (ImageView)findViewById(R.id.imgView); iv.setImageBitmap(bitmap); } catch (FileNotFoundException e) {}
Si estamos utilizando la cámara la vista será de la siguiente forma:
Si estamos capturando de la galería será así:
Descarga:
Puedes descargar el código de la aplicación completa y funcional en: Trabajado con imágenes (cámara y galería).
Conclusión
- RelativeLayout, RadioButton y RadioGroup: aprendimos cómo pueden acomodarse componentes ubicándolos en el diseño con posiciones relativas con respecto a otros componentes y también los controles necesarios para el manejo de radio buttons y su agrupación.
- Utilización de intents para utilizar la cámara y accesar la galería: se utilizaron intents para realizar acciones específicas, la existencia de intents para acciones comunes predefinidas nos facilitan muchas tareas, en este caso no fue necesario accesar directamente el hardware de la cámara si no pudimos tomar una fotografía de una manera más sencilla. Algo similar sucede con el acceso a la galería de fotos.
- Utilización de la cámara de fotos: a través de un ejemplo sencillo, aprendimos como utilizar parte del hardware del teléfono. A partir de aquí podemos trabajar los imagénes guardadas y modificarlas o utilizarla para lo que nos interese.
Muchas gracias por esta aportación, la verdad que es muy interesante esta parte del tratamiento de imagenes y uso de camara.
[…] Trabajar con imágenes (cámara y galería) […]
esta muy bien gracias por estos aportes que nos hacen son muy buenos.
Buenas!! muchas gracias por los manuales son muy intuitivos y perfectamente explicados. Mi comentario viene a una duda que me surge y no se si me pasa sólo a mí o a todo el mundo, he realizado toda la tarea tal como se explica, pero a mi no me crea la foto con el nombre “test.jpg”, sino que pone el nombre que por defecto en mi caso IMAG0039.jpg, antetodo decir que soy un novato en programación android y no se si es una duda o directamente mi ignorancia en el tema.
Saludos y muchas gracias de antemano
Muchas gracias por el articulo, el ejemplo es simple y claro.
Me quedan 1 duda, luego de tomar al foto la aplicacion cambia su orientacion y no puedo volver a la inicial.
Desde ya muchas gracias
Hola, lo primero agradecerte por tu artículo.
Quería comentarte que sólo me aparece la imagen en el ImageView cuando la selecciono de la galería, si selecciono las otras dos opciones no, a menos que vuelva a iniciar la cámara y vuelva a atrás. ¿La única diferencia entre las dos primeras opciones es que al tomar la imagen completa se te guarda? Porque al tomar la foto me da opción de guardarla igualmente.
Saludos y gracias de nuevo
SAUDOS.
SI ME PODRIAS ENVIAR EL CODIGO FUENTE DE ESTOS EJEMPLOS A MI CORREO.
TE LO AGRADECERIA.
SALUDOS Y GRACIAS
Hola, muchas gracias por tus ejemplos, no veas el bien que haceis para los que estamos empezando.
A los que tienen dudas, seguno lo que he visto yo:
patrulleroo: a mi me pasaba lo mismo. Lo que he hecho, ha sido cambiar la ruta donde guarda las imagenes. En vez de cogerla de la variable de entorno, la pongo yo “/sdcard/DCIM/camara/test.jpg” y asi aparece.
Martin: cuando cambias la orientacion de la pantalla, creo que la activity se inicia otra vez, asi que las variables donde estan las imagesnes desaparecen.
florencio: lee un poco….
hola y felicitaciones por el tutorial, tengo una duda, si yo kiero tomar una foto y kiero ke el tamanio de la foto sea de 125X125 px como se podria hacer??? gracias por tu tiempo