ase-palette 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fefbb045aba878667c779f8cf8a72f21c9c91f919efad22a436bc27594a22a0d
4
+ data.tar.gz: 7bbc45674d4344377fbdda0057fbb0b174c2f9eca06d7c495b50a59889e172cb
5
+ SHA512:
6
+ metadata.gz: e25b1c71ae0192350717faf8fe00cd438ba999cf27f8b70b9ca11547d9d3f103452c426b3fd02c132ef2cd5a9efd5e0db5e33061fef3a287b5a4d43d8a218a3c
7
+ data.tar.gz: 3a3de6e42b122ceb0f9c5db2f7c0c35e285e67af4e96e85645b56b56c57395c4e26f6b4ea9c5c181677de4a493186921acebb1ace0a81698d1f95393c0ce0471
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ *.gem
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.1
7
+ before_install: gem install bundler -v 2.0.1
@@ -0,0 +1,4 @@
1
+ # Changelog
2
+
3
+ `0.9.0`
4
+ - Initial beta version of gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ase_palette.gemspec
4
+ gemspec
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ase-palette (0.9.0)
5
+ bindata (~> 2.4.4)
6
+ hex_string (~> 1.0.1)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ bindata (2.4.4)
12
+ diff-lcs (1.3)
13
+ hex_string (1.0.1)
14
+ rake (11.3.0)
15
+ rspec (3.8.0)
16
+ rspec-core (~> 3.8.0)
17
+ rspec-expectations (~> 3.8.0)
18
+ rspec-mocks (~> 3.8.0)
19
+ rspec-core (3.8.0)
20
+ rspec-support (~> 3.8.0)
21
+ rspec-expectations (3.8.2)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.8.0)
24
+ rspec-mocks (3.8.0)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.8.0)
27
+ rspec-support (3.8.0)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ ase-palette!
34
+ bundler (~> 2.0)
35
+ rake (~> 11.2)
36
+ rspec (~> 3.8)
37
+
38
+ BUNDLED WITH
39
+ 2.0.1
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Sam Becker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,132 @@
1
+ # ASEPalette
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'ase-palette'
9
+ ```
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install ase-palette
18
+
19
+ ## Usage
20
+
21
+ ### Load
22
+
23
+ ```ruby
24
+ require 'ase-palette'
25
+ ```
26
+
27
+ ### Write
28
+
29
+ ```ruby
30
+ # Create palette
31
+ palette = ASEPalette.new
32
+
33
+ # Create color
34
+ color = ASEPalette::Color::RGB.new "Red", 255, 0, 0
35
+
36
+ # Add color to palette
37
+ palette.add_color color
38
+
39
+ # Add color to group
40
+ palette.add_color color, group_name: "Group Name"
41
+ ```
42
+
43
+ ### Read
44
+
45
+ ```ruby
46
+ # Access top-level colors
47
+ palette.colors.each do |color|
48
+ puts "Found color #{color.name}"
49
+ end
50
+
51
+ # Access colors from groups
52
+ palette.groups.each do |group|
53
+ puts "Found group #{group.name}"
54
+ group.colors.each do |color|
55
+ puts "- #{color.name}"
56
+ end
57
+ end
58
+
59
+ # Access all colors, including those from groups, as a flat array
60
+ palette.colors(include_from_groups: true).each do |color|
61
+ puts "Found color #{color.name}, which may or may not belong to a group"
62
+ end
63
+ ```
64
+
65
+ ### Edit
66
+
67
+ ```ruby
68
+ # Remove a color, including those from groups
69
+ palette.remove_color_with_name "Red"
70
+
71
+ # Remove a group and all of the colors it contains
72
+ palette.remove_group_with_name "Group Name"
73
+ ```
74
+
75
+ ### Export
76
+
77
+ ```ruby
78
+ # Store file
79
+ IO.binwrite('palette.ase', palette.to_binary)
80
+
81
+ # Send file (from Rails controller)
82
+ respond_to do |format|
83
+ format.ase {
84
+ send_data palette.to_binary, type: 'application/octet-stream', filename: 'palette.ase'
85
+ }
86
+ end
87
+ ```
88
+
89
+ ### Import [UNDER DEVELOPMENT]
90
+
91
+ ```ruby
92
+ # Open palette from file
93
+ palette = ASEPalette.open('path/to/palette.ase')
94
+
95
+ # Access color
96
+ puts palette.color_with_name "Red"
97
+ # Red, RGB: 255/0/0, :global
98
+
99
+ # Access palette
100
+ puts palette
101
+ # ASEPalette 2.0
102
+ # --------------
103
+ #
104
+ # Red, RGB: 255/0/0, :global
105
+ #
106
+ # Group 1:
107
+ # Violet, RGB: 90/0/255, :global
108
+ # Blue, RGB: 0/0/255, :global
109
+ # Green, RGB: 50/255/50, :global
110
+ # Red, RGB: 240/0/20, :global
111
+ #
112
+ # Group 2
113
+ # Orange CMYK, CMYK: 0/80/100/0, :global
114
+ # Yellow CMYK, CMYK: 0/20/100/0, :global
115
+ #
116
+ # --------------
117
+ # 7 colors, 2 groups
118
+ ```
119
+
120
+ ## Development
121
+
122
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
123
+
124
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
125
+
126
+ ## Contributing
127
+
128
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sambecker/ase-palette.
129
+
130
+ ## License
131
+
132
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,46 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "ase-palette/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ase-palette"
8
+ spec.version = ASEPalette::VERSION
9
+ spec.authors = ["Sam Becker"]
10
+ spec.email = ["sam@sambecker.com"]
11
+
12
+ spec.summary = %q{Create and manage Adobe ASE palettes.}
13
+ spec.description = %q{Read and write Adobe Swatch Exchange files.}
14
+ spec.homepage = "https://github.com/sambecker/ase-palette"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
+ spec.metadata["homepage_uri"] = spec.homepage
22
+ spec.metadata["source_code_uri"] = spec.homepage
23
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/" \
24
+ "blob/master/CHANGELOG.md"
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against " \
27
+ "public gem pushes."
28
+ end
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
33
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ end
35
+ spec.bindir = "exe"
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+ spec.required_ruby_version = ">= 2.5.0"
39
+
40
+ spec.add_dependency "bindata", "~>2.4.4"
41
+ spec.add_dependency "hex_string", "~>1.0.1"
42
+
43
+ spec.add_development_dependency "bundler", "~> 2.0"
44
+ spec.add_development_dependency "rake", "~> 11.2"
45
+ spec.add_development_dependency "rspec", "~> 3.8"
46
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ase_palette"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,16 @@
1
+ require "bindata"
2
+ require "hex_string"
3
+
4
+ require "ase-palette/version"
5
+ require "ase-palette/palette"
6
+ require "ase-palette/palette_binary"
7
+ require "ase-palette/group"
8
+ require "ase-palette/color"
9
+
10
+ module ASEPalette
11
+ class Error < StandardError; end
12
+
13
+ def self.new
14
+ Palette.new
15
+ end
16
+ end
@@ -0,0 +1,89 @@
1
+ module ASEPalette
2
+ DEFAULT_COLOR_TYPE = :global
3
+
4
+ class Color
5
+ # Name cannot changed once a color is created in order to
6
+ # protect the integrity of unique names in a palette
7
+ attr_reader :name
8
+ attr_accessor :type
9
+
10
+ # Get color model
11
+ def model
12
+ self.class.to_s.split('::').last.downcase.to_sym
13
+ end
14
+
15
+ # Convert color to string
16
+ def to_s
17
+ "#{@name}, " \
18
+ "#{model.upcase}: " \
19
+ "#{data.values.join("/")}, " \
20
+ ":#{@type}"
21
+ end
22
+
23
+ # Convert color to hash,
24
+ # necessary for binary representation
25
+ def to_h
26
+ {
27
+ name: @name,
28
+ model: model,
29
+ data: data,
30
+ type: @type,
31
+ }
32
+ end
33
+
34
+ class RGB < Color
35
+ attr_accessor :r, :g, :b
36
+ def initialize(name, r, g, b, type = DEFAULT_COLOR_TYPE)
37
+ @name = name
38
+ @r = r
39
+ @g = g
40
+ @b = b
41
+ @type = type
42
+ end
43
+ def data
44
+ { r: @r, g: @g, b: @b }
45
+ end
46
+ end
47
+
48
+ class CMYK < Color
49
+ attr_accessor :c, :m, :y, :k
50
+ def initialize(name, c, m, y, k, type = DEFAULT_COLOR_TYPE)
51
+ @name = name
52
+ @c = c
53
+ @m = m
54
+ @y = y
55
+ @k = k
56
+ @type = type
57
+ end
58
+ def data
59
+ { c: @c, m: @m, y: @y, k: @k }
60
+ end
61
+ end
62
+
63
+ class LAB < Color
64
+ attr_accessor :l, :a, :b
65
+ def initialize(name, l, a, b, type = DEFAULT_COLOR_TYPE)
66
+ @name = name
67
+ @l = l
68
+ @a = a
69
+ @b = b
70
+ @type = type
71
+ end
72
+ def data
73
+ { l: @l, a: @a, b: @b }
74
+ end
75
+ end
76
+
77
+ class GRAY < Color
78
+ attr_accessor :gray
79
+ def initialize(name, gray, type = DEFAULT_COLOR_TYPE)
80
+ @name = name
81
+ @gray = gray
82
+ @type = type
83
+ end
84
+ def data
85
+ { gray: @gray }
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,39 @@
1
+ module ASEPalette
2
+ class Group
3
+ # Name and colors cannot changed once a group is created in order to
4
+ # protect the integrity of unique names in a palette
5
+ attr_reader :name, :colors
6
+
7
+ # Initialize group
8
+ def initialize(name)
9
+ @name = name
10
+ @colors = []
11
+ end
12
+
13
+ # Convert group to string
14
+ def to_s
15
+ s = "- #{@name}:\n"
16
+ if @colors.length > 0
17
+ @colors.each do |color|
18
+ s += " #{color}\n"
19
+ end
20
+ else
21
+ s += " <empty>\n"
22
+ end
23
+ s
24
+ end
25
+
26
+ # Convert group to hash,
27
+ # necessary for binary representation
28
+ def to_h
29
+ {
30
+ name: @name,
31
+ colors: @colors.map(&:to_h),
32
+ }
33
+ end
34
+
35
+ def remove_color_with_name(name)
36
+ @colors = @colors.select { |color| color.name != name }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,166 @@
1
+ module ASEPalette
2
+ class Palette
3
+ # TODO: Consider removing 'with_name' from method signatures
4
+ # TODO: Make sure to encode strings back to UTF-8 when importing ASE files
5
+ # TODO: Check case-sensitivity of the ASE spec for color and group names
6
+
7
+ # Initialize palette
8
+ def initialize
9
+ @version_major = 1
10
+ @version_minor = 0
11
+ @colors = []
12
+ @groups = []
13
+ end
14
+
15
+ # Get palette version
16
+ def version
17
+ "#{@version_major}.#{@version_minor}"
18
+ end
19
+
20
+ # Set palette version
21
+ def set_version(major, minor)
22
+ @version_major = major
23
+ @version_minor = minor
24
+ end
25
+
26
+ # Get read-only list of colors
27
+ # Optionally include all colors from groups
28
+ def colors(include_from_groups: false)
29
+ if include_from_groups
30
+ all_colors
31
+ else
32
+ @colors.clone
33
+ end
34
+ end
35
+
36
+ # Get color by name
37
+ def color_with_name(name)
38
+ found_colors = all_colors.select { |c| c.name == name }
39
+ found_colors.length >= 1 ? found_colors[0] : nil
40
+ end
41
+
42
+ # Get read-only list of groups
43
+ def groups
44
+ @groups.clone
45
+ end
46
+
47
+ # Get read-only group by name
48
+ def group_with_name(name)
49
+ found_groups = @groups.select { |g| g.name == name }
50
+ found_groups.length >= 1 ? found_groups[0].clone : nil
51
+ end
52
+
53
+ # Add color to palette
54
+ # Optionally provide 'group_name' to place color in group
55
+ # Group will be created if it does not exist
56
+ # Returns true if color is added
57
+ def add_color(color, group_name: nil)
58
+ if color.is_a? Color
59
+ if color_does_not_exist_in_palette(color.name)
60
+ if group_name
61
+ group = find_or_create_group(group_name)
62
+ group.colors << color
63
+ true
64
+ else
65
+ @colors << color
66
+ true
67
+ end
68
+ else
69
+ raise Error, "A color named #{color.name} already exists"
70
+ end
71
+ else
72
+ raise Error, "Argument 'color' is not of type #{ASEPalette::Color}"
73
+ end
74
+ end
75
+
76
+ # Create empty group in palette
77
+ # Returns true if group is created
78
+ def create_group(name)
79
+ if @groups.select { |group| group.name == name }.length == 0
80
+ @groups << ASEPalette::Group.new(name)
81
+ true
82
+ else
83
+ raise Error, "A group named #{name} already exists"
84
+ end
85
+ end
86
+
87
+ # Remove color from palette
88
+ # Color may or may not be in a group
89
+ def remove_color_with_name(name)
90
+ @colors = @colors.select { |color| color.name != name }
91
+ @groups.each { |group| group.remove_color_with_name(name) }
92
+ true
93
+ end
94
+
95
+ # Remove group, and its colors, from palette
96
+ def remove_group_with_name(name)
97
+ @groups = @groups.select { |group| group.name != name }
98
+ true
99
+ end
100
+
101
+ # Create string representation of palette
102
+ def to_s
103
+ s = "ASEPalette #{version}\n"
104
+ divider = "#{"-" * (s.length - 1)}\n"
105
+ s += divider
106
+ if @colors.length > 0 || @groups.length > 0
107
+ s += "\n"
108
+ @colors.each do |color|
109
+ s += "#{color}\n"
110
+ end
111
+ s += "\n"
112
+ @groups.each do |group|
113
+ s += "#{group}\n"
114
+ end
115
+ else
116
+ s += "This palette is empty\n"
117
+ end
118
+ s += divider
119
+ s += "#{all_colors.length} color#{if all_colors.length != 1 then "s" end}, " \
120
+ "#{@groups.length} group#{if @groups.length != 1 then "s" end}"
121
+ s
122
+ end
123
+
124
+ # Create binary representation of palette
125
+ def to_binary
126
+ palette = PaletteBinary.build_binary_palette(
127
+ @colors.map(&:to_h),
128
+ @groups.map(&:to_h),
129
+ @version_major,
130
+ @version_minor,
131
+ )
132
+ palette.to_binary_s
133
+ end
134
+
135
+ # Create human-readable hex representation of palette
136
+ def to_hex
137
+ to_binary.to_hex_string
138
+ end
139
+
140
+ private
141
+
142
+ # Returns an array of all colors in the palette,
143
+ # including those in groups
144
+ def all_colors
145
+ @colors + @groups.map { |group| group.colors }.flatten
146
+ end
147
+
148
+ # Determines whether or not a color exists in the palette,
149
+ # including those in groups
150
+ def color_does_not_exist_in_palette(name)
151
+ all_colors.select { |color| color.name == name }.length == 0
152
+ end
153
+
154
+ # Returns a found or created group
155
+ def find_or_create_group(name)
156
+ found_groups = @groups.select { |group| group.name == name }
157
+ if found_groups.length > 0
158
+ found_groups[0]
159
+ else
160
+ new_group = ASEPalette::Group.new(name)
161
+ @groups << new_group
162
+ new_group
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,210 @@
1
+ module ASEPalette
2
+ module PaletteBinary
3
+ DEFAULT_VERSION_MAJOR = 1
4
+ DEFAULT_VERSION_MINOR = 0
5
+
6
+ BLOCK_TYPE_COLOR = 0x1
7
+ BLOCK_TYPE_GROUP_START = 0xC001
8
+ BLOCK_TYPE_GROUP_END = 0xC002
9
+
10
+ COLOR_TYPE_GLOBAL = 0
11
+ COLOR_TYPE_SPOT = 1
12
+ COLOR_TYPE_NORMAL = 2
13
+ COLOR_TYPE_DEFAULT = COLOR_TYPE_NORMAL
14
+
15
+ COLOR_MODEL_RGB = "RGB "
16
+ COLOR_MODEL_CMYK = "CMYK"
17
+ COLOR_MODEL_LAB = "LAB "
18
+ COLOR_MODEL_GRAY = "GRAY"
19
+ COLOR_MODEL_DEFAULT = COLOR_MODEL_RGB
20
+
21
+ class ASEBinData < BinData::Record
22
+ endian :big
23
+
24
+ string :signature, value: "ASEF"
25
+ uint16 :version_major, initial_value: DEFAULT_VERSION_MAJOR
26
+ uint16 :version_minor, initial_value: DEFAULT_VERSION_MINOR
27
+ uint32 :block_count, value: -> { blocks.length }
28
+
29
+ array :blocks do
30
+ uint16 :block_type
31
+ uint32 :block_length, value: -> {
32
+ block_length = 0
33
+ if block_type == BLOCK_TYPE_COLOR ||
34
+ block_type == BLOCK_TYPE_GROUP_START
35
+ block_length += block_data.name.length
36
+ end
37
+ if block_type == BLOCK_TYPE_COLOR
38
+ block_length += 10
39
+ case block_data.color_model
40
+ when COLOR_MODEL_RGB
41
+ block_length += 4 * 3
42
+ when COLOR_MODEL_CMYK, COLOR_MODEL_GRAY
43
+ block_length += 4 * 4
44
+ when COLOR_MODEL_LAB
45
+ block_length += 4 * 3
46
+ end
47
+ elsif block_type == BLOCK_TYPE_GROUP_START
48
+ block_length += 4
49
+ end
50
+ block_length
51
+ }
52
+ choice :block_data, selection: -> { block_type } do
53
+ class BlockGroupStart < BinData::Record
54
+ endian :big
55
+ uint16 :name_length, value: -> { name.length / 2 + 1 }
56
+ string :name, read_length: :name_length
57
+ uint16 :null_padding, value: 0
58
+ end
59
+ class BlockGroupEnd < BinData::Record
60
+ end
61
+ class BlockColor < BinData::Record
62
+ endian :big
63
+ uint16 :name_length, value: -> { name.length / 2 + 1 }
64
+ string :name, read_length: :name_length
65
+ uint16 :null_padding, value: 0
66
+ string :color_model, initial_value: COLOR_MODEL_DEFAULT
67
+ choice :color_data, selection: -> { color_model } do
68
+ class ColorDataRGB < BinData::Record
69
+ endian :big
70
+ float :red, initial_value: 0
71
+ float :green, initial_value: 0
72
+ float :blue, initial_value: 0
73
+ end
74
+ class ColorDataCMYK < BinData::Record
75
+ endian :big
76
+ float :cyan, initial_value: 0
77
+ float :magenta, initial_value: 0
78
+ float :yellow, initial_value: 0
79
+ float :black, initial_value: 0
80
+ end
81
+ class ColorDataLAB < BinData::Record
82
+ endian :big
83
+ float :lightness, initial_value: 0
84
+ float :a, initial_value: 0
85
+ float :b, initial_value: 0
86
+ end
87
+
88
+ ColorDataRGB COLOR_MODEL_RGB
89
+ ColorDataCMYK COLOR_MODEL_CMYK
90
+ ColorDataLAB COLOR_MODEL_LAB
91
+ # Grayscale data is stored in a CMYK structure
92
+ ColorDataCMYK COLOR_MODEL_GRAY
93
+ end
94
+ uint16 :color_type, initial_value: COLOR_TYPE_DEFAULT
95
+ end
96
+ BlockGroupStart BLOCK_TYPE_GROUP_START
97
+ BlockGroupEnd BLOCK_TYPE_GROUP_END
98
+ BlockColor BLOCK_TYPE_COLOR
99
+ end
100
+ end
101
+ end
102
+
103
+ def self.build_binary_palette(
104
+ colors,
105
+ groups,
106
+ version_major = DEFAULT_VERSION_MAJOR,
107
+ version_minor = DEFAULT_VERSION_MINOR
108
+ )
109
+ palette = ASEBinData.new
110
+ palette.version_major = version_major
111
+ palette.version_minor = version_minor
112
+ colors.each do |color|
113
+ binary_add_color(
114
+ palette,
115
+ color[:name],
116
+ color[:model],
117
+ color[:type],
118
+ color[:data],
119
+ )
120
+ end
121
+ groups.each do |group|
122
+ binary_begin_group(palette, group[:name])
123
+ group[:colors].each do |color|
124
+ binary_add_color(
125
+ palette,
126
+ color[:name],
127
+ color[:model],
128
+ color[:type],
129
+ color[:data],
130
+ )
131
+ end
132
+ binary_end_group(palette)
133
+ end
134
+ palette
135
+ end
136
+
137
+ private
138
+
139
+ def self.binary_add_color(palette, name, model, type, data)
140
+ case model
141
+ when :rgb
142
+ color_model = COLOR_MODEL_RGB
143
+ color_data = {
144
+ red: data[:r] / 255.0,
145
+ green: data[:g] / 255.0,
146
+ blue: data[:b] / 255.0,
147
+ }
148
+ when :cmyk
149
+ color_model = COLOR_MODEL_CMYK
150
+ color_data = {
151
+ cyan: data[:c] / 100.0,
152
+ magenta: data[:m] / 100.0,
153
+ yellow: data[:y] / 100.0,
154
+ black: data[:k] / 100.0,
155
+ }
156
+ when :lab
157
+ color_model = COLOR_MODEL_LAB
158
+ color_data = {
159
+ lightness: data[:l] / 100.0,
160
+ a: data[:a],
161
+ b: data[:b],
162
+ }
163
+ when :gray
164
+ # Grayscale is no longer supported by Adobe (was it ever?)
165
+ # This will default to a CMYK value with data only for black
166
+ color_model = COLOR_MODEL_CMYK
167
+ color_data = {
168
+ cyan: 0.0,
169
+ magenta: 0.0,
170
+ yellow: 0.0,
171
+ black: data[:gray] / 100.0,
172
+ }
173
+ end
174
+
175
+ case type
176
+ when :global
177
+ color_type = COLOR_TYPE_GLOBAL
178
+ when :spot
179
+ color_type = COLOR_TYPE_SPOT
180
+ when :normal
181
+ color_type = COLOR_TYPE_NORMAL
182
+ end
183
+
184
+ palette.blocks.push({
185
+ block_type: BLOCK_TYPE_COLOR,
186
+ block_data: {
187
+ name: name.encode(Encoding::UTF_16BE),
188
+ color_model: color_model,
189
+ color_data: color_data,
190
+ color_type: color_type,
191
+ }
192
+ })
193
+ end
194
+
195
+ def self.binary_begin_group(palette, name)
196
+ palette.blocks.push({
197
+ block_type: BLOCK_TYPE_GROUP_START,
198
+ block_data: {
199
+ name: name.encode(Encoding::UTF_16BE),
200
+ }
201
+ })
202
+ end
203
+
204
+ def self.binary_end_group(palette)
205
+ palette.blocks.push({
206
+ block_type: BLOCK_TYPE_GROUP_END,
207
+ })
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,3 @@
1
+ module ASEPalette
2
+ VERSION = "0.9.0"
3
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ase-palette
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Sam Becker
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bindata
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.4.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.4.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: hex_string
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '11.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '11.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.8'
83
+ description: Read and write Adobe Swatch Exchange files.
84
+ email:
85
+ - sam@sambecker.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - CHANGELOG.md
94
+ - Gemfile
95
+ - Gemfile.lock
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - ase-palette.gemspec
100
+ - bin/console
101
+ - bin/setup
102
+ - lib/ase-palette.rb
103
+ - lib/ase-palette/color.rb
104
+ - lib/ase-palette/group.rb
105
+ - lib/ase-palette/palette.rb
106
+ - lib/ase-palette/palette_binary.rb
107
+ - lib/ase-palette/version.rb
108
+ homepage: https://github.com/sambecker/ase-palette
109
+ licenses:
110
+ - MIT
111
+ metadata:
112
+ allowed_push_host: https://rubygems.org
113
+ homepage_uri: https://github.com/sambecker/ase-palette
114
+ source_code_uri: https://github.com/sambecker/ase-palette
115
+ changelog_uri: https://github.com/sambecker/ase-palette/blob/master/CHANGELOG.md
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 2.5.0
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubygems_version: 3.0.3
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Create and manage Adobe ASE palettes.
135
+ test_files: []