Imagens SVG e Java ME

Introdução

                    O surgimento das imagens SVG (Scalable Vector Graphics) trouxe novas possibilidades para os desenvolvedores Java ME, possibilitando a criação de interfaces poderosas, com animações e outros efeitos gráficos conhecidos. Além disso, as imagens SVG tem um tamanho reduzido se comparado a outros formatos, além de fornecer características importantes como manutenção da qualidade, mesmo quando a imagem é redimensionada.
                    A plataforma Java ME oferece vários pacotes opcionais, para permitir que funcionalidades mais avançadas possam ser aplicadas aos aplicativos, sem excluir os dispositivos low-end da sua gama de aparelhos suportados, características como Bluetooth, GPS, dados multimídia, mobile payment, dentre outros. A Scalable 2D Vector Graphics API (JSR 226) é um destes pacotes opcionais, que permite o uso de imagens SVG.
                    O presente artigo pretende demonstrar de forma prática o uso da JSR 226, listando códigos fonte para a renderização de imagens e animações SVG, além de sintetizar a forma de alteração de uma imagem SVG a partir de um aplicativo Java ME, em tempo de execução. Presumimos, que o leitor tenha um breve conhecimento da linguagem Java e da plataforma Java ME, além de um breve conhecimento de XML.

SVG (Scalable Vector Graphics)

                    Segundo Wikipedia, “SVG é a abreviatura de Scalable Vectorial Graphics que pode ser traduzido do inglês como gráficos vectoriais escaláveis. Trata-se de uma linguagem XML para descrever de forma vectorial desenhos e gráficos bidimensionais, quer de forma estática, quer dinâmica ou animada. Umas das principais características dos gráficos vectoriais, é que não perdem qualidade ao serem ampliados. A grande diferença entre o SVG e outros formatos vectoriais, é o facto de ser um formato aberto, não sendo propriedade de nenhuma empresa. Foi criado pela World Wide Web Consortium, responsável pela definição de outros padrões, como o HTML e o XHTML”.
                    Segundo W3Schools, “SVG é uma linguagem para descrever gráficos em duas dimensões e aplicações gráficas  em XML”.
                    Segundo Costa, “SVG é um formato gráfico vectorial que no seu estado nativo é inteiramente dedicado a bases vectoriais. Linhas, preenchimentos, gradientes e texto. O SVG é também extensível no sentido em que suporta extensões com capacidades de filtrar, e pode ser expansível de uma maneira modular através de outras aplicações XML. Por exemplo, trabalha com scripting, eventos e modelos de objectos definidos pelo DOM e pode ser alterado dinamicamente com CSS, mas pode ser também integrado com qualquer coisa como animação integrada”.
                    Um exemplo simples retirado da W3Schools pode ser visto na Listagem 1, e o resultado do código ilustrado na Figura 1:
                    Na imagem, são visualizados dois componentes, um retângulo e um círculo. Estes componentes são elementos XML, que podem ser animados.  Na Listagem 1, eles são referenciados pelos componentes <rect> e <circle>. Como o objetivo deste artigo não é analisarmos o SVG e sim, sua integração com Java ME, recomenda-se a leitura na íntegra do tutorial apresentado em W3Schools, para um conhecimento mais detalhado sobre SVG.
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="20" rx="20" ry="20" width="250"
height="100" style="fill:red;stroke:black;
stroke-width:5;opacity:0.5"/>
<circle cx="100" cy="50" r="40" stroke="black"
stroke-width="2" fill="red"/>
</svg>
Listagem 1 - Código SVG



Fig1ImagemSVG
Figura 1 - Imagem SVG

Java ME – Pacotes Opcionais

                    Segundo Giguere (2002), um pacote opcional é um conjunto de APIs, mas diferentemente do perfil (MIDP por exemplo), não define um ambiente de aplicação completo. Um pacote opcional sempre será usado em conjunto com uma configuração ou um perfil. Estende o ambiente de runtime, para suportar as capacidades de dispositivos que não são definidas por algum perfil de forma universal. A Tabela 1, mostra alguns dos pacotes opcionais existentes.
JSR Sigla Nome
JSR 75 PIM PDA Optional Packages for the J2ME Plataform
JSR 82 BTAPI Java APIs for Bluetooth
JSR 120 WMA Wireless Message API
JSR 135 MMAPI Mobile Media API
JSR 179 Location API for J2ME
JSR 184 3D Mobile 3D Graphics API for J2ME
JSR 205 WMA 2.0       Wireless Message API 2.0
JSR 209   Advanced Graphics and User Interface Optional Package for
 J2ME Plataform
