ascii_paint 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/data/block_characters/0.txt +5 -0
  3. data/data/block_characters/1.txt +5 -0
  4. data/data/block_characters/2.txt +5 -0
  5. data/data/block_characters/3.txt +5 -0
  6. data/data/block_characters/4.txt +5 -0
  7. data/data/block_characters/5.txt +5 -0
  8. data/data/block_characters/6.txt +5 -0
  9. data/data/block_characters/7.txt +5 -0
  10. data/data/block_characters/8.txt +5 -0
  11. data/data/block_characters/9.txt +5 -0
  12. data/data/block_characters/A.txt +5 -0
  13. data/data/block_characters/B.txt +5 -0
  14. data/data/block_characters/C.txt +5 -0
  15. data/data/block_characters/D.txt +5 -0
  16. data/data/block_characters/E.txt +5 -0
  17. data/data/block_characters/F.txt +5 -0
  18. data/data/block_characters/G.txt +5 -0
  19. data/data/block_characters/H.txt +5 -0
  20. data/data/block_characters/I.txt +5 -0
  21. data/data/block_characters/J.txt +5 -0
  22. data/data/block_characters/K.txt +5 -0
  23. data/data/block_characters/L.txt +5 -0
  24. data/data/block_characters/M.txt +5 -0
  25. data/data/block_characters/N.txt +5 -0
  26. data/data/block_characters/O.txt +5 -0
  27. data/data/block_characters/P.txt +5 -0
  28. data/data/block_characters/Q.txt +5 -0
  29. data/data/block_characters/R.txt +5 -0
  30. data/data/block_characters/S.txt +5 -0
  31. data/data/block_characters/T.txt +5 -0
  32. data/data/block_characters/U.txt +5 -0
  33. data/data/block_characters/V.txt +5 -0
  34. data/data/block_characters/W.txt +5 -0
  35. data/data/block_characters/X.txt +5 -0
  36. data/data/block_characters/Y.txt +5 -0
  37. data/data/block_characters/Z.txt +5 -0
  38. data/lib/ascii_paint.rb +113 -0
  39. data/lib/ascii_paint/block_character.rb +85 -0
  40. data/lib/ascii_paint/block_string.rb +49 -0
  41. data/lib/ascii_paint/config.rb +197 -0
  42. data/lib/ascii_paint/version.rb +3 -0
  43. data/spec/ascii_paint_spec.rb +108 -0
  44. data/spec/block_string_spec.rb +75 -0
  45. data/spec/fixtures/ascii.txt +2 -0
  46. data/spec/spec_helper.rb +54 -0
  47. metadata +135 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: 07fb319a0666e394fce07cca879a6d3c16cf81c9
