pixelate

Here's a variation of the img2ascii program. Seems to work best when the "key" file is fairly uniform.


#http://mattmik.com/articles/ascii/ascii.html
const block_width = 8
const block_height = 4

func
calc_block(byref dat, h, y2, w, x2)
local y,x,c,r,g,b,n

n = 0
for y = 0 to h
for x = 0 to w
c = -dat[y2 + y, x2 + x]
r = ((c band 0xff0000) rshift 16)
g = ((c band 0xff00) rshift 8)
b = (c band 0xff)
n += (r + g + b) / 3
next x
next y
return n
end

func
get_cell(byref dat, h, y2, w, x2)
local y,x,c,r,g,b,n

dim n(h, w)
for y = 0 to h
for x = 0 to w
n(y, x) = dat[y2 + y, x2 + x]
next x
next y
return image(n)
end

func
get_char(byref tbl, n)
local r = tbl[n]
if ismap(r) then return image(r)
for sn in tbl.sorted
if (sn > n) then
' round up to the nearest value
tbl[n] = tbl[sn]
return image(tbl[sn])
endif
next n
return r
end

# analyze the graphic data corresponding to each character in the character set.
func
create_table(path)
local img,dat,i,ch,x2,n,f

open path for input as #1
img = image(#1)
img.save(dat)
close #1

local w = img.width
local h = txth("1")
local cw = txtw("1")

local nchars = img.width / cw
local vals = []
local minv = maxint
local maxv = 0

for i = 1 to nchars
x2 = ((i - 1) * cw)
n = calc_block(dat, h - 1, 0, cw - 1, x2) / (w * h)
minv = min(minv, n)
maxv = max(maxv, n)
vals << n
next i

' scale the values from 0:255
local tbl = {}
for i = 1 to nchars
diff = iff(maxv - minv == 0, 1, maxv - minv)
n = 255 * (vals[i - 1] - minv) / diff
vals[i - 1] = n
x2 = ((i - 1) * cw)
tbl[n] = get_cell(dat, h - 1, 0, cw - 1, x2)
next i

sort vals
tbl["sorted"] = vals
return tbl
end

sub
pixelate(path,keypath)
local img,dat,pic,bly,blx,y2,x2,n,minv,maxv,row,i,c
local tbl = create_table(keypath)

open path for input as #2
img = image(#2)
img.save(dat)
close #2

local w = img.width
local h = img.height
local blw = w / block_width
local blh = h / block_height
local vals = []
local minv = maxint
local maxv = 0

dim pic(blh, blw)

for bly = 0 to blh - 2
for blx = 0 to blw - 2
y2 = bly * block_height
x2 = blx * block_width
n = calc_block(dat, block_height, y2, block_width - 1, x2) / (w * h)
minv = min(minv, n)
maxv = max(maxv, n)
pic[bly,blx] = n
next blx
next bly

for bly = 0 to blh - 2
for blx = 0 to blw - 2
diff = iff(maxv - minv == 0, 1, maxv - minv)
n = 255 * (pic[bly, blx] - minv) / diff
i = get_char(tbl, n)
if (ismap(i)) then i.show(blx*i.width,bly*i.height)
next blx
next bly
end

f1 = "http://clipart-library.com/image_gallery2/Donald-Trump-Free-Download-PNG.png"
f2 = "http://www.freepngimg.com/download/beach/5-2-beach-download-png.png"
pixelate(f1,f2)

Oh dear... All I get, when pressing either F1 or F2, is a mass of white/blue-white 'blocks' of pixels, filling the display. I checked the images (Trump and Beach) and they are ok.
I did not change the program. Just ran it as is.
Running with Linux Mint (64bit) and SB 0.12.10 (64 bit)

I am surprised to see "anscii" characters that are much wider than high. This code seems to depend more on color than matching B&W patterns of characters to B&W "character" in image though I see code that might be attempting that??? and what are those anscii characters being used? I've not seen ones that look like that before.

The previous sample Harry_s image had a problem of too many characters per line so last part of the line was printed on the following line. Odd, the first time I ran it, maybe it was with SB 012.10 it was OK? or I hadn't noticed problem yet. I have yet to play around with code to study it.

The code doesn't scale to the window dimensions so unless you maximise the window, you could just be looking at the top left corner. I just included the online images so you could run something straight away, but it's more practical to work with locally stores images. You can play with the two constants to see a different effect.

Just started looking at this code and already lost! Opening the image file for output destroys the image file??? Lost my image file!

Sorry, fixed it. the direction didn't matter with web images.

Hi Johnno,

When I created the minor Windows 0.12.11 update to fix the SDL sound issue, I also made a slight change to the image save command to give the resulting array the correct dimensions. I've just uploaded a Linux build of 0.12.11 which should now produce the expected image.

Ok. I can see images. Trump looks better in blue... lol
The "beach" (greyscale) was visible but 'enlarged'. The image produce a 'zoomed' palm tree.
Hey! At least I am now getting images. Thanks Chris!!

All smiles here...

J

I also checked the listing from table. It is not sorted correctly, the numbers are treated as strings and the decimal places out of sequence in sorts. Would sort even sort a list of integers correctly?

This line baffles me, I guess that is my next experiment ;-) )
tbl["sorted"] = vals

The create_table function assigns values to each of the "characters" creating a lookup table from value to character. When reading the input image, the calculated value for the next block of pixels may not be an exact match for a value in the table. In this case the get_char function scans down the sorted list of character values to find the nearest value, then returns the corresponding "character". The lookup table is a map, and the "sorted" entry is a regular array.
The sort function will sort an array of numbers in ascending order. If you wanted descending order or to sort some other type of list, you need to supply a callback function. This should return whether a pair of elements are less than, equal or greater than each other via: -1,0,1.