# Average an image

Here is an image:

%%%%%%%%%%%%%
% Hello,    %
%    world! %
%%%%%%%%%%%%%


But it is too confusing for our undersized brains to compute. So we average it like this:

1. Split it into 2 x 2 sections. If the picture ends before a section is complete, imagine that there are spaces there.

2. Average the values of the ASCII characters in each section.

3. Round this average and convert it to an ASCII character.

4. Finally, replace all characters in the section to the average character.

Repeat this for all sections.

So the average of the image above looks like this:

$$>>II99######$$>>II99######
$$##88KKGG####$$##88KKGG####


Your task: Write a program that takes an ASCII image as input and outputs its average.

Note Integers are rounded by function floor(x+0.5) or similar function - in other words, round halves upwards.

• What happens if the width is odd? Commented Apr 8, 2016 at 8:49
• @KennyLau " If the picture ends before a section is complete, imagine that there are spaces there." I think that cover the case when the width is odd ;) Commented Apr 8, 2016 at 9:01
• Can we assume the height will always be even ?
– THC
Commented Apr 8, 2016 at 9:24
• @DenkerAffe No. That would be cheating. :P
– user51533
Commented Apr 8, 2016 at 9:27
• Just to clarify with expected behavior, a 7x7 image would act as an 8x8 image with spaces on the bottom and right edge? Therefore our output would also be 8x8? Commented Apr 8, 2016 at 15:51

# JavaScript (ES6), 159 bytes

document.write("<pre>"+(

// --- Solution ---
s=>s.replace(/./g,(c,i)=>(a=String.fromCharCode([t=0,1,l=s.search
+1,l+1].map(o=>t+=(n=s.charCodeAt(p=i+o-i%l%2-(i/l|0)%2*l))>32?n:32)|t/4+.5))+(++p%l?"":a))
// ----------------

)(%%%%%%%%%%%%%
% Hello,    %
%    world! %
%%%%%%%%%%%%%))

Takes a multiline string as input.

• Running on Firefox, this produces incorrect output. Commented Apr 8, 2016 at 18:49
• @Trebuchette Ah, I misinterpreted the space rule. It's fixed now. Commented Apr 9, 2016 at 0:01

# MATL, 32 30 bytes

2thZCO32XEoYmYocGZy2/Xke2t3$Y"  Input is a 2D char array, with rows separated by ;. Try it online! ### Explanation 2th % push array [2 2] ZC % take input implicitly. Arrange distinct 2x2 blocks as columns, padding with 0 O32XE % replace 0 by 32 (space) oYm % convert to number. Take mean of each column Yoc % round. Convert to char GZy % size of input in the 2 dimensions 2/Xk % divide each dimension by 2, and round up to account for the padding e % reshape into image with half original size in each dimension 2t3$Y"  % replicate by a factor of 2 in each dimension. Display implicitly


# Pyth, 58 bytes

J2A,lQlhQV:0GJ
Ksm*C+csmsm?&<kG<bHC@@Qkb32hBdhBN4 .5J:0HJK


Try it online!

• The bonus is not there anymore
– THC
Commented Apr 8, 2016 at 9:38

# Lua, 382376367353 348 bytes

