Criando imagens com Java

Criando imagens com Java

Neste artigo vamos discutir e ver como podemos utilizar o Java para criar, gerar e manipular imagens simples, como gráficos e textos. A partir deste rápido artigo, podemos ter uma boa base para poder desenvolver componentes mais elaborados para geração de imagens.

Criandos as imagens

Geralmente, os componentes Swing já possuem um buffer de imagem, e só precisamos implementar o método paint( ). Para criarmos nossas imagens, teremos então que criar um buffer para a nossa imagem e então criar um objeto do tipo java.awt.Graphics.

A classe java.awt.image.BufferedImage é uma subclasse de java.awt.Image, que usa um bloco de memória, e é onde vamos criar nossa imagem. No construtor da classe passaremos 3 parâmetros: width (largura da imagem), height (altura da imagem) e o tipo da imagem. Inicialmente vamos usar o tipo de imagem definido por BufferedImage.TYPE_INT_RGB, que não permite imagens transparentes. Mas isto está fora do escopo deste artigo.

Para criamos o gráfico que utilizaremos, usamos o seguinte código:

[code]1 int width=200, height=200;
2 BufferedImage buffer = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB );
3 Graphics g = buffer.createGraphics();

Como isso temos um buffer de imagem, que representa uma imagem de 200 por 200 pixels de tamanho. A partir daí, temos um objeto de Graphics que vamos utilizar para desenhar as primitivas que desejarmos.

As primitivas são: pontos, retas, ovais (e círculos), retângulos (e quadrados), dentre outros.

Criada a imagem, vamos criar um fundo para ela:

1 g.setColor( Color.WHITE );
2 g.fillRect( 0, 0, width, height );  

Com o método setColor() da classe Graphics, definimos a cor da primitive que iremos desenhar. O fundo, nada mais é do que um retângulo preenchido, do tamanho da própria imagem, e para isso utilizamos o método fillRect( ), eu desenha um retêngulo preenchido com a cor informada em setColor(). Simples, não?

Agora vamos desenhar uma simples reta na nossa imagem. Veja o código:

1 g.setColor( Color.BLACK );
2 g.drawLine(0,0,width,height);  

Definimos a nova cor que usaremos para desenhar e mandamos desenhar uma linha, com o método drawLine(), informando os pontos inicial e final da reta.

Já que chegamos até aqui, vamos então ver algum resultado para seguirmos com o resto da aplicação, pois assim já poderemos ter uma idéia visual do que podemos fazer.

Vamos criar uma simples aplicação Swing para exibir a imagem que criamos na tela. Aqui segue o código para o exemplo:

01 import javax.swing.*;
02 import java.awt.*;
03 import java.awt.image.*;
04 
05 public class ExemploImagem {
06     public static void main(String[] args) {
07         JFrame frm = new JFrame("Teste Imagem");
08         JPanel pan = new JPanel();
09         JLabel lbl = new JLabel( criarImagem() );
10         pan.add( lbl );
11         frm.getContentPane().add( pan );
12         frm.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
13         frm.pack();
14         frm.show();
15     }
16     
17     private static ImageIcon criarImagem() {
18         int width=200, height=200;
19         BufferedImage buffer = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB );
20         Graphics g = buffer.createGraphics();
21         g.setColor( Color.WHITE );
22         g.fillRect( 0, 0, width, height );
23         g.setColor( Color.BLACK );
24         g.drawLine( 0, 0, width, height );
25         return new ImageIcon( buffer );
26     }
27 } 

No método main() apenas criamos os componentes Swing para fazer a exibição da imagem, mas atente para o método criarImagem() que é o que realmente nos interessa, pois é lá que estamos criando a imagem em buffer e então retornamos um objeto do tipo ImageIcon, que é o componente visual do Swing que representa uma imagem.

Executando a aplicação, veremos uma janela como esta:

Este primeiro exemplo, apesar de simples e, aparentemente, sem utilidade, foi importante para que pudéssemos iniciar nossa experiência com a manipulação de imagens com Java.

Agora, vamos elaborar nosso exemplo um pouco mais, gerando um gráfico em pizza. Para isso, vamos cria uma classe, chamada PieChart, que vai ser um componente que vai gerar para gente um gráfico em pizza, a partir de um array de valor do tipo int.

Veja a implementação:

