psd 2.1.2 → 3.1.2

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/psd.rb +8 -6
  4. data/lib/psd/blend_mode.rb +46 -38
  5. data/lib/psd/channel_image.rb +9 -5
  6. data/lib/psd/descriptor.rb +39 -16
  7. data/lib/psd/header.rb +33 -32
  8. data/lib/psd/image_formats/rle.rb +4 -10
  9. data/lib/psd/image_modes/rgb.rb +4 -4
  10. data/lib/psd/layer.rb +1 -15
  11. data/lib/psd/layer/blend_modes.rb +12 -12
  12. data/lib/psd/layer/helpers.rb +8 -10
  13. data/lib/psd/layer/info.rb +9 -7
  14. data/lib/psd/layer/position_and_channels.rb +0 -4
  15. data/lib/psd/layer_info.rb +0 -4
  16. data/lib/psd/layer_info/blend_clipping_elements.rb +4 -2
  17. data/lib/psd/layer_info/blend_interior_elements.rb +4 -2
  18. data/lib/psd/layer_info/fill_opacity.rb +4 -2
  19. data/lib/psd/layer_info/layer_group.rb +4 -2
  20. data/lib/psd/layer_info/layer_id.rb +4 -2
  21. data/lib/psd/layer_info/layer_name_source.rb +4 -2
  22. data/lib/psd/layer_info/layer_section_divider.rb +4 -2
  23. data/lib/psd/layer_info/legacy_typetool.rb +5 -3
  24. data/lib/psd/layer_info/locked.rb +4 -2
  25. data/lib/psd/layer_info/metadata_setting.rb +4 -2
  26. data/lib/psd/layer_info/object_effects.rb +4 -2
  27. data/lib/psd/layer_info/pattern.rb +14 -0
  28. data/lib/psd/layer_info/placed_layer.rb +4 -2
  29. data/lib/psd/layer_info/reference_point.rb +4 -2
  30. data/lib/psd/layer_info/sheet_color.rb +18 -0
  31. data/lib/psd/layer_info/solid_color.rb +36 -0
  32. data/lib/psd/layer_info/typetool.rb +4 -2
  33. data/lib/psd/layer_info/unicode_name.rb +4 -2
  34. data/lib/psd/layer_info/vector_mask.rb +4 -2
  35. data/lib/psd/layer_info/vector_origination.rb +14 -0
  36. data/lib/psd/layer_info/vector_stroke.rb +4 -2
  37. data/lib/psd/layer_info/vector_stroke_content.rb +4 -2
  38. data/lib/psd/layer_mask.rb +2 -8
  39. data/lib/psd/lazy_execute.rb +5 -1
  40. data/lib/psd/node.rb +112 -48
  41. data/lib/psd/nodes/ancestry.rb +80 -75
  42. data/lib/psd/nodes/build_preview.rb +4 -4
  43. data/lib/psd/nodes/group.rb +35 -0
  44. data/lib/psd/nodes/layer.rb +40 -0
  45. data/lib/psd/nodes/root.rb +90 -0
  46. data/lib/psd/nodes/search.rb +19 -19
  47. data/lib/psd/path_record.rb +1 -71
  48. data/lib/psd/renderer.rb +6 -5
  49. data/lib/psd/renderer/blender.rb +10 -5
  50. data/lib/psd/renderer/cairo_helpers.rb +46 -0
  51. data/lib/psd/renderer/canvas.rb +39 -19
  52. data/lib/psd/renderer/canvas_management.rb +2 -2
  53. data/lib/psd/renderer/clipping_mask.rb +5 -4
  54. data/lib/psd/renderer/compose.rb +61 -68
  55. data/lib/psd/renderer/layer_styles.rb +15 -5
  56. data/lib/psd/renderer/layer_styles/color_overlay.rb +46 -27
  57. data/lib/psd/renderer/mask.rb +26 -22
  58. data/lib/psd/renderer/mask_canvas.rb +12 -0
  59. data/lib/psd/renderer/vector_shape.rb +239 -0
  60. data/lib/psd/resource_section.rb +4 -7
  61. data/lib/psd/resources.rb +4 -19
  62. data/lib/psd/resources/base.rb +27 -0
  63. data/lib/psd/resources/guides.rb +6 -4
  64. data/lib/psd/resources/layer_comps.rb +6 -4
  65. data/lib/psd/resources/slices.rb +7 -5
  66. data/lib/psd/version.rb +1 -1
  67. data/psd.gemspec +1 -2
  68. data/spec/files/blendmodes.psd +0 -0
  69. data/spec/hierarchy_spec.rb +5 -0
  70. metadata +27 -26
  71. data/lib/psd/layer_info/vector_mask_2.rb +0 -10
  72. data/lib/psd/node_exporting.rb +0 -20
  73. data/lib/psd/node_group.rb +0 -86
  74. data/lib/psd/node_layer.rb +0 -81
  75. data/lib/psd/node_root.rb +0 -93
  76. data/lib/psd/nodes/has_children.rb +0 -13
  77. data/lib/psd/nodes/lock_to_origin.rb +0 -7
  78. data/lib/psd/nodes/parse_layers.rb +0 -18
  79. data/lib/psd/renderer/layer_styles/drop_shadow.rb +0 -75
  80. data/lib/psd/section.rb +0 -26
