ase-palette 0.9.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,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: []