[QUIZ] Text Image (#50)


R

Ruby Quiz

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

This week's Ruby Quiz is to create a tool that will allow you to preview an
image file at the command-line in pure text.

Your program will need to read in an image, in whatever format you want to
support, and respond with a text representation of the image that fits in the
terminal.

For example, given the image:

http://rubyquiz.com/images/Ducky.png

Your program might respond with something like:

........--**####**::::::::::::........
......--##oooooo\\**::::::::..........
......**oo==oooo\\\\::::..............
....--\\oooooooo\\$$**::..............
....**&&$$oooo\\$$$$%%................
....**\\oooo\\<<<<$$##................
....!!<<<<<<<<<<\\\\##..........::::::
....::%%<<<<<<<<\\$$^^....::**++**....
....^^%%<<<<<<<<$$$$##**""==++++==****
....**oo<<<<<<$$<<<<\\oo==++++++==""""
..!!==oo<<<<<<<<$$$$oo====++++==oo####
^^====oo\\<<$$\\oooooo==++======oo****
**++++====oooo====++++======oooo\\^^^^
++====++++========++======oooooo**....
""====++++==========oooooooooo##--....
""==================oooooooooo^^......
!!oo==oo======oooooooooo\\##^^::......
..""oooooooooooooooo\\oo""^^..........
..::**====oooooooooo==**::............
....::^^**""""""""!!..--::............
....::^^**""""""""!!..--::............

Go for as much accuracy as you can possibly squeeze out of it.
 
Ad

Advertisements

J

Jim Freeze

Ahh, a half-toning algorithm.

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz = until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-= =3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D=
-=3D-=3D-=3D

This week's Ruby Quiz is to create a tool that will allow you to preview = an
image file at the command-line in pure text.

Your program will need to read in an image, in whatever format you want t= o
support, and respond with a text representation of the image that fits in= the
terminal.

For example, given the image:

http://rubyquiz.com/images/Ducky.png

Your program might respond with something like:

........--**####**::::::::::::........
......--##oooooo\\**::::::::..........
......**oo=3D=3Doooo\\\\::::..............
....--\\oooooooo\\$$**::..............
....**&&$$oooo\\$$$$%%................
....**\\oooo\\<<<<$$##................
....!!<<<<<<<<<<\\\\##..........::::::
....::%%<<<<<<<<\\$$^^....::**++**....
....^^%%<<<<<<<<$$$$##**""=3D=3D++++=3D=3D****
....**oo<<<<<<$$<<<<\\oo=3D=3D++++++=3D=3D""""
..!!=3D=3Doo<<<<<<<<$$$$oo=3D=3D=3D=3D++++=3D=3Doo####
^^=3D=3D=3D=3Doo\\<<$$\\oooooo=3D=3D++=3D=3D=3D=3D=3D=3Doo****
**++++=3D=3D=3D=3Doooo=3D=3D=3D=3D++++=3D=3D=3D=3D=3D=3Doooo\\^^^= ^
ooo**....
""=3D=3D=3D=3D++++=3D=3D=3D=3D=3D=3D=3D=3D=3D=3Doooooooooo##--...=
 
H

Hal Fulton

Ruby said:
This week's Ruby Quiz is to create a tool that will allow you to preview an
image file at the command-line in pure text.

Your program will need to read in an image, in whatever format you want to
support, and respond with a text representation of the image that fits in the
terminal.

I never participate in these, but this one is tempting.

What about ANSI color? ;)


Hal
 
J

James Edward Gray II

I never participate in these, but this one is tempting.

Ah, why not? :) We do try to have a little fun.

Perhaps that means you need to send in a problem *you* can't resist! ;)
What about ANSI color? ;)

Very clever. I didn't think of that...

James Edward Gray II
 
Ad

Advertisements

J

James Edward Gray II

do all contributors get a free sample?

Contributors of quizzes and code used in the book will be contacted
very soon now...

James Edward Gray II
 
S

Simon Kröger

Hi,

here is my attempt of solving this weeks quiz:

This solution uses the RMagick lib to read the image and
to find edges because trying to find apropiate letters for
halftoning is hard on all the different terminals.

I had another version without the generator/enumerator
stuff and it was a lot faster. But speed isn't an issue this
week and it's so much smoother than fiddling with indexes.

cheers

Simon

----------------------------------------------------------------
require 'RMagick'
require 'generator'
require 'enumerator'

puts "Usage: #{$0} <img> [size]" or exit if !ARGV[0]

