ASCII Art Generation

13

1

Task

Write a program or function that takes an image of width w and height h, and two integers a <= w/2 and b <= h/2, and outputs an ascii art representation of the image, with the dimensions a x b.

The ascii art should be generated through the following steps (or another process with the same output):

  1. Resize the w x h image to 2a x 2b. The color of the pixel (x, y) in the resized image should be equal to the average of the colors of all the pixels from the original image inside the rectangle with the following corners:

    (floor[x * w/2a], floor[y * h/2b])
    (ceil[(x+1) * w/2a], ceil[(y+1) * h/2b])
    
  2. The resized image should be desaturated by taking the average of the red, green, and blue components of the color, and setting each component to this average.

  3. A character should be outputted for each 2x2 block of pixels, following the rules below:

    • Let e = 3 - floor[color/64], where color refers to the red component of the color of the top-left pixel (in the range 0..255). Let f, g, and h refer to this value, but for the top-right, bottom-left, and bottom-right pixels respectively.
    • Let z be the average of e, f, g, h.
    • Output the character corresponding to the following (white represents a pixel where 3 - floor[color/64] is zero, and grey represents nonzero).
    • All pixels are zero = Output a space ()
    • Top left pixel is nonzero or Top right pixel is nonzero = Output " if e (or f) >= 2 and ' otherwise.
    • Bottom left pixel is nonzero or Bottom right pixel is nonzero = Output , if g (or h) >= 2 and . otherwise.
    • Top pixels nonzero or Bottom pixels nonzero = Output -
    • Left pixels nonzero or Right pixels nonzero = Output ;
    • Top left, bottom right pixels nonzero = Output \
    • Top right, bottom left pixels nonzero = Output /
    • Top left pixel zero = Output J
    • Top right pixel zero = Output L
    • Bottom left pixel zero = Output 7
    • Bottom right pixel zero = Output P
    • All nonzero
      • z = 1: output *.
      • z = 2: output C.
      • z = 3: output #.

Other notes: All averages taken in the above steps should use integer division (i.e. rounding towards 0).

You may use a library to read images, but libraries may not be used for the resizing and desaturation steps.

Input

Your program will take in three pieces of data:

  • An image. This image may be in any format of your choice (e.g. PNG, PPM)
  • The width of the ascii art (in number of characters)
  • The height of the ascii art (in number of characters)

Input may be read through STDIN, passed as an command-line argument, stored as a variable, etc.

Output

Your program will output the ascii art generated from the image and through the process described above. Each line must be the same width (the width passed as input), and no extra spaces may be added or removed. The last line may have a trailing newline, but this is not mandatory. Blank lines (lines with only spaces) must not be omitted.

Examples

All images were taken from Wikipedia and released into public domain. Your program is expected to work for all images and valid inputs.

Picture of lemons

Width = 52, Height = 25:


            .--***--                   ----.        
          -**********L.--          .--7----P-       
        .J****************.       .*********\.      
       ,******************L      \J**********'.     
      -********************.     J***********L/     
     J*********************;   ./*************.L    
    ;*********************P    J**************;7;   
   .**********************'   .***************;;*   
   ;**********************    ;***************;J*.  
   ***********************    *******P********'**;  
   C*********************C    *******P;*******.**;  
   C**********************    J***************;**;  
   C*********************;    ****************.**;  
   **********************'    ***************P;**   
  J*********************P     ***************/***   
 .**********************      7*************'J**;   
 ;********************C"      'P***********PJ***'   
 "7******************C"        '**********P.**C;    
     '*C*************'         ;*********-J**CP     
      '*C**********P            7**7**P/-****P      
        -*CCCCC*P-               '7********P'       
          '---                       '---'          

Width: 70, Height: 3:

         ---------------------------.        .----------------        
    J*****************************P     -J********************/J**;   
  ----------*********P---------'          ----------------------'        

Potatoes

Width: 50, Height: 25:





        .J---                                     
      .J*P                     ---J*L--.          
     J***'                L -J***********-        
    J****                ;****************L       
   ;*****'             .J********************     
   J****7              ************************P  
   **CC*    ;         .*********LJ***********P-   
   **C*P    '         J**********************-    
   7*C*L              **********************;     
   J*C**;             **********************;     
  JC**C**.     ;      ;********CCC*C**CCCC**      
  "7*****L     .       7*****CCCCCC****CC**'      
     -*****. -J         -**C*C*CC******CC*'       
      ;**CC***;          '**CCC*****CCCC*;        
       '-****-             --***CCCCC***-         
                               '------'           




Clipart sample

Width: 26, Height: 17:

    -                  ,L 
  J-**L               .C# 
 J';*P-L             ,C#" 