4
+ data.tar.gz: 07e594e70ac58ebd656b72dabcbda59f2ae3e03b
5
+ !binary "U0hBNTEy":
6
+ metadata.gz: 5e952740658a8fec7f020877d6d2e66e5bdf4bd5d370a2cd2ce507fa4b3f97179b093bf24894e509a2206377614a384c3488f34e4b98e866ca2a0e53fbb3eb76
7
+ data.tar.gz: 4bef3c9a2cc135a6646c7ce6abd52fdee20cb568828b68ffee032f6ebb6ec4b28f71af91665c81e55b7f04b3b439e2b39b8cd61a003c529a3f4b20cd34bad8a0
@@ -0,0 +1,5 @@
1
+ 000
2
+ 0 00
3
+ 0 0 0
4
+ 00 0
5
+ 000
@@ -0,0 +1,5 @@
1
+ 11
2
+ 1
3
+ 1
4
+ 1
5
+ 1
@@ -0,0 +1,5 @@
1
+ 222
2
+ 2 2
3
+ 2
4
+ 22
5
+ 22222
@@ -0,0 +1,5 @@
1
+ 3333
2
+ 3
3
+ 33
4
+ 3
5
+ 3333
@@ -0,0 +1,5 @@
1
+ 4 4
2
+ 4 4
3
+ 44444
4
+ 4
5
+ 4
@@ -0,0 +1,5 @@
1
+ 55555
2
+ 5
3
+ 5555
4
+ 5
5
+ 5555
@@ -0,0 +1,5 @@
1
+ 66666
2
+ 6
3
+ 66666
4
+ 6 6
5
+ 66666
@@ -0,0 +1,5 @@
1
+ 77777
2
+ 7
3
+ 7
4
+ 7
5
+ 7
@@ -0,0 +1,5 @@
1
+ 888
2
+ 8 8
3
+ 888
4
+ 8 8
5
+ 888
@@ -0,0 +1,5 @@
1
+ 99999
2
+ 9 9
3
+ 99999
4
+ 9
5
+ 9
@@ -0,0 +1,5 @@
1
+ AAAAA
2
+ A A
3
+ AAAAA
4
+ A A
5
+ A A
@@ -0,0 +1,5 @@
1
+ BBBB
2
+ B B
3
+ BBBB
4
+ B B
5
+ BBBB
@@ -0,0 +1,5 @@
1
+ CCCC
2
+ C
3
+ C
4
+ C
5
+ CCCC
@@ -0,0 +1,5 @@
1
+ DDDD
2
+ D D
3
+ D D
4
+ D D
5
+ DDDD
@@ -0,0 +1,5 @@
1
+ EEEEE
2
+ E
3
+ EEEE
4
+ E
5
+ EEEEE
@@ -0,0 +1,5 @@
1
+ FFFFF
2
+ F
3
+ FFFF
4
+ F
5
+ F
@@ -0,0 +1,5 @@
1
+ GGGGG
2
+ G
3
+ G GGG
4
+ G G
5
+ GGGGG
@@ -0,0 +1,5 @@
1
+ H H
2
+ H H
3
+ HHHHH
4
+ H H
5
+ H H
@@ -0,0 +1,5 @@
1
+ IIIII
2
+ I
3
+ I
4
+ I
5
+ IIIII
@@ -0,0 +1,5 @@
1
+ JJJJJ
2
+ J
3
+ J
4
+ J J
5
+ JJJJ
@@ -0,0 +1,5 @@
1
+ K K
2
+ K K
3
+ KKK
4
+ K K
5
+ K K
@@ -0,0 +1,5 @@
1
+ L
2
+ L
3
+ L
4
+ L
5
+ LLLLL
@@ -0,0 +1,5 @@
1
+ MMMMM
2
+ M M M
3
+ M M M
4
+ M M
5
+ M M
@@ -0,0 +1,5 @@
1
+ N N
2
+ NN N
3
+ N N N
4
+ N NN
5
+ N N
@@ -0,0 +1,5 @@
1
+ OOOOO
2
+ O O
3
+ O O
4
+ O O
5
+ OOOOO
@@ -0,0 +1,5 @@
1
+ PPPPP
2
+ P P
3
+ PPPPP
4
+ P
5
+ P
@@ -0,0 +1,5 @@
1
+ QQQQ
2
+ Q Q
3
+ Q Q
4
+ QQQQ
5
+ QQQ
@@ -0,0 +1,5 @@
1
+ RRRR
2
+ R R
3
+ RRRR
4
+ R R
5
+ R R
@@ -0,0 +1,5 @@
1
+ SSSS
2
+ S
3
+ SSS
4
+ S
5
+ SSSS
@@ -0,0 +1,5 @@
1
+ TTTTT
2
+ T
3
+ T
4
+ T
5
+ T
@@ -0,0 +1,5 @@
1
+ U U
2
+ U U
3
+ U U
4
+ U U
5
+ UUU
@@ -0,0 +1,5 @@
1
+ V V
2
+ V V
3
+ V V
4
+ V V
5
+ V
@@ -0,0 +1,5 @@
1
+ W W
2
+ W W
3
+ W W W
4
+ W W W
5
+ W W
@@ -0,0 +1,5 @@
1
+ X X
2
+ X X
3
+ X
4
+ X X
5
+ X X
@@ -0,0 +1,5 @@
1
+ Y Y
2
+ Y Y
3
+ YYY
4
+ Y
5
+ Y
@@ -0,0 +1,5 @@
1
+ ZZZZZ
2
+ Z
3
+ Z
4
+ Z
5
+ ZZZZZ
@@ -0,0 +1,113 @@
1
+ require 'bundler/setup'
2
+ require 'chunky_png'
3
+
4
+ module AsciiPaint
5
+
6
+ # Exception raised when ASCII paint encounters a character without a paint
7
+ # color specified.
8
+ class CharacterNotFound < Exception; end
9
+
10
+ # Paints a PNG based on the given ASCII art.
11
+ #
12
+ # Example:
13
+ # text = "
14
+ # !!!!! @@@@@ $$$$$ %%%%% ^^^^^ @@@@@ $$$$$ %%%%% ^ ^ !!!!!
15
+ # ! ! @ $ % ^ @ @ $ $ % ^^ ^ !
16
+ # !!!!! @@@@@ $ % ^ @@@@@ $$$$$ % ^ ^ ^ !
17
+ # ! ! @ $ % ^ @ $ $ % ^ ^^ !
18
+ # ! ! @@@@@ $$$$$ %%%%% ^^^^^ !!!!! @ $ $ %%%%% ^ ^ !
19
+ # "
20
+ #
21
+ # AsciiPaint.paint(text, 'out.png')
22
+ #
23
+ # @param ascii_art [#to_s, Array<String>]
24
+ # multiline string, string array or filename with the ASCII art to paint
25
+ # @param out_filename [#to_s]
26
+ # the name of the painted PNG file
27
+ # @param conf [Hash<Symbol, value>]
28
+ # configuration settings. Keys should be the names of attributes of
29
+ # {AsciiPaint::Config}, such as +:character_height+.
30
+ # @return [String]
31
+ # the name of the painted PNG file
32
+ def self.paint(ascii_art, out_filename, configuration = {})
33
+ global_configuration = self.config
34
+ local_configuration = global_configuration.dup.set_options(configuration)
35
+
36
+ ascii_array = ascii_art_to_array(ascii_art)
37
+ image = ascii_to_image(ascii_array, local_configuration)
38
+ save_image(image, out_filename, local_configuration)
39
+
40
+ if block_given?
41
+ begin
42
+ yield out_filename
43
+ ensure
44
+ FileUtils.rm(out_filename)
45
+ end
46
+
47
+ true
48
+ else
49
+ out_filename
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def self.ascii_art_to_array(ascii_art)
56
+ return ascii_art if ascii_art.is_a? Array
57
+
58
+ ascii_art = ascii_art.to_s.split("\n")
59
+ if ascii_art.size == 1
60
+ ascii_art = File.open(ascii_art[0], 'r').to_a.map(&:chomp)
61
+ end
62
+ ascii_art
63
+ end
64
+
65
+ def self.ascii_to_image(ascii_array, configuration)
66
+ colors_grid = ascii_to_colors(ascii_array, configuration)
67
+ image = blank_image(ascii_array, configuration)
68
+ painted_image(image, colors_grid, configuration)
69
+ end
70
+
71
+ def self.blank_image(lines, configuration)
72
+ height = lines.size
73
+ width = lines.map(&:size).max
74
+
75
+ width_pixels, height_pixels = configuration.characters_to_pixels(width, height)
76
+ png = ChunkyPNG::Image.new(width_pixels, height_pixels, configuration.color_map[' '])
77
+ end
78
+
79
+ def self.ascii_to_colors(strings, configuration)
80
+ strings.map do |line|
81
+ line.chars.map do |char|
82
+ color = configuration.color_map[char]
83
+ raise AsciiPaint::CharacterNotFound.new "Couldn't find a color mapping for character: #{char}" unless color
84
+ color
85
+ end
86
+ end
87
+ end
88
+
89
+ def self.painted_image(image, color_grid, configuration)
90
+ color_grid.each_with_index do |row, y|
91
+ row.each_with_index do |color, x|
92
+ x_pixels, y_pixels = configuration.characters_to_pixels(x, y)
93
+ width_pixels, height_pixels = configuration.characters_to_pixels(1, 1)
94
+ image.rect(x_pixels, y_pixels, x_pixels + width_pixels, y_pixels + height_pixels, configuration.border_color, color)
95
+ end
96
+ end
97
+
98
+ image
99
+ end
100
+
101
+ def self.save_image(image, filename, _)
102
+ image.save(filename, :interlace => true)
103
+ end
104
+
105
+ def self.root
106
+ Pathname.new(__FILE__).parent.parent
107
+ end
108
+ end
109
+
110
+ require_relative 'ascii_paint/block_character.rb'
111
+ require_relative 'ascii_paint/block_string.rb'
112
+ require_relative 'ascii_paint/config.rb'
113
+ require_relative 'ascii_paint/version.rb'
@@ -0,0 +1,85 @@
1
+ module AsciiPaint
2
+ class BlockCharacter
3
+ attr_reader :ascii
4
+
5
+ # TODO: make customizable
6
+ UNPADDED_HEIGHT = 5
7
+ UNPADDED_WIDTH = 5
8
+ VERTICAL_PADDING = 2
9
+ HORIZONTAL_PADDING = 2
10
+
11
+ def initialize(character)
12
+ raise "Only single characters please! #{character}" unless character.size == 1
13
+
14
+ if character == "\n"
15
+ @newline = true
16
+ return
17
+ end
18
+
19
+ load_ascii(character)
20
+ end
21
+
22
+ def newline?
23
+ !!@newline
24
+ end
25
+
26
+ def to_s
27
+ ascii.join("\n")
28
+ end
29
+
30
+ def self.height
31
+ UNPADDED_HEIGHT + VERTICAL_PADDING
32
+ end
33
+
34
+ def self.width
35
+ UNPADDED_WIDTH + HORIZONTAL_PADDING
36
+ end
37
+
38
+ def self.left_padding
39
+ HORIZONTAL_PADDING / 2
40
+ end
41
+
42
+ def self.right_padding
43
+ (HORIZONTAL_PADDING + 1) / 2
44
+ end
45
+
46
+ def self.top_padding
47
+ VERTICAL_PADDING / 2
48
+ end
49
+
50
+ def self.bottom_padding
51
+ (VERTICAL_PADDING + 1) / 2
52
+ end
53
+
54
+ private
55
+
56
+ # TODO: filename escaping
57
+ def load_ascii(character)
58
+ path = block_characters_dir.join("#{character}.txt")
59
+ if File.exists? path
60
+ @ascii = File.open(path, 'r').to_a.map(&:chomp)
61
+ @ascii = pad_ascii(@ascii)
62
+ else
63
+ raise "Character not supported: #{character}"
64
+ end
65
+ end
66
+
67
+ def pad_ascii(ascii)
68
+ left = " " * self.class.left_padding
69
+ right = " " * self.class.right_padding
70
+ padded = ascii.map do |row|
71
+ "#{left}#{row}#{right}"
72
+ end
73
+
74
+ blank_row = " " * self.class.width
75
+ self.class.top_padding.times { padded.unshift(blank_row) }
76
+ self.class.bottom_padding.times { padded.push(blank_row) }
77
+
78
+ padded
79
+ end
80
+
81
+ def block_characters_dir
82
+ AsciiPaint.root.join('data', 'block_characters')
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,49 @@
1
+ module AsciiPaint
2
+ class BlockString
3
+ attr_reader :block_characters
4
+
5
+ def initialize(string)
6
+ @block_characters = string.chars.map { |char| BlockCharacter.new(char) }
7
+ end
8
+
9
+ def each_row
10
+ return to_enum(:each_row) unless block_given?
11
+
12
+ rows =
13
+ block_characters.chunk do |block_char|
14
+ if block_char.newline?
15
+ nil
16
+ else
17
+ :not_newline
18
+ end
19
+ end.map do |symbol, row|
20
+ row
21
+ end
22
+
23
+ rows.each do |row|
24
+ yield row
25
+ end
26
+ end
27
+
28
+ def to_a
29
+ each_row.flat_map do |block_row|
30
+ (0...BlockCharacter.height).map do |h|
31
+ block_row.inject('') do |string_row, block_char|
32
+ string_row + block_char.ascii[h]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ module AsciiPaint
41
+ # TODO: support filename arguments
42
+ # TODO: write tests
43
+ # TODO: write docs
44
+ def self.block_paint(block_string, out_filename, conf = {}, &block)
45
+ block_string = block_string.join("\n") if block_string.respond_to? :join
46
+ ascii_art = BlockString.new(block_string).to_a
47
+ paint(ascii_art, out_filename, conf, &block)
48
+ end
49
+ end
@@ -0,0 +1,197 @@
1
+ # An instance of class +AsciiPaint::Config+ is used to set global configuration
2
+ # options for ASCII paint. Pass a block to {AsciiPaint.config} to access this
3
+ # object.
4
+
5
+ module AsciiPaint
6
+ class Config
7
+
8
+ TRANSPARENT = ChunkyPNG::Color::TRANSPARENT
9
+ SPECIAL_SYMBOL_MAP = {
10
+ transparent: TRANSPARENT
11
+ }
12
+ private_constant :TRANSPARENT, :SPECIAL_SYMBOL_MAP
13
+
14
+ # The horizontal size in pixels of the rectangle that replaces a single
15
+ # character during painting.
16
+ attr_accessor :character_width
17
+
18
+ # The vertical size in pixels of the rectangle that replaces a single
19
+ # character during painting.
20
+ attr_accessor :character_height
21
+
22
+ attr_accessor :color_map
23
+
24
+ def initialize(settings = {})
25
+ reset!
26
+ set_options(settings)
27
+ end
28
+
29
+ class << self
30
+ alias_method :default, :new
31
+ end
32
+
33
+ # Merge new mappings into the color map.
34
+ #
35
+ # The color map specifies which color paints over each character. For example,
36
+ # config.color_map = { 'a' => :blue }
37
+ # tells ASCII paint to replace the character 'a' with the color blue.
38
+ #
39
+ # @param hash [Hash<String, Symbol>]
40
+ # the new mappings to be merged into the color map.
41
+ # @return [void]
42
+ def color_map=(hash)
43
+ replace_special_symbols!(hash)
44
+ @color_map = color_map.merge(hash)
45
+ end
46
+
47
+ # Set the color to paint over characters whose color hasn't been defined by
48
+ # the color map.
49
+ #
50
+ # @param default_color [Symbol]
51
+ # the default color to replace characters without a specified color.
52
+ # @return [void]
53
+ def color_for_undefined_character=(default_color)
54
+ color_map.default = replacement_for_special_symbol(default_color)
55
+ end
56
+
57
+ def characters_to_pixels(x, y)
58
+ [x * character_width, y * character_height]
59
+ end
60
+
61
+ # Set configuration options using a hash instead of using method calls. For
62
+ # example,
63
+ # config.set_options({character_width: 10})
64
+ # is equivalent to
65
+ # config.character_width = 10
66
+ #
67
+ # @param options [Hash<Symbol, value>]
68
+ # settings mapping from attribute name to value.
69
+ # @return self
70
+ def set_options(options)
71
+ options.each do |key, value|
72
+ mutator_name = "#{key}="
73
+ self.send(mutator_name, value)
74
+ end
75
+ self
76
+ end
77
+
78
+ def border_color
79
+ TRANSPARENT
80
+ end
81
+
82
+ def reset!
83
+ @character_height = Default::CHARACTER_HEIGHT
84
+ @character_width = Default::CHARACTER_WIDTH
85
+ @color_map =
86
+ begin
87
+ map = Default::COLOR_MAP.dup
88
+ map.default = Default::COLOR_FOR_UNDEFINED_CHARACTER
89
+ replace_special_symbols!(map)
90
+ map
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def replace_special_symbols!(hash)
97
+ hash.each do |char, color_sym|
98
+ hash[char] = replacement_for_special_symbol(color_sym)
99
+ end
100
+ end
101
+
102
+ def replacement_for_special_symbol(symbol)
103
+ SPECIAL_SYMBOL_MAP[symbol] || symbol
104
+ end
105
+
106
+ public
107
+
108
+ # Default values for configuration settings.
109
+ module Default
110
+ private
111
+
112
+ def self.rainbow_mapping(characters)
113
+ # Thanks jbum (http://krazydad.com/tutorials/makecolors.php)
114
+ hash = {}
115
+ period = Math::PI * 2
116
+ frequency = period / characters.count
117
+ characters.each_with_index do |char, index|
118
+ r = Math.cos(frequency * index + 0) * 127 + 128;
119
+ g = Math.cos(frequency * index + period / 3) * 127 + 128;
120
+ b = Math.cos(frequency * index + period * 2 / 3) * 127 + 128;
121
+ color = ChunkyPNG::Color.rgb(r.to_i, g.to_i, b.to_i)
122
+ hash[char] = color
123
+ end
124
+ hash
125
+ end
126
+
127
+ public
128
+
129
+ CHARACTER_HEIGHT = 16
130
+ CHARACTER_WIDTH = 8
131
+ COLOR_FOR_UNDEFINED_CHARACTER = :black
132
+ COLOR_MAP =
133
+ begin
134
+ map = {
135
+ ' ' => :transparent,
136
+
137
+ '!' => :red,
138
+ '@' => :orange,
139
+ '#' => :yellow,
140
+ '$' => :green,
141
+ '%' => :blue,
142
+ '^' => :purple,
143
+
144
+ '_' => :white,
145
+ '~' => :black,
146
+
147
+ '<' => :lightgrey,
148
+ '>' => :grey,
149
+ '?' => :darkgrey,
150
+ ',' => :lightslategrey,
151
+ '.' => :slategrey,
152
+ '/' => :darkslategrey,
153
+ '\\' => :dimgrey,
154
+
155
+ ':' => :chocolate,
156
+ ';' => :blanchedalmond,
157
+ '\'' => :coral,
158
+ '"' => :deepskyblue,
159
+ '{' => :indigo,
160
+ '}' => :ivory,
161
+ '[' => :khaki,
162
+ ']' => :lavender,
163
+ '|' => :hotpink,
164
+ '&' => :darksalmon,
165
+ '*' => :lime,
166
+ '(' => :lightyellow,
167
+ ')' => :honeydew,
168
+ '-' => :azure,
169
+ '+' => :crimson,
170
+ '=' => :antiquewhite,
171
+ '`' => :cornsilk
172
+ }
173
+
174
+ letters = ('a'..'z').zip('A'..'Z').flatten # ['a', 'A', 'b', 'B', ...]
175
+ map.merge! rainbow_mapping(letters)
176
+
177
+ numbers = ('0'..'9')
178
+ map.merge! rainbow_mapping(numbers)
179
+
180
+ map
181
+ end
182
+ end
183
+
184
+ end
185
+ end
186
+
187
+ module AsciiPaint
188
+ # Passes an instance of {AsciiPaint::Config} to the given block. Used to set
189
+ # global configuration.
190
+ #
191
+ # @return [Config] the global configuration
192
+ def self.config
193
+ @configuration ||= Config.default
194
+ yield(@configuration) if block_given?
195
+ @configuration
196
+ end
197
+ end
@@ -0,0 +1,3 @@
1
+ module AsciiPaint
2
+ VERSION = '0.2.1'
3
+ end
@@ -0,0 +1,108 @@
1
+ require 'ascii_paint'
2
+ require 'pry'
3
+
4
+ describe AsciiPaint do
5
+
6
+ let(:input_filename) { Helpers.fixtures_directory.join('ascii.txt') }
7
+
8
+ before(:each) do
9
+ Helpers.cd_work_directory
10
+ end
11
+
12
+ after(:each) do
13
+ Helpers.rm_rf_work_directory
14
+ AsciiPaint.config.reset!
15
+ end
16
+
17
+ it "does math good" do
18
+ (1 + 1).should eq(2)
19
+ end
20
+
21
+ it "writes a file" do
22
+ AsciiPaint.paint("ASCII\npaint", OUTPUT_FILENAME)
23
+ File.should be_a_file OUTPUT_FILENAME
24
+ end
25
+
26
+ it "paints the correct dimensions" do
27
+ AsciiPaint.paint("ASCII\npaint", OUTPUT_FILENAME, character_width: 10, character_height: 10)
28
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
29
+ result.height.should eq(2 * 10)
30
+ result.width.should eq(5 * 10)
31
+ end
32
+
33
+ it "paints the correct colors" do
34
+ AsciiPaint.paint("ASCII\npaint", OUTPUT_FILENAME, character_width: 10, color_map: {'S' => :blue})
35
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
36
+ color = result.get_pixel(15, 0)
37
+ red = ChunkyPNG::Color.r(color)
38
+ green = ChunkyPNG::Color.g(color)
39
+ blue = ChunkyPNG::Color.b(color)
40
+ [red, green, blue].should eq([0, 0, 255])
41
+ end
42
+
43
+ it "accepts a multiline string input" do
44
+ multiline_string = "ASCII\npaint"
45
+ AsciiPaint.paint(multiline_string, OUTPUT_FILENAME, character_width: 10, character_height: 10)
46
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
47
+ result.height.should eq(2 * 10)
48
+ result.width.should eq(5 * 10)
49
+ end
50
+
51
+ it "accepts a string array input" do
52
+ string_array = ["ASCII", "paint"]
53
+ AsciiPaint.paint(string_array, OUTPUT_FILENAME, character_width: 10, character_height: 10)
54
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
55
+ result.height.should eq(2 * 10)
56
+ result.width.should eq(5 * 10)
57
+ end
58
+
59
+ it "accepts a filename input" do
60
+ AsciiPaint.paint(input_filename, OUTPUT_FILENAME, character_width: 10, character_height: 10)
61
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
62
+ result.height.should eq(2 * 10)
63
+ result.width.should eq(5 * 10)
64
+ end
65
+
66
+ it "obeys AsciiPaint.config configuration" do
67
+ AsciiPaint.config do |config|
68
+ config.character_height = 100
69
+ end
70
+
71
+ AsciiPaint.paint(input_filename, OUTPUT_FILENAME)
72
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
73
+ result.height.should eq(2 * 100)
74
+ end
75
+
76
+ it "obeys per-method-call configuration" do
77
+ AsciiPaint.paint("ASCII\npaint", OUTPUT_FILENAME, character_width: 10, character_height: 10)
78
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
79
+ result.height.should eq(2 * 10)
80
+ result.width.should eq(5 * 10)
81
+ end
82
+
83
+ it "overrides global config with local config" do
84
+ AsciiPaint.config do |config|
85
+ config.character_height = 100
86
+ end
87
+
88
+ AsciiPaint.paint(input_filename, OUTPUT_FILENAME, character_height: 77)
89
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
90
+ result.height.should eq(2 * 77)
91
+ end
92
+
93
+ it "paints transparent paint" do
94
+ AsciiPaint.paint("ASCII\npaint", OUTPUT_FILENAME, character_width: 10, color_map: {'S' => :transparent})
95
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
96
+ color = result.get_pixel(15, 0)
97
+ alpha = ChunkyPNG::Color.a(color)
98
+ alpha.should eq(0)
99
+ end
100
+
101
+ it "deletes temporary files" do
102
+ AsciiPaint.paint("ASCII\npaint", OUTPUT_FILENAME) do |f|
103
+ File.should be_a_file OUTPUT_FILENAME
104
+ end
105
+
106
+ File.should_not be_a_file OUTPUT_FILENAME
107
+ end
108
+ end
@@ -0,0 +1,75 @@
1
+ require 'ascii_paint'
2
+ require 'pry'
3
+
4
+ describe AsciiPaint::BlockString do
5
+
6
+ before(:each) do
7
+ Helpers.cd_work_directory
8
+ end
9
+
10
+ after(:each) do
11
+ Helpers.rm_rf_work_directory
12
+ AsciiPaint.config.reset!
13
+ end
14
+
15
+ it "writes a file" do
16
+ AsciiPaint.block_paint("ASCII", OUTPUT_FILENAME)
17
+ File.should be_a_file OUTPUT_FILENAME
18
+ end
19
+
20
+ it "obeys local configuration" do
21
+ AsciiPaint.block_paint("ASCII", OUTPUT_FILENAME, character_height: 100)
22
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
23
+ result.height.should eq(100 * AsciiPaint::BlockCharacter.height)
24
+ end
25
+
26
+ it "obeys global configuration" do
27
+ AsciiPaint.config do |config|
28
+ config.character_height = 100
29
+ end
30
+
31
+ AsciiPaint.block_paint("ASCII", OUTPUT_FILENAME)
32
+ result = ChunkyPNG::Image.from_file(OUTPUT_FILENAME)
33
+ result.height.should eq(100 * AsciiPaint::BlockCharacter.height)
34
+ end
35
+
36
+ it "deletes temporary files" do
37
+ AsciiPaint.block_paint("ASCII\npaint", OUTPUT_FILENAME) do |f|
38
+ File.should be_a_file OUTPUT_FILENAME
39
+ end
40
+
41
+ File.should_not be_a_file OUTPUT_FILENAME
42
+ end
43
+
44
+ context "data directory" do
45
+ it "has character files of the correct width" do
46
+ Helpers.each_block_character_path do |path|
47
+ File.open(path, 'r') do |file|
48
+ file.each_line do |line|
49
+ line.chomp.size.should eq(AsciiPaint::BlockCharacter::UNPADDED_WIDTH), file.path
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ it "has character files of the correct height" do
56
+ Helpers.each_block_character_path do |path|
57
+ File.open(path, 'r') do |file|
58
+ file.each_line.count.should eq(AsciiPaint::BlockCharacter::UNPADDED_HEIGHT), file.path
59
+ end
60
+ end
61
+ end
62
+
63
+ it "has character files for all alphanumeric characters" do
64
+ desired_characters = ('A'..'Z').to_a + ('0'..'9').to_a
65
+ found_characters = []
66
+
67
+ Helpers.each_block_character_path do |path|
68
+ character = path.to_s.match(/\/(.)\.txt/)[1]
69
+ found_characters << character
70
+ end
71
+
72
+ found_characters.should =~ desired_characters
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,2 @@
1
+ ASCII
2
+ paint
@@ -0,0 +1,54 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
18
+
19
+ require 'ascii_paint'
20
+
21
+ OUTPUT_FILENAME = 'painted.png'
22
+
23
+ module Helpers
24
+ def self.cd_work_directory
25
+ create_work_directory
26
+ Dir.chdir(Helpers.work_directory)
27
+ end
28
+
29
+ def self.rm_rf_work_directory
30
+ Dir.chdir(work_directory.parent)
31
+ FileUtils.rm_rf(Helpers.work_directory)
32
+ end
33
+
34
+ def self.create_work_directory
35
+ FileUtils.mkdir_p(work_directory)
36
+ end
37
+
38
+ def self.work_directory
39
+ AsciiPaint.root.join('tmp', 'spec')
40
+ end
41
+
42
+ def self.fixtures_directory
43
+ AsciiPaint.root.join('spec', 'fixtures')
44
+ end
45
+
46
+ # TODO: split into separate helper
47
+ def self.each_block_character_path
48
+ block_characters_dir = AsciiPaint.root.join('data', 'block_characters')
49
+ block_characters_dir.each_child(false) do |path|
50
+ full_path = block_characters_dir.join(path)
51
+ yield full_path
52
+ end
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ascii_paint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Nate Sullivan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chunky_png
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.9
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.9
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.14.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 2.14.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Convert ASCII art to PNGs in pure Ruby.
56
+ email: nathanielsullivan00+ascii_paint@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/ascii_paint/block_character.rb
62
+ - lib/ascii_paint/block_string.rb
63
+ - lib/ascii_paint/config.rb
64
+ - lib/ascii_paint/version.rb
65
+ - lib/ascii_paint.rb
66
+ - data/block_characters/0.txt
67
+ - data/block_characters/1.txt
68
+ - data/block_characters/2.txt
69
+ - data/block_characters/3.txt
70
+ - data/block_characters/4.txt
71
+ - data/block_characters/5.txt
72
+ - data/block_characters/6.txt
73
+ - data/block_characters/7.txt
74
+ - data/block_characters/8.txt
75
+ - data/block_characters/9.txt
76
+ - data/block_characters/A.txt
77
+ - data/block_characters/B.txt
78
+ - data/block_characters/C.txt
79
+ - data/block_characters/D.txt
80
+ - data/block_characters/E.txt
81
+ - data/block_characters/F.txt
82
+ - data/block_characters/G.txt
83
+ - data/block_characters/H.txt
84
+ - data/block_characters/I.txt
85
+ - data/block_characters/J.txt
86
+ - data/block_characters/K.txt
87
+ - data/block_characters/L.txt
88
+ - data/block_characters/M.txt
89
+ - data/block_characters/N.txt
90
+ - data/block_characters/O.txt
91
+ - data/block_characters/P.txt
92
+ - data/block_characters/Q.txt
93
+ - data/block_characters/R.txt
94
+ - data/block_characters/S.txt
95
+ - data/block_characters/T.txt
96
+ - data/block_characters/U.txt
97
+ - data/block_characters/V.txt
98
+ - data/block_characters/W.txt
99
+ - data/block_characters/X.txt
100
+ - data/block_characters/Y.txt
101
+ - data/block_characters/Z.txt
102
+ - spec/ascii_paint_spec.rb
103
+ - spec/block_string_spec.rb
104
+ - spec/fixtures/ascii.txt
105
+ - spec/spec_helper.rb
106
+ homepage: https://github.com/nate00/ascii_paint
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.0.3
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Paint in ASCII!
130
+ test_files:
131
+ - spec/ascii_paint_spec.rb
132
+ - spec/block_string_spec.rb
133
+ - spec/fixtures/ascii.txt
134
+ - spec/spec_helper.rb
135
+ has_rdoc: