ToyCamera トイカメラ風エフェクト
2010.04.22 保存機能追加
/**
* Copyright fernet ( http://wonderfl.net/user/fernet )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/xaas
*/
// 2010.04.22 保存機能追加
package
{
import com.bit101.components.PushButton;
import com.bit101.components.HUISlider;
import com.bit101.components.CheckBox;
import com.bit101.components.RadioButton;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(width=465,height=465,backgroundColor=0xaaaaaa)]
/**
* ...
* @author fernet
*/
public class Main extends Sprite
{
private var _imgbox:Sprite = new Sprite;
private var _lastLoad:Bitmap;
private var _ctrlCont:CheckBox;
private var _ctrlContLevel:HUISlider;
private var _ctrlSat:CheckBox;
private var _ctrlSatLevel:HUISlider;
private var _ctrlTunnel:CheckBox;
private var _ctrlTunnelSize:HUISlider;
private var _ctrlTunnelRatio:HUISlider;
private var _ctrlNoise:CheckBox;
private var _ctrlNoiseLevel:HUISlider;
private var _ctrlCA:CheckBox;
private var _ctrlCALevel:HUISlider;
private var _ctrlBlur:CheckBox;
private var _ctrlBlurLevel:HUISlider;
public function Main():void
{
Wonderfl.capture_delay(30);
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
addChild(_imgbox);
_imgbox.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
_imgbox.startDrag();
});
_imgbox.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void {
_imgbox.stopDrag();
});
var y:int = 0;
var imloader:LocalImageLoader = new LocalImageLoader;
new PushButton(stage, 0, y, "Browse Image", function(e:Event):void {
imloader.load(_onBitmap);
});
y += 30;
_ctrlCont = new CheckBox(stage, 0, y, "Contrast", _onChangeControl); y += 10;
_ctrlCont.selected = true;
_ctrlContLevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
_ctrlContLevel.setSliderParams(0, 2, 0.8);
y += 20;
_ctrlSat = new CheckBox(stage, 0, y, "Saturation", _onChangeControl); y += 10;
_ctrlSat.selected = true;
_ctrlSatLevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
_ctrlSatLevel.setSliderParams(0.5, 3, 1.2);
y += 20;
_ctrlTunnel = new CheckBox(stage, 0, y, "TunnelEffect", _onChangeControl); y += 10;
_ctrlTunnel.selected = true;
_ctrlTunnelSize = new HUISlider(stage, 0, y, "Size", _onChangeControl); y += 10;
_ctrlTunnelSize.setSliderParams(2, 5, 3);
_ctrlTunnelRatio = new HUISlider(stage, 0, y, "Ratio", _onChangeControl); y += 10;
_ctrlTunnelRatio.setSliderParams(1, 254, 210);
y += 20;
_ctrlNoise = new CheckBox(stage, 0, y, "Noise", _onChangeControl); y += 10;
_ctrlNoise.selected = true;
_ctrlNoiseLevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
_ctrlNoiseLevel.setSliderParams(0, 255, 30);
y += 20;
_ctrlCA = new CheckBox(stage, 0, y, "ChromaticAberration", _onChangeControl); y += 10;
_ctrlCA.selected = true;
_ctrlCALevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
_ctrlCALevel.setSliderParams(0, 10, 2);
y += 20;
_ctrlBlur = new CheckBox(stage, 0, y, "Blur", _onChangeControl); y += 10;
_ctrlBlur.selected = true;
_ctrlBlurLevel = new HUISlider(stage, 0, y, "Level", _onChangeControl); y += 10;
_ctrlBlurLevel.setSliderParams(0, 20, 1.5);
y += 20;
var formatJpg:RadioButton = new RadioButton(stage, 0, y, "JPEG", true);
var formatPng:RadioButton = new RadioButton(stage, 50, y, "PNG", false);
y += 20;
new PushButton(stage, 0, y, "Save Image", function(e:Event):void {
if (!_lastLoad) return;
var encoder:LocalImageEncoder = new LocalImageEncoder;
var bd:BitmapData = (_imgbox.getChildAt(0) as Bitmap).bitmapData;
var now:String = new DateFormat("%Y%m%d_%H%M%S").make();
formatJpg.selected ?
encoder.saveJpg(bd, "toycamera_" + now + ".jpg"):
encoder.savePng(bd, "toycamera_" + now + ".png");
});
}
private function _onBitmap(bmp:Bitmap):void
{
_lastLoad = bmp;
_process();
}
private function _onChangeControl(e:Event):void
{
if (_lastLoad)
_process();
}
private function _onClickSave(e:Event):void
{
if (_lastLoad)
{
var encoder:LocalImageEncoder = new LocalImageEncoder;
_process();
}
}
private function _process():void
{
var bd:BitmapData = _lastLoad.bitmapData.clone();
var tc:ToyCamera = new ToyCamera(bd);
if(_ctrlCont.selected)
tc.setContrast(_ctrlContLevel.value);
if (_ctrlSat.selected)
tc.setSaturation(_ctrlSatLevel.value);
if(_ctrlTunnel.selected)
tc.setTunnel(_ctrlTunnelRatio.value, _ctrlTunnelSize.value);
if(_ctrlCA.selected)
tc.setChromaticAberration(_ctrlCALevel.value);
if(_ctrlNoise.selected)
tc.setNoise(_ctrlNoiseLevel.value);
if(_ctrlBlur.selected)
tc.setBlur(_ctrlBlurLevel.value);
if (_imgbox.numChildren)
_imgbox.removeChildAt(0);
_imgbox.addChild(new Bitmap(tc.data));
}
}
}
class ToyCamera {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.Shape;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.utils.ByteArray;
private var _canvas:BitmapData;
public function ToyCamera(bd:BitmapData)
{
_canvas = bd;
_canvas.lock();
}
/**
* コントラスト
*/
public function setContrast(c:Number):void
{
var mtx:Array = [
c+1, 0, 0, 0, -c*0x80,
0, c+1, 0, 0, -c*0x80,
0, 0, c+1, 0, -c*0x80,
0, 0, 0, 1, 0
];
var filter:ColorMatrixFilter = new ColorMatrixFilter(mtx);
_canvas.applyFilter(_canvas, _canvas.rect, new Point, filter);
}
/**
* 彩度
*/
public function setSaturation(s:Number = 3):void
{
var a:Number = s * 2 / 3 + 1 / 3;
var b:Number = (1 - a) / 2;
var mtx:Array = [
a, b, b, 0, 0,
b, a, b, 0, 0,
b, b, a, 0, 0,
0, 0, 0, 1, 0
];
var filter:ColorMatrixFilter = new ColorMatrixFilter(mtx);
_canvas.applyFilter(_canvas, _canvas.rect, new Point, filter);
}
/**
* トンネル
*/
public function setTunnel(ratio:int, size:Number):void
{
var h:int = _canvas.height, w:int = _canvas.width;
var larger:int = w > h ? w : h;
var shape:Shape = new Shape;
shape.graphics.beginGradientFill(GradientType.RADIAL,
[0x0, 0x0, 0x0],
[0.0, 0.0, 1.0],
[0x00, ratio, 0xFF]
);
shape.graphics.drawCircle(0, 0, larger / 2);
var mtx:Matrix = new Matrix(
size, 0,
0, size,
w / 2, h / 2);
_canvas.draw(shape, mtx);
}
/**
* ぼかし
*/
public function setBlur(lv:Number):void
{
var src:BitmapData = _canvas;
var blur:BlurFilter = new BlurFilter(lv, lv, 1);
src.applyFilter(src, src.rect, new Point, blur);
}
/**
* 色収差
* 赤チャンネルをlv%縮小し、青チャンネルをlv%拡大してる
*/
public function setChromaticAberration(lv:Number):void
{
lv /= 100;
var src:BitmapData = _canvas.clone();
var dst:BitmapData = _canvas;
var w:int = dst.width, h:int = dst.height;
for (var y:int=0; y<h; y++) {
for (var x:int = 0; x<w; x++) {
var r:uint = src.getPixel(_calcPx(x,w,+lv), _calcPx(y,h,+lv)) & 0xff0000;
var g:uint = src.getPixel(_calcPx(x,w, 0), _calcPx(y,h, 0)) & 0x00ff00;
var b:uint = src.getPixel(_calcPx(x,w,-lv), _calcPx(y,h,-lv)) & 0x0000ff;
dst.setPixel(x, y, r|g|b);
}
}
}
// 中心からlen%外側の座標
private function _calcPx(pos:int, max:int, lv:Number):int
{
var ret:int = (pos * (1 + lv)) - (max / 2 * lv);
if (ret < 0) ret = 0;
if (ret > max - 1) ret = max - 1;
return ret;
}
/**
* ノイズ
* 0xC0に近いほど粒状感が出やすいらしい?
*/
public function setNoise(level:Number):void
{
var src:BitmapData = _canvas;
var noise:BitmapData = new BitmapData(src.width, src.height, true, 0x00ffffff);
noise.noise(123, 0, 255, 4 | 2 | 1, true);
for (var y:int=0; y<src.height; y++) {
for (var x:int = 0; x < src.width; x++) {
var col:uint = src.getPixel(x, y);
var gray:int = ((col >> 16) + (col >> 8 & 0xff) + (col & 0xff)) / 3;
var alpha:int = (0xc0 - Math.abs(0xc0 - gray)) / 0xc0 * level;
var noisecol:uint = noise.getPixel(x,y)
noise.setPixel32(x, y, (alpha << 24) | noisecol);
}
}
src.copyPixels(noise, noise.rect, new Point, null, new Point, true);
}
public function get data():BitmapData
{
_canvas.unlock();
return _canvas;
}
}
class LocalImageLoader
{
import flash.display.Loader;
import flash.display.Bitmap;
import flash.net.FileReference;
import flash.net.FileFilter;
import flash.events.Event;
private var _callback:Function = function(bmp:Bitmap):void{};
private var _file:FileReference = new FileReference;
private var _loader:Loader = new Loader;
public function LocalImageLoader()
{
_file.addEventListener(Event.SELECT, _onSelect);
_file.addEventListener(Event.COMPLETE, _onComplete);
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _finish);
}
public function load(callback:Function):void
{
_callback = callback;
_file.browse([new FileFilter("Images", "*.jpg;*.jpeg;*.gif;*.png")]);
}
private function _onSelect(e:Event):void
{
_file.load();
}
private function _onComplete(e:Event):void
{
_loader.loadBytes(_file.data);
}
private function _finish(e:Event):void
{
_callback(_loader.content);
}
}
class LocalImageEncoder
{
import flash.net.FileReference;
import flash.display.BitmapData;
import flash.utils.ByteArray;
import com.adobe.images.PNGEncoder;
import com.adobe.images.JPGEncoder;
private var _file:FileReference = new FileReference;
public function savePng(bd:BitmapData, filename:String = null):void
{
_saveByteArray(PNGEncoder.encode(bd), filename);
}
public function saveJpg(bd:BitmapData, filename:String = null, quality:int = 95):void
{
var enc:JPGEncoder = new JPGEncoder(quality);
_saveByteArray(enc.encode(bd), filename);
}
private function _saveByteArray(ba:ByteArray, filename:String = null):void
{
_file.save(ba, filename);
}
}
class DateFormat
{
private var _format:String;
public function DateFormat(format:String)
{
_format = format;
}
public function make(time:Date = null):String
{
if (time == null) time = new Date;
var ret:String = _format.replace(/%(.)/g, function():String {
switch(arguments[1])
{
case "Y": return time.getFullYear().toString();
case "m": return ("0" + time.getMonth().toString()).substr(-2);
case "d": return ("0" + time.getDate().toString()).substr(-2);
case "H": return ("0" + time.getHours().toString()).substr(-2);
case "M": return ("0" + time.getMinutes().toString()).substr(-2);
case "S": return ("0" + time.getSeconds().toString()).substr( -2);
}
return arguments[0];
});
return ret;
}
}