aboutsummaryrefslogtreecommitdiffstats
path: root/docs/psdchannelimage.html
blob: a7fdd43459b1aac4e99c160b2db1108ff9a4a25c (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
86
<!DOCTYPE html>  <html> <head>   <title>psdchannelimage.coffee</title>   <meta http-equiv="content-type" content="text/html; charset=UTF-8">   <link rel="stylesheet" media="all" href="docco.css" /> </head> <body>   <div id="container">     <div id="background"></div>            <div id="jump_to">         Jump To &hellip;         <div id="jump_wrapper">           <div id="jump_page">                                           <a class="source" href="blackwhite.html">                 blackwhite.coffee               </a>                                           <a class="source" href="brightnesscontrast.html">                 brightnesscontrast.coffee               </a>                                           <a class="source" href="colorbalance.html">                 colorbalance.coffee               </a>                                           <a class="source" href="curves.html">                 curves.coffee               </a>                                           <a class="source" href="exposure.html">                 exposure.coffee               </a>                                           <a class="source" href="gradient.html">                 gradient.coffee               </a>                                           <a class="source" href="huesaturation.html">                 huesaturation.coffee               </a>                                           <a class="source" href="invert.html">                 invert.coffee               </a>                                           <a class="source" href="layereffect.html">                 layereffect.coffee               </a>                                           <a class="source" href="levels.html">                 levels.coffee               </a>                                           <a class="source" href="pattern.html">                 pattern.coffee               </a>                                           <a class="source" href="photofilter.html">                 photofilter.coffee               </a>                                           <a class="source" href="posterize.html">                 posterize.coffee               </a>                                           <a class="source" href="selectivecolor.html">                 selectivecolor.coffee               </a>                                           <a class="source" href="solidcolor.html">                 solidcolor.coffee               </a>                                           <a class="source" href="threshold.html">                 threshold.coffee               </a>                                           <a class="source" href="typetool.html">                 typetool.coffee               </a>                                           <a class="source" href="vibrance.html">                 vibrance.coffee               </a>                                           <a class="source" href="log.html">                 log.coffee               </a>                                           <a class="source" href="psd.html">                 psd.coffee               </a>                                           <a class="source" href="psdassert.html">                 psdassert.coffee               </a>                                           <a class="source" href="psdchannelimage.html">                 psdchannelimage.coffee               </a>                                           <a class="source" href="psdcolor.html">                 psdcolor.coffee               </a>                                           <a class="source" href="psddescriptor.html">                 psddescriptor.coffee               </a>                                           <a class="source" href="psdfile.html">                 psdfile.coffee               </a>                                           <a class="source" href="psdheader.html">                 psdheader.coffee               </a>                                           <a class="source" href="psdimage.html">                 psdimage.coffee               </a>                                           <a class="source" href="psdlayer.html">                 psdlayer.coffee               </a>                                           <a class="source" href="psdlayermask.html">                 psdlayermask.coffee               </a>                                           <a class="source" href="psdresource.html">                 psdresource.coffee               </a>                                           <a class="source" href="util.html">                 util.coffee               </a>                        </div>         </div>       </div>          <table cellpadding="0" cellspacing="0">       <thead>         <tr>           <th class="docs">             <h1>               psdchannelimage.coffee             </h1>           </th>           <th class="code">           </th>         </tr>       </thead>       <tbody>                               <tr id="section-1">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-1">&#182;</a>               </div>               <p>PSD files also store merged image data for each individual layer.
Unfortunately, parsing this image data is a bit different than parsing
the overall merged image data at the end of the file. The main difference
is that each image channel has independent compression, and the channel
order is defined individually for each layer. Also, the layer size is often
not the same size as the full image.</p>             </td>             <td class="code">               <div class="highlight"><pre><span class="k">class</span> <span class="nx">PSDChannelImage</span> <span class="k">extends</span> <span class="nx">PSDImage</span>
  <span class="nv">constructor: </span><span class="nf">(file, header, @layer) -&gt;</span>
    <span class="vi">@width = </span><span class="nx">@layer</span><span class="p">.</span><span class="nx">cols</span>
    <span class="vi">@height = </span><span class="nx">@layer</span><span class="p">.</span><span class="nx">rows</span>
    <span class="vi">@channelsInfo = </span><span class="nx">@layer</span><span class="p">.</span><span class="nx">channelsInfo</span>

    <span class="k">super</span> <span class="nx">file</span><span class="p">,</span> <span class="nx">header</span>

  <span class="nv">skip: </span><span class="o">-&gt;</span>
    <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;Skipping channel image data. Layer = #{@layer.name}&quot;</span>
    <span class="k">for</span> <span class="nx">channel</span> <span class="k">in</span> <span class="nx">@channelsInfo</span>
      <span class="nx">@file</span><span class="p">.</span><span class="nx">seek</span> <span class="nx">channel</span><span class="p">.</span><span class="nx">length</span>

  <span class="nv">getImageWidth: </span><span class="o">-&gt;</span> <span class="nx">@width</span>
  <span class="nv">getImageHeight: </span><span class="o">-&gt;</span> <span class="nx">@height</span>
  <span class="nv">getImageChannels: </span><span class="o">-&gt;</span> <span class="nx">@layer</span><span class="p">.</span><span class="nx">channels</span></pre></div>             </td>           </tr>                               <tr id="section-2">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-2">&#182;</a>               </div>               <p>Since we're working on a per-channel basis now, we only read the byte counts
for the current channel only.</p>             </td>             <td class="code">               <div class="highlight"><pre>  <span class="nv">getByteCounts: </span><span class="o">-&gt;</span>
    <span class="nv">byteCounts = </span><span class="p">[]</span>
    <span class="k">for</span> <span class="nx">i</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">@getImageHeight</span><span class="p">()]</span>
      <span class="nx">byteCounts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@file</span><span class="p">.</span><span class="nx">readShortInt</span><span class="p">()</span>

    <span class="nx">byteCounts</span>

  <span class="nv">parse: </span><span class="o">-&gt;</span>
    <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;\nLayer: #{@layer.name}, image size: #{@length} (#{@getImageWidth()}x#{@getImageHeight()})&quot;</span>
    </pre></div>             </td>           </tr>                               <tr id="section-3">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-3">&#182;</a>               </div>               <p>We must keep track of the current channel data position global to this object
now, since we parse a single channel at a time.</p>             </td>             <td class="code">               <div class="highlight"><pre>    <span class="vi">@chanPos = </span><span class="mi">0</span></pre></div>             </td>           </tr>                               <tr id="section-4">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-4">&#182;</a>               </div>               <p>Loop through each image channel and parse each one like a full image.</p>             </td>             <td class="code">               <div class="highlight"><pre>    <span class="k">for</span> <span class="nx">i</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">@getImageChannels</span><span class="p">()]</span>
      <span class="vi">@chInfo = </span><span class="nx">@layer</span><span class="p">.</span><span class="nx">channelsInfo</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span>

      <span class="k">if</span> <span class="nx">@chInfo</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;=</span> <span class="mi">0</span>
        <span class="nx">@parseCompression</span><span class="p">()</span>
        <span class="k">continue</span></pre></div>             </td>           </tr>                               <tr id="section-5">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-5">&#182;</a>               </div>               <p>If the ID of this current channel is -2, then we assume the dimensions