@@ -1,29 +1,29 @@
1
1
  class PSD
2
2
  class Layer
3
3
  module BlendModes
4
- attr_reader :blend_mode, :opacity
4
+ attr_reader :blend_mode
5
+
6
+ delegate :opacity, :visible, :clipped?, to: :blend_mode
7
+ alias_method :visible?, :visible
8
+
9
+ # Is this layer hidden?
10
+ def hidden?
11
+ !visible
12
+ end
5
13
 
6
14
  def blending_mode
7
15
  if !info[:section_divider].nil? && info[:section_divider].blend_mode
8
16
  BlendMode::BLEND_MODES[info[:section_divider].blend_mode.strip.to_sym]
9
17
  else
10
- @blending_mode
18
+ @blend_mode.mode
11
19
  end
12
20
  end
13
21
 
14
- # Is the layer below this one a clipping mask?
15
- def clipped?
16
- @blend_mode.clipping == 1
17
- end
18
-
19
22
  private
20
23
 
21
24
  def parse_blend_modes
22
- @blend_mode = BlendMode.read(@file)
23
-
24
- @blending_mode = @blend_mode.mode
25
- @opacity = @blend_mode.opacity
26
- @visible = @blend_mode.visible
25
+ @blend_mode = BlendMode.new(@file)
26
+ @blend_mode.parse!
27
27
  end
28
28
  end
29
29
  end
@@ -47,16 +47,6 @@ class PSD
47
47
  info[:locked].transparency_locked
48
48
  end
49
49
 
50
- # Is this layer visible?
51
- def visible?
52
- @visible
53
- end
54
-
55
- # Is this layer hidden?
56
- def hidden?
57
- !@visible
58
- end
59
-
60
50
  # Helper that exports the text data in this layer, if any.
61
51
  def text
62
52
  return nil unless info[:type]
@@ -72,6 +62,14 @@ class PSD
72
62
  return 255 unless info.has_key?(:fill_opacity)
73
63
  info[:fill_opacity].value
74
64
  end
65
+
66
+ def raster_mask?
67
+ image.has_mask? && image.mask_data.length > 0
68
+ end
69
+
70
+ def vector_mask?
71
+ !vector_mask.nil?
72
+ end
75
73
  end
76
74
  end
77
75
  end
@@ -12,21 +12,27 @@ class PSD
12
12
  object_effects: ObjectEffects,
13
13
  name: UnicodeName,
14
14
  section_divider: LayerSectionDivider,
15
+ sheet_color: SheetColor,
15
16
  nested_section_divider: NestedLayerDivider,
16
17
  reference_point: ReferencePoint,
17
18
  layer_id: LayerID,
18
19
  fill_opacity: FillOpacity,
19
20
  placed_layer: PlacedLayer,
20
21
  locked: Locked,
22
+ solid_color: SolidColor,
21
23
  vector_mask: VectorMask,