.P  P  7.           JC7P  
;; * J ;;          ,C'C;  
J; C C ;L          C" #   
*L 7-P ;*         ;P  C   
7CL***J*P         C'  #   
'7#C*C#P'        ;P JC#C- 
 J#CCC#L      .JC#CJCC##C;
;#-   -#,     CCC#CCCCCCCC
;*.- -.C;    ;CCCCCCCCCCCC
;****J**L    ;CCCCCCCCCCCC
;*******;    'CCCCCCCCCCCP
'*******'     CCCCCCCCCCC'
 '*P-7*'      "CCCCP '--  
               '---       

This is , so the shortest answer wins.

es1024

Posted 2015-05-04T01:12:59.877

Reputation: 8 953

2thats quiet crippling challenge .... .... – Abr001am – 2015-05-04T01:55:36.457

When you say image input, do you mean a filename? Or the actual image data? – sirpercival – 2015-05-05T10:37:52.440

@sirpercival either is fine – es1024 – 2015-05-05T13:51:18.050

Answers

6

JavaScript 752,701

function Z(I,a,b){
    var C=document.createElement('canvas')
    var W=C.width=I.width,H=C.height=I.height,X=C.getContext('2d')
    X.drawImage(I,0,0)
    a*=2,b*=2,W/=a,H/=b
    for(var o=a*b,x=0,y=0,T="",S=[],V;--o;){
        var A=~~(x*W),B=~~(y*H)
        var d=X.getImageData(A,B,(((x+1)*W)<<0)-A,(((y+1)*H)<<0)-B).data
        for(var i=0,p=0,L=d.length;i<L;i+=4)p+=(d[i]+d[i+1]+d[i+2])/3
        p/=L/4
        S[x]=3-(p>>6)
        if(x%2&&y%2){
            var e=V[x-1],f=V[x],g=S[x-1],h=S[x],z=(e+f+g+h)>>2,B=0,c
            B|=e>0?8:0,B|=f>0?4:0,B|=g>0?2:0,B|=h>0?1:0
            c=" ..-';\\J'/;L-7P*".charAt(B)
            c=c=="'"&&(e>1||f>1)?'"':c
            c=c=="."&&(g>1||h>1)?",":c
            T+=c=="*"?z>2?"#":z>1?"C":c:c
        }
        if(++x==a)x=0,y++,V=S,T+=y%2?"\n":"",S=[]
    }
    return T
}

Examples:

var items = {
    lemons: {w:52, h:25},
    spuds: {w:50, h:25},
    tux: {w:26, h:17}
};

for(var k in items) {
    var val = items[k];
    var img = new Image();
    img.onload = function() {
        console.log(Z(this,this.w,this.h));
    }
    img.src=k+'.png';
    img.w = val.w;
    img.h = val.h;
}

Lemons:

            .--JJL--                   .---.        
          -**********-.--          .--7----P-       
        .J***************L.       .*********\.      
       .******************L      \J**********'.     
      .********************.     ;***********L/     
     J*********************;   ./*************.L    
    ,*********************P    -**************;7;   
    **********************'   .***************;;*   
   ;**********************    ;***************;;*.  
   ***********************    *******PP*******'J*;  
   ***********************    *******P;*******.**;  
   ***************7*******    J******;J*******;**;  
   **********************;    ****************.**;  
   **********************'    ***************P;**'  
  J*********************P     ***************/***   
 .**********************      7*************'J**P   
 ;*********************"      '\***********PJ***'   
 "7*******************"        '**********P.***;    
     '***************'         ;*********-J***P     
      '************P'           7*-7**P/-****P      
        -*******P-               '7********P'       
          '---                       -----          

Spuds:

         J---                                     
      .J*P                     .---*L--.          
     J***'                L -J***********-        
    J****                ;****************L       
   ;*****'             .J******************L*     
   J***L7              ************************P  
   **CC*    .         .*********L'***********P-   
   **C*P    '         J**********************-    
   7*C*L              **********************;     
   J*C**.             **********************;     
  JC**C**      .      7********CCC****CCCC**      
  "7*****L     .       7*****CCCCCC****CC**'      
     -****L. .J         -**C*C**C*******C*'       
      ;**CC***;          '**CCC*****CCCC*;        
       '-****-             --**CCCCCC***-         
                               '------'           

Tux:

                       ,L 
  --**L                C#'
 J';*P-L             ,C#" 
 P  7  7.           ,C7P  
;; J J ;;          ,C"C;  
;; C C  L          C" C   
*L 7-P ;*         ;P  #   
;CL***J**         C'  #   
'7#C*C#C'        ,P JC#C- 
 J#CCC#L      .JCCLJCC##C,
