Informática Numaboa - Tutoriais e Programação
Applet Espelhando Imagens
Sex 10 Abr 2009 21:41 |
- Detalhes
- Categoria: Aprenda Java fazendo applets
- Atualização: Sexta, 10 Abril 2009 22:43
- Autor: vovó Vicki
- Acessos: 7268
O espelhamento de imagens é um efeito interessante e muito fácil de ser obtido quando as ferramentas certas são utilizadas. Neste caso, o conhecimento e o domínio do método copyArea é essencial para obter o resultado desejado, portanto, a leitura de Os segredos de copyArea é altamente recomendada.
Objetivo do projeto
- Criar e controlar threads
- Entender a estrutura de matrizes
- Trabalhar com a interface gráfica
- Trabalhar com o MediaTracker
- Criar mensagens na barra de status
- Criar efeitos gráficos interessantes
O código Java
O applet funcionando
O código Java foi compilado para um arquivo de bytecodes de nome espelhoImg.class. Crie um documento HTML e insira este applet. A altura e a largura do applet devem ser a altura e a largura da imagem que deve ser espelhada. O resultado é o seguinte:
Aproveite e dê uma olhada no rodapé do seu browser. Lá você poderá ver a sequência da cópia das colunas de pixels.
Explicações que podem ser úteis
Há algumas novidades neste applet além do uso do método copyArea: usamos a interface gráfica de um objeto Image para atualizá-la antes de mostrá-la na janela do applet, um objeto MediaTracker para monitorar a leitura de uma imagem e usamos operadores de deslocamento bit-a-bit.
A declaração da classe
Precisamos apenas dos pacotes java.applet.* e java.awt.*. Este applet também é Runnable, quer dizer, o applet vai conter um método run que irá gerenciar o seu comportamento. Para isto criamos um thread adicional. Se você ainda não leu O que são threads e como domá-los, aproveite a oportunidade agora. Neste ponto, o tutorial Brincando com Cores também é uma boa pedida. O thread para controlar o comportamento do applet é declarado como Thread linha = null e boolean vivo = true o acompanha.
Além disto, declaramos um objeto Image origImg = null e int larg (largura da imagem) e int alt (altura da imagem).
O método init()
No método init() lemos o parâmetro "imagem" e atribuímos seu valor à variável local String s. Se s não for null, temos o nome do arquivo que contém a imagem desejada. Instanciamos então o objeto Image img, o qual conterá a imagem gráfica. Se o arquivo mencionado não existir, img será igual a null e as linhas seguintes não serão executadas.
De posse da imagem, criamos o objeto MediaTracker mt (do pacote AWT). O MediaTracker permite monitorar e controlar o carregamento de objetos de mídia (imagens e sons), mas, atualmente, o MediaTracker rastreia apenas os objetos Image. Adicionamos o objeto Image img ao nosso rastreador usando seu método addImage - mt.addImage(img, 0). O método exige dois parâmetros: a imagem que deve ser monitorada e um número de identidade (id). Este id é qualquer número inteiro e poderá ser utilizado para obter informações da imagem correspondente. Podemos adicionar quantas imagens quisermos ao MediaTracker e, desta forma, monitorar seu pre-carregamento. Se atribuirmos o mesmo id a um grupo de imagens, podemos obter informações sobre o grupo todo. Os métodos waitForAll (espere por todas) e waitForID (espere pelo id), também do MediaTracker, retornarão o controle ao chamador apenas quando a(s) imagen(s) esteja(m) carregada(s). No nosso applet utilizamos mt.waitForID(0) dentro de um bloco try/catch.
Com a imagem em mãos, atribuímos à variável larg a largura da imagem e à alt a sua altura. Em seguida criamos o objeto Image origImg com o dobro da largura da imagem enviada como parâmetro - origImg = createImage(larg << 1, alt) (veja o operador << em "Funções e Operadores Matemáticos"). Em seguida, obtemos a interface gráfica Graphics g do objeto Image recém-criado (Graphics g = origImg.getGraphics()) e aplicamos a ela a imagem do nosso gráfico a partir das coordenadas 0,0 (g.drawImage(img, 0, 0, this)).
Com o applet inicializado, está tudo pronto para o método start.
O método start()
No método start() criamos nossa linha de execução, a Thread linha. A esta altura já sabemos que o método start() é executado toda vez que a página que contém o applet se tornar ativa no browser. Portanto, se a linha de execução não existir e se a imagem origImg foi obtida no método init (if (linha == null && origImg != null) ), criamos uma nova (linha = new Thread(this) - "this" significa "este applet") e a tornamos ativa com linha.start(). A seguir, atribuímos à variável vivo o valor true (vivo = true;), a qual indica que o thread se encontra no estado ativo (executável).
O método run()
Se o applet implementa a interface Runnable e já possui um thread adicional, a presença de um método run() é obrigatória, porém o método run() só atua se o thread de execução estiver ativo (while(vivo)), e vivo só é verdadeiro se a página que contém o applet estiver ativa. Caso o usuário mude de página, o thread é desativado pela Java, assim como todos os procedimentos a ele associados. Não sobra "lixo" e os recursos da máquina do usuário são liberados. É claro que nossa variável vivo precisa indicar esta nova situação. Como sabemos que o método stop() é chamado quando o thread "morre", é neste ponto que atualizamos nossa variável.
A primeira coisa que o método run() faz é obter a interface gráfica do objeto Image origImg com Graphics g = origImg.getGraphics(). Esta interface gráfica é uma tela de pixels com tantas linhas quanto for a altura e tantas colunas quanto for a largura da imagem. No exemplo, temos 80 linhas e 240 colunas. Não podemos esquecer que as coordenadas desta tela se iniciam em x = 0 e y = 0. Isto significa que as coordenadas das linhas vão de 0 a 79 (80 linhas) e as das colunas vão de 0 a 239 (240 colunas). Portanto, quando quiser se referir à 10a. linha, por exemplo, sua coordenada y é igual a 9 e que sua 58a. coluna tem x = 57.
Na inicialização do applet colocamos na metade da esquerda da interface gráfica g imagem origImg. A metade da direita está livre e é nela que inicialmente desenhamos um retângulo preenchido de branco: g.setColor(Color.white) e g.fillRect(larg, 0, larg, alt). As coordenadas da imagem na metade esquerda são 0,0 até 119,80. O retângulo branco é desenhado a partir de 120, 0 com uma largura (x) de 120 e altura (y) de 80. Portanto, ocupa toda a metade direita da interface gráfica.
Tendo preparado a interface gráfica para receber nossa imagem espelhada, iniciamos um loop com valores de i que vão de 0 a 119, que são as coordenadas x da imagem original. Dentro deste loop colocamos o método copyArea, que fará todo o trabalho de espelhamento: g.copyArea(i, 0, (larg << 1) - i * 2, 0). O formato de copyArea é o seguinte:
onde x e y são as coordenadas do ponto de origem (onde começa o retângulo que deve ser copiado); int largura e int altura são a largura e a altura do retângulo a ser copiado; int desloca_x é o deslocamento do retângulo copiado no eixo x a partir das coordenadas do ponto de origem; int desloca_y é o deslocamento do retângulo copiado no eixo y a partir das coordenadas do ponto de origem.
Copiamos a imagem original em "fatias", coluna por coluna, e transportamos a cópia do fim para o começo da metade direita do ambiente gráfico. Veja o exemplo abaixo:
- Quando copiamos o retângulo com as coordenadas de origem x = 0 e y = 0, largura 1 e altura 5, e o deslocamos para a 10a. coluna, o deslocamento de x é 10 (pois 0 + 10 = 10).
- Quando copiamos o retângulo com as coordenadas de origem x = 1 e y = 0, largura 1 e altura 5, e o deslocamos para a 9a. coluna, o deslocamento de x é 8 (pois 1 + 8 = 9), e assim sucessivamente.
A fórmula que calcula o deslocamento é largura total - 2 * coluna, ou seja,
desloca0 = 10 - 2 * 0 = 10 desloca1 = 10 - 2 * 1 = 8 ... desloca4 = 10 - 2 * 4 = 2
10 | ||||||||
8 | ||||||||
6 | ||||||||
4 | ||||||||
2 |
0,0 | 1,0 | 2,0 | 3,0 | 4,0 | 5,0 | 6,0 | 7,0 | 8,0 | 9,0 | 10,0 |
No nosso applet, o cálculo (larg << 1) - i * 2 indica o deslocamento da coluna i. A cada cópia, a barra de status indica qual coluna foi copiada para onde e solicitamos que a imagem recém modificada seja mostrada na tela do applet. Para isto, basta utilizar o método showStatus("mensagem") e o método repaint(), o qual acionará os métodos update e paint. Precisamos de repaint porque o ambiente gráfico de origImg é apenas um buffer de trabalho que só é mostrado na tela do applet quando o copiamos para o ambiente gráfico da tela do applet.
Como o procedimento de copiar a imagem original em "fatias" e transportá-la para a metade direita é MUITO rápido, precisamos introduzir um tempo de espera através de linha.sleep(100), que faz com que o thread fique "dormindo" 0.1 segundo.
Terminado o loop, toda a imagem à esquerda é transportada "ao contrário" para a direita e o espelhamento horizontal é obtido. Fazemos uma pausa de 1 segundo com linha.sleep(1000) e reiniciamos o processo.
O método update()
O método update(Graphics g) nada mais faz do que chamar o método paint(). Não há necessidade de implementar código por que não precisamos refazer o fundo da nossa imagem, principal função do update.
O método paint()
Neste applet, a única função do método paint(Graphics g) é desenhar na tela do mesmo a imagem origImg, se ela existir. Caso a imagem não tenha sido encontrada e/ou carregada, o método paint não faz nada.
O método stop()
Quando o usuário abandona a página onde está o applet (ou por motivos outros), o método stop() é invocado. No nosso caso, sua única e importantíssima missão é "desligar" nossa linha de execução e deixar que a Java faça a faxina (liberando variáveis, threads ocultos, etc) antes de "matar" o thread que nós criamos... ou seja, não sobra lixo e os recursos da máquina são liberados. Basta dizer que a variável vivo é falsa para que o método run() seja interrompido e para que a Java assuma o comando.
Lição de casa
Modifique e amplie o código deste applet. Sugestões:
- Passe parâmetros para controlar as pausas.
- Passe um parâmetro para indicar a cor de fundo da metade direita do applet.
- Experimente fazer um espelhamento vertical da imagem. É praticamente o mesmo applet, basta alterar as referências no loop for do método run. Se você não conseguir, dê uma olhada em "Reflexo, o espelhamento vertical".
Finalmentes
Ufa!!! Haja explicação! Mas, para o bem de todos e felicidade geral da nação, estes conceitos servirão de base para muitos outros applets, dos mais simples aos mais elaborados.
Este applet é bastante simples, a explicação é que precisou ser longa. O que importa é que o efeito obtido é interessante e pode ser utilizado em applets mais complexos, como aquele do lago... sabe qual é?
Você pode baixar o texto deste tutorial, o código fonte e a classe deste applet na seção de downloads em tutoriais/java.
Grande abraço e sucesso!
vó Vicki