Buscar

Tratando Imagens em Java

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 3 páginas

Prévia do material em texto

Trabalhando com Imagens
Escrito por Vinícius Godoy de Mendonça
10 people like this. Be the first of your friends.Like
Nos artigos passados, vimos como desenhar imagens através de comandos de pintura. Entretanto, geralmente, não é o programador que desenha imagens, e sim, um artista
num software de pintura qualquer. Nesse artigo, vamos ver como trabalhar com essas imagens, gravadas em disco.
Carregando imagens
O primeiro passo para usar qualquer imagem, obviamente, é carrega­las do disco. O Java oferece duas maneiras de se fazer isso, através da carga indireta, assíncrona e
através da carga direta, síncrona.
Carga assíncrona
Com a carga assíncrona, comandamos o Java para que carregue uma imagem. Uma thread secundária é disparada para realizar esse trabalho, fazendo com que o método de
leitura retorne imediatamente. Não poderemos usar a imagem logo em seguida, pois ela pode não estar na memória. Para sabermos o momento em que ela foi completamente
carregada, temos que registrar umImageObserver, ou utilizar da interface MediaTracker. O código abaixo demonstra um exemplo:
Carga síncrona
Embora a carga assíncrona seja adequada para aplicações, sobretudo applets, ela não é adequada para jogos. Em quase 100% dos casos, iremos precisar ter certeza de que a
imagem foi carregada, antes de exibi­la. Com a carga síncrona o java carregará uma imagem, e só retornará quando ela estiver integralmente carregada. Fazemos a carga
síncrona através da classe ImageIO:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Disparamos a carga da imagem. O objeto Image representa a imagem sendo carregada.
//Esse método retorna imediatamente.
Image image = Toolkit.getDefaultTookit().getImage(fileName);
 
 
//Criamos um MediaTracker para aguardar a carga. O parâmetro this representa um componente, 
//que pode ser o frame ou o applet onde o tracker está.
MediaTracker mt = new MediaTracker(this);
 
//Registramos a imagem com id 0. 
mt.addImage(image, 0);
//Esperamos ela carregar. Poderíamos registrar várias imagens,
//e também chamar o método waitForAll(), para carregar todas. 
try { 
   mt.waitForId(0); 
} catch (InterruptedException e) { }
1
2
3
4
try {
   BufferedImage image = ImageIO.read(new File(fileName));
} catch (IOException e) {
}
?
?
Note que o tipo retornado agora é um BufferedImage, não simplesmente um Image. O BufferedImage é uma classe filha de Image que representa uma imagem carregada na
memória. A grande diferença das duas é que o BufferedImage irá permitir a manipulação da imagem. Carregar imagens através da classe ImageIO é a forma recomendada pela
Sun atualmente.
Desenhando a imagem
Você já viu nos artigos anteriores como trabalhar com a classe Graphics. Como você já deve ter deduzido, existem métodos por lá para desenhar a imagem. Uma das coisas
mais interessantes, é que o Java não disponibiliza um, mas sim, dezenas de métodos para isso. Veremos dois dos mais importantes. Os outros, são derivações destes.
O primeiro, e mais simples, é quando queremos desenhar uma imagem num local específico da tela.
Simplesmente passamos a imagem, duas coordenadas e, opcionalmente, um ImageObserver. Essa interface é útil para quando usamos carga assíncrona, e não carregamos a
imagem através do media tracker. O método draw() irá esperar até que a imagem esteja desenhada, para então disparar um evento nos avisando que a pintura terminou. Essa
técnica é adequada em aplicações, onde esperar pela carga da imagem no momento da pintura não é um problema. Não é o caso dos jogos. Como já teremos carregado nossa
imagem com um MediaTracker, ou teremos usado o ImageIO, podemos passar null nesse parâmetro.
O segundo método de pintura, permite­nos desenhar apenas uma parte da imagem:
Nesse método, fornecemos a imagem, 4 coordenadas no destino (dst) e 4 na origem (src). O Java irá pintar só a porção determinada por essas coordenadas, fazendo a escala
para que ela encaixe no destino. Por exemplo, se as coordenadas de origem forem (0,0)­(10,10) e a de destino forem (0,0)­(25,25), a imagem será redimensionada. Esse
método é útil para criarmos, por exemplo, uma única imagem com várias partes de uma animação, e desenharmos apenas uma parte por vez no programa.
Desenhando sobre uma imagem
Um dos recursos mais bacanas da API do Java 2D, é que é extremamente fácil desenhar sobre uma imagem. Todo BufferedImage é também uma área de pintura. Podemos criar
um BufferedImage em branco e desenhar sobre ele, ou mesmo desenhar sobre uma imagem carregada. Para isso, usamos o método createGraphics(), que retorna um objeto do
tipo Graphics2D. A partir daí, basta desenhar na imagem como faríamos na tela.
No artigo anterior, comentei que o desenhar diretamente no Java 2D, sobretudo quando se usa antialiasing e GradientPaint pode ser uma tarefa bastante custosa. Agora, e se
fizéssemos esses comandos de desenho uma única vez, e guardássemos o resultado numa BufferedImage? Os desenhos seguintes seriam feitos diretamente através da
imagem, sem envolver cálculos de antialising, escala, rotação, preenchimento ou texturas. De fato, fazer isso é possível, e até bastante fácil:
1
2
3
boolean Graphics.drawImage(Image img, 
                           int x, int y,
                           ImageObserver observer);
