41bb726c

Dia 25

Divertimento com filtros de imagem

Michael Morrison


CONTEÚDOS

Como aprendeu tanto ontem como antes neste livro, Java fornece muitos modos arrumados de trabalhar com imagens gráficas. Uma de características tratam a imagem mais interessantes de Java é o seu suporte de filtros de imagem, que lhe permitem alterar os pixéis individuais de uma imagem segundo um determinado algoritmo. Os filtros de imagem podem variar de efeitos simples como ajuste do brilho de uma imagem a efeitos mais promovidos como gravação em relevo.

No coração de gráfica de Java e visualização são modelos de cor de Java. A lição de hoje começa investigando qual um modelo a cores é, junto com como os modelos a cores afetam o manejo de imagem e a gráfica de Java em geral. Então mudará para aprender sobre filtros de imagem de Java e como se usam para manipular imagens gráficas. Java fornece várias classes de filtro de imagem que interagem em conjunto para formar uma armação para filtrar facilmente imagens gráficas. Pode estender as classes de filtração de imagem de Java padrão e construir os seus próprios filtros de imagem para executar quase qualquer tipo da imagem que o processa pode imaginar. Terminará a lição de hoje implementando os seus próprios filtros de imagem.

Portanto a lição de hoje cobre os seguintes tópicos primários:

Penso que encontrará que os filtros de imagem são uma característica muito interessante e potente de Java que não receberam tanta atenção como merecem. Concedido, os filtros de imagem não compartilham a larga aplicabilidade de alguns outros aspectos de Java, mas podem ser divertimento de remendar e serão inevitavelmente úteis em alguns applets especializado.

Os fundamentos de cor

Todo gráfico em Java, inclusive filtros de imagem, começa com o conceito da cor. Sei, ouviu provavelmente algo sobre a cor antes, mas talvez não no caminho estou a ponto descrevem. Vê, quando falo sobre a noção da cor, quero dizer a noção de um computador da cor. Em outras palavras, quero dar uma olhada resumidamente em como a cor se representa em um computador, desde que lhe dará enfim mais compreensão como a imagem filtra o trabalho.

Desde que os ambientes de computador modernos são altamente gráficos, é imperativo que os computadores saibam como processar e expor a informação em cores. Embora a maior parte de sistemas operacionais de computador tenham algum grau do manejo dependente da plataforma da cor, todos eles compartilham uma abordagem comum à representação geral de cores. Sabendo que todos os dados em um computador se guardam enfim em uma forma binária, suporta para raciocinar que fazem o mapa de qualquer maneira de cores físicas a valores binários ou números, no domínio de computador. A pergunta é, como são as cores feitas o mapa a números?

Um modo de subir com representações numéricas de cores seria começar em um fim do espectro a cores e destinar um número a cada cor até que consiga outro fim. Esta aproximação resolve o problema de representar uma cor como um número, mas não fornece nenhum modo de tratar a mistura de cores. Como cada um que experimentou a alegria do Jogo-Doh pode dizer-lhe, as cores reagem de maneiras diferentes quando combinado um com outro. De caminho a mistura de cores para formar outras cores volta à física, que está um pouco além desta discussão. O caso é que um sistema de cor de computador tem de ser capaz de tratar cores se misturam com resultados exatos, predizíveis.

O melhor lugar de procurar uma solução para o problema a cores é um monitor de computador a cores. Um monitor a cores tem três armas de elétrons: vermelho, verde, e azul. A produção destas três armas converge em cada pixel da tela, fósforo excitante para produzir a cor apropriada (ver a Figura 25.1). As intensidades combinadas de cada arma determinam a cor de pixel resultante. Esta convergência de cores diferentes das armas de monitor é muito semelhante à convergência do Jogo-Doh colorido diferente. A diferença primária é que os monitores usam só estas três cores (vermelho, verde, e azul) para subir de cada cor possível que pode representar-se em um computador. (De fato, a diferença mais grande é que o Jogo-Doh não pode expor a gráfica de computador de alta resolução, mas isto é outra discussão.)

A figura 25.1: armas de elétrons em um monitor a cores que converge para criar uma cor única.

Conhecimento que os monitores formam cores únicas usando intensidades variadas das cores vermelhas, verdes, e azuis, poderia estar pensando que uma boa solução para o problema a cores seria fornecer um valor de intensidade para cada uma destas cores primárias. Isto é exatamente como o modelo de computador colore. Os computadores representam cores diferentes combinando as intensidades numéricas das cores primárias vermelhas, verdes, e azuis. Este sistema a cores conhece-se como RGB (vermelho, verde, azul) e apoia-se totalmente por Java.

Novo termo
RGB é o sistema a cores primário usado por Java e significa o vermelho, o verde, o azul.