JSR 226 Scalable 2D Vector Graphics API
JSR 229 Payment API
Tabela 1. Pacotes opcionais

                    A JSR 226 teve sua versão final aprovada no ano de 2006, segundo a página oficial da JSR. Por este motivo, somente alguns celulares high-end dispõe desta API. Um exemplo, é a série de celulares N da Nokia, dentre eles o N95. Porém, com a crescente utilização de imagens SVG, a lógica é a expansão da JSR 226, consequentemente, o desenvolvedor Java ME deve ter  conhecimento deste pacote opcional, desde o início.
JSR 226 - Utilização

                    Agora a brincadeira vai começar de verdade! Assume-se, que o leitor já tenha conhecimento básico da programação em Java ME, caso contrário, antes de prosseguir, aconselha-se o estudo da Java ME.
                Renderizando imagens 2D
                    O primeiro passo no aprendizado, é inserir uma simples imagem SVG na nossa aplicação, sem nenhuma animação. A Listagem 2, mostra o código necessário para realizar esta tarefa.
1: public class Midlet extends MIDlet {
2:    public String IMAGE = "/loadScreen.svg";
3:    private Display display;
4:   
5:    public void startApp() {
6:        InputStream is = getClass().getResourceAsStream(IMAGE);
7:        display = Display.getDisplay(this);
8:       
9:        try {
10:           
11:            SVGImage pointerimage = (SVGImage)SVGImage.createImage(is, null);
12:            M2GCanvas canvas = new M2GCanvas(pointerimage);
13:            display.setCurrent(canvas);
14:        } catch (IOException ex) {}
15:    }
16:   
17:    public void pauseApp() {}   
18:    public void destroyApp(boolean unconditional) {}
19:}
20:
21:class M2GCanvas extends Canvas
22:{
23:    ScalableImage scalableImage;
24:    ScalableGraphics scalableGraphics;
25:   
26:    public M2GCanvas( ScalableImage inImage )
27:    {
28:        scalableImage = inImage;
29:        scalableGraphics = ScalableGraphics.createInstance();
30:    }
31:
32:    public void paint( Graphics g )
33:    {
34:        scalableGraphics.bindTarget( g );
35:        scalableImage.setViewportWidth( getWidth() );
36:        scalableImage.setViewportHeight( getHeight() );
37:        scalableGraphics.render( 0, 0, scalableImage );
38:        scalableGraphics.releaseTarget();
39:    }
40:}
Listagem 2. Renderizando imagens 2D

                    É importante ressaltar, que os códigos mostrados neste artigo, bem como as explicações, foram baseadas no artigo de Powers (2005),  listado nas referências bibliográficas. As imagens SVG foram retiradas do exemplo “SVGContactList”, que acompanha o software Sun Wireless Toolkit 2.5, da Sun. Vamos ao código!
                    O código da linha 1 até a linha 20 deve ser de fácil compreensão do leitor, pois é o código padrão para criação de uma MIDlet, apresentando diferenças fundamentais entre as linhas 11 e 13. Utilizando uma variável chamada “IMAGE”, que indica o lugar onde se encontra a imagem SVG, é obtida a instância da classe InputStream,   que serve de parâmetro para o método createImage da classe SVGImage. Depois que a instância de SVGImage foi construída, passamos o objeto para o construtor da classe MG2Canvas.
                    A classe definida entre as linhas 21 e 40 é de grande importância dentro da API e neste exemplo. Para renderizar a imagem SVG, precisamos atribuir a mesma a um objeto da classe Canvas. Para tanto, utiliza-se as classes ScalableImage e ScalableGraphics. A instância de ScalableImage é recebida por parâmetro no construtor da classe,  porém, a instância de ScalableGraphics é criada através do método createInstance() da mesma classe.
                  O próximo passo é ligar o objeto Graphics do Canvas ao mesmo objeto da classe ScalableGraphics. Para isso, utiliza-se  o método bindTarget(Graphics g) da ScalableGraphics. As linhas 35 e 36, especificam a largura e a altura que a imagem SVG vai ocupar no display do device, que para este exemplo, configuramos o tamanho máximo. A linha 37, especifica a localização onde a imagem será renderizada, e por fim, a linha 38 libera o contexto dos gráficos. O resultado deste código é apresentado na Figura 2.
Fig2ImagemSVG2D
Figura 2. Imagem SVG 2D


                    Para fixar o conteúdo, se o código das linhas 35 até a linha 37 for alterado pelo código da Listagem 3, o resultado seria semelhante ao ilustrado na Figura 3. Observe, que a largura e altura da imagem SVG foram fixadas como 150, e como o display é maior que este valor, a imagem não ocupa toda a tela. Além disso, ela foi desenhada na coordenada 30, 30, que não representa o canto superior esquerdo da tela.
scalableImage.setViewportWidth( 150 );
scalableImage.setViewportHeight( 150 );
scalableGraphics.render( 30, 30, scalableImage );
Listagem 3. Linhas alteradas

