Adobe Photoshop PSD and PSB File Formats

Written by Paul Bourke
June 2015


Adobe PhotoShop PSD and PSB (large document format) are convenient formats for exporting image data, particularly 16 or 32 bit high dynamic range data. The following gives a brief overview of the minimum requirements to create a legal (Adobe PhotoShop will read it) file, a more complete reference is provided here.

A PSD or PSB file consists of a simple header followed by 4 sections, fortunately all the section data can be left empty by specifying 0 in the section length except for the last section which is the image data. The header consists of the usual suspects

  • a magic string to ensure correct file identification, usually "8BPS".

  • a version number, usually 1.

  • the number of channels.

  • the height and width of the image data.

  • the colour depth of each channel in bits, usually 1, 8, 16 or 32.

  • the colour mode, usually Bitmap, Grayscale, Indexed, RGB, CMYK, Multichannel, Duotone or Lab.

The image data can be raw (now compression), rle or zip compressed. In all cases the data is presented in planar (as opposed to interleaved) form.

An (incomplete) example creating a 16bit greyscale PSD file is illustrated below, the functions WriteXXX() write binary data to a file file performing an option byte swap to handle big or little endian data.

   FILE *fptr;
   int i,j;
   char header[8] = "8BPS";
   unsigned short int version = 1,channels = 1,zero = 0;
   unsigned int width = 150,height = 200;
   unsigned int zerolength = 0;
   unsigned short depth = 16,colourmode = 1,compression = 0;
   unsigned short intvalue = 0;

   fptr = fopen("test.psd","w");

   // Header
   fwrite(header,4,1,fptr);
   WriteShort(fptr,version,TRUE);
   for (i=0;i<3;i++)
      WriteShort(fptr,zero,TRUE);
   WriteShort(fptr,channels,TRUE);
   WriteInt(fptr,height,TRUE);
   WriteInt(fptr,width,TRUE);
   WriteShort(fptr,depth,TRUE);
   WriteShort(fptr,colourmode,TRUE);
   WriteInt(fptr,zerolength,TRUE); // Colour mode data
   WriteInt(fptr,zerolength,TRUE); // Image resource data
   WriteInt(fptr,zerolength,TRUE); // Layer and mask section
   // Image data
   WriteShort(fptr,compression,TRUE);
   for (j=0;j<height;j++) {
      for (i=0;i<width;i++) {
         intvalue = j * 65535 / height;
         WriteShort(fptr,intvalue,TRUE);
      }
   }
   fclose(fptr);