psd 3.4.0 → 3.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d022d5b521a64f3578c5755ba18d5bbc1f419ea
4
- data.tar.gz: 3f72cd4899c112f55171eab1f96629e354d1eb9f
3
+ metadata.gz: 94c708889f40e2d66fa1f271bbe5a2f385fcfef3
4
+ data.tar.gz: ff0cf841ac51420fe267285c725cc44191396fac
5
5
  SHA512:
6
- metadata.gz: ed4a582c87fd81ee3a6a19d487cea8fa6e388740e16097e185268581af549d032c125b3d66fde8dfe52ec0af2f4d67c57bce0990030e3eb7b8f06b18b1b62c51
7
- data.tar.gz: dce119bc89f527695fbd46229fbd82447d23722b60f19002afb0984bb10e3c7aee992ba301ad7f53cdd15ea4ad6277e47a2842ec21ca9bc17941e5ff4d561475
6
+ metadata.gz: 5a315bcfd5bf734cfcb2d712b0df72569ee42e34fd593072c91923119ccdcd5a5b5b785ae250af2ef82dda47abf847131eeae4c658a870e7d661977a90cdfb12
7
+ data.tar.gz: 0666ac938c7f75cc01aff7e60f3fc3c6a7f28d366e4703199fa1ccc1dc292796b111cf877bc803d552db97c06d0b7ce6a151e003fef1afc2f28ecd87bcdc5b1e
@@ -1,3 +1,4 @@
1
+ sudo: false
1
2
  language: ruby
2
3
  rvm:
3
4
  - 1.9.3
@@ -6,8 +6,17 @@ class PSD
6
6
  module Color
7
7
  extend self
8
8
 
9
- # This is a relic of libpsd that will likely go away in a future version. It
10
- # stored the entire color value in a 32-bit address space for speed.
9
+ COLOR_SPACE = {
10
+ 0 => :rgb,
11
+ 1 => :hsb,
12
+ 2 => :cmyk,
13
+ 7 => :lab,
14
+ 8 => :grayscale
15
+ }
16
+
17
+ # In some places in the PSD file, colors are stored with a short that
18
+ # describes the color space, and the following 4 bytes that store the
19
+ # color data.
11
20
  def color_space_to_argb(color_space, color_component)
12
21
  color = case color_space
13
22
  when 0
@@ -20,7 +29,7 @@ class PSD
20
29
  color_component[1] / 100.0, color_component[2] / 100.0,
21
30
  color_component[3] / 100.0
22
31
  when 7
23
- lab_to_color *color_component
32
+ alab_to_color *color_component
24
33
  else
25
34
  0x00FFFFFF
26
35
  end
@@ -101,7 +110,7 @@ class PSD
101
110
 
102
111
  def alab_to_color(alpha, l, a, b)
103
112
  xyz = lab_to_xyz(l, a, b)
104
- axyz_to_color alpha, xyz[:x], xyz[:y], xyz[:z]
113
+ axyz_to_color alpha, xyz[0], xyz[1], xyz[2]
105
114
  end
106
115
 
107
116
  def lab_to_xyz(l, a, b)
@@ -122,4 +131,4 @@ class PSD
122
131
  }.map { |k, v| [k, Util.clamp(v, 0, 255)] }]
123
132
  end
124
133
  end
125
- end
134
+ end
@@ -96,12 +96,12 @@ class PSD
96
96
  # Reads a 32-bit color space value.
97
97
  def read_space_color
98
98
  color_space = read_short
99
- color_component = []
100
- 4.times do |i|
101
- color_component.push(read_short >> 8)
99
+ color_components = []
100
+ 4.times.map do |i|
101
+ color_components.push(read_short >> 8)
102
102
  end
103
103
 
104
- Color.color_space_to_argb(color_space, color_component)
104
+ { color_mode: color_space, color_components: color_components }
105
105
  end
106
106
  end
107
107
  end
@@ -1,54 +1,90 @@
1
+ require 'psd/layer/info/black_white'
1
2
  require 'psd/layer/info/blend_clipping_elements'
2
3
  require 'psd/layer/info/blend_interior_elements'
