Reputation: 65
I have to build a flash application for simple wrinkle retouching. The user should be able to upload a portrait photo, select the wrinkled areas and then a blur filter will be applied to the selected parts. My question is - is it somehow possible to apply the filter to a freeform area? I know it would be easy to make the selection rectangular, but that would not be very useful to really mark the correct areas. Ideally the user should get some kind of round brush to use for marking the areas, press "OK" and then the filter will be applied. Is there any way to do this? And do you maybe have some further recommendations on how to approach this task? I have very little experience with manipulating bitmap data with ActionScript.
Any help is appreciated! Thanks very much in advance :-)
Upvotes: 0
Views: 652
Reputation: 3532
The algorithm is as follows:
BitmapData.draw()
(let it be A)Bitmapdata.copyPixels()
(let it be B).BitmapData.threshold()
using A as source bitmap.Bitmapdata.copyPixels()
Here's a complete and working example.
I've written the code anyway while figuring out the solution.
Hope you find it usefull.
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.URLRequest;
import flash.system.LoaderContext;
[SWF(width="800", height="600",backgroundColor="#FFFFFF")]
public class TestBlur extends Sprite
{
private const loader:Loader = new Loader();
public function TestBlur()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
loader.load(new URLRequest("https://i.sstatic.net/u3iEv.png"), new LoaderContext(true));
}
protected function onLoadComplete(event:Event):void
{
trace(event);
var bmp:Bitmap = loader.content as Bitmap;
addChild(bmp);
// create some test selection area
var selection:Shape = new Shape();
selection.graphics.lineStyle(30, 0xFF0000, .5);
selection.graphics.curveTo(75, -50, 200, 10);
selection.x = 40;
selection.y = 60;
addChild(selection);
// create a duplicate of the original image
var target:BitmapData = bmp.bitmapData.clone();
var targetBmp:Bitmap = new Bitmap(target);
targetBmp.x = bmp.x + bmp.width;
addChild(targetBmp);
//
// *** main work starts here ***
// by now we have selection shape and a bitmap to blur
const destPoint:Point = new Point();
const drawMatrix:Matrix = new Matrix();
const blurMargin:uint = 10;
const blur:BlurFilter = new BlurFilter(2, 2, 3);
var rect:Rectangle;
// 0: prepare an image of selection area
// we'll need it at step 3
rect = selection.getBounds(selection);
rect.x -= blurMargin;
rect.y -= blurMargin;
rect.width += blurMargin*2;
rect.height += blurMargin*2;
var selectionImage:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
drawMatrix.identity();
drawMatrix.translate(-rect.x, -rect.y);
selectionImage.draw(selection, drawMatrix);
// just some testing
var test0:Bitmap = new Bitmap(selectionImage.clone());
test0.y = bmp.y + bmp.height;
addChild(test0);
// 1: cut a rectangular piece of original image that is covered by selection area
rect = selection.getBounds(selection.parent);
rect.x -= blurMargin;
rect.y -= blurMargin;
rect.width += blurMargin*2;
rect.height += blurMargin*2;
var area:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
area.copyPixels(bmp.bitmapData, rect, destPoint);
// just some testing
var test1:Bitmap = new Bitmap(area.clone());
test1.y = bmp.y + bmp.height;
test1.x = test0.x + test0.width;
addChild(test1);
// 2: remove all pixels that are not covered by selection
area.threshold(selectionImage, area.rect, destPoint, "==", 0, 0, 0xFF000000);
// just some testing
var test2:Bitmap = new Bitmap(area.clone());
test2.y = test0.y + test0.height;
test2.x = test0.x;
addChild(test2);
// 3: blur copied area
area.applyFilter(area, area.rect, destPoint, blur);
// just some testing
var test3:Bitmap = new Bitmap(area.clone());
test3.y = test0.y + test0.height;
test3.x = test2.x + test2.width;
addChild(test3);
// 4: copy blurred pixels back to target image
destPoint.x = rect.x;
destPoint.y = rect.y;
target.copyPixels(area, area.rect, destPoint);
}
}
}
Upvotes: 3