如果看不到下边的flash,请更新flash player到最新版本。
利用AGAL实现旧照片效果,大家可以对照一下之前一篇文章,关于图像处理(pixelbender)。硬件处理肯定会更快,但这里无法表现出来,毕竟图片就这么小。拖拉进度条,可以设置照片旧的程度。
package { import com.adobe.utils.AGALMiniAssembler; import com.bit101.components.HSlider; import com.bit101.components.PushButton; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.Sprite; import flash.display.Stage3D; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.display3D.Context3D; import flash.display3D.IndexBuffer3D; import flash.display3D.Program3D; import flash.display3D.VertexBuffer3D; import flash.display3D.textures.Texture; import flash.events.Event; import flash.geom.Matrix; import flash.geom.Matrix3D; import flash.net.FileFilter; import flash.net.FileReference; import flash.utils.ByteArray; import net.hires.debug.Stats; /** * 借用了boycy815的代码框架 * @author kenkozheng */ [SWF(frameRate="60")] public class AGAL_Filter extends Sprite { private const WIDTH:Number = 512; private const HEIGHT:Number = 512; //stage3d五巨头 private var _stage3d:Stage3D; private var _context3d:Context3D; private var _program3d:Program3D; private var _index:IndexBuffer3D; private var _vertex:VertexBuffer3D; private var _texture:Texture; [Embed(source=("4.jpg"))] private var ImageSource:Class; private var _vertexProgram:String = "mov op, va0\n" + "mov v0, va1"; //传递给片段shader坐标值 private var _fragmentProgram:String = "tex ft1, v0, fs0<2d,linear,nomip>\n" + "m44 ft2, ft1, fc1\n" + //颜色变换 "mul ft2, ft2, fc0.x\n" + //效果图跟原图做multiply,向量float4 * float = float4,类似PixelBender "mul ft1, ft1, fc0.y\n" + "add ft2, ft2, ft1\n" + "mov oc, ft2"; public function AGAL_Filter():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; removeEventListener(Event.ADDED_TO_STAGE, init); _stage3d = stage.stage3Ds[0]; _stage3d.addEventListener(Event.CONTEXT3D_CREATE, onCreate); _stage3d.requestContext3D(); addChild(new Stats()); } private function onCreate(e:Event):void { e.target.removeEventListener(Event.CONTEXT3D_CREATE, onCreate); _context3d = _stage3d.context3D; _context3d.enableErrorChecking = true; var agal:AGALMiniAssembler = new AGALMiniAssembler(); var vp:ByteArray = agal.assemble("vertex", _vertexProgram); var fp:ByteArray = agal.assemble("fragment", _fragmentProgram); _program3d = _context3d.createProgram(); _program3d.upload(vp, fp); _context3d.setProgram(_program3d); _context3d.configureBackBuffer(WIDTH, HEIGHT, 0, false); _context3d.setBlendFactors("one", "zero"); _context3d.setCulling("back"); //两个三角形拼成平面 _index = _context3d.createIndexBuffer(6); _index.uploadFromVector(new<uint>[0, 1, 2, 0, 2, 3], 0, 6); _vertex = _context3d.createVertexBuffer(4, 4); //这是由于纹理的坐标原点是左上角,y轴向下,最大值为1最小值为0 //而顶点的坐标原点则是在舞台中央,而且y轴向上,最大值为1最小值为-1 //那么(-1,-1)点对应的纹理就是(0,1) _vertex.uploadFromVector(new<Number>[ //x, y, u, v -1, -1, 0, 1, -1, 1, 0, 0, 1, 1, 1, 0, 1, -1, 1, 1], 0, 4); _context3d.setVertexBufferAt(0, _vertex, 0, "float2"); //xy坐标 _context3d.setVertexBufferAt(1, _vertex, 2, "float2"); //uv坐标 //纹理位图 var bt:Bitmap = Bitmap(new ImageSource()); var btmap:BitmapData = new BitmapData(WIDTH, HEIGHT); btmap.draw(bt); //上传纹理 _texture = _context3d.createTexture(btmap.width, btmap.height, "bgra", false); _texture.uploadFromBitmapData(btmap); _context3d.setTextureAt(0, _texture); //multiple比例 _context3d.setProgramConstantsFromVector("fragment", 0, new<Number>[1, 0, 0, 0]); //颜色矩阵 _context3d.setProgramConstantsFromMatrix("fragment", 1, new Matrix3D(new <Number>[ 0.393, 0.768, 0.189, 0, 0.349, 0.686, 0.168, 0, 0.272, 0.534, 0.13, 0, 0, 0, 0, 1 ])); _context3d.clear(0, 0, 0, 0); _context3d.drawTriangles(_index); _context3d.present(); start(); } private function start():void { new PushButton(this, 282, 515, "change", onUpload); new HSlider(this, 392, 520, onBar).setSliderParams(0, 1, 1); } private function onBar(e:Event):void { var v:Number = e.currentTarget.value; _context3d.setProgramConstantsFromVector("fragment", 0, new<Number>[v, 1-v, 0, 0]); _context3d.clear(0, 0, 0, 0); _context3d.drawTriangles(_index); _context3d.present(); } private function onUpload(e:Event):void { var fr:FileReference = new FileReference(); fr.addEventListener(Event.SELECT, onSelect); fr.browse([new FileFilter("jpg/png", "*.jpg;*.png")]); } private function onSelect(e:Event):void { e.currentTarget.removeEventListener(Event.SELECT, onSelect); e.currentTarget.addEventListener(Event.COMPLETE, onComplete); e.currentTarget.addEventListener(Event.OPEN, function(e:Event):void { } ); e.currentTarget.load(); } private function onComplete(e:Event):void { e.currentTarget.removeEventListener(Event.COMPLETE, onComplete); var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderOnComplete); loader.loadBytes(e.currentTarget.data); } private function loaderOnComplete(e:Event):void { e.currentTarget.removeEventListener(Event.COMPLETE, loaderOnComplete); var btmap:BitmapData = new BitmapData(WIDTH, HEIGHT); var scale:Number = Math.max(WIDTH/e.currentTarget.loader.width, HEIGHT/e.currentTarget.loader.height); btmap.draw(e.currentTarget.loader, new Matrix(scale, 0, 0, scale), null, null, null, true); _texture.uploadFromBitmapData(btmap); _context3d.clear(0, 0, 0, 0); _context3d.drawTriangles(_index); _context3d.present(); } } }