Exemple de filtrage des objets d’affichage : Filter Workbench

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

L’exemple Filter Workbench comporte une interface utilisateur qui permet d’appliquer divers filtres à des images et autre contenu visuel et de voir le code résultant, qui peut être utilisé pour générer le même effet en ActionScript. Non seulement cette application fournit un outil permettant d’expérimenter avec les filtres, mais elle illustre également les techniques suivantes :

  • Création d’occurrences de filtres divers

  • Application de plusieurs filtres à un objet d’affichage

Pour obtenir les fichiers d’application de cet exemple, voir www.adobe.com/go/learn_programmingAS3samples_flash_fr. Les fichiers d’application Filter Workbench résident dans le dossier Samples/FilterWorkbench. L’application se compose des fichiers suivants :

Fichier

Description

com/example/programmingas3/filterWorkbench/FilterWorkbenchController.as

Classe qui fournit la principale fonctionnalité de l’application, notamment permuter le contenu auquel sont appliqués les filtres et appliquer les filtres au contenu.

com/example/programmingas3/filterWorkbench/IFilterFactory.as

Interface qui définit les méthodes courantes et implémentées par chacune des classes usine de filtres. Cette interface définit la fonctionnalité commune utilisée par la classe FilterWorkbenchController pour interagir avec chaque classe usine de filtres.

Dans le dossier com/example/programmingas3/filterWorkbench/ :

BevelFactory.as

BlurFactory.as

ColorMatrixFactory.as

ConvolutionFactory.as

DropShadowFactory.as

GlowFactory.as

GradientBevelFactory.as

GradientGlowFactory.as

Jeu de classes, dont chacune implémente l’interface IFilterFactory. Chacune de ces classes permet de créer et de définir les valeurs associées à un type unique de filtre. Les panneaux de propriétés des filtres de l’application utilisent ces classes usine pour créer des occurrences des filtres correspondants, que la classe FilterWorkbenchController extrait et applique au contenu d’image.

com/example/programmingas3/filterWorkbench/IFilterPanel.as

Interface qui définit les méthodes courantes et implémentées par les classes qui spécifient les panneaux de l’interface utilisateur employés pour manipuler les valeurs de filtre dans l’application.

com/example/programmingas3/filterWorkbench/ColorStringFormatter.as

Classe d’utilitaires qui comporte une méthode de conversion d’une valeur de couleur numérique au format chaîne hexadécimal.

com/example/programmingas3/filterWorkbench/GradientColor.as

Classe servant d’objet de valeur, qui combine en un objet unique les trois valeurs (couleur, alpha et rapport) associées à chaque couleur dans GradientBevelFilter et GradientGlowFilter.

Interface utilisateur (Flex)

FilterWorkbench.mxml

Fichier principal qui définit l’interface utilisateur de l’application.

flexapp/FilterWorkbench.as

Classe qui assure la fonctionnalité de l’interface utilisateur de l’application principale. Elle sert de classe code-behind au fichier MXML de l’application.

Dans le dossier flexapp/filterPanels :

BevelPanel.mxml

BlurPanel.mxml

ColorMatrixPanel.mxml

ConvolutionPanel.mxml

DropShadowPanel.mxml

GlowPanel.mxml

GradientBevelPanel.mxml

GradientGlowPanel.mxml

Jeu de composants MXML qui assurent la fonctionnalité de chaque panneau utilisé pour définir les options d’un filtre unique.

flexapp/ImageContainer.as

Objet d’affichage qui sert de conteneur à l’image chargée à l’écran.

flexapp/controls/BGColorCellRenderer.as

Composant de rendu de cellule personnalisé permettant de modifier la couleur d’arrière-plan d’une cellule dans le composant DataGrid

flexapp/controls/QualityComboBox.as

Contrôle personnalisé qui définit une liste déroulante modifiable associée au paramètre Qualité dans plusieurs panneaux de filtre.

flexapp/controls/TypeComboBox.as

Contrôle personnalisé qui définit une liste déroulante modifiable associée au paramètre Type dans plusieurs panneaux de filtre.

Interface utilisateur (Flash)

FilterWorkbench.fla

Fichier principal qui définit l’interface utilisateur de l’application.

flashapp/FilterWorkbench.as

Classe qui assure la fonctionnalité de l’interface utilisateur de l’application principale. Elle sert de classe de document au fichier FLA de l’application.

Dans le dossier flashapp/filterPanels :