Embora RGB seja o sistema de cor de computador mais popular no uso, há outros. Outro sistema a cores popular é HSB, que significa a cor, a saturação, o brilho. Neste sistema, as cores definem-se por graus variados de cor, saturação e brilho. O sistema de cor de HSB também se apoia por Java.

Observar
Já aprendeu sobre o suporte de Java da cor no Dia 9, "Gráfica, Fontes e Cor". Somente portanto não pensará que repito o que já aprendeu, entenda que esta discussão da cor está destinada para pôr a base mais completa das questões promovidas de usar a cor que são uma grande parte da filtração de imagem de Java.

Imagens a cores em Java

As imagens de cor de Bitmapped compõem-se de pixéis que descrevem as cores em cada posição de uma imagem. Cada pixel em uma imagem tem uma cor específica que se descreve normalmente usando o sistema de cor de RGB. Java fornece o suporte de trabalhar com imagens de 32 bits, que significa que cada pixel em uma imagem se descreve usando 32 bits. Os componentes vermelhos, verdes, e azuis da cor de um pixel guardam-se nestes 32 bits, junto com um componente alfabético. O componente alfabético de um pixel refere-se à transparência ou a opacidade do pixel.

Novo termo
Um pixel é o componente gráfico mais pequeno de uma imagem e destina-se uma determinada cor.

Novo termo
O componente alfabético de um pixel refere-se à transparência ou a opacidade do pixel.

Um pixel de imagem de Java de 32 bits, por isso, compõe-se de vermelho, verde, azul, e componentes alfabéticos. À revelia, estes quatro componentes empacotam-se em um valor de pixel de 32 bits, como mostrado na Figura 25.2. Note que cada componente se descreve em 8 bits (um byte), produzindo valores possíveis entre 0 e 255 para cada um. Estes componentes empacotam-se no valor de pixel de 32 bits do byte de alta ordem ao byte de ordem baixa na seguinte ordem: alfa, vermelha, verde, e azul. É possível para os componentes de pixel empacotar-se diferentemente, mas isto é o método de armazenamento de pixel à revelia usado em Java.

A figura 25.2: Os quatro componentes de um pixel em uma imagem de Java de 32 bits.

Um valor componente a cores de 0 significa que o componente se ausenta, e um valor de 255 significa que é maxed fora. Se os três componentes a cores forem 0, a cor de pixel resultante é preta. De mesmo modo, se os três componentes são 255, a cor é branca. Se o componente vermelho for 255 e os outros são 0, a cor resultante é a vermelhidão pura.

O componente alfabético descreve a transparência de um pixel, independente dos componentes a cores. Um valor alfabético de 0 significa que um pixel é completamente transparente (invisível), e um valor alfabético de 255 significa que um pixel é completamente opaco. Os valores entre 0 e 255 permitem à cor de fundo mostrar por um pixel em graus variados.

Os componentes a cores de uma imagem de Java encapsulam-se em uma classe simples chamada Color. A classe de Color é membro do pacote de java.awt e representa três componentes a cores primários vermelhos, verdes, e azuis. Esta classe é útil porque fornece uma abstração limpa para representar a cor, junto com métodos úteis para extrair e modificar os componentes primários. A classe de Color também contém membros constantes predestinados que representam muitas cores populares.

Modelos a cores

Em Java, as cores de pixel dirigem-se por modelos a cores. Os modelos de cor de Java fornecem uma abstração importante que permite a Java trabalhar com imagens de formatos diferentes de uma maneira semelhante. Mais especificamente, um modelo a cores é um objeto de Java que provê métodos para traduzir do pixel valoriza aos componentes a cores vermelhos, verdes, e azuis correspondentes de uma imagem. No início, isto pode parecer uma pequena tarefa trivial, sabendo que os componentes de cor de pixel se empacotam asseadamente em um valor de 32 bits. Contudo, há tipos diferentes de modelos a cores que refletem métodos diferentes de manter cores de pixel. Os dois tipos de modelos a cores apoiados por Java são modelos a cores diretos e modelos de cor de índice.

Novo termo
Um modelo a cores é uma abstração que provê um meio de converter a cor de pixel valoriza a cores absolutas.

Os modelos a cores usam-se extensivamente nas implementações internas de várias classes de processamento de imagem de Java. O que isto significa para você, programador de Java alguma vez prático? Significa que entendendo modelos a cores sabe muito sobre o trabalho interno da cor no sistema de gráfica de Java. Sem entender totalmente modelos a cores e como trabalham, não há dúvida bateria em dificuldades tentando trabalhar com as classes de gráficos e processam a imagem promovidas fornecidas por Java.

Modelos a cores diretos