4
+ require 'psd/layer/info/brightness_contrast'
5
+ require 'psd/layer/info/channel_mixer'
6
+ require 'psd/layer/info/color_balance'
7
+ require 'psd/layer/info/color_lookup'
8
+ require 'psd/layer/info/content_generator'
9
+ require 'psd/layer/info/curves'
10
+ require 'psd/layer/info/exposure'
3
11
  require 'psd/layer/info/fill_opacity'
4
12
  require 'psd/layer/info/gradient_fill'
13
+ require 'psd/layer/info/gradient_map'
14
+ require 'psd/layer/info/hue_saturation'
15
+ require 'psd/layer/info/invert'
5
16
  require 'psd/layer/info/layer_group'
6
17
  require 'psd/layer/info/layer_id'
7
18
  require 'psd/layer/info/layer_name_source'
8
19
  require 'psd/layer/info/layer_section_divider'
9
20
  require 'psd/layer/info/legacy_typetool'
21
+ require 'psd/layer/info/levels'
10
22
  require 'psd/layer/info/locked'
11
23
  require 'psd/layer/info/metadata_setting'
12
24
  require 'psd/layer/info/object_effects'
13
25
  require 'psd/layer/info/pattern'
26
+ require 'psd/layer/info/pattern_fill'
27
+ require 'psd/layer/info/photo_filter'
14
28
  require 'psd/layer/info/placed_layer'
29
+ require 'psd/layer/info/posterize'
15
30
  require 'psd/layer/info/reference_point'
31
+ require 'psd/layer/info/selective_color'
16
32
  require 'psd/layer/info/sheet_color'
17
33
  require 'psd/layer/info/solid_color'
34
+ require 'psd/layer/info/threshold'
18
35
  require 'psd/layer/info/typetool'
19
36
  require 'psd/layer/info/unicode_name'
20
37
  require 'psd/layer/info/vector_mask'
21
38
  require 'psd/layer/info/vector_origination'
22
39
  require 'psd/layer/info/vector_stroke'
23
40
  require 'psd/layer/info/vector_stroke_content'
41
+ require 'psd/layer/info/vibrance'
24
42
 
25
43
  class PSD
26
44
  class Layer
27
45
  module Info
28
46
  # All of the extra layer info sections that we know how to parse.
29
47
  LAYER_INFO = {
48
+ black_white: BlackWhite,
30
49
  blend_clipping_elements: BlendClippingElements,
31
50
  blend_interior_elements: BlendInteriorElements,
32
- type: TypeTool,
51
+ brightness_contrast: BrightnessContrast,
52
+ channel_mixer: ChannelMixer,
53
+ color_balance: ColorBalance,
54
+ color_lookup: ColorLookup,
55
+ content_generator: ContentGenerator,
56
+ curves: Curves,
57
+ exposure: Exposure,
58
+ fill_opacity: FillOpacity,
59
+ gradient_fill: GradientFill,
60
+ gradient_map: GradientMap,
61
+ hue_saturation: HueSaturation,
62
+ invert: Invert,
63
+ layer_id: LayerID,
64
+ layer_name_source: LayerNameSource,
33
65
  legacy_type: LegacyTypeTool,
66
+ levels: Levels,
67
+ locked: Locked,
34
68
  metadata: MetadataSetting,
35
- layer_name_source: LayerNameSource,
36
- object_effects: ObjectEffects,
37
69
  name: UnicodeName,
38
- section_divider: LayerSectionDivider,
39
- sheet_color: SheetColor,
40
70
  nested_section_divider: NestedLayerDivider,
41
- reference_point: ReferencePoint,
42
- layer_id: LayerID,
43
- fill_opacity: FillOpacity,
71
+ object_effects: ObjectEffects,
72
+ pattern_fill: PatternFill,
73
+ photo_filter: PhotoFilter,
44
74
  placed_layer: PlacedLayer,
45
- locked: Locked,
75
+ posterize: Posterize,
76
+ reference_point: ReferencePoint,
77
+ selective_color: SelectiveColor,
78
+ section_divider: LayerSectionDivider,
79
+ sheet_color: SheetColor,
46
80
  solid_color: SolidColor,
81
+ threshold: Threshold,
82
+ type: TypeTool,
47
83
  vector_mask: VectorMask,
48
84
  vector_origination: VectorOrigination,
49
85
  vector_stroke: VectorStroke,
50
86
  vector_stroke_content: VectorStrokeContent,
51
- gradient_fill: GradientFill
87
+ vibrance: Vibrance
52
88
  }.freeze
