├── .gitignore ├── LICENSE ├── README.md ├── ansize.go └── examples ├── pikachu.ansi ├── pikachu.png ├── raichu.ansi └── raichu.png /.gitignore: -------------------------------------------------------------------------------- 1 | ansize 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2013 Jason Chen 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansize 2 | 3 | Converts an image to binary ANSI art like so: 4 | 5 | [![stage-pikachu.png](https://d23f6h5jpj26xu.cloudfront.net/jason_24594515608662_small.png)](http://img.svbtle.com/jason_24594515608662.png) 6 | 7 | Check out the examples folder for some image samples and their corresponding output. Ex. 8 | 9 | cat examples/pikachu.ansi 10 | 11 | I optimized for images with dark backgrounds and used 0's and 1's for the character set but it's pretty easy to customize the code to convert to your liking! The basic strategy of conversion is very simple: 12 | 13 | 1. Shrink image to desired size 14 | 2. For each pixel, find the corresponding color in ANSI's limited color palette 15 | 3. Set the foreground to that color 16 | 4. Print a random 0 or 1 17 | 18 | ## Installation 19 | 20 | go get github.com/jhchen/ansize 21 | 22 | ## Usage 23 | 24 | ansize [width] 25 | 26 | ## Development 27 | 28 | 1. Install go 29 | 2. Set your $GOPATH 30 | 3. Install github.com/nfnt/resize 31 | 4. Clone ansize 32 | 5. Build ansize 33 | 34 | On a Mac with Homebrew the commands are 35 | 36 | brew install go 37 | mkdir /usr/local/lib/go 38 | export GOPATH=/usr/local/lib/go 39 | go get github.com/nfnt/resize 40 | git clone git@github.com:jhchen/ansize.git 41 | go build ansize.go 42 | -------------------------------------------------------------------------------- /ansize.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "image" 7 | "image/color" 8 | _ "image/gif" 9 | _ "image/png" 10 | _ "image/jpeg" 11 | "math/rand" 12 | "os" 13 | "strconv" 14 | "github.com/nfnt/resize" 15 | "time" 16 | ) 17 | 18 | const ( 19 | ANSI_BASIC_BASE int = 16 20 | ANSI_COLOR_SPACE uint32 = 6 21 | ANSI_FOREGROUND string = "38" 22 | ANSI_RESET string = "\x1b[0m" 23 | CHARACTERS string = "01" 24 | DEFAULT_WIDTH int = 100 25 | PROPORTION float32 = 0.46 26 | RGBA_COLOR_SPACE uint32 = 1 << 16 27 | ) 28 | 29 | 30 | func toAnsiCode(c color.Color) (string) { 31 | r, g, b, _ := c.RGBA() 32 | code := int(ANSI_BASIC_BASE + toAnsiSpace(r) * 36 + toAnsiSpace(g) * 6 + toAnsiSpace(b)) 33 | if code == ANSI_BASIC_BASE { 34 | return ANSI_RESET 35 | } 36 | return "\033[" + ANSI_FOREGROUND + ";5;" + strconv.Itoa(code) + "m" 37 | } 38 | 39 | func toAnsiSpace(val uint32) (int) { 40 | return int(float32(ANSI_COLOR_SPACE) * (float32(val) / float32(RGBA_COLOR_SPACE))) 41 | } 42 | 43 | func writeAnsiImage(img image.Image, file *os.File, width int) { 44 | imgW, imgH := float32(img.Bounds().Dx()), float32(img.Bounds().Dy()) 45 | height := float32(width) * (imgH / imgW) * PROPORTION 46 | m := resize.Resize(uint(width), uint(height), img, resize.Lanczos3) 47 | var current, previous string 48 | bounds := m.Bounds() 49 | for y := bounds.Min.Y; y < bounds.Max.Y; y++ { 50 | for x:= bounds.Min.X; x < bounds.Max.X; x++ { 51 | current = toAnsiCode(m.At(x, y)) 52 | if (current != previous) { 53 | fmt.Print(current) 54 | file.WriteString(current) 55 | } 56 | if (ANSI_RESET != current) { 57 | char := string(CHARACTERS[rand.Int()%len(CHARACTERS)]) 58 | fmt.Print(char) 59 | file.WriteString(char) 60 | } else { 61 | fmt.Print(" ") 62 | file.WriteString(" ") 63 | } 64 | } 65 | fmt.Print("\n") 66 | file.WriteString("\n") 67 | } 68 | fmt.Print(ANSI_RESET) 69 | file.WriteString(ANSI_RESET) 70 | } 71 | 72 | 73 | func main() { 74 | rand.Seed(time.Now().UTC().UnixNano()) 75 | if len(os.Args) < 3 { 76 | fmt.Println("Usage: ansize [width]>") 77 | return 78 | } 79 | imageName, outputName := os.Args[1], os.Args[2] 80 | var width int = DEFAULT_WIDTH 81 | if len(os.Args) >= 4 { 82 | var err error 83 | width, err = strconv.Atoi(os.Args[3]) 84 | if err != nil { 85 | fmt.Println("Invalid width " + os.Args[3] + ". Please enter an integer.") 86 | return 87 | } 88 | } 89 | imageFile, err := os.Open(imageName) 90 | if err != nil { 91 | fmt.Println("Could not open image " + imageName) 92 | return 93 | } 94 | outFile, err := os.Create(outputName) 95 | if err != nil { 96 | fmt.Println("Could not open " + outputName + " for writing") 97 | return 98 | } 99 | defer imageFile.Close() 100 | defer outFile.Close() 101 | imageReader := bufio.NewReader(imageFile) 102 | img, _, err := image.Decode(imageReader) 103 | if err != nil { 104 | fmt.Println("Could not decode image") 105 | return 106 | } 107 | 108 | writeAnsiImage(img, outFile, width) 109 | } 110 | -------------------------------------------------------------------------------- /examples/pikachu.ansi: -------------------------------------------------------------------------------- 1 |                                                                                                     2 |                                                                             0101                    3 |                                                                          000001                     4 |                                                                      011010001                      5 |                                                                   00010101111                       6 |                                                                 011000000101                        7 |                                                                101011100101                         8 |                                                              111001101011                           9 |                                                            1101100010000                            10 |        1  1011001                                         010001000101                              11 |    1010001011101101011000110         1000000001001011   110101111000                                12 |        10011011100011111101011000000010001000001100010110100011101          1000                    13 |              001101100001001111101011101100011001001100001111111          0000000000                14 |                   10001100010001011010001010101111010101110011         0010111001010001             15 |                           0001110001111111101000110110101011110      1011101111011110000110         16 |                          001010010100100010111001010000101111000   110110100110101100101111100      17 |                          10  001111010000111101011  010001101110 100010111010110101101101010010     18 |                         1110   0100110110111011     01001001010000100010010110100101101010111       19 |                        0001000110101100010100010111010001011100101001100111001111000001110          20 |                        0001010111010101110111100011001000111100010011111001110011111101             21 |                       10001111010010001000110100011101011010101100000000010110100111                22 |                       10101011001011100100010000101111000000001001111100000000101                   23 |                         100011010011100110011110100100101010001010000011011001101011                24 |                          1111000110010110101101111101001110111000010011000010010011011001           25 |                            1111001001010110100100100011011111111      00011011010010000001010       26 |                               0100001010011110001000000000010001          100111010111010110        27 |                              101010100010101101100001001010001001       0110101111110001            28 |                              1000010011011010001111111001001111100    0111101011011                 29 |                              10010111011111010111001010100001001000  0100111110101                  30 |                             1010101101101011100110011001010100111101    000100100011010             31 |                             10101100110111010000011100010110001111110        100000011101           32 |                            000110010000001001001001111000000001001000      111101100111             33 |                            1010010100010011000101111111011111100000000   0000011110                 34 |                           00000110100010011100100100110111000101100001 00100001                     35 |                           0001101111010011100111001011000010101110100000110                         36 |                           100000101010001111111011101011001110010011000                             37 |                           11101111001111100001011101000010001000011011                              38 |                            111101001110001100111101101111011010111010                               39 |                             1001110000101011001010001100001001011110                                40 |                               0010111000111010110101000000000011001                                 41 |                             10011111011               0111010010100                                 42 |                           10001000000                       01011110                                43 |                           0110111                            0111000                                44 |                                                                01000                                45 |                                                                                                     46 |                                                                                                     47 |  -------------------------------------------------------------------------------- /examples/pikachu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jhchen/ansize/3bb41b2dc6e6e4b217b99c29d868fe8329d211ed/examples/pikachu.png -------------------------------------------------------------------------------- /examples/raichu.ansi: -------------------------------------------------------------------------------- 1 |                                                                                                     2 |                                                                                                     3 |                                                                10100                                4 |                                                            01100110                                 5 |                                                         001011010                                   6 |                                                      10100001100                                    7 |         1                       11100100101        110010101111          011                        8 |         00000111           110110011010001010101 0100110011011            11011                     9 |           10111101010   110010101101111110010110101100101000001             01001                   10 |             100001011111111011011111111010111111001001100111101101           010101                 11 |              1111010101001010001100101110111011001100                         1000011               12 |             01000101011000111010100001010111 111000110                         1011001              13 |            010100   11111100000100101000001010101111011                 1       1111100             14 |                     11  0101100111100110000100100000110                 11100    1000111            15 |                     0001 000010110010000000010101100111                  0101111 01110100           16 |                     011011100010010111110010010101110101                  1011001011100000          17 |                    1101111110101110001001010011100101011                   110000110010001          18 |           11011101000101010010011100001111010110010000011                  0111001001000001         19 |         0001011110101010111101010111110100110011001100001                   111101000101010         20 |          111100110110011001011011100100010110111110101100    011            011001101000000         21 |             110101011100001101110001111000000000010001011101011101          011110111010110         22 |                1000110010010010111001001111100100111000011110111111         000110  0001000         23 |                 11110100101000000010010011010110000101110110000110          11110     10111         24 |                   10000100101110000110100001101011001110101001100          10111       0000         25 |                 10101011100001001001011111101011101011011101100           10011          0          26 |             11101    001110010110001011010011111000000111010            111101                      27 |           111        001110100100000011110110100010100001100 1      00011001                        28 |          01         1110101110001101000001110100110000000100   1110100111                           29 |         01        100001011000101001111110110000010110101100                                        30 |         11      0010111010101101111001001010100001110001010                                         31 |          11001100100011101100111101011011001010010101000011                                         32 |              10000000111101010100000101001100110100001001000                                        33 |                 00111100001110101110110001010110100011000111                                        34 |                 10001101000100000100001011100011100110110010                                        35 |                  1010001111011011101010110110010000101111010                                        36 |                   110111001100101011000100010100100101011111                                        37 |                    0100001110001011000101110100110100111001                                         38 |                       0000000011111101001000100101000011100                                         39 |                              0010 001000011001001010100000                                          40 |                                1         010101100000111                                            41 |                                         11110110110111                                              42 |                                          110011                                                     43 |                                          00101111                                                   44 |                                           110101                                                    45 |                                                                                                     46 |                                                                                                     47 |  -------------------------------------------------------------------------------- /examples/raichu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jhchen/ansize/3bb41b2dc6e6e4b217b99c29d868fe8329d211ed/examples/raichu.png --------------------------------------------------------------------------------