psd 2.1.2 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
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