psd 2.1.2 → 3.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.
Files changed (130) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +2 -0
  3. data/README.md +60 -20
  4. data/lib/psd/blend_mode.rb +46 -38
  5. data/lib/psd/channel_image.rb +11 -5
  6. data/lib/psd/color.rb +14 -5
  7. data/lib/psd/descriptor.rb +39 -16
  8. data/lib/psd/file.rb +9 -6
  9. data/lib/psd/header.rb +38 -33
  10. data/lib/psd/helpers.rb +2 -2
  11. data/lib/psd/image.rb +21 -16
  12. data/lib/psd/image_formats/layer_rle.rb +2 -2
  13. data/lib/psd/image_formats/rle.rb +4 -10
  14. data/lib/psd/image_modes/cmyk.rb +18 -5
  15. data/lib/psd/image_modes/greyscale.rb +6 -1
  16. data/lib/psd/image_modes/rgb.rb +17 -5
  17. data/lib/psd/layer/blend_modes.rb +15 -13
  18. data/lib/psd/layer/helpers.rb +8 -10
  19. data/lib/psd/layer/info/black_white.rb +33 -0
  20. data/lib/psd/{layer_info → layer/info}/blend_clipping_elements.rb +4 -2
  21. data/lib/psd/{layer_info → layer/info}/blend_interior_elements.rb +4 -2
  22. data/lib/psd/layer/info/brightness_contrast.rb +21 -0
  23. data/lib/psd/layer/info/channel_blending_restrictions.rb +27 -0
  24. data/lib/psd/layer/info/channel_mixer.rb +27 -0
  25. data/lib/psd/layer/info/color_balance.rb +23 -0
  26. data/lib/psd/layer/info/color_lookup.rb +14 -0
  27. data/lib/psd/layer/info/content_generator.rb +42 -0
  28. data/lib/psd/layer/info/curves.rb +78 -0
  29. data/lib/psd/layer/info/effects_layer.rb +174 -0
  30. data/lib/psd/layer/info/exposure.rb +20 -0
  31. data/lib/psd/{layer_info → layer/info}/fill_opacity.rb +4 -2
  32. data/lib/psd/layer/info/gradient_fill.rb +14 -0
  33. data/lib/psd/layer/info/gradient_map.rb +69 -0
  34. data/lib/psd/layer/info/hue_saturation.rb +41 -0
  35. data/lib/psd/layer/info/invert.rb +17 -0
  36. data/lib/psd/layer/info/knockout.rb +22 -0
  37. data/lib/psd/layer/info/layer_effects.rb +16 -0
  38. data/lib/psd/{layer_info → layer/info}/layer_group.rb +4 -2
  39. data/lib/psd/{layer_info → layer/info}/layer_id.rb +4 -2
  40. data/lib/psd/layer/info/layer_mask_as_global_mask.rb +16 -0
  41. data/lib/psd/{layer_info → layer/info}/layer_name_source.rb +4 -2
  42. data/lib/psd/{layer_info → layer/info}/layer_section_divider.rb +4 -2
  43. data/lib/psd/{layer_info → layer/info}/legacy_typetool.rb +6 -4
  44. data/lib/psd/layer/info/levels.rb +48 -0
  45. data/lib/psd/{layer_info → layer/info}/locked.rb +4 -2
  46. data/lib/psd/{layer_info → layer/info}/metadata_setting.rb +5 -3
  47. data/lib/psd/{layer_info → layer/info}/object_effects.rb +5 -5
  48. data/lib/psd/layer/info/pattern.rb +14 -0
  49. data/lib/psd/layer/info/pattern_fill.rb +15 -0
  50. data/lib/psd/layer/info/photo_filter.rb +44 -0
  51. data/lib/psd/{layer_info → layer/info}/placed_layer.rb +4 -2
  52. data/lib/psd/layer/info/posterize.rb +16 -0
  53. data/lib/psd/{layer_info → layer/info}/reference_point.rb +4 -2
  54. data/lib/psd/layer/info/selective_color.rb +32 -0
  55. data/lib/psd/layer/info/sheet_color.rb +36 -0
  56. data/lib/psd/layer/info/solid_color.rb +36 -0
  57. data/lib/psd/layer/info/threshold.rb +16 -0
  58. data/lib/psd/layer/info/transparency_shapes_layer.rb +16 -0
  59. data/lib/psd/{layer_info → layer/info}/typetool.rb +27 -13
  60. data/lib/psd/{layer_info → layer/info}/unicode_name.rb +4 -2
  61. data/lib/psd/{layer_info → layer/info}/vector_mask.rb +7 -5
  62. data/lib/psd/layer/info/vector_mask_as_global_mask.rb +16 -0
  63. data/lib/psd/layer/info/vector_origination.rb +14 -0
  64. data/lib/psd/{layer_info → layer/info}/vector_stroke.rb +4 -2
  65. data/lib/psd/{layer_info → layer/info}/vector_stroke_content.rb +4 -2
  66. data/lib/psd/layer/info/vibrance.rb +22 -0
  67. data/lib/psd/layer/info.rb +106 -19
  68. data/lib/psd/layer/position_and_channels.rb +2 -6
  69. data/lib/psd/layer.rb +13 -16
  70. data/lib/psd/layer_info.rb +0 -4
  71. data/lib/psd/layer_mask.rb +61 -50
  72. data/lib/psd/lazy_execute.rb +5 -1
  73. data/lib/psd/mask.rb +7 -1
  74. data/lib/psd/node.rb +142 -49
  75. data/lib/psd/nodes/ancestry.rb +7 -6
  76. data/lib/psd/nodes/build_preview.rb +4 -4
  77. data/lib/psd/nodes/group.rb +36 -0
  78. data/lib/psd/nodes/layer.rb +45 -0
  79. data/lib/psd/nodes/layer_comps.rb +93 -0
  80. data/lib/psd/nodes/locking.rb +36 -0
  81. data/lib/psd/nodes/root.rb +87 -0
  82. data/lib/psd/nodes/search.rb +8 -65
  83. data/lib/psd/path_record.rb +5 -70
  84. data/lib/psd/renderer/blender.rb +10 -5
  85. data/lib/psd/renderer/cairo_helpers.rb +46 -0
  86. data/lib/psd/renderer/canvas.rb +41 -20
  87. data/lib/psd/renderer/canvas_management.rb +2 -2
  88. data/lib/psd/renderer/clipping_mask.rb +5 -4
  89. data/lib/psd/renderer/compose.rb +59 -69
  90. data/lib/psd/renderer/layer_styles/color_overlay.rb +45 -27
  91. data/lib/psd/renderer/layer_styles.rb +15 -5
  92. data/lib/psd/renderer/mask.rb +26 -22
  93. data/lib/psd/renderer/mask_canvas.rb +12 -0
  94. data/lib/psd/renderer/vector_shape.rb +239 -0
  95. data/lib/psd/renderer.rb +18 -7
  96. data/lib/psd/resource_section.rb +13 -6
  97. data/lib/psd/resources/base.rb +33 -0
  98. data/lib/psd/resources/guides.rb +6 -4
  99. data/lib/psd/resources/layer_comps.rb +6 -4
  100. data/lib/psd/resources/resolution_info.rb +48 -0
  101. data/lib/psd/resources/saved_path.rb +19 -0
  102. data/lib/psd/resources/slices.rb +7 -5
  103. data/lib/psd/resources/work_path.rb +22 -0
  104. data/lib/psd/resources/xmp_metadata.rb +46 -0
  105. data/lib/psd/resources.rb +17 -21
  106. data/lib/psd/slice.rb +44 -0
  107. data/lib/psd/slices.rb +13 -0
  108. data/lib/psd/util.rb +4 -2
  109. data/lib/psd/version.rb +1 -1
  110. data/lib/psd.rb +31 -45
  111. data/psd.gemspec +2 -3
  112. data/spec/files/alignment_modes.psd +0 -0
  113. data/spec/files/blendmodes.psd +0 -0
  114. data/spec/files/example.psb +0 -0
  115. data/spec/hierarchy_spec.rb +5 -0
  116. data/spec/locked_spec.rb +8 -8
  117. data/spec/psb_parsing_spec.rb +57 -0
  118. data/spec/text_spec.rb +13 -1
  119. metadata +115 -75
  120. data/circle.yml +0 -6
  121. data/lib/psd/layer_info/vector_mask_2.rb +0 -10
  122. data/lib/psd/node_exporting.rb +0 -20
  123. data/lib/psd/node_group.rb +0 -86
  124. data/lib/psd/node_layer.rb +0 -81
  125. data/lib/psd/node_root.rb +0 -93
  126. data/lib/psd/nodes/has_children.rb +0 -13
  127. data/lib/psd/nodes/lock_to_origin.rb +0 -7
  128. data/lib/psd/nodes/parse_layers.rb +0 -18
  129. data/lib/psd/renderer/layer_styles/drop_shadow.rb +0 -75
  130. data/lib/psd/section.rb +0 -26