22
- vector_mask_2: VectorMask2,
24
+ vector_origination: VectorOrigination,
23
25
  vector_stroke: VectorStroke,
24
26
  vector_stroke_content: VectorStrokeContent
25
- }
27
+ }.freeze
26
28
 
27
29
  attr_reader :adjustments
28
30
  alias :info :adjustments
29
31
 
32
+ LAYER_INFO.keys.each do |key|
33
+ define_method(key) { @adjustments[key] }
34
+ end
35
+
30
36
  private
31
37
 
32
38
  # This section is a bit tricky to parse because it represents all of the
@@ -47,7 +53,7 @@ class PSD
47
53
 
48
54
  key_parseable = false
49
55
  LAYER_INFO.each do |name, info|
50
- next unless info.key == key
56
+ next unless info.should_parse?(key)
51
57
 
52
58
  PSD.logger.debug "Layer Info: key = #{key}, start = #{pos}, length = #{length}"
53
59
 
@@ -65,10 +71,6 @@ class PSD
65
71
 
66
72
  @extra_data_end = @file.tell
67
73
  end
68
-
69
- def vector_mask
70
- info[:vector_mask_2] || info[:vector_mask]
71
- end
72
74
  end
73
75
  end
74
76
  end
@@ -10,8 +10,6 @@ class PSD
10
10
  private
11
11
 
12
12
  def parse_position_and_channels
13
- start_section(:info)
14
-
15
13
  @top = @file.read_int
16
14
  @left = @file.read_int
17
15
  @bottom = @file.read_int
@@ -27,8 +25,6 @@ class PSD
27
25
 
28
26
  @channels_info << {id: channel_id, length: channel_length}
29
27
  end
30
-
31
- end_section(:info)
32
28
  end
33
29
 
34
30
  def export_position_and_channels(outfile)
@@ -3,10 +3,6 @@ class PSD
3
3
  class LayerInfo
4
4
  attr_reader :data
5
5
 
6
- # The value of the key as used in the PSD format.
7
- class << self; attr_accessor :key; end
8
- @key = ""
9
-
10
6
  def initialize(layer, length)
11
7
  @layer = layer
12
8
  @file = layer.file
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class BlendClippingElements < LayerInfo
5
- @key = 'clbl'
5
+ def self.should_parse?(key)
6
+ key == 'clbl'
7
+ end
6
8
 
7
9
  attr_reader :enabled
8
10
  def parse
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class BlendInteriorElements < LayerInfo
5
- @key = 'infx'
5
+ def self.should_parse?(key)
6
+ key == 'infx'
7
+ end
6
8
 
7
9
  attr_reader :enabled
8
10
  def parse
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class FillOpacity < LayerInfo
5
- @key = 'iOpa'
5
+ def self.should_parse?(key)
6
+ key == 'iOpa'
7
+ end
6
8
 
7
9
  attr_reader :value
8
10
 
@@ -1,4 +1,4 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  # Not 100% sure what the purpose of this key is, but it seems to exist
@@ -7,7 +7,9 @@ class PSD
7
7
  #
8
8
  # See https://github.com/layervault/psd.rb/issues/38
9
9
  class NestedLayerDivider < LayerInfo
10
- @key = 'lsdk'
10
+ def self.should_parse?(key)
11
+ key == 'lsdk'
12
+ end
11
13
 
12
14
  attr_reader :is_folder, :is_hidden
13
15
 
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class LayerID < LayerInfo
5
- @key = 'lyid'
5
+ def self.should_parse?(key)
6
+ key == 'lyid'
7
+ end
6
8
 
7
9
  attr_reader :id
8
10
 
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class LayerNameSource < LayerInfo
5
- @key = 'lnsr'
5
+ def self.should_parse?(key)
6
+ key == 'lnsr'
7
+ end
6
8
 
7
9
  attr_reader :id
8
10
 
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class LayerSectionDivider < LayerInfo
5
- @key = 'lsct'
5
+ def self.should_parse?(key)
6
+ key == 'lsct'
7
+ end
6
8
 
