手描きアニメ風?線文字
上部テキスト入力エリアの文を手描きアニメ風の文字にします。
この文字は上部のテキストフィールドで変更可能です。
フォントから線描への変換は、テキストフィールド→ビットマップデータ→ドット検出→線描領域決定という流れで行っています。
フォントサイズとかテキストフィールドの設定を変えると文字の出方も変化します
ビットマップをスキャンする際の平方ピクセル域の値でも変わります。
線はスプライン曲線にしています。
※スプライン曲線のコードは[http://l00oo.oo00l.com/blog/archives/category/actionscript]のものを使わさせて頂いてます
これa*とかの経路探索アルゴリズムを応用して線を描くようにしたらもっと実用的な表現になるとおもうけどどうだろ
/**
* Copyright lagash ( http://wonderfl.net/user/lagash )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rqq8
*/
// 上部テキスト入力エリアの文を手描きアニメ風の文字にします。
// この文字は変更可能です。
package{
import flash.display.*;
import flash.events.*;
import flash.text.TextField;
import flash.external.ExternalInterface;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.net.*;
import flash.geom.*;
import flash.filters.*;
import flash.utils.*;
import flash.text.Font;
import caurina.transitions.Tweener;
import caurina.transitions.properties.*;
FilterShortcuts.init();
ColorShortcuts.init();
public class Main extends Sprite{
var date:Date;
var input_text:TextField;
var date_text:TextField;
var datetext_format:TextFormat;
var datetext_bitmapdata:BitmapData;
var display_bitmapdata:BitmapData;
var clear_bmd:BitmapData;
public function Main() {
var fonts:Array = Font.enumerateFonts(false);
fonts.forEach(function(item, arr, index) { trace(item.fontName) } );
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init() {
stage.addChild(this);
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
datetext_format = new TextFormat();
with (datetext_format) {
color = 0x000000;
size = 21;
bold = true;
kerning = true;
}
date_text = new TextField();
with (date_text) {
autoSize = TextFieldAutoSize.CENTER;
defaultTextFormat = datetext_format;
wordWrap = true;
width = 100;
}
input_text = new TextField();
var tmp_format = new TextFormat();
tmp_format.color = 0xffffff;
with (input_text) {
border = true;
borderColor = 0xffffff;
defaultTextFormat = tmp_format;
type = TextFieldType.INPUT;
x = 10;
y = 10;
width = 250;
height = 20;
multiline = false;
text = "手描き アニメ風線文字";
}
display_bitmapdata = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00000000);
clear_bmd = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00000000);
var timer:Timer = new Timer(150,0);
timer.addEventListener(TimerEvent.TIMER, enterframeHndlr);
timer.start();
//addEventListener(Event.ENTER_FRAME, enterframeHndlr);
addChild(new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000), "auto", true));
addChild(new Bitmap(display_bitmapdata, "auto", true));
addChild(input_text);
for (var i = 0; i < cells * cells; i++) zeroStr += "0";
}
var cells:uint = 3;//←ここ変えると文字の形も変わる(2~5くらい)
var zeroStr = "";
private function enterframeHndlr(e:Event) {
date = new Date();
var tmpString = String("00" + date.getHours()).substr( -2, 2) + ":" + String("00" + date.getMinutes()).substr( -2, 2) + ":" + String("00" + date.getSeconds()).substr( -2, 2);// + "." + String("000" + date.getMilliseconds()).substr( -3, 1);
tmpString = input_text.text;
date_text.text = tmpString;
date_text.text=tmpString.substr(0,(int(date.getSeconds())%tmpString.length)+1);
datetext_bitmapdata = new BitmapData(date_text.textWidth+(date_text.textWidth%cells), date_text.textHeight+(date_text.textHeight%cells), true, 0x00000000);
datetext_bitmapdata.draw(date_text);
var cell_scaleA = datetext_bitmapdata.width / stage.stageWidth;
var cell_scaleB = stage.stageWidth / datetext_bitmapdata.width;
display_bitmapdata.copyPixels(clear_bmd,new Rectangle(0,0,clear_bmd.width,clear_bmd.height),new Point(0,0));
display_bitmapdata.lock();
var tmpVV = new Vector.<Point>();
var tmpShape:Shape = new Shape();
for (var yy = 0; yy < datetext_bitmapdata.height / cells; yy++) {
for (var xx = 0; xx < datetext_bitmapdata.width / cells; xx++) {
var tmpcells = 0;
for (var j = 0; j < cells; j++) for (var i = 0; i < cells; i++) {
var addvalue=(datetext_bitmapdata.getPixel32(xx * cells + i, yy * cells + j) > 0x55000000)?1:0;
tmpcells = tmpcells << 1;
tmpcells += addvalue;
}
var tmpV = new Vector.<Point>();
tmpShape.graphics.clear();
var drawcell:String = String(zeroStr + tmpcells.toString(2)).substr( -cells*cells, cells*cells);
for (i = 0; i < cells*cells; i++) {
if (drawcell.substr(i, 1) == "1") {
for (j = 0; j < 5-((date_text.text.length<3)?date_text.text.length:3); j++) {
tmpV.push(new Point(Math.random() * cell_scaleB * 1.5 + (i % cells) * cell_scaleB, Math.random() * cell_scaleB * 1.5 + int(i / cells) * cell_scaleB));
}
}
}
if (tmpV.length > 0) {
tmpV = shuffle_new(tmpV);
drawSpline(tmpV,tmpShape)
}
display_bitmapdata.draw(tmpShape, new Matrix( 1.1, 0, 0, 1.1, xx * (cells * cell_scaleB * .9), yy * (cells * cell_scaleB * .9)-15) );
}
}
display_bitmapdata.unlock();
}
public function shuffle_new(v:Vector.<Point>):Vector.<Point> {
for (var j:int, t:Point, i:int = v.length, a:Vector.<Point> = v.slice(); i; j = Math.random() * i, t = a[--i], a[i] = a[j], a[j] = t);return a;
}
private function drawSpline(v:Vector.<Point>,g):void{
if(v.length<2) return;
v.splice(0,0,v[0]);
v.push(v[v.length-1]);
var numSegments:uint = 5;//曲線分割数(補完する数)
for(var i:uint=0; i<v.length-3; i++){
var p0:Point = v[i];
var p1:Point = v[i+1];
var p2:Point = v[i+2];
var p3:Point = v[i+3];
splineTo(p0, p1, p2, p3, numSegments,g);
}
}
private function splineTo(p0:Point, p1:Point, p2:Point, p3:Point, numSegments:uint, g):void {
var d:Date = new Date();
var col = 0xaaaaaa;//d.getTime();
g.graphics.lineStyle(.5, col,.5);
g.graphics.moveTo(p1.x, p1.y);
for(var i:uint=0; i<numSegments; i++){
var t:Number = (i+1)/numSegments;
g.graphics.lineTo(
catmullRom(p0.x, p1.x, p2.x, p3.x, t),catmullRom(p0.y, p1.y, p2.y, p3.y, t)
);
}
}
private function catmullRom(p0:Number,p1:Number,p2:Number,p3:Number,t:Number):Number{
var v0:Number = (p2 - p0) * 0.5;
var v1:Number = (p3 - p1) * 0.5;
return (2*p1 - 2*p2 + v0 + v1)*t*t*t +
(-3*p1 + 3*p2 - 2*v0 - v1)*t*t + v0*t + p1;
}
}
}
class Bugfix {
function Bugfix(){}
}