53
89
 
54
90
  BIG_LAYER_INFO_KEYS = %w{ LMsk Lr16 Lr32 Layr Mt16 Mt32 Mtrn Alph FMsk lnk2 FEid FXid PxSD }
@@ -0,0 +1,33 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class BlackWhite < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'blwh'
7
+ end
8
+
9
+ attr_reader :red, :yellow, :green, :cyan, :blue, :magenta
10
+ attr_reader :tint, :tint_color, :preset_id, :preset_name
11
+
12
+ def parse
13
+ @file.seek 4, IO::SEEK_CUR
14
+ @data = Descriptor.new(@file).parse
15
+
16
+ @red = @data['Rd ']
17
+ @yellow = @data['Yllw']
18
+ @green = @data['Grn ']
19
+ @cyan = @data['Cyn ']
20
+ @blue = @data['Bl ']
21
+ @magenta = @data['Mgnt']
22
+ @tint = @data['useTint']
23
+ @tint_color = {
24
+ red: @data['tintColor']['Rd '],
25
+ green: @data['tintColor']['Grn '],
26
+ blue: @data['tintColor']['Bl ']
27
+ }
28
+
29
+ @preset_id = @data['bwPresetKind']
30
+ @preset_name = @data['blackAndWhitePresetFileName']
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ # NOTE: this only has the correct values when the "Use Legacy"
5
+ # checkbox is checked. If the 'CgEd' info key is present, these
6
+ # values will all be 0. Use that info block instead.
7
+ class BrightnessContrast < LayerInfo
8
+ def self.should_parse?(key)
9
+ key == 'brit'
10
+ end
11
+
12
+ attr_reader :brightness, :contrast, :mean_value, :lab_color
13
+
14
+ def parse
15
+ @brightness = @file.read_short
16
+ @contrast = @file.read_short
17
+ @mean_value = @file.read_short
18
+ @lab_color = @file.read_boolean
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class ChannelMixer < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'mixr'
7
+ end
8
+
9
+ attr_reader :monochrome, :color
10
+
11
+ def parse
12
+ @file.seek 2, IO::SEEK_CUR
13
+
14
+ @monochrome = @file.read_short > 0
15
+
16
+ @color = 4.times.map do
17
+ {
18
+ red_cyan: @file.read_short,
19
+ green_magenta: @file.read_short,
20
+ blue_yellow: @file.read_short,
21
+ black: @file.read_short,
22
+ constant: @file.read_short
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class ColorBalance < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'blnc'
7
+ end
8
+
9
+ attr_reader :shadows, :midtones, :highlights, :preserve_luminosity
10
+
11
+ def parse
12
+ @shadows, @midtones, @highlights = 3.times.map do
13
+ {
14
+ cyan_red: @file.read_short,
15
+ magenta_green: @file.read_short,
16
+ yellow_blue: @file.read_short
17
+ }
18
+ end
19
+
20
+ @preserve_luminosity = @file.read_short > 0
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class ColorLookup < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'clrL'
7
+ end
8
+
9
+ def parse
10
+ @file.seek 6, IO::SEEK_CUR
11
+ @data = Descriptor.new(@file).parse
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,42 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ # This is the new way that Photoshop stores the brightness/contrast
5
+ # data. If this data is present, DO NOT use the legacy BrightnessContrast
6
+ # info block.
7
+ class ContentGenerator < LayerInfo
8
+ def self.should_parse?(key)
9
+ key == 'CgEd'
10
+ end
11
+
12
+ def parse
13
+ # Version
14
+ @file.seek 4, IO::SEEK_CUR
15
+ @data = Descriptor.new(@file).parse
16
+ end
17
+
18
+ def brightness
19
+ @data['Brgh']
20
+ end
21
+
22
+ def contrast
23
+ @data['Cntr']
24
+ end
25
+
26
+ def mean_value
27
+ @data['means']
28
+ end
29
+
30
+ def lab_color
31
+ @data['Lab ']
32
+ end
33
+
34
+ def use_legacy
35
+ @data['useLegacy']
36
+ end
37
+
38
+ def auto
39
+ @data['Auto']
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,78 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Curves < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'curv'
7
+ end
8
+
9
+ attr_reader :curves
10
+
11
+ def parse
12
+ # Padding, spec is wrong. Maybe Photoshop bug?
13
+ @file.seek 1, IO::SEEK_CUR
14
+
15
+ # Version
16
+ @file.seek 2, IO::SEEK_CUR
17
+
18
+ tag = @file.read_int
19
+ curve_count = 0
20
+
21
+ # Legacy data, it looks like there are 32 positions
22
+ # where you can adjust the curve, and there is a chunk
23
+ # of 32 bytes that determine whether that chunk is set.
24
+ 32.times do |i|
25
+ curve_count += 1 if tag & (1 << i) > 0
26
+ end
27
+
28
+ @curves = []
29
+ curve_count.times do |i|
30
+ # Before each curve is a channel index
31
+ count = 0
32
+ curve = {}
33
+ 32.times do |j|
34
+ if tag & (1 << j) > 0
35
+ if count == i
36
+ curve[:channel_index] = j
37
+ break
38
+ end
39
+
40
+ count += 1
41
+ end
42
+ end
43
+
44
+ point_count = @file.read_short
45
+ curve[:points] = point_count.times.map do
46
+ {
47
+ output_value: @file.read_short,
48
+ input_value: @file.read_short
49
+ }
50
+ end
51
+
52
+ @curves << curve
53
+ end
54
+
55
+ if @file.tell < @section_end - 4
56
+ tag = @file.read_string(4)
57
+ raise "Extra curves key error: #{tag}" if tag != 'Crv '
58
+
59
+ @file.seek 2, IO::SEEK_CUR
60
+
61
+ curve_count = @file.read_int
62
+ curve_count.times do
63
+ curve = { channel_index: @file.read_short }
64
+
65
+ point_count = @file.read_short
66
+ curve[:points] = point_count.times.map do
67
+ {
68
+ output_value: @file.read_short,
69
+ input_value: @file.read_short
70
+ }
71
+ end
72
+
73
+ @curves << curve
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -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
@@ -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,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
@@ -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
@@ -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
@@ -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
@@ -1,12 +1,26 @@
1
1
  require 'psd/layer_info'
2
2
 
3
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".
4
6
  class SheetColor < LayerInfo
5
7
  def self.should_parse?(key)
6
8
  key == 'lclr'
7
9
  end
8
10
 
11
+ COLORS = [
12
+ :no_color,
13
+ :red,
14
+ :orange,
15
+ :yellow,
16
+ :green,
17
+ :blue,
18
+ :violet,
19
+ :gray
20
+ ]
21
+
9
22
  def parse
23
+ # Only the first entry is used, the rest are always 0.
10
24
  @data = [
11
25
  @file.read_short,
12
26
  @file.read_short,
@@ -14,5 +28,9 @@ class PSD
14
28
  @file.read_short
15
29
  ]
16
30
  end
31
+
32
+ def color
33
+ COLORS[@data[0]]
34
+ end
17
35
  end
18
- 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,22 @@
1
+ require 'psd/layer_info'
2
+
3
+ class PSD
4
+ class Vibrance < LayerInfo
5
+ def self.should_parse?(key)
6
+ key == 'vibA'
7
+ end
8
+
9
+ def parse
10
+ @file.seek 4, IO::SEEK_CUR
11
+ @data = Descriptor.new(@file).parse
12
+ end
13
+
14
+ def vibrance
15
+ @data['vibrance']
16
+ end
17
+
18
+ def saturation
19
+ @data['Strt']
20
+ end
21
+ end
22
+ end
@@ -54,6 +54,10 @@ class PSD
54
54
  (@flags & (0x01 << 2)) > 0
55
55
  end
56
56
 
57
+ def from_other_data
58
+ (@flags & (0x01 << 3)) > 0
59
+ end
60
+
57
61
  def to_hash
58
62
  return {} if @size == 0
59
63
 
@@ -71,4 +75,4 @@ class PSD
71
75
  }
