Статьи

Сравнение фильтров во Flash

В этом уроке мы создадим программу фильтрации, которая позволит пользователю применять различные фильтры к изображению, изменять уровни интенсивности и сравнивать исходные и отфильтрованные изображения. Мы также будем использовать компоненты для наших элементов управления.




Там будет три слоя: один для ActionScript, другой для текста и компонентов и последний для изображения. Скомпилированная программа будет содержать два изображения, так как одно будет создано во время выполнения. Во время выполнения к нему будут применены фильтры. Кроме того, во время выполнения будет создана маска, которая будет использоваться для отображения / скрытия частей отфильтрованного изображения.

Я предполагаю, что у вас уже есть базовое понимание Flash и ActionScript 3.0. Тем не менее, я все равно постараюсь сделать каждый шаг максимально четким.

Примечание. В этом уроке я буду использовать слабые ссылки при добавлении прослушивателей событий. Для получения дополнительной информации о слабых ссылках, обратитесь к этому сообщению в блоге .

Создайте новый документ ActionScript 3.0. Установите размер сцены на 600 х 500 пикселей. Я выбрал этот размер, поскольку изображение, которое я буду использовать, будет удобно вписываться в эти размеры.

Создайте три ранее упомянутых слоя (а именно: «действия», «текст и компоненты» и «изображение (оригинал)»). Заблокируйте слой «Actions», так как вы ничего не добавите к этому слою, кроме ActionScript.

Выберите слой «текст и компоненты» и добавьте статический текст «Фильтр» и «Интенсивность» в верхний левый угол.

Перейдите на панель «Компоненты» и перетащите пять кнопок и два ползунка на сцену. Вы можете в основном выложить их так, как вам нравится.

Присвойте кнопкам значения меток «По умолчанию», «Размытие», «Тиснение», «Яркость» и «Негатив». Затем дайте им имена экземпляров «default_btn», «blur_btn», «emboss_btn», «Bright_btn» и «absolute_btn».

Дайте ползунку интенсивности имя экземпляра «интенсивность_sld», затем назовите ползунок маски «mask_sld».

Примечание: не слишком важно, где вы размещаете ползунок маски, так как мы будем использовать ActionScript, чтобы переместить его позже.

Терминология: В этом руководстве я могу сослаться на «ползунок маски» или «mask_sld». То же самое относится к «ползунку интенсивности» и «интенсивность_sld».

Теперь вы можете заблокировать слой «текст и компоненты». Затем выберите слой «image (original)» и импортируйте изображение, которое вы хотите использовать. Я собираюсь использовать фотографию одуванчика.

Выберите изображение и преобразуйте его в символ мувиклипа. Я назвал это «одуванчик», но это может быть что угодно. Убедитесь, что точка регистрации находится в верхнем левом углу. Перейдите в представление «Advanced» и установите флажок «Export for ActionScript». «Экспорт в кадре 1» должен автоматически проверяться. Для класса введите «PhotoDandelion» и оставьте базовый класс как «flash.display.MovieClip».

Присвойте новому изображению Movie Clip имя экземпляра «photoOriginal». Теперь вы можете заблокировать слой «image (original)».

Flash позволяет применять фильтры, аналогичные тем, которые есть в Photoshop. Вы можете применять фильтры на панели «Свойства» или с помощью ActionScript. Вот некоторые из основных фильтров, которые предоставляет Flash: скос, размытие, тень, свечение и т. Д.

Используя ActionScript, мы можем применить фильтр к любому DisplayObject через его свойство «filters». Значение, присвоенное свойству «filters», должно быть массивом. Вы также можете применить более одного фильтра.

1
2
3
4
// Applying a blur filter to a DisplayObject.
var bFilter:BlurFilter = new BlurFilter();
var arrFilters:Array = [bFilter];
displayObj.filters = arrFilters;

Flash также поддерживает фильтры свертки, которые могут выполнять более сложные эффекты, такие как яркость, обнаружение краев, тиснение и т. Д.

Сверточные фильтры могут быть применены только через ActionScript, а также требуют использования матриц, описывающих, как следует воздействовать на цвета для каждого пикселя. Матрица должна быть в массиве.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
// Default
var matrixDefault:Array = [0, 0, 0,
                           0, 1, 0,
                           0, 0, 0];
 
// Brighter
var matrixBrighter:Array = [0, 0, 0,
                            0, 2, 0,
                            0, 0, 0];
 
// Darker
var matrixDarker:Array = [0, 0, 0,
                          0, 0.5, 0,
                          0, 0, 0];
 
// Emboss
var matrixEmboss:Array = [-1, -1, 0,
                          -1, 1, 1,
                           0, 1, 1];

