aboutsummaryrefslogtreecommitdiffstats
path: root/src/psdheader.coffee
blob: 9892a36ca65b6cb1dd63118db1b1c1c2253c1d29 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# The PSD header describes all kinds of important information pertaining to 
# the PSD file such as size, color channels, color depth, and so on.
class PSDHeader
  # All of the sections that the header contains. These will become properties 
  # of the instantiated header object once parsed.
  HEADER_SECTIONS = [
    "sig"
    "version"
    
    # These are reserved bytes, always zero
    "r0"
    "r1"
    "r2"
    "r3"
    "r4"
    "r5"

    "channels"
    "rows"
    "cols"
    "depth"
    "mode"
  ]

  # Common names for various color modes, which are specified by an integer in 
  # the header.
  MODES =
    0:  'Bitmap'
    1:  'GrayScale'
    2:  'IndexedColor'
    3:  'RGBColor'
    4:  'CMYKColor'
    5:  'HSLColor'
    6:  'HSBColor'
    7:  'Multichannel'
    8:  'Duotone'
    9:  'LabColor'
    10: 'Gray16'
    11: 'RGB48'
    12: 'Lab48'
    13: 'CMYK64'
    14: 'DeepMultichannel'
    15: 'Duotone16'

  constructor: (@file) ->

  parse: ->
    # Read the header section
    data = @file.readf ">4sH 6B HLLHH"

    # Add all of the header sections as properties of this object.
    @[section] = data.shift() for section in HEADER_SECTIONS

    # Store size in an easy to use place for later
    @size = [@rows, @cols]

    # This must be 8BPS according to the spec, or else this is not a valid PSD 
    # file.
    if @sig isnt "8BPS"
      throw "Not a PSD signature: #{@header['sig']}"
    
    # The spec only covers version 1 of PSDs. I believe this is the only 
    # version available at this time, anyways.
    if @version isnt 1
      throw "Can not handle PSD version #{@header['version']}"

    # Store the common mode name
    if 0 <= @mode < 16
      @modename = MODES[@mode]
    else
      @modename = "(#{@mode})"

    # Information about the color mode is a bit complex. We're skipping this 
    # for now. TODO.
    @colormodepos = @file.pos
    @file.skipBlock "color mode data"

  toJSON: ->
    data = {}
    for section in HEADER_SECTIONS
      data[section] = @[section]

    # Some extra data
    data.modename = @modename
    data