psd 0.4.2 → 1.0.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 +4 -4
- data/README.md +0 -1
- data/lib/psd/color.rb +90 -92
- data/lib/psd/image_modes/greyscale.rb +0 -16
- data/lib/psd/layer_info/typetool.rb +23 -2
- data/lib/psd/layer_mask.rb +1 -1
- data/lib/psd/nodes/ancestry.rb +2 -2
- data/lib/psd/version.rb +1 -1
- data/psd.gemspec +1 -1
- data/spec/files/text.psd +0 -0
- data/spec/hierarchy_spec.rb +34 -34
- data/spec/identity_spec.rb +3 -3
- data/spec/parsing_spec.rb +42 -41
- data/spec/psd_spec.rb +6 -4
- data/spec/text_spec.rb +16 -1
- metadata +6 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 8e806c5a8d10b43d7bddb5bf2e0e9ca3843a579f
         | 
| 4 | 
            +
              data.tar.gz: 5560fc10135e67e5d396a367c5ae737cf0f84c51
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: bcac2c4003765bc89eaba409c48b860bcc6d49ec377953332dcfccbb58baecc9b7531d285a95cfeaff14c1f8102b5b8bfab341ae915b4270f67760d271abf186
         | 
| 7 | 
            +
              data.tar.gz: c8656fe0d3ccb52301f09e40856a0f90d1ad7ebeba4ba2793a0cc3edef958fd57daa9e16a69034abf1ae416420126bd1e9e456da5ba69b7edc28d0483755c3cb
         | 
    
        data/README.md
    CHANGED
    
    
    
        data/lib/psd/color.rb
    CHANGED
    
    | @@ -4,122 +4,120 @@ class PSD | |
| 4 4 | 
             
              # value of some kind. This means that we have to do all the conversion ourselves
         | 
| 5 5 | 
             
              # for each color space.
         | 
| 6 6 | 
             
              class Color
         | 
| 7 | 
            -
                instance_eval do
         | 
| 8 7 | 
             
                  # This is a relic of libpsd that will likely go away in a future version. It
         | 
| 9 8 | 
             
                  # stored the entire color value in a 32-bit address space for speed.
         | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                    end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                    color_to_argb(color)
         | 
| 9 | 
            +
                def self.color_space_to_argb(color_space, color_component)
         | 
| 10 | 
            +
                  color = case color_space
         | 
| 11 | 
            +
                  when 0
         | 
| 12 | 
            +
                    rgb_to_color *color_component
         | 
| 13 | 
            +
                  when 1
         | 
| 14 | 
            +
                    hsb_to_color color_component[0], 
         | 
| 15 | 
            +
                      color_component[1] / 100.0, color_component[2] / 100.0
         | 
| 16 | 
            +
                  when 2
         | 
| 17 | 
            +
                    cmyk_to_color color_component[0] / 100.0,
         | 
| 18 | 
            +
                      color_component[1] / 100.0, color_component[2] / 100.0,
         | 
| 19 | 
            +
                      color_component[3] / 100.0
         | 
| 20 | 
            +
                  when 7
         | 
| 21 | 
            +
                    lab_to_color *color_component
         | 
| 22 | 
            +
                  else
         | 
| 23 | 
            +
                    0x00FFFFFF
         | 
| 28 24 | 
             
                  end
         | 
| 29 25 |  | 
| 30 | 
            -
                   | 
| 31 | 
            -
             | 
| 32 | 
            -
                      (color) >> 24,
         | 
| 33 | 
            -
                      ((color) & 0x00FF0000) >> 16,
         | 
| 34 | 
            -
                      ((color) & 0x0000FF00) >> 8,
         | 
| 35 | 
            -
                      (color) & 0x000000FF
         | 
| 36 | 
            -
                    ]
         | 
| 37 | 
            -
                  end
         | 
| 26 | 
            +
                  color_to_argb(color)
         | 
| 27 | 
            +
                end
         | 
| 38 28 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 29 | 
            +
                def self.color_to_argb(color)
         | 
| 30 | 
            +
                  [
         | 
| 31 | 
            +
                    (color) >> 24,
         | 
| 32 | 
            +
                    ((color) & 0x00FF0000) >> 16,
         | 
| 33 | 
            +
                    ((color) & 0x0000FF00) >> 8,
         | 
| 34 | 
            +
                    (color) & 0x000000FF
         | 
| 35 | 
            +
                  ]
         | 
| 36 | 
            +
                end
         | 
| 42 37 |  | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 38 | 
            +
                def self.rgb_to_color(*args)
         | 
| 39 | 
            +
                  argb_to_color(255, *args)
         | 
| 40 | 
            +
                end
         | 
| 46 41 |  | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 42 | 
            +
                def self.argb_to_color(a, r, g, b)
         | 
| 43 | 
            +
                  (a << 24) | (r << 16) | (g << 8) | b
         | 
| 44 | 
            +
                end
         | 
| 50 45 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 46 | 
            +
                def self.hsb_to_color(*args)
         | 
| 47 | 
            +
                  ahsb_to_color(255, *args)
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def self.ahsb_to_color(alpha, hue, saturation, brightness)
         | 
| 51 | 
            +
                  if saturation == 0.0
         | 
| 52 | 
            +
                    b = g = r = (255 * brightness).to_i
         | 
| 53 | 
            +
                  else
         | 
| 54 | 
            +
                    if brightness <= 0.5
         | 