Os modelos a cores diretos são baseados na descrição mais adiantada de pixéis, onde cada pixel contém cor específica e componentes alfabéticos. Os modelos a cores diretos fornecem métodos para traduzir estes tipos de pixéis na sua cor correspondente e componentes alfabéticos. Tipicamente, os modelos a cores diretos extraem os componentes apropriados do valor de pixel de 32 bits usando máscaras de bit.

Nota técnica
Um bocado a máscara é um código binário usado para extrair bits específicos fora de um valor numérico. Os bits extraem-se por AND bitwise ing a máscara com o valor. As próprias máscaras especificam-se tipicamente no hexadecimal. Por exemplo, à máscara fora a palavra de ordem baixa de um valor de 32 bits, usa a máscara 0x0000FFFF.

Modelos de cor de índice

Os modelos de cor de índice trabalham diferentemente do que modelos a cores diretos. De fato, índice colorem o trabalho de modelos com pixéis que contêm informação completamente diferente do que aprendeu até aqui. Os pixéis em uma imagem usando um modelo de cor de índice não contêm a alfa e componentes RGB como os pixéis usados em um modelo a cores direto. O pixel modelar de uma cor de índice contém um índice em uma tabela de cores fixas (ver a Figura 25.3). Esta tabela de cores chama-se um mapa a cores.

A figura 25.3: Uma cor de índice pixel modelar e o seu mapa a cores associado.

Novo termo
Um mapa a cores é uma lista de cores referidas por uma imagem usando um modelo de cor de índice. Os mapas a cores são referidos também às vezes como paletas.

Um exemplo de uma imagem que usa um modelo de cor de índice é uma imagem de 256 cores. As imagens de 256 cores usam 8 bits para descrever cada pixel, que não deixa muito quarto de componentes RGB, sem falar em um componente alfabético. Em vez de tentar abarrotar estes componentes em 8 bits, os pixéis de 256 cores guardam um índice de 8 bits em um mapa a cores. O próprio mapa a cores tem 256 entradas a cores que cada um contém RGB e a alfa valoriza descrição de uma determinada cor.

Os modelos de cor de índice fornecem métodos para resolver pixéis que contêm índices de mapa a cores na alfa, componentes vermelhos, verdes, e azuis. Maçaneta de modelos de cor de índice que procura o índice de um pixel no mapa a cores e extrai os componentes apropriados da entrada a cores.

As classes modelares a cores

Java fornece classes padrão para trabalhar com modelos a cores no pacote de java.awt.image. Em cima da hierarquia é a classe de ColorModel, que define a funcionalidade principal necessitada de todos os modelos a cores. A classe de ColorModel é uma classe abstrata que contém o suporte básico necessitado traduzir valores de pixel para alfa e componentes a cores. Duas outras classes conseguem-se de ColorModel, representando os dois tipos de modelos a cores apoiados por Java: DirectColorModel e IndexColorModel.

A classe de DirectColorModel consegue-se de ColorModel e fornece o suporte específico de modelos a cores diretos. Se lembrar, os pixéis em um modelo a cores direto diretamente contêm a alfa e colorem componentes em cada valor de pixel.

A classe de IndexColorModel também se consegue de ColorModel e fornece o suporte de modelos de cor de índice. Os pixéis em um modelo de cor de índice contêm índices em uma tabela fixa de cores conhecidas como um mapa a cores ou paleta. Embora as classes modelares a cores sejam importantes na compreensão do lado conceptual da gráfica de Java, não os estará usando diretamente trabalhando com filtros de imagem, então não há necessidade de entrar mais no detalhe com eles aqui.

Filtros de imagem

Agora é tempo de mover-se na carne da lição de hoje: filtros de imagem. A filtração de imagem é referida às vezes como processamento de imagem. A maior parte de programas de pintura gráficos populares contêm características processam a imagem, como afiação ou amolecimento de uma imagem. Tipicamente, os programas de processamento de imagem implicam o uso de bibliotecas complexas de rotinas para manipular imagens. Java fornece um simples armação ainda potente para manipular imagens. Em Java, os objetos de processamento de imagem chamam-se filtros de imagem, e servem de um modo de abstrair a filtração de uma imagem sem incomodar-se com os detalhes associados com a fonte ou o destino dos dados de imagem.

Novo termo
Um filtro de imagem é um objeto que altera os pixéis individuais de uma imagem segundo um determinado algoritmo.

Podem pensar em um filtro de imagem de Java bastante literalmente como um filtro no qual todos os dados de uma imagem devem entrar e saída no seu caminho de uma fonte a um destino. Dê uma olhada na Figura 25.4 para ver como os dados de imagem passam por um filtro de imagem.

A figura 25.4: dados de imagem que passam por um filtro de imagem.

