1 /**
2     This PSD file parser
3 
4     This is more or less based on psd_sdk
5 
6     Various features of PSD_SDK are left out for simplicity
7 */
8 module psd.parser;
9 import utils.io;
10 import utils;
11 import psd;
12 import std.exception;
13 import std.format;
14 import std..string;
15 import psd.rle;
16 
17 /**
18     Parses document
19 */
20 PSD parseDocument(string fileName) {
21     auto file = File(fileName, "r");
22     return parseDocument(file);
23 }
24 
25 /**
26     Parses a Photoshop Document
27 */
28 PSD parseDocument(ref File file) {
29     PSD psd;
30     file.seek(0); // Seek back to start of file, just in case.
31 
32     // First, parse the header section.
33     parseHeader(file, psd);
34 
35     // Parse the various sections
36     parseColorModeSection(file, psd);
37     //parseImageResourceSection(file, psd);
38     psd.imageResourceSectionOffset = file.tell();
39     psd.imageResourceSectionLength = file.readValue!uint;
40     file.skip(psd.imageResourceSectionLength);
41     
42     parseLayerMaskInfoSection(file, psd);
43     parseImageDataSectionOffset(file, psd);
44 
45     return psd;
46 }
47 
48 
49 
50 package(psd):
51 
52 /**
53     Finds the index of the channel
54 */
55 uint findChannel(Layer* layer, ChannelType channelType)
56 {
57 	for (uint i = 0; i < layer.channels.length; ++i)
58 	{
59 		const ChannelInfo* channel = &layer.channels[i];
60 		if ((channel.dataLength > 0) && channel.type == channelType)
61 			return i;
62 	}
63 
64 	return ChannelType.INVALID;
65 }
66 
67 
68 void extractLayer(ref Layer layer) {
69     auto file = layer.filePtr;
70 
71     // Skip empty layers
72     if (layer.width == 0 && layer.height == 0) return;
73 
74     const size_t channelCount = layer.channels.length;
75     //layer.data = new ubyte[layer.width*layer.height*channelCount];
76     
77     foreach(i; 0..channelCount) {
78         ChannelInfo* channel = &layer.channels[i];
79         file.seek(channel.fileOffset);
80 
81         // HACK: To allow transparency to be put as RGBA
82         //       an offset is applied based on its layer type.
83         size_t offset = i;
84         if (channelCount > 3) {
85             switch(channel.type) {
86                 case -1:
87                     offset = 3;
88                     break;
89                 default:
90                     offset = channel.type;
91                     break;
92             }
93         }
94 
95         const ushort compressionType = file.readValue!ushort;
96         switch(compressionType) {
97             //RAW
98             case 0:
99                 // TODO: RAW decode
100                 enforce(false, "RAW encoding not implemented yet.");
101                 break;
102             
103             // RLE
104             case 1:
105 
106                 // RLE compressed data is preceded by a 2-byte data count for each scanline
107                 uint rleDataSize;
108                 foreach(_; 0..layer.height) {
109                     const ushort dataCount = file.readValue!ushort;
110                     rleDataSize += dataCount;
111                 }
112 
113                 if (rleDataSize > 0) {
114 
115                     // Read planar data
116                     ubyte[] rleData = new ubyte[rleDataSize];
117 
118                     // We need to work around the same D bug as before.
119                     size_t readBegin = file.tell();
120                     file.rawRead(rleData);
121                     file.seek(readBegin+rleDataSize);
122 
123                     // Decompress RLE
124                     // FIXME:  We're assuming psd.channelsPerBit == 8 right now, and that's not 
125                     //         always the case.
126                     channel.data = new ubyte[layer.width*layer.height];
127                     decodeRLE(rleData, channel.data);
128                 }
129                 break;
130             default: assert(0, "Unsupported compression type.");
131         }
132 
133     }
134 
135     // Transcode to RGBA
136     auto rgba = new ubyte[layer.width*layer.height*channelCount];
137     auto rgbaPtr = rgba.ptr;
138     
139 
140     // Channel indices.
141     auto aI = findChannel(&layer, ChannelType.TRANSPARENCY_MASK);
142     auto rI = findChannel(&layer, ChannelType.R);
143     auto gI = findChannel(&layer, ChannelType.G);
144     auto bI = findChannel(&layer, ChannelType.B);
145     
146     
147     auto a = layer.channels[aI].data.ptr;
148     auto r = layer.channels[rI].data.ptr;
149     auto g = layer.channels[gI].data.ptr;
150     auto b = layer.channels[bI].data.ptr;
151 
152     for (size_t j = 0; j < rgba.length; j += 4)
153     {
154         rgba[j+0] = *r++;
155         rgba[j+1] = *g++;
156         rgba[j+2] = *b++;
157         rgba[j+3] = *a++;
158     }
159 
160     // 
161     //foreach (size_t y; 0 .. layer.height)
162     //{
163     //    ubyte* a = layer.data.ptr + (y * layer.width * channelCount) + (layer.width * aI);
164     //    ubyte* r = layer.data.ptr + (y * layer.width * channelCount) + (layer.width * rI);
165     //    ubyte* g = layer.data.ptr + (y * layer.width * channelCount) + (layer.width * gI);
166     //    ubyte* b = layer.data.ptr + (y * layer.width * channelCount) + (layer.width * bI);
167     //    foreach (size_t x; 0 .. layer.width)
168     //    {
169     //        *rgbaPtr++ = *r++;
170     //        *rgbaPtr++ = *g++;
171     //        *rgbaPtr++ = *b++;
172     //        *rgbaPtr++ = *a++;   
173     //    }
174     //}
175 
176     layer.data = rgba;
177 }
178 
179 private:
180 
181 /*
182                                 PSD HEADER
183 */
184 void parseHeader(ref File file, ref PSD psd) {
185     
186     // Check signature
187     {
188         enforce(file.readStr(4) == "8BPS", "Invalid file, must be a Photoshop PSD file. PSB's are not supported!");
189     }
190 
191     // Check version (must be 1)
192     {
193         enforce(file.readValue!ushort() == 1, "Version does not match 1.");
194     }
195 
196     // Check reserve bytes
197     {
198         enforce(file.read(6) == [0, 0, 0, 0, 0, 0], "Unexpected reserve bytes, file may be corrupted.");
199     }
200 
201     // Read number of channels
202     // This is the number of channels contained in the document for all layers, including alpha channels.
203     // e.g. for an RGB document with 3 alpha channels, this would be 3 (RGB) + 3 (Alpha) = 6 channels
204     // however, note that the individual layers can have extra channels for transparency masks, vector masks, and user masks.
205     // this is different from layer to layer.
206     psd.channels = file.readValue!ushort;
207 
208     // Read rest of header info
209     psd.height = file.readValue!uint;
210     psd.width = file.readValue!uint;
211     psd.bitsPerChannel = file.readValue!ushort;
212     psd.colorMode = cast(ColorMode)file.readValue!ushort;
213 }
214 
215 
216 
217 
218 /*
219                                 COLOR MODE DATA
220 */
221 void parseColorModeSection(ref File file, ref PSD psd) {
222     psd.colorModeDataSectionLength = file.readValue!uint;
223     psd.colorModeDataSectionOffset = file.tell();
224 
225     file.skip(psd.colorModeDataSectionLength);
226 }
227 
228 
229 
230 
231 /*
232                                 IMAGE RESOURCES
233 */
234 
235 /**
236     Reads a padded value.
237 */
238 pragma(inline, true)
239 T readPaddedValue(T)(ref File file, T multipleOf = 2, T addTo = 0) {
240     T value = file.readValue!T;
241     return cast(T)roundUpToMultiple(value + addTo, multipleOf);
242 }
243 
244 void parseImageResourceSection(ref File file, ref PSD psd) {
245     psd.imageResourceSectionLength = file.readValue!uint;
246     psd.imageResourceSectionOffset = file.tell();
247 
248     // TODO: read
249     ulong leftToRead = psd.imageResourceSectionLength;
250 
251     while (leftToRead > 0) {
252         string signature = file.readStr(4);
253         
254         enforce(signature == "8BIM" || signature == "psdM", 
255             "Image resources section seems to be corrupt, signature does not match \"8BIM\" nor \"psdM\".");
256 
257         const ushort id = file.readValue!ushort;
258 
259         const ubyte nameLength = readPaddedValue!ubyte(file, 2, 1);
260         const string name = file.readStr(nameLength - 1);
261         
262         const uint resourceSize = readPaddedValue!uint(file);
263 
264         switch (id) {
265 			case ImageResourceType.IPTC_NAA:
266 			case ImageResourceType.CAPTION_DIGEST:
267 			case ImageResourceType.PRINT_INFORMATION:
268 			case ImageResourceType.PRINT_STYLE:
269 			case ImageResourceType.PRINT_SCALE:
270 			case ImageResourceType.PRINT_FLAGS:
271 			case ImageResourceType.PRINT_FLAGS_INFO:
272 			case ImageResourceType.PRINT_INFO:
273 			case ImageResourceType.RESOLUTION_INFO:
274 			case ImageResourceType.GLOBAL_ANGLE:
275 			case ImageResourceType.GLOBAL_ALTITUDE:
276 			case ImageResourceType.COLOR_HALFTONING_INFO:
277 			case ImageResourceType.COLOR_TRANSFER_FUNCTIONS:
278 			case ImageResourceType.MULTICHANNEL_HALFTONING_INFO:
279 			case ImageResourceType.MULTICHANNEL_TRANSFER_FUNCTIONS:
280 			case ImageResourceType.LAYER_STATE_INFORMATION:
281 			case ImageResourceType.LAYER_GROUP_INFORMATION:
282 			case ImageResourceType.LAYER_GROUP_ENABLED_ID:
283 			case ImageResourceType.LAYER_SELECTION_ID:
284 			case ImageResourceType.GRID_GUIDES_INFO:
285 			case ImageResourceType.URL_LIST:
286 			case ImageResourceType.SLICES:
287 			case ImageResourceType.PIXEL_ASPECT_RATIO:
288 			case ImageResourceType.ICC_UNTAGGED_PROFILE:
289 			case ImageResourceType.ID_SEED_NUMBER:
290 			case ImageResourceType.BACKGROUND_COLOR:
291 			case ImageResourceType.ALPHA_CHANNEL_UNICODE_NAMES:
292 			case ImageResourceType.ALPHA_IDENTIFIERS:
293 			case ImageResourceType.COPYRIGHT_FLAG:
294 			case ImageResourceType.PATH_SELECTION_STATE:
295 			case ImageResourceType.ONION_SKINS:
296 			case ImageResourceType.TIMELINE_INFO:
297 			case ImageResourceType.SHEET_DISCLOSURE:
298 			case ImageResourceType.WORKING_PATH:
299 			case ImageResourceType.MAC_PRINT_MANAGER_INFO:
300 			case ImageResourceType.WINDOWS_DEVMODE:
301 				// we are currently not interested in this resource type, skip it
302 			default:
303 				// this is a resource we know nothing about, so skip it
304 				file.skip(resourceSize);
305 				break;
306 			
307 			case ImageResourceType.DISPLAY_INFO:
308 			{
309 				// the display info resource stores color information and opacity for extra channels contained
310 				// in the document. these extra channels could be alpha/transparency, as well as spot color
311 				// channels used for printing.
312 			
313 				// check whether storage for alpha channels has been allocated yet
314 				// (ImageResourceType.ALPHA_CHANNEL_ASCII_NAMES stores the channel names)
315 				if (psd.imageResourcesData.alphaChannels.length == 0)
316 				{
317 					// note that this assumes RGB mode
318 					const uint channelCount = psd.channels - 3;
319 					psd.imageResourcesData.alphaChannelCount = channelCount;
320 					psd.imageResourcesData.alphaChannels.length = channelCount;
321 				}
322 			
323 				const uint versionNum = file.readValue!uint;
324 			
325 				for (uint i = 0u; i < psd.imageResourcesData.alphaChannelCount; ++i) {
326                     AlphaChannel* channel = &psd.imageResourcesData.alphaChannels[i];
327 					channel.colorSpace = file.readValue!ushort;
328 					channel.color[0] = file.readValue!ushort;
329 					channel.color[1] = file.readValue!ushort;
330 					channel.color[2] = file.readValue!ushort;
331 					channel.color[3] = file.readValue!ushort;
332 					channel.opacity = file.readValue!ushort;
333 					channel.mode = cast(AlphaChannel.Mode)file.readValue!ubyte;
334 				}
335 			}
336 			break;
337 			
338 			case ImageResourceType.VERSION_INFO:
339 			{
340 				const uint versionNum = file.readValue!uint;
341 				const ubyte hasRealMergedData = file.readValue!ubyte;
342 				psd.imageResourcesData.containsRealMergedData = (hasRealMergedData != 0u);
343 				file.skip(resourceSize - 5u);
344 			}
345 			break;
346 			
347 			case ImageResourceType.THUMBNAIL_RESOURCE:
348 			{
349 				const uint format = file.readValue!uint;
350 				const uint width = file.readValue!uint;
351 				const uint height = file.readValue!uint;
352 				const uint widthInBytes = file.readValue!uint;
353 				const uint totalSize = file.readValue!uint;
354 				const uint binaryJpegSize = file.readValue!uint;
355 			
356 				const ushort bitsPerPixel = file.readValue!ushort;
357 				const ushort numberOfPlanes = file.readValue!ushort;
358 			
359 				psd.imageResourcesData.thumbnail.width = width;
360 				psd.imageResourcesData.thumbnail.height = height;
361 				psd.imageResourcesData.thumbnail.binaryJpegSize = binaryJpegSize;
362 				psd.imageResourcesData.thumbnail.binaryJpeg = file.rawRead(new ubyte[binaryJpegSize]);
363 				
364 				const uint bytesToSkip = resourceSize - 28u - binaryJpegSize;
365 				file.skip(bytesToSkip);
366 			}
367 			break;
368 			
369 			case ImageResourceType.XMP_METADATA:
370 			{
371 				// load the XMP metadata as raw data
372                 enforce(psd.imageResourcesData.xmpMetadata.length != 0, "File contains more than one XMP metadata resource.");
373 				psd.imageResourcesData.xmpMetadata = file.rawRead(new ubyte[resourceSize]);
374 			}
375 			break;
376 			
377 			case ImageResourceType.ICC_PROFILE:
378 			{
379 				// load the ICC profile as raw data
380                 enforce(psd.imageResourcesData.iccProfile.length != 0, "File contains more than one ICC profile.");
381 				psd.imageResourcesData.iccProfile = file.rawRead(new ubyte[resourceSize]);
382 				psd.imageResourcesData.sizeOfICCProfile = resourceSize;
383 			}
384 			break;
385 			
386 			case ImageResourceType.EXIF_DATA:
387 			{
388 				// load the EXIF data as raw data
389                 enforce(psd.imageResourcesData.exifData.length != 0, "File contains more than one EXIF data block.");
390 				psd.imageResourcesData.exifData = file.rawRead(new ubyte[resourceSize]);
391 				psd.imageResourcesData.sizeOfExifData = resourceSize;
392 			}
393 			break;
394 			
395 			case ImageResourceType.ALPHA_CHANNEL_ASCII_NAMES:
396 			{
397 				// check whether storage for alpha channels has been allocated yet
398 				// (ImageResourceType.DISPLAY_INFO stores the channel color data)
399 				if (psd.imageResourcesData.alphaChannels.length == 0)
400 				{
401 					// note that this assumes RGB mode
402 					const uint channelCount = psd.channels - 3;
403 					psd.imageResourcesData.alphaChannelCount = channelCount;
404 					psd.imageResourcesData.alphaChannels.length = channelCount;
405 				}
406 			
407 				// the names of the alpha channels are stored as a series of Pascal strings
408 				uint channel = 0;
409 				long remaining = resourceSize;
410 				while (remaining > 0) {
411                     string channelName;
412 					const ubyte channelNameLength = file.readValue!ubyte;
413 					if (channelNameLength > 0) {
414                         channelName = file.readStr(channelNameLength);
415 					}
416 			
417 					remaining -= 1 + channelNameLength;
418 			
419 					if (channel < psd.imageResourcesData.alphaChannelCount) {
420 						psd.imageResourcesData.alphaChannels[channel].asciiName = channelName;
421 						++channel;
422 					}
423 				}
424 			}
425 			break;
426         }
427 
428 		leftToRead -= 10 + nameLength + resourceSize;
429     }
430 }
431 
432 
433 
434 
435 
436 
437 /*
438                                 LAYER MASK INFO
439 */
440 
441 // ---------------------------------------------------------------------------------------------------------------------
442 // ---------------------------------------------------------------------------------------------------------------------
443 long ReadMaskRectangle(ref File file, ref MaskData maskData)
444 {
445     maskData.top = file.readValue!int;
446     maskData.left = file.readValue!int;
447     maskData.bottom = file.readValue!int;
448     maskData.right = file.readValue!int;
449 
450     return 4u*int.sizeof;
451 }
452 
453 
454 // ---------------------------------------------------------------------------------------------------------------------
455 // ---------------------------------------------------------------------------------------------------------------------
456 long ReadMaskDensity(ref File file, ref ubyte density)
457 {
458     density = file.readValue!ubyte;
459     return ubyte.sizeof;
460 }
461 
462 
463 // ---------------------------------------------------------------------------------------------------------------------
464 // ---------------------------------------------------------------------------------------------------------------------
465 long ReadMaskFeather(ref File file, ref double feather)
466 {
467     feather = file.readValue!double;
468     return double.sizeof;
469 }
470 
471 
472 // ---------------------------------------------------------------------------------------------------------------------
473 // ---------------------------------------------------------------------------------------------------------------------
474 long ReadMaskParameters(ref File file, ref ubyte layerDensity, ref double layerFeather, ref ubyte vectorDensity, ref double vectorFeather)
475 {
476     long bytesRead = 0;
477 
478     const ubyte flags = file.readValue!ubyte;
479     bytesRead += ubyte.sizeof;
480 
481     const bool hasUserDensity = (flags & (1u << 0)) != 0;
482     const bool hasUserFeather = (flags & (1u << 1)) != 0;
483     const bool hasVectorDensity = (flags & (1u << 2)) != 0;
484     const bool hasVectorFeather = (flags & (1u << 3)) != 0;
485     if (hasUserDensity)
486     {
487         bytesRead += ReadMaskDensity(file, layerDensity);
488     }
489     if (hasUserFeather)
490     {
491         bytesRead += ReadMaskFeather(file, layerFeather);
492     }
493     if (hasVectorDensity)
494     {
495         bytesRead += ReadMaskDensity(file, vectorDensity);
496     }
497     if (hasVectorFeather)
498     {
499         bytesRead += ReadMaskFeather(file, vectorFeather);
500     }
501 
502     return bytesRead;
503 }
504 
505 // ---------------------------------------------------------------------------------------------------------------------
506 // ---------------------------------------------------------------------------------------------------------------------
507 template ApplyMaskData(T)
508 {
509     void ApplyMaskData(ref const MaskData maskData, double feather, ubyte density, T* layerMask)
510     {
511         layerMask.top = maskData.top;
512         layerMask.left = maskData.left;
513         layerMask.bottom = maskData.bottom;
514         layerMask.right = maskData.right;
515         layerMask.feather = feather;
516         layerMask.density = density;
517         layerMask.defaultColor = maskData.defaultColor;
518     }
519 }
520 
521 
522 
523 
524 
525 
526 
527 
528 
529 
530 
531 
532 
533 
534 void parseLayerMaskInfoSection(ref File file, ref PSD psd) {
535     psd.layerMaskInfoSectionLength = file.readValue!uint;
536     psd.layerMaskInfoSectionOffset = file.tell();
537     
538     // Parse the length of the layer info section
539     uint layerInfoSectionLength = file.readValue!uint;
540     LayerMaskSection* layerMaskSection = parseLayer(file, psd, psd.layerMaskInfoSectionOffset, cast(uint)psd.layerMaskInfoSectionLength, cast(uint)layerInfoSectionLength);
541 
542     // TODO: Build hirearchy
543     psd.layers = layerMaskSection.layers;
544 }
545 
546 LayerMaskSection* parseLayer(ref File file, ref PSD psd, ulong sectionOffset, uint sectionLength, uint layerLength) {
547     LayerMaskSection* layerMaskSection = new LayerMaskSection;
548 
549     if (layerLength != 0) {
550 
551         // Read the layer count. If it is a negative number, its absolute value is the number of the layers and the
552         // first alpha channel contains the transparency data for the merged result.
553         // this will also be reflected in the channelCount of the document.
554         short layerCount = file.readValue!short;
555         layerMaskSection.hasTransparencyMask = (layerCount < 0);
556         if (layerCount < 0) layerCount *= -1;
557 
558         layerMaskSection.layerCount = cast(uint)layerCount;
559         layerMaskSection.layers = new Layer[layerCount];
560 
561         foreach(i; 0..layerMaskSection.layers.length) {
562             Layer layer;
563             layer.filePtr = file;
564             layer.type = LayerType.Any;
565 
566             layer.top = file.readValue!int;
567             layer.left = file.readValue!int;
568 
569             // NOTE: It breaks here WTF???
570             layer.bottom = file.readValue!int;
571             layer.right = file.readValue!int;
572 
573             // Number of channels in the layer.
574             // this includes channels for transparency, layer, and vector masks, if any.
575             const ushort channelCount = file.readValue!ushort;
576             layer.channels = new ChannelInfo[channelCount];
577 
578             foreach(j; 0..layer.channels.length) {
579                 ChannelInfo* channel = &layer.channels[j];
580                 channel.type = file.readValue!short;
581                 channel.dataLength = file.readValue!uint;
582             }
583 
584             auto blendModeSignature = file.readStr(4);
585             enforce(blendModeSignature == "8BIM", "Layer mask info section seems to be corrupt, signature does not match \"8BIM\". (was \"%s\")".format(blendModeSignature));
586 
587             //layer.blendModeKey = cast(BlendingMode)file.readStr(4);
588             layer.blendModeKey = file.readValue!uint;
589             layer.opacity = file.readValue!ubyte;
590             layer.clipping = !file.readValue!bool;
591             layer.flags = cast(LayerFlags)file.readValue!ubyte;
592 
593             file.skip(1);
594 
595             const uint extraDataLength = file.readValue!uint;
596             const uint layerMaskDataLength = file.readValue!uint;
597             
598             // the layer mask data section is weird. it may contain extra data for masks, such as density and feather parameters.
599             // there are 3 main possibilities:
600             //	*) length == zero		.	skip this section
601             //	*) length == [20, 28]	.	there is one mask, and that could be either a layer or vector mask.
602             //								the mask flags give rise to mask parameters. they store the mask type, and additional parameters, if any.
603             //								there might be some padding at the end of this section, and its size depends on which parameters are there.
604             //	*) length == [36, 56]	.	there are two masks. the first mask has parameters, but does NOT store flags yet.
605             //								instead, there comes a second section with the same info (flags, default color, rectangle), and
606             //								the parameters follow after that. there is also padding at the end of this second section.
607             if (layerMaskDataLength != 0)
608             {
609                 // there can be at most two masks, one layer and one vector mask
610                 MaskData[2] maskData;
611                 uint maskCount = 1u;
612 
613                 double layerFeather = 0.0;
614                 double vectorFeather = 0.0;
615                 ubyte layerDensity = 0;
616                 ubyte vectorDensity = 0;
617 
618                 long toRead = layerMaskDataLength;
619 
620                 // enclosing rectangle
621                 toRead -= ReadMaskRectangle(file, maskData[0]);
622 
623                 maskData[0].defaultColor = file.readValue!ubyte;
624                 toRead -= ubyte.sizeof;
625 
626                 const ubyte maskFlags = file.readValue!ubyte;
627                 toRead -= ubyte.sizeof;
628 
629                 maskData[0].isVectorMask = (maskFlags & (1u << 3)) != 0;
630                 bool maskHasParameters = (maskFlags & (1u << 4)) != 0;
631                 if (maskHasParameters && (layerMaskDataLength <= 28))
632                 {
633                     toRead -= ReadMaskParameters(file, layerDensity, layerFeather, vectorDensity, vectorFeather);
634                 }
635 
636                 // check if there is enough data left for another section of mask data
637                 if (toRead >= 18)
638                 {
639                     // in case there is still data left to read, the following values are for the real layer mask.
640                     // the data we just read was for the vector mask.
641                     maskCount = 2u;
642 
643                     const ubyte realFlags = file.readValue!ubyte;
644                     toRead -= ubyte.sizeof;
645 
646                     maskData[1].defaultColor = file.readValue!ubyte;
647                     toRead -= ubyte.sizeof;
648 
649                     toRead -= ReadMaskRectangle(file, maskData[1]);
650 
651                     maskData[1].isVectorMask = (realFlags & (1u << 3)) != 0;
652 
653                     // note the OR here. whether the following section has mask parameter data or not is influenced by
654                     // the availability of parameter data of the previous mask!
655                     maskHasParameters |= ((realFlags & (1u << 4)) != 0);
656                     if (maskHasParameters)
657                     {
658                         toRead -= ReadMaskParameters(file, layerDensity, layerFeather, vectorDensity, vectorFeather);
659                     }
660                 }
661 
662                 // skip the remaining padding bytes, if any
663                 enforce(toRead >= 0, format("Parsing failed, #d bytes left", toRead));
664                 file.skip(cast(ulong)toRead);
665 
666                 // apply mask data to our own data structures
667                 for (uint mask=0; mask < maskCount; ++mask)
668                 {
669                     const bool isVectorMask = maskData[mask].isVectorMask;
670                     if (isVectorMask)
671                     {
672                         enforce(layer.vectorMask == null, "A vector mask already exists.");
673                         layer.vectorMask = new VectorMask[1];
674                         layer.vectorMask[0].data = null;
675                         layer.vectorMask[0].fileOffset = 0;
676                         ApplyMaskData!VectorMask(maskData[mask], vectorFeather, vectorDensity, &layer.vectorMask[0]);
677                     }
678                     else
679                     {
680                         enforce(layer.layerMask == null, "A layer mask already exists.");
681                         layer.layerMask = new LayerMask[1];
682                         layer.layerMask[0].data = null;
683                         layer.layerMask[0].fileOffset = 0;
684                         ApplyMaskData!LayerMask(maskData[mask], layerFeather, layerDensity, &layer.layerMask[0]);
685                     }
686                 }
687             }
688             
689             // skip blending ranges data, we are not interested in that for now
690             const uint layerBlendingRangesDataLength = file.readValue!uint;
691             file.skip(layerBlendingRangesDataLength);
692 
693             // the layer name is stored as pascal string, padded to a multiple of 4
694             // we peek here as the actual calculation happens inside readPascalStr
695             // TODO: make this more pretty?
696             const ubyte nameLength = file.peekValue!ubyte;
697             const uint paddedNameLength = roundUpToMultiple(nameLength + 1u, 4u);
698 
699             layer.name = file.readPascalStr(paddedNameLength - 1u);
700 
701             // read Additional Layer Information that exists since Photoshop 4.0.
702             // getting the size of this data is a bit awkward, because it's not stored explicitly somewhere. furthermore,
703             // the PSD format sometimes includes the 4-byte length in its section size, and sometimes not.
704             const uint additionalLayerInfoSize = extraDataLength - layerMaskDataLength - layerBlendingRangesDataLength - paddedNameLength - 8u;
705             long toRead = additionalLayerInfoSize;
706 
707             while (toRead > 0)
708             {
709                 const string signature = file.readStr(4);
710                 enforce(signature == "8BIM", "Additional Layer Information section seems to be corrupt, signature does not match \"8BIM\". (was \"%s\")".format(signature));
711 
712                 const string key = file.readStr(4);
713 
714                 // length needs to be rounded to an even number
715                 uint length = file.readValue!uint;
716                 length = roundUpToMultiple(length, 2u);
717 
718                 // read "Section divider setting" to identify whether a layer is a group, or a section divider
719                 if (key == "lsct")
720                 {
721                     layer.type = cast(LayerType)file.readValue!uint;
722 
723                     // skip the rest of the data
724                     file.skip(length - 4u);
725                 }
726                 // read Unicode layer name
727                 else if (key == "luni")
728                 {
729                     // PSD Unicode strings store 4 bytes for the number of characters, NOT bytes, followed by
730                     // 2-byte UTF16 Unicode data without the terminating null.
731                     const uint characterCountWithoutNull = file.readValue!uint;
732                     wstring utf16Name;
733                     for (uint c = 0u; c < characterCountWithoutNull; ++c)
734                     {
735                         utf16Name ~= cast(wchar)file.readValue!ushort;
736                     }
737 
738                     // If there's a unicode name we may as well use that here.
739                     import std.utf : toUTF8;
740                     layer.name = utf16Name.toUTF8;
741 
742                     // skip possible padding bytes
743                     file.skip(length - 4u - characterCountWithoutNull * ushort.sizeof);
744                 }
745                 else
746                 {
747                     file.skip(length);
748                 }
749 
750                 toRead -= 3*uint.sizeof + length;
751             }
752 
753             layerMaskSection.layers[i] = layer;
754             writeln(file.tell(), ": ", layer.name, " : ", layer.type);
755         }
756 
757 
758         // walk through the layers and channels, but don't extract their data just yet. only save the file offset for extracting the
759         // data later.
760         foreach (i; 0..layerMaskSection.layers.length)
761         {            
762             Layer* layer = &layerMaskSection.layers[i];
763             foreach(j; 0..layer.channels.length) {
764                 ChannelInfo* channel = &layer.channels[j];
765                 channel.fileOffset = cast(uint)file.tell();
766                 file.skip(channel.dataLength);
767             }
768         }
769     }
770 
771     if (sectionLength > 0)
772     {
773         // start loading at the global layer mask info section, located after the Layer Information Section.
774         // note that the 4 bytes that stored the length of the section are not included in the length itself.
775         const ulong globalInfoSectionOffset = sectionOffset + layerLength + 4u;
776         file.seek(globalInfoSectionOffset);
777 
778         // work out how many bytes are left to read at this point. we need that to figure out the size of the last
779         // optional section, the Additional Layer Information.
780         if (sectionOffset + sectionLength > globalInfoSectionOffset)
781         {
782             long toRead = cast(long)(sectionOffset + sectionLength - globalInfoSectionOffset);
783             const uint globalLayerMaskLength = file.readValue!uint;
784             toRead -= uint.sizeof;
785 
786             if (globalLayerMaskLength != 0)
787             {
788                 layerMaskSection.overlayColorSpace = file.readValue!ushort;
789 
790                 // 4*2 byte color components
791                 file.skip(8);
792 
793                 layerMaskSection.opacity = file.readValue!ushort;
794                 layerMaskSection.kind = file.readValue!ubyte;
795 
796                 toRead -= 2u*ushort.sizeof + ubyte.sizeof + 8u;
797 
798                 // filler bytes (zeroes)
799                 const uint remaining = cast(uint)(globalLayerMaskLength - 2u*ushort.sizeof - ubyte.sizeof - 8u);
800                 file.skip(remaining);
801 
802                 toRead -= remaining;
803             }
804 
805             // are there still bytes left to read? then this is the Additional Layer Information that exists since Photoshop 4.0.
806             while (toRead > 0)
807             {
808                 const string signature = file.readStr(4);
809                 enforce(signature == "8BIM", "Additional Layer Information section seems to be corrupt, signature does not match \"8BIM\".");
810 
811                 const string key = file.readStr(4);
812 
813                 // again, length is rounded to a multiple of 4
814                 uint length = file.readValue!uint;
815                 length = roundUpToMultiple(length, 4u);
816 
817                 if (key == "Lr16")
818                 {
819                     const ulong offset = file.tell();
820                     
821                     // NOTE: I think in D we...can just let this get copied over?
822                     //DestroyLayerMaskSection(layerMaskSection, allocator);
823                     layerMaskSection = parseLayer(file, psd, 0u, 0u, length);
824                     file.seek(offset + length);
825                 }
826                 else if (key == "Lr32")
827                 {
828                     const ulong offset = file.tell();
829                     
830                     // NOTE: I think in D we...can just let this get copied over?
831                     //DestroyLayerMaskSection(layerMaskSection, allocator);
832 
833                     layerMaskSection = parseLayer(file, psd, 0u, 0u, length);
834                     file.seek(offset + length);
835                 }
836                 else if (key == "vmsk")
837                 {
838                     // TODO: could read extra vector mask data here
839                     file.skip(length);
840                 }
841                 else if (key == "lnk2")
842                 {
843                     // TODO: could read individual smart object layer data here
844                     file.skip(length);
845                 }
846                 else
847                 {
848                     file.skip(length);
849                 }
850 
851                 toRead -= 3u*uint.sizeof + length;
852             }
853         }
854     }
855 
856     return layerMaskSection;
857 }
858 
859 
860 /*
861                                 IMAGE DATA
862 */
863 void parseImageDataSectionOffset(ref File file, ref PSD psd) {
864     psd.imageDataSectionOffset = file.tell();
865     psd.imageDataSectionLength = file.size() - psd.imageDataSectionOffset;
866 
867     // TODO: read
868 }