7
9
  attr_reader :layer_type, :is_folder, :is_hidden, :blend_mode, :sub_type
8
10
 
@@ -1,9 +1,11 @@
1
- require_relative '../layer_info'
2
- require_relative 'typetool'
1
+ require 'psd/layer_info'
2
+ require 'psd/layer_info/typetool'
3
3
 
4
4
  class PSD
5
5
  class LegacyTypeTool < TypeTool
6
- @key = 'tySh'
6
+ def self.should_parse?(key)
7
+ key == 'tySh'
8
+ end
7
9
 
8
10
  def parse
9
11
  version = @file.read_short
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class Locked < LayerInfo
5
- @key = 'lspf'
5
+ def self.should_parse?(key)
6
+ key == 'lspf'
7
+ end
6
8
 
7
9
  attr_reader :all_locked, :transparency_locked, :composite_locked, :position_locked
8
10
 
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class MetadataSetting < LayerInfo
5
- @key = 'shmd'
5
+ def self.should_parse?(key)
6
+ key == 'shmd'
7
+ end
6
8
 
7
9
  def parse
8
10
  count = @file.read_int
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class ObjectEffects < LayerInfo
5
- @key = 'lfx2'
5
+ def self.should_parse?(key)
6
+ key == 'lfx2'
7
+ end
6
8
 
7
9
  def parse
8
10
  version = @file.read_int
@@ -0,0 +1,14 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Pattern < LayerInfo
5
+ def self.should_parse?(key)
6
+ return false
7
+ ['Patt', 'Pat2', 'Pat3'].include?(key)
8
+ end
9
+
10
+ def parse
11
+
12
+ end
13
+ end
14
+ end
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class PlacedLayer < LayerInfo
5
- @key = 'SoLd'
5
+ def self.should_parse?(key)
6
+ key == 'SoLd'
7
+ end
6
8
 
7
9
  def parse
8
10
  # Useless id/version info
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class ReferencePoint < LayerInfo
5
- @key = 'fxrp'
5
+ def self.should_parse?(key)
6
+ key == 'fxrp'
7
+ end
6
8
 
7
9
  attr_reader :x, :y
8
10
 
@@ -0,0 +1,18 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class SheetColor < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'lclr'
7
+ end
8
+
9
+ def parse
10
+ @data = [
11
+ @file.read_short,
12
+ @file.read_short,
13
+ @file.read_short,
14
+ @file.read_short
15
+ ]
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class SolidColor < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'SoCo'
7
+ end
8
+
9
+ def parse
10
+ @file.seek 4, IO::SEEK_CUR
11
+ @data = Descriptor.new(@file).parse
12
+ end
13
+
14
+ def color
15
+ ChunkyPNG::Color.rgb(r, g, b)
16
+ end
17
+
18
+ def r
19
+ @r ||= color_data['Rd '].round
20
+ end
21
+
22
+ def g
23
+ @g ||= color_data['Grn '].round
24
+ end
25
+
26
+ def b
27
+ @b ||= color_data['Bl '].round
28
+ end
29
+
30
+ private
31
+
32
+ def color_data
33
+ @data['Clr ']
34
+ end
35
+ end
36
+ end
@@ -1,11 +1,13 @@
1
1
  # encoding: UTF-8
2
- require_relative '../layer_info'
2
+ require 'psd/layer_info'
3
3
 
4
4
  class PSD
5
5
  # Parses and provides information about text areas within layers in
6
6
  # the document.
7
7
  class TypeTool < LayerInfo
8
- @key = 'TySh'
8
+ def self.should_parse?(key)
9
+ key == 'TySh'
10
+ end
9
11
 
10
12
  # Parse all of the text data in the layer.
11
13
  def parse
@@ -1,8 +1,10 @@
1
- require_relative '../layer_info'
1
+ require 'psd/layer_info'
2
2
 
3
3
  class PSD
4
4
  class UnicodeName < LayerInfo
5
- @key = 'luni'
5
+ def self.should_parse?(key)
6
+ key == 'luni'
7
+ end
6
8
 
7
9
  def parse
8
10
  pos = @file.tell