Création et application de filtres

Flash Player 9 et les versions ultérieures, Adobe AIR 1.0 et les versions ultérieures

Les filtres permettent d’appliquer divers effets (ombre portée, biseau, flou, etc.) à des images bitmap et à des objets d’affichage. Chaque filtre étant défini sous forme de classe, il suffit pour appliquer un filtre de créer une occurrence d’un objet filtre, ce qui n’est guère différent de la création de tout autre objet. Après avoir créé une occurrence d’un objet filtre, il est facile de l’appliquer à un objet d’affichage à l’aide de la propriété filters de cet objet ou, dans le cas d’un objet BitmapData, de sa méthode applyFilter() .

Création d’un filtre

Pour créer un objet filtre, il suffit d’appeler la fonction constructeur de la classe du filtre voulu. Par exemple, pour créer un objet DropShadowFilter, utilisez le code suivant :

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

Bien que cela n’apparaisse pas dans cet exemple, le constructeur de DropShadowFilter() (comme tous les autres constructeurs des classes de filtres) accepte plusieurs paramètres facultatifs qui permettent de modifier l’aspect de l’effet du filtre.

Application d’un filtre

Lorsque l’objet filtre a été créé, vous pouvez l’appliquer à un objet d’affichage ou à un objet BitmapData, mais le mode d’application du filtre dépend de l’objet concerné.

Application d’un filtre à un objet d’affichage

Pour appliquer un effet de filtrage à un objet d’affichage, utilisez sa propriété filters . La propriété filters d’un objet d’affichage est une occurrence de l’objet Array, dont les éléments sont les objets filtres appliqués à l’objet d’affichage. Pour appliquer un seul filtre à un objet d’affichage, créez l’occurrence de ce filtre, ajoutez-la à une occurrence d’Array, et affectez cet objet Array à la propriété filters de l’objet d’affichage :

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;

Pour affecter plusieurs filtres à l’objet, il suffit d’ajouter tous ces filtres à l’occurrence d’Array avant de l’affecter à la propriété filters . Vous pouvez ajouter plusieurs objets à un objet Array en les passant en paramètres à son constructeur. Par exemple, ce code applique un filtre Biseau et un filtre Rayonnement à l’objet d’affichage créé précédemment :

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;

Pour créer le tableau des filtres, vous pouvez utiliser le constructeur new Array() (comme dans les exemples précédents) ou la syntaxe littérale Array, en mettant les filtres entre crochets ( [] ). Par exemple, cette ligne de code :

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

donne un résultat identique à celle-ci :

var filters:Array = [dropShadow, blur];

Si vous appliquez plusieurs filtres à des objets d’affichage, ils sont appliqués en séquence, de manière cumulative. Par exemple, si un tableau de filtres comporte deux éléments, le filtre Biseau puis le filtre Ombre portée, ce dernier est appliqué à la fois au filtre Biseau et à l’objet d’affichage lui-même, du fait que le filtre Ombre portée est en seconde position dans le tableau des filtres. Si vous souhaitez appliquer des filtres de manière non cumulative, appliquez chaque filtre à une nouvelle copie de l’objet d’affichage.

Pour affecter uniquement un ou quelques filtres à un objet d’affichage, vous pouvez créer l’occurrence du filtre et l’affecter à l’objet dans la même instruction. Par exemple, le code suivant applique un filtre Flou à un objet d’affichage nommé myDisplayObject :

myDisplayObject.filters = [new BlurFilter()];

Le code précédent crée une occurrence d’Array en utilisant la syntaxe littérale d’Array (entre crochets), puis crée une nouvelle occurrence de BlurFilter comme élément du tableau, et affecte ce dernier à la propriété filters de l’objet d’affichage myDisplayObject .

Suppression des filtres appliqués à un objet

Pour supprimer tous les filtres d’un objet d’affichage, il suffit d’affecter la valeur null à la propriété filters de celui-ci :

myDisplayObject.filters = null;

Si vous avez appliqué plusieurs filtres à un objet et souhaitez n’en supprimer qu’un, plusieurs étapes sont nécessaires pour modifier le tableau de la propriété filters . Pour plus d’informations, voir Problèmes potentiels d’utilisation des filtres .

Application d’un filtre à un objet BitmapData

L’application d’un filtre à un objet BitmapData nécessite d’utiliser la méthode applyFilter() de l’objet BitmapData :

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

La méthode applyFilter() applique un filtre à un objet source BitmapData, produisant ainsi une nouvelle image filtrée. Cette méthode ne modifie pas l’image originale, car le résultat de l’application du filtre à celle-ci est enregistré dans l’occurrence de BitmapData pour laquelle la méthode applyFilter() est appelée.

