Last active
March 22, 2021 03:34
-
-
Save Sunjammer/cf71dd5f956b6a509bab to your computer and use it in GitHub Desktop.
Naive bitmap to ascii converter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package; | |
| /** | |
| * Mostly stolen from http://www.codeproject.com/Articles/20435/Using-C-To-Generate-ASCII-Art-From-An-Image | |
| * @author Andreas Rønning | |
| */ | |
| private typedef BMD = { | |
| function getPixel(x:Int, y:Int):Int; | |
| var width(default, never):Int; | |
| var height(default, never):Int; | |
| }; | |
| private typedef Vec3D = { x:Float, y:Float, z:Float }; | |
| class BitmapToAscii | |
| { | |
| static var grayVec:Vec3D = { x:0.2126, y:0.7152, z:0.0722 }; | |
| static inline var BLACK = "@"; | |
| static inline var CHARCOAL = "#"; | |
| static inline var DARKGRAY = "8"; | |
| static inline var MEDIUMGRAY = "&"; | |
| static inline var MEDIUM = "o"; | |
| static inline var GRAY = ":"; | |
| static inline var SLATEGRAY = "*"; | |
| static inline var LIGHTGRAY = "."; | |
| static inline var WHITE = " "; | |
| static inline var R = 1 / 255; | |
| static inline function dot(a:Vec3D, b:Vec3D):Float { | |
| return a.x * b.x + a.y * b.y + a.z * b.z; | |
| } | |
| static inline function setFromHex(vec:Vec3D, color:Int) { | |
| vec.x = (color >> 16) * R; | |
| vec.y = (color >> 8 & 0xFF) * R; | |
| vec.z = (color & 0xFF) * R; | |
| } | |
| static inline function desaturate(vec:Vec3D) { | |
| var d = dot(grayVec, vec); | |
| vec.x = vec.y = vec.z = d; | |
| } | |
| static function avgTile(bmd:BMD, ox:Int, oy:Int, width:Int, height:Int):Float { | |
| var out = { x:0.0, y:0.0, z:0.0 }; | |
| var count = 0; | |
| for (x in ox...ox + width) { | |
| for (y in oy...oy + height) { | |
| var c = bmd.getPixel(x, y); | |
| out.x += c >> 16; | |
| out.y += c >> 8 & 0xFF; | |
| out.z += c & 0xFF; | |
| count++; | |
| } | |
| } | |
| var rec = 1 / count; | |
| out.x = out.x * rec * R; | |
| out.y = out.y * rec * R; | |
| out.z = out.z * rec * R; | |
| desaturate(out); | |
| return out.x; | |
| } | |
| static inline function getGrayShade(value:Float):String | |
| { | |
| if (value >= .90) { | |
| return WHITE; | |
| }else if (value >= .78){ | |
| return LIGHTGRAY; | |
| }else if (value >= .70){ | |
| return SLATEGRAY; | |
| }else if (value >= .62){ | |
| return GRAY; | |
| }else if (value >= .50){ | |
| return MEDIUM; | |
| }else if (value >= .39){ | |
| return MEDIUMGRAY; | |
| }else if (value >= .27){ | |
| return DARKGRAY; | |
| }else if (value >= .19){ | |
| return CHARCOAL; | |
| }else{ | |
| return BLACK; | |
| } | |
| } | |
| public static function convert(bmp:BMD, strideX:Int = 8, strideY:Int = 16, invert:Bool = false, highQuality:Bool = true, linebreakchar:String = "\n"):String { | |
| var temp:Vec3D = { x:0.0, y:0.0, z:0.0 }; | |
| var str = ""; | |
| var y = 0; | |
| var v = 0.0; | |
| while (y < bmp.height) { | |
| var x = 0; | |
| while (x < bmp.width) { | |
| if (highQuality) { | |
| v = avgTile(bmp, x, y, strideX, strideY); | |
| }else { | |
| setFromHex(temp, bmp.getPixel(x, y)); | |
| desaturate(temp); | |
| v = temp.x; | |
| } | |
| if (invert) { | |
| str += getGrayShade(1 - v); | |
| }else { | |
| str += getGrayShade(v); | |
| } | |
| x += strideX; | |
| if (x >= bmp.width - 1) { | |
| str += linebreakchar; | |
| } | |
| } | |
| y += strideY; | |
| } | |
| return str; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment