Criação e aplicação de filtros

Flash Player 9 e posterior, Adobe AIR 1.0 e posterior

Os filtros permitem aplicar diversos efeitos em objetos de exibição e bitmap, variando desde sombras projetadas até biséis e desfoques. Cada filtro é definido como uma classe, de modo que a aplicação de filtros envolve a criação de ocorrências de objetos de filtro, o que equivale a criar qualquer outro objeto. Depois de criar uma ocorrência de um objeto de filtro, é possível aplicá-la com facilidade em um objeto de exibição usando a propriedade filters do objeto ou, no caso de um objeto BitmapData, usando o método applyFilter() .

Criação de um filtro

Para criar um objeto de filtro, basta chamar o método de construtor da classe de filtro selecionada. Por exemplo, para criar um objeto DropShadowFilter, use o seguinte código:

import flash.filters.DropShadowFilter; 
var myFilter:DropShadowFilter = new DropShadowFilter();

Embora não seja mostrado aqui, o construtor DropShadowFilter() (como todos os construtores de classes de filtro) aceita vários parâmetros opcionais que podem ser usados para personalizar a aparência do efeito do filtro.

Aplicação de um filtro

Depois de criar um objeto de filtro, você pode aplicá-lo em um objeto de exibição ou em um objeto BitmapData; o modo de aplicação do filtro depende do objeto no qual ele será aplicado.

Aplicação de um filtro em um objeto de exibição

Use a propriedade filters para aplicar efeitos de filtro em um objeto de exibição. A propriedade filters de um objeto de exibição é uma ocorrência de Array, cujos elementos são objetos de filtro aplicados no objeto de exibição. Para aplicar um único filtro em um objeto de exibição, crie a ocorrência de filtro, adicione-a a uma ocorrência de Array e atribua esse objeto Array à propriedade filters do objeto de exibição:

import flash.display.Bitmap; 
import flash.display.BitmapData; 
import flash.filters.DropShadowFilter; 
 
// Create a bitmapData object and render it to screen 
var myBitmapData:BitmapData = new BitmapData(100,100,false,0xFFFF3300); 
var myDisplayObject:Bitmap = new Bitmap(myBitmapData); 
addChild(myDisplayObject); 
 
// Create a DropShadowFilter instance. 
var dropShadow:DropShadowFilter = new DropShadowFilter(); 
 
// Create the filters array, adding the filter to the array by passing it as  
// a parameter to the Array() constructor. 
var filtersArray:Array = new Array(dropShadow); 
 
// Assign the filters array to the display object to apply the filter. 
myDisplayObject.filters = filtersArray;

Se desejar atribuir vários filtros ao objeto, basta adicionar todos os filtros à ocorrência de Array antes de atribuí-la à propriedade filters . Para adicionar vários objetos a uma matriz, transmita-os como parâmetros para o construtor. Por exemplo, esse código aplica um filtro de bisel e um filtro de brilho ao objeto de exibição criado anteriormente:

import flash.filters.BevelFilter; 
import flash.filters.GlowFilter; 
 
// Create the filters and add them to an array. 
var bevel:BevelFilter = new BevelFilter(); 
var glow:GlowFilter = new GlowFilter(); 
var filtersArray:Array = new Array(bevel, glow); 
 
// Assign the filters array to the display object to apply the filter. 
myDisplayObject.filters = filtersArray;

Ao criar a matriz que contém os filtros, você pode usar o construtor new Array() (conforme mostrado nos exemplos anteriores) ou a sintaxe do literal de matriz, colocando os filtros entre colchetes ( [] ). Por exemplo, esta linha de código:

var filters:Array = new Array(dropShadow, blur); 

faz a mesma coisa que esta linha de código:

var filters:Array = [dropShadow, blur];

Se vários filtros forem aplicados em objetos de exibição, a aplicação será feita de modo cumulativo e sequencial. Por exemplo, se uma matriz de filtros tiver dois elementos, um filtro de bisel adicionado primeiro e um filtro de sombra projetada adicionado depois, o filtro de sombra projetada será aplicado no filtro de bisel e no objeto de exibição. Isso ocorre devido à posição do filtro de sombra projetada em segundo lugar na matriz de filtros. Se desejar aplicar filtros de modo não cumulativo, você deve aplicar cada filtro em uma nova cópia do objeto de exibição.