72
76
  end
73
77
  end
74
- end
78
+ end
@@ -2,6 +2,7 @@ require 'psd/nodes/ancestry'
2
2
  require 'psd/nodes/build_preview'
3
3
  require 'psd/nodes/search'
4
4
  require 'psd/nodes/layer_comps'
5
+ require 'psd/nodes/locking'
5
6
 
6
7
  # Internal structure to help us build trees of a Photoshop documents.
7
8
  # A lot of method names borrowed from the Ruby ancestry gem.
@@ -15,6 +16,7 @@ class PSD
15
16
  include Search
16
17
  include LayerComps
17
18
  include BuildPreview
19
+ include Locking
18
20
 
19
21
  # Default properties that all nodes contain
20
22
  PROPERTIES = [:name, :left, :right, :top, :bottom, :height, :width]
@@ -91,6 +93,17 @@ class PSD
91
93
  end
92
94
  alias_method :clipped_by, :clipping_mask
93
95
 
96
+ # Color label is a little tricky. If you set the color of a group, all
97
+ # of it's descendants inhert the color unless manually overridden. So,
98
+ # if this node has no defined color, we have to walk up the ancestry tree
99
+ # to make sure the color isn't set somewhere else.
100
+ def color_label
101
+ color = layer.sheet_color.color
102
+ return color if color != :no_color || node.parent.root?
103
+
104
+ parent.color_label
105
+ end
106
+
94
107
  def layer?