img, size = Magick::ImageList.new(ARGV[0]), (ARGV[1]||40).to_f
factor = [size*1.5/img.rows, size/img.columns].min

img.resize!(img.columns*factor, 2*(img.rows*factor*0.75).round)
img = img.edge.despeckle.despeckle.normalize.threshold(50)

pixels = img.get_pixels(0, 0, img.columns, img.rows).map{|c| c.red.zero?}

pixels.to_enum:)each_slice, img.columns).each_slice(2) do |l|
puts SyncEnumerator.new(*l).map{|p1, p2|
[' ', "'", ".", ":"] [(p1 ? 0 : 1) + (p2 ? 0 : 2)]}.join('')
end
----------------------------------------------------------------

sample output:

.:'''''''.
.: :.
.: :.
: :
:' ':
.: :
: .':. ::
:'.' : .. ':
: :..' :' ': :
:. ' : .: :
': '::'':.. ':' . :
:: ''.. :' .:'':.
:: . ': .: ..' . '.
': ''''' .: .:::::''' :.
:: .:': :
.: : .:' :
.' '' '' :
:' :
: :
' :
: ' :'
: .:
' : .:
' :
: .:
: .:
: .'
'. :'
:. .'
'. .:'
':. .:'
':. .:'
''..........''
 
J

James Edward Gray II

Hi,

here is my attempt of solving this weeks quiz:
[snip]

sample output:

.:'''''''.
.: :.
.: :.
: :
:' ':
.: :
: .':. ::
:'.' : .. ':
: :..' :' ': :
:. ' : .: :
': '::'':.. ':' . :
:: ''.. :' .:'':.
:: . ': .: ..' . '.
': ''''' .: .:::::''' :.
:: .:': :
.: : .:' :
.' '' '' :
:' :
: :
.' :
: ' :'
: .:
' : .:
' :
: .:
: .:
: .'
'. :'
:. .'
'. .:'
':. .:'
':. .:'
''..........''

Wow, I really like that! Too cool.

Here's the code used in the quiz:

#!/usr/local/bin/ruby -w

unless ARGV.size =3D=3D 1 and File.exists? ARGV.first
puts "Usage: #{File.basename($0)} IMAGE_FILE"
exit
end

require "RMagick"

