PhotoMosaic
MediaRSS でフォトモザイク
フォトモザイクは
Flash Math & Physics Design ActionScript 3.0による数学・物理学表現[実践編] を参照
/**
* Copyright h_kamizono ( http://wonderfl.net/user/h_kamizono )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ttkj
*/
// MediaRSS でフォトモザイク
// フォトモザイクは
// Flash Math & Physics Design ActionScript 3.0による数学・物理学表現[実践編] を参照
package {
import flash.display.*;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.trace.Trace;
import flash.system.Security;
public class Main extends Sprite {
private var tags:Vector.<String> = Vector.<String>([
"black", "landscape", "yellow", "pink", "purple", "animal", "green", "red",
"shadow", "sea", "leaf", "tree", "pepper", "apple", "banana", "aqua", "auburn",
"blue", "sky", "ninjya", "samurai", "buff", "nude", "human", "man", "woman", "people",
"cloud", "rock", "gundam"
]);
private var _feed:String = "http://api.flickr.com/services/feeds/photos_public.gne?tags=";
private var media:Namespace = new Namespace("http://search.yahoo.com/mrss/");
private var ps:Array = new Array();
//private var basePicUrl:String = "http://farm5.static.flickr.com/4075/4927175448_704667c380.jpg";
private var bps:BasePictureSymbol;
private var calculateCount:int = 0;
public function Main() {
Security.loadPolicyFile("http://farm5.static.flickr.com/crossdomain.xml");
var idx:int = Math.floor(Math.random() * tags.length);
// baseとなる画像のURL取得、適当にtagsの中からランダムに
var basePictureLdr:URLLoader = new URLLoader;
basePictureLdr.addEventListener(Event.COMPLETE, function _load(e:Event):void {
basePictureLdr.removeEventListener(Event.COMPLETE, _load);
var basePicUrl:String = XML(basePictureLdr.data)..media::thumbnail.@url.toXMLString().split('\n')[0];
// baseとなる画像の描画
bps = new BasePictureSymbol(basePicUrl);
bps.x = 0; bps.y = 0;
addChild(bps);
bps.addEventListener(BasePictureSymbol.HAS_LOADED, function ():void {
bps.clear();
mosaic();
});
});
basePictureLdr.load(new URLRequest(_feed + tags [idx] + "&format=rss_200"));
}
private function mosaic() :void {
for (var i:int = 0; i < tags.length; i++) {
var ldr:URLLoader = new URLLoader;
ldr.addEventListener (Event.COMPLETE, function _load (event:Event):void {
var ldr:URLLoader = URLLoader (event.target);
ldr.removeEventListener (Event.COMPLETE, _load);
var a:Array = XML(ldr.data)..media::thumbnail.@url.toXMLString().split('\n');
for (var j:int = 0; j < a.length; j++) {
if (a [j] == "") continue;
var sp:PictureSymbol = new PictureSymbol(a[j]);
sp.addEventListener(TheEvent.HAS_LOADED, function _PUSH ():void {
ps.push(sp);
calculate();
//trace(calculateCount);
});
}
});
ldr.load (new URLRequest (_feed + tags [i] + "&format=rss_200"));
}
}
private function calculate() :void {
if (ps.length > 0) {
calculateCount++;
//trace("ps "+ps.length);
for (var i:int = 0; i < bps.redValue.length; ++i) {
for (var j:int = 0; j < bps.redValue[i].length; ++j) {
var minDist:Number = 10000000;
var minNum:Number = -1;
for (var k:int = 0; k < ps.length; ++k) {
var dist:Number = Math.sqrt(
Math.pow(ps[k].redValue - bps.redValue[i][j], 2) +
Math.pow(ps[k].greenValue - bps.greenValue[i][j], 2) +
Math.pow(ps[k].blueValue - bps.blueValue[i][j], 2));
if (minDist > dist && bps.avgColors[i][j] > dist) {
minDist = dist;
minNum = k;
bps.avgColors[i][j] = dist;
}
}
if (minNum >= 0) {
bps.place(ps[minNum], j, i);
}
}
}
// 使い終わった画像を削除
ps.shift();
}
}
}
}
import flash.events.MouseEvent;
import flash.text.TextFormat;
import flash.text.TextField;
import flash.events.IOErrorEvent;
import flash.media.Sound;
import flash.display.MovieClip;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.system.LoaderContext;
class BasePictureSymbol extends MovieClip {
public static const displaySize:Number = 500;
public static const motoSize:Number = 500;
public static var picSize:Number = 20;
public var redValue:Array = new Array();
public var greenValue:Array = new Array();
public var blueValue:Array = new Array();
public var avgColors:Array = new Array();
private var motoBmd:BitmapData;
private var placeBmd:BitmapData;
public static const HAS_LOADED:String = "hasLoaded";
public function BasePictureSymbol(loc:String) :void {
scaleX = displaySize/motoSize;
scaleY = displaySize/motoSize;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(
Event.COMPLETE, onImageLoaded);
loader.load(new URLRequest(loc.replace("_s", "")));
}
public function onImageLoaded(ev:Event) :void {
try {
var loader:Loader = Loader(ev.target.loader);
var image:Bitmap = Bitmap(loader.content);
trace(image.width, image.height);
loader.contentLoaderInfo.removeEventListener(
Event.COMPLETE, onImageLoaded);
makeBitmap(image);
this.dispatchEvent(new Event(HAS_LOADED));
} catch (err:TypeError) {
trace("Error : "+ err.message);
}
}
public function makeBitmap(img:Bitmap) :void {
motoBmd = new BitmapData(motoSize, motoSize);
var bai:Number = motoSize/Math.min(img.width, img.height);
var idoX:Number = 0;
var idoY:Number = 0;
if (img.width > img.height) {
idoX = -bai*(img.width - img.height)/2;
} else {
idoY = -bai*(img.height - img.width)/2;
}
var mat:Matrix = new Matrix(bai, 0, 0, bai, idoX, idoY);
var rct:Rectangle = new Rectangle(
0, 0, bai*Math.min(img.width, img.height),
bai*Math.min(img.width, img.height));
motoBmd.draw(img, mat, null ,null, rct, false);
addChild(new Bitmap(motoBmd));
placeBmd = new BitmapData(motoSize, motoSize);
addChild(new Bitmap(placeBmd));
}
public function clear() :void {
placeBmd.fillRect(new Rectangle(0, 0, motoSize, motoSize),
0x00FF0000);
analysis();
}
public function analysis() :void {
redValue = new Array();
greenValue = new Array();
blueValue = new Array();
for (var i:Number = 0; i < motoBmd.height; i += picSize) {
redValue.push(new Array());
greenValue.push(new Array());
blueValue.push(new Array());
avgColors.push(new Array());
for (var j:Number = 0; j < motoBmd.width; j += picSize) {
var col:uint = Functions.getAvgColor(
motoBmd, j, i, picSize, picSize);
redValue[redValue.length - 1].push(col >> 16 & 0x0000FF);
greenValue[greenValue.length - 1].push(col >> 8 & 0x0000FF);
blueValue[blueValue.length - 1].push(col & 0x0000FF);
avgColors[avgColors.length - 1].push(10000000);
}
}
}
public function place(ps:PictureSymbol, x:Number, y:Number) :void {
var bitmap:Bitmap = ps.getBitmap();
if (bitmap != null) {
placeBmd.draw(bitmap, new Matrix(1, 0, 0, 1,
x*picSize, y*picSize));
}
}
}
import flash.display.MovieClip;
import flash.display.Loader;
import flash.net.URLLoader;
import flash.events.Event;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Rectangle;
import flash.geom.Matrix;
class PictureSymbol extends MovieClip {
public var redValue:Number = 0;
public var greenValue:Number = 0;
public var blueValue:Number = 0;
private var bmp:Bitmap;
public function PictureSymbol(loc:String) :void {
var context:LoaderContext = new LoaderContext(true);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(
Event.COMPLETE, onImageLoaded);
loader.contentLoaderInfo.addEventListener(
IOErrorEvent.IO_ERROR, onImageErrorLoaded);
//loader.load(new URLRequest(loc.replace("_s", "")), context);
loader.load(new URLRequest(loc), context);
}
public function onImageLoaded(ev:Event) :void {
try {
var loader:Loader = Loader(ev.target.loader);
var image:Bitmap = Bitmap(loader.content);
loader.contentLoaderInfo.addEventListener(
Event.COMPLETE, onImageLoaded);
loader.contentLoaderInfo.addEventListener(
IOErrorEvent.IO_ERROR, onImageErrorLoaded);
var bmd:BitmapData = new BitmapData(
BasePictureSymbol.picSize,
BasePictureSymbol.picSize);
var bai:Number = BasePictureSymbol.picSize/Math.min(image.width, image.height);
var idoX:Number = 0;
var idoY:Number = 0;
if (image.width > image.height) {
idoX = -bai*(image.width - image.height)/2;
} else {
idoY = -bai*(image.height - image.width)/2;
}
var mat:Matrix = new Matrix(bai, 0, 0, bai, idoX, idoY);
var rct:Rectangle = new Rectangle(
0, 0, Math.min(image.width, image.height),
Math.min(image.width, image.height));
bmd.draw(image, mat, null ,null, rct, false);
var col:uint = Functions.getAvgColor(bmd, 0, 0,
bmd.width, bmd.height);
redValue = col >> 16 & 0x0000FF;
greenValue = col >> 8 & 0x0000FF;
blueValue = col & 0x0000FF;
bmp = new Bitmap(bmd);
dispatchEvent(new TheEvent(TheEvent.HAS_LOADED, true));
//trace(bmp.width+ " " + bmp.height);
} catch (err:TypeError) {
trace("Error " + err.message);
}
}
public function onImageErrorLoaded(ev:IOErrorEvent) :void {
try {
dispatchEvent(new TheEvent(TheEvent.HAS_LOADED, false));
} catch (err:TypeError) {
trace("Error " + err.message);
}
}
public function getBitmap() :Bitmap {
return bmp;
}
}
import flash.events.Event;
class TheEvent extends Event {
public var flag:Boolean = false;
public static const HAS_LOADED:String = "hasLoaded";
function TheEvent(type:String, f:Boolean = false,
bubbles:Boolean = false,
cancelable:Boolean = false) {
flag = f;
super(type, bubbles, cancelable);
}
}
import flash.display.Sprite;
import flash.text.TextFormatAlign;
class Functions {
public static function getAvgColor(bmd:BitmapData,
xx:Number, yy:Number,
w:Number, h:Number) :uint {
var rrr:uint = 0;
var ggg:uint = 0;
var bbb:uint = 0;
for (var y:Number = yy; y < yy+h; ++y) {
for (var x:Number = xx; x < xx + w; ++x) {
var col:uint = bmd.getPixel(x, y);
rrr += 0xFF & col >> 16;
ggg += 0xFF & col >> 8;
bbb += 0xFF & col >> 0;
}
}
rrr /= w*h;
ggg /= w*h;
bbb /= w*h;
return int(rrr) << 16 | int(ggg) << 8| int(bbb);
}
}