r="\n"o=... n=o:find(r)-1
l=n+n%2
a=o:gsub(r,(n~=l and" "or"")..r).." "..(#o//(l+1)%2<1 and r..(" "):rep(l)or"")print(a:gsub("()([^\n])(.)",function(p,m,c)t=p//(l+1)%2==0return string.char(math.floor((m:byte()+c:byte()+(t and a:sub(p+l+1,p+l+1)or a:sub(p-l,p-l)):byte()+(t and a:sub(p+l+2,p+l+2)or a:sub(p-l-1,p-l-1)):byte())/4+.5)):rep(2)end).."")


Works on the command line; accepts a string like the test case.

• Care to include an ungolfed version? Commented Apr 8, 2016 at 22:25

# Ruby, 235 230 bytes

->i{i=i.split($/).map{|s|s.bytes+[s.size%2>0?32:0]} w=i[0].size;h=i.size;h+=h%2;r=[[]]*h (h/2).times{|y|y*=2 (w/2).times{|x|x*=2 c=((i[y][x,2]+(i[y+1]||[32]*w)[x,2]).inject(:+)/4.0).round.chr r[y+1]=r[y]+=[c,c]}} r.map(&:join)*$/}


# Python, 319 bytes

def f(A):
L,R,S=len,range,A.split('\n')
if L(S[0])%2:S=[s+' 'for s in S]
m=L(S[0])
if L(S)%2:S+=[' '*m]
C=[chr(int(sum(map(ord,[S[i][j],S[i+1][j],S[i][j+1],S[i+1][j+1]]))/4.0+0.5))for i in R(0,L(S),2)for j in R(0,m,2)]
f=t='';i=0
while i<L(C):
t+=C[i]*2
i+=1
if i%(m/2)<1:f+=(t+'\n')*2;t=''
f=f[:-1]
print f


2nd indentation is tabs.

Stuff before C is padding, C is the averaging process to single letters and rest is output

## R, 433 399 bytes

y=scan(,'',sep="\n")
h=nchar(y[1])
v=length(y)
p=function(x)paste(x,collapse="")
if(h%%2){y=sapply(y,function(x)paste0(x," "));h=h+1}
if(v%%2){y=c(y,p(rep(" ",h)));v=v+1}
z=matrix(unlist(lapply(y,function(x)strtoi(charToRaw(x),16))),ncol=h,byrow=T)
a=array(,c(v,h))
for(i in 1:(v/2)){for(j in 1:(h/2)){r=2*i-1:0;s=2*j-1:0;a[r,s]=rawToChar(as.raw(floor(mean(z[r,s])+.5)))}}
cat(apply(a,1,p),sep="\n")


I am getting desperate because this thing seems to be non-competing as heck. It prints

$$>>II99######$$>>II99######
$$##88KKGG####$$##88KKGG####


for the test case.

If you feed in the 7×3

%%%%%%%
Example
%%%%%%%


the output will be

BBFFJJ33
BBFFJJ33
######!!
######!!


because of the divisibility by 2 etc. etc.

Ungolfed:

y <- scan(, '', sep="\n") # Read STDIN and make it a character vector
h <- nchar(y[1]) # Get line width: how many chars per line
v <- length(y)   # Get array height: how many lines
p <- function(x) paste(x, collapse="") # A function that merges a vector of strings
if (h%%2) {y <- sapply(y, function(x) paste0(x, " ")); h=h+1} # If height is odd, add an empty line
if (v%%2) {y <- c(y, p(rep(" ", h))); v=v+1} # If width is odd, add an empty column
z <- matrix(unlist(lapply(y, function(x) strtoi(charToRaw(x), 16))), ncol=h, byrow=T)
# z now stores ASCII codes in a matrix; analogous to C strtol
a <- array(, dim=c(v,h)) # Reserve an array for the final result
for (i in 1:(v/2)) {
for(j in 1:(h/2)) {
r <- 2*i - 1:0 # Range of rows to average
s <- 2*j - 1:0 # Range of columns to average
a[r, s] <- rawToChar(as.raw(floor(mean(z[r, s]) + .5))) # Average, round, convert the ASCII codes
} # and write them to the same place as in the original array
}
cat(apply(a, 1 , p), sep="\n") # Prints the array row-wise (index 1 for rows)


Just look how it handles this one gorgeous example (courtesy of chris.com):

                                                MRMMMMM8MMX
<R????!!?MMMR$RMMh. :M$$R?!!~~~~!!!!!!!MMM$$$$X :M$$$X!~~~   ~~~~~!!MM8$MM$$M! :!XM$$R!~~~~~ ~~~~~!!M$$R! <!XM$$MR!~~~~ ~~ ~:!!<:!M$$! '<!XMBQQRMMMMX:::~~~<!?!!~~!!!!$$$M!$X ~!!MM$M8R!!!?!:~!!M$f?!~~~!M$8HXX?
<!!!XMM$MMRM$$!~!~~~~~~~~~~~!XM?!!M! <!!!!XMM$$M$$MMM!!~~~ ~~~ ~ :~!!!X!~~R! !!!!XMMMMMMMMMMM!!~~~ ~~~~ ~~~!!!X~~X!~ '~~!!MMMM@MMMX!!MM!:~!!!~~ ~~~~!!XXXX~ ~!!!XMMMMMMMM!MMM!~~~~:: <<~~~~!!$$R! '!!!!MM888M$MXMMM!!!!()!!~~~~~<!X$$> ~!!!M???MMRRMMX<~!!!!~~~~~:!XN$$M
~!!!!!M@$@$$!!~~' ~~:XH8$$$WR
!!!!MM$RM$RRMMMM?t!:::XX8>
~~!!MMM$WX!!!!!!$$RR$$$R"
'  <!!MT!!!~~~!#BX!!!~~?T#?!!!M$$X. <!!!!~~~~~~~~~?!!!~~~~~~:!M$$$$MXH: ~~~~~~~~~~~ ~~!M&!!!~~~<!!X$$$R$W>
<~~~~~~~~    '~~!$!!!!!!!!MMRM$R?#!!$N! x~~~~~~~~~ ~~~!MX!!!!!!?!M!M!~~:!!$B!
M!~~~~~~~~~~  <~~:!$R!!!!!!!X!!!~~!!~!RR! :M!~~~~~~~~~~~ ~~~!X$R!!!!!!!!~~~:!!~~tMM!
dR!!~~~~~~~~~~~~~~~~!M$R!!!!!!!~!!!!!!~~@$@~
tR!!!~~~~~~~~~~~~~~~!!M$R!!!!!!!!!!!!!~~!$$E~ d!~~~~~~~~~~~~~~~~~~~!!$$X!!!!!!!!!!!!~~~X$$!~ 8R~~~~~~~~~~~~~~~~~~~<!X$$!!!!!!!!!!!<~~~!MR$~~
8$~~~~~~~!~~~~~~~~~~~<!!$$R!!!MX!!!!~~~~~<XR!~< :$$!~~~~~~!!~~~~~~~~~~~!!M$$!!!!MM!!!~~~~~<!8F~<! .x8$$$!~~~~::!~~~~~~~~~~~!!X$$!!!!MM!!~~~~~!!MR~~~! .::xxxnHW8$$!!~~~~~~~~~~<!@$$X!!!!MM~~~~~<!!XE~~~~! :t$$$!!~~~~~~~~~~!X$$X~!!!MX~~~~~!!X$$~~~~!! ~~~~#R$RR8$$!!~~~~~~~~~<!M$$$B~!!!M!~~~~~!X$$!~~~~!! ~~~~~~~~?$$$$!!~~~~~~~~~!!$$$$X!!X!~~~~!X$$R~~~~<!f :~~~~~~~~~~?!!~~~~~~~~!!X$$X!M~~~<!W$$R~~~~~!! ~~~~~~~~~~ ~~M$$!!~~~~~~~~!!M$$$$Bid$$!~~~~~!! !~~~~~~~~~~~~~~~$$!~~~~~~~~~!!$$!~~~~~~!~ !~~~~~~~~~~~~~~~M$$!:~~~~~~~<!X$$$$!~~~~~~!! ~~~~~~~~~~~~~~!!!$$$$R!!:~~~~~~!!M$$"XR~~~~~~~!! ~~~~~~~~~~~~~!!!!$R!<!~~~~~!!!X$$P~ !~~~~~~~!! ~~~~~~~~~~~<!!!!!$$$$X!!~~~~~<!!!@#"" ~~~~~~~~!! ~~~~~~~~~~~!!!!!X$$$$X!~~~~~~!!! '~~~~~~~!! ~~~~~~~~~~~<!!!!M$$$$X!~~~~~!!!f '~~~~~~<!! ~~~~~~~~~~~~~!!!$$$$R!~~~~~~!!! '~~~~~<!!> ~~~~~~~~~~~~~~!!M$$$" !~~~~~!!!! ~~~~~~!!! ~~~~~~~~~~~~~~!!!$R~ .!~~~~~!!!                  ~~~~~!!!!
~~~~~~~~~~~~~~~!!!$*?!!!~!!~~~~<!!~ ~~~~!!!!! ~~~~~~~~~~~~~~~~!!!*"~!!!!!!!!!~~~~!!! <~~~:!!!!! !~~~~~~~~~~~~~~~~!!M#~~~~~~~~~~~!!~~~~~!! ~~~~~~~!!! !<~~~~~~~~~~~~~~~!!!R"~~~~~~~~~~~~~!!!~~~~<!! '~~~~~~<!! !<~~~~~~~~~~~~~~~~!!!~~~~~~~~~~~~~~!!~~~~~!!!X: ~~~~~~~!!~ !!~~~~~~~~~~~~~~~~!!!!~~~~~~~~~~~~<!!~~~~!!!9$MX:              ~~~~~~<!!
!!!!!~~~~~~~~~~~~~!!!!:~~~~~~~~~~~!!~~~~~!!X$$X!~ '~~~~~~!!~ !!!!!!~~~~~~~~~~~<!!!!!!~~~~~~~~~~!!~~~~!!!M$$R!~~~~          ~~~~~~!!!
!!!!!!!<~~~~~~~~~~~!!!!!!!:<:~~~~~!!~~~~!!X$$R!~~~~~~ ~~~~~~!! !!!!!!!!~~~~~~~~~~<!!!!!!!!!!!!!<!!!~~~~!!@$$!~~~~~~~~        ~~~~~!!~
!!!!!!!!!~~~~~~~~:<!!!!X!!!!!!!!!!!!~~~!!X$$!~~~~~~~~~~~~: '~~~~~!! '!!!!!!!!!!~~~~~~~!!!!!!?!!!!!!!!!!!~~<!!MM!~~~~~~~~~~~~~~~ '~~~~~!~ !!!!!!!!!!\~~~~~~~>!!!! "MMMHX!!~~~<!!R!~~~~~~~~~~~~~~~~~<~~~~!! !!!!!!!!!!<~~~~~<!!!!! .::<!!!!<~~!!X8X!~~~~~~~~~~~~~~~~~~~~~~!! X!!!!!!!!~~~~~!<!!!!!!!!!!!!~~!!\~~!!MMX!:~~~~~~~~~~~~~~~~<!~~!> !X!!!!!!!!~!!:!!!!!!!!!!~!!!:~~!!~~~!!M!~~!!<~~~~~~~~~~~~~~~!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!:!!~~:!9R!~~~~~~!~~~~~~~~~~~~~~<!!f 'CHAT!!!!!!!!!!!!!!!!!!!!!!!!!!!!~~~!!MX~~~~~~~~~~~~~~~~~~~~~~!!X  After:  ''..$$662266??MMIIDDEE66
''..$$662266??MMIIDDEE66 ''>>$$<<WWOOOOggPP88,,HH99..;;
''>>$$<<WWOOOOggPP88,,HH99..;; ..HH..$$$$EEPP~~ggOOggVV??22..$$$$00!! ..HH..$$$$EEPP~~ggOOggVV??22..$$$$00!! 99((PP77;;CCII5555VVVV4433WWPP88..<<==66 99((PP77;;CCII5555VVVV4433WWPP88..<<==66 ..!!==MM$$..99DD8899gggg~~ggOOmm88HH@@PP!!
..!!==MM$$..99DD8899gggg~~ggOOmm88HH@@PP!! ::88EEMM@@MMPP77BB??gg88~~88__~~88==kkTT88 ::88EEMM@@MMPP77BB??gg88~~88__~~88==kkTT88 ::!!EEHHCCCCEEMM77PPQQ00??nn~~??0000(( ::!!EEHHCCCCEEMM77PPQQ00??nn~~??0000(( 8888,,00??..BB@@11??PP""ggmmVV55//GG 8888,,00??..BB@@11??PP""ggmmVV55//GG 8888,,MM00..HHEE77==((//>>));;$$00))
8888,,MM00..HHEE77==((//>>));;$$00)) ""''((,,\\PP~~ggII00!!~~ddXX''88$$;;<<''
""''((,,\\PP~~ggII00!!~~ddXX''88$$;;<<'' VV~~~~~~ggOO99gg..!!88PP((EE::00++..;;(( VV~~~~~~ggOO99gg..!!88PP((EE::00++..;;(( BB~~~~~~~~gg VVmm--;;!!!!))::,,gg??88CC!! BB~~~~~~~~gg VVmm--;;!!!!))::,,gg??88CC!! 11??PP~~~~~~~~~~__~~PP;;::!!!!!!PPPP''PPll@@88 11??PP~~~~~~~~~~__~~PP;;::!!!!!!PPPP''PPll@@88 11YYPPgg~~~~~~~~~~~~~~!!..;;!!!!!!!!!!88~~00,,OO 11YYPPgg~~~~~~~~~~~~~~!!..;;!!!!!!!!!!88~~00,,OO &&KK~~~~~~gg~~~~~~~~~~FF0000!!,,//!!88VV~~MMEEPP?? &&KK~~~~~~gg~~~~~~~~~~FF0000!!,,//!!88VV~~MMEEPP?? ::..$$PP~~mm??gg~~~~~~~~gg//..##!!777788~~~~??33OOnn!!
::..$$PP~~mm??gg~~~~~~~~gg//..##!!777788~~~~??33OOnn!! <<""&&//NNLL::))$$$$##PP~~~~~~~~VV77$$TT!!77hh~~~~((==CC~~gg!!
<<""&&//NNLL::))##PP~~~~~~~~VV77$$TT!!77hh~~~~((==CC~~gg!! 88gg~~ggMM$$$$;;))$$$$##PP~~~~~~~~((..$$OO!!;;PP~~gg==00gg~~??22
88gg~~ggMM;;))##PP~~~~~~~~((..$$OO!!;;PP~~gg==00gg~~??22 88mm~~~~~~gg__LL$$##PP~~~~~~PP::$$0066rrAA00$$\\~~~~!!
88mm~~~~~~gg__LL$$##PP~~~~~~PP::$$0066rrAA00$$\\~~~~!! PP~~~~~~~~~~~~~~..$$$$##mm~~~~~~??00$$$$99~~~~gg88 PP~~~~~~~~~~~~~~..$$$$##mm~~~~~~??00$$$$99~~~~gg88 ~~~~~~~~~~~~gg!!##$$$$::..~~~~gg!!;;$$FF""RR~~~~~~88
~~~~~~~~~~~~gg!!##::..~~~~gg!!;;$$FF""RR~~~~~~88 ~~~~~~~~~~VV!!!!00$$$$==gg~~~~((!!))!!00 ""~~~~~~gg!! ~~~~~~~~~~VV!!!!00$$$$==gg~~~~((!!))!!00 ""~~~~~~gg!! ~~~~~~~~~~nn88!!..$$00FF~~~~PP!!22              $$~~~~nn(((( ~~~~~~~~~~nn88!!..$$00FF~~~~PP!!22              $$~~~~nn(((( ~~~~~~~~~~~~~~!!..$$$$FF$$PP~~~~!!!!                OO~~~~88!!
~~~~~~~~~~~~~~!!..FF$$PP~~~~!!!! OO~~~~88!! ~~~~~~~~~~~~~~gg!!##$$&&::$$))!!88PP~~VV!!88 VV~~??!!!! ~~~~~~~~~~~~~~gg!!##$$&&::$$))!!88PP~~VV!!88 VV~~??!!!! ??~~~~~~~~~~~~~~PP,,//QQgg~~~~~~~~gg!!~~~~??!! ""~~~~~~??!! ??~~~~~~~~~~~~~~PP,,//QQgg~~~~~~~~gg!!~~~~??!! ""~~~~~~??!! ((~~~~~~~~~~~~~~~~!!88~~~~~~~~~~~~??PP~~gg!!66@@'' OO~~~~nn!!88 ((~~~~~~~~~~~~~~~~!!88~~~~~~~~~~~~??PP~~gg!!66@@'' OO~~~~nn!!88 !!!!88~~~~~~~~~~nn!!!!??~~~~~~~~~~!!~~~~88::$$<<ggOO          hh~~~~8888
!!!!88~~~~~~~~~~nn!!!!??~~~~~~~~~~!!~~~~88::$$<<ggOO hh~~~~8888 !!!!!!((~~~~~~~~~~??!!!!!!..??PPVV!!~~~~!!88//gg~~~~gg ~~~~gg88 !!!!!!((~~~~~~~~~~??!!!!!!..??PPVV!!~~~~!!88//gg~~~~gg ~~~~gg88 ##!!!!!!88gg~~~~mm((!!//))!!!!!!!!!!~~??::..PP~~~~~~~~~~mmOO$$~~~~PP88
##!!!!!!88gg~~~~mm((!!//))!!!!!!!!!!~~??::..PP~~~~~~~~~~mmOO~~~~PP88
!!!!!!!!00nn~~~~FF!!!!  44DD==//??~~((55;;~~~~~~~~~~~~~~~~nn~~~~!!
!!!!!!!!00nn~~~~FF!!!!  44DD==//??~~((55;;~~~~~~~~~~~~~~~~nn~~~~!!
LL!!!!!!!!ggVV88((!!!!!!88!!VVPPGG~~!!99QQ??VV~~~~~~~~~~~~~~??PP((
LL!!!!!!!!ggVV88((!!!!!!88!!VVPPGG~~!!99QQ??VV~~~~~~~~~~~~~~??PP((
""3366!!!!!!!!!!!!!!!!!!!!!!!!!!''ggVV22RR~~~~~~gg~~~~~~~~~~~~VV//22
""3366!!!!!!!!!!!!!!!!!!!!!!!!!!''ggVV22RR~~~~~~gg~~~~~~~~~~~~VV//22


# Ruby, 180158148128 + 4 124 + 4 = 128 bytes

Run with $ruby -nl (+4 bytes for -nl flags). Takes input on STDIN. y,x=x,$_.scan(/..?/)
(puts [x.zip(y).map{|c|(("%2s"*2%c).bytes.reduce(:+)/4.0).round.chr*2}*""]*2
y,x=x,[])if$.%2<1||$<.eof?


See it on ideone: http://ideone.com/brmP3L

## Ungolfed & explanation

Per man ruby, the -n flag "[c]auses Ruby to assume the following loop around your script ... while gets ... end". The special variable $_ contains the last line read by gets. The -l flag removes the \n from each line, equivalent to $_.chop!.

y, x = x, $_.scan(/..?/) ( puts [ x.zip(y).map {|c| (("%2s" * 2 % c).bytes.reduce(:+) / 4.0).round.chr * 2 } * "" ] * 2 y, x = x, [] ) if$. % 2 < 1 || $<.eof?  The special variable $. is the number of lines that have been read so far, and $< is STDIN. The pairs of characters from every second line gets zipped with the previous line's. The format string %2s%2s combines the characters and pads it with spaces, then the characters are averaged. • w=s=~/$/ is shorter for calculating initial width. Also just return the calculated string instead of printing because that counts as output Commented Aug 12, 2016 at 22:21