psd 1.2.2 → 1.3.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.
- checksums.yaml +4 -4
- data/README.md +22 -0
- data/lib/psd/file.rb +1 -1
- data/lib/psd/helpers.rb +4 -0
- data/lib/psd/layer.rb +1 -0
- data/lib/psd/layer_info/metadata_setting.rb +35 -0
- data/lib/psd/layer_info/typetool.rb +1 -1
- data/lib/psd/node.rb +5 -1
- data/lib/psd/node_group.rb +6 -0
- data/lib/psd/node_layer.rb +6 -6
- data/lib/psd/node_root.rb +3 -1
- data/lib/psd/nodes/search.rb +35 -0
- data/lib/psd/resources/layer_comps.rb +4 -0
- data/lib/psd/version.rb +1 -1
- data/spec/hierarchy_spec.rb +17 -0
- data/spec/parsing_spec.rb +13 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d04a7ff525ba486c5d37f11d89b6106c5ae9960a
|
4
|
+
data.tar.gz: 8993d2ce5b328983e55ee77a1ba6297afc37ad0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5da04951ba02c95f1770574a70258736033ff3b9d8b74ede4873592c3ac102fe7972372df4e5ae8f5279d5044c7a475ac5f7de5e86611769d9db59234edf693
|
7
|
+
data.tar.gz: c2e37f8843ff642688c8ea136e28821c51ba8f964368026968301a69046eee757b7b4e48480fe91ff43bd18542d95814046fef9c07cee604aa6f25ad3466393f
|
data/README.md
CHANGED
@@ -15,6 +15,7 @@ A general purpose Photoshop file parser written in Ruby. It allows you to work w
|
|
15
15
|
* Color mode and bit-depth
|
16
16
|
* Vector mask data
|
17
17
|
* Flattened image data
|
18
|
+
* Layer comps
|
18
19
|
|
19
20
|
PSD.rb is tested against:
|
20
21
|
|
@@ -90,6 +91,27 @@ For any of the traversal methods, you can also retrieve folder or layer nodes on
|
|
90
91
|
psd.tree.descendant_layers
|
91
92
|
```
|
92
93
|
|
94
|
+
If you know the path to a group or layer within the tree, you can search by that path. Note that this always returns an Array because layer/group names do not have to be unique.
|
95
|
+
|
96
|
+
``` ruby
|
97
|
+
psd.tree.children_at_path("Version A/Matte")
|
98
|
+
```
|
99
|
+
|
100
|
+
**Layer Comps**
|
101
|
+
|
102
|
+
You can also filter nodes based on a layer comp. To generate a new tree consisting only of the layers that are enabled in a certain layer comp:
|
103
|
+
|
104
|
+
``` ruby
|
105
|
+
# Get information about all the available layer comps
|
106
|
+
puts psd.layer_comps
|
107
|
+
|
108
|
+
# Can filter by name or by ID (obtained from above)
|
109
|
+
tree = psd.tree.filter_by_comp('Version A')
|
110
|
+
puts tree.children.map(&:name)
|
111
|
+
```
|
112
|
+
|
113
|
+
This returns a new node tree and does not alter the original so you won't lose any data.
|
114
|
+
|
93
115
|
**Accessing Layer Data**
|
94
116
|
|
95
117
|
To get data such as the name or dimensions of a layer:
|
data/lib/psd/file.rb
CHANGED
data/lib/psd/helpers.rb
CHANGED
data/lib/psd/layer.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative '../layer_info'
|
2
|
+
|
3
|
+
class PSD
|
4
|
+
class MetadataSetting < LayerInfo
|
5
|
+
@key = 'shmd'
|
6
|
+
|
7
|
+
def parse
|
8
|
+
count = @file.read_int
|
9
|
+
|
10
|
+
count.times do
|
11
|
+
@file.seek 4, IO::SEEK_CUR # signature, always 8BIM
|
12
|
+
|
13
|
+
key = @file.read_string(4)
|
14
|
+
copy_on_sheet_dup = @file.read(1).bytes.to_a[0]
|
15
|
+
@file.seek 3, IO::SEEK_CUR # Padding
|
16
|
+
|
17
|
+
len = @file.read_int
|
18
|
+
data_end = @file.tell + len
|
19
|
+
|
20
|
+
PSD.logger.debug "Layer metadata: key = #{key}, length = #{len}"
|
21
|
+
|
22
|
+
parse_layer_comp_setting if key == 'cmls'
|
23
|
+
|
24
|
+
@file.seek data_end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def parse_layer_comp_setting
|
31
|
+
@file.seek 4, IO::SEEK_CUR # Version
|
32
|
+
@data[:layer_comp] = Descriptor.new(@file).parse
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/psd/node.rb
CHANGED
@@ -11,7 +11,7 @@ class PSD
|
|
11
11
|
# Default properties that all nodes contain
|
12
12
|
PROPERTIES = [:name, :left, :right, :top, :bottom, :height, :width]
|
13
13
|
|
14
|
-
attr_accessor :parent, :children
|
14
|
+
attr_accessor :parent, :children, :layer
|
15
15
|
|
16
16
|
def initialize(layers=[])
|
17
17
|
@children = []
|
@@ -29,6 +29,10 @@ class PSD
|
|
29
29
|
@layer.visible?
|
30
30
|
end
|
31
31
|
|
32
|
+
def psd
|
33
|
+
parent.psd
|
34
|
+
end
|
35
|
+
|
32
36
|
def layer?
|
33
37
|
is_a?(PSD::Node::Layer)
|
34
38
|
end
|
data/lib/psd/node_group.rb
CHANGED
@@ -55,6 +55,12 @@ class PSD::Node
|
|
55
55
|
})
|
56
56
|
end
|
57
57
|
|
58
|
+
# If the method is missing, we blindly send it to the layer.
|
59
|
+
# The layer handles the case in which the method doesn't exist.
|
60
|
+
def method_missing(method, *args, &block)
|
61
|
+
@layer.send(method, *args, &block)
|
62
|
+
end
|
63
|
+
|
58
64
|
private
|
59
65
|
|
60
66
|
def get_dimensions
|
data/lib/psd/node_layer.rb
CHANGED
@@ -25,12 +25,6 @@ class PSD::Node
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
# If the method is missing, we blindly send it to the layer.
|
29
|
-
# The layer handles the case in which the method doesn't exist.
|
30
|
-
def method_missing(method, *args, &block)
|
31
|
-
layer.send(method, *args, &block)
|
32
|
-
end
|
33
|
-
|
34
28
|
# Attempt to translate the layer.
|
35
29
|
def translate(x=0, y=0)
|
36
30
|
@layer.translate x, y
|
@@ -67,5 +61,11 @@ class PSD::Node
|
|
67
61
|
ref_y: @layer.reference_point.y
|
68
62
|
})
|
69
63
|
end
|
64
|
+
|
65
|
+
# If the method is missing, we blindly send it to the layer.
|
66
|
+
# The layer handles the case in which the method doesn't exist.
|
67
|
+
def method_missing(method, *args, &block)
|
68
|
+
@layer.send(method, *args, &block)
|
69
|
+
end
|
70
70
|
end
|
71
71
|
end
|
data/lib/psd/node_root.rb
CHANGED
@@ -6,7 +6,7 @@ class PSD::Node
|
|
6
6
|
include PSD::HasChildren
|
7
7
|
include PSD::Node::ParseLayers
|
8
8
|
|
9
|
-
|
9
|
+
attr_accessor :children
|
10
10
|
|
11
11
|
# Stores a reference to the parsed PSD and builds the
|
12
12
|
# tree hierarchy.
|
@@ -51,6 +51,8 @@ class PSD::Node
|
|
51
51
|
0
|
52
52
|
end
|
53
53
|
|
54
|
+
def psd; @psd; end
|
55
|
+
|
54
56
|
private
|
55
57
|
|
56
58
|
def build_hierarchy
|
data/lib/psd/nodes/search.rb
CHANGED
@@ -23,6 +23,41 @@ class PSD
|
|
23
23
|
return matches.map { |m| m.children_at_path(path, opts) }.flatten
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
# Given a layer comp ID, name, or :last for last document state, create a new
|
28
|
+
# tree based on the layers/groups that belong to the comp only.
|
29
|
+
def filter_by_comp(id)
|
30
|
+
if id.is_a?(String)
|
31
|
+
comp = psd.layer_comps.select { |c| c[:name] == id }.first
|
32
|
+
raise "Layer comp not found" if comp.nil?
|
33
|
+
|
34
|
+
id = comp[:id]
|
35
|
+
elsif id == :last
|
36
|
+
id = 0
|
37
|
+
end
|
38
|
+
|
39
|
+
root = PSD::Node::Root.new(psd)
|
40
|
+
filter_for_comp!(id, root)
|
41
|
+
|
42
|
+
return root
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def filter_for_comp!(id, node)
|
48
|
+
node.children.select! do |c|
|
49
|
+
c
|
50
|
+
.metadata
|
51
|
+
.data[:layer_comp]['layerSettings'].map { |l| !l.has_key?('enab') || l['enab'] ? l['compList'] : nil }
|
52
|
+
.flatten
|
53
|
+
.compact
|
54
|
+
.include?(id)
|
55
|
+
end
|
56
|
+
|
57
|
+
node.children.each do |c|
|
58
|
+
filter_for_comp!(id, c) if c.is_a?(PSD::Node::Group)
|
59
|
+
end
|
60
|
+
end
|
26
61
|
end
|
27
62
|
end
|
28
63
|
end
|
data/lib/psd/version.rb
CHANGED
data/spec/hierarchy_spec.rb
CHANGED
@@ -86,6 +86,23 @@ describe "Hierarchy" do
|
|
86
86
|
expect(@tree.children_at_path('NOPE')).to be_an_instance_of(Array)
|
87
87
|
expect(@tree.children_at_path('NOPE').size).to eq(0)
|
88
88
|
end
|
89
|
+
|
90
|
+
it "should throw an error if filtering by a non-existant layer comp" do
|
91
|
+
expect { @tree.filter_by_comp('WAT') }.to raise_error("Layer comp not found")
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should correctly filter and produce a new tree when filtering by layer comp" do
|
95
|
+
tree = @tree.filter_by_comp('Version A')
|
96
|
+
expect(tree).to be_an_instance_of(PSD::Node::Root)
|
97
|
+
expect(tree.children.size).to eq(1)
|
98
|
+
expect(tree.children[0].name).to eq("Version A")
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should return a new tree when filtering by layer comps" do
|
102
|
+
tree = @tree.filter_by_comp('Version A')
|
103
|
+
expect(tree).to_not eq(@tree)
|
104
|
+
expect(@tree.children.size).to eq(3)
|
105
|
+
end
|
89
106
|
end
|
90
107
|
end
|
91
108
|
end
|
data/spec/parsing_spec.rb
CHANGED
@@ -131,5 +131,18 @@ describe 'Parsing' do
|
|
131
131
|
expect(blend_mode.opacity_percentage).to eq(100)
|
132
132
|
expect(blend_mode.visible).to be_true
|
133
133
|
end
|
134
|
+
|
135
|
+
it "should parse all layer comps" do
|
136
|
+
expect(@psd.layer_comps.size).to eq(3)
|
137
|
+
expect(@psd.layer_comps.map { |c| c[:name] }).to eq([
|
138
|
+
'Version A',
|
139
|
+
'Version B',
|
140
|
+
'Version C'
|
141
|
+
])
|
142
|
+
|
143
|
+
@psd.layer_comps.each do |c|
|
144
|
+
expect(c[:id]).to be > 0
|
145
|
+
end
|
146
|
+
end
|
134
147
|
end
|
135
148
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: psd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan LeFevre
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -165,6 +165,7 @@ files:
|
|
165
165
|
- lib/psd/layer_info/layer_name_source.rb
|
166
166
|
- lib/psd/layer_info/layer_section_divider.rb
|
167
167
|
- lib/psd/layer_info/legacy_typetool.rb
|
168
|
+
- lib/psd/layer_info/metadata_setting.rb
|
168
169
|
- lib/psd/layer_info/object_effects.rb
|
169
170
|
- lib/psd/layer_info/placed_layer.rb
|
170
171
|
- lib/psd/layer_info/reference_point.rb
|