Se estiver atribuindo apenas um ou alguns filtros a um objeto de exibição, crie a ocorrência do filtro e atribua-a ao objeto em uma única instrução. Por exemplo, a linha de código a seguir aplica um filtro de desfoque em um objeto de exibição chamado myDisplayObject :

myDisplayObject.filters = [new BlurFilter()];

O código anterior cria uma ocorrência de Array usando a sintaxe do literal de matriz (entre colchetes), cria uma ocorrência de BlurFilter como um elemento da matriz e atribui a essa matriz a propriedade filters do objeto de exibição chamado myDisplayObject .

Remoção de filtros de um objeto de exibição

A remoção de todos os filtros de um objeto de exibição é tão simples quanto atribuir um valor nulo à propriedade filters :

myDisplayObject.filters = null;

Se tiver aplicado vários filtros em um objeto e desejar remover apenas um dos filtros, realize as etapas para alterar a matriz da propriedade filters . Para obter mais informações, consulte Possíveis problemas resultantes do trabalho com filtros .

Aplicação de um filtro em um objeto BitmapData

A aplicação de um filtro em um objeto BitmapData requer o uso do método applyFilter() do objeto BitmapData:

var rect:Rectangle = new Rectangle(); 
var origin:Point = new Point(); 
myBitmapData.applyFilter(sourceBitmapData, rect, origin, new BlurFilter());

O método applyFilter() aplica um filtro em um objeto BitmapData de origem, produzindo uma nova imagem filtrada. Esse método não modifica a imagem de origem inicial; em vez disso, o resultado da aplicação do filtro na imagem de origem é armazenado na ocorrência de BitmapData na qual o método applyFilter() é chamado.

Como funcionam os filtros

A filtragem de objetos de exibição funciona armazenando uma cópia do objeto original em cache como um bitmap transparente.

Assim que um filtro é aplicado em um objeto de exibição, o tempo de execução armazena o objeto em cache como um bitmap enquanto o objeto tiver uma lista de filtros válida. O bitmap de origem é usado como imagem original para todos os efeitos de filtro aplicados posteriormente.

Cada objeto de exibição geralmente contém dois bitmaps: um com o objeto original de exibição de origem e outro para a imagem final, após a filtragem. A imagem final é usada no momento da renderização. Desde que o objeto de exibição não seja alterado, a imagem final não precisa de atualização.

Possíveis problemas resultantes do trabalho com filtros

Existem várias fontes de possíveis problemas que devem ser consideradas ao trabalhar com filtros.

Cache de bitmaps e filtros

Para aplicar um filtro em um objeto de exibição, o cache de bitmaps deve ser ativado para esse objeto. Quando você aplica um filtro a um objeto de exibição cuja propriedade cacheAsBitmap está definida como false , a propriedade cacheAsBitmap do objeto é automaticamente definida como true . Se mais tarde você remover todos os filtros do objeto de exibição, a propriedade cacheAsBitmap é definida para o último valor em que estava.

Alteração de filtros em tempo de execução

Se um objeto de exibição já tiver um ou mais filtros aplicados, não será possível alterar o conjunto de filtros adicionando mais filtros ou removendo filtros da matriz da propriedade filters . Em vez disso, para adicionar ou alterar o conjunto de filtros aplicados, faça as alterações em uma matriz separada e, em seguida, atribua essa matriz à propriedade filters do objeto de exibição para que os filters sejam aplicados no objeto. A maneira mais simples de fazer isso é ler a matriz da propriedade filters em uma variável Array e fazer as modificações nessa matriz temporária. Depois, atribua essa matriz novamente à propriedade filters do objeto de exibição. Em casos mais complexos, talvez seja necessário manter uma matriz de filtros principal separada. Faça as alterações nessa matriz de filtros principal e atribua-a novamente à propriedade filters do objeto de exibição depois de cada alteração.

Adição de mais um filtro

O código a seguir demonstra o processo de adição de mais um filtro a um objeto de exibição que já tem um ou mais filtros aplicados. Inicialmente, um filtro de brilho é aplicado no objeto de exibição chamado myDisplayObject ; posteriormente, quando o objeto de exibição é clicado, a função addFilters() é chamada. Nesta função, dois filtros adicionais são aplicados em myDisplayObject :

import flash.events.MouseEvent; 
import flash.filters.*; 
 
myDisplayObject.filters = [new GlowFilter()]; 
 
