1 module psd.parse.sections.header; 2 import psd.parse; 3 import psd.parse.io; 4 import std.exception; 5 6 /** 7 PSD Color Modes 8 */ 9 enum ColorMode : ushort { 10 Bitmap = 0, 11 Grayscale = 1, 12 Indexed = 2, 13 RGB = 3, 14 CMYK = 4, 15 Multichannel = 7, 16 Duotone = 8, 17 Lab = 9 18 } 19 20 21 /** 22 Will read the signature from the header. 23 */ 24 pragma(inline, true) 25 char[4] readSignature(ref ParserContext ctx) { 26 char[4] signature; 27 28 foreach (i; 0 .. 4) 29 signature[i] = ctx.readValue!byte; 30 31 return signature; 32 } 33 34 /** 35 Will read the reserve bytes from the header. 36 */ 37 pragma(inline, true) 38 char[6] readReserveBytes(ref ParserContext ctx) { 39 char[6] reserve; 40 41 foreach (i; 0 .. 6) 42 reserve[i] = ctx.readValue!byte; 43 44 return reserve; 45 } 46 47 48 49 struct PSD_Header { 50 /** 51 Signature of the file 52 */ 53 char[4] signature; 54 55 /** 56 Amount of channels in file 57 */ 58 short versionNo; 59 60 /** 61 Reserved bytes, should be zero 62 */ 63 char[6] reserved; 64 65 /** 66 Amount of channels in file 67 */ 68 short channels; 69 70 /** 71 Width of document 72 */ 73 uint width; 74 75 /** 76 Height of document 77 */ 78 uint height; 79 80 /** 81 Bits per channel 82 */ 83 ushort bitsPerChannel; 84 85 /** 86 Color mode of document 87 */ 88 ColorMode colorMode; 89 } 90 91 /** 92 Parses PSD header 93 */ 94 void parseHeader(ref ParserContext ctx) { 95 PSD_Header header; 96 header.signature = readSignature(ctx); 97 byte[4] signatureBytes = [ '8','B','P','S' ]; 98 99 // Make sure that this file has a photoshop header and is the correct version 100 enforce(signatureBytes == header.signature, "Invalid PSD file signature"); 101 102 auto versionNo = ctx.readValue!ushort; 103 enforce((1 == versionNo) || (2 == versionNo), "Invalid PSD or PSB file version"); 104 105 if (2 == versionNo) 106 ctx.psd.psbFile = true; 107 else 108 ctx.psd.psbFile = false; 109 110 header.reserved = readReserveBytes(ctx); 111 byte[6] reserveBytes = [ '\0','\0','\0','\0','\0','\0' ]; 112 enforce(reserveBytes == header.reserved, "Invalid PSD reserve bytes."); 113 114 // Read channels 115 header.channels = ctx.readValue!ushort; 116 117 // NOTE: Photoshop flips width/height order for some reason 118 header.height = ctx.readValue!uint; 119 header.width = ctx.readValue!uint; 120 121 header.bitsPerChannel = ctx.readValue!ushort; 122 header.colorMode = cast(ColorMode)ctx.readValue!ushort; 123 124 ctx.psd.header = header; 125 126 // TODO: Support maybe CMYK 127 enforce(header.colorMode == ColorMode.RGB, "Only RGB/RGBA files are supported currently!"); 128 129 ctx.psd.colorModeDataSection.length = ctx.readValue!uint; 130 ctx.psd.colorModeDataSection.offset = cast(ulong)ctx.tell(); 131 ctx.skip(ctx.psd.colorModeDataSection.length); 132 133 ctx.psd.imageResourcesSection.length = ctx.readValue!uint; 134 ctx.psd.imageResourcesSection.offset = cast(ulong)ctx.tell(); 135 ctx.skip(ctx.psd.imageResourcesSection.length); 136 137 ctx.psd.layerMaskInfoSection.length = ctx.readValue!uint; 138 ctx.psd.layerMaskInfoSection.offset = cast(ulong)ctx.tell(); 139 ctx.skip(ctx.psd.layerMaskInfoSection.length); 140 141 ctx.psd.imageDataSection.length = cast(uint)(ctx.length() - ctx.tell()); 142 ctx.psd.imageDataSection.offset = ctx.tell(); 143 }