[RESOLVIDO] Tamanho, qualidade e profundidade de cor de uma JPEG

5 respostas
GabrielGarcia

Bom dia a todos.

Tenho um problema com gravação de imagem JPG que ainda não consegui resolver. Eu tiro uma screen da tela e envio da máquina cliente até a máquina servidor pela Internet, porém, notei que está meio lento para atualizar as telas, e descobri que as imagens geradas estão muito grandes (em kb).

Uma imagem JPG, de 1024x768, em 256 cores com 70% de qualidade está girando em torno de 100KB (inviável).

Mesmo com o programa enviando telas apenas quando a screen tirada pelo robot for diferente da screen anteriormente enviada, ainda fica lento.

Tenho o seguinte código:

Rectangle screenSize = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage screen = robot.createScreenCapture(screenSize);
BufferedImage bimage = new BufferedImage(screenSize.width, screenSize.height, preferencias.getQualidadeCor());
Onde qualidade cor pode ser
byte qualidadeCor = BufferedImage.TYPE_BYTE_INDEXED //256 Cores
byte qualidadeCor = BufferedImage.TYPE_BYTE_GRAY //Tons de Cinza

Após obter esta BufferedImage, eu crio ela com a qualidade desejada assim

public static void createJPG(BufferedImage image, OutputStream out, float quality) throws IOException {

     Iterator jpgWriter = ImageIO.getImageWritersBySuffix("jpeg");
     ImageWriter imageWriter = (ImageWriter) jpgWriter.next();
     ImageOutputStream ios = ImageIO.createImageOutputStream(out);
     jpgWriter.setOutput(ios);
     ImageWriteParam imgParam = jpgWriter.getDefaultWriteParam();

     imgParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
     imgParam.setCompressionQuality(quality);

     jpgWriter.write(null, new IIOImage(image, null, null), imgParam);
}

onde quality é

Float quality = new Float(7 / 10.0f)

Depois, envio esta imagem, que é um byte[], em um byte[] comprimido em ZIP. Mesmo com compressão máxima, a imagem não muda muito de tamanho. Consigo uma compressão de no máximo 10%.

Minha pergunta é:

- Existe a possibilidade de gravar uma imagem JPG entre 60-70% de qualidade, com 256 cores (pode até ser menos, só preciso mesmo é "ver" a tela do computador monitorado) e que fique com um tamanho mais "aceitável"?

Pensei em redimensionar para enviar, mas a imagem fica muito pequena.

A imagem precisa ser pequena (em kb) e não precisa ter qualidade, portanto, não há necessidade de trabalhar com Antialiasing, Blur, etc, etc.

Tentei até mesmo usar o depreciado JPEGEncoder, mas é lento que chega a dar dó.

Alguma dica?

5 Respostas

victorcosta

Ja pensasse em salvar a imagem em PNG? JPEG eh mais adequado pra fotos reais

Salvei meu desktop aqui (1440x900), converti pra preto e branco e PNG de 256 cores no GIMP e deu 60kb. O melhor eh que PNG nao perde qualidade nenhuma. Voce pode ate tentar salvar a imagem em tamanhos menores pra diminuir mais ainda o tamanho

So evite wallpapers no desktop e etc, pq ai PNG nao se da muito bem, a especialidade dele eh imagems sem muita variacao de cores, tipo uma imagem com quadrados cada um com uma unica cor. Se tiver fotos, degradês, ai vai ter q diminuir o numero de cores pra algo bem baixo tipo 4-16 pra ficar um tamanho aceitavel

GabrielGarcia

Obrigado pela resposta victorcosta, mas o Java parece gravar as PNGs com tamanho maior que a JPEG.

Basicamente, este programa é um VNC, onde o dono do estabelecimento poderia, a qualquer momento, interagir no PC do funcionário.

Fiz um código bem enxuto para isto. Meus eventos de mouse, por exemplo, só enviam cliques. mousePressed em XY e mouseReleased em X+10Y-90 seria um drag. Nem mesmo a movimentação da seta eu envio.

Pensei ser este o culpado, mas vi que a imagem é que está me passando a perna.

Mas enfim, tive uma idéia e gostaria de pedir outra dica agora:

  • Pensei em dividir a tela decorrente do screenshot em 6 setores, calculados pelo tamanho do desktop do PC monitorado.
  • Ao mudar a tela, eu iria apenas enviar o setor que sofreu modificações nos seus pixels, e “colar” este setor enviado na tela do visualizador por cima do setor alterado.
  • Não pode ser transmissão síncrona, por isso corro o risco de não ter um setor atualizado caso o pacote se perca

Pergunta: Graphics2D seria a melhor maneira de gerar os setores e fazer a comparação?

Imagino que deva ficar meio lento esta comparação.

  • Tira screen A
  • Tira screen B
  • Sccreen B é diferente de A
  • Percorre os (digamos) 6 setores de A e os compara com os 6 setores de B
  • Avalia qual sofreu modificação
  • Envia setor modificado

Seria uma boa saída ou não?!?!?!

Abraço

T

http://www.tightvnc.com/doc/java/README.txt - no seu caso, provavelmente você teria de habilitar um túnel ssh para usar o protocolo vnc de forma segura.

GabrielGarcia

Vou dar uma lida neste Readme, mas eu já posso te adiantar que a conexão estabelecida entre as máquinas é feita usando SSH.

Malditas imagens que não cooperam :stuck_out_tongue:

Se não conseguir um encode com tamanho menor, vou tentar usar a idéia dos setores.

GabrielGarcia

Respondendo para não deixar o tópico sem uma “finalização”.

O tamanho final da imagem não tem como ficar menor.

A tela inteira em PNG fica menor que do que em JPG, mas mesmo assim, com tamanho não aceitável.

Acabei dividindo a imagem da screenshot em 8 subImages e enviando apenas a subImage modificada. Escolhi o formato JPG, pois as subImages em JPG ficaram menores do que em PNG, e como 95% do tráfego vai ser de subImages, optei por este formato.

Era isto.

Obrigado aos que despenderam seu tempo dando dicas.

Abraço

Criado 23 de junho de 2009
Ultima resposta 24 de jun. de 2009
Respostas 5
Participantes 3