Dans ce didacticiel, nous allons créer un programme de filtrage qui permettra à l’utilisateur d’appliquer différents filtres à une image, de modifier les niveaux d’intensité et de comparer les images originales et filtrées. Nous allons également utiliser des composants pour nos contrôles.
Il y aura trois couches: une pour le code ActionScript, une autre pour le texte et les composants et la dernière pour l'image. Le programme compilé contiendra deux images puisqu'un sera créé au moment de l'exécution. Des filtres seront appliqués à la version d'exécution. De plus, un masque sera créé au moment de l’exécution et sera utilisé pour afficher / masquer des parties de l’image filtrée..
Je suppose que vous avez déjà une compréhension de base de Flash et d'ActionScript 3.0. Cependant, je vais toujours essayer de garder chaque étape aussi claire que possible.
Remarque: Tout au long de ce didacticiel, j'utiliserai des références faibles lors de l'ajout d'écouteurs d'événement. Pour plus d'informations sur les références faibles, consultez cet article de blog..
Créez un nouveau document ActionScript 3.0. Définissez la taille de la scène sur 600 x 500 pixels. J'ai choisi cette taille car l'image que je vais utiliser s'intégrera facilement dans ces dimensions..
Créez les trois couches mentionnées précédemment (à savoir "actions", "texte et composants" et "image (originale)"). Verrouillez le calque "actions" car vous n'ajouterez rien à ce calque en dehors d'ActionScript..
Sélectionnez le calque "texte et composants" et ajoutez le texte statique "Filtre" et "Intensité" dans le coin supérieur gauche..
Accédez au panneau Composants et faites glisser cinq boutons et deux curseurs sur la scène. Vous pouvez essentiellement les disposer comme vous le souhaitez.
Indiquez aux boutons les valeurs "Défaut", "Flou", "Relief", "Luminosité" et "Négatif". Puis donnez-leur les noms d'occurrence "default_btn", "blur_btn", "emboss_btn", "luminosité_btn" et "negative_btn"..
Donnez au curseur d’intensité un nom d’occurrence "intensité_sld", puis nommez le curseur de masque "masque_sld"..
Remarque: il n'est pas très important de placer le curseur de masque, car nous utiliserons ActionScript pour le repositionner ultérieurement..
Terminologie: Tout au long de ce didacticiel, je peux me référer indifféremment à "masque de curseur" ou à "masque_sld". Il en va de même pour "curseur d'intensité" et "intensité_sld".
Vous pouvez maintenant verrouiller le calque "texte et composants". Ensuite, sélectionnez le calque "image (original)" et importez l'image que vous souhaitez utiliser. Je vais utiliser une photo d'un pissenlit.
Sélectionnez l'image et convertissez-la en un symbole de clip. Je l'ai nommé "pissenlit", mais cela peut être ce que vous voulez. Assurez-vous que le point d’inscription est dans le coin supérieur gauche. Allez dans la vue "Avancé" et cochez l'option "Exporter pour ActionScript". Le "Exporter dans l'image 1" doit être automatiquement coché. Pour la classe, entrez "PhotoDandelion" et laissez la classe de base sous "flash.display.MovieClip"..
Donnez à la nouvelle image Movie Clip le nom d’instance "photoOriginal". Vous pouvez maintenant verrouiller le calque "image (original)".
Flash vous permet d'appliquer des filtres similaires à ceux de Photoshop. Vous pouvez appliquer des filtres à partir du panneau Propriétés ou via ActionScript. Voici quelques-uns des filtres de base fournis par Flash: biseau, flou, ombre portée, lueur, etc..
En utilisant ActionScript, nous pouvons appliquer un filtre à tout objet DisplayObject via sa propriété "filters". La valeur assignée à la propriété "filters" doit être un tableau. Vous pouvez également appliquer plus d'un filtre.
// Application d'un filtre de flou à un objet DisplayObject. var bFilter: BlurFilter = new BlurFilter (); var arrFilters: Array = [bFilter]; displayObj.filters = arrFilters;
Flash prend également en charge les filtres de convolution pouvant effectuer des effets plus avancés tels que la luminosité, la détection des contours, le gaufrage, etc..
Les filtres de convolution ne peuvent être appliqués que via ActionScript et nécessitent également l'utilisation de matrices décrivant la manière dont les couleurs de chaque pixel doivent être affectées. La matrice doit être dans un tableau.
// Valeur par défaut de var matrixDefault: Array = [0, 0, 0, 0, 1, 0, 0, 0, 0]; // Plus lumineux var matrixBrighter: Tableau = [0, 0, 0, 0, 2, 0, 0, 0, 0]; // plus sombre var matrixDarker: Array = [0, 0, 0, 0, 0.5, 0, 0, 0, 0]; // Emboss var matriceEmboss: Tableau = [-1, -1, 0, -1, 1, 1, 0, 1, 1];
La valeur centrale est le pixel actuel et les valeurs environnantes sont ses pixels voisins. La valeur par défaut est 1; Si vous augmentez cette valeur, l'image sera plus lumineuse. En le diminuant, il sera plus sombre. Avoir des valeurs négatives en haut à gauche et des valeurs positives en bas à droite (ou inversement) crée un effet de relief.
En utilisant ActionScript, nous pouvons appliquer un filtre de convolution comme suit:
// La matrice suivante éclaircira l'image. var matrixBrighter: tableau = [0, 0, 0, 0, 2, 0, 0, 0, 0]; var matrixCol: Nombre = 3; // Numéro de colonne var matrixRow: Number = 3; // Nombre de lignes var cvFilter: ConvolutionFilter = new ConvolutionFilter (matrixCol, matrixRow, matrixBrighter); var arrFilters: Array = [cvFilter]; displayObj.filters = arrFilters;
Pour plus d'informations sur le filtre de convolution, consultez cet article Adobe Flash..
Nous allons maintenant écrire le code ActionScript. Sélectionnez la première image du calque "actions" et allez dans le panneau Actions..
Normalement, j'aime garder le texte cohérent dans tout le programme. Alors, voici le code pour définir le texte (Verdana) pour tous les composants globalement.
importer fl.managers.StyleManager; format var: TextFormat = new TextFormat ("Verdana", 10, 0x000000); StyleManager.setStyle ("textFormat", format);
Créons maintenant une copie de la photo (pour appliquer des filtres) et positionnez-la au même emplacement que la photo d'origine. Je vais utiliser la version B, car je veux appliquer un masque après le filtre. Avec la version A, si vous appliquez un filtre de flou, vous remarquerez peut-être que le flou dépasse le masque. En effet, le filtre applique son effet après le masque..
Plus tard, nous masquerons "photoWrapper" et n'appliquerons les filtres que sur "photo affecté".
/ * // Version A var photoEffected: PhotoDandelion = new PhotoDandelion (); photoEffected.x = photoOriginal.x; photoEffected.y = photoOriginal.y; addChild (photoEffected); * / // Version B var photoWrapper: Sprite = new Sprite (); photoWrapper.x = photoOriginal.x; photoWrapper.y = photoOriginal.y; var photoEffected: PhotoDandelion = new PhotoDandelion (); photoWrapper.addChild (photoEffected); addChild (photoWrapper);
Créez ensuite la ligne qui séparera la photo filtrée de la photo originale. Nous allons utiliser une forme pour tracer une ligne. Positionnez la ligne en bas au centre de la photo, puis tracez la ligne de bas en haut..
var ComparisonLine: Shape = new Shape (); compareLine.x = photoOriginal.x + photoOriginal.width / 2; compareLine.y = photoOriginal.y + photoOriginal.height; comparaisonLine.graphics.lineStyle (2, 0x999999, 1, vrai); benchmarkLine.graphics.moveTo (0, 0); comparaisonLine.graphics.lineTo (0, -photoOriginal.height); addChild (compareLine);
Vous vous souviendrez que nous avons un curseur de masque. À l'aide d'ActionScript, nous pouvons le positionner sous la photo et l'étirer de sorte que sa largeur soit identique à celle de la photo. Le réglage des valeurs "maximum" et "width" sur la largeur de la photo aide à créer un rapport 1: 1. Nous n'aurons donc pas besoin de créer une conversion d'échelle plus tard. De plus, nous allons centrer la flèche dans le curseur.
mask_sld.x = photoOriginal.x; mask_sld.y = photoOriginal.y + photoOriginal.height; mask_sld.minimum = 0; mask_sld.maximum = photoOriginal.width; mask_sld.value = photoOriginal.width / 2; mask_sld.width = photoOriginal.width;
Créons maintenant la fonction et assignons l’événement pour le curseur de masque. Nous voulons que la "ligne de comparaison" suive le curseur du masque. La largeur de "photoMask" doit changer en fonction du curseur de masque lorsque celui-ci est déplacé. Je sais que nous n'avons pas encore abordé "photoMask", mais c'est la prochaine étape.
import fl.events.SliderEvent; function maskSliderDrag (evt: SliderEvent): void compareLine.x = evt.target.value + evt.target.x; photoMask.width = evt.target.value; mask_sld.addEventListener (SliderEvent.THUMB_DRAG, maskSliderDrag, false, 0, true);
Comme mentionné précédemment, "photoMask" sera utilisé pour masquer le "photoWrapper" par opposition à "photoEffected". Puisqu'il s'agira d'un masque rectangulaire, nous utiliserons une forme. Définissez la position et la dimension du rectangle de la même manière que "photoOriginal". Assurez-vous de remplir la forme avec une couleur (cela peut être n'importe quelle couleur), sinon le masque risque de ne pas fonctionner comme prévu. Définissez ensuite "photoMask" en tant que masque de photoWrapper et la largeur du masque avec la "valeur" du curseur de masque..
var photoMask: Shape = new Shape (); photoMask.x = photoOriginal.x; photoMask.y = photoOriginal.y; photoMask.graphics.beginFill (0xff9900); photoMask.graphics.drawRect (0, 0, photoOriginal.width, photoOriginal.height); photoMask.graphics.endFill (); addChild (photoMask); photoWrapper.mask = photoMask; photoMask.width = mask_sld.value;
Nous avons besoin d'un moyen de stocker le dernier bouton enfoncé, que nous allons stocker dans "activeFilter". Ceci sera utilisé plus tard par le curseur d'intensité.
var activeFilter: Button;
Ensuite, nous allons passer au curseur d’intensité. Nous définissons la fonction "intensitéChange" qui sera appelée chaque fois que le curseur d'intensité est déplacé. La fonction distribuera un événement (par exemple, un clic de souris) en fonction du dernier bouton enfoncé. Nous allons également attribuer l'événement et désactiver initialement le curseur.
function intensitéChange (evt: SliderEvent): void activeFilter.dispatchEvent (new MouseEvent (MouseEvent.CLICK)); intensité_sld.addEventListener (SliderEvent.THUMB_DRAG, intensitéChange, false, 0, true); intensité_sld.enabled = false;
Définissons maintenant les fonctions de filtrage. Les fonctions de filtre "par défaut" et "négatif" sont similaires en ce sens qu'elles désactivent le curseur d'intensité et qu'il n'est donc pas nécessaire de mettre à jour les propriétés du curseur. Pour le "flou", le "relief" et la "luminosité", ils doivent tous réactiver le curseur d'intensité. De plus, ils utilisent la propriété "value" pour déterminer l'intensité du filtre. De plus, chaque filtre a sa propre valeur "maximale" unique. Nous devons donc recalculer le "snapInterval". La propriété "valeur" est également recalculée car j'aimerais que le curseur se réinitialise à mi-chemin entre min et max. Il suffit de définir les propriétés du curseur d’intensité lorsque le "filtre actif" n’est pas égal à la cible actuelle..
function default_btnHandler (evt: MouseEvent): void var matrixDefault: Array = [0, 0, 0, 0, 1, 0, 0, 0, 0]; var conv: ConvolutionFilter = new ConvolutionFilter (3, 3, matrixDefault); photoEffected.filters = [conv]; activeFilter = evt.target as Button; intensité_sld.enabled = false; function blur_btnHandler (evt: MouseEvent): void if (activeFilter! = evt.target) intensité_sld.maximum = 30; intensité_sld.snapInterval = (intensité_sld.maximum - intensité_sld.minimum) / 40; intensité_sld.value = intensité_sld.maximum / 2; var blurX: Number = intensité_sld.value; var blurY: Number = intensité_sld.value; photoEffected.filters = [new BlurFilter (blurX, blurY, BitmapFilterQuality.HIGH)]; activeFilter = evt.target as Button; intensité_sld.enabled = true; function emboss_btnHandler (evt: MouseEvent): void if (activeFilter! = evt.target) intensité_sld.maximum = 4; intensité_sld.snapInterval = (intensité_sld.maximum - intensité_sld.minimum) / 40; intensité_sld.value = intensité_sld.maximum / 2; var matrixEmboss: Array = [-intensity_sld.value, -intensity_sld.value, 0, -intensity_sld.value, 1, intensité_sld.value, 0, intensité_sld.value, intensité_sld.value]; var conv: ConvolutionFilter = new ConvolutionFilter (3, 3, matrixEmboss); photoEffected.filters = [conv]; activeFilter = evt.target as Button; intensité_sld.enabled = true; function luminosité_btnHandler (evt: MouseEvent): void if (activeFilter! = evt.target) intensité_sld.maximum = 6; intensité_sld.snapInterval = (intensité_sld.maximum - intensité_sld.minimum) / 40; intensité_sld.value = intensité_sld.maximum / 2; var matrixBrightness: Array = [0, 0, 0, 0, intensité_sld.value, 0, 0, 0, 0]; var conv: ConvolutionFilter = new ConvolutionFilter (3, 3, matrixBrightness); photoEffected.filters = [conv]; activeFilter = evt.target as Button; intensité_sld.enabled = true; function negative_btnHandler (evt: MouseEvent): void var matrixNegative: ColorMatrixFilter = new ColorMatrixFilter ([- 1, 0, 0, 0, 255, 0, -1, 0, 255, 0, 0, -1, 0 , 255, 0, 0, 0, 1, 0]); photoEffected.filters = [matrixNegative]; activeFilter = evt.target as Button; intensité_sld.enabled = false;
Remarque: Pour le filtre "négatif", j'ai utilisé un filtre ColorMatrixFilter qui utilise une matrice de 4 sur 5 pour appliquer des transformations de couleur. Pour plus d'informations sur ColorMatrixFilter, consultez cet article Adobe Flash..
Attribuons maintenant chacun des boutons aux fonctions correspondantes.
default_btn.addEventListener (MouseEvent.CLICK, default_btnHandler, false, 0, true); blur_btn.addEventListener (MouseEvent.CLICK, blur_btnHandler, false, 0, true); emboss_btn.addEventListener (MouseEvent.CLICK, emboss_btnHandler, false, 0, true); luminosité_btn.addEventListener (MouseEvent.CLICK, luminosité_btnHandler, false, 0, true); negative_btn.addEventListener (MouseEvent.CLICK, negative_btnHandler, false, 0, true);
J'ai créé trois fonctions supplémentaires, à savoir "applyConvolutionFilter", "activeFilterAndIntensityOnOff" et "setSliderProperties". Leur but est de réduire le codage répétitif dans les fonctions de filtrage.
Votre code complet final devrait ressembler à ceci…
import fl.events.SliderEvent; importer fl.managers.StyleManager; format var: TextFormat = new TextFormat ("Verdana", 10, 0x000000); StyleManager.setStyle ("textFormat", format); var photoWrapper: Sprite = new Sprite (); photoWrapper.x = photoOriginal.x; photoWrapper.y = photoOriginal.y; var photoEffected: PhotoDandelion = new PhotoDandelion (); photoWrapper.addChild (photoEffected); addChild (photoWrapper); var ComparisonLine: Shape = new Shape (); compareLine.x = photoOriginal.x + photoOriginal.width / 2; compareLine.y = photoOriginal.y + photoOriginal.height; comparaisonLine.graphics.lineStyle (2, 0x999999, 1, vrai); benchmarkLine.graphics.moveTo (0, 0); comparaisonLine.graphics.lineTo (0, -photoOriginal.height); addChild (compareLine); mask_sld.x = photoOriginal.x; mask_sld.y = photoOriginal.y + photoOriginal.height; mask_sld.minimum = 0; mask_sld.maximum = photoOriginal.width; mask_sld.value = photoOriginal.width / 2; mask_sld.width = photoOriginal.width; function maskSliderDrag (evt: SliderEvent): void compareLine.x = evt.target.value + evt.target.x; photoMask.width = evt.target.value; mask_sld.addEventListener (SliderEvent.THUMB_DRAG, maskSliderDrag); var photoMask: Shape = new Shape (); photoMask.x = photoOriginal.x; photoMask.y = photoOriginal.y; photoMask.graphics.beginFill (0xff9900); photoMask.graphics.drawRect (0, 0, photoOriginal.width, photoOriginal.height); photoMask.graphics.endFill (); addChild (photoMask); photoWrapper.mask = photoMask; photoMask.width = mask_sld.value; var activeFilter: Button; function intensitéChange (evt: SliderEvent): void activeFilter.dispatchEvent (new MouseEvent (MouseEvent.CLICK)); intensité_sld.addEventListener (SliderEvent.THUMB_DRAG, intensitéChange); intensité_sld.enabled = false; function applyConvolutionFilter (matrix: Array): void var cFilter: ConvolutionFilter = new ConvolutionFilter (3, 3, matrice); photoEffected.filters = [cFilter]; function activeFilterAndIntensityOnOff (btn: Bouton, intensitéOnOff: Booléen): void activeFilter = btn; intensité_sld.enabled = intensitéOnOff; function setSliderProperties (btn: bouton, max: nombre): void if (activeFilter! = btn) intensité_sld.maximum = max; intensité_sld.snapInterval = (intensité_sld.maximum - intensité_sld.minimum) / 40; intensité_sld.value = intensité_sld.maximum / 2; function default_btnHandler (evt: MouseEvent): void var matrixDefault: Array = [0, 0, 0, 0, 1, 0, 0, 0, 0]; applyConvolutionFilter (matrixDefault); activeFilterAndIntensityOnOff (evt.target as Button, false); function blur_btnHandler (evt: MouseEvent): void var btn: Button = evt.target as Button; setSliderProperties (btn, 30); var blurX: Number = intensité_sld.value; var blurY: Number = intensité_sld.value; photoEffected.filters = [new BlurFilter (blurX, blurY, BitmapFilterQuality.HIGH)]; activeFilterAndIntensityOnOff (btn, true); function emboss_btnHandler (evt: MouseEvent): void var btn: Button = evt.target as Button; setSliderProperties (btn, 4); var matrixEmboss: Array = [-intensity_sld.value, -intensity_sld.value, 0, -intensity_sld.value, 1, intensité_sld.value, 0, intensité_sld.value, intensité_sld.value]; applyConvolutionFilter (matrixEmboss); activeFilterAndIntensityOnOff (btn, true); function luminosité_btnHandler (evt: MouseEvent): void var btn: Button = evt.target as Button; setSliderProperties (btn, 6); var matrixBrightness: Tableau = [0, 0, 0, 0, intensité_sld.valeur, 0, 0, 0, 0]; applyConvolutionFilter (matrixBrightness); activeFilterAndIntensityOnOff (btn, true); function negative_btnHandler (evt: MouseEvent): void var matrixNegative: ColorMatrixFilter = new ColorMatrixFilter ([- 1, 0, 0, 0, 255, 0, -1, 0, 255, 0, 0, -1, 0 , 255, 0, 0, 0, 1, 0]); photoEffected.filters = [matrixNegative]; activeFilterAndIntensityOnOff (evt.target as Button, false); default_btn.addEventListener (MouseEvent.CLICK, default_btnHandler, false, 0, true); blur_btn.addEventListener (MouseEvent.CLICK, blur_btnHandler, false, 0, true); emboss_btn.addEventListener (MouseEvent.CLICK, emboss_btnHandler, false, 0, true); luminosité_btn.addEventListener (MouseEvent.CLICK, luminosité_btnHandler, false, 0, true); negative_btn.addEventListener (MouseEvent.CLICK, negative_btnHandler, false, 0, true);
Remarque: vous pouvez même aller au-delà de ce que j'ai fait, par exemple en mettant en place une fonction centrale englobant tous les filtres. Puis utilisez "if else if" ou "switch" pour exécuter le code nécessaire au filtre correspondant..
Il y a beaucoup de choses que vous pouvez faire avec les filtres, je vous ai simplement donné une brève introduction. Les filtres de base dans Flash sont assez bons dans la mesure où il y a suffisamment de paramètres pour jouer. Si vous ne trouvez pas ce que vous cherchez, essayez d'autres filtres tels que ColorMatrixFilter, ConvolutionFilter, DisplacementMapFilter, etc. Vous pourriez être surpris de ce que vous trouvez. Continuez à expérimenter et surtout, amusez-vous!
Merci d'avoir pris le temps de visionner ce tutoriel. J'espère que tu as trouvé ça utile.