| Class | Color::Palette::AdobeColor |
| In: |
lib/color/palette/adobecolor.rb
|
| Parent: | Object |
A class that can read an Adobe Color palette file (used for Photoshop swatches) and provide a Hash-like interface to the contents. Not all colour formats in ACO files are supported. Based largely off the information found by Larry Tesler.
Not all Adobe Color files have named colours; all named entries are returned as an array.
pal = Color::Palette::AdobeColor.from_file(my_aco_palette) pal[0] => Color::RGB<...> pal["white"] => [ Color::RGB<...> ] pal["unknown"] => [ Color::RGB<...>, Color::RGB<...>, ... ]
AdobeColor palettes are always indexable by insertion order (an integer key).
Version 2 palettes use UTF-16 colour names.
| lost | [R] | Contains the "lost" colours in the palette. These colours could not be properly loaded (e.g., L*a*b* is not supported by Color, so it is "lost") or are not understood by the algorithms. |
| statistics | [R] | Returns statistics about the nature of the colours loaded. |
| version | [R] |
Create an AdobeColor palette object from the named file.
# File lib/color/palette/adobecolor.rb, line 39
39: def from_file(filename)
40: File.open(filename, "rb") { |io| Color::Palette::AdobeColor.from_io(io) }
41: end
Create an AdobeColor palette object from the provided IO.
# File lib/color/palette/adobecolor.rb, line 44
44: def from_io(io)
45: Color::Palette::AdobeColor.new(io.read)
46: end
Create a new AdobeColor palette from the palette file as a string.
# File lib/color/palette/adobecolor.rb, line 60
60: def initialize(palette)
61: @colors = []
62: @names = {}
63: @statistics = Hash.new(0)
64: @lost = []
65: @order = []
66: @version = nil
67:
68: class << palette
69: def readwords(count = 1)
70: @offset ||= 0
71: raise IndexError if @offset >= self.size
72: val = self[@offset, count * 2]
73: raise IndexError if val.nil? or val.size < (count * 2)
74: val = val.unpack("n" * count)
75: @offset += count * 2
76: val
77: end
78:
79: def readutf16(count = 1)
80: @offset ||= 0
81: raise IndexError if @offset >= self.size
82: val = self[@offset, count * 2]
83: raise IndexError if val.nil? or val.size < (count * 2)
84: @offset += count * 2
85: val
86: end
87: end
88:
89: @version, count = palette.readwords 2
90:
91: raise "Unknown AdobeColor palette version #@version." unless @version.between?(1, 2)
92:
93: count.times do
94: space, w, x, y, z = palette.readwords 5
95: name = nil
96: if @version == 2
97: raise IndexError unless palette.readwords == [ 0 ]
98: len = palette.readwords
99: name = palette.readutf16(len[0] - 1)
100: raise IndexError unless palette.readwords == [ 0 ]
101: end
102:
103: color = case space
104: when 0 then # RGB
105: @statistics[:rgb] += 1
106:
107: Color::RGB.new(w / 256, x / 256, y / 256)
108: when 1 then # HS[BV] -- Convert to RGB
109: @statistics[:hsb] += 1
110:
111: h = w / 65535.0
112: s = x / 65535.0
113: v = y / 65535.0
114:
115: if defined?(Color::HSB)
116: Color::HSB.from_fraction(h, s, v)
117: else
118: @statistics[:converted] += 1
119: if Color.near_zero_or_less?(s)
120: Color::RGB.from_fraction(v, v, v)
121: else
122: if Color.near_one_or_more?(h)
123: vh = 0
124: else
125: vh = h * 6.0
126: end
127:
128: vi = vh.floor
129: v1 = v.to_f * (1 - s.to_f)
130: v2 = v.to_f * (1 - s.to_f * (vh - vi))
131: v3 = v.to_f * (1 - s.to_f * (1 - (vh - vi)))
132:
133: case vi
134: when 0 then Color::RGB.from_fraction(v, v3, v1)
135: when 1 then Color::RGB.from_fraction(v2, v, v1)
136: when 2 then Color::RGB.from_fraction(v1, v, v3)
137: when 3 then Color::RGB.from_fraction(v1, v2, v)
138: when 4 then Color::RGB.from_fraction(v3, v1, v)
139: else Color::RGB.from_fraction(v, v1, v2)
140: end
141: end
142: end
143: when 2 then # CMYK
144: @statistics[:cmyk] += 1
145: Color::CMYK.from_percent(100 - (w / 655.35),
146: 100 - (x / 655.35),
147: 100 - (y / 655.35),
148: 100 - (z / 655.35))
149: when 7 then # L*a*b*
150: @statistics[:lab] += 1
151:
152: l = [w, 10000].min / 100.0
153: a = [[-12800, UwToSw[x]].max, 12700].min / 100.0
154: b = [[-12800, UwToSw[x]].max, 12700].min / 100.0
155:
156: if defined? Color::Lab
157: Color::Lab.new(l, a, b)
158: else
159: [ space, w, x, y, z ]
160: end
161: when 8 then # Grayscale
162: @statistics[:gray] += 1
163:
164: g = [w, 10000].min / 100.0
165: Color::GrayScale.new(g)
166: when 9 then # Wide CMYK
167: @statistics[:wcmyk] += 1
168:
169: c = [w, 10000].min / 100.0
170: m = [x, 10000].min / 100.0
171: y = [y, 10000].min / 100.0
172: k = [z, 10000].min / 100.0
173: Color::CMYK.from_percent(c, m, y, k)
174: else
175: @statistics[space] += 1
176: [ space, w, x, y, z ]
177: end
178:
179: @order << [ color, name ]
180:
181: if color.kind_of? Array
182: @lost << color
183: else
184: @colors << color
185:
186: if name
187: @names[name] ||= []
188: @names[name] << color
189: end
190: end
191: end
192: end
If a Numeric key is provided, the single colour value at that position will be returned. If a String key is provided, the colour set (an array) for that colour name will be returned.
# File lib/color/palette/adobecolor.rb, line 202
202: def [](key)
203: if key.kind_of?(Numeric)
204: @colors[key]
205: else
206: @names[key]
207: end
208: end