.#-   -#,     JCC#CCCCCCCC
;C.- -.*;    .CCCCCCCCCCCC
;L***J**C    ;CCCCCCCCCCCC
;*******P    'CCCCCCCCCCCP
'*******"     CCCCCCCCCCC'
 '*P-7*'      "CCCCP "--  
               '---       

wolfhammer

Posted 2015-05-04T01:12:59.877

Reputation: 1 219

2

IDL 8.3, 588 597 588 bytes

I'm getting slightly different values than you are, I'm not sure why... I did integer division for everything. But it otherwise works splendidly... are these results acceptable? Much better now, though still not identical for some reason.

pro c,m,a,b
e=2*a
f=2*b
s=size(m,/d)/[1.,e,f]
g=intarr(3,e,f)
u=floor([0:e-1]*s[1])
x=ceil([1:e]*s[1])-1
v=floor([0:f-1]*s[2])
y=ceil([1:f]*s[2])-1
n=(x-u)#(y-v)
for k=0,2 do for i=0,e-1 do for j=0,f-1 do g[k,i,f-j-1]=total(m[k,u[i]:x[i],v[j]:y[j]],/i)/n[i,j]
g=3-total(g/192,1,/i)
t=intarr(4,a,b)
for i=0,3 do t[i,*,*]=g[rebin([0:a-1]*2+i mod 2,a,b),rebin(2#[0:b-1]+i/2,a,b)]
w=total((t ne 0)*rebin(2^[0:3],4,a,b),1,/i)
for i=0,3 do w+=(w eq 2^i)*(t ge 2)[i,*,*]*(18-2^i+i/2)
w+=(w eq 15)*(total(t,1,/i)/4-1)
print,strmid(' '+"''"+'-.;/P.\;7-LJ*C#",',w[*],1),f='('+strtrim(a,2)+'A1)'
end

Test cases:

IDL> c,read_png('lemons.png'),52,25


            .-J***L-.                 .----.        
          -**********L.--          .J-*LJJ**-       
        .J****************.       J*********J.      
       ,*******************      /J**********7.     
      J********************.    ;J***********L*     
     J*********************;   .\*************/L    
    ;*********************P    ***************;*;   
   .C*********************'   ;***************;**   
   J**********************    J***************;**.  
   ***********************    ****************'**;  
   C*********************C    ********J*******;**;  
   C**********************    *******************;  
   C*********************P   ;****************7**;  
  .**********************'    ***************PJ**'  
  J*********************P     ***************\***   
 .**********************      7*************'***P   
 ;********************C"      ;************PJ**C'   
 "7******************C"        ***********PJ***;    
     '*C*************"         ;*********7J**CP     
      '*C*********CP'           7*****P\-***CP      
        -*CCCCC*P-               '7********P"       
          '---                       -----          

IDL> c,read_png('lemons.png'),70,3
        --------J**********L--------.       .-----------------        
   .J*****************************P'    -*************************;   
  ---------*************P-------         '------7**********P-----  
IDL> c,read_png('potatoes.png'),50,25





         J-"-                                     
      .J*'                     ----JL--           
     -*C*                 * -J***********-        
    J*C*L                ;****************L       
   .*C*-*              .J********************     
   J*CC;-              ********************C**CP  
   *CC#*    7         .**********************P-   
   *CCC;    '         J**********************-    
   7CCCL              **********************;     
   JCCC*.             ****C*C*****CCCC*CC***;     
  ;C*CCCL      .      ;***CC*CCCCCCCCCCCCC**      
  "--*CCC;             7***CCCCCCCCCCCCCCC*'      
     '7CC*L.  .         -*CCCCCCCCCCCCCCCP'       
       7CCCCC*'           7CC#CCCCCCC###P         
        '-7P-'             '-7CC######C-          
                                 '-'              




IDL> c,read_png('penguin.png'),26,17
                       ,L 
      ,                C# 
 "  #- ;             ,##" 
 ;  -  ;            ,#7;  
;" - - ";          ,#"J"  
;  # #  ;          #" #   
;; .-. ,;         ;;  #   
;#-***-#;         #   #   
 7#C*C#P         ,P -C#C, 
 J##-##L       JCCL-CC#CC,
,#"   "#,     JCC#CCCCCCCL
;L.- -.C;    ,CCCCCCCCCCCC
;***L***;    ;CCCCCCCCCCCC
;*******;     CCCCCCCCCCC;
 *** ***"     CCCCCC7CCCP 
 '*P--*'      "CCCCP "-"  
                --"       

sirpercival

Posted 2015-05-04T01:12:59.877

Reputation: 1 824