of the layer mask.</p>             </td>             <td class="code">               <div class="highlight"><pre>      <span class="k">if</span> <span class="nx">@chInfo</span><span class="p">.</span><span class="nx">id</span> <span class="o">is</span> <span class="o">-</span><span class="mi">2</span>
        <span class="vi">@width = </span><span class="nx">@layer</span><span class="p">.</span><span class="nx">mask</span><span class="p">.</span><span class="nx">width</span>
        <span class="vi">@height = </span><span class="nx">@layer</span><span class="p">.</span><span class="nx">mask</span><span class="p">.</span><span class="nx">height</span>
      <span class="k">else</span>
        <span class="vi">@width = </span><span class="nx">@layer</span><span class="p">.</span><span class="nx">cols</span>
        <span class="vi">@height = </span><span class="nx">@layer</span><span class="p">.</span><span class="nx">rows</span>

      <span class="nv">start = </span><span class="nx">@file</span><span class="p">.</span><span class="nx">tell</span><span class="p">()</span>

      <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;Channel ##{@chInfo.id}: length=#{@chInfo.length}&quot;</span>
      <span class="nx">@parseImageData</span><span class="p">()</span>

      <span class="nv">end = </span><span class="nx">@file</span><span class="p">.</span><span class="nx">tell</span><span class="p">()</span></pre></div>             </td>           </tr>                               <tr id="section-6">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-6">&#182;</a>               </div>               <p>Sanity check</p>             </td>             <td class="code">               <div class="highlight"><pre>      <span class="k">if</span> <span class="nx">end</span> <span class="o">isnt</span> <span class="nx">start</span> <span class="o">+</span> <span class="nx">@chInfo</span><span class="p">.</span><span class="nx">length</span>
        <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;ERROR: read incorrect number of bytes for channel ##{@chInfo.id}. Layer=#{@layer.name}, Expected = #{start + @chInfo.length}, Actual: #{end}&quot;</span>
        <span class="nx">@file</span><span class="p">.</span><span class="nx">seek</span> <span class="nx">start</span> <span class="o">+</span> <span class="nx">@chInfo</span><span class="p">.</span><span class="nx">length</span><span class="p">,</span> <span class="kc">false</span></pre></div>             </td>           </tr>                               <tr id="section-7">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-7">&#182;</a>               </div>               <p>Futher sanity checks</p>             </td>             <td class="code">               <div class="highlight"><pre>    <span class="k">if</span> <span class="nx">@channelData</span><span class="p">.</span><span class="nx">length</span> <span class="o">isnt</span> <span class="nx">@length</span>
      <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;ERROR: #{@channelData.length} read; expected #{@length}&quot;</span>

    <span class="nx">@processImageData</span><span class="p">()</span></pre></div>             </td>           </tr>                               <tr id="section-8">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-8">&#182;</a>               </div>               <p>@parseUserMask()</p>             </td>             <td class="code">               <div class="highlight"><pre>    <span class="k">if</span> <span class="nx">exports</span><span class="o">?</span>
      <span class="nv">memusage = </span><span class="nx">process</span><span class="p">.</span><span class="nx">memoryUsage</span><span class="p">()</span>
      <span class="nv">used = </span><span class="nb">Math</span><span class="p">.</span><span class="nx">round</span> <span class="nx">memusage</span><span class="p">.</span><span class="nx">heapUsed</span> <span class="sr">/ 1024 /</span> <span class="mi">1024</span>
      <span class="nv">total = </span><span class="nb">Math</span><span class="p">.</span><span class="nx">round</span> <span class="nx">memusage</span><span class="p">.</span><span class="nx">heapTotal</span> <span class="sr">/ 1024 /</span> <span class="mi">1024</span>
      <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;\nMemory usage: #{used}MB / #{total}MB&quot;</span></pre></div>             </td>           </tr>                               <tr id="section-9">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-9">&#182;</a>               </div>               <p>Since we're parsing on a per-channel basis, we need to modify the behavior