Passando por um filtro de imagem, os pixéis individuais de uma imagem podem alterar-se de qualquer modo como determinado pelo filtro. Pelo desenho, os filtros de imagem estruturam-se para ser componentes reservados. O modelo de filtro de imagem apoiado por Java é baseado em três componentes lógicos: um produtor de imagem, um filtro de imagem e um consumidor de imagem. O produtor de imagem faz os dados de pixel crus de uma imagem disponíveis, o filtro de imagem à sua vez filtra estes dados, e os dados de imagem filtrados resultantes transmitem-se ao consumidor de imagem onde se solicitava normalmente. A figura 25.5 mostra como estes três componentes interagem um com outro.

A figura 25.5: A relação entre um produtor de imagem, um filtro de imagem e um consumidor de imagem.

Novo termo
Um produtor de imagem é uma fonte de dados abstrata que põe dados de pixel crus à disposição de uma imagem.

Novo termo
Um consumidor de imagem é um destino de dados abstrato que recebe dados de pixel crus de um consumidor de imagem.

Avariar o processo de filtrar imagens nestes três componentes fornece uma solução orientada ao objeto muito potente para um problema complexo. Os tipos diferentes de produtores de imagem podem conseguir-se que são capazes de recuperar dados de imagem de várias fontes de imagem. De mesmo modo, esta organização permite a filtros ignorar as complexidades associadas com fontes de imagem diferentes e concentrar-se nos detalhes de manipular os pixéis individuais de uma imagem.

As classes de filtro de imagem

O suporte de Java de filtros de imagem espalha-se através de várias classes e interfaces. Não necessariamente tem de entender todas estas classes detalhadamente para trabalhar com filtros de imagem, mas é importante que entenda que funcionalidade fornecem e onde se ajustam no esquema de coisas. O seguinte é as classes de Java e interfaces que fornecem o suporte da filtração de imagem:

A interface de ImageProducer descreve os métodos necessários para extrair dados de pixel de imagem de objetos de Image. As classes implementando a interface de ImageProducer fornecem implementações destes métodos específicos para a fonte de imagem que representam. Por exemplo, a classe de MemoryImageSource implementa a interface de ImageProducer e produz pixéis de imagem de uma tabela de valores de pixel guardados na memória.

A classe de FilteredImageSource implementa a interface de ImageProducer e produz dados de imagem filtrados. Os dados de imagem filtrados produzidos são baseados na imagem e o objeto de filtro passou no construtor de classe de FilteredImageSource. FilteredImageSource fornece um modo muito simples de aplicar filtros de imagem a objetos de Image.

A classe de MemoryImageSource implementa a interface de ImageProducer e produz dados de imagem baseados em uma tabela de pixéis na memória. Isto é muito útil em casos onde tem de construir um objeto de Image diretamente de dados na memória.

A interface de ImageConsumer descreve métodos necessários para um objeto de recuperar dados de imagem de um produtor de imagem. Os objetos implementando a interface de ImageConsumer anexam-se a um objeto de produtor de imagem quando se interessam nos seus dados de imagem. O objeto de produtor de imagem entrega os dados de imagem chamando métodos definidos pela interface de ImageConsumer.

A classe de PixelGrabber implementa a interface de ImageConsumer e fornece um modo de recuperar um subconjunto dos pixéis em uma imagem. Um objeto de PixelGrabber pode criar-se baseado em um objeto de Image ou em um objeto implementando a interface de ImageProducer. O construtor de PixelGrabber permite-lhe especificar uma seção retangular dos dados de imagem a agarrar-se. Estes dados de imagem então entregam-se pelo produtor de imagem ao objeto de PixelGrabber.

A classe de ImageFilter fornece a funcionalidade básica de um filtro de imagem que produz dados de imagem que se livram de um produtor de imagem a um consumidor de imagem. os objetos de ImageFilter projetam-se especificamente para usar-se em conjunto com objetos de FilteredImageSource. A classe de ImageFilter implementa-se como um filtro nulo, que significa que passa dados de imagem não modificados. No entanto, implementa o de cima para processar os dados em uma imagem. A única coisa que falha é a modificação real dos dados de pixel, que se deixam até classes de filtro conseguidas. Isto é de fato um desenho muito bonito porque lhe permite criar novos filtros de imagem derivando de ImageFilter e ignorando só alguns métodos.

A classe de ImageFilter produz uma imagem usando o modelo a cores definido pelo produtor de imagem. A classe de RGBImageFilter, de outro lado, deriva de ImageFilter e implementa um filtro de imagem específico para o default modelo de cor de RGB. RGBImageFilter fornece o necessário de cima para processar dados de imagem em um método único que converte pixéis um após outro no default modelo de cor de RGB. Este processamento realiza-se no default o modelo de cor de RGB apesar do modelo a cores usado pelo produtor de imagem. Como ImageFilter, RGBImageFilter está destinado para usar-se em conjunto com o produtor de imagem de FilteredImageSource.

