Asciify – Actionscript 3 (as3) Ascii Art class

actionscript 3, ascii art, BitmapData, classes

There are trends on the web (as in real world) that last days or weeks and there are things that became a classic form of expression of the geek culture and are still interesting to explore after 20+ years.

Ascii Art is one of these things. If you don’t know what ascii art is you’re probably reading the wrong blog, however for the one or two that doesn’t know about it, here you can learn more about it: Ascii art on wikipedia.

I always had in mind the idea to create an actionscript class to render ascii art from pictures and now with as3 this is going to be possible at decent speed.

My class is called Asciify and it can actually “ascii-fy” every DisplayObject instance on the display list.

Usage is very simple and it’s actually REALLY fast.
Didn’t think AVM2 could asciify a video in real time but I was wrong. You cannot go further certain resolutions but if you stay on small videos with decent detail 30fps are guaranteed.

This is the constructor method:

public function Asciify(targetClip:DisplayObject, tformat:TextFormat, pixelSize:Number=8, negative:Boolean=false) {

and this is a sample usage:

var asciifyInstance:Asciify=new Asciify(picture, textFormat, 16);
addChild(asciifyInstance);

Demos & download

See a working demo here:
Asciify class test demo 1
Pictures demo

Another demo applied to a video (see original video here)… this demo uses a glow effect too that make you loose a couple o fps but I couldn’t resist:

Asciify class test demo 2
Video demo

You can offcourse apply it to an animated movieclip or anything else.
In this demos I use ProggyCleanTT font, but you can use any monospaced font that must be imported into the library and have a linkage (in this case I gave it “Font1″ linkage name).
Then just play a little with size, leading and kerning of the textformat to achive the desired effect.

Here is the class:

Asciify class download

Just extract it to [your custom classes folder]/com/oaxoa/fx/

Here is the code for the video demo:

import fl.controls.Button;
import flash.events.Event;
import flash.text.TextFormat;
import flash.filters.GlowFilter;
import fl.controls.CheckBox;
import com.oaxoa.fx.Asciify;
import com.oaxoa.components.FrameRater;

var glow:GlowFilter=new GlowFilter(0xffff00);

/*******************************************/

// setup the TextFormat object to use
var font:Font=new Font1();
var textFormat:TextFormat=new TextFormat();
textFormat.font=font.fontName;
textFormat.size=16;
textFormat.leading=-9;
textFormat.color=0xffff00;

// create an istance of the class and add a nice glow filter
var asciifyInstance:Asciify=new Asciify(video, textFormat, 6);
asciifyInstance.y=30;
asciifyInstance.filters=[glow];
addChild(asciifyInstance);

// update asciifyInstance at every frame
addEventListener(Event.ENTER_FRAME, onframe);

function onframe(event:Event):void {
	asciifyInstance.render();
}

/*******************************************/

// just add some interface for the demo
// you don't really need stuff below this line

var interfaceFormat:TextFormat=new TextFormat();
interfaceFormat.color=0xffffff;
interfaceFormat.size=12;

var cb:CheckBox=new CheckBox();
cb.label="Glow active";
cb.y=4;
cb.x=260;
cb.setStyle("textFormat", interfaceFormat);
cb.selected=true;
addChild(cb);

cb.addEventListener(Event.CHANGE, oncb);

function oncb(event:Event):void {
	cb.selected ? asciifyInstance.filters=[glow] : asciifyInstance.filters=[];
}

var button:Button=new Button();
button.label="Copy frame to clipboard";
button.y=4;
button.x=70;
button.width=170;
button.setStyle("textFormat", interfaceFormat);
addChild(button);

button.addEventListener(MouseEvent.CLICK, onclick);

function onclick(event:MouseEvent):void {
	asciifyInstance.copyContentsToClipboard();
}

var fr:FrameRater=new FrameRater(0xffffff);
fr.x=10;
fr.y=4;
addChild(fr);
52 Comments

33 Comments

  1. Fardeen  •  Mar 4, 2008 @11:17 pm

    Great !

  2. Mczaicki  •  Mar 5, 2008 @11:05 pm

    Gooooood Job!
    Thanks!

  3. jvc  •  Mar 9, 2008 @7:26 am

    very cool – one question

    is there a reason you create the bitmapdata in the render function instead of the constructor? I would think putting it in the constructor would use less memory.

  4. Pierluigi Pesenti  •  Mar 9, 2008 @10:06 am

    The reason was that I initially wanted the class being able to draw target clips that could change size runtime, like a movieclip, so I needed to recreate the bitmap at every frame.

    Then I realized this was quite unuseful and fixed the target size in the constructor method but forgot to move the bitmap creation code.

    EDIT:
    —————

    There was another reason I forgot… movieclips with transparent background. If you only apply a draw method at every frame on a movieclip containing a bouncing ball or some moving element, the draw method doesn’t draw the trasnparency so what you get is a tail of the moving element. So when you render you have to clean the bitmapdata and have two options:

    - with fillrect (with all the transparency problems and 32 bit colors to manage and sample):

    - or simply recreate the bitmapData (that is better so you don’t need to specify a bg color).
    These problems just applies when you have a movieclip containing moving object with no bg at all.

    However I profiled the memory usage and fps for the first and the second option, and the results are almost identical. A little less memory usage with the second option.

    p.s.: I just reinitialize the _bd var… I don’t create a new bitmapdata var every frame, so it shouldn’t have memory issues.

  5. jvc  •  Mar 9, 2008 @12:05 pm

    yeah, I see your reasoning with the transparency. i just noticed it when I was trying to reuse the bitmapdata in another class to create a thumb window of the video being processed. It would work for the first frame but the reference was lost after that. Moving it to the constructor solved that.

    The other reason I was asking was that I wasn’t sure if reinitializing left the old bitmapdata floating if you didn’t use BitmapData.dispose. Thanks for profiling it

  6. Pierluigi Pesenti  •  Mar 9, 2008 @12:12 pm

    The var _bd is a class variable so the reference to it should be always present in every function.
    For the same reason if you reinitialize it at every frame you are not creating a new bitmapdata, just updating the same one.

  7. jvc  •  Mar 9, 2008 @8:21 pm

    Here is the code I was using to create the thumb. I don’t know if the blog will let me post code in the comments so I linked my URI to a text file if it gets posted incorrectly.

    addEventListener(Event.ENTER_FRAME, onframe);

    // Asciify class is modified so _bd is public
    // this works with _bd created in constructor
    // if _bd is reinitialized in render thumb is unable to update
    //
    var thumb:Bitmap = new Bitmap(asciifyInstance._bd);
    addChild(thumb);
    thumb.width=150;
    thumb.scaleY = thumb.scaleX;

  8. Pierluigi Pesenti  •  Mar 10, 2008 @9:31 am

    Yes I got the point, even if the class was not thought to have a public thumbnail. You have the target clip on the root or where you placed it… you can just create yourself another bitmapdata and use it for the thumb.

    You even know the pixelSize parameter (multiplier) because you pass it to the asciify instance… etc.

    You could be much more free without using the class bitmapdata at the cost of a little extra memory usage.
    You could even do a resizable or filtered thumbnail, which you will never be able to do reusing the internal _bd instance.

    Or you could simply set targetClip.visible=true (which overrides the opposite rule in the asciify class and set targetClip.scaleX=targetClip.scaleY=1/pixelSize to resize it… and you have done the thumb. (even if scaling clips give never as smoother results as using bitmapdatas).

    =)

  9. John Allen  •  Mar 14, 2008 @5:31 pm

    THAT IS PHAT!

  10. well  •  Mar 14, 2008 @6:34 pm

    the movie doesn’t work for me in Flash 9 on FF2

  11. Simon  •  Mar 16, 2008 @6:47 pm

    Great idea and implementation. Thumbs up!

    … reminds my of one of my unfinished projects: http://kolchose.org/simon/excelart/

  12. Milan Cole  •  Mar 17, 2008 @6:44 am

    What a fun idea… it used to take hours and hours to make this stuff.

  13. Vyper  •  Mar 19, 2008 @8:09 pm

    This is absolutely brilliant!!! Why has no one done this before!!! Looking at the class, I can see quite a few places where the code could be streamlined but as it is this is great. Keep up the good work!

  14. Zu  •  Jun 18, 2008 @8:21 am

    WOW – real nice! Thanks for sharing the code :D

  15. Eugene  •  Jul 9, 2008 @11:47 am

    Hi

    just wanted you to know that i created ASCII Screensaver based on your idea of representing images in ASCII style.

    http://www.inspirit.ru/exchange/ascii_saver/

    thanx for sharing and keep cool!

  16. Tim  •  Feb 27, 2009 @5:24 am

    This is very exciting. Thank you for sharing your code. I am a relative newbie to AS3. I’ve spent several nights trying to get Asciify to work for a video clip. Can anyone share a simple .fla and support .as that has this working? Thanks in advance.

    Tim

  17. secret007  •  Jun 23, 2009 @11:55 am

    Hi,

    I have a movieclip on the stage name pics, and in the document i wrote this code..

    package
    {

    import com.oaxoa.fx.Asciify;
    import flash.text.*;
    import flash.display.*;

    public class Main extends MovieClip
    {
    var textFormat:TextFormat = new TextFormat();
    var converter:Asciify;

    public function Main()
    {

    textFormat.font= “Arial”;
    textFormat.size=15;
    textFormat.color=0xFF0000;
    converter = new Asciify(pics,textFormat,20);
    converter.x = 300;
    converter.y = 300;
    addChild(converter);
    converter.render();

    }

    }

    }

    But i didn’t see anything coverted perhaps blank stage ?? why is that help me plz i want to use this class in my project . thanx in advance..

  18. baek  •  Jul 16, 2009 @7:37 pm

    Very cool, though i wonder if the stage or container size has to be the same as the image size ?

  19. Ricardo  •  Oct 3, 2009 @2:32 pm

    Same code as secret007 … not working :( … what´s wrong ???

  20. Ricardo  •  Oct 3, 2009 @3:11 pm

    Oh got it ! Font MUST be imported from library … This is a great work, but I´m getting a lot of work to “fine tune” my Asciify instance. As an example, my initial images stretches too much in vertical axis, then a have to change the leading of the textformat … I think the code need improvements . but it´s a great job, no doubt :)

  21. Facebook Applications  •  Oct 21, 2009 @10:39 am

    Same code as secret007 … not working. I am facing this problem in AS3

  22. It’s great. I really like the way you render ascii art from pictures and now with as3. Keep it up :)

  23. secret007  •  Jan 5, 2010 @5:20 pm

    Anyone here who is saying “its great” can answer my comments above i have code as sample file but it shows me nothing .. ?? perhaps other guys also post that same problem with them …

  24. Pierluigi Pesenti  •  Jan 5, 2010 @6:06 pm

    Hey secret007. 6 months and still has this problem? You really should want to implement this ;)
    However sorry for not noticing your question before, here is the key.

    This class only works with EMBEDDED fonts.

    So, create a new font in the library, give it a linkage (class) name and add something like this:

    var font:Font=new myLibraryFontLinkageName();
    textFormat.font=font.fontName;

    textFormat.size=15;
    textFormat.color=0xFF0000;
    converter=new Asciify(pics,textFormat,8);
    converter.x=0;
    converter.y=0;
    addChild(converter);
    converter.render();

    Then remember to lower the leading of the textformat to see the effect correctly. To answer to another previous comment about leading and fine tuning the reason about a missing default leading is that the leading you need for a good effect differs from font to font. And personally I think the cool thing of this class is that you can simply pass whatever TextFormat you want, so the fine tuning is just prepare it.

    Let me know if you need some more halp. Happy new year.

  25. secret007  •  Jan 6, 2010 @7:14 am

    Ya, actually 6 months ago i found this useful class but not working due to font embedding so i left my comments and didn’t check back after a long time now i want to do some extra stuff other than facebook apps :) so this is cool class i want to play around, anyway thanx for the answer , cheers !!

  26. Rogue  •  Apr 25, 2010 @10:31 am

    Hi same code as 007 in my .as + suggested mod, a movieclip named pics with a few shapes inside it, on my timeline. Font embedded as “font1″ and font specified as courier. Asciify.as in [custom class folder] \com\oaxoa\fx\Asciify.as

    Not getting any errors, just see the blocks of the “pics” movieclip. Any ideas? would really like this to work!

  27. Pierluigi Pesenti  •  Apr 25, 2010 @1:47 pm

    Hi Rogue, it’s not that clear. Could you post some code?

  28. Harry Hilders  •  May 9, 2010 @2:03 pm

    Ascii art is truly amazing imo. An ASCII art class is a cool idea, art class 21th century style :D

  29. Dejan  •  Dec 5, 2010 @11:23 pm

    It gives me an 1137 error at:
    var asciifyInstance:Asciify=new Asciify(pic, textFormat, 16);

    pic is a instance name of a mc

  30. gyro  •  Jan 15, 2011 @9:48 pm

    Sweet!!

  31. woodlgz  •  May 6, 2011 @4:45 am

    hey man,greate work..
    but i just ran into a problem,wonder if you can help me solve this out ..
    my test code is as following:

    import flash.text.TextFormat;

    var picture_data:pp =new pp(64,64);
    var bm:Bitmap =new Bitmap(picture_data);
    var font:Font = new font1(); //i use arial as embeded font
    var textFormat:TextFormat=new TextFormat();
    textFormat.font=font.fontName;
    textFormat.size=16;
    textFormat.leading=-8;
    //i tried changing the leading for serval times,but seemingly no help
    textFormat.color=0x000000;

    var asciifyInstance:Asciify=new Asciify(bm, textFormat, 16);
    addChild(asciifyInstance);

    my problem is that the outcome ascii image was not pretty like what i had expected (i could not distinguish the outlines of it).the way i see it,it was a mess of ascii characters and not related to the original image..

    maybe i did somthing wrong.
    hope you could help me.thanks in advance.

  32. Pierluigi Pesenti  •  May 6, 2011 @8:15 am

    You are using Arial font which is a proportional font so the “i” is much thinner than the “w”, since you dont know which char Asciify is creating to resemble that pixel you dont know the width. So you have to use a non-proportional or monospaced font as Courier new or Consolas etc. and everything will go ok.

    Cya

  33. woodlgz  •  May 8, 2011 @4:25 am

    appreciate your reply,Pierluigi.
    so i think i figure it out.
    again,that’s a greate work.
    keep cool,man.

19 Trackbacks

Leave a Reply

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>