BevelPanel.as

BlurPanel.as

ColorMatrixPanel.as

ConvolutionPanel.as

DropShadowPanel.as

GlowPanel.as

GradientBevelPanel.as

GradientGlowPanel.as

Jeu de classes qui assurent la fonctionnalité de chaque panneau utilisé pour définir les options d’un filtre unique.

A chaque classe correspond également un symbole MovieClip dans la bibliothèque du fichier FLA de l’application principale, dont le nom est identique à celui de la classe (par exemple, le symbole « BlurPanel » est lié à la classe définie dans BlurPanel.as). Les composants de l’interface utilisateur sont placés et identifiés par nom dans ces symboles.

flashapp/ImageContainer.as

Objet d’affichage qui sert de conteneur à l’image chargée à l’écran.

flashapp/BGColorCellRenderer.as

Composant de rendu de cellule personnalisé permettant de modifier la couleur d’arrière-plan d’une cellule dans le composant DataGrid

flashapp/ButtonCellRenderer.as

Composant de rendu de cellule personnalisé permettant d’insérer un composant Button dans une cellule du composant DataGrid

Contenu d’image filtré

com/example/programmingas3/filterWorkbench/ImageType.as

Cette classe sert d’objet de valeur contenant le type et l’URL d’un fichier d’image unique, dans lequel l’application peut charger et appliquer des filtres. Cette classe comporte également un jeu de constantes qui représentent les fichiers d’image en tant que tels disponibles.

images/sampleAnimation.swf,

images/sampleImage1.jpg,

images/sampleImage2.jpg

Images et autre contenu visuel auxquels sont appliqués des filtres dans l’application.

Utilisation des filtres ActionScript

L’application Filter Workbench est conçue pour vous aider à expérimenter avec divers effets de filtre et générer le code ActionScript approprié correspondant. Elle vous permet de sélectionner trois fichiers distincts comportant un contenu visuel, tel que des images bitmap et une animation créée par Flash et d’appliquer huit filtres ActionScript distincts à l’image sélectionnée, soit seuls, soit combinés à d’autres filtres. L’application comprend les filtres suivants :

  • Biseau (flash.filters.BevelFilter)

  • Flou (flash.filters.BlurFilter)

  • Matrice de couleurs (flash.filters.ColorMatrixFilter)

  • Convolution (flash.filters.ConvolutionFilter)

  • Ombre portée (flash.filters.DropShadowFilter)

  • Rayonnement (flash.filters.GlowFilter)

  • Biseau dégradé (flash.filters.GradientBevelFilter)

  • Rayonnement dégradé (flash.filters.GradientGlowFilter)

Lorsqu’un utilisateur a sélectionné une image et un filtre à appliquer à celle-ci, l’application affiche un panneau contenant des contrôles de définition des propriétés du filtre sélectionné. Par exemple, l’image suivante illustre l’application dans laquelle est sélectionné le filtre Biseau :

Lorsque l’utilisateur règle les propriétés du filtre, l’aperçu est actualisé en temps réel. L’utilisateur peut également appliquer plusieurs filtres. Pour ce faire, il personnalise un filtre, clique sur le bouton Apply, personnalise un autre filtre, clique sur le bouton Apply, et ainsi de suite.

Les panneaux de filtre de l’application proposent diverses fonctions et sont soumis à quelques limites :

  • Le filtre Matrice de couleurs comprend un jeu de contrôles permettant de manipuler directement des propriétés d’image courantes telles que la luminosité, les contrastes, la saturation et la teinte. Il est également possible de définir des valeurs de matrice de couleurs personnalisées.

  • Le filtre Convolution, qui n’est disponible qu’en ActionScript, comprend un jeu de valeurs de matrice de convolution couramment utilisées. Il est également possible de définir des valeurs personnalisées. Toutefois, bien que la classe ConvolutionFilter gère une matrice de n’importe quelle taille, l’application Filter Workbench utilise une matrice de 3 x 3 fixe, soit la taille de filtre la plus fréquemment utilisée.

  • Le filtre Mappage de déplacement et le filtre Shader, réservés à ActionScript, ne sont pas disponibles dans l’application Filter Workbench.

Création d’occurrences de filtre