text =3D %w{. : - ^ ! * + " =3D % o # \\ $ < &}

image =3D Magick::Image.read(ARGV.shift).first

image =3D image.quantize(text.size)
image.scale!([39.0 / image.columns, 20.0 / image.rows].min)
image =3D image.quantize(text.size)

pixels =3D Array.new
0.upto(image.rows) do |y|
0.upto(image.columns) do |x|
pixel =3D image.pixel_color(x, y).intensity
pixels << pixel unless pixels.include? pixel
end
end
pixels.sort! { |a, b| b <=3D> a }

0.upto(image.rows) do |y|
0.upto(image.columns) do |x|
2.times { print text[pixels.index(image.pixel_color(x, =20
y).intensity)] }
end
puts
end

__END__

James Edward Gray II
 
T

Timothy Hunter

My solution relies on having RMagick do all the work. Here's the output
for the test image:

+-------------------------------------------------------------------------+
| .::+====+:: |
| .:==o======ooo*oo+. |
| +oo=====++++===oo***+ |
| :eek:o==++++===++==ooooo*^*. |
| :eek:o====++++====oooooooo*^* |
| .oo=====++++========ooo**^^o |
| .ooo=====++++++======ooo**^^%: |
| :*oo*o==============oooo****^^^. |
| :eek:oo$WW^===========oooo****^^^^^= |
| ooo*WWW%=========oooo^^*^**^^^^^^ |
| oooo=o::eek:=====oooo*%WWW$^^*^^^^*^: |
| =ooo=:+====ooooo**o^WWW$***^****^: |
| .*o*o*ooooo==ooo*^*+====o*^*****^. |
| :eek:%$$$$$WW$$$%%^^^^**********^^= |
| .oWWWWWWWWWWWWWW$%%^**o****^^= :::::: |
| %$$$$$$$W$$W$WWWW$^****^^o. ...::::::::==: |
| =WWWW$$$W$$$$WW$$%^^****+. .........:::::::::::::::::=o+ |
| :$WWWWWWWWWWWW%^****^%%%%%^^**oo====++:::::::::::::::+=o+ |
| :+oo*$$WWWWWWW$%^*^^^^^%$$$%%%^**o===+:::::::::::::::::++==o: |
| .:====o*^%$$$$$%^^%%^^^^%%%%%%%^^**o===+::::::::::::::::::===oo |
| .:+++++==o*^%%%%%%$%%%%^^^^%%%^^^**oo===++:::::::::::::::::+==ooo |
| .:+::::+++=oo*^%%%$%%%%%^^^^^*****ooo===+++::::::::::::::::++===oo= |
| :++::::::+++=oo*^%%%%%%^^****ooooo=====++:::::::::::::++:::++====o*. |
| :+::::::::::+===o**^^^^**ooo=====+=+++++::::::::::::+::==++++===ooo+ |
| :+::::::::::::+++==oooooo====+::::+:::::+::::+::++::+::+==++=====oo= |
| .+::::::::::::::::++=+=====+::::::+:::::+::::+:::+:::+++========ooo= |
| :+::::::::::::::::::+:++++::::::++::::::::::+:::++:++==========ooo+ |
|.++++:::::::::::::::::::::::::::+:::::+::::+:::++++===========oooo: |
|.++++::::::::::::::::::::::::::::::++:+::+=+++==============oooo=. |
| +++++++::::::::::::::::::::::++::++::+==+=+===========o===ooo=: |
| :==++++::::+:::::::::+:+:::::::::+++===++=============ooooo=: |
| .===++++++++++::+++::+++:+++++::+===++====o==========o=o==:. |
| :=======+++++++++++++++++:++===============oo====oo=o==:. |
| :====================++++++==+=========o=====ooo====: |
| .==================================ooooooo=oo===+: |
| :+=============================oooo=o==oo==::. |
| ::==========================o====oo===::. |
| ::++==============+===========+::. |
| ..:::++++==++=+++++++++::.. |
| ....:.::::::... |
+-------------------------------------------------------------------------+


require 'RMagick'

CHARS = ['W', 'M', '$', '@', '#', '%', '^', 'x', '*', 'o', '=', '+',
':', '~', '.', ' ']
FONT_ROWS = 8
FONT_COLS = 4

img = Magick::Image.read(ARGV[0] || "Flower_Hat.jpg").first

# Resize too-large images. The resulting image is going to be
# about twice the size of the input, so if the original image is too
# large we need to make it smaller so the ASCII version won't be too
# big. The `change_geometry' method computes new dimensions for an
# image based on the geometry argument. The '320x320>' argument says
# "If the image is too big to fit in a 320x320 square, compute the
# dimensions of an image that will fit, but retain the original aspect
# ratio. If the image is already smaller than 320x320, keep the same
# dimensions."
img.change_geometry('320x320>') do |cols, rows|
img.resize!(cols, rows) if cols != img.columns || rows != img.rows
end

# Compute the image size in ASCII "pixels" and resize the image to have
# those dimensions. The resulting image does not have the same aspect
# ratio as the original, but since our "pixels" are twice as tall as
# they are wide we'll get our proportions back (roughly) when we render.
pr = img.rows / FONT_ROWS
pc = img.columns / FONT_COLS
img.resize!(pc, pr)

img = img.quantize(16, Magick::GRAYColorspace)
img = img.normalize

# Draw the image surrounded by a border. The `view' method is slow but
# it makes it easy to address individual pixels. In grayscale images,
# all three RGB channels have the same value so the red channel is as
# good as any for choosing which character to represent the intensity of
# this particular pixel.
border = '+' + ('-' * pc) + '+'
puts border
img.view(0, 0, pc, pr) do |view|
pr.times do |i|
putc '|'
pc.times { |j| putc CHARS[view[j].red/16] }
puts '|'
end
end
puts border
 
R

Ryan Leavengood

I'm surprised how easy this Quiz was because of ImageMagick and
RMagick (based on the other submissions, I didn't try it.) Kudos to
the developers of those projects (though I imagine only the RMagick
developer will be reading this.)

Of course you quiz developers deserve kudos for your clever solutions
using RMagick.

I wonder how long the code would be for a solution that did NOT use
RMagick or any other image library? Maybe future submissions will
answer this question for me...

Ryan
 
Ad

Advertisements

J

James Edward Gray II

I'm surprised how easy this Quiz was because of ImageMagick and
RMagick (based on the other submissions, I didn't try it.)

Indeed. I only found RMagick two weeks ago, but it impressed me
enough to make the quiz. It's a bit of a bear to get installed
(because of ImageMagick, not the Ruby bindings), but worth the effort.

I second the thanks to the developer for giving us such great tools
to work with!

James Edward Gray II
 
R

Rob Rypka

I tried this one out. I'm not sure if I was successful or not...

My first instinct was to rank characters for intensity levels
programmaticly. I then came to the realization that not all
characters have the same distribution of intensity, so I thought I
would try splitting them up, and matching them with sets of pixel
intensities (instead of just one).

ruby create_tables.rb num [extended]
does the first part - pass it a number (number of pixels sqare that
will be replaced by one character). uses extended ASCII if the second
argument is applied.

ruby i2a.rb src_img outfile num [normalized]
does the second part. takes num x num clumps of pixels from src_image
and finds the closest character from the appropriate table (by
Euclidean distance), puts it out to outfile. If normalized is
supplied, the image is normalized for maximum contrast in the source
image.

You can find the code here:
http://www.rabble-rooster.org/rubyquiz/50/

Results are in the results folder.

The underscore also rendered to pure white, so I had to remove it
manully from the YAML tables. Those tables are available also.

I know this code needs some refactoring/reengineering, and I didn't
take the time to look into how *Magick did things like scaling. Feel
free to chide me on any points that are inefficient/bad/wrong/stupid.
 
B

Brian Schröder

Hello Everyone,

I went into this quiz using the following approach. I split the image
into pieces and find for each piece of the image the letter most
similar to this piece. I did it all with image magick. There is room
for improvement in the distance function, but it works ok. I'm sure it
is the slowest solution so far, but it works.

You can find the sourcecode and examples at

http://ruby.brian-schroeder.de/quiz/asciiview/

best regards,

Brian

_,,uuuuu,,_
_u:EEEEEEEEEE{{[p,_
_:EEEEEEEEEEEEEEE{{[Ou
:EEEEEEEEEEEEEEEE{{{{[O3_
UEEEEEEEEEEEEEEEE{{E{{{[O3_
UEEEEEEEEEEEEEEEEEEEEE{{[S3B
;{EEEEEEEEEEEEEEEEEEEE{{[SO3B$
;{{{EEEEEEEEEEEEEEEEEE{{[[O3333u
{[[SQQ{EEEEEEEEEEEEEEE{{[[OO3333B
E{{[###${EEEEEEEEEEEE{{[SSSS333333q
E{{{###PEEEEEEEEEEE{SSQQ3333O333333
{{{{ " LEEEEEEEE{{[S$####$333333333
{{{{{:cEEEEEE{{{[[SZZ####Z3O3333OS3
F{{{{{{EEjjEEE{[SO35EEEFEEOO3OOOO33
F{]###########QQ3993SSSOSOO[[OS33~
"f################$Q3O[[[[OSS33~ L-F"FL
I#IIII#############Q[SSOO33P" L--" FE.
P######$##IIII####T3SS333P' LL---F -EEU
##############T3OOO3OOQ$$$9SSUUUUEEEEEEF- -EEE=
E
.;{[I##########TS3333S3$IIII$$B3O[{EEEEEFF -EEE=
E{
LEEEE{O#$I#####@BBB33333$$$II]$$B3O[{EEEEEF- -EEE=
E{L
LEEEEEEE[[email protected][{EEEEEE-- --EEEE=
E{{
LEEEEEEEEEE[3B$$]I]]$$$$$BBBBBBB333O[[{EEEEEEF-- ---EEEEEE=
E{{
LEFFFFFFEEEEE{[3B$$]]$$$$B333OOO[[[{{{EEEEEEEEFF .EE--EEEEEEE=
E{{"
-FFF-- --FEEEEE{[[email protected]@@@@B33O[[{{EEEEEEEEEEEFFF L E .LEEEEEEEEEEE=
E{{
-FFFF- -FFEEEEE{[O22OOO[[{EEEEEEEEEFFFEEF --- LE -F .EEEEEEEEEEEE=
{{
LEF--- --FFEEEEEEEEEEEEEEEFFF-FEF EE LE LE" -E EEEEEEEEEEEE{{=
"
EEE--- --FFFEEEEEEEEEEEFF LEF LE LE -EE LEEEEEEEEEEEEEE{{"
EEEEEF- ---FFEEEFEEFF -EE" -EF LEFL-EEEEEEEEEEEEEEEEEE{E"
EEEE-F--- --F-FFFFFF -EF LLE LLEFEEEEEEEEEEEEEEEEEEEE{{E
EEEEEE--------- --- --- LE LLEFFLEEEEEEEEEEEEEEEEEEEEEEE{{EF
EEEEEEEEE--F------ - -L--LLLLLEEELLEEE-LEEEEEEEEEEEEEEEEEEEEEEEE{EE"
FEEEEEEEEEEEE-----L-LLEEEEFF" .""FF"LEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
.EEEEEEEEEEEEEEEEEEEEEEEEEELLLEELLLEEEEEEEEEEEEEEEEEEEEEEEEEEEEF
.FEEEEEEEEEEEEEEEEEEEEEEEEEEEFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEF
FEEEEEEEEEEEEEEEEEEEEEEEELLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEF
FEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE{{E{EEEEEEEEEF"
"FEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE{EEEEEEF"
FFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFF"
"FFEEEEEEEEEEEEEEEEEEEEEEEEEEEFFF"
"FFFFFFEEEEEEEEEEEEEEFF"
FF"""""


_yv*/^^^^^^^/#Yy_
y#^ '^#y
y# ^#,
_#^ Ty
_# #y
# ,- #_
#^ #
_#' ^g
y# _Y/Xy #
# # Tg ^$
# #,^ y^ y**v_ #
$ ###^ # _. # #
# ^ _$_'_,# #
#y _yyyyyyv*gyy_ ^###IIP #
#y#$ ^ ^P*yy_ '' yf ,yvy_
^#$ ^P*y_ y# _y#^^ ,^#y
'# ^P/*+ ,_ _T* _#^ __yv*P^ ' ^#=
_
Ty~/**^^M ^P**#^v/^y# _g#yyyyyyyyvY*#P^^ =
#y
y# '^rr**~'y#^^ _vP^' =
#_
y#P^ #P_ y#^ T =
Y #
_#^ ^#C/xvv-_yYP' =
^$
y#^ ^^Pr/~^' =
#
_#^ =
#
g^ =
yT
#^ # =
#
# F ^ =
$^
#' _P @ # g # =
y^
y^ ,^ / g ^ y=
^
# v y^
# _/ y _ #^
# Y^ _. , ,#'
# r^ _^ g^
# r/ Yr *^ _x ' y#
^y _ *' _- y#^
# __ r _#^
# '^ ' ' y#^
^# - y#^
#y _ _YP'
^#, r _y#^
^#y r _v#^
^#y_ -x `~ -r _y*P^
^/*y_ ~/***r__yY/^^
^^P**YvyyyyyyyyyvvY*/P^^
 
Ad

Advertisements

R

Rob Rypka

I went into this quiz using the following approach. I split the image
into pieces and find for each piece of the image the letter most
similar to this piece. I did it all with image magick. There is room
for improvement in the distance function, but it works ok. I'm sure it
is the slowest solution so far, but it works.

You can find the sourcecode and examples at

http://ruby.brian-schroeder.de/quiz/asciiview/

I do believe I got pWn3d!!1!... Nice work, Brian.

I think my solution is probably slower, though :). I'm too used to
doing this kind of thing in C/++.
 
B

Brian Schröder

[snip]
I do believe I got pWn3d!!1!... Nice work, Brian.

Thank you, rob. Though I can't decipher sms-code, though I hope it's
good for me ;-)

greetings,

Brian
 
S

Simon Kröger

Hi,

i'm completely new to ncurses, so could someone with more exprerience
(or another OS) try this and tell me whats happening?
On windows all the colors are very pale (are there consts for lighter
colors?)
-----------------------------------------------------------------------
require 'RMagick'
require "ncurses"

Ncurses.initscr
puts "Usage: #{$0} <img> [size]" or exit if !ARGV[0]
puts "Sorry, no colors!" or exit unless Ncurses.has_colors?

img, size = Magick::ImageList.new(ARGV[0]), (ARGV[1]||40).to_f
factor = [size*2/img.rows, size/img.columns].min
img.resize!(img.columns*factor, (img.rows*factor*0.5).round)

COLORS =
[[Ncurses::COLOR_BLACK, [0, 0, 0]], [Ncurses::COLOR_RED, [1, 0, 0]],
[Ncurses::COLOR_GREEN, [0, 1, 0]], [Ncurses::COLOR_BLUE, [0, 0, 1]],
[Ncurses::COLOR_YELLOW, [1, 1, 0]], [Ncurses::COLOR_MAGENTA, [1, 0, 1]],
[Ncurses::COLOR_CYAN, [0, 1, 1]], [Ncurses::COLOR_WHITE, [1, 1, 1]]]

GRADIENT = [[0, ' '], [50, ':'], [100, '|'], [150, 'I'], [200, '#']]
COLORMAP = {}

COLORS.size.times do |bg|
COLORS.size.times do |fg|
next if fg == bg
i = (bg*COLORS.size) + fg
Ncurses.init_pair(i, COLORS[fg][0], COLORS[bg][0])
GRADIENT.each do |gr, c|
r = COLORS[fg][1][0] * gr + COLORS[bg][1][0] * (255-gr)
g = COLORS[fg][1][1] * gr + COLORS[bg][1][1] * (255-gr)
b = COLORS[fg][1][2] * gr + COLORS[bg][1][2] * (255-gr)
COLORMAP[[r, g, b]] = [i, c]
end
end
end

#(16*16*4).times do |i|
# Ncurses.stdscr.attrset(Ncurses.COLOR_PAIR(i))
# Ncurses.stdscr.mvaddstr(i/16, (i%16)*4, 'TEST')
#end
#Ncurses.refresh

pixels = img.get_pixels(0, 0, img.columns, img.rows)
img.rows.times do |y|
img.columns.times do |x|
p = pixels[y*img.columns + x]
r, g, b, best, dist = p.red, p.green, p.blue, -1, 255
COLORMAP.each do |k, v|
d = Math.sqrt((r-k[0])**2 + (g-k[1])**2 + (b-k[2])**2)
(best, dist = v, d) if d < dist
end
Ncurses.stdscr.attrset(Ncurses.COLOR_PAIR(best[0]))
Ncurses.stdscr.mvaddstr(y, x, best[1])
end
end

Ncurses.refresh
-----------------------------------------------------------------------

maybe someone can help..

cheers

Simon
 
Ad

Advertisements

H

Harold Hausman

------=_Part_4998_28661170.1129080179787
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hi,

Best quiz yet. Er, well, quiz which held my attention longest anyway. :)

My solution is um, less... elegant, than some of the others, but in a lot o=
f
ways, like a parent who mistakenly thinks their ugly child is cute I kinda
like it. I don't really share my code a lot (maybe for obvious reasons) but
I'm just so pleased with how easily ruby lets me hack things to high heaven
and this one in particular makes me smile. Take special note that it only
works on 24 bit .bmp files and put your hard hat on if you think you're
going to feed anything but that into it. ;) Okay, enough blather, without
further ado, the first code I've shared with you guys:

#It only supports 24bit bmp files, and it even chokes on most of them ;)
#It creates one character per pixel (which has obvious implications)
#But it's 40 lines of pure ruby no lib use binary file up-hackery...
#And quite frankly, thats what I do.

MyPixel =3D Struct.new( 'MyPixel', :r, :g, :b )

the_gradient =3D %w|D Y 8 S 6 5 J j t c + i ! ; : .|
###############PUT YOUR FILENAME
HERE#########################################
the_file =3D File.new('ducky.bmp', 'rb')
the_file.read(2) #BM
the_file.read(4).unpack('V')[0] #filesize
the_file.read(4) #unused
the_file.read(4).unpack('V')[0] #offset from beginning to bitmap data
the_file.read(4).unpack('V')[0] #size of bitmap header
image_x =3D the_file.read(4).unpack('V')[0] #width x in pixels
image_y =3D the_file.read(4).unpack('V')[0] #height y in pixels
the_file.read(2).unpack('v')[0] #planes?
the_file.read(2).unpack('v')[0] #bits per pixel
the_file.read(24) #unused

the_bitmap =3D []
puts "CRRRRUNCHHHH --- please wait, reading file..."
image_y.times do |row|
the_bitmap[row] =3D []
image_x.times do |col|
the_bitmap[row][col] =3D MyPixel.new( 0, 0, 0 )
the_bitmap[row][col].b =3D the_file.read(1).unpack('c')[0]
the_bitmap[row][col].g =3D the_file.read(1).unpack('c')[0]
the_bitmap[row][col].r =3D the_file.read(1).unpack('c')[0]
end
end

puts "output coming:"
the_output =3D File.new('output.asciiart', 'w')
(image_y-1).downto(0) do |row|
image_x.times do |col|
the_avg =3D
(the_bitmap[row][col].b+the_bitmap[row][col].g+the_bitmap[row][col].r)/3
the_output.write(the_gradient[the_avg>>4])
end
the_output.write("\n")
end

------=_Part_4998_28661170.1129080179787--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top