function addFilters(event:MouseEvent):void 
{ 
    // Make a copy of the filters array. 
    var filtersCopy:Array = myDisplayObject.filters; 
 
    // Make desired changes to the filters (in this case, adding filters). 
    filtersCopy.push(new BlurFilter()); 
    filtersCopy.push(new DropShadowFilter()); 
 
    // Apply the changes by reassigning the array to the filters property. 
    myDisplayObject.filters = filtersCopy; 
} 
 
myDisplayObject.addEventListener(MouseEvent.CLICK, addFilters);

Remoção de um filtro do conjunto de filtros

Se um objeto de exibição tiver vários filtros aplicados e você desejar remover um dos filtros enquanto os outros continuam a ser aplicados no objeto, copie os filtros em uma matriz separada, remova o filtro indesejado dessa matriz e atribua a matriz temporária novamente à propriedade filters do objeto de exibição. Várias maneiras de remover um ou mais elementos de qualquer matriz são descritas em Recuperação de valores e remoção de elementos de matriz .

O mais fácil é remover o filtro de nível superior do objeto (o último filtro aplicado no objeto). Use o método pop() da classe Array para remover o filtro da matriz:

// Example of removing the top-most filter from a display object  
// named "filteredObject". 
 
var tempFilters:Array = filteredObject.filters; 
 
// Remove the last element from the Array (the top-most filter). 
tempFilters.pop(); 
 
// Apply the new set of filters to the display object. 
filteredObject.filters = tempFilters;

Similarmente, para remover o filtro de nível inferior (o primeiro aplicado no objeto), use o mesmo código, usando o método shift() da matriz Array em vez do método pop() .

Para remover um filtro do meio de uma matriz de filtros (supondo que a matriz tem mais de dois filtros), use o método splice() . Você deve saber o índice (a posição na matriz) do filtro que deseja remover. Por exemplo, o código a seguir remove o segundo filtro (no índice 1) de um objeto de exibição:

// Example of removing a filter from the middle of a stack of filters 
// applied to a display object named "filteredObject". 
 
var tempFilters:Array = filteredObject.filters; 
 
// Remove the second filter from the array. It's the item at index 1  
// because Array indexes start from 0. 
// The first "1" indicates the index of the filter to remove; the  
// second "1" indicates how many elements to remove. 
tempFilters.splice(1, 1); 
 
// Apply the new set of filters to the display object. 
filteredObject.filters = tempFilters;

Determinação do índice de um filtro

Você precisa saber qual filtro deve ser removido da matriz para determinar o índice do filtro. Você deve saber (em virtude da designação do aplicativo) ou calcular o índice do filtro a ser removido.

A melhor maneira é designar o aplicativo de modo que o filtro a ser removido sempre fique na mesma posição no conjunto de filtros. Por exemplo, se houver apenas um objeto de exibição com um filtro de convolução e um filtro de sombra projetada aplicados (nessa ordem) e você desejar remover o filtro de sombra projetada, mas manter o outro, o filtro estará em uma posição conhecida (o filtro de nível superior) para que você saiba com antecedência qual método Array deve ser usado (neste caso, Array.pop() para remover o filtro de sombra projetada).

Se o filtro que deseja remover for sempre do mesmo tipo, mas não estiver necessariamente na mesma posição do conjunto de filtros todas as vezes, verifique o tipo de dados de cada filtro da matriz para determinar qual deve ser removido. Por exemplo, o código a seguir determina qual é o filtro de brilho em um conjunto de filtros e remove esse filtro do conjunto.

// Example of removing a glow filter from a set of filters, where the 
//filter you want to remove is the only GlowFilter instance applied  
// to the filtered object. 
 
var tempFilters:Array = filteredObject.filters; 
 
// Loop through the filters to find the index of the GlowFilter instance. 
var glowIndex:int; 
var numFilters:int = tempFilters.length; 
for (var i:int = 0; i < numFilters; i++) 
{ 
    if (tempFilters[i] is GlowFilter) 
    { 
        glowIndex = i; 
        break; 
    } 
} 
 
// Remove the glow filter from the array. 
tempFilters.splice(glowIndex, 1); 
 
// Apply the new set of filters to the display object. 
filteredObject.filters = tempFilters;

Em um caso mais complexo, como se o filtro a ser removido for selecionado em tempo de execução, o melhor é manter uma cópia separada permanente da matriz de filtros que serve como a lista principal de filtros. Sempre que você alterar o conjunto de filtros, altere a lista principal e aplique essa matriz de filtros como a propriedade filters do objeto de exibição.