Fig3ImagemSVG2D


                   Renderizando animações 2D
                    Depois que o leitor compreendeu a forma de renderizar uma imagem SVG, o próximo passo, é renderizar uma animação SVG. A Listagem 4 apresenta o código necessário. Apenas insira o mesmo no bloco try da Listagem 2.

SVGImage pointerimage = (SVGImage)SVGImage.createImage(is, null);

SVGAnimator svgAnimator = SVGAnimator.createAnimator(pointerimage);

svgAnimator.setTimeIncrement(0.10f);

Canvas svgCanvas = (Canvas)svgAnimator.getTargetComponent();

svgCanvas.setFullScreenMode(true);

pointerimage.setViewportWidth(svgCanvas.getWidth());

pointerimage.setViewportHeight(svgCanvas.getHeight());

display.setCurrent(svgCanvas);

svgAnimator.play();

Listagem 4. Código para renderizar uma animação SVG

                    Primeiramente é necessário a criação de um objeto SVGAnimator, construído através do método estático createAnimator(), que recebe  por parâmetro um objeto de SVGImage. A linha a seguir serve para definir o tempo de animação, sendo este opcional. Perceba, que não é mais necessário o uso da classe M2GCanvas, isso porque, o método getTargetComponent() da classe SVGAnimator traz um objeto da classe Canvas. Os métodos de setViewportWidth e setViewportHeight tem a mesma função dos métodos citados na Listagem 2, que tem a mesma nomenclatura. E por fim, o método play() inicia a animação da imagem SVG.

                    Configurando a imagem SVG em tempo de execução
                    Pessoalmente, uma das características mais impressionantes das imagens SVG e da JSR 226, é a possibilidade de editar o código fonte de uma imagem SVG em tempo de execução, isso porque, a imagem SVG é um XML. Então, utilizando-se  da mesma lógica de parser, que APIs como DOM e SAX (do Java SE) possuem, é possível navegar pela árvore XML do documento que compõe a imagem SVG, e fazer as alterações que quiser.
                  Para referenciar os elementos que compõe o XML da imagem SVG, é preciso de um atributo único, que identifique-os. Veja a Listagem 5, que mostra duas linhas do arquivo SVG antes da alteração e depois da alteração, e observe a inclusão do atributo id. Os elementos de texto serão identificados pelos seus ids: superior e inferior.
<text x="120" y="230" font-family="'ArialNarrow'" font-size="12" text-anchor="middle" fill="rgb(28, 28, 28)">Aguarde, buscando</text>
<text x="120" y="250" font-family="'ArialNarrow'" font-size="12" text-anchor="middle" fill="rgb(28, 28, 28)">dados dos satelites</text>