L’application Filter Workbench comprend un jeu de classes, une par filtre disponible, qui sont utilisées par les divers panneaux pour créer les filtres. Lorsqu’un utilisateur sélectionne un filtre, le code ActionScript associé au panneau de filtre crée une occurrence de la classe de filtres usine appropriée. (Ces classes portent le nom de classes usine, car elles ont pour objet de créer des occurrences d’autres objets, à l’instar d’une vraie usine qui fabrique des produits).

Lorsque l’utilisateur modifie la valeur d’une propriété dans le panneau, le code correspondant appelle la méthode appropriée dans la classe usine. Chaque classe usine comporte des méthodes spécifiques utilisées par le panneau pour créer l’occurrence de filtre appropriée. Par exemple, si l’utilisateur sélectionne le filtre Flou, l’application crée une occurrence de BlurFactory. La classe BlurFactory comporte une méthode modifyFilter() qui gère trois paramètres : blurX, blurY et quality. Conjointement, ces paramètres permettent de créer l’occurrence de BlurFilter requise :

private var _filter:BlurFilter; 
 
public function modifyFilter(blurX:Number = 4, blurY:Number = 4, quality:int = 1):void 
{ 
    _filter = new BlurFilter(blurX, blurY, quality); 
    dispatchEvent(new Event(Event.CHANGE)); 
}

En revanche, si l’utilisateur sélectionne le filtre Convolution, celui-ci étant beaucoup plus souple, il contrôle un nombre supérieur de propriétés. Dans la classe ConvolutionFactory, le code suivant est appelé lorsque l’utilisateur sélectionne une autre valeur dans le panneau des filtres :

private var _filter:ConvolutionFilter; 
 
public function modifyFilter(matrixX:Number = 0,  
                                                matrixY:Number = 0,  
                                                matrix:Array = null,  
                                                divisor:Number = 1.0,  
                                                bias:Number = 0.0,  
                                                preserveAlpha:Boolean = true,  
                                                clamp:Boolean = true,  
                                                color:uint = 0,  
                                                alpha:Number = 0.0):void 
{ 
    _filter = new ConvolutionFilter(matrixX, matrixY, matrix, divisor, bias, preserveAlpha, clamp, color, alpha); 
    dispatchEvent(new Event(Event.CHANGE)); 
}

Notez que dans chaque cas, lorsque les valeurs du filtre sont modifiées, l’objet usine distribue un événement Event.CHANGE pour avertir les écouteurs de la modification. La classe FilterWorkbenchController, qui applique les filtres au contenu filtré, recherche cet événement pour s’assurer qu’elle doit extraire une nouvelle copie du filtre et l’appliquer à nouveau au contenu filtré.

La classe FilterWorkbenchController n’a pas besoin de connaître les détails précis de chaque classe usine associé au filtre. Elle doit juste savoir que le filtre a été modifié et être en mesure d’accéder à une copie de ce dernier. A cet effet, l’application comporte une interface, IFilterFactory, qui définit le comportement requis d’une classe usine de filtres pour que l’occurrence de FilterWorkbenchController de l’application soit en mesure de fonctionner correctement. L’interface IFilterFactory définit la méthode getFilter() utilisée par la classe FilterWorkbenchController :

function getFilter():BitmapFilter;

Notez que la définition de la méthode de l’interface getFilter() stipule de renvoyer une occurrence de BitmapFilter plutôt qu’un type déterminé de filtre. La classe BitmapFilter ne définit pas de type spécifique de filtre. BitmapFilter constitue de fait la classe de base sur laquelle se fondent toutes les classes de filtre. Chaque classe usine de filtres définit une implémentation déterminée de la méthode getFilter(), dans laquelle elle renvoie une référence à l’objet filtre généré. Par exemple, une version abrégée du code source de la classe ConvolutionFactory est illustrée ci-après :

public class ConvolutionFactory extends EventDispatcher implements IFilterFactory 
{ 
    // ------- Private vars ------- 
    private var _filter:ConvolutionFilter; 
    ... 
    // ------- IFilterFactory implementation ------- 
    public function getFilter():BitmapFilter 
    { 
        return _filter; 
    } 
    ... 
}

Dans l’implémentation de la classe ConvolutionFactory de la méthode getFilter(), elle renvoie une occurrence de ConvolutionFilter, bien que tout objet qui appelle getFilter() ne sache pas nécessairement que, conformément à la définition de la méthode getFilter() appliquée par ConvolutionFactory, il doit renvoyer toute occurrence de BitmapFilter, soit une occurrence de n’importe quelle classe de filtre ActionScript.