A coisa aparentemente estranha sobre RGBImageFilter consiste em que é uma classe abstrata, portanto não pode instantiate objetos dele. É abstrato por causa de um método abstrato único, filterRGB. O método de filterRGB usa-se para converter um pixel de entrada único em um pixel de produção único no default modelo de cor de RGB. filterRGB é o método de cavalo para puxar arado que trata a filtração dos dados de imagem; cada pixel na imagem envia-se por este método para o processamento. Para criar os seus próprios filtros de imagem RGB, tudo que deve fazer é derivam de RGBImageFilter e implementam o método de filterRGB. Isto é a técnica que usará um pouco depois hoje quando implementa os seus próprios filtros de imagem.

A classe de RGBImageFilter contém uma variável de membro que é muito importante na determinação como processa dados de imagem: canFilterIndexColorModel. A variável de membro de canFilterIndexColorModel é um booleano que especifica se o método de filterRGB pode usar-se para filtrar as entradas de mapa a cores de uma imagem usando um modelo de cor de índice, em vez dos próprios pixéis individuais. Se esta variável de membro for false, cada pixel na imagem processa-se, semelhante a se usava um modelo a cores direto.

A classe de CropImageFilter consegue-se de ImageFilter e fornece um meio de extrair uma região retangular dentro de uma imagem. Como ImageFilter, a classe de CropImageFilter projeta-se para usar-se com o produtor de imagem de FilteredImageSource. Pode confundir-se um pouco por CropImageFilter porque parece muito com a classe de PixelGrabber mencionada antes. É importante entender as diferenças entre estas duas classes porque executam funções muito diferentes.

Em primeiro lugar, lembre-se de que PixelGrabber implementa a interface de ImageConsumer, portanto funciona como um consumidor de imagem. CropImageFilter, de outro lado, é um filtro de imagem. Isto significa que PixelGrabber se usa como um destino para dados de imagem, onde CropImageFilter se aplica a dados de imagem no trânsito. Usa PixelGrabber para extrair uma região de uma imagem para guardar em uma tabela de pixéis (o destino). Usa CropImageFilter para extrair uma região de uma imagem que se envia ao longo ao seu destino (normalmente outro objeto de Image).

Escrever os seus próprios filtros de imagem

Embora as classes de filtro de imagem de Java padrão sejam potentes como uma armação, não são que excitação para trabalhar com por si mesmos. Os filtros de imagem realmente não se tornam interessantes até que comece a implementar o seu próprio. Afortunadamente, as classes de Java fazem muito simples escrever os seus próprios filtros de imagem.

Toda a imagem filtra vai se desenvolver na lição de hoje conseguem-se de RGBImageFilter, que lhe permite filtrar imagens por um método único, filterRGB. Realmente é tão fácil como conseguir a sua classe de RGBImageFilter e implementar o método de filterRGB. Vamos dar-lhe uma tentativa!

Um filtro de imagem a cores

Provavelmente a imagem mais simples filtra imaginável é aquele que filtra os componentes a cores individuais (vermelho, verde, e azul) de uma imagem. A classe de ColorFilter faz exatamente isto. A listagem 25.1 contém o texto fonte da classe de ColorFilter. Localiza-se no CD-ROM no arquivo ColorFilter.java.


