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
@@ -1,11 +1,13 @@
1
+ require 'psd/resources/base'
2
+
1
3
  class PSD
2
4
  class Resource
3
- class Section
4
- class Slices < Section
5
- attr_reader :data, :version
5
+ module Section
6
+ class Slices < Base
7
+ resource_id 1050
8
+ name :slices
6
9
 
7
- def self.id; 1050; end
8
- def self.name; :slices; end
10
+ attr_reader :data, :version
9
11
 
10
12
  def parse
11
13
  @version = @file.read_int
@@ -0,0 +1,22 @@
1
+ require 'psd/resources/base'
2
+
3
+ class PSD
4
+ class Resource
5
+ module Section
6
+ class WorkPath < Base
7
+ resource_id 1025
8
+ name :work_path
9
+
10
+ def parse
11
+ paths = []
12
+ record_count = @resource.size / 26
13
+ record_count.times do
14
+ paths << PathRecord.new(@file)
15
+ end
16
+
17
+ @resource.data = paths
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,46 @@
1
+ require 'psd/resources/base'
2
+
3
+ class PSD
4
+ class Resource
5
+ module Section
6
+ class XMPMetadata < Base
7
+ resource_id 1060
8
+ name :xmp_metadata
9
+
10
+ attr_reader :xml, :data
11
+ alias_method :to_hash, :data
12
+
13
+ def parse
14
+ @xml = @file.read(@resource.size)
15
+ @data = {}
16
+
17
+ @xmp = XMP.new(xml)
18
+ @xmp.namespaces.each do |a|
19
+ parse_tree(a.to_sym)
20
+ end
21
+ rescue
22
+ PSD.logger.error "Unable to parse XMP Metadata"
23
+ ensure
24
+ @resource.data = self
25
+ end
26
+
27
+ private
28
+
29
+ def parse_tree(attr_name)
30
+ @data[attr_name] = {}
31
+ @xmp.send(attr_name).attributes.each do |a|
32
+ begin
33
+ @data[attr_name][a.to_sym] = @xmp.send(attr_name).send(a)[0]
34
+ rescue
35
+ @data[attr_name][a.to_sym] = parse_text_node(@xmp.send(attr_name), "//#{attr_name}:#{a}")
36
+ end
37
+ end
38
+ end
39
+
40
+ def parse_text_node(node, path)
41
+ node.send(:xml).xpath(path).first.text
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
data/lib/psd/resources.rb CHANGED
@@ -1,11 +1,13 @@
1
+ require 'psd/resource_section'
2
+ require 'psd/resource'
3
+ require 'psd/resources/base'
4
+
1
5
  class PSD
2
6
  # Parses and reads all of the Resource records in the document.
3
7
  class Resources
4
- include Section
5
-
6
8
  attr_reader :resources
7
9
  alias :data :resources
8
-
10
+
9
11
  def initialize(file)
10
12
  @file = file
11
13
  @resources = {}
@@ -15,14 +17,9 @@ class PSD
15
17
 
16
18
  # Parses each Resource and stores them.
17
19
  def parse
18
- start_section
19
-
20
- n = length
21
- start = @file.tell
22
-
23
- while n > 0
24
- pos = @file.tell
20
+ finish = length + @file.tell
25
21
 
22
+ while @file.tell < finish
26
23
  resource = Resource.new(@file)
27
24
  resource.parse
28
25
 
@@ -33,14 +30,9 @@ class PSD
33
30
  @type_index[name] = resource.id unless name.nil?
34
31
 
35
32
  @file.seek resource_end
36
- n -= @file.tell - pos
37
33
  end
38
34
 
39
- unless n == 0
40
- @file.seek start + length
41
- end
42
-
43
- end_section
35
+ @file.seek finish if @file.tell != finish
44
36
  end
45
37
 
46
38
  def skip
@@ -55,15 +47,19 @@ class PSD
55
47
  end
56
48
  end
57
49
 
50
+ # Paths exist between resource ID 2000 and 2997
51
+ def saved_paths
52
+ @resources.
53
+ select { |id, r| id >= 2000 && id <= 2997 }.
54
+ map { |id, r| r }
55
+ end
56
+
58
57
  def by_type(id)
59
58
  @resources[@type_index[id]]
60
59
  end
61
60
 
62
- private
63
-
64
61
  def length
65
- return @length unless @length.nil?
66
- @length = @file.read_int
62
+ @length ||= @file.read_int
67
63
  end
68
64
  end
