psd 3.4.0 → 3.5.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: 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