Fonctionnement des filtres

Le filtrage des objets d’affichage consiste à mettre en cache une copie de l’objet original sous forme d’un bitmap transparent.

Lorsqu’un filtre a été appliqué à un objet d’affichage, le moteur d’exécution conserve en cache l’objet sous forme de bitmap tant que cet objet possède une liste de filtres valide. Le bitmap source est ensuite repris en tant qu’image originale pour les effets de filtrage suivants.

Tout objet d’affichage comporte généralement deux bitmaps : le premier avec l’objet d’affichage source non filtré d’origine et un autre pour l’image finale après filtrage. L’image finale est utilisée pour le rendu. Tant que l’objet d’affichage ne change pas, l’image source ne nécessite aucune actualisation.

Problèmes potentiels d’utilisation des filtres

Plusieurs sources potentielles de confusion ou de problèmes peuvent survenir lors de l’utilisation de filtres.

Filtres et mise en cache bitmap

Pour appliquer un filtre à un objet d’affichage, vous devez activer la mise en cache sous forme de bitmap pour cet objet. Si vous appliquez un filtre à un objet d’affichage dont la propriété cacheAsBitmap est false , la propriété cacheAsBitmap de l’objet est automatiquement définie sur true . Si vous supprimez tous les filtres appliqués à l’objet d’affichage, la propriété cacheAsBitmap retrouve la valeur précédemment définie.

Modification des filtres à l’exécution

Si un ou plusieurs filtres sont déjà appliqués à un objet d’affichage, vous ne pouvez pas modifier le jeu de filtres en ajoutant d’autres filtres ou en supprimant des filtres existants du tableau de la propriété filters . Pour modifier le jeu de filtres appliqué ou lui ajouter des filtres, vous devez plutôt effectuer les modifications requises dans un tableau distinct, puis l’assigner à la propriété filters de l’objet d’affichage pour que les filtres soient appliqués à l’objet. La procédure la plus simple consiste à lire le tableau de la propriété filters dans une variable Array, puis à effectuer les modifications requises dans ce tableau temporaire. Vous réassignez alors ce tableau à la propriété filters de l’objet d’affichage. Dans les cas de figure plus complexes, il peut s’avérer nécessaire de conserver un tableau maître distinct de filtres. Vous effectuez toute modification requise dans ce tableau maître de filtres, puis vous le réassignez à la propriété filters de l’objet d’affichage après chaque modification.

Ajout d’un autre filtre

Le code suivant illustre le processus d’ajout d’un autre filtre à un objet d’affichage auquel sont déjà appliqués un ou plusieurs filtres. Initialement, un filtre Rayonnement est appliqué à l’objet d’affichage myDisplayObject . Lorsque l’utilisateur clique sur l’objet d’affichage, la fonction addFilters() est appelée. Dans cette fonction, deux filtres supplémentaires sont appliqués à 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);

Suppression d’un filtre dans un jeu de filtres

Si plusieurs filtres sont appliqués à un objet d’affichage et que vous souhaitez supprimer l’un des filtres sans affecter les autres filtres appliqués, vous copiez les filtres dans un tableau temporaire, vous supprimez le filtre superflu du tableau, puis vous réassignez le tableau temporaire à la propriété filters de l’objet d’affichage. La section Récupération des valeurs et suppression des éléments du tableau décrit plusieurs techniques de suppression d’un ou de plusieurs éléments de tout tableau.

La technique la plus simple consiste à supprimer le filtre en tête de pile appliqué à l’objet (en d’autres termes, le dernier filtre appliqué à ce dernier). Vous utilisez la méthode pop() de la classe Array pour supprimer le filtre du tableau :

// 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;

Pour supprimer le filtre en bas de pile (en d’autres termes, le premier filtre appliqué à l’objet), vous utilisez le même code en substituant la méthode shift() de la classe Array à la méthode pop() .

Pour supprimer un filtre figurant au centre d’un tableau de filtres (sous réserve que le tableau contienne plus de deux filtres), vous disposez de la méthode splice() . Vous devez connaître l’index (la position dans le tableau) du filtre à supprimer. Par exemple, le code suivant supprime le deuxième filtre (doté de l’index 1) d’un objet d’affichage :

// 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;

Identification de l’index d’un filtre

Vous devez connaître l’index du filtre à supprimer du tableau. A cet effet, il est nécessaire d’identifier (selon le mode de conception de l’application) ou de calculer l’index du filtre à supprimer.