Центральное значение — это текущий пиксель, а окружающие значения — его соседние пиксели. Значением по умолчанию является 1; увеличение этого значения приведет к тому, что изображение станет ярче. Уменьшение этого сделает его темнее. Наличие отрицательных значений в верхнем левом углу и положительных значений в нижнем правом (или наоборот) создает эффект тиснения.

Используя ActionScript, мы можем применить сверточный фильтр следующим образом:

1
2
3
4
5
6
7
8
9
// The following matrix will brighten the image.
var matrixBrighter:Array = [0, 0, 0,
                            0, 2, 0,
                            0, 0, 0];
var matrixCol:Number = 3;
var matrixRow:Number = 3;
var cvFilter:ConvolutionFilter = new ConvolutionFilter(matrixCol, matrixRow, matrixBrighter);
var arrFilters:Array = [cvFilter];
displayObj.filters = arrFilters;

Для получения дополнительной информации о фильтре Convolution обратитесь к этой статье Adobe Flash .

Теперь мы собираемся написать код ActionScript. Выберите первый кадр слоя «Actions» и перейдите на панель Actions.

Обычно я люблю сохранять согласованность текста во всей программе. Итак, вот код для установки текста (Verdana) для всех компонентов по всему миру.

1
2
3
import fl.managers.StyleManager;
var format:TextFormat = new TextFormat(«Verdana», 10, 0x000000);
StyleManager.setStyle(«textFormat», format);

Теперь давайте создадим копию фотографии (для применения фильтров) и разместим ее в том же месте, что и исходная фотография. Я собираюсь использовать версию B, так как я хочу применить маску после фильтра. В версии A, если вы примените фильтр размытия, вы можете заметить, что размытие превышает маску. Это потому, что фильтр применяет свой эффект после маски.

