Foro de elhacker.net

Programación => Java => Mensaje iniciado por: Proteus1989 en 31 Marzo 2012, 03:13 am



Título: La clase BufferedImage
Publicado por: Proteus1989 en 31 Marzo 2012, 03:13 am
He desarrollado una aplicación que captura la pantalla de un PC y mediante sockets la envía a un segundo ordenador.
La aplicación en sí funciona perfectamente. A través de los sockets envío como cadena de bytes la imagen capturada y en el receptor recompongo esa información para mostrarla por la pantalla.

El problema es el siguiente, en 1080x1920 la pantalla consta de 2073600 pixeles. Estos pixeles se encuentran dentro de un objeto BufferedImage y los convierto en un array de enteros de 4 bytes de tamaño 2073600.
Una vez obtengo el array de enteros transformo cada entero en 4 bytes, añadiendolo finalmente a un array de tamaño 2073600*4 para enviarlo por el socket.

Total que al final me encuentro con un array de 8MB para enviar por el socket.

Entonces mi pregunta es obvia, ¿como hago para reducir ese tamaño tan exagerado a algo más asequible como por ejemplo 500 kb.


Título: Re: La clase BufferedImage
Publicado por: raul_samp en 15 Abril 2012, 04:07 am
Pues en los algoritmos de compresión con perdida (que son los que se usan para imágenes como JPEG) hay muchas matemáticas de por medio. Pero si quieres algo ya implementado creo que la clase que buscas es ImageWriteParam
o algo por el estilo. Échale un vistazo al Api y ya nos cuentas si te sirve.

Api JDK6 ImageWriteParam: http://docs.oracle.com/javase/6/docs/api/javax/imageio/ImageWriteParam.html (http://docs.oracle.com/javase/6/docs/api/javax/imageio/ImageWriteParam.html)


Título: Re: La clase BufferedImage
Publicado por: Proteus1989 en 15 Abril 2012, 14:43 pm
Ya pensaba que nadie sabía responderme. Lo miraré, tenlo por seguro.
Gracias!


Título: Re: La clase BufferedImage
Publicado por: Proteus1989 en 19 Abril 2012, 00:57 am
He estado mirando la clase pero no la termino de comprender, como le pasaría mi array de enteros para que me lo comprimiese?


Título: Re: La clase BufferedImage
Publicado por: raul_samp en 24 Abril 2012, 23:18 pm
Aquí te lo explican, y no es por trolear :rolleyes: pero Google no muerde.

http://www.universalwebservices.net/web-programming-resources/java/adjust-jpeg-image-compression-quality-when-saving-images-in-java (http://www.universalwebservices.net/web-programming-resources/java/adjust-jpeg-image-compression-quality-when-saving-images-in-java)


Título: Re: La clase BufferedImage
Publicado por: Proteus1989 en 25 Abril 2012, 18:57 pm
Encontré esto, pero era con jpgs http://www.exampledepot.com/egs/javax.imageio/JpegWrite.html
El problema es que el uso de disco duro no es eficiente.

PD: Lo encontré con el google, que se que no muerde xD


Título: Re: La clase BufferedImage
Publicado por: raul_samp en 26 Abril 2012, 13:57 pm
Si a lo que te refieres es que no te renta guardarlos en disco para luego mandarlo, lo veo normal xD, y ahora mismo no se decirte así como se programaría exactamente, me tendría que poner a programar, pero la idea supongo que seria algo así como decirle al ImageWriter que su Output es el mismo que el del socket.

Ya te digo que no estoy muy seguro de que sea exactamente así, habría que profundizar la idea en el API, si no es mucho código y quieres subirlo para que le echemos un vistazo lo haré encantado.

Un saludo!!


Título: Re: La clase BufferedImage
Publicado por: Proteus1989 en 26 Abril 2012, 18:56 pm
Exacto, el tener que guardarlos y recuperarlos del HDD es demasiado costoso. El código es algo extenso (sobre unas 7 u 8 clases), quizás demasiado para lo que aquí interesa resolver.

Emisor
Este código recupera una captura de pantalla que transforma a int[] para enviarla por el socket.
Código
  1. int ancho = (int) java.awt.Toolkit.getDefaultToolkit().getScreenSize().getWidth();
  2. int alto = (int) java.awt.Toolkit.getDefaultToolkit().getScreenSize().getHeight();
  3. v = new int[ancho*alto];
  4. dataBuffer = robot.createScreenCapture(rectangulo).getData().getDataBuffer(); //Captura la pantalla
  5. for(int i = 0; i < ancho*alto; i++)
  6. v[i] = dataBuffer.getElem(i);
  7.  



Receptor
Se encarga de recibir el int[] y recomponerlo.
Código
  1.  
  2. // Creo un ByteBuffer donde añado v (byte[])
  3. // v es el int[] que envié y que recibo en forma de 4 bytes por int.
  4. ByteBuffer bb = ByteBuffer.allocate(v.length);
  5. bb.put(v);
  6. bb.order(ByteOrder.BIG_ENDIAN);
  7. bb.rewind();
  8.  
  9. // Ahora transformo ese ByteBuffer en un IntBuffer
  10. IntBuffer ib = bb.asIntBuffer();
  11. int[] result = new int[v.length / 4];
  12. ib.get(result);
  13. BufferdedImage imagen = generarBufferedImage(result); //este método está implementando en el código de abajo.
  14.  



Y con este último código copiado de internet y que no comprendo muy bien recupero el BufferedImage inicial

Código
  1. private BufferedImage generarBufferedImage(int[] v)
  2. {
  3. DataBufferInt DB = new DataBufferInt(v, (resolucion.getAncho() * resolucion.getAlto()), 0);
  4. int[] BM = new int[]
  5. { 0xff0000, 0xff00, 0xff };
  6. SinglePixelPackedSampleModel SM = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, resolucion.getAncho(), resolucion.getAlto(), BM);
  7.  
  8. // creating the raster
  9. Point P = new Point(0, 0);
  10. WritableRaster R = Raster.createWritableRaster(SM, DB, P);
  11. BufferedImage bi = new BufferedImage(resolucion.getAncho(), resolucion.getAlto(), BufferedImage.TYPE_INT_RGB);
  12. BufferedImage BI = new BufferedImage(bi.getColorModel(), R, false, null);
  13. return BI;
  14. }
  15.  


Título: Re: La clase BufferedImage
Publicado por: raul_samp en 27 Abril 2012, 13:02 pm
La verdad no se si esto es una paja mental muy grande pero podrías intentar partir de esta idea a ver que sale:

Código
  1. BufferedImage buffer = robot.createScreenCapture(rectangulo);
  2.  
  3. try {
  4. out = new GZIPOutputStream(socket.getOutputStream());
  5. ImageIO.write(buffer, "jpg", out);
  6. } catch (IOException e1) {
  7. e1.printStackTrace();
  8. }finally{
  9. if(out != null)
  10. out.close();
  11. }
  12.  

La intención esta clara, es usar un flujo de salida comprimido desde el emisor y descomprimir en el receptor con un GZIPInputStream.

A mi me parece que algo así tendría que funcionar, no se si ves que no coméntanos a ver cual es el problema y que más podemos hacer. Ya te digo que es lo primero que se me ha ocurrido  :D


Título: Re: La clase BufferedImage
Publicado por: Proteus1989 en 29 Abril 2012, 13:15 pm
Parece no funcionar. El GZIP no deja apuntar al OutputStream ni casteandolo