95
108
  is_a?(PSD::Node::Layer)
96
109
  end
@@ -0,0 +1,36 @@
1
+ class PSD
2
+ module Node
3
+ # Locking is inherited by descendants, but Photoshop doesn't reflect
4
+ # this directly in the file, so we have to recursively traverse the
5
+ # ancestry tree to make sure an ancestor isn't locked.
6
+ module Locking
7
+ def all_locked?
8
+ return true if layer.all_locked?
9
+ return false if parent.root?
10
+ return parent.all_locked?
11
+ end
12
+
13
+ def any_locked?
14
+ position_locked? || composite_locked? || transparency_locked?
15
+ end
16
+
17
+ def position_locked?
18
+ return true if layer.position_locked?
19
+ return false if parent.root?
20
+ return parent.position_locked?
21
+ end
22
+
23
+ def composite_locked?
24
+ return true if layer.composite_locked?
25
+ return false if parent.root?
26
+ return parent.composite_locked?
27
+ end
28
+
29
+ def transparency_locked?
30
+ return true if layer.transparency_locked?
31
+ return false if parent.root?
32
+ return parent.transparency_locked?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,3 @@
1
1
  class PSD
2
- VERSION = "3.4.0"
2
+ VERSION = "3.5.0"
3
3
  end
@@ -45,10 +45,10 @@ describe 'Locked' do
45
45
  expect(psd.tree.children[7].composite_locked?).to eq(true)
46
46
  expect(psd.tree.children[7].transparency_locked?).to eq(true)
47
47
 
48
- expect(psd.tree.children[7].children[0].position_locked?).to eq(false)
49
- expect(psd.tree.children[7].children[0].all_locked?).to eq(false)
50
- expect(psd.tree.children[7].children[0].composite_locked?).to eq(false)
51
- expect(psd.tree.children[7].children[0].transparency_locked?).to eq(false)
48
+ expect(psd.tree.children[7].children[0].position_locked?).to eq(true)
49
+ expect(psd.tree.children[7].children[0].all_locked?).to eq(true)
50
+ expect(psd.tree.children[7].children[0].composite_locked?).to eq(true)
51
+ expect(psd.tree.children[7].children[0].transparency_locked?).to eq(true)
52
52
 
53
53
  expect(psd.tree.children[7].children[1].position_locked?).to eq(true)
54
54
  expect(psd.tree.children[7].children[1].all_locked?).to eq(true)
@@ -56,9 +56,9 @@ describe 'Locked' do
56
56
  expect(psd.tree.children[7].children[1].transparency_locked?).to eq(true)
57
57
 
58
58
  expect(psd.tree.children[7].children[1].children[0].position_locked?).to eq(true)
59
- expect(psd.tree.children[7].children[1].children[0].all_locked?).to eq(false)
60
- expect(psd.tree.children[7].children[1].children[0].composite_locked?).to eq(false)
61
- expect(psd.tree.children[7].children[1].children[0].transparency_locked?).to eq(false)
59
+ expect(psd.tree.children[7].children[1].children[0].all_locked?).to eq(true)
60
+ expect(psd.tree.children[7].children[1].children[0].composite_locked?).to eq(true)
61
+ expect(psd.tree.children[7].children[1].children[0].transparency_locked?).to eq(true)
62
62
 
