coloration 0.3.3 → 0.4.0

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.
@@ -0,0 +1,314 @@
1
+ #--
2
+ # Colour management with Ruby.
3
+ #
4
+ # Copyright 2005 Austin Ziegler
5
+ # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: rgb.rb,v 1.6 2005/08/08 02:44:17 austin Exp $
10
+ #++
11
+
12
+ # An RGB colour object.
13
+ class Color::RGB
14
+ # The format of a DeviceRGB colour for PDF. In color-tools 2.0 this will
15
+ # be removed from this package and added back as a modification by the
16
+ # PDF::Writer package.
17
+ PDF_FORMAT_STR = "%.3f %.3f %.3f %s"
18
+
19
+ class << self
20
+ # Creates an RGB colour object from percentages 0..100.
21
+ #
22
+ # Color::RGB.from_percentage(10, 20 30)
23
+ def from_percentage(r = 0, g = 0, b = 0)
24
+ from_fraction(r / 100.0, g / 100.0, b / 100.0)
25
+ end
26
+
27
+ # Creates an RGB colour object from fractional values 0..1.
28
+ #
29
+ # Color::RGB.from_fraction(.3, .2, .1)
30
+ def from_fraction(r = 0.0, g = 0.0, b = 0.0)
31
+ colour = Color::RGB.new
32
+ colour.r = r
33
+ colour.g = g
34
+ colour.b = b
35
+ colour
36
+ end
37
+
38
+ # Creates an RGB colour object from an HTML colour descriptor (e.g.,
39
+ # <tt>"fed"</tt> or <tt>"#cabbed;"</tt>.
40
+ #
41
+ # Color::RGB.from_html("fed")
42
+ # Color::RGB.from_html("#fed")
43
+ # Color::RGB.from_html("#cabbed")
44
+ # Color::RGB.from_html("cabbed")
45
+ def from_html(html_colour)
46
+ html_colour = html_colour.gsub(%r{[#;]}, '')
47
+
48
+ case html_colour.size
49
+ when 0
50
+ return
51
+ when 3
52
+ colours = html_colour.scan(%r{[0-9A-Fa-f]}).map { |el| (el * 2).to_i(16) }
53
+ when 6
54
+ colours = html_colour.scan(%r<[0-9A-Fa-f]{2}>).map { |el| el.to_i(16) }
55
+ else
56
+ raise ArgumentError
57
+ end
58
+
59
+ Color::RGB.new(*colours)
60
+ end
61
+ end
62
+
63
+ # Compares the other colour to this one. The other colour will be
64
+ # converted to RGB before comparison, so the comparison between a RGB
65
+ # colour and a non-RGB colour will be approximate and based on the other
66
+ # colour's default #to_rgb conversion. If there is no #to_rgb
67
+ # conversion, this will raise an exception. This will report that two
68
+ # RGB colours are equivalent if all component values are within 1e-4
69
+ # (0.0001) of each other.
70
+ def ==(other)
71
+ other = other.to_rgb
72
+ other.kind_of?(Color::RGB) and
73
+ ((@r - other.r).abs <= 1e-4) and
74
+ ((@g - other.g).abs <= 1e-4) and
75
+ ((@b - other.b).abs <= 1e-4)
76
+ end
77
+
78
+ # Creates an RGB colour object from the standard range 0..255.
79
+ #
80
+ # Color::RGB.new(32, 64, 128)
81
+ # Color::RGB.new(0x20, 0x40, 0x80)
82
+ def initialize(r = 0, g = 0, b = 0)
83
+ @r = r / 255.0
84
+ @g = g / 255.0
85
+ @b = b / 255.0
86
+ end
87
+
88
+ # Present the colour as a DeviceRGB fill colour string for PDF. This
89
+ # will be removed from the default package in color-tools 2.0.
90
+ def pdf_fill
91
+ PDF_FORMAT_STR % [ @r, @g, @b, "rg" ]
92
+ end
93
+
94
+ # Present the colour as a DeviceRGB stroke colour string for PDF. This
95
+ # will be removed from the default package in color-tools 2.0.
96
+ def pdf_stroke
97
+ PDF_FORMAT_STR % [ @r, @g, @b, "RG" ]
98
+ end
99
+
100
+ # Present the colour as an HTML/CSS colour string.
101
+ def html
102
+ r = (@r * 255).round
103
+ r = 255 if r > 255
104
+
105
+ g = (@g * 255).round
106
+ g = 255 if g > 255
107
+
108
+ b = (@b * 255).round
109
+ b = 255 if b > 255
110
+
111
+ "#%02x%02x%02x" % [ r, g, b ]
112
+ end
113
+
114
+ # Converts the RGB colour to CMYK. Most colour experts strongly suggest
115
+ # that this is not a good idea (some even suggesting that it's a very
116
+ # bad idea). CMYK represents additive percentages of inks on white
117
+ # paper, whereas RGB represents mixed colour intensities on a black
118
+ # screen.
119
+ #
120
+ # However, the colour conversion can be done. The basic method is
121
+ # multi-step:
122
+ #
123
+ # 1. Convert the R, G, and B components to C, M, and Y components.
124
+ # c = 1.0 � r
125
+ # m = 1.0 � g
126
+ # y = 1.0 � b
127
+ # 2. Compute the minimum amount of black (K) required to smooth the
128
+ # colour in inks.
129
+ # k = min(c, m, y)
130
+ # 3. Perform undercolour removal on the C, M, and Y components of the
131
+ # colours because less of each colour is needed for each bit of
132
+ # black. Also, regenerate the black (K) based on the undercolour
133
+ # removal so that the colour is more accurately represented in ink.
134
+ # c = min(1.0, max(0.0, c � UCR(k)))
135
+ # m = min(1.0, max(0.0, m � UCR(k)))
136
+ # y = min(1.0, max(0.0, y � UCR(k)))
137
+ # k = min(1.0, max(0.0, BG(k)))
138
+ #
139
+ # The undercolour removal function and the black generation functions
140
+ # return a value based on the brightness of the RGB colour.
141
+ def to_cmyk
142
+ c = 1.0 - @r.to_f
143
+ m = 1.0 - @g.to_f
144
+ y = 1.0 - @b.to_f
145
+
146
+ k = [c, m, y].min
147
+ k = k - (k * brightness)
148
+
149
+ c = [1.0, [0.0, c - k].max].min
150
+ m = [1.0, [0.0, m - k].max].min
151
+ y = [1.0, [0.0, y - k].max].min
152
+ k = [1.0, [0.0, k].max].min
153
+
154
+ Color::CMYK.from_fraction(c, m, y, k)
155
+ end
156
+
157
+ def to_rgb(ignored = nil)
158
+ self
159
+ end
160
+
161
+ # Returns the YIQ (NTSC) colour encoding of the RGB value.
162
+ def to_yiq
163
+ y = (@r * 0.299) + (@g * 0.587) + (@b * 0.114)
164
+ i = (@r * 0.596) + (@g * -0.275) + (@b * -0.321)
165
+ q = (@r * 0.212) + (@g * -0.523) + (@b * 0.311)
166
+ Color::YIQ.from_fraction(y, i, q)
167
+ end
168
+
169
+ # Returns the HSL colour encoding of the RGB value.
170
+ def to_hsl
171
+ min = [ @r, @g, @b ].min
172
+ max = [ @r, @g, @b ].max
173
+ delta = (max - min).to_f
174
+
175
+ lum = (max + min) / 2.0
176
+
177
+ if delta <= 1e-5 # close to 0.0, so it's a grey
178
+ hue = 0
179
+ sat = 0
180
+ else
181
+ if (lum - 0.5) <= 1e-5
182
+ sat = delta / (max + min).to_f
183
+ else
184
+ sat = delta / (2 - max - min).to_f
185
+ end
186
+
187
+ if @r == max
188
+ hue = (@g - @b) / delta.to_f
189
+ elsif @g == max
190
+ hue = (2.0 + @b - @r) / delta.to_f
191
+ elsif (@b - max) <= 1e-5
192
+ hue = (4.0 + @r - @g) / delta.to_f
193
+ end
194
+ hue /= 6.0
195
+
196
+ hue += 1 if hue < 0
197
+ hue -= 1 if hue > 1
198
+ end
199
+ Color::HSL.from_fraction(hue, sat, lum)
200
+ end
201
+
202
+ # Mix the RGB hue with White so that the RGB hue is the specified
203
+ # percentage of the resulting colour. Strictly speaking, this isn't a
204
+ # darken_by operation.
205
+ def lighten_by(percent)
206
+ mix_with(White, percent)
207
+ end
208
+
209
+ # Mix the RGB hue with Black so that the RGB hue is the specified
210
+ # percentage of the resulting colour. Strictly speaking, this isn't a
211
+ # darken_by operation.
212
+ def darken_by(percent)
213
+ mix_with(Black, percent)
214
+ end
215
+
216
+ # Mix the mask colour (which must be an RGB object) with the current
217
+ # colour at the stated opacity percentage (0..100).
218
+ def mix_with(mask, opacity)
219
+ opacity /= 100.0
220
+ rgb = self.dup
221
+
222
+ rgb.r = (@r * opacity) + (mask.r * (1 - opacity))
223
+ rgb.g = (@g * opacity) + (mask.g * (1 - opacity))
224
+ rgb.b = (@b * opacity) + (mask.b * (1 - opacity))
225
+
226
+ rgb
227
+ end
228
+
229
+ # Returns the brightness value for a colour, a number between 0..1.
230
+ # Based on the Y value of YIQ encoding, representing luminosity, or
231
+ # perceived brightness.
232
+ #
233
+ # This may be modified in a future version of color-tools to use the
234
+ # luminosity value of HSL.
235
+ def brightness
236
+ to_yiq.y
237
+ end
238
+ def to_grayscale
239
+ Color::GrayScale.from_fraction(to_hsl.l)
240
+ end
241
+
242
+ alias to_greyscale to_grayscale
243
+
244
+ # Returns a new colour with the brightness adjusted by the specified
245
+ # percentage. Negative percentages will darken the colour; positive
246
+ # percentages will brighten the colour.
247
+ #
248
+ # Color::RGB::DarkBlue.adjust_brightness(10)
249
+ # Color::RGB::DarkBlue.adjust_brightness(-10)
250
+ def adjust_brightness(percent)
251
+ percent /= 100.0
252
+ percent += 1.0
253
+ percent = [ percent, 2.0 ].min
254
+ percent = [ 0.0, percent ].max
255
+
256
+ hsl = to_hsl
257
+ hsl.l *= percent
258
+ hsl.to_rgb
259
+ end
260
+
261
+ # Returns a new colour with the saturation adjusted by the specified
262
+ # percentage. Negative percentages will reduce the saturation; positive
263
+ # percentages will increase the saturation.
264
+ #
265
+ # Color::RGB::DarkBlue.adjust_saturation(10)
266
+ # Color::RGB::DarkBlue.adjust_saturation(-10)
267
+ def adjust_saturation(percent)
268
+ percent /= 100.0
269
+ percent += 1.0
270
+ percent = [ percent, 2.0 ].min
271
+ percent = [ 0.0, percent ].max
272
+
273
+ hsl = to_hsl
274
+ hsl.s *= percent
275
+ hsl.to_rgb
276
+ end
277
+
278
+ # Returns a new colour with the hue adjusted by the specified
279
+ # percentage. Negative percentages will reduce the hue; positive
280
+ # percentages will increase the hue.
281
+ #
282
+ # Color::RGB::DarkBlue.adjust_hue(10)
283
+ # Color::RGB::DarkBlue.adjust_hue(-10)
284
+ def adjust_hue(percent)
285
+ percent /= 100.0
286
+ percent += 1.0
287
+ percent = [ percent, 2.0 ].min
288
+ percent = [ 0.0, percent ].max
289
+
290
+ hsl = to_hsl
291
+ hsl.h *= percent
292
+ hsl.to_rgb
293
+ end
294
+
295
+ attr_accessor :r, :g, :b
296
+ remove_method :r=, :g=, :b= ;
297
+ def r=(rr) #:nodoc:
298
+ rr = 1.0 if rr > 1
299
+ rr = 0.0 if rr < 0
300
+ @r = rr
301
+ end
302
+ def g=(gg) #:nodoc:
303
+ gg = 1.0 if gg > 1
304
+ gg = 0.0 if gg < 0
305
+ @g = gg
306
+ end
307
+ def b=(bb) #:nodoc:
308
+ bb = 1.0 if bb > 1
309
+ bb = 0.0 if bb < 0
310
+ @b = bb
311
+ end
312
+ end
313
+
314
+ require 'coloration/color/rgb-colors'
@@ -0,0 +1,28 @@
1
+ #--
2
+ # Colour management with Ruby.
3
+ #
4
+ # Copyright 2005 Austin Ziegler
5
+ # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: metallic.rb,v 1.1 2005/08/05 23:07:20 austin Exp $
10
+ #++
11
+
12
+ # This namespace contains some RGB metallic colours suggested by Jim Freeze.
13
+ module Color::RGB::Metallic
14
+ Aluminum = Color::RGB.new(0x99, 0x99, 0x99)
15
+ CoolCopper = Color::RGB.new(0xd9, 0x87, 0x19)
16
+ Copper = Color::RGB.new(0xb8, 0x73, 0x33)
17
+ Iron = Color::RGB.new(0x4c, 0x4c, 0x4c)
18
+ Lead = Color::RGB.new(0x19, 0x19, 0x19)
19
+ Magnesium = Color::RGB.new(0xb3, 0xb3, 0xb3)
20
+ Mercury = Color::RGB.new(0xe6, 0xe6, 0xe6)
21
+ Nickel = Color::RGB.new(0x80, 0x80, 0x80)
22
+ PolySilicon = Color::RGB.new(0x60, 0x00, 0x00)
23
+ Poly = PolySilicon
24
+ Silver = Color::RGB.new(0xcc, 0xcc, 0xcc)
25
+ Steel = Color::RGB.new(0x66, 0x66, 0x66)
26
+ Tin = Color::RGB.new(0x7f, 0x7f, 0x7f)
27
+ Tungsten = Color::RGB.new(0x33, 0x33, 0x33)
28
+ end
@@ -0,0 +1,78 @@
1
+ #--
2
+ # Colour management with Ruby.
3
+ #
4
+ # Copyright 2005 Austin Ziegler
5
+ # http://rubyforge.org/ruby-pdf/
6
+ #
7
+ # Licensed under a MIT-style licence.
8
+ #
9
+ # $Id: yiq.rb,v 1.3 2005/08/08 02:44:17 austin Exp $
10
+ #++
11
+
12
+ # A colour object representing YIQ (NTSC) colour encoding.
13
+ class Color::YIQ
14
+ # Creates a YIQ colour object from fractional values 0 .. 1.
15
+ #
16
+ # Color::YIQ.new(0.3, 0.2, 0.1)
17
+ def self.from_fraction(y = 0, i = 0, q = 0)
18
+ color = Color::YIQ.new
19
+ color.y = y
20
+ color.i = i
21
+ color.q = q
22
+ color
23
+ end
24
+
25
+ # Creates a YIQ colour object from percentages 0 .. 100.
26
+ #
27
+ # Color::YIQ.new(10, 20, 30)
28
+ def initialize(y = 0, i = 0, q = 0)
29
+ @y = y / 100.0
30
+ @i = i / 100.0
31
+ @q = q / 100.0
32
+ end
33
+
34
+ # Compares the other colour to this one. The other colour will be
35
+ # converted to YIQ before comparison, so the comparison between a YIQ
36
+ # colour and a non-YIQ colour will be approximate and based on the other
37
+ # colour's #to_yiq conversion. If there is no #to_yiq conversion, this
38
+ # will raise an exception. This will report that two YIQ values are
39
+ # equivalent if all component colours are within 1e-4 (0.0001) of each
40
+ # other.
41
+ def ==(other)
42
+ other = other.to_yiq
43
+ other.kind_of?(Color::YIQ) and
44
+ ((@y - other.y).abs <= 1e-4) and
45
+ ((@i - other.i).abs <= 1e-4) and
46
+ ((@q - other.q).abs <= 1e-4)
47
+ end
48
+
49
+ def to_yiq
50
+ self
51
+ end
52
+
53
+ def brightness
54
+ @y
55
+ end
56
+ def to_grayscale
57
+ Color::GrayScale.new(@y)
58
+ end
59
+ alias to_greyscale to_grayscale
60
+
61
+ attr_accessor :y, :i, :q
62
+ remove_method :y=, :i=, :q=
63
+ def y=(yy) #:nodoc:
64
+ yy = 1.0 if yy > 1
65
+ yy = 0.0 if yy < 0
66
+ @y = yy
67
+ end
68
+ def i=(ii) #:nodoc:
69
+ ii = 1.0 if ii > 1
70
+ ii = 0.0 if ii < 0
71
+ @i = ii
72
+ end
73
+ def q=(qq) #:nodoc:
74
+ qq = 1.0 if qq > 1
75
+ qq = 0.0 if qq < 0
76
+ @q = qq
77
+ end
78
+ end
@@ -1,4 +1,6 @@
1
1
  class Color::RGBA < Color::RGB
2
+
3
+ # @param col [String] e.g. '#1a1a1a'
2
4
  def self.from_html(col, bg)
3
5
  if col.size > 7 # we have color with alpha channel
4
6
  alpha = (100 * ((col[-2..-1]).to_i(16) / 255.0)).to_i
@@ -8,4 +10,5 @@ class Color::RGBA < Color::RGB
8
10
  super(col)
9
11
  end
10
12
  end
13
+
11
14
  end
@@ -0,0 +1,86 @@
1
+ module Coloration
2
+
3
+ module Converters
4
+
5
+ class AbstractConverter
6
+
7
+ attr_accessor :name, :ui, :items, :input, :result
8
+
9
+ class << self
10
+ attr_reader :in_theme_type
11
+ end
12
+
13
+ def self.process_cmd_line
14
+ new(ARGV).process
15
+ end
16
+
17
+ def initialize(argv = ARGV)
18
+ @argv = argv
19
+ end
20
+
21
+ def process
22
+ return usage_message unless argv.any?
23
+
24
+ read
25
+
26
+ parse_input
27
+
28
+ build_result
29
+
30
+ write
31
+
32
+ rescue Coloration::Readers::TextMateThemeReader::InvalidThemeError
33
+ invalid_theme_message
34
+
35
+ end
36
+
37
+ protected
38
+
39
+ # @!attribute [r] argv
40
+ # @return [Array<String>]
41
+ attr_reader :argv
42
+
43
+ # @!attribute [r] converter
44
+ # @return [Class]
45
+ attr_reader :converter
46
+
47
+ # @return [String]
48
+ def comment_message
49
+ "Converted from #{in_theme_type} theme #{name} using Coloration " \
50
+ "v#{VERSION} (http://github.com/sickill/coloration)"
51
+ end
52
+
53
+ private
54
+
55
+ def in_theme_filename
56
+ argv[0]
57
+ end
58
+
59
+ def invalid_theme_message
60
+ STDERR.puts "Err: given file doesn't look like xml plist file " \
61
+ "containing Textmate theme"
62
+ end
63
+
64
+ def out_theme_filename
65
+ argv[1] || in_theme_filename.
66
+ gsub(/\.#{in_theme_ext}$/, ".#{out_theme_ext}")
67
+ end
68
+
69
+ def read
70
+ @input = File.read(in_theme_filename)
71
+ end
72
+
73
+ def usage_message
74
+ STDOUT.puts "#{File.basename($0)} <in #{in_theme_type} theme> [out " \
75
+ "#{out_theme_type} theme]"
76
+ end
77
+
78
+ def write
79
+ @output = File.open(out_theme_filename, 'w') { |f| f.write(result) }
80
+ end
81
+
82
+ end # AbstractConverter
83
+
84
+ end # Converters
85
+
86
+ end # Coloration