A listagem 25.1. A classe de ColorFilter.
 1: class ColorFilter extends RGBImageFilter {
 2:   boolean red, green, blue;
 3:
 4:   public ColorFilter(boolean r, boolean g, boolean b) {
 5:     red = r;
 6:     green = g;
 7:     blue = b;
 8:     canFilterIndexColorModel = true;
 9:   }
10:
11:   public int filterRGB(int x, int y, int rgb) {
12:     // Filter the colors
13:     int r = red ? 0: ((rgb >> 16) & 0xff);
14:     int g = green ? 0: ((rgb >> 8) & 0xff);
15:     int b = blue ? 0: ((rgb >> 0) & 0xff);
16:
17:     // Return the result
18:     return (rgb & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
19:   }
20: }

Análise
A classe de ColorFilter consegue-se de RGBImageFilter e contém três variáveis de membro booleanas que determinam que cores devem filtrar-se fora da imagem. Estas variáveis de membro estabelecem-se pelos parâmetros passados no construtor. A variável de membro herdou de RGBImageFilter-canFilterIndexColorModel-is o jogo a true para indicar que as entradas de mapa a cores podem filtrar-se usando filterRGB se a imagem de entrada estiver usando um modelo de cor de índice.

Além do construtor, ColorFilter implementa só um método, filterRGB, que é o método abstrato definido em RGBImageFilter. filterRGB toma três parâmetros: o x e a posição y do pixel dentro da imagem e o de 32 bits (número inteiro) colorem o valor. O único parâmetro com o qual se preocupa é o valor a cores, rgb.

Recordando que o default modelo de cor de RGB coloca os componentes vermelhos, verdes, e azuis em 24 bits mais baixos do valor a cores de 32 bits, é fácil extrair cada um deslocando fora do parâmetro de rgb. Estes componentes individuais guardam-se nas variáveis locais r, g e b. Note, contudo, que cada componente a cores só se desloca se não se estiver filtrando. Para cores filtradas, o componente a cores estabelece-se em 0.

Os novos componentes a cores então deslocam-se atrás em um valor a cores de 32 bits e devolvem-se de filterRGB. Note que o cuidado se toma para assegurar que o componente alfabético do valor a cores não se altera. A máscara de 0xff000000 cuida disto porque o componente alfabético reside no byte superior do valor a cores.

Congratulações! Escreveu o seu primeiro filtro de imagem! Tem mais dois para ir antes que tape todos eles em um programa de prova.

Um filtro de imagem alfabético

Não sempre é evidente para programadores como o valor alfabético guardado no valor a cores de cada pixel afeta uma imagem. Lembre-se de que o componente alfabético especifica a transparência ou a opacidade de um pixel. Alterando a alfa valoriza por uma imagem inteira, pode fazê-la parecer subir e fora. Isto trabalha porque a alfa valoriza variedade do totalmente transparente (invisível) para o totalmente opaco.

A classe de AlphaFilter filtra os componentes alfabéticos de uma imagem segundo o nível alfabético que fornece no seu construtor. A listagem 25.2 contém o texto fonte da classe de AlphaFilter. Localiza-se no CD-ROM no arquivo AlphaFilter.java.


A listagem 25.2. A classe de AlphaFilter.
 1: class AlphaFilter extends RGBImageFilter {
 2:   int alphaLevel;
 3:
 4:   public AlphaFilter(int alpha) {
 5:     alphaLevel = alpha;
 6:     canFilterIndexColorModel = true;
 7:   }
 8:
 9:   public int filterRGB(int x, int y, int rgb) {
10:     // Adjust the alpha value
11:     int alpha = (rgb >> 24) & 0xff;
12:     alpha = (alpha * alphaLevel) / 255;
13:
14:     // Return the result
15:     return ((rgb & 0x00ffffff) | (alpha << 24));
16:   }
17: }

Análise
A classe de AlphaFilter contém uma variável de membro única, alphaLevel, que acompanha o nível alfabético a aplicar-se à imagem. Esta variável de membro inicializa-se no construtor, como é a variável de membro de canFilterIndexModel.

Semelhante à classe de ColorFilter, o método de filterRGB é o único outro método implementado por AlphaFilter. O componente alfabético do pixel extrai-se primeiro deslocando-o em uma variável local, alpha. Este valor então escala-se segundo a variável de membro de alphaLevel inicializada no construtor. O objetivo da escalada é alterar o valor alfabético baseado no seu valor atual. Se devesse estabelecer o componente alfabético no nível alfabético, não estaria considerando o valor de componente alfabético original.

O novo componente alfabético desloca-se atrás no valor de cor de pixel e o resultado voltou de filterRGB. Note que os componentes vermelhos, verdes, e azuis se conservam usando a máscara de 0x00ffffff.

Um filtro de imagem de brilho

Por enquanto os filtros de imagem que viu foram bastante simples. O último que cria é um pouco mais complexo, mas atua como um filtro mais interessante. A classe de BrightnessFilter implementa um filtro de imagem que clareia ou escurece uma imagem baseada em uma percentagem de brilho que fornece no construtor. A listagem 25.3 contém o texto fonte da classe de BrightnessFilter. Localiza-se no CD-ROM no arquivo BrightnessFilter.java.


A listagem 25.3. A classe de BrightnessFilter.
 1: class BrightnessFilter extends RGBImageFilter {
 2:   int brightness;
 3:
 4:   public BrightnessFilter(int b) {
 5:     brightness = b;
 6:     canFilterIndexColorModel = true;
 7:   }
 8:
 9:   public int filterRGB(int x, int y, int rgb) {
10:     // Get the individual colors
11:     int r = (rgb >> 16) & 0xff;
12:     int g = (rgb >> 8) & 0xff;
13:     int b = (rgb >> 0) & 0xff;
14:
15:     // Calculate the brightness
16:     r += (brightness * r) / 100;
17:     g += (brightness * g) / 100;
18:     b += (brightness * b) / 100;
19:
20:     // Check the boundaries
21:     r = Math.min(Math.max(0, r), 255);
22:     g = Math.min(Math.max(0, g), 255);
23:     b = Math.min(Math.max(0, b), 255);
24:
25:     // Return the result
26:     return (rgb & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
27:   }
28: }

Análise
A classe de BrightnessFilter contém uma variável de membro, brightness, que guarda a pista da percentagem para alterar o brilho da imagem. Esta variável de membro estabelece-se via o construtor, junto com a variável de membro de canFilterIndexModel. A variável de membro de brightness pode conter valores na variedade-100 a 100. Um valor de -100 significa que a imagem se escurece em 100 por cento, e um valor de 100 significa que a imagem se clareia em 100 por cento. Um valor de 0 não altera o brilho da imagem em absoluto.

Não deve vir como nenhuma surpresa por agora que filterRGB seja o único outro método implementado por BrightnessFilter. Em filterRGB, os componentes a cores individuais extraem-se primeiro nas variáveis locais r, g e b. Os efeitos de brilho então calculam-se baseados na variável de membro de brightness. Os novos componentes a cores então verificam-se contra os 0 e 255 limites e modificam-se se necessário.

Finalmente, os novos componentes a cores deslocam-se atrás no valor de cor de pixel e devolvem-se de filterRGB. Eh, não que complicado no fim de tudo!

Utilização de filtros de imagem

Instala no tempo escrevendo alguns dos seus próprios filtros de imagem, mas ainda tem de gostar do fruto dos seus trabalhos. É tempo de tapar os filtros em verdadeiro Java applet e ver como trabalham. A figura 25.6 mostra o FilterTest applet de maneira ocupada no trabalho que filtra uma imagem de uma pêra, bastante literalmente o fruto dos seus trabalhos!

A figura 25.6: The FilterTest applet.

O FilterTest applet usa os três filtros escreveu permitir-lhe filtrar uma imagem de uma pêra. O R, G, e B ligam a modificação de teclado as cores diferentes filtradas pelo filtro a cores. As teclas de seta esquerdas e direitas modificam o nível alfabético do filtro alfabético. O de cima para baixo de teclas de seta alteram a percentagem de brilho usada pelo filtro de brilho. Finalmente, a chave de Casa restitui a imagem ao seu estado não filtrado.

A listagem 25.4 contém o texto fonte do FilterTest applet. O texto fonte completo e executables do FilterTest applet localizam-se no acompanhamento
CD-ROM.


A listagem 25.4. O FilterTest applet.
 1: public class FilterTest extends Applet {
 2:   Image     src, dst;
 3:   boolean   red, green, blue;
 4:   final int alphaMax = 9;
 5:   int       alphaLevel = alphaMax;
 6:   int       brightness;
 7:
 8:   public void init() {
 9:     src = getImage(getDocumentBase(), "Pear.gif");
10:     dst = src;
11:   }
12:
13:   public void paint(Graphics g) {
14:     g.drawImage(dst, 0, 0, this);
15:   }
16:
17:   public boolean keyDown(Event evt, int key) {
18:     switch (key) {
19:     case Event.HOME:
20:       red = false;
21:       green = false;
22:       blue = false;
23:       alphaLevel = alphaMax;
24:       brightness = 0;
25:       break;
26:     case Event.LEFT:
27:       if (--alphaLevel < 0)
28:         alphaLevel = 0;
29:       break;
30:     case Event.RIGHT:
31:       if (++alphaLevel > alphaMax)
32:         alphaLevel = alphaMax;
33:       break;
34:     case Event.UP:
35:       brightness = Math.min(brightness + 10, 100);
36:       break;
37:     case Event.DOWN:
38:       brightness = Math.max(-100, brightness - 10);
39:       break;
40:     case (int)'r':
41:     case (int)'R':
42:       red = !red;
43:       break;
44:     case (int)'g':
45:     case (int)'G':
46:       green = !green;
47:       break;
48:     case (int)'b':
49:     case (int)'B':
50:       blue = !blue;
51:       break;
52:     default:
53:       return false;
54:     }
55:     filterImage();
56:     return true;
57:   }
58:
59:   void filterImage() {
60:     dst = src;
61:
62:     // Apply the color filter
63:     dst = createImage(new FilteredImageSource(dst.getSource(),
64:       new ColorFilter(red, green, blue)));
65:
66:     // Apply the alpha filter
67:     dst = createImage(new FilteredImageSource(dst.getSource(),
68:       new AlphaFilter((alphaLevel * 255) / alphaMax)));
69:
70:     // Apply the brightness filter
71:     dst = createImage(new FilteredImageSource(dst.getSource(),
72:       new BrightnessFilter(brightness)));
73:
74:     // Redraw the image
75:     repaint();
76:   }
77: }

Análise
O FilterTest applet classe contém variáveis de membro para acompanhar a fonte e imagens de destino, junto com variáveis de membro para manter vários parâmetros de filtro.

O primeiro método implementado por FilterTest é init, que carrega a imagem Pear.gif na variável de membro de src. Também inicializa a variável de membro de dst à mesma imagem. O método de paint implementa-se depois, e simplesmente compõe-se de uma chamada ao método de drawImage, que desenha o objeto de Image (filtrado) do destino.

O método de keyDown implementa-se para tratar eventos de teclado gerados pelo usuário. Neste caso, as chaves usadas para controlar os filtros de imagem tratam-se na afirmação de switch. As variáveis de membro correspondentes alteram-se segundo as chaves apertadas. Note a chamada ao filterImage perto do fim de keyDown.

O método de filterImage é onde a filtração real se realiza; aplica cada filtro de imagem à imagem. A variável de membro de dst inicializa-se primeiro com a variável de membro de src para restituir a imagem de destino ao seu estado original. Cada filtro então aplica-se usando uma chamada confusa de aspecto a createImage. O único parâmetro a createImage é um objeto de ImageProducer. Neste caso, cria um objeto de FilteredImageSource de passar em createImage. O construtor de FilteredImageSource toma dois parâmetros: um produtor de imagem e um filtro de imagem. O primeiro parâmetro é um objeto de ImageProducer da imagem de fonte, que se obtém usando o método de getSource para a imagem. O segundo parâmetro é um ImageFilter - objeto conseguido.

O filtro a cores aplica-se primeiro à imagem criando um objeto de ColorFilter usando três variáveis de membro de valor a cores booleanas. O filtro alfabético aplica-se criando um objeto de AlphaFilter usando a variável de membro de alphaLevel. Em vez de permitir 255 níveis alfabéticos diferentes, o nível alfabético normaliza-se para fornecer só 10 níveis alfabéticos diferentes. Isto é evidente na equação usando alphaMax, que se estabelece em 9. Finalmente, o filtro de brilho aplica-se criando um objeto de BrightnessFilter e passando na variável de membro de brightness.

Sumário

Embora a meta total da lição de hoje seja aprender como usar filtros de imagem, também cobriu muito material relacionado ao longo do caminho. Primeiro aprendeu sobre a cor em geral e logo sobre o coração da gráfica de Java promovida: modelos a cores. Com modelos a cores abaixo do seu cinto, mudou a filtros de imagem. Viu como as classes de filtro de imagem de Java fornecem uma armação potente para trabalhar com imagens sem incomodar-se com detalhes desnecessários. Terminou a lição escrevendo três dos seus próprios filtros de imagem, junto com um applet que os põem para trabalhar filtrando uma verdadeira imagem.

É bem versado agora em uma das áreas mais promovidas da programação de gráfica de Java. A título de prevenção começa a queimar em todo este material de gráficos, a lição de amanhã desloca engrenagens dramaticamente e apresenta-o à programação de rede de cliente/servidor em Java.

Perguntas e Respostas

Q:
Se as cores de Java forem inerentemente 32 bits, como Java expõe a cor em sistemas usando menos de 32 bits para representar a cor?
A:
A realidade é que não há muitos sistemas de computador lá fora equipados para apoiar totalmente a cor de 32 bits. Por exemplo, os PCs mais de alta qualidade e os Macintosh só apoiam a cor de 24 bits. Adicionalmente, o PC médio só apoia a cor de 8 bits. Java trata isto interiormente fazendo o mapa da cor de 32 bits valoriza ao sistema subjacente o mais eficientemente possível, às vezes usando um modelo de cor de índice. Em alguns casos a qualidade de imagem sofrerá porque a variedade cheia de cores na imagem não pode expor-se.
Q:
Ainda não entendo porque há um componente alfabético em cores de Java. Qual é o acordo?
A:
Propriamente dito, tudo que se necessita de Java apoiar uma ampla variação de cores é três componentes a cores primários: vermelho, verde, e azul. Contudo, o componente alfabético acrescenta a capacidade de alterar a opacidade de uma cor, que faz muito mais fácil implementar efeitos de gráficos que alteram as propriedades de transparência de uma cor.
Q:
Há uma situação em que precisarei de implementar alguma vez o meu próprio modelo a cores?
A:
Sou hesitante para dizer que nunca precisará de implementar o seu próprio modelo a cores, mas deixar-me dizer que a situação na qual precisaria de um modelo a cores alfandegário altamente improvavelmente ocorrerá. Isto é porque os modelos a cores são principalmente uma abstração interna usada pelo próprio sistema de gráfica de Java.
Q:
Entendo porque os filtros de imagem são úteis, mas qual exatamente é a importância de produtores de imagem e consumidores?
A:
Os produtores de imagem e os consumidores fornecem uma abstração limpa para a fonte e o destino de dados de imagem crus. Sem produtores de imagem e consumidores, teria de usar uma solução alfandegária cada vez quando quis adquirir dados de ou escrever dados a uma imagem. Tendo a fonte e o destino de dados de imagem as funções de gráficos claramente definidas, mais promovidas como filtros de imagem são muito mais fáceis trabalhar com.