Application de filtres aux objets d’affichage

Comme indiqué précédemment, l’application Filter Workbench utilise une occurrence de la classe FilterWorkbenchController (appelée à partir de maintenant l’« occurrence de contrôleur »), chargée d’appliquer les filtres à l’objet visuel sélectionné. Avant que l’occurrence de contrôleur ne puisse appliquer un filtre, elle doit identifier l’image ou le contenu visuel concerné. Lorsque l’utilisateur sélectionne une image, l’application appelle la méthode setFilterTarget() de la classe FilterWorkbenchController et transmet l’une des constantes définies dans la classe ImageType :

public function setFilterTarget(targetType:ImageType):void 
{ 
    ... 
    _loader = new Loader(); 
    ... 
    _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, targetLoadComplete); 
    ... 
}

En se référant à ces informations, l’occurrence de contrôleur charge le fichier indiqué, puis le stocke dans une variable d’occurrence appelée _currentTarget :

private var _currentTarget:DisplayObject; 
 
private function targetLoadComplete(event:Event):void 
{ 
    ... 
    _currentTarget = _loader.content; 
    ... 
}

Lorsque l’utilisateur sélectionne un filtre, l’application appelle la méthode setFilter() de l’occurrence de contrôleur en indiquant au contrôleur une référence à l’objet Filter Factory approprié, qu’elle stocke dans une variable d’occurrence appelée _filterFactory.

private var _filterFactory:IFilterFactory; 
 
public function setFilter(factory:IFilterFactory):void 
{ 
    ... 
     
    _filterFactory = factory; 
    _filterFactory.addEventListener(Event.CHANGE, filterChange); 
}

Notez que, comme indiqué précédemment, l’occurrence de contrôleur ne connaît pas le type de données précis de l’occurrence de Filter Factory assigné. Elle ne sait qu’une chose, c’est que l’objet implémente l’occurrence de IFilterFactory, ce qui signifie qu’il possède une méthode getFilter() et distribue un événement change (Event.CHANGE) lorsque le filtre est modifié.

Lorsque l’utilisateur modifie les propriétés d’un filtre dans le panneau des filtres, l’occurrence de contrôleur est avertie de la modification par l’événement change de Filter Factory, qui appelle la méthode filterChange() de l’occurrence de contrôleur. Cette méthode appelle alors la méthode applyTemporaryFilter() :

private function filterChange(event:Event):void 
{ 
    applyTemporaryFilter(); 
} 
 
private function applyTemporaryFilter():void 
{ 
    var currentFilter:BitmapFilter = _filterFactory.getFilter(); 
     
    // Add the current filter to the set temporarily 
    _currentFilters.push(currentFilter); 
     
    // Refresh the filter set of the filter target 
    _currentTarget.filters = _currentFilters; 
     
    // Remove the current filter from the set 
    // (This doesn't remove it from the filter target, since  
    // the target uses a copy of the filters array internally.) 
    _currentFilters.pop(); 
}

L’application du filtre à l’objet d’affichage se produit au sein de la méthode applyTemporaryFilter(). Le contrôleur extrait d’abord une référence à l’objet filtre en appelant la méthode getFilter() de Filter Factory.

var currentFilter:BitmapFilter = _filterFactory.getFilter();

L’occurrence de contrôleur possède une variable d’occurrence de Array appelée _currentFilters, dans laquelle elle stocke tous les filtres appliqués à l’objet d’affichage. L’étape suivante consiste à ajouter le filtre mis à jour à ce tableau :

_currentFilters.push(currentFilter);

Le code assigne ensuite le tableau de filtres à la propriété filters de l’objet d’affichage, qui applique à proprement parler les filtres à l’image :

_currentTarget.filters = _currentFilters;

Enfin, puisque le filtre appliqué en dernier demeure le filtre de « travail », il ne doit pas être appliqué à titre définitif à l’objet d’affichage. Il est donc supprimé du tableau _currentFilters :

_currentFilters.pop();

Supprimer ce filtre du tableau n’affecte pas l’objet d’affichage filtré, car un objet d’affichage effectue une copie du tableau de filtres lorsqu’il est assigné à la propriété filters et utilise ce tableau interne au lieu du tableau initial. De ce fait, toute modification du tableau de filtres n’affecte pas l’objet d’affichage tant que le tableau n’a pas été à nouveau assigné à la propriété filters de l’objet d’affichage.