| 55 | 
            +
                      m2 = brightness * (1 + saturation)
         | 
| 54 56 | 
             
                    else
         | 
| 55 | 
            -
                       | 
| 56 | 
            -
                        m2 = brightness * (1 + saturation)
         | 
| 57 | 
            -
                      else
         | 
| 58 | 
            -
                        m2 = brightness + saturation - brightness * saturation
         | 
| 59 | 
            -
                      end
         | 
| 60 | 
            -
             | 
| 61 | 
            -
                      m1 = 2 * brightness - m2
         | 
| 62 | 
            -
                      r = hue_to_color(hue + 120, m1, m2)
         | 
| 63 | 
            -
                      g = hue_to_color(hue, m1, m2)
         | 
| 64 | 
            -
                      b = hue_to_color(hue - 120, m1, m2)
         | 
| 57 | 
            +
                      m2 = brightness + saturation - brightness * saturation
         | 
| 65 58 | 
             
                    end
         | 
| 66 59 |  | 
| 67 | 
            -
                     | 
| 60 | 
            +
                    m1 = 2 * brightness - m2
         | 
| 61 | 
            +
                    r = hue_to_color(hue + 120, m1, m2)
         | 
| 62 | 
            +
                    g = hue_to_color(hue, m1, m2)
         | 
| 63 | 
            +
                    b = hue_to_color(hue - 120, m1, m2)
         | 
| 68 64 | 
             
                  end
         | 
| 69 65 |  | 
| 70 | 
            -
                   | 
| 71 | 
            -
             | 
| 72 | 
            -
                    if hue < 60
         | 
| 73 | 
            -
                      v = m1 + (m2 - m1) * hue / 60
         | 
| 74 | 
            -
                    elsif hue < 180
         | 
| 75 | 
            -
                      v = m2
         | 
| 76 | 
            -
                    elsif hue < 240
         | 
| 77 | 
            -
                      v = m1 + (m2 - m1) * (240 - hue) / 60
         | 
| 78 | 
            -
                    else
         | 
| 79 | 
            -
                      v = m1
         | 
| 80 | 
            -
                    end
         | 
| 66 | 
            +
                  argb_to_color alpha, r, g, b
         | 
| 67 | 
            +
                end
         | 
| 81 68 |  | 
| 82 | 
            -
             | 
| 69 | 
            +
                def self.hue_to_color(hue, m1, m2)
         | 
| 70 | 
            +
                  hue = (hue % 360).to_i
         | 
| 71 | 
            +
                  if hue < 60
         | 
| 72 | 
            +
                    v = m1 + (m2 - m1) * hue / 60
         | 
| 73 | 
            +
                  elsif hue < 180
         | 
| 74 | 
            +
                    v = m2
         | 
| 75 | 
            +
                  elsif hue < 240
         | 
| 76 | 
            +
                    v = m1 + (m2 - m1) * (240 - hue) / 60
         | 
| 77 | 
            +
                  else
         | 
| 78 | 
            +
                    v = m1
         | 
| 83 79 | 
             
                  end
         | 
| 84 80 |  | 
| 85 | 
            -
                   | 
| 86 | 
            -
             | 
| 87 | 
            -
                    g = 1 - (m * (1 - k) + k) * 255
         | 
| 88 | 
            -
                    b = 1 - (y * (1 - k) + k) * 255
         | 
| 81 | 
            +
                  (v * 255).to_i
         | 
| 82 | 
            +
                end
         | 
| 89 83 |  | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 84 | 
            +
                def self.cmyk_to_color(c, m, y, k)
         | 
| 85 | 
            +
                  r = 1 - (c * (1 - k) + k) * 255
         | 
| 86 | 
            +
                  g = 1 - (m * (1 - k) + k) * 255
         | 
| 87 | 
            +
                  b = 1 - (y * (1 - k) + k) * 255
         | 
| 93 88 |  | 
| 94 | 
            -
             | 
| 95 | 
            -
                   | 
| 89 | 
            +
                  r = [0, r, 255].sort[1]
         | 
| 90 | 
            +
                  g = [0, g, 255].sort[1]
         | 
| 91 | 
            +
                  b = [0, b, 255].sort[1]
         | 
| 96 92 |  | 
| 97 | 
            -
                   | 
| 98 | 
            -
             | 
| 99 | 
            -
                  end
         | 
| 93 | 
            +
                  rgb_to_color r, g, b
         | 
| 94 | 
            +
                end
         | 
| 100 95 |  | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
                  end
         | 
| 96 | 
            +
                def self.lab_to_color(*args)
         | 
| 97 | 
            +
                  alab_to_color(255, *args)
         | 
| 98 | 
            +
                end
         | 
| 105 99 |  | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 100 | 
            +
                def self.alab_to_color(alpha, l, a, b)
         | 
| 101 | 
            +
                  xyz = lab_to_xyz(l, a, b)
         | 
| 102 | 
            +
                  axyz_to_color alpha, xyz[:x], xyz[:y], xyz[:z]
         | 
| 103 | 
            +
                end
         | 
| 110 104 |  | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
                   | 
| 105 | 
            +
                def self.lab_to_xyz(l, a, b)
         | 
| 106 | 
            +
                  y = (l + 16) / 116
         | 
| 107 | 
            +
                  x = y + (a / 500)
         | 
| 108 | 
            +
                  z = y - (b / 200)
         | 
