Posterize
FileReference で読み込んだ画像をポスタライズ
@author YOSHIDA, Akio (Aquioux)
/**
* Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/jox5
*/
package {
import flash.display.Sprite;
import flash.events.Event;
/**
* FileReference で読み込んだ画像をポスタライズ
* @author YOSHIDA, Akio (Aquioux)
*/
[SWF(width = "465", height = "465", frameRate = "20", backgroundColor = "#FFFFFF")]
public class Main extends Sprite {
public function Main() {
Wonderfl.capture_delay(15);
// Model を生成
var model:Model = new Model(stage);
// View を生成
var view:View = new View(model);
addChild(view);
// Controller を生成
var controller:Controller = new Controller(model);
controller.setup(stage);
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
class Model extends EventDispatcher {
public const MAX_RENGE:uint = 16; // ポスタライズ諧調最大値(256より大きい値の設定不可)
public const MIN_RENGE:uint = 2; // ポスタライズ諧調最小値(2より小さい値の設定不可)
private var stageWidth:uint; // ステージ幅
private var stageHeight:uint; // ステージ高
private const imageEdge:uint = 420; // 表示される画像の辺の最大値
private var _saveBitmapData:BitmapData; // 読み込んだ画像の BitmapData の退避
private var _rect:Rectangle; // BitmapData.draw 用 Rectangle
private const DEST_POINT:Point = new Point(0, 0); // BitmapData.draw 用 Point
// --------------------------------------------------
// View へ渡すデータ(プロパティ)
// --------------------------------------------------
/**
* 加工済みの画像
*/
private var _data:BitmapData;
public function get data():BitmapData { return _data; }
// --------------------------------------------------
// 外部との通信をおこなうメソッド
// --------------------------------------------------
/**
* 対 View 用メソッド
* このメソッドの終了時にイベントを発行するので、View との通信手段となる
* @private
*/
private function update():void {
dispatchEvent(new Event(Event.CHANGE));
}
/**
* 対 Controller 用メソッド
* PushButton
* @param bitmapData FileReference で読み込んだ画像の BitmapData
*/
internal function updateFromPushButton(bitmapData:BitmapData):void {
_saveBitmapData.fillRect(_rect, 0xFFFFFFFF);
var scale:Number = imageEdge / Math.max(bitmapData.width, bitmapData.height);
var w:uint = bitmapData.width * scale;
var h:uint = bitmapData.height * scale;
_saveBitmapData.draw(bitmapData, new Matrix(scale, 0, 0, scale, (stageWidth - w) / 2 >> 0, (stageHeight - h) / 2 >> 0));
updateFromSlider(MAX_RENGE);
}
/**
* 対 Controller 用メソッド
* Slider
* @param val スライダーからの値
*/
internal function updateFromSlider(val:uint):void {
_data = _saveBitmapData.clone()
posterize(_data, val);
update();
}
// --------------------------------------------------
// その他のメソッド
// --------------------------------------------------
/**
* コンストラクタ
*/
public function Model(stage:Stage) {
stageWidth = stage.stageWidth;
stageHeight = stage.stageHeight;
_saveBitmapData = new BitmapData(stageWidth, stageHeight);
_rect = _saveBitmapData.rect;
}
/**
* ポスタライズ
* @private
*/
private function posterize(bitmapData:BitmapData, step:uint):void {
if (step < MIN_RENGE || step > MAX_RENGE){
var message:String = "ステップ数は" + MIN_RENGE + "から" + MAX_RENGE + "の間です"
throw(new Error(message));
}
// 各段階における色階層値を計算
var thresholds:Array = [];
for (var i:int = 0; i < step; i++) {
thresholds[i] = ((256 / (step - 1)) * i) >> 0;
}
var lastIdx:uint = step - 1;
if (thresholds[lastIdx] != 255) thresholds[lastIdx] = 255;
// palletMap 用 Array の生成
var r:Array = [];
var g:Array = [];
var b:Array = [];
for (i = 0; i < 256; i++) {
var idx:uint = (i / (256 / step)) >> 0;
var val:uint = thresholds[idx];
r[i] = val << 16;
g[i] = val << 8;
b[i] = val;
}
// paletteMap
bitmapData.paletteMap(bitmapData, _rect, DEST_POINT, r, g, b);
}
}
import flash.display.Bitmap;
import flash.events.Event;
/**
* @author YOSHIDA, Akio (Aquioux)
*/
class View extends Bitmap {
/**
* コンストラクタ
* @param model Model
*/
private var model:Model;
public function View(model:Model) {
this.model = model;
this.model.addEventListener(Event.CHANGE, changeHandler);
}
/**
* Model との通信手段
* @private
*/
private function changeHandler(event:Event):void {
// Model からデータを受け取り、視覚化
this.bitmapData = model.data;
}
}
import com.bit101.components.Label;
import com.bit101.components.PushButton;
import com.bit101.components.Slider;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.net.FileReference;
class Controller {
private var sliderLayer:Sprite;
private var slider:Slider;
private var label:Label;
private var pushButton:PushButton;
/**
* コンストラクタ
* @param model Model
*/
private var model:Model;
public function Controller(model:Model) {
this.model = model;
}
/**
* セットアップ
* @param stage ステージ
*/
private var stage:Stage;
public function setup(stage:Stage):void {
this.stage = stage;
this.stage.addChild(sliderLayer = initSlider());
this.stage.addChild(initPushButton());
}
/**
* スライダーの生成
* @private
*/
private function initSlider():Sprite {
var layer:Sprite = new Sprite();
// スライダー
slider = new Slider(Slider.HORIZONTAL, null, 0, 0, sliderHandler);
slider.setSliderParams(model.MIN_RENGE, model.MAX_RENGE, model.MAX_RENGE);
slider.width = stage.stageWidth;
slider.y = stage.stageHeight - slider.height;
layer.addChild(slider);
// ステップ数を表示するラベル
label = new Label();
changeLabel(slider.value);
label.y = slider.y - label.height;
layer.addChild(label);
layer.visible = false; // 最初は不可視
return layer;
}
/**
* スライダーのラベルの表示を書き換える
* @private
*/
private function changeLabel(value:uint):void {
label.text = "Step " + String(value);
}
/**
* イベントハンドラ
* Model との通信手段
* Slider のイベント
* @private
*/
private function sliderHandler(event:Event):void {
var sliderValue:uint = int(event.target.value);
changeLabel(sliderValue); // スライダーのラベルを書き換える
model.updateFromSlider(sliderValue);
}
/**
* ロード用ボタンの生成
* @private
*/
private function initPushButton():PushButton {
pushButton = new PushButton(null, 0, 0, "LOAD", pushButtonHandler);
pushButton.width = 60;
return pushButton;
}
/**
* イベントハンドラ
* Model との通信手段
* PushButton のイベント
* 画像ロード step 1
* ファイル選択
* @private
*/
private var loadFileRef:FileReference;
private function pushButtonHandler(event:Event):void {
if (!sliderLayer.visible) sliderLayer.visible = true;
resetSlider(); // スライダーの初期化
// FileReference
loadFileRef = new FileReference();
loadFileRef.addEventListener(Event.SELECT, loadFileSelectedHandler);
loadFileRef.browse();
}
/**
* 画像ロード step 2
* ファイル読込
* @private
*/
private function loadFileSelectedHandler(event:Event):void {
loadFileRef.addEventListener(Event.COMPLETE, fileLoadCompleteHandler);
loadFileRef.load();
}
/**
* 画像ロード step 3
* ファイル読込完了
* @private
*/
private var loader:Loader;
private function fileLoadCompleteHandler(event:Event):void {
loader = new Loader();
loader.loadBytes(FileReference(event.target).data);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoadedHandler);
}
/**
* 画像ロード step 4
* 読み込んだ画像の BitmapData を Model に送信
* @private
*/
private function imageLoadedHandler(event:Event):void {
model.updateFromPushButton(Bitmap(loader.content).bitmapData);
}
/**
* スライダーのリセット
* @private
*/
private function resetSlider():void {
slider.value = model.MAX_RENGE;
changeLabel(slider.value);
}
}