1
2
3
4
boolean Graphics.drawImage(Image img,
                           int dstx1, int dsty1, int dstx2, int dsty2,
                           int srcx1, int srcy1, int srcx2, int srcy2,
                           ImageObserver observer);
1
2
3
4
5
6
7
8
9
10
11
//Criamos uma imagem de 80x100 pixels
BufferedImage ghost = new BufferedImage(
 80, 100, BufferedImage.TYPE_INT_ARGB);
 
//Obtemos o contexto gráfico dessa imagem
Graphics2D g2d = ghost.createGraphics();
 
//Desenhamos nela o fantasma do artigo anterior :)
new Ghost().draw(g2d);
 
//Liberamos o contexto.
?
?
?
Após esse código, poderíamos simplesmente desenhar a imagem definida na variável ghost, quantas vezes quiséssemos. Isso permite manter a qualidade do desenho ao
mesmo tempo que mantemos a velocidade de pintura na hora do jogo propriamente dito.
Salvando a imagem no disco
O método ImageIO.write é responsável por salvar a imagem no disco. Devemos passar para o método a imagem a ser salva, o formato do arquivo e o nome. O Java se
encarregará de fazer a conversão do formato da BufferedImage para o formato de saída, podendo haver perdas nesse processo. Uma imagem com transparência, por exemplo,
poderá ficar com fundo branco se for gravada num formato que não suporte transparência. Da mesma forma, imagens do tipo JPG geralmente são geradas com uma taxa de
compactação alta e podem apresentar distorções.
Gravar imagens no disco pode ser uma técnica interessante para criar caches, e evitar penalizar o jogador com operações caras como redimensionamento e desenho toda vez
que o jogo é carregado. A assinatura do método é a seguinte:
A classe BufferedImage implementa a interface RenderedImage. O boolean retornado pelo método indica se um writer para aquele formato foi encontrado ou não. Para os
formatos descritos abaixo, o retorno true é garantido. Outros formatos podem ser instalados através da APIs externas.
Formatos de imagem suportados
O Java suporta uma série de formatos de imagem. Abaixo, uma breve descrição dos principais:
Bitmaps (BMP): É o formato, de longe, mais rápido de ser carregado e pintado. Porém, não suporta transparência e por não conter compactação, gera arquivos de imagem
de tamanho grande.
JPG: Possui compactação do tipo lossy, ou seja, pode haver perda de qualidade se a compactação for muito agressiva. Por outro lado, mesmo numa taxa baixa de
compactação já apresenta um tamanho de arquivo consideravelmente menor que o bitmap. Também não suporta transparência.
GIF: Suporta transparência e vários tipos de compactação. Também suporta que várias imagenssejam gravadas no mesmo arquivo, e sejam exibidas na forma de
animação em browsers.
PNG: Equivalente ao GIF, mas a compactação geralmente é sem perdas. Como é um formato livre, foi extremamente otimizado na API do Java, e é o formato com
transparência recomendado pela Sun.
Concluindo
Nesse artigo, vimos de maneira bem prática e direta como carregar e manipular imagens em Java. Só com o que foi visto, já é possível desenhar qualquer cena do jogo. Sugiro
que você tente fazer um programa que carregue algumas imagens, para exercitar o que foi visto.
11
12
//Liberamos o contexto.
g2d.dispose();
1
2
3
static boolean ImageIO.write(RenderedImage im,
                             String formatName,
                             File output) throws IOException
?

Continue navegando