@@ -0,0 +1,20 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Exposure < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'expA'
7
+ end
8
+
9
+ attr_reader :exposure, :offset, :gamma
10
+
11
+ def parse
12
+ @file.seek 2, IO::SEEK_CUR
13
+
14
+ # Why this shit is big endian is beyond me. Thanks Adobe.
15
+ @exposure = @file.read(4).unpack('g')[0]
16
+ @offset = @file.read(4).unpack('g')[0]
17
+ @gamma = @file.read(4).unpack('g')[0]
18
+ end
19
+ end
20
+ end
@@ -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
 
@@ -0,0 +1,14 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class GradientFill < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'GdFl'
7
+ end
8
+
9
+ def parse
10
+ @file.seek 4, IO::SEEK_CUR
11
+ @data = Descriptor.new(@file).parse
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,69 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class GradientMap < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'grdm'
7
+ end
8
+
9
+ attr_reader :reverse, :dither, :name, :color_stops, :transparency_stops,
10
+ :interpolation, :mode, :random_seed, :showing_transparency, :using_vector_color,
11
+ :roughness_factor, :color_model, :minimum_color, :maximum_color
12
+
13
+ def parse
14
+ # Version
15
+ @file.seek 2, IO::SEEK_CUR
16
+
17
+ @reverse = @file.read_boolean
18
+ @dither = @file.read_boolean
19
+
20
+ @name = @file.read_unicode_string
21
+
22
+ color_stops = @file.read_short
23
+ @color_stops = color_stops.times.map do
24
+ color = {
25
+ location: @file.read_int,
26
+ midpoint: @file.read_int,
27
+ color: @file.read_space_color
28
+ }
29
+
30
+ # Mystery padding
31
+ @file.seek 2, IO::SEEK_CUR
32
+ color
33
+ end
34
+
35
+ transparency_stops = @file.read_short
36
+ @transparency_stops = transparency_stops.times.map do
37
+ {
38
+ location: @file.read_int,
39
+ midpoint: @file.read_int,
40
+ opacity: @file.read_short
41
+ }
42
+ end
43
+
44
+ expansion_count = @file.read_short
45
+ if expansion_count > 0
46
+ @interpolation = @file.read_short
47
+ length = @file.read_short
48
+ if length >= 32
49
+ @mode = @file.read_short
50
+ @random_seed = @file.read_int
51
+ @showing_transparency = @file.read_short > 0
52
+ @using_vector_color = @file.read_short > 0
53
+ @roughness_factor = @file.read_int
54
+
55
+ @color_model = @file.read_short
56
+ @minimum_color = 4.times.map do
57
+ @file.read_short >> 8
58
+ end
59
+
60
+ @maximum_color = 4.times.map do
61
+ @file.read_short >> 8
62
+ end
63
+ end
64
+ end
65
+
66
+ @file.seek 2, IO::SEEK_CUR
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,41 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class HueSaturation < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'hue2'
7
+ end
8
+
9
+ attr_reader :type, :colorization, :master, :range_values, :setting_values
10
+
11
+ def parse
12
+ # Version
13
+ @file.seek 2, IO::SEEK_CUR
14
+
15
+ @type = @file.read_byte == 0 ? :hue : :colorization
16
+
17
+ # Padding byte
18
+ @file.seek 1, IO::SEEK_CUR
19
+
20
+ @colorization = {
21
+ hue: @file.read_short,
22
+ saturation: @file.read_short,
23
+ lightness: @file.read_short
24
+ }
25
+
26
+ @master = {
27
+ hue: @file.read_short,
28
+ saturation: @file.read_short,
29
+ lightness: @file.read_short
30
+ }
31
+
32
+ @range_values = []
33
+ @setting_values = []
34
+
35
+ 6.times do
36
+ @range_values << 4.times.map { @file.read_short }
37
+ @setting_values << 3.times.map { @file.read_short }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Invert < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'nvrt'
7
+ end
8
+
9
+ attr_reader :inverted
10
+
11
+ def parse
12
+ # There is no data. The presence of this info block is
13
+ # all that's provided.
14
+ @inverted = true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Knockout < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'knko'
7
+ end
8
+
9
+ MODES = [:shallow, :deep]
10
+
11
+ attr_reader :enabled, :mode
12
+
13
+ def parse
14
+ val = @file.read_byte
15
+
16
+ @enabled = val > 0
17
+ @mode = MODES[val - 1]
18
+
19
+ @file.seek 3, IO::SEEK_CUR
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class LayerEffects < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'lfxs'
7
+ end
8
+
9
+ def parse
10
+ version = @file.read_int
11
+ descriptor_version = @file.read_int
12
+
13
+ @data = Descriptor.new(@file).parse
14
+ end
15
+ end
16
+ end
@@ -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
 