<text id="superior" x="120" y="230" font-family="'ArialNarrow'" font-size="12" text-anchor="middle" fill="rgb(28, 28, 28)">Aguarde, buscando</text>
<text id="inferior" x="120" y="250" font-family="'ArialNarrow'" font-size="12" text-anchor="middle" fill="rgb(28, 28, 28)">dados dos satelites</text>
Listagem 5. Código XML da imagem SVG

                    A Listagem 6 apresenta o código Java ME necessário para alteração da imagem SVG. A primeira linha já estava presente desde a Listagem 2, posteriormente, é criada uma instância da classe Document, obtida através do método getDocument da classe SVGImage. De posse do documento XML, o próximo passo é obter a instância da classe SVGElement, através do método getElementById() da classe Document. Observe, que o elemento é recuperado através de seu id, definido na Listagem 5. Finalmente, editamos o elemento com o método setTrait(). O primeiro atributo identifica o elemento (no caso de elementos texto, é usado o #text) e o segundo atributo é o novo valor do elemento. A Figura 5 ilustra o resultado. Além do texto, qualquer atributo referente ao elemento pode ser configurado em tempo de execução. Faça você mesmo alguns testes!.


SVGImage pointerimage = (SVGImage)SVGImage.createImage(is, null);


Document doc = pointerimage.getDocument();

SVGElement element = (SVGElement)doc.getElementById("superior");

element.setTrait("#text", "Por favor, aguarde");

Listagem 6. Código Java ME para alteração da imagem SVG

fig4ImagemSVG
Figura 4. Imagem SVG alterada em tempo de execução


                    Esta API JSR 226 permite que imagens SVG sejam criadas através de código Java, possibilitando ainda que a alteração em um arquivo SVG seja realizado em tempo de execução, como mostrado na Listagem 7. A primeira linha é de fundamental importância. Nela, cria-se uma instância de SVGImage, que ao contrário das listagens anteriores, não se referencia nenhum arquivo SVG, passando-se null como parâmetro. Desta forma, instâncias das classes Document e SVGSVGElement são necessárias para navegar pela árvore XML.
                    A instância da classe SVGRect define a área de trabalho do SVG, definindo-se um tamanho de 100 x 100 para este exemplo de listagem. O método createElementNS serve para criarmos os elementos do SVG. O segundo parâmetro deste método define qual o tipo de elemento. No exemplo, foi criado dois elementos, um do tipo rect na variável r, e um do tipo circle na variável c. Observe o uso do método setFloatTrait(), que tem a mesma função do método setTrait() da Listagem  6, e que através dele, todos os atributos dos nossos elementos XML são configurados. Finalizando, para adicionar o elemento ao arquivo SVG, utiliza-se o método appendChild() da classe SVGImage, conforme mostrado na Figura 6. O código para inserir a imagem SVG em um Canvas pode ser reaproveitado das listagens anteriores.

SVGImage svgImage = SVGImage.createEmptyImage(null); Document doc = svgImage.getDocument(); SVGSVGElement svg = (SVGSVGElement)doc.getDocumentElement();

// First, set the viewBox so that we can work in

// a 100 by 100 area.

SVGRect vb = svg.createSVGRect();

vb.setWidth(100);

vb.setHeight(100);

svg.setRectTrait("viewBox", vb); SVGElement r = (SVGElement)doc.createElementNS ("http://www.w3.org/2000/svg", "rect"); SVGRGBColor bkgColor = svg.createSVGRGBColor(0, 30, 147); r.setRGBColorTrait("fill", bkgColor); r.setFloatTrait("x", 25); r.setFloatTrait("y", 25); r.setFloatTrait("rx", 5); r.setFloatTrait("ry", 5); r.setFloatTrait("width", 50); r.setFloatTrait("height", 50); svg.appendChild(r); SVGElement c = (SVGElement)doc.createElementNS ("http://www.w3.org/2000/svg", "circle"); SVGRGBColor fgColor = svg.createSVGRGBColor(255, 255, 255); c.setRGBColorTrait("fill", fgColor); c.setFloatTrait("cx", 50); c.setFloatTrait("cy", 50); c.setFloatTrait("r", 20); svg.appendChild(c);
Listagem 7. Criando imagens SVG em tempo de execuç

fig5ImagemSVG

Figura 5. Imagem SVG criada em tempo de execução

Conclusão
                    Apesar de ser uma área relativamente nova, com poucos dispositivos suportando a JSR 226, é de suma importância que o desenvolvedor Java ME tenha conhecimento de imagens SVG e de sua utilização nos seus aplicativos. Por mais que dispositivos low-end dominem o mercado, a evolução tecnológica comprova que não podemos ficar parados, além disso, interfaces ricas estão se tornando um requisito básico para aplicativos Java ME.                 O presente artigo mostrou uma descrição do formato de imagem SVG, de forma não técnica. Entenda-se como uma visão de um programador Java ME e não de um expert em edição de imagens. A API JSR 226 foi apenas sintetizada, mostrando de forma rápida como fazer os principais processos, tais como: renderização de imagens e animações SVG, além de alterações de imagens em tempo de execução.


                Referências Bibliográficas



                    Costa, Maria de Fátima. SVG(Scalable Vector Graphics). Disponível em: http://student.dei.uc.pt/~mcosta/smm.html. Acessado em Outubro de 2007.

<                    Giguere, Eric (2002). J2M2 Optional Package. Disponível em: http://developers.sun.com/mobility/midp/articles/optional/index.html. Acessado em Outubro de 2007.

>                    JSR 226. Página oficial. Disponível em: http://www.jcp.org/en/jsr/detail?id=226. Acessado em Outubro de 2007.

                    Powers, Michael (2005), Getting Started with Mobile 2D Graphics for J2ME. Disponível em: http://developers.sun.com/mobility/midp/articles/s2dvg/index.html. Acessado em Outubro de 2007.

                    Wikipedia. SVG. Disponível em: http://pt.wikipedia.org/wiki/SVG. Acessado em Outubro de 2007.

W3Schools. Introduction to SVG. Disponível em: http://www.w3schools.com/svg/svg_intro.asp. Acessado em Outubro de 2007.


Sobre o Autor:

Ricardo da Silva Ogliari é Bacharel em Ciência da Computação pela Universidade de Passo Fundo-Rio Grande do Sul. Membro atuante do JavaFree ( www.javafree.org ),onde publica vários artigos em Java ME. Trabalha atualmente como desenvolvedor de aplicações direcionadas a telefones celulares na Kwead.com de São Paulo. Palestrante no JustJava 2007 e 2005. Possui diversas participações em Congressos e  Eventos. Fez várias palestras sobre a tecnologia Java. Criador do projeto de código aberto MECHART. Objetiva o desenvolvimento de uma API para a construção de gráficos na plataforma Java ME. Site do projeto: http://mechart.dev.java.net .Colaborou com o Java Noroeste com o artigo Socket + JME ( http://www.javanoroeste.com.br/artigos/socketJ2ME.pdf ).