| 115 109 |  | 
| 116 | 
            -
                   | 
| 117 | 
            -
                     | 
| 118 | 
            -
                      r: (65535 - (c * (255 - k) + (k << 8))) >> 8,
         | 
| 119 | 
            -
                      g: (65535 - (m * (255 - k) + (k << 8))) >> 8,
         | 
| 120 | 
            -
                      b: (65535 - (y * (255 - k) + (k << 8))) >> 8
         | 
| 121 | 
            -
                    }.map { |k, v| [k, Util.clamp(v, 0, 255)] }]
         | 
| 110 | 
            +
                  x, y, z = [x, y, z].map do |n|
         | 
| 111 | 
            +
                    n**3 > 0.008856 ? n**3 : (n - 16 / 116) / 7.787
         | 
| 122 112 | 
             
                  end
         | 
| 123 113 | 
             
                end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                def self.cmyk_to_rgb(c, m, y, k)
         | 
| 116 | 
            +
                  Hash[{
         | 
| 117 | 
            +
                    r: (65535 - (c * (255 - k) + (k << 8))) >> 8,
         | 
| 118 | 
            +
                    g: (65535 - (m * (255 - k) + (k << 8))) >> 8,
         | 
| 119 | 
            +
                    b: (65535 - (y * (255 - k) + (k << 8))) >> 8
         | 
| 120 | 
            +
                  }.map { |k, v| [k, Util.clamp(v, 0, 255)] }]
         | 
| 121 | 
            +
                end
         | 
| 124 122 | 
             
              end
         | 
| 125 123 | 
             
            end
         | 
| @@ -2,22 +2,6 @@ class PSD::Image::Mode | |
| 2 2 | 
             
              module Greyscale
         | 
| 3 3 | 
             
                private
         | 
| 4 4 |  | 
| 5 | 
            -
                def combine_greyscale8_channel
         | 
| 6 | 
            -
                  if channels == 2
         | 
| 7 | 
            -
                    # We have an alpha channel
         | 
| 8 | 
            -
                    @num_pixels.times do |i|
         | 
| 9 | 
            -
                      alpha = @channel_data[i]
         | 
| 10 | 
            -
                      grey = @channel_data[@channel_length + i]
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                      @pixel_data.push grey, grey, grey, alpha
         | 
| 13 | 
            -
                    end
         | 
| 14 | 
            -
                  else
         | 
| 15 | 
            -
                    @num_pixels.times do |i|
         | 
| 16 | 
            -
                      @pixel_data.push *([@channel_data[i]] * 3), 255
         | 
| 17 | 
            -
                    end
         | 
| 18 | 
            -
                  end
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
             | 
| 21 5 | 
             
                def combine_greyscale_channel
         | 
| 22 6 | 
             
                  if channels == 2
         | 
| 23 7 | 
             
                    (0...@num_pixels).step(pixel_step) do |i|
         | 
| @@ -58,7 +58,7 @@ class PSD | |
| 58 58 | 
             
                    name: fonts.first,
         | 
| 59 59 | 
             
                    sizes: sizes,
         | 
| 60 60 | 
             
                    colors: colors,
         | 
| 61 | 
            -
                    css:  | 
| 61 | 
            +
                    css: to_css
         | 
| 62 62 | 
             
                  }
         | 
| 63 63 | 
             
                end
         | 
| 64 64 |  | 
| @@ -80,7 +80,8 @@ class PSD | |
| 80 80 | 
             
                #
         | 
| 81 81 | 
             
                # => [[255, 0, 0, 255], [0, 0, 255, 255]]
         | 
| 82 82 | 
             
                def colors
         | 
| 83 | 
            -
                   | 
| 83 | 
            +
                  # If the color is opaque black, this field is sometimes omitted.
         | 
| 84 | 
            +
                  return [[0, 0, 0, 255]] if engine_data.nil? || !styles.has_key?('FillColor')
         | 