69
- end
65
+ end
data/lib/psd/slice.rb ADDED
@@ -0,0 +1,44 @@
1
+ class PSD
2
+ class Slice
3
+ attr_reader :id, :group_id, :origin, :associated_layer_id, :name, :type,
4
+ :bounds, :url, :target, :message, :alt, :cell_text_is_html,
5
+ :cell_text, :horizontal_alignment, :vertical_alignment,
6
+ :color, :outset
7
+
8
+ def initialize(psd, data)
9
+ @psd = psd
10
+ @keys = data.keys
11
+ data.each do |k, v|
12
+ instance_variable_set("@#{k}", v)
13
+ end
14
+ end
15
+
16
+ [:left, :top, :right, :bottom].each do |dir|
17
+ define_method(dir) { @bounds[dir] }
18
+ end
19
+
20
+ def width
21
+ right - left
22
+ end
23
+
24
+ def height
25
+ bottom - top
26
+ end
27
+
28
+ def associated_layer
29
+ @psd.tree.find_by_id(associated_layer_id)
30
+ end
31
+
32
+ def to_png
33
+ @png ||= @psd.image.to_png.crop(left, top, width, height)
34
+ end
35
+
36
+ def save_as_png(file)
37
+ @png.save(file, :fast_rgba)
38
+ end
39
+
40
+ def to_hash
41
+ Hash[@keys.map { |k| [k.to_sym, self.send(k)] }]
42
+ end
43
+ end
44
+ end
data/lib/psd/slices.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'psd/slice'
2
+
3
+ class PSD
4
+ module Slices
5
+ def slices_by_name(name)
6
+ slices.select { |s| s.name == name }
7
+ end
8
+
9
+ def slice_by_id(id)
10
+ slices.select { |s| s.id == id }.first
11
+ end
12
+ end
13
+ end
data/lib/psd/util.rb CHANGED
@@ -12,7 +12,9 @@ class PSD
12
12
  end
13
13
 
14
14
  def clamp(num, min, max)
15
- [min, num, max].sort[1]
15
+ return max if num > max
16
+ return min if num < min
17
+ num
16
18
  end
17
19
  end
18
- end
20
+ end
data/lib/psd/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class PSD
2
- VERSION = "2.1.2"
2
+ VERSION = "3.9.0"
3
3
  end
data/lib/psd.rb CHANGED
@@ -1,21 +1,29 @@
1
- require "bindata"
2
- require "psd/enginedata"
3
- require "chunky_png"
4
-
5
- require_relative 'psd/section'
6
-
7
- dir_root = File.dirname(File.absolute_path(__FILE__)) + '/psd'
8
- [
9
- '/image_exports/*',
10
- '/image_formats/*',
11
- '/image_modes/*',
12
- '/nodes/*',
13
- '/layer_info/*',
14
- '/layer/*',
15
- '/**/*'
16
- ].each do |path|
17
- Dir.glob(dir_root + path) { |file| require file if File.file?(file) }
18
- end
1
+ require 'forwardable'
2
+ require 'psd/enginedata'
3
+ require 'chunky_png'
4
+ require 'xmp'
5
+
6
+ require 'psd/blend_mode'
7
+ require 'psd/channel_image'
8
+ require 'psd/color'
9
+ require 'psd/descriptor'
10
+ require 'psd/file'
11
+ require 'psd/header'
12
+ require 'psd/helpers'
13
+ require 'psd/image'
14
+ require 'psd/layer'
15
+ require 'psd/layer_info'
16
+ require 'psd/layer_mask'
17
+ require 'psd/lazy_execute'
18
+ require 'psd/logger'
19
+ require 'psd/mask'
20
+ require 'psd/node'
21
+ require 'psd/path_record'
22
+ require 'psd/renderer'
23
+ require 'psd/resources'
24
+ require 'psd/slices'
25
+ require 'psd/util'
26
+ require 'psd/version'
19
27
 
20
28
  # A general purpose parser for Photoshop files. PSDs are broken up in to 4 logical sections:
21
29
  # the header, resources, the layer mask (including layers), and the preview image. We parse
@@ -23,7 +31,7 @@ end
23
31
  class PSD
24
32
  include Logger
25
33
  include Helpers
26
- include NodeExporting
34
+ include Slices
27
35
 
28
36
  attr_reader :file, :opts
29
37
  alias :options :opts
@@ -86,7 +94,9 @@ class PSD
86
94
  def header
87
95
  return @header if @header
88
96
 
89
- @header = Header.read(@file)
97
+ @header = Header.new(@file)
98
+ @header.parse!
99
+
90
100
  PSD.logger.debug @header.inspect
91
101
  end
92
102
 
@@ -127,30 +137,6 @@ class PSD
127
137
  )
128
138
  end
129
139
 
