Uma visão rápida sobre o Java 2D Escrito por Vinícius Godoy de Mendonça - Última atualização Seg, 26 de Outubro de 2009 10:38 O Java 2D é uma API extensa e poderosa. Ele faz parte do JDK padrão, e inclui diversos tipos de funções para desenhar diretamente na tela, desenhar texto, manipular imagens e utilizar a impressora. Nesse artigo, vamos conhecer um pouco da terminologia básica do Java 2D, e ver de maneira resumida suas funcionalidades. Introdução O Java 2D é implementado como uma extensão do Abstract Window Toolkit (AWT). Ele tornou-se muito poderoso depois da adição de outra extensão: o Swing. Inicialmente, os projetistas da AWT delegavam a tarefa de desenhar janelas, botões e caixas de texto ao sistema operacional. Mas logo perceberam que isso não era muito portável, e limitava severamente a performance do Java em aplicações mais sérias. Então, decidiram associar a AWT uma nova extensão, chamada Swing, que desenharia integralmente todos os componentes de tela. Ao fazer isso, a biblioteca Java 2D ganhou grande importância. O Swing rapidamente tornou-se o padrão do Java para todo o tipo de aplicação desktop. Entretanto, uma de suas grandes reclamações sempre foi a performance, o que motivou os desenvolvedores da Sun a investir em otimizações agressivas no Java 2D. Entre elas, está a aceleração de hardware (integrada com OpenGL), possibilidade de trabalhar em modo janela exclusivo (FSEM), otimizações agressivas na biblioteca de manipulação de imagens, entre outras coisas. Dentre as principais capacidades do Java 2D, podemos citar: - Um modelo uniforme de desenho para dispositivos de vídeo e impressoras; - Um grande número de primitivas geométricas (retângulos, elipses, curvas), e um mecanismo para se desenhar qualquer forma geométrica; - Mecanismos para detectar colisão em texto e imagens; - Modelos de composição (Alpha Composition), que permitem escolher como combinar imagens que se interceptam; - Modelo de cores avançado; - Diretivas para controlar a qualidade do desenho; - Classes para manipulação uniforme dos principais formatos de imagem; Desenho com Java 2D 1/7 Uma visão rápida sobre o Java 2D Escrito por Vinícius Godoy de Mendonça - Última atualização Seg, 26 de Outubro de 2009 10:38 Espaço de coordenadas O Java 2D permite o trabalho em dois tipos de sistemas de coordenadas. As coordenadas do dispositivo e as coordenadas de usuário. As coordenadas do dispositivo se referem ao sistema do hardware que está sendo trabalhado. Vão alterar de acordo com a resolução de tela, ou o tamanho da folha, por exemplo. Já as coordenadas do usuário são um sistema lógico, usado pelo seu programa. Elas são uniformes e independentes de dispositivo, é o próprio Java 2D que se encarrega da conversão de um sistema para outro. O sistema de coordenadas da aplicação inicialmente considera a coordenada (0,0) como o canto superior esquerdo da área de desenho. As coordenadas serão sempre crescentes, com x crescendo para direita e y para baixo. Na realidade, o Java 2D permite que essas coordenadas sejam alteradas à vontade, permitindo a criação de diversos sistemas coordenados próprios, dentro da aplicação. O contexto gráfico 2/7 Uma visão rápida sobre o Java 2D Escrito por Vinícius Godoy de Mendonça - Última atualização Seg, 26 de Outubro de 2009 10:38 Todo desenho no Java 2D é feito através da classe Graphics2D . Essa classe. que deriva da classe Graphics , representa o contexto gráfico sobre o qual o desenho será feito. Por isso, a classe guarda informações como cor será aplicada sobre a pintura, que tipo de borda o desenho terá ou qual será a fonte utilizada no texto, entre outras coisas. Normalmente, uma aplicação é formada não por uma só imagem, mas por várias. Seria extremamente trabalhoso garantir que uma alteração no feita em uma imagem não interferisse em outra. Por exemplo, ao desenhar o fantasminha azul acima, você poderia definir no Graphics que ele deveria usar 80% de transparência. Entretanto, se você esquecer de desfazer essa definição, o pacman, que será desenhado logo em seguida, poderia ficar transparente também. Para contornar esse problema, os projetistas do Java 2D criaram uma forma de copiar o contexto gráfico. Isso permite que você trabalhe sobre uma cópia, faça as modificações necessárias para pintar a imagem, e descarte essa cópia ao final da pintura, deixando o contexto gráfico original inalterado. /** Método paint do fantasma */ public void paint(Graphics g) { //1. Copiamos o contexto gráfico Graphics2D g2d = (Graphics2D) g.create(); //2. Desenhamos o fantasma 80% transparente AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8); g2d.setComposite(alpha); g2d.drawImage(x, y, phantomImage, null); //3. Descartamos a cópia do contexto gráfico g2d.dispose(); } Uma confusão comum feita pelos iniciantes em Java 2D é pensar que a classe Graphics representa a superfície de desenho em si. Isso não é verdade. Ela só representa o estado exato em que será feita a pintura. Por isso, copiar esse contexto como sugerido acima é uma operação extremamente eficiente e barata. Assim como descarta-lo ao final da pintura não destruirá o desenho. De fato, isso nos leva a primeira regra de ouro ao desenhar em Java 2D: “Jamais altere o estado do objeto Graphics recebido como parâmetro nas funções de pintura”. Caso contrário, o Swing poderá usar esse objeto na hora de desenhar partes de sua janela, e você poderá obter efeitos muito estranhos, diferentes do esperado e difíceis de corrigir. Dentre os estados no interior da classe Graphics2D, podemos citar: 3/7 Uma visão rápida sobre o Java 2D Escrito por Vinícius Godoy de Mendonça - Última atualização Seg, 26 de Outubro de 2009 10:38 - A largura que as bordas de uma figura são desenhadas (Pen, Stroke); - Como duas bordas se conectam; - A área, não necessariamente retangular, em que o desenho será realizado (Clipping path); - Transformações de translação, rotação, escala e shear (AffineTransform); - Cores e padrões de pintura; - Composições entre múltiplos objetos (Composite); Entretanto, a classe Graphics2D não guarda somente estados, mas também provê métodos para realizar a pintura em si. E isso nos leva ao próximo tópico. Primitivas geométricas As primitivas geométricas do Java 2D são: pontos, linhas, retângulos, arcos e elipses e curvas. As classes que lidam com cada uma dessas geometrias são definidas no pacote java.awt.geo m . Por questões de performance e conveniência, o objeto Graphics também fornece métodos para a pintura direta dessas primitivas, sem a necessidade de criação de um objeto. Além dessas, o Java 2D fornece uma classe chamada GeneralPath , que permite a criação de formas arbitrárias, baseadas em linhas e curvas de Bézier. 4/7 Uma visão rápida sobre o Java 2D Escrito por Vinícius Godoy de Mendonça - Última atualização Seg, 26 de Outubro de 2009 10:38 As classes entre determinada comuns dois como pontos deforma, primitivas interseção (Point2D), etc. O também ou Java área subtração ainda fornecem de figuras fornece de duas diversos sólidas, a formas. classe métodos teste Area, se um que bastante ponto permite práticos, está realizar contido como operações emdistância uma Texto O Java 2D fornece diversas classes para trabalhar com texto. Embora a forma mais direta e mais comumente usada seja simplesmente chamar os métodos setFont e drawString da classe Graphics, a API fornece classes auxiliares, que facilitam recursos mais avançados, como o posicionamento do texto. Essas classes, são parte do pacote java.awt.Font . Chamamos de Glyph a forma usada para representar um caractere dentro de uma fonte. Um caractere de texto real pode ser formado por uma combinação de dois glyphs, como é o caso da maior parte das letras acentuadas. Da mesma forma, podem haver Glyphs que representam o desenho de mais de um caractere, como esse aqui o do símbolo de peseta: ₧ Uma fonte, é portanto, um conjunto de Glyphs, com o mesmo estilo artístico. Essa fonte pode ter uma série de variações, como itálico ou negrito, e essas variações são chamadas de faces. 5/7 Uma visão rápida sobre o Java 2D Escrito por Vinícius Godoy de Mendonça - Última atualização Seg, 26 de Outubro de 2009 10:38 O conjunto de todas as faces de uma fonte é chamada de família . Podemos questionar o Java sobre diversas propriedades da fonte em questão, tais como altura, largura e outras métricas. Essas propriedades são encapsuladas na classe FontMetrics . Antes do texto ser exibido, entretanto, ele deve ser formatado. Quem realiza essa tarefa é a classe TextLayout . Ela fornece métodos para lidar com fontes misturadas, idiomas diferentes e texto bidirecional. Caso você queira um controle ainda mais refinado sobre as opções de layout, o Java 2D fornece uma classe de mais baixo nível, chamada Glyph Vector . Imagens Por último, mas não menos importante, o Java 2D fornece diversos recursos para a manipulação de imagens. O primeiro recurso interessante é certamente uma classe que permite a carga e escrita de diversos tipos de imagem de maneira uniforme, chamada ImageI O . As imagens representadas pela classe BufferedImage . Um dos recursos mais interessantes do Java 2D, é que podemos requisitar o objeto Graphics de qualquer imagem, e realizar pintura ou escrever texto sobre imagens da mesma forma que fazemos para desenhar os componentes de tela. O Java ainda suporta filtros sobre imagens, através da classe BufferedImageOp . Alguns sites de terceiros, como o jhlabs , já tem diversos desses filtros implementados, o que pode adicionar efeitos bastante interessantes aos jogos. Por fim, o Java permite ainda a manipulação direta e eficiente dos pixels de uma imagem, através de suas definições, contidas na classe Raster . Essa manipulação avançada é geralmente necessária apenas para quem vai trabalhar com aplicações que geram filtros diretamente e, se esse é o seu caso, pode ser interessante consultar o tutorial 6/7 Uma visão rápida sobre o Java 2D Escrito por Vinícius Godoy de Mendonça - Última atualização Seg, 26 de Outubro de 2009 10:38 “Using Rasters for Image Processing”, do Java Boutique . Fique atento, pois o tutorial também tem uma segunda parte . Infelizmente, a biblioteca Java2D cobre bem apenas imagens formadas por mapas de bits. Para imagens vetoriais, é necessário utilizar bibliotecas de terceiros. Conclusões Nesse artigo, vimos rapidamente os recursos do Java 2D, e conhecemos a terminologia básica da maior parte de seus componentes. Deixamos de fora somente a parte de impressão, menos importante para jogos. Embora ainda não possamos desenhar nada, já podemos ter uma boa noção do quão poderosa a biblioteca é. Mais importante, aprendemos a terminologia do Java 2D, associada ao nome de diversas de suas principais classes. 7/7