Позже мы будем маскировать «photoWrapper» и применять фильтры только к «photoEffect».

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
/*
// 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);

Затем создайте линию, которая разделит отфильтрованную и оригинальную фотографию. Мы будем использовать форму, чтобы нарисовать линию. Поместите линию в нижнюю середину фотографии, затем нарисуйте линию снизу вверх.

1
2
3
4
5
6
7
var comparisonLine:Shape = new Shape();
comparisonLine.x = photoOriginal.x + photoOriginal.width/2;
comparisonLine.y = photoOriginal.y + photoOriginal.height;
comparisonLine.graphics.lineStyle(2, 0x999999, 1, true);
comparisonLine.graphics.moveTo(0, 0);
comparisonLine.graphics.lineTo(0, -photoOriginal.height);
addChild(comparisonLine);

Вы помните, что у нас есть ползунок маски. Используя ActionScript, мы можем расположить его под фотографией и растянуть так, чтобы его ширина соответствовала ширине фотографии. Установка значений «максимальная» и «ширина» на ширину фотографии помогает создать соотношение 1: 1. Поэтому нам не нужно создавать преобразование масштаба позже. Кроме того, мы будем центрировать стрелку на слайдере.

1
2
3
4
5
6
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;

Теперь давайте создадим функцию и назначим событие для ползунка маски. Мы хотим, чтобы «строка сравнения» следовала за ползунком маски. Ширина «photoMask» должна меняться в зависимости от ползунка маски, когда он перетаскивается. Я знаю, что мы еще не обратились к «фотоМаске», но это следующий шаг.

1
2
3
4
5
6
7
8
import fl.events.SliderEvent;
 
function maskSliderDrag(evt:SliderEvent):void {
    comparisonLine.x = evt.target.value + evt.target.x;
    photoMask.width = evt.target.value;
}
 
mask_sld.addEventListener(SliderEvent.THUMB_DRAG, maskSliderDrag, false, 0, true);

Как упоминалось ранее, «photoMask» будет использоваться для маскировки «photoWrapper», а не «photoEffect». Поскольку это будет прямоугольная маска, мы будем использовать форму. Установите положение и размер прямоугольника так же, как «photoOriginal». Убедитесь, что вы заполните форму цветом (это может быть любой цвет), иначе маска может работать не так, как ожидалось. Затем установите «photoMask» в качестве маски photoWrapper и ширину маски в «значение» ползунка маски.

01
02
03
04
05
06
07
08
09
10
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;

Нам нужен способ сохранить последнюю нажатую кнопку, которую мы будем хранить в «activeFilter». Это будет использоваться позже ползунком интенсивности.

1
var activeFilter:Button;

Далее мы перейдем к слайдеру интенсивности. Мы определяем функцию «интенсивность изменения», которая будет вызываться всякий раз, когда ползунок интенсивности перетаскивается. Функция отправляет событие (например, щелчок мышью) на основе последней нажатой кнопки. Мы также назначим событие и первоначально отключим ползунок.

1
2
3
4
5
function intensityChange(evt:SliderEvent):void {
    activeFilter.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
intensity_sld.addEventListener(SliderEvent.THUMB_DRAG, intensityChange, false, 0, true);
intensity_sld.enabled = false;

Теперь давайте определим функции фильтра. Функции фильтра «по умолчанию» и «отрицательный» похожи в том, что они оба отключают ползунок интенсивности и, следовательно, не нуждаются в обновлении свойств ползунка. Для «размытия», «тиснения» и «яркости» все они должны повторно включить ползунок интенсивности. Кроме того, они используют свойство value для определения интенсивности фильтра. Кроме того, каждый фильтр имеет свое уникальное «максимальное» значение, поэтому нам нужно пересчитать «snapInterval». Свойство «value» также пересчитывается, так как я бы хотел, чтобы ползунок сбрасывался на полпути между min и max. Нам нужно только установить свойства ползунка интенсивности, когда «activeFilter» не равен текущей цели.

1
function default_btnHandler(evt:MouseEvent):void { var matrixDefault:Array = [0, 0, 0, 0, 1, 0, 0, 0, 0];

Примечание: для «негативного» фильтра я использовал ColorMatrixFilter, который использует матрицу 4 на 5 для применения цветовых преобразований. Для получения дополнительной информации о ColorMatrixFilter обратитесь к этой статье Adobe Flash .

Теперь давайте назначим каждой кнопке соответствующие функции.

1
2
3
4
5
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);
brightness_btn.addEventListener(MouseEvent.CLICK, brightness_btnHandler, false, 0, true);
negative_btn.addEventListener( MouseEvent.CLICK, negative_btnHandler, false, 0, true);

Я создал три дополнительные функции, а именно: applyConvolutionFilter, activeFilterAndIntensityOnOff и setSliderProperties. Их цель — уменьшить количество повторяющихся кодов в функциях фильтра.

Ваш окончательный полный код должен выглядеть примерно так …

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import fl.events.SliderEvent;
import fl.managers.StyleManager;
 
 
var format: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();
comparisonLine.x = photoOriginal.x + photoOriginal.width/2;
comparisonLine.y = photoOriginal.y + photoOriginal.height;
comparisonLine.graphics.lineStyle(2, 0x999999, 1, true);
comparisonLine.graphics.moveTo(0, 0);
comparisonLine.graphics.lineTo(0, -photoOriginal.height);
addChild(comparisonLine);
 
 
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 {
    comparisonLine.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 intensityChange(evt:SliderEvent):void {
    activeFilter.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
intensity_sld.addEventListener(SliderEvent.THUMB_DRAG, intensityChange);
intensity_sld.enabled = false;
 
 
function applyConvolutionFilter(matrix:Array):void {
    var cFilter:ConvolutionFilter = new ConvolutionFilter(3, 3 , matrix);
    photoEffected.filters = [cFilter];
}
function activeFilterAndIntensityOnOff(btn:Button, intensityOnOff:Boolean):void {
    activeFilter = btn;
    intensity_sld.enabled = intensityOnOff;
}
function setSliderProperties(btn:Button, max:Number):void {
    if(activeFilter != btn) {
        intensity_sld.maximum = max;
        intensity_sld.snapInterval = (intensity_sld.maximum — intensity_sld.minimum)/40;
        intensity_sld.value = intensity_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 = intensity_sld.value;
    var blurY:Number = intensity_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, intensity_sld.value,
                               0, intensity_sld.value, intensity_sld.value];
    applyConvolutionFilter(matrixEmboss);
    activeFilterAndIntensityOnOff(btn, true);
}
 
function brightness_btnHandler(evt:MouseEvent):void {
    var btn:Button = evt.target as Button;
    setSliderProperties(btn, 6);
    var matrixBrightness:Array = [0, 0, 0,
                                  0, intensity_sld.value, 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, 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);
brightness_btn.addEventListener(MouseEvent.CLICK, brightness_btnHandler, false, 0, true);
negative_btn.addEventListener( MouseEvent.CLICK, negative_btnHandler, false, 0, true);

Примечание. Вы даже можете пойти дальше того, что я сделал, например, реализовать центральную функцию, которая охватывает все фильтры. Затем используйте «if else if» или «switch», чтобы выполнить необходимый код для соответствующего фильтра.

Есть много вещей, которые вы можете сделать с фильтрами, я просто дал краткое введение. Основные фильтры во Flash довольно хороши тем, что есть достаточно параметров, с которыми можно поиграться. Если вы не можете найти то, что ищете, попробуйте другие фильтры, такие как ColorMatrixFilter, ConvolutionFilter, DisplacementMapFilter и т. Д. Вы можете быть удивлены тем, что найдете. Продолжайте экспериментировать и, самое главное, получайте удовольствие!

Спасибо, что нашли время для просмотра этого урока. Я надеюсь, что вы сочли полезным.