@@ -0,0 +1,16 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class LayerMaskAsGlobalMask < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'lmgm'
7
+ end
8
+
9
+ attr_reader :enabled
10
+
11
+ def parse
12
+ @enabled = @file.read_boolean
13
+ @file.seek 3, IO::SEEK_CUR
14
+ end
15
+ end
16
+ end
@@ -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
@@ -85,4 +87,4 @@ class PSD
85
87
  ""
86
88
  end
87
89
  end
88
- end
90
+ end
@@ -0,0 +1,48 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Levels < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'levl'
7
+ end
8
+
9
+ attr_reader :records
10
+
11
+ def parse
12
+ @file.seek 2, IO::SEEK_CUR
13
+
14
+ @records = 29.times.map do
15
+ {
16
+ input_floor: @file.read_short,
17
+ input_ceiling: @file.read_short,
18
+ output_floor: @file.read_short,
19
+ output_ceiling: @file.read_short,
20
+ gamma: @file.read_short / 100.0,
21
+ }
22
+ end
23
+
24
+ # Photoshop CS (8.0) additional information
25
+ if @file.tell < @section_end - 4
26
+ tag = @file.read_string(4)
27
+ raise 'Extra levels key error' if tag != 'Lvls'
28
+
29
+ @file.seek 2, IO::SEEK_CUR
30
+
31
+ # Count of total level record structures. Subtract the legacy number of
32
+ # level record structures, 29, to determine how many are remaining in
33
+ # the file for reading.
34
+ extra_levels = @file.read_short - 29
35
+
36
+ extra_levels.times do
37
+ @records << {
38
+ input_floor: @file.read_short,
39
+ input_ceiling: @file.read_short,
40
+ output_floor: @file.read_short,
41
+ output_ceiling: @file.read_short,
42
+ gamma: @file.read_short / 100.0
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -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
@@ -32,4 +34,4 @@ class PSD
32
34
  @data[:layer_comp] = Descriptor.new(@file).parse
33
35
  end
34
36
  end
35
- end
37
+ end
@@ -1,16 +1,16 @@
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
9
11
  descriptor_version = @file.read_int
10
12
 
11
13
  @data = Descriptor.new(@file).parse
12
-
13
- return self
14
14
  end
15
15
  end
16
- end
16
+ end
@@ -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
@@ -0,0 +1,15 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class PatternFill < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'PtFl'
7
+ end
8
+
9
+ def parse
10
+ # Version
11
+ @file.seek 4, IO::SEEK_CUR
12
+ @data = Descriptor.new(@file).parse
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class PhotoFilter < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'phfl'
7
+ end
8
+
9
+ attr_reader :color, :density, :preserve_luminosity
10
+
11
+ def parse
12
+ version = @file.read_short
13
+
14
+ case version
15
+ when 2 then parse_version_2
16
+ when 3 then parse_version_3
17
+ else return
18
+ end
19
+
20
+ @density = @file.read_int
21
+ @preserve_luminosity = @file.read_boolean
22
+ end
23
+
24
+ private
25
+
26
+ def parse_version_2
27
+ color_space = @file.read_short
28
+ color_components = 4.times.map { @file.read_short }
29
+
30
+ @color = {
31
+ color_space: Color::COLOR_SPACE[color_space],
32
+ components: color_components
33
+ }
34
+ end
35
+
36
+ def parse_version_3
37
+ @color = {
38
+ x: @file.read_int >> 8,
39
+ y: @file.read_int >> 8,
40
+ z: @file.read_int >> 8
41
+ }
42
+ end
43
+ end
44
+ 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
@@ -0,0 +1,16 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Posterize < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'post'
7
+ end
8
+
9
+ attr_reader :levels
10
+
11
+ def parse
12
+ @levels = @file.read_short
13
+ @file.seek 2, IO::SEEK_CUR # Padding?
14
+ end
15
+ end
16
+ end
@@ -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,32 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class SelectiveColor < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'selc'
7
+ end
8
+
9
+ attr_reader :correction_mode, :cyan_correction, :magenta_correction,
10
+ :yellow_correction, :black_correction
11
+
12
+ def parse
13
+ @file.seek 2, IO::SEEK_CUR
14
+
15
+ @correction_mode = @file.read_short == 0 ? :relative : :absolute
16
+ @cyan_correction = []
17
+ @magenta_correction = []
18
+ @yellow_correction = []
19
+ @black_correction = []
20
+
21
+ 10.times do |i|
22
+ # First record is all 0 and is ignored by Photoshop
23
+ @file.seek(8, IO::SEEK_CUR) and next if i == 0
24
+
25
+ @cyan_correction << @file.read_short
26
+ @magenta_correction << @file.read_short
27
+ @yellow_correction << @file.read_short
28
+ @black_correction << @file.read_short
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ # This is the color label for a group/layer. Not sure why Adobe
5
+ # refers to it as the "Sheet Color".
6
+ class SheetColor < LayerInfo
7
+ def self.should_parse?(key)
8
+ key == 'lclr'
9
+ end
10
+
11
+ COLORS = [
12
+ :no_color,
13
+ :red,
14
+ :orange,
15
+ :yellow,
16
+ :green,
17
+ :blue,
18
+ :violet,
19
+ :gray
20
+ ]
21
+
22
+ def parse
23
+ # Only the first entry is used, the rest are always 0.
24
+ @data = [
25
+ @file.read_short,
26
+ @file.read_short,
27
+ @file.read_short,
28
+ @file.read_short
29
+ ]
30
+ end
31
+
32
+ def color
33
+ COLORS[@data[0]]
34
+ end
35
+ end
36
+ 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
@@ -0,0 +1,16 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Threshold < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'thrs'
7
+ end
8
+
9
+ attr_reader :level
10
+
11
+ def parse
12
+ @level = @file.read_short
13
+ @file.seek 2, IO::SEEK_CUR # Padding?
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class TransparencyShapesLayer < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'tsly'
7
+ end
8
+
9
+ attr_reader :enabled
10
+
11
+ def parse
12
+ @enabled = @file.read_byte == 1
13
+ @file.seek 3, IO::SEEK_CUR
14
+ end
15
+ end
16
+ end