01 import javax.swing.*;
02 import java.awt.*;
03 import java.awt.image.*;
04 
05 public class PieChart {
06     
07     //guarda os valores a serem exibidos no gráfico
08     private int[] values;
09     //guarda o buffer da imagem desenhada
10     private BufferedImage imageBuffer;
11     //guarda a cor de fundo
12     private Color background;
13     //guardam as dimensões da imagem
14     private int width, height;
15     //cores para os pedaços do gráfico
16     private Color[] colors = { Color.BLUE, Color.GREEN, Color.RED,
17                                 Color.YELLOW, Color.ORANGE, Color.PINK,
18                                 Color.MAGENTA, Color.LIGHT_GRAY, Color.GRAY,
19                                 Color.BLACK };
20     
21     /**
22      * Cria um objeto da classe que gera um gráfico em pizza.
23      * @param values Array de valores inteiros a serem representados.
24      * @param width Largura da imagem.
25      * @param height Altura da imagem.
26      * @param background Cor de fundo da imagem.
27      */
28     public PieChart( int[] values, int width, int height, Color background ) {
29         if( values==null || values.length<1 ||
30             width<0 || height<0 ||
31             background==null ) throw new IllegalArgumentException();
32         this.values = values;
33         this.width = width;
34         this.height = height;
35         this.background = background;
36         createChart();
37     }
38     
39     /**
40      * Cria a imagem internamente.
41      */
42     private void createChart() {
43         imageBuffer = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB );
44         Graphics g = imageBuffer.createGraphics();
45         g.setColor( background );
46         g.fillRect( 0, 0, width, height );
47         int arc = 0;
48         int[] sizes = calculateAngles( values );
49         for(int i=0, j=0; i<sizes.length; i++, j++) {
50             if( j==10 ) j = 0;
51             g.setColor( colors[j] );
52             g.fillArc( 0, 0, width, height, arc, sizes[i] );
53             arc += sizes[i];
54         }
55     }
56     
57     /**
58      * Calcula os ângulos para cada valor informado.
59      * @param values Valores a terem seus ângulos calculados.
60      * @return Array de int com os ângulos para cada valor.
61      */
62     private int[] calculateAngles( int[] values ) {
63         int[] angles = new int[ values.length ];
64         int total = 0;
65         //calcula a somatória total dos valores
66         for( int i=0; i<values.length; i++ ) {
67             total += values[i];
68         }
69         //calcula os ângulos para cada pedaço
70         for( int i=0; i<values.length; i++ ) {
71             angles[i] = (360 * values[i]) / total;
72         }
73         return angles;
74     }
75     
76     /**
77      * Retorna a imagem do gráfico em pizza.
78      * @return Retorna um objeto do tipo ImageIcon.
79      */
80     public ImageIcon getImageIcon() {
81         return new ImageIcon( imageBuffer );
82     }
83     
84     /**
85      * Retorna o buffer da imagem do gráfico em pizza.
86      * @return Retorna um objeto do tipo BufferedImage.
87      */
88     public BufferedImage getBufferedImage() {
89         return imageBuffer;
90     }
91 }  

Esta classe gera a imagem internamente já no próprio construtor da classe. Para pegar a imagem a ser exibida, utilizamos o método getImageIcon().

Para exibirmos a imagem do gráfico gerado, podemos aproveitar o exemplo anterior e apenas trocar a linha onde é criado o JLabel com a imagem, pelas seguintes linhas:

[code]1 int[ ] valores = { 20, 10, 60, 90, 180 };
2 PieChart pie = new PieChart( valores, 200, 200, Color.WHITE );
3 JLabel lbl = new JLabel( pie.getImageIcon( ) ); [/code]

Viu como é simples? Com algumas linhas de código, escreves uma classe que representa e desenha uma gráfico em pizza, que é muito utilizado em aplicações comerciais.

Isto mostra o poder e a facilidade de Java para manipulação deste tipo de aplicação. As APIs oferecidas pela Sun são extremamente poderosas.

Às vezes desejamos não apenas gerar e apresentar as imagens, mas podemos também salvá-las em disco, e para isso utilizaremos a classe ImageIO, do pacote javax.imageio. Esta API do Java, permite salvar as imagens nos formatos JPEG e PNG. Infelizmente, por motivos de licensa, não é possível salvar no formato GIF. Mas existem APIs de terceiros para salvar as imagens no formato GIF. O Google pode te dar uma boa ajuda.

O procedimento para gravar a imagem em disco é simples, veja:

ImageIO.write( pie.getBufferedImage(), "png", new File("img.png") );

O primeiro parâmetro do método estático write() é o buffer da imagem gerada, depois o tipo da imagem, que no nosso caso é PNG e por último o File que representa qual o arquivo a ser criado.

Uma outra opção do método write() é informar um OutputStream ao invés de um File. Com isso, podemos facilmente fazer um Servlet Java que gera uma imagem. Exemplo:

1 response.setContentType("image/png");
2 OutputStream os = response.getOutputStream();
3 ImageIO.write(buffer, "png", os);
4 os.close();  

Neste caso mudamos o content type para image/png, que é uma imagem PNG. Em seguida passamos o OutputStream de resposta com o cliente web para o método write(), que grava na resposta os dados da imagem gerada e representada por buffer. Simples!

Por vezes, desejamos incrementar nossas imagens, adicionando um texto decorativo, e isto é tão simples quanto gerar a própria imagem. Podemos, inclusive, escolher a fonte, o tamanho e a posição do texto. Vejam o exemplo:

1 Font font = new Font("Courier", Font.BOLD, 30);
2 g.setColor( Color.BLUE );
3 g.setFont( font );
4 g.drawString("GUJ",0,20);  

A classe Font, como o nome sugere, representa uma Font do sistema. No seu construtor, informamos no nome da fonte, suas características (no caso BOLD) e o seu tamanho. Depois só informamos ao gráfico a cor do texto, a fonte a ser usada e mandamos desenhar o texto com o método drawString(), informando a String do texto a posição (X, Y) na imagem.

Daí pra frente é só você usar a sua imaginação e desenvolver suas aplicações.

Nós queremos saber sua opinião aqui

Marcius disse:

Este por foi extremamente util para mim. Obrigado! Funcionou tudo de primeira!