of the RAW encoding parser a bit. This version is aware of the current
channel data position, since layers that have RAW encoding often use RLE
encoded alpha channels.</p>             </td>             <td class="code">               <div class="highlight"><pre>  <span class="nv">parseRaw: </span><span class="o">-&gt;</span>
    <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;Attempting to parse RAW encoded channel...&quot;</span>
    <span class="nv">data = </span><span class="nx">@file</span><span class="p">.</span><span class="nx">read</span><span class="p">(</span><span class="nx">@chInfo</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span>
    <span class="nv">dataIndex = </span><span class="mi">0</span>
    <span class="k">for</span> <span class="nx">i</span> <span class="k">in</span> <span class="p">[</span><span class="nx">@chanPos</span><span class="p">...</span><span class="nx">@chanPos</span><span class="o">+</span><span class="nx">@chInfo</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span>
      <span class="nx">@channelData</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">data</span><span class="p">[</span><span class="nx">dataIndex</span><span class="o">++</span><span class="p">]</span>

    <span class="nx">@chanPos</span> <span class="o">+=</span> <span class="nx">@chInfo</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">2</span></pre></div>             </td>           </tr>                               <tr id="section-10">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-10">&#182;</a>               </div>               <p>Compression is stored on a per-channel basis, not a per-image basis for layers</p>             </td>             <td class="code">               <div class="highlight"><pre>  <span class="nv">parseImageData: </span><span class="o">-&gt;</span>
    <span class="vi">@compression = </span><span class="nx">@parseCompression</span><span class="p">()</span>

    <span class="k">switch</span> <span class="nx">@compression</span>
      <span class="k">when</span> <span class="mi">0</span> <span class="k">then</span> <span class="nx">@parseRaw</span><span class="p">()</span>
      <span class="k">when</span> <span class="mi">1</span> <span class="k">then</span> <span class="nx">@parseRLE</span><span class="p">()</span>
      <span class="k">when</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span> <span class="k">then</span> <span class="nx">@parseZip</span><span class="p">()</span>
      <span class="k">else</span>
        <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;Unknown image compression. Attempting to skip.&quot;</span>
        <span class="k">return</span> <span class="nx">@file</span><span class="p">.</span><span class="nx">seek</span> <span class="nx">@endPos</span><span class="p">,</span> <span class="kc">false</span></pre></div>             </td>           </tr>                               <tr id="section-11">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-11">&#182;</a>               </div>               <p>Parse a single channel instead of every image channel</p>             </td>             <td class="code">               <div class="highlight"><pre>  <span class="nv">parseChannelData: </span><span class="o">-&gt;</span>
    <span class="nv">lineIndex = </span><span class="mi">0</span>
    
    <span class="nx">Log</span><span class="p">.</span><span class="nx">debug</span> <span class="s2">&quot;Parsing layer channel ##{@chInfo.id}, Start = #{@file.tell()}&quot;</span>
    <span class="p">[</span><span class="nx">@chanPos</span><span class="p">,</span> <span class="nx">lineIndex</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@decodeRLEChannel</span><span class="p">(</span><span class="nx">@chanPos</span><span class="p">,</span> <span class="nx">lineIndex</span><span class="p">)</span></pre></div>             </td>           </tr>                               <tr id="section-12">             <td class="docs">               <div class="pilwrap">                 <a class="pilcrow" href="#section-12">&#182;</a>               </div>               <p>parseUserMask: ->
 if @getImageDepth() is 8
   @parseUserMask8()</p>             </td>             <td class="code">               <div class="highlight"><pre>    

</pre></div>             </td>           </tr>                </tbody>     </table>   </div> </body> </html>