psd 1.2.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a6c401c74ed1123fa74ad8b50dfc6a0df6da1e5
4
- data.tar.gz: c2092822eb4eae245fce20204cf05ff3f4bbe0df
3
+ metadata.gz: d04a7ff525ba486c5d37f11d89b6106c5ae9960a
4
+ data.tar.gz: 8993d2ce5b328983e55ee77a1ba6297afc37ad0a
5
5
  SHA512:
6
- metadata.gz: 3696d5e2ff46cff1496b739551d264ae5c7316e6cb6a8b74e8e99a37d4d757330d32badfe66b6d2b6da5dbca32ab871a8105cd72d5b0b43486b06541d01be835
7
- data.tar.gz: de41bf1813b74520558fc2161a4266d5f32b0ed7d6b26fda86ae55fbafbd2e2043f403ebcac4e23faa6441d81a8bd43f62c60e68c2b8232f9656d164d5cc65f9
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:
@@ -83,7 +83,7 @@ class PSD
83
83
 
84
84
  # Reads a boolean value.
85
85
  def read_boolean
86
- read(1)[0] != 0
86
+ read(1).bytes.to_a[0] != 0
87
87
  end
88
88
 
89
89
  # Reads a 32-bit color space value.
@@ -31,5 +31,9 @@ class PSD
31
31
  def tree
32
32
  @root ||= PSD::Node::Root.new(self)
33
33
  end
34
+
35
+ def layer_comps
36
+ @resources[:layer_comps].data.to_a
37
+ end
34
38
  end
35
39
  end
@@ -19,6 +19,7 @@ class PSD
19
19
  LAYER_INFO = {
20
20
  type: TypeTool,
21
21
  legacy_type: LegacyTypeTool,
22
+ metadata: MetadataSetting,
22
23
  layer_name_source: LayerNameSource,
23
24
  object_effects: ObjectEffects,
24
25
  name: UnicodeName,
@@ -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
@@ -25,7 +25,7 @@ class PSD
25
25
  parser.parse!
26
26
  @data[:engine_data] = parser.result
27
27
  rescue Exception => e
28
- puts e.message
28
+ PSD.logger.error e.message
29
29
  end
30
30
 
31
31
  warpVersion = @file.read_short
@@ -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
@@ -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
@@ -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
@@ -6,7 +6,7 @@ class PSD::Node
6
6
  include PSD::HasChildren
7
7
  include PSD::Node::ParseLayers
8
8
 
9
- attr_reader :children
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
@@ -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
@@ -20,6 +20,10 @@ class PSD
20
20
  def [](val)
21
21
  @data[val]
22
22
  end
23
+
24
+ def to_a
25
+ @data['list'].map { |c| {id: c['compID'], name: c['Nm '], captured_info: c['capturedInfo']} }
26
+ end
23
27
  end
24
28
  end
25
29
  end
@@ -1,3 +1,3 @@
1
1
  class PSD
2
- VERSION = "1.2.2"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -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
@@ -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.2.2
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-23 00:00:00.000000000 Z
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