63
63
  expect(psd.tree.children[8].position_locked?).to eq(true)
64
64
  expect(psd.tree.children[8].all_locked?).to eq(false)
@@ -75,4 +75,4 @@ describe 'Locked' do
75
75
  expect(psd.tree.children[12].composite_locked?).to eq(false)
76
76
  expect(psd.tree.children[12].transparency_locked?).to eq(false)
77
77
  end
78
- end
78
+ 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: 3.4.0
4
+ version: 3.5.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: 2015-10-12 00:00:00.000000000 Z
12
+ date: 2015-11-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -164,29 +164,47 @@ files:
164
164
  - lib/psd/layer/exporting.rb
165
165
  - lib/psd/layer/helpers.rb
166
166
  - lib/psd/layer/info.rb
167
+ - lib/psd/layer/info/black_white.rb
167
168
  - lib/psd/layer/info/blend_clipping_elements.rb
168
169
  - lib/psd/layer/info/blend_interior_elements.rb
170
+ - lib/psd/layer/info/brightness_contrast.rb
171
+ - lib/psd/layer/info/channel_mixer.rb
172
+ - lib/psd/layer/info/color_balance.rb
173
+ - lib/psd/layer/info/color_lookup.rb
174
+ - lib/psd/layer/info/content_generator.rb
175
+ - lib/psd/layer/info/curves.rb
176
+ - lib/psd/layer/info/exposure.rb
169
177
  - lib/psd/layer/info/fill_opacity.rb
170
178
  - lib/psd/layer/info/gradient_fill.rb
179
+ - lib/psd/layer/info/gradient_map.rb
180
+ - lib/psd/layer/info/hue_saturation.rb
181
+ - lib/psd/layer/info/invert.rb
171
182
  - lib/psd/layer/info/layer_group.rb
172
183
  - lib/psd/layer/info/layer_id.rb
173
184
  - lib/psd/layer/info/layer_name_source.rb
174
185
  - lib/psd/layer/info/layer_section_divider.rb
175
186
  - lib/psd/layer/info/legacy_typetool.rb
187
+ - lib/psd/layer/info/levels.rb
176
188
  - lib/psd/layer/info/locked.rb
177
189
  - lib/psd/layer/info/metadata_setting.rb
178
190
  - lib/psd/layer/info/object_effects.rb
179
191
  - lib/psd/layer/info/pattern.rb
192
+ - lib/psd/layer/info/pattern_fill.rb
193
+ - lib/psd/layer/info/photo_filter.rb
180
194
  - lib/psd/layer/info/placed_layer.rb
195
+ - lib/psd/layer/info/posterize.rb
181
196
  - lib/psd/layer/info/reference_point.rb
197
+ - lib/psd/layer/info/selective_color.rb
182
198
  - lib/psd/layer/info/sheet_color.rb
183
199
  - lib/psd/layer/info/solid_color.rb
200
+ - lib/psd/layer/info/threshold.rb
184
201
  - lib/psd/layer/info/typetool.rb
185
202
  - lib/psd/layer/info/unicode_name.rb
186
203
  - lib/psd/layer/info/vector_mask.rb
187
204
  - lib/psd/layer/info/vector_origination.rb
188
205
  - lib/psd/layer/info/vector_stroke.rb
189
206
  - lib/psd/layer/info/vector_stroke_content.rb
207
+ - lib/psd/layer/info/vibrance.rb
190
208
  - lib/psd/layer/mask.rb
191
209
  - lib/psd/layer/name.rb
192
210
  - lib/psd/layer/path_components.rb
@@ -202,6 +220,7 @@ files:
202
220
  - lib/psd/nodes/group.rb
203
221
  - lib/psd/nodes/layer.rb
204
222
  - lib/psd/nodes/layer_comps.rb
223
+ - lib/psd/nodes/locking.rb
205
224
  - lib/psd/nodes/root.rb
206
225
  - lib/psd/nodes/search.rb
207
226
  - lib/psd/path_record.rb