| 84 85 | 
             
                  styles['FillColor'].map { |s|
         | 
| 85 86 | 
             
                    values = s['Values'].map { |v| (v * 255).round }
         | 
| 86 87 | 
             
                    values << values.shift # Change ARGB -> RGBA for consistency
         | 
| @@ -115,6 +116,26 @@ class PSD | |
| 115 116 | 
             
                  @parser ||= PSD::EngineData.new(@data[:text]['EngineData'])
         | 
| 116 117 | 
             
                end
         | 
| 117 118 |  | 
| 119 | 
            +
                # Creates the CSS string and returns it. Each property is newline separated
         | 
| 120 | 
            +
                # and not all properties may be present depending on the document.
         | 
| 121 | 
            +
                #
         | 
| 122 | 
            +
                # Colors are returned in rgba() format and fonts may include some internal
         | 
| 123 | 
            +
                # Photoshop fonts.
         | 
| 124 | 
            +
                def to_css      
         | 
| 125 | 
            +
                  definition = {
         | 
| 126 | 
            +
                    'font-family' => fonts.join(', '),
         | 
| 127 | 
            +
                    'font-size' => "#{sizes.first}pt",
         | 
| 128 | 
            +
                    'color' => "rgba(#{colors.first.join(', ')})"
         | 
| 129 | 
            +
                  }
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  css = []
         | 
| 132 | 
            +
                  definition.each do |k, v|
         | 
| 133 | 
            +
                    css << "#{k}: #{v};"
         | 
| 134 | 
            +
                  end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                  css.join("\n")
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
             | 
| 118 139 | 
             
                def to_hash
         | 
| 119 140 | 
             
                  {
         | 
| 120 141 | 
             
                    value:      text_value,
         | 
    
        data/lib/psd/layer_mask.rb
    CHANGED
    
    | @@ -115,7 +115,7 @@ class PSD | |
| 115 115 | 
             
                  @global_mask = {}
         | 
| 116 116 | 
             
                  @global_mask[:overlay_color_space] = @file.read_short
         | 
| 117 117 | 
             
                  @global_mask[:color_components] = 4.times.map { |i| @file.read_short >> 8 }
         | 
| 118 | 
            -
                  @global_mask[:opacity] = @file.read_short
         | 
| 118 | 
            +
                  @global_mask[:opacity] = @file.read_short / 16.0
         | 
| 119 119 |  | 
| 120 120 | 
             
                  # 0 = color selected, 1 = color protected, 128 = use value per layer
         | 
| 121 121 | 
             
                  @global_mask[:kind] = @file.read(1).bytes.to_a[0]
         | 
    
        data/lib/psd/nodes/ancestry.rb
    CHANGED
    
    | @@ -27,7 +27,7 @@ class PSD | |
| 27 27 | 
             
                  end
         | 
| 28 28 |  | 
| 29 29 | 
             
                  # Inverse of has_children?
         | 
| 30 | 
            -
                  def  | 
| 30 | 
            +
                  def childless?
         | 
| 31 31 | 
             
                    !has_children?
         | 
| 32 32 | 
             
                  end
         | 
| 33 33 |  | 
| @@ -44,7 +44,7 @@ class PSD | |
| 44 44 | 
             
                  end
         | 
| 45 45 |  | 
| 46 46 | 
             
                  # Is this node the only descendant of its parent?
         | 
| 47 | 
            -
                  def  | 
| 47 | 
            +
                  def only_child?
         | 
| 48 48 | 
             
                    siblings.length == 1
         | 
| 49 49 | 
             
                  end
         | 
| 50 50 |  | 
    
        data/lib/psd/version.rb
    CHANGED
    
    
    
        data/psd.gemspec
    CHANGED
    
    | @@ -20,7 +20,7 @@ Gem::Specification.new do |gem| | |
| 20 20 |  | 
| 21 21 | 
             
              gem.add_dependency "bindata"
         | 
| 22 22 | 
             
              gem.add_dependency "oily_png"
         | 
| 23 | 
            -
              gem.add_dependency 'psd-enginedata'
         | 
| 23 | 
            +
              gem.add_dependency 'psd-enginedata', '~> 1.0'
         | 
| 24 24 |  | 
| 25 25 | 
             
              gem.test_files = Dir.glob("spec/**/*")
         | 
| 26 26 | 
             
              gem.add_development_dependency 'rspec'
         | 
    
        data/spec/files/text.psd
    CHANGED
    
    | Binary file | 
    
        data/spec/hierarchy_spec.rb
    CHANGED
    
    | @@ -9,8 +9,8 @@ describe "Hierarchy" do | |
| 9 9 | 
             
                @psd.parse!
         | 
| 10 10 |  | 
| 11 11 | 
             
                tree = @psd.tree.to_hash
         | 
| 12 | 
            -
                tree. | 
| 13 | 
            -
                tree[:children].length. | 
| 12 | 
            +
                expect(tree).to include :children
         | 
| 13 | 
            +
                expect(tree[:children].length).to eq(3)
         | 
| 14 14 | 
             
              end
         | 
| 15 15 |  | 
| 16 16 | 
             
              describe "Ancestry" do
         | 
| @@ -20,66 +20,66 @@ describe "Hierarchy" do | |
| 20 20 | 
             
                end
         | 
| 21 21 |  | 
| 22 22 | 
             
                it "should provide tree traversal methods" do
         | 
| 23 | 
            -
                  @tree.respond_to | 
| 24 | 
            -
                  @tree.respond_to | 
| 25 | 
            -
                  @tree.respond_to | 
| 26 | 
            -
                  @tree.respond_to | 
| 23 | 
            +
                  expect(@tree).to respond_to(:root)
         | 
| 24 | 
            +
                  expect(@tree).to respond_to(:siblings)
         | 
| 25 | 
            +
                  expect(@tree).to respond_to(:descendants)
         | 
| 26 | 
            +
                  expect(@tree).to respond_to(:subtree)
         | 
| 27 27 | 
             
                end
         | 
| 28 28 |  | 
| 29 29 | 
             
                it "should properly identify the root node" do
         | 
| 30 | 
            -
                  @tree.root | 
| 31 | 
            -
                  @tree.root. | 
| 32 | 
            -
                  @tree.children.last.root. | 
| 30 | 
            +
                  expect(@tree.root?).to be_true
         | 
| 31 | 
            +
                  expect(@tree.root).to be @tree
         | 
| 32 | 
            +
                  expect(@tree.children.last.root).to be @tree
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 35 | 
             
                it "should retrieve all descendants of a node" do
         | 
| 36 | 
            -
                  @tree.descendants.size. | 
| 37 | 
            -
                  @tree.descendant_layers.size. | 
| 38 | 
            -
                  @tree.descendant_groups.size. | 
| 39 | 
            -
                  @tree.descendants.first. | 
| 36 | 
            +
                  expect(@tree.descendants.size).to eq(12)
         | 
| 37 | 
            +
                  expect(@tree.descendant_layers.size).to eq(9)
         | 
| 38 | 
            +
                  expect(@tree.descendant_groups.size).to eq(3)
         | 
| 39 | 
            +
                  expect(@tree.descendants.first).not_to be @tree
         | 
| 40 40 | 
             
                end
         | 
| 41 41 |  | 
| 42 42 | 
             
                it "should retreive the entire subtree of a node" do
         | 
| 43 | 
            -
                  @tree.subtree.size. | 
| 44 | 
            -
                  @tree.subtree_layers.size. | 
| 45 | 
            -
                  @tree.subtree_groups.size. | 
| 46 | 
            -
                  @tree.subtree.first. | 
| 43 | 
            +
                  expect(@tree.subtree.size).to eq(13)
         | 
| 44 | 
            +
                  expect(@tree.subtree_layers.size).to eq(9)
         | 
| 45 | 
            +
                  expect(@tree.subtree_groups.size).to eq(3)
         | 
| 46 | 
            +
                  expect(@tree.subtree.first).to be @tree
         | 
| 47 47 | 
             
                end
         | 
| 48 48 |  | 
| 49 49 | 
             
                it "should properly identify the existence of children" do
         | 
| 50 | 
            -
                  @tree. | 
| 51 | 
            -
                  @tree. | 
| 52 | 
            -
                  @tree.descendant_layers.first. | 
| 53 | 
            -
                  @tree.descendant_layers.first. | 
| 50 | 
            +
                  expect(@tree).to have_children
         | 
| 51 | 
            +
                  expect(@tree).to_not be_childless
         | 
| 52 | 
            +
                  expect(@tree.descendant_layers.first).to_not have_children
         | 
| 53 | 
            +
                  expect(@tree.descendant_layers.first).to be_childless
         | 
| 54 54 | 
             
                end
         | 
| 55 55 |  | 
| 56 56 | 
             
                it "should retrieve all siblings of a node" do
         | 
| 57 | 
            -
                  @tree.children.first.siblings. | 
| 58 | 
            -
                  @tree.children.first.siblings. | 
| 59 | 
            -
                  @tree.children.first. | 
| 60 | 
            -
                  @tree.children.first. | 
| 57 | 
            +
                  expect(@tree.children.first.siblings).to be @tree.children
         | 
| 58 | 
            +
                  expect(@tree.children.first.siblings).to include @tree.children.first
         | 
| 59 | 
            +
                  expect(@tree.children.first).to have_siblings
         | 
| 60 | 
            +
                  expect(@tree.children.first).to_not be_only_child
         | 
| 61 61 | 
             
                end
         | 
| 62 62 |  | 
| 63 63 | 
             
                it "should properly calculate node depth" do
         | 
| 64 | 
            -
                  @tree.depth. | 
| 65 | 
            -
                  @tree.descendant_layers.last.depth. | 
| 66 | 
            -
                  @tree.children.first.depth. | 
| 64 | 
            +
                  expect(@tree.depth).to eq(0)
         | 
| 65 | 
            +
                  expect(@tree.descendant_layers.last.depth).to eq(2)
         | 
| 66 | 
            +
                  expect(@tree.children.first.depth).to eq(1)
         | 
| 67 67 | 
             
                end
         | 
| 68 68 |  | 
| 69 69 | 
             
                describe "Searching" do
         | 
| 70 70 | 
             
                  it "should find a node given a path" do
         | 
| 71 | 
            -
                    @tree.children_at_path('Version A/Matte'). | 
| 72 | 
            -
                    @tree.children_at_path('Version A/Matte').size. | 
| 73 | 
            -
                    @tree.children_at_path('Version A/Matte').first. | 
| 71 | 
            +
                    expect(@tree.children_at_path('Version A/Matte')).to be_an_instance_of(Array)
         | 
| 72 | 
            +
                    expect(@tree.children_at_path('Version A/Matte').size).to eq(1)
         | 
| 73 | 
            +
                    expect(@tree.children_at_path('Version A/Matte').first).to be_an_instance_of(PSD::Node::Layer)
         | 
| 74 74 | 
             
                  end
         | 
| 75 75 |  | 
| 76 76 | 
             
                  it "should ignore leading slashes" do
         | 
| 77 | 
            -
                    @tree.children_at_path('/Version A/Matte').size. | 
| 77 | 
            +
                    expect(@tree.children_at_path('/Version A/Matte').size).to eq(1)
         | 
| 78 78 | 
             
                  end
         | 
| 79 79 |  | 
| 80 80 | 
             
                  it "should return an empty array when a node is not found" do
         | 
| 81 | 
            -
                    @tree.children_at_path(' | 
| 82 | 
            -
                    @tree.children_at_path(' | 
| 81 | 
            +
                    expect(@tree.children_at_path('NOPE')).to be_an_instance_of(Array)
         | 
| 82 | 
            +
                    expect(@tree.children_at_path('NOPE').size).to eq(0)
         | 
| 83 83 | 
             
                  end
         | 
| 84 84 | 
             
                end
         | 
| 85 85 | 
             
              end
         | 
    
        data/spec/identity_spec.rb
    CHANGED
    
    | @@ -9,7 +9,7 @@ describe "Identity exports" do | |
| 9 9 | 
             
                tmpfile = Tempfile.new("simplest_export.psd")
         | 
| 10 10 | 
             
                psd.export tmpfile.path
         | 
| 11 11 |  | 
| 12 | 
            -
                Digest::MD5.hexdigest(tmpfile.read). | 
| 12 | 
            +
                expect(Digest::MD5.hexdigest(tmpfile.read)).to eq(Digest::MD5.hexdigest(File.read(filepath)))
         | 
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 15 | 
             
              it "should export a file with a layer" do
         | 
| @@ -19,7 +19,7 @@ describe "Identity exports" do | |
| 19 19 | 
             
                tmpfile = Tempfile.new("one_layer_export.psd")
         | 
| 20 20 | 
             
                psd.export tmpfile.path
         | 
| 21 21 |  | 
| 22 | 
            -
                Digest::MD5.hexdigest(tmpfile.read). | 
| 22 | 
            +
                expect(Digest::MD5.hexdigest(tmpfile.read)).to eq(Digest::MD5.hexdigest(File.read(filepath)))
         | 
| 23 23 | 
             
              end
         | 
| 24 24 |  | 
| 25 25 | 
             
              it "should export a PSD with vector paths" do
         | 
| @@ -29,6 +29,6 @@ describe "Identity exports" do | |
| 29 29 | 
             
                tmpfile = Tempfile.new("path_export.psd")
         | 
| 30 30 | 
             
                psd.export tmpfile.path
         | 
| 31 31 |  | 
| 32 | 
            -
                Digest::MD5.hexdigest(tmpfile.read). | 
| 32 | 
            +
                expect(Digest::MD5.hexdigest(tmpfile.read)).to eq(Digest::MD5.hexdigest(File.read(filepath)))
         | 
| 33 33 | 
             
              end
         | 
| 34 34 | 
             
            end
         | 
    
        data/spec/parsing_spec.rb
    CHANGED
    
    | @@ -7,7 +7,7 @@ describe 'Parsing' do | |
| 7 7 |  | 
| 8 8 | 
             
              it "should parse without error" do
         | 
| 9 9 | 
             
                @psd.parse!
         | 
| 10 | 
            -
                @psd. | 
| 10 | 
            +
                expect(@psd).to be_parsed
         | 
| 11 11 | 
             
              end
         | 
| 12 12 |  | 
| 13 13 | 
             
              describe 'Header' do
         | 
| @@ -16,25 +16,25 @@ describe 'Parsing' do | |
| 16 16 | 
             
                end
         | 
| 17 17 |  | 
| 18 18 | 
             
                it "should contain data" do
         | 
| 19 | 
            -
                  @psd.header. | 
| 19 | 
            +
                  expect(@psd.header).not_to be_nil
         | 
| 20 20 | 
             
                end
         | 
| 21 21 |  | 
| 22 22 | 
             
                it "should be the proper version" do
         | 
| 23 | 
            -
                  @psd.header.version. | 
| 23 | 
            +
                  expect(@psd.header.version).to eq(1)
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| 26 26 | 
             
                it "should have the proper number of channels" do
         | 
| 27 | 
            -
                  @psd.header.channels. | 
| 27 | 
            +
                  expect(@psd.header.channels).to eq(3)
         | 
| 28 28 | 
             
                end
         | 
| 29 29 |  | 
| 30 30 | 
             
                it "should parse the proper document dimensions" do
         | 
| 31 | 
            -
                  @psd.header.width. | 
| 32 | 
            -
                  @psd.header.height. | 
| 31 | 
            +
                  expect(@psd.header.width).to eq(900)
         | 
| 32 | 
            +
                  expect(@psd.header.height).to eq(600)
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 35 | 
             
                it "should correctly parse the color mode" do
         | 
| 36 | 
            -
                  @psd.header.mode. | 
| 37 | 
            -
                  @psd.header.mode_name. | 
| 36 | 
            +
                  expect(@psd.header.mode).to eq(3)
         | 
| 37 | 
            +
                  expect(@psd.header.mode_name).to eq('RGBColor')
         | 
| 38 38 | 
             
                end
         | 
| 39 39 | 
             
              end
         | 
| 40 40 |  | 
| @@ -44,18 +44,18 @@ describe 'Parsing' do | |
| 44 44 | 
             
                end
         | 
| 45 45 |  | 
| 46 46 | 
             
                it "should contain data" do
         | 
| 47 | 
            -
                  @psd.resources. | 
| 48 | 
            -
                  @psd.resources.data. | 
| 49 | 
            -
                  @psd.resources.data.size. | 
| 47 | 
            +
                  expect(@psd.resources).not_to be_nil
         | 
| 48 | 
            +
                  expect(@psd.resources.data).to be_an_instance_of(Hash)
         | 
| 49 | 
            +
                  expect(@psd.resources.data.size).to be >= 1
         | 
| 50 50 | 
             
                end
         | 
| 51 51 |  | 
| 52 52 | 
             
                it "should be of type 8BIM" do
         | 
| 53 | 
            -
                  @psd.resources.data.each { |id, r| r.type. | 
| 53 | 
            +
                  @psd.resources.data.each { |id, r| expect(r.type).to eq('8BIM') }
         | 
| 54 54 | 
             
                end
         | 
| 55 55 |  | 
| 56 56 | 
             
                it "should have an ID" do
         | 
| 57 57 | 
             
                  @psd.resources.data.each do |id, r|
         | 
| 58 | 
            -
                    r.id. | 
| 58 | 
            +
                    expect(r.id).to_not be_nil
         | 
| 59 59 | 
             
                  end
         | 
| 60 60 | 
             
                end
         | 
| 61 61 | 
             
              end
         | 
| @@ -66,18 +66,19 @@ describe 'Parsing' do | |
| 66 66 | 
             
                end
         | 
| 67 67 |  | 
| 68 68 | 
             
                it "should contain data" do
         | 
| 69 | 
            -
                  @psd.layer_mask. | 
| 70 | 
            -
                  @psd.layer_mask. | 
| 69 | 
            +
                  expect(@psd.layer_mask).to_not be_nil
         | 
| 70 | 
            +
                  expect(@psd.layer_mask).to be_an_instance_of(PSD::LayerMask)
         | 
| 71 71 | 
             
                end
         | 
| 72 72 |  | 
| 73 73 | 
             
                it "should contain layers" do
         | 
| 74 | 
            -
                  @psd.layer_mask.layers.size. | 
| 74 | 
            +
                  expect(@psd.layer_mask.layers.size).to be > 0
         | 
| 75 75 | 
             
                end
         | 
| 76 76 |  | 
| 77 77 | 
             
                it "should contain the global layer mask data" do
         | 
| 78 | 
            -
                   | 
| 79 | 
            -
             | 
| 80 | 
            -
                  @psd.layer_mask.global_mask. | 
| 78 | 
            +
                  expect(@psd.layer_mask.global_mask).to_not be_nil
         | 
| 79 | 
            +
                  expect(@psd.layer_mask.global_mask).to include :overlay_color_space
         | 
| 80 | 
            +
                  expect(@psd.layer_mask.global_mask).to include :color_components
         | 
| 81 | 
            +
                  expect(@psd.layer_mask.global_mask).to include opacity: 1.0
         | 
| 81 82 | 
             
                end
         | 
| 82 83 | 
             
              end
         | 
| 83 84 |  | 
| @@ -87,48 +88,48 @@ describe 'Parsing' do | |
| 87 88 | 
             
                end
         | 
| 88 89 |  | 
| 89 90 | 
             
                it "should contain each layer" do
         | 
| 90 | 
            -
                  @psd.layer_mask.layers.size. | 
| 91 | 
            -
                  @psd.layers. | 
| 92 | 
            -
                  @psd.layers.each { |l| l. | 
| 91 | 
            +
                  expect(@psd.layer_mask.layers.size).to eq(15)
         | 
| 92 | 
            +
                  expect(@psd.layers).to be @psd.layer_mask.layers
         | 
| 93 | 
            +
                  @psd.layers.each { |l| expect(l).to be_an_instance_of(PSD::Layer) }
         | 
| 93 94 | 
             
                end
         | 
| 94 95 |  | 
| 95 96 | 
             
                it "should have a name" do
         | 
| 96 | 
            -
                  @psd.layers.first.name. | 
| 97 | 
            +
                  expect(@psd.layers.first.name).to eq('Version C')
         | 
| 97 98 | 
             
                end
         | 
| 98 99 |  | 
| 99 100 | 
             
                it "should properly identify folders" do
         | 
| 100 | 
            -
                  @psd.layers.first. | 
| 101 | 
            -
                  @psd.layers.select { |l| l.name == 'Matte' }.first. | 
| 101 | 
            +
                  expect(@psd.layers.first).to be_folder
         | 
| 102 | 
            +
                  expect(@psd.layers.select { |l| l.name == 'Matte' }.first).not_to be_folder
         | 
| 102 103 | 
             
                end
         | 
| 103 104 |  | 
| 104 105 | 
             
                it "should properly detect visibility" do
         | 
| 105 | 
            -
                  @psd.layers.first. | 
| 106 | 
            -
                   | 
| 107 | 
            -
                     | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 106 | 
            +
                  expect(@psd.layers.first).not_to be_visible
         | 
| 107 | 
            +
                  expect(
         | 
| 108 | 
            +
                    @psd
         | 
| 109 | 
            +
                      .layers
         | 
| 110 | 
            +
                      .select { |l| l.name == 'Version A' }.first
         | 
| 111 | 
            +
                  ).to be_visible
         | 
| 111 112 | 
             
                end
         | 
| 112 113 |  | 
| 113 114 | 
             
                it "should properly calculate dimensions" do
         | 
| 114 115 | 
             
                  layer = @psd.layers.select { |l| l.name == 'Logo_Glyph' }.last
         | 
| 115 | 
            -
                  layer.width. | 
| 116 | 
            -
                  layer.height. | 
| 116 | 
            +
                  expect(layer.width).to eq(142)
         | 
| 117 | 
            +
                  expect(layer.height).to eq(179)
         | 
| 117 118 | 
             
                end
         | 
| 118 119 |  | 
| 119 120 | 
             
                it "should properly calculate coordinates" do
         | 
| 120 121 | 
             
                  layer = @psd.layers.select { |l| l.name == 'Logo_Glyph' }.last
         | 
| 121 | 
            -
                  layer.left. | 
| 122 | 
            -
                  layer.top. | 
| 122 | 
            +
                  expect(layer.left).to eq(379)
         | 
| 123 | 
            +
                  expect(layer.top).to eq(210)
         | 
| 123 124 | 
             
                end
         | 
| 124 125 |  | 
| 125 126 | 
             
                it "should have a blend mode" do
         | 
| 126 | 
            -
                   | 
| 127 | 
            -
                   | 
| 128 | 
            -
                   | 
| 129 | 
            -
                   | 
| 130 | 
            -
                   | 
| 131 | 
            -
                   | 
| 127 | 
            +
                  blend_mode = @psd.layers.select { |l| l.name == 'Version A' }.last.blend_mode
         | 
| 128 | 
            +
                  expect(blend_mode).to_not be_nil
         | 
| 129 | 
            +
                  expect(blend_mode.mode).to eq('normal')
         | 
| 130 | 
            +
                  expect(blend_mode.opacity).to eq(255)
         | 
| 131 | 
            +
                  expect(blend_mode.opacity_percentage).to eq(100)
         | 
| 132 | 
            +
                  expect(blend_mode.visible).to be_true
         | 
| 132 133 | 
             
                end
         | 
| 133 134 | 
             
              end
         | 
| 134 135 | 
             
            end
         | 
    
        data/spec/psd_spec.rb
    CHANGED
    
    | @@ -5,8 +5,8 @@ describe 'PSD' do | |
| 5 5 |  | 
| 6 6 | 
             
            	it 'should open a file without a block' do
         | 
| 7 7 | 
             
                psd = PSD.open(filename)
         | 
| 8 | 
            -
                psd. | 
| 9 | 
            -
                psd. | 
| 8 | 
            +
                expect(psd).to be_parsed
         | 
| 9 | 
            +
                expect(psd).to be_an_instance_of(PSD)
         | 
| 10 10 | 
             
            	end
         | 
| 11 11 |  | 
| 12 12 | 
             
              it 'should refuse to open a bad filename' do
         | 
| @@ -15,11 +15,13 @@ describe 'PSD' do | |
| 15 15 |  | 
| 16 16 | 
             
              it 'should open a file and feed it to a block' do
         | 
| 17 17 | 
             
                PSD.open(filename) do |psd|
         | 
| 18 | 
            -
                  psd. | 
| 19 | 
            -
                  psd. | 
| 18 | 
            +
                  expect(psd).to be_parsed
         | 
| 19 | 
            +
                  expect(psd).to be_an_instance_of(PSD)
         | 
| 20 20 | 
             
                end
         | 
| 21 21 | 
             
              end
         | 
| 22 22 |  | 
| 23 | 
            +
              # We have to use #should syntax here because the DSL binds
         | 
| 24 | 
            +
              # the block to the PSD instance.
         | 
| 23 25 | 
             
              it 'should open a file and feed it to a block DSL style' do
         | 
| 24 26 | 
             
                PSD.open(filename) do
         | 
| 25 27 | 
             
                  parsed?.should == true
         | 
    
        data/spec/text_spec.rb
    CHANGED
    
    | @@ -7,6 +7,21 @@ describe 'Text' do | |
| 7 7 |  | 
| 8 8 | 
             
                text = psd.tree.children.first.text
         | 
| 9 9 | 
             
                text.should be_an_instance_of(Hash)
         | 
| 10 | 
            -
                text[:value]. | 
| 10 | 
            +
                expect(text[:value]).to eq('Test')
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              it "can be exported as CSS" do
         | 
| 14 | 
            +
                psd = PSD.new('spec/files/text.psd')
         | 
| 15 | 
            +
                psd.parse!
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                type = psd.tree.children.first.type
         | 
| 18 | 
            +
                css = type.to_css
         | 
| 19 | 
            +
                expect(css).to be_an_instance_of(String)
         | 
| 20 | 
            +
                expect(css).to include 'MyriadPro-Regular'
         | 
| 21 | 
            +
                expect(css).to include '37.0pt'
         | 
| 22 | 
            +
                expect(css).to include 'rgba(24, 24, 24, 255)'
         | 
| 23 | 
            +
                css.split(/\n/).each do |c|
         | 
| 24 | 
            +
                  expect(c[-1]).to eq(";")
         | 
| 25 | 
            +
                end
         | 
| 11 26 | 
             
              end
         | 
| 12 27 | 
             
            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: 0. | 
| 4 | 
            +
              version: 1.0.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: 2013-08- | 
| 12 | 
            +
            date: 2013-08-25 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: bindata
         | 
| @@ -43,16 +43,16 @@ dependencies: | |
| 43 43 | 
             
              name: psd-enginedata
         | 
| 44 44 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 45 45 | 
             
                requirements:
         | 
| 46 | 
            -
                - -  | 
| 46 | 
            +
                - - ~>
         | 
| 47 47 | 
             
                  - !ruby/object:Gem::Version
         | 
| 48 | 
            -
                    version: '0'
         | 
| 48 | 
            +
                    version: '1.0'
         | 
| 49 49 | 
             
              type: :runtime
         | 
| 50 50 | 
             
              prerelease: false
         | 
| 51 51 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 52 52 | 
             
                requirements:
         | 
| 53 | 
            -
                - -  | 
| 53 | 
            +
                - - ~>
         | 
| 54 54 | 
             
                  - !ruby/object:Gem::Version
         | 
| 55 | 
            -
                    version: '0'
         | 
| 55 | 
            +
                    version: '1.0'
         | 
| 56 56 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 57 57 | 
             
              name: rspec
         | 
| 58 58 | 
             
              requirement: !ruby/object:Gem::Requirement
         |