psd 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +7 -0
- data/README.md +14 -8
- data/lib/psd.rb +7 -5
- data/lib/psd/image.rb +5 -0
- data/lib/psd/image_exports/png.rb +2 -1
- data/lib/psd/image_formats/rle.rb +3 -2
- data/lib/psd/image_modes/rgb.rb +11 -7
- data/lib/psd/layer.rb +8 -3
- data/lib/psd/layer_mask.rb +24 -1
- data/lib/psd/logger.rb +42 -0
- data/lib/psd/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ad5fbd51101b2362d57e17fe0fe5544ebc51ea8
|
4
|
+
data.tar.gz: bb899376edd469fd83536d6bf2b50b96fb044b6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92068cabd35464e01395b673cc8a4322fd0cd5e8f9317fcc33571df8cea9d0bd59cc98e4faeeca91399634f5549c3b04b4fbf3f891d5b32a154a54843a46e98d
|
7
|
+
data.tar.gz: 26686e5b31b29de64da12dce875cc9edde976451028cd0ccd1f25c855db2851e00be26619c4a8d49e84d8ee076b05e3015acd92bb978a24b014203489890b4ea
|
data/CONTRIBUTING.md
ADDED
data/README.md
CHANGED
@@ -142,6 +142,20 @@ png = psd.image.to_png # reference to PNG data
|
|
142
142
|
psd.image.save_as_png 'path/to/output.png' # writes PNG to disk
|
143
143
|
```
|
144
144
|
|
145
|
+
**Debugging**
|
146
|
+
|
147
|
+
If you run into any problems parsing a PSD, you can enable debug logging via the `PSD_DEBUG` environment variable. For example:
|
148
|
+
|
149
|
+
``` bash
|
150
|
+
PSD_DEBUG=STDOUT bundle exec examples/parse.rb
|
151
|
+
```
|
152
|
+
|
153
|
+
You can also give a path to a file instead. If you need to enable debugging programatically:
|
154
|
+
|
155
|
+
``` ruby
|
156
|
+
PSD.debug = true
|
157
|
+
```
|
158
|
+
|
145
159
|
## To-do
|
146
160
|
|
147
161
|
There are a few features that are currently missing from PSD.rb.
|
@@ -150,11 +164,3 @@ There are a few features that are currently missing from PSD.rb.
|
|
150
164
|
* Individual layer image exporting
|
151
165
|
* More image modes + depths for image exporting
|
152
166
|
* A few layer info blocks
|
153
|
-
|
154
|
-
## Contributing
|
155
|
-
|
156
|
-
1. Fork it
|
157
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
158
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
159
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
160
|
-
5. Create new Pull Request
|
data/lib/psd.rb
CHANGED
@@ -19,13 +19,10 @@ end
|
|
19
19
|
# the header, resources, the layer mask (including layers), and the preview image. We parse
|
20
20
|
# each of these sections in order.
|
21
21
|
class PSD
|
22
|
+
include Logger
|
22
23
|
include Helpers
|
23
24
|
include NodeExporting
|
24
25
|
|
25
|
-
# Just used to track what layer info keys we didn't parse in this file for development purposes.
|
26
|
-
def self.keys; @@keys; end
|
27
|
-
@@keys = []
|
28
|
-
|
29
26
|
DEFAULTS = {
|
30
27
|
parse_image: false,
|
31
28
|
parse_layer_images: false
|
@@ -66,7 +63,10 @@ class PSD
|
|
66
63
|
|
67
64
|
# Get the Header, parsing it if needed.
|
68
65
|
def header
|
69
|
-
@header
|
66
|
+
return @header if @header
|
67
|
+
|
68
|
+
@header = Header.read(@file)
|
69
|
+
PSD.logger.debug @header.inspect
|
70
70
|
end
|
71
71
|
|
72
72
|
# Get the Resources section, parsing if needed.
|
@@ -78,6 +78,8 @@ class PSD
|
|
78
78
|
@resources = Resources.new(@file)
|
79
79
|
@resources.parse
|
80
80
|
|
81
|
+
PSD.logger.debug @resources.inspect
|
82
|
+
|
81
83
|
return @resources.data
|
82
84
|
end
|
83
85
|
|
data/lib/psd/image.rb
CHANGED
@@ -40,6 +40,8 @@ class PSD
|
|
40
40
|
@end_pos = @start_pos + @length
|
41
41
|
|
42
42
|
@pixel_data = []
|
43
|
+
|
44
|
+
PSD.logger.debug "Image: #{width}x#{height}, length = #{@length}, mode = #{@header.mode_name}, position = #{@start_pos}"
|
43
45
|
end
|
44
46
|
|
45
47
|
# Begins parsing the image by first figuring out the compression format used, and then
|
@@ -49,9 +51,12 @@ class PSD
|
|
49
51
|
|
50
52
|
# ZIP not implemented
|
51
53
|
if [2, 3].include?(@compression)
|
54
|
+
PSD.logger.debug "Warning: ZIP image compression not supported yet. Skipping."
|
52
55
|
@file.seek @end_pos and return
|
53
56
|
end
|
54
57
|
|
58
|
+
PSD.logger.debug "Compression: id = #{@compression}, name = #{COMPRESSIONS[@compression]}"
|
59
|
+
|
55
60
|
parse_image_data!
|
56
61
|
|
57
62
|
return self
|
@@ -7,6 +7,7 @@ class PSD::Image
|
|
7
7
|
# Load the image pixels into a PNG file and return a reference to the
|
8
8
|
# data.
|
9
9
|
def to_png
|
10
|
+
PSD.logger.debug "Beginning PNG export"
|
10
11
|
png = ChunkyPNG::Image.new(width, height, ChunkyPNG::Color::TRANSPARENT)
|
11
12
|
|
12
13
|
i = 0
|
@@ -29,7 +30,7 @@ class PSD::Image
|
|
29
30
|
|
30
31
|
# Saves the PNG data to disk.
|
31
32
|
def save_as_png(file)
|
32
|
-
to_png.save(file)
|
33
|
+
to_png.save(file, :fast_rgba)
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -25,6 +25,7 @@ class PSD::Image
|
|
25
25
|
line_index = 0
|
26
26
|
|
27
27
|
channels.times do |i|
|
28
|
+
PSD.logger.debug "Parsing RLE channel ##{i}: position = #{chan_pos}, line = #{line_index}"
|
28
29
|
chan_pos = decode_rle_channel(chan_pos, line_index)
|
29
30
|
line_index += height
|
30
31
|
end
|
@@ -34,9 +35,9 @@ class PSD::Image
|
|
34
35
|
height.times do |j|
|
35
36
|
byte_count = @byte_counts[line_index]
|
36
37
|
line_index += 1
|
37
|
-
|
38
|
+
finish = @file.tell + byte_count
|
38
39
|
|
39
|
-
while @file.tell <
|
40
|
+
while @file.tell < finish
|
40
41
|
len = @file.read(1).bytes.to_a[0]
|
41
42
|
|
42
43
|
if len < 128
|
data/lib/psd/image_modes/rgb.rb
CHANGED
@@ -4,21 +4,25 @@ class PSD::Image::Mode
|
|
4
4
|
private
|
5
5
|
|
6
6
|
def combine_rgb_channel
|
7
|
+
PSD.logger.debug "Beginning RGB processing"
|
8
|
+
|
7
9
|
(0...@num_pixels).step(pixel_step) do |i|
|
8
|
-
|
10
|
+
r = g = b = 0
|
11
|
+
a = 255
|
9
12
|
|
10
|
-
PSD::Image::CHANNEL_INFO
|
13
|
+
PSD::Image::CHANNEL_INFO.each_with_index do |chan, index|
|
14
|
+
next if channels == 3 && chan[:id] == -1
|
11
15
|
val = @channel_data[i + (@channel_length * index)]
|
12
16
|
|
13
17
|
case chan[:id]
|
14
|
-
when -1 then
|
15
|
-
when 0 then
|
16
|
-
when 1 then
|
17
|
-
when 2 then
|
18
|
+
when -1 then a = val
|
19
|
+
when 0 then r = val
|
20
|
+
when 1 then g = val
|
21
|
+
when 2 then b = val
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
|
-
@pixel_data.push
|
25
|
+
@pixel_data.push r, g, b, a
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
data/lib/psd/layer.rb
CHANGED
@@ -68,6 +68,8 @@ class PSD
|
|
68
68
|
parse_legacy_layer_name
|
69
69
|
parse_extra_data
|
70
70
|
|
71
|
+
PSD.logger.debug "Layer name = #{name}"
|
72
|
+
|
71
73
|
@file.seek @layer_end # Skip over any filler zeros
|
72
74
|
|
73
75
|
end_section
|
@@ -310,21 +312,24 @@ class PSD
|
|
310
312
|
LAYER_INFO.each do |name, info|
|
311
313
|
next unless info.key == key
|
312
314
|
|
315
|
+
PSD.logger.debug "Layer Info: key = #{key}, start = #{pos}, length = #{length}"
|
316
|
+
|
313
317
|
begin
|
314
318
|
i = info.new(@file, length)
|
315
319
|
i.parse
|
316
320
|
|
317
321
|
@adjustments[name] = i
|
318
322
|
info_parsed = true
|
319
|
-
rescue Exception
|
323
|
+
rescue Exception => e
|
324
|
+
PSD.logger.error "Parsing error: key = #{key}, message = #{e.message}"
|
325
|
+
PSD.logger.error e.backtrace.join("\n")
|
320
326
|
end
|
321
327
|
|
322
328
|
break
|
323
329
|
end
|
324
330
|
|
325
331
|
if !info_parsed
|
326
|
-
PSD.
|
327
|
-
# puts "SKIPPING #{key}, length = #{length}"
|
332
|
+
PSD.logger.debug "SKIPPING: key = #{key}, length = #{length}"
|
328
333
|
@file.seek pos + length
|
329
334
|
end
|
330
335
|
|
data/lib/psd/layer_mask.rb
CHANGED
@@ -64,7 +64,9 @@ class PSD
|
|
64
64
|
layers.reverse!
|
65
65
|
group_layers
|
66
66
|
|
67
|
-
|
67
|
+
parse_global_mask
|
68
|
+
|
69
|
+
# Ensure we're at the end of this section
|
68
70
|
@file.seek finish
|
69
71
|
end_section
|
70
72
|
|
@@ -102,5 +104,26 @@ class PSD
|
|
102
104
|
end
|
103
105
|
end
|
104
106
|
end
|
107
|
+
|
108
|
+
def parse_global_mask
|
109
|
+
length = @file.read_int
|
110
|
+
return if length == 0
|
111
|
+
|
112
|
+
mask_end = @file.tell + length
|
113
|
+
PSD.logger.debug "Global Mask: length = #{length}"
|
114
|
+
|
115
|
+
@global_mask = {}
|
116
|
+
@global_mask[:overlay_color_space] = @file.read_short
|
117
|
+
@global_mask[:color_components] = 4.times.map { |i| @file.read_short >> 8 }
|
118
|
+
@global_mask[:opacity] = @file.read_short
|
119
|
+
|
120
|
+
# 0 = color selected, 1 = color protected, 128 = use value per layer
|
121
|
+
@global_mask[:kind] = @file.read(1).bytes.to_a[0]
|
122
|
+
|
123
|
+
PSD.logger.debug @global_mask
|
124
|
+
|
125
|
+
# Filler zeros
|
126
|
+
@file.seek mask_end
|
127
|
+
end
|
105
128
|
end
|
106
129
|
end
|
data/lib/psd/logger.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
class PSD
|
4
|
+
module Logger
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
attr_accessor :debug
|
11
|
+
|
12
|
+
def logger
|
13
|
+
return @logger if @logger
|
14
|
+
|
15
|
+
if debug || ENV['PSD_DEBUG']
|
16
|
+
@logger = ::Logger.new(debug_output)
|
17
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
18
|
+
"#{severity}: #{msg}\n"
|
19
|
+
end
|
20
|
+
else
|
21
|
+
@logger = DisabledLogger.new
|
22
|
+
end
|
23
|
+
|
24
|
+
return @logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def debug_output
|
28
|
+
if ENV['PSD_DEBUG']
|
29
|
+
ENV['PSD_DEBUG'] == 'STDOUT' ? STDOUT : ENV['PSD_DEBUG']
|
30
|
+
end
|
31
|
+
|
32
|
+
STDOUT
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class DisabledLogger
|
38
|
+
def method_missing(method, *args, &block)
|
39
|
+
# silence
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/psd/version.rb
CHANGED
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.3.
|
4
|
+
version: 0.3.5
|
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-
|
12
|
+
date: 2013-08-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bindata
|
@@ -119,6 +119,7 @@ extra_rdoc_files: []
|
|
119
119
|
files:
|
120
120
|
- .gitignore
|
121
121
|
- .rspec
|
122
|
+
- CONTRIBUTING.md
|
122
123
|
- Gemfile
|
123
124
|
- Guardfile
|
124
125
|
- LICENSE.txt
|
@@ -154,6 +155,7 @@ files:
|
|
154
155
|
- lib/psd/layer_info/unicode_name.rb
|
155
156
|
- lib/psd/layer_info/vector_mask.rb
|
156
157
|
- lib/psd/layer_mask.rb
|
158
|
+
- lib/psd/logger.rb
|
157
159
|
- lib/psd/mask.rb
|
158
160
|
- lib/psd/node.rb
|
159
161
|
- lib/psd/node_exporting.rb
|