130
- # Export the current file to a new PSD. This may or may not work.
131
- def export(file)
132
- parse! unless parsed?
133
-
134
- # Create our file for writing
135
- outfile = File.open(file, 'w')
136
-
137
- # Reset the file pointer
138
- @file.seek 0
139
- @header.write outfile
140
- @file.seek @header.num_bytes, IO::SEEK_CUR
141
-
142
- # Nothing in the header or resources we want to bother with changing
143
- # right now. Write it straight to file.
144
- outfile.write @file.read(@resources.end_of_section - @file.tell)
145
-
146
- # Now, the changeable part. Layers and masks.
147
- layer_mask.export(outfile)
148
-
149
- # And the rest of the file (merged image data)
150
- outfile.write @file.read
151
- outfile.flush
152
- end
153
-
154
140
  private
155
141
 
156
142
  def ensure_header
@@ -170,4 +156,4 @@ class PSD
170
156
  @layer_mask = LayerMask.new(@file, @header, @opts)
171
157
  @layer_mask.skip
172
158
  end
173
- end
159
+ end
data/psd.gemspec CHANGED
@@ -19,10 +19,9 @@ Gem::Specification.new do |gem|
19
19
  gem.require_paths = ["lib"]
20
20
 
21
21
  gem.add_dependency 'rake'
22
- gem.add_dependency 'bindata'
23
- gem.add_dependency 'psd-enginedata', '~> 1.0'
24
-
22
+ gem.add_dependency 'psd-enginedata', '~> 1'
25
23
  gem.add_dependency 'chunky_png'
24
+ gem.add_dependency 'xmp'
26
25
 
27
26
  gem.test_files = Dir.glob("spec/**/*")
28
27
  gem.add_development_dependency 'rspec'
Binary file
Binary file
Binary file
@@ -71,6 +71,11 @@ describe "Hierarchy" do
71
71
  expect(node.path).to eq('Version A/Matte')
72
72
  end
73
73
 
74
+ it "should be able to return a path as an array" do
75
+ node = @tree.children_at_path('Version A/Matte').first
76
+ expect(node.path(:as_array)).to eq(['Version A', 'Matte'])
77
+ end
78
+
74
79
  describe "Searching" do
75
80
  it "should find a node given a path" do
76
81
  expect(@tree.children_at_path('Version A/Matte')).to be_an_instance_of(Array)
data/spec/locked_spec.rb CHANGED
@@ -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
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Photoshop Big parsing' do
4
+ before(:each) do
5
+ @psd = PSD.new('spec/files/example.psb')
6
+ end
7
+
8
+ it 'parses without error' do
9
+ @psd.parse!
10
+ expect(@psd).to be_parsed
11
+ end
12
+
13
+ describe 'Header' do
14
+ before(:each) do
15
+ @psd.parse!
16
+ end
17
+
18
+ it 'should contain data' do
19
+ expect(@psd.header).not_to be_nil
20
+ end
21
+
22
+ it 'should be the proper version' do
23
+ expect(@psd.header.version).to eq(2)
24
+ end
25
+ end
26
+
27
+ describe 'Layer Mask' do
28
+ before(:each) do
29
+ @psd.parse!
30
+ end
31
+
32
+ it 'contains data' do
33
+ expect(@psd.layer_mask).to_not be_nil
34
+ expect(@psd.layer_mask).to be_an_instance_of(PSD::LayerMask)
35
+ end
36
+
37
+ it 'contains layers' do
38
+ expect(@psd.layer_mask.layers.size).to be > 0
39
+ end
40
+ end
41
+
42
+ describe 'Layers' do
43
+ before(:each) do
44
+ @psd.parse!
45
+ end
46
+
47
+ it 'contains each layer' do
48
+ expect(@psd.layer_mask.layers.size).to eq(2)
49
+ expect(@psd.layers).to be @psd.layer_mask.layers
50
+ @psd.layers.each { |l| expect(l).to be_an_instance_of(PSD::Layer) }
51
+ end
52
+
53
+ it 'shows the proper layer names' do
54
+ expect(@psd.layers.map(&:name)).to match_array(['summer', 'haze'])
55
+ end
56
+ end
57
+ end
data/spec/text_spec.rb CHANGED
@@ -24,4 +24,16 @@ describe 'Text' do
24
24
  expect(c[-1]).to eq(";")
25
25
  end
26
26
  end
27
- end
27
+ end
28
+
29
+ describe "Justified Text" do
30
+ let (:psd) { PSD.new('spec/files/alignment_modes.psd').tap(&:parse!) }
31
+
32
+ ["left", "right", "center", "justify"].each do |alignment|
33
+ it "that is #{alignment} justified can be exported to CSS" do
34
+ type = psd.tree.children_at_path(alignment).first.type
35
+ css = type.to_css
36
+ expect(css).to include "text-align: #{alignment}"
37
+ end
38
+ end
39
+ end