選択した範囲の画像をハイライトする(2)

昨日の記事でひだちのいろさんから指摘を受けましたが、とりあえず現在既にぼかしをかけるものがあるので、とりあえず貼付けておきます。

このバージョンではぼかし方がよくわからなかったので、setPixelやgetPixelと選択したポイントからの距離を使用して無理矢理ぼかしを作成しています。力技って感じで、エレガントじゃないです。

追記:2007/11/26
ハイライトするプログラムを公開しました。BlurHighlight


package {
	import flash.display.*;
	import flash.filters.*;
	import flash.geom.*;
	import flash.events.MouseEvent;

	public class Study10Gradient extends Sprite {
		[Embed(source='assets/palau.jpg')]
		private var Palau:Class;
		private var beginPoint:Point = new Point(0, 0);
		private var endPoint:Point = new Point(0, 0);
		private var container:Sprite;
		private var bmp:Bitmap;
		private var cachedBmp:Bitmap;
		private var maskRect:Shape;
		private static const FADE:int = 10;
		private static const FADE_ALPHA:Number = 0.4;

		public function Study10Gradient() {
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			container = new Sprite();
			addChild(container);
			bmp = new Palau();
			container.addChild(bmp);
			cachedBmp = new Palau();
			draw();
			container.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
		}

		private function onMouseDown(event:MouseEvent):void {
			trace(event);
			beginPoint = endPoint = new Point(mouseX, mouseY);
			draw();
			container.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
			container.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		}

		private function onMouseMove(event: MouseEvent):void {
			endPoint = new Point(mouseX, mouseY);
			draw();
		}

		private function onMouseUp(event: MouseEvent):void {
			endPoint = new Point(mouseX, mouseY);
			draw();
			container.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
			container.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		}

		private function draw():void {
			// キャッシュしないようにクリアする
			graphics.clear();
			var bmd:BitmapData = bmp.bitmapData;
			// 一度キャッシュしたものに初期化
			bmd.copyPixels(cachedBmp.bitmapData, new Rectangle(0, 0, cachedBmp.width, cachedBmp.height), new Point(0, 0));
			// アルファを下げて全体を暗くする
			var filter:ColorMatrixFilter = new ColorMatrixFilter([
				1, 0, 0, 0, 0,
				0, 1, 0, 0, 0,
				0, 0, 1, 0, 0,
				0, 0, 0, FADE_ALPHA, 0
			]);
			bmd.applyFilter(bmd, bmd.rect, new Point(0, 0), filter);
			// 四隅を定義する
			var sx:int, ex:int, sy:int, ey:int;
			if (beginPoint.x > endPoint.x) {
				sx = endPoint.x;
				ex = beginPoint.x;
			} else {
				sx = beginPoint.x;
				ex = endPoint.x;
			}
			if (beginPoint.y > endPoint.y) {
				sy = endPoint.y;
				ey = beginPoint.y;
			} else {
				sy = beginPoint.y;
				ey = endPoint.y;
			}

			// 一定の大きさが無いとかけないようにする
			if (Math.abs(beginPoint.x - endPoint.x) <= FADE * 2 || Math.abs(beginPoint.y - endPoint.y) <= FADE * 2) return;

			// ハイライトする
			var rectAngle:Rectangle = new Rectangle(sx ,sy, ex - sx, ey - sy);
			bmd.copyPixels(cachedBmp.bitmapData, rectAngle, new Point(sx, sy));

			blurHighlight(bmd, rectAngle);
		}

		// ハイライト部分をぼかして自然なハイライトにする
		private function blurHighlight(bmd:BitmapData, rectAngle:Rectangle):void {
			var i:int;
			var j:int;
			var dist:int;
			// 描画領域を狭める
			rectAngle.inflate(-FADE, -FADE);
			for (i = rectAngle.left; i < rectAngle.right; i++) {
				for (j = rectAngle.top; j >= rectAngle.top - FADE; j--) {
					blurBoundary(bmd, rectAngle.top - j, i, j);
				}
				for (j = rectAngle.bottom; j < rectAngle.bottom + FADE; j++) {
					blurBoundary(bmd, j - rectAngle.bottom, i, j);
				}
			}
			for (j = rectAngle.top; j < rectAngle.bottom; j++) {
				for (i = rectAngle.left; i >= rectAngle.left - FADE; i--) {
					blurBoundary(bmd, rectAngle.left - i, i, j);
				}
				for (i = rectAngle.right; i < rectAngle.right + FADE; i++) {
					blurBoundary(bmd, i - rectAngle.right, i, j);
				}
			}
			// 4隅をぼかす
			for (i = rectAngle.left - FADE; i < rectAngle.left; i++) {
				for (j = rectAngle.top - FADE; j < rectAngle.top; j++) {
					dist = Math.sqrt(Math.pow(rectAngle.left - i, 2) + Math.pow(rectAngle.top - j, 2));
					blurBoundary(bmd, dist, i, j);
				}
				for (j = rectAngle.bottom; j < rectAngle.bottom + FADE; j++) {
					dist = Math.sqrt(Math.pow(rectAngle.left - i, 2) + Math.pow(j - rectAngle.bottom, 2));
					blurBoundary(bmd, dist, i, j);
				}
			}
			for (i = rectAngle.right; i < rectAngle.right + FADE; i++) {
				for (j = rectAngle.top - FADE; j < rectAngle.top; j++) {
					dist = Math.sqrt(Math.pow(i - rectAngle.right, 2) + Math.pow(rectAngle.top - j, 2));
					blurBoundary(bmd, dist, i, j);
				}
				for (j = rectAngle.bottom; j < rectAngle.bottom + FADE; j++) {
					dist = Math.sqrt(Math.pow(i - rectAngle.right, 2) + Math.pow(j - rectAngle.bottom, 2));
					blurBoundary(bmd, dist, i, j);
				}
			}
		}

		// 距離に応じてぼかす
		private function blurBoundary(bmd:BitmapData, distance:int, x:int, y:int):void {
			if (distance > FADE) distance = FADE;
			var alpha:Number = (distance / FADE) * (1 - FADE_ALPHA);
			var transform:ColorTransform = new ColorTransform(1, 1, 1, 1 - alpha);
			var rect:Rectangle = new Rectangle(x, y, 1, 1);
			bmd.colorTransform(rect, transform);
		}
	}
}