IMPORTANTE: esta práctica es OPTATIVA. Ver al final del enunciado el baremo de puntuación.
ACLARACIÓN: J2ME es el antiguo nombre de JavaME, lo veréis todavía referenciado así en muchos libros y artículos (aparte de en esta página :) ).
En esta práctica implementaremos una aplicación J2ME que nos permita capturar imágenes con la cámara del móvil y subirlas directamente a una nueva entrada del blog realizado en prácticas anteriores.
Como en clase se ha visto muy poco sobre J2ME, necesitaréis más información si queréis implementar la práctica. Tened presente que la dificultad de la práctica es que tendréis que aprender J2ME por vosotros mismos. En concreto debéis saber:
Para la realización de esta práctica, además del software utilizado en la anterior práctica, deberemos instalar:
Vamos a realizar una aplicación cliente en J2ME que nos permitirá publicar entradas en el foro, incluyendo como imagen fotografías tomadas con la cámara del móvil. Esta aplicación tendrá un menú principal con las siguientes opciones:
Al pulsar sobre Subir imagen se nos mostrará una pantalla en la que veremos el video capturado por la cámara del móvil. En esta pantalla tendremos dos comandos:
Si se pulsa sobre el comando Cancelar se detendrá el video y se volverá al menú principal. Si se pulsa sobre el comando Capturar foto se nos llevará a una pantalla en la que veremos la imagen capturada y se nos pedirán los datos necesarios para publicar la entrada. Los datos que deberemos introducir son:
En esta pantalla tendremos dos posibles comandos:
NOTA: Al probar la captura de video en un emulador veremos un patrón de rectángulos en movimiento y un contador. En un móvil real si que se vería el video capturado por su cámara.
Para la implementación de la práctica utilizaremos las librerías CLDC 1.0, MIDP 2.0 y MMAPI. Deberemos especificar estas librerías en el buildpath del proyecto de Eclipse (y eliminar de él la librería del JRE) para que no aparezcan errores de código en el editor.
Podemos capturar una imagen utilizando la API Multimedia
(MMAPI) de J2ME. Para ello deberemos crear un reproductor (Player)
que utilice como fuente la cámara del móvil (capture://video):
VideoControl vc;
Player p;
// Crea reproductor
p = Manager.createPlayer("capture://video");
p.realize();
// Crea control de video
vc = (VideoControl)p.getControl("VideoControl");
vc.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, this);
vc.setDisplayLocation(0,0);
vc.setDisplaySize(this.getWidth(), this.getHeight());
vc.setVisible(true);
En este fragmento de código se ha especificado con setDisplaySize
que el tamaño del video capturado se ajuste a las
dimensiones de la pantalla del móvil.
NOTA: En
móviles con pantalla grande se podrían tener
problemas de memoria al capturar la imagen. Por ello es recomendable
utilizar un emulador como el MediaControlSkin.
Para empezar a reproducir el video capturado de la
cámara utilizaremos el método start
del reproductor:
p.start();
Durante la reproducción, podemos capturar el fotograma actual de la siguiente forma:
byte [] datosImagenPng = vc.getSnapshot(null);
Esto nos devuelve los bytes de la imagen en formato PNG (tal como se almacenaría en un fichero).
NOTA: La captura de la imagen es una operación costosa, por lo que siempre deberemos realizarla desde un hilo para no bloquear el hilo de eventos de la aplicación.
Una vez hayamos capturado la imagen de la cámara, deberemos detener la reproducción. Primero detendremos la reproducción de la fuente de video, y a continuación liberamos los recursos:
p.stop();
p.deallocate();
Si queremos mostrar la imagen capturada en la interfaz del
móvil (antes de enviarla al servidor), deberemos crear un
objeto Image a partir de los bytes del PNG:
Image img = Image.createImage(datos,0,datos.length);
Para enviar los datos del cliente al servidor utilizaremos el bloque de contenido del mensaje de petición HTTP. En este bloque de contenido escribiremos toda la información necesaria en binario. En el lado del servidor tendremos un JSP que se encargará de leer este bloque de contenido y creará una nueva entrada a partir de los datos leídos.
En el cliente deberemos definir la dirección del servidor a la que subiremos la imagen y el resto de datos de la entrada. Por ejemplo:
private final static String UPLOAD_URL = "http://localhost:8080/BlogTW/uploadImagen.jsp";
Podemos enviar estos datos al servidor de la siguiente forma:
HttpConnection con = null;
try {
con = (HttpConnection) Connector.open(UPLOAD_URL);
// Envia datos al servidor
DataOutputStream dos = con.openDataOutputStream();
dos.writeUTF(login);
dos.writeUTF(password);
dos.writeUTF(titulo);
dos.writeUTF(texto);
dos.writeInt(imagen.length);
for(int i=0;i<imagen.length;i++) {
dos.write(imagen[i]);
}
dos.flush();
dos.close();
// Recibe respuesta del servidor
if(con.getResponseCode()!=200) {
throw new IOException("Error en la comunicación con el servidor");
}
} finally {
if(con!=null) {
con.close();
}
}
Por otro lado, el JSP en el servidor puede leer los datos codificados con este formato en el bloque de contenido de la petición de la siguiente forma:
DataInputStream dis = new DataInputStream(request.getInputStream());
String login = dis.readUTF();
String password = dis.readUTF();
String titulo = dis.readUTF();
String texto = dis.readUTF();
if(<el usuario (login,password) está registrado>) {
int imgSize = dis.readInt();
byte [] imagen = new byte[imgSize];
for(int i=0;i<imagen.length;i++) {
imagen[i] = (byte)dis.read();
}
<Registrar la nueva entrada en la BD>
String filename = application.getRealPath("/imagenes") + File.separator + <nombre imagen> + ".png";
FileOutputStream fos = new FileOutputStream(filename);
for(int i=0;i<imagen.length;i++) {
fos.write(imagen[i]);
}
fos.flush();
fos.close();
}
El método application.getRealPath("/imagenes")
obtiene la ruta absoluta en el sistema de ficheros correspondiente al
directorio /imagenes relativo al directorio
raíz de nuestro sitio web, suponiendo que las
imágenes del blog se guarden en un directorio con este
nombre. Si tuviese un nombre distinto, se deberá modificar
este fragmento de código para especificar el nombre
correcto. Si el directorio especificado no existiese, nos
daría un error al crear el fichero.
NOTA: Deberemos modificar la aplicación web para que muestre las imágenes PNG (y no las JPEG como hacía anteriormente). Para simplificar podemos asumir que todas las imágenes que se subirán al servidor van a estar en este formato.