Por exemplo, na listagem de código a seguir, vários filtros de convolução são aplicados em um objeto de exibição para criar efeitos visuais diferentes e, posteriormente, um desses filtros é removido enquanto os outros são mantidos. Neste caso, o código mantém uma cópia principal da matriz de filtros, bem como uma referência ao filtro a ser removido. Localizar e remover o filtro específico é similar à abordagem anterior, mas, em vez de criar uma cópia temporária da matriz de filtros, a cópia principal é manipulada e aplicada no objeto de exibição.

// Example of removing a filter from a set of  
// filters, where there may be more than one  
// of that type of filter applied to the filtered  
// object, and you only want to remove one. 
 
// A master list of filters is stored in a separate, 
// persistent Array variable. 
var masterFilterList:Array; 
 
// At some point, you store a reference to the filter you 
// want to remove. 
var filterToRemove:ConvolutionFilter; 
 
// ... assume the filters have been added to masterFilterList, 
// which is then assigned as the filteredObject.filters: 
filteredObject.filters = masterFilterList; 
 
// ... later, when it's time to remove the filter, this code gets called: 
 
// Loop through the filters to find the index of masterFilterList. 
var removeIndex:int = -1; 
var numFilters:int = masterFilterList.length; 
for (var i:int = 0; i < numFilters; i++) 
{ 
    if (masterFilterList[i] == filterToRemove) 
    { 
        removeIndex = i; 
        break; 
    } 
} 
 
if (removeIndex >= 0) 
{ 
    // Remove the filter from the array. 
    masterFilterList.splice(removeIndex, 1); 
 
    // Apply the new set of filters to the display object. 
    filteredObject.filters = masterFilterList; 
}

Nesta abordagem (quando estiver comparando uma referência de filtro armazenada com os itens da matriz de filtros para determinar qual filtro deve ser removido), você deve manter uma cópia separada da matriz de filtros - o código não funcionará se a referência de filtro armazenada for comparada com os elementos de uma matriz temporária copiada da propriedade filters do objeto de exibição. Isso ocorre porque internamente, quando uma matriz é atribuída à propriedade filters , o tempo de execução faz uma cópia de cada objeto de filtro na matriz. Essas cópias (não os objetos originais) são aplicadas no objeto de exibição e, quando a propriedade filters é lida em uma matriz temporária, a matriz temporária contém referências aos objetos de filtro copiados, em vez de referências aos objetos de filtro originais. Consequentemente, se no exemplo anterior você tentar determinar o índice de filterToRemove comparando-o com os filtros de uma matriz temporária, nenhuma correspondência será encontrada.

Transformações de objeto e filtros

Nenhuma região filtrada (uma sombra projetada, por exemplo) fora do retângulo delimitador do objeto de exibição é considerada como parte da superfície para fins de detecção de ocorrências (determinar se uma ocorrência se sobrepõe ou faz interseção com outra). Como os métodos de detecção de ocorrências da classe DisplayObject são baseados em vetores, não é possível detectar ocorrências no resultado de bitmap. Por exemplo, se um filtro de bisel for aplicado em uma ocorrência de botão, a detecção de ocorrências não estará disponível na parte do bisel da ocorrência.

Os filtros não permitem dimensionar, girar e inclinar objetos; se o objeto de exibição filtrado for dimensionado (se scaleX e scaleY não forem 100%), o efeito de filtro não será dimensionado com a ocorrência. Isso significa que a forma original da ocorrência é girada, dimensionada ou inclinada; no entanto, o filtro não é girado, dimensionado ou inclinado com a ocorrência.

Você pode animar uma ocorrência com um filtro para criar efeitos realistas ou aninhar ocorrências e usar a classe BitmapData para animar os filtros e atingir esse efeito.

Objetos de bitmap e filtros

Quando algum filtro é aplicado em um objeto BitmapData, a propriedade cacheAsBitmap é definida automaticamente como true . Desse modo, o filtro é realmente aplicado na cópia do objeto, não no original.

Em seguida, essa cópia é colocada na exibição principal (no objeto original) o mais perto possível do pixel mais próximo. Se os limites do bitmap original forem alterados, o bitmap de cópia filtrado será recriado a partir do original, em vez de ser esticado ou distorcido.

Se você apagar todos os filtros de um objeto de exibição, a propriedade cacheAsBitmap será redefinida como o valor original antes do filtro ser aplicado.