L’approche recommandée consiste à concevoir votre application de sorte que le filtre à supprimer occupe systématiquement la même position dans le jeu de filtres. Par exemple, si vous disposez d’un objet d’affichage unique auquel sont appliqués un filtre Convolution et un filtre Ombre portée (dans cet ordre) et que vous souhaitez supprimer le filtre Ombre portée tout en conservant le filtre Convolution, vous connaissez la position occupée par le filtre (première). Vous savez donc à l’avance quelle méthode Array utiliser (soit, dans ce cas, Array.pop() pour supprimer le filtre Ombre portée).

Si le filtre à supprimer est toujours d’un type déterminé, mais qu’il n’occupe pas systématiquement la même position dans le jeu de filtres, vous pouvez vérifier le type de données de chaque filtre du tableau pour identifier le filtre à supprimer. Par exemple, le code suivant identifie le filtre Rayonnement dans un jeu de filtres et le supprime de ce dernier.

// 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;

Dans un cas de figure plus complexe (si le filtre à supprimer est sélectionné à l’exécution, par exemple), l’approche recommandée consiste à conserver une copie distincte et permanente du tableau de filtres, qui sert de liste maîtresse de filtres. Lorsque vous modifiez le jeu de filtres, modifiez la liste maîtresse, puis appliquez ce tableau de filtres en tant que propriété filters de l’objet d’affichage.

Par exemple, dans le code ci-après, plusieurs filtres Convolution sont appliqués à un objet d’affichage pour créer divers effets visuels et l’un de ces filtres est supprimé ultérieurement dans l’application sans affecter les autres filtres. Dans ce cas de figure, le code conserve une copie maîtresse du tableau de filtres, ainsi qu’une référence au filtre à supprimer. Rechercher et identifier le filtre approprié est similaire à l’approche précédente, excepté qu’au lieu d’effectuer une copie temporaire du tableau de filtres, la copie maîtresse est manipulée, puis appliquée à l’objet d’affichage.

// 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; 
}

Si vous adoptez cette approche (qui consiste à comparer une référence stockée à un filtre aux éléments que contient le tableau de filtres pour identifier le filtre à supprimer), vous devez conserver une copie distincte du tableau de filtres. En effet, le code ne fonctionne pas si vous comparez la référence stockée au filtre aux éléments d’un tableau temporaire copié dans la propriété filters de l’objet d’affichage. La raison en est simple : lorsque vous assignez un tableau à la propriété filters , le moteur d’exécution effectue une copie de chaque objet filtre du tableau. Ces copies (plutôt que les objets d’origine) sont appliquées à l’objet d’affichage. Lorsque vous lisez la propriété filters dans un tableau temporaire, celui-ci contient des références aux objets filtre copiés plutôt qu’aux objets filtre d’origine. Par conséquent, si vous tentez dans l’exemple précédent de déterminer l’index de filterToRemove en le comparant aux filtres d’un tableau de filtres temporaire, aucune correspondance n’est détectée.

Filtres et transformations d’objets

Les zones filtrées (ombres portées, par exemple) situées hors du cadre de sélection d’un objet d’affichage ne sont pas prises en considération pour la détection de clics (chevauchement ou intersection de deux occurrences). La méthode de détection des clics de la classe DisplayObject étant de type vectoriel, il est impossible d’en pratiquer une sur le bitmap résultant. Par exemple, si vous appliquez un filtre Biseau à une occurrence de bouton, la détection des clics n’est pas possible sur la partie biseautée de l’occurrence.

Le redimensionnement, la rotation et l’inclinaison ne sont pas pris en charge par les filtres ; si l’objet d’affichage filtré lui-même est redimensionné ( scaleX et scaleY différents de 100 %), l’effet de filtre n’est pas redimensionné avec l’occurrence. La forme originale de l’occurrence est certes pivotée, inclinée ou redimensionnée, mais pas le filtre.

Vous pouvez animer une occurrence avec un filtre afin de créer des effets réalistes, ou imbriquer des occurrences et utiliser la classe BitmapData pour animer des filtres afin d’obtenir ces effets.

Filtres et objets bitmaps

Si vous appliquez un filtre à un objet BitmapData, la propriété cacheAsBitmap de cet objet est automatiquement true . Le filtre peut ainsi être appliqué à la copie de l’objet plutôt qu’à ce dernier.

Cette copie est alors placée à l’écran par-dessus l’objet original, aussi près que possible, au pixel près. Si les limites du bitmap original changent, la copie à laquelle le filtrage est appliqué est recréée à partir de l’original au lieu d’être étirée.

Si vous supprimez tous les filtres de l’objet d’affichage, la propriété cacheAsBitmap retrouve sa valeur d’origine.