// psdread.cpp

// File created on 8/19/1998
// Written by Thatcher Ulrich <ulrich@world.std.com>
// I'm putting this module in the public domain.  Do what you want with it.


// Some code to read Photoshop 2.5 .PSD files.


#include <stdio.h>
#include "psdread.hpp"
#include "error.hpp"


namespace PSDRead {
;


int	Read16(FILE* fp)
// Reads a two-byte big-endian integer from the given file and returns its value.
// Assumes unsigned.
{
	int	hi = fgetc(fp);
	int	lo = fgetc(fp);
	return lo + (hi << 8);
}


uint32	Read32(FILE* fp)
// Reads a four-byte big-endian integer from the given file and returns its value.
// Assumes unsigned.
{
	uint32	b3 = fgetc(fp);
	uint32	b2 = fgetc(fp);
	uint32	b1 = fgetc(fp);
	uint32	b0 = fgetc(fp);
	return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
}


void	ScanForResolution(float* HRes, float* VRes, FILE* fp, int ByteCount)
// Scans through the next ByteCount bytes of the file, looking for an
// image resource block encoding the image's resolution.  Returns the resolution(s),
// if found, in the pointed-to floats.  Units are in pixels/meter.
{
	while (ByteCount) {
		// Read the image resource block header.
		uint32	Header = Read32(fp);
		if (Header != 0x3842494D /* "8BIM" */) {
			// Format problem.
			Error e; e << "PSDRead: image resource block has unknown signature.";
			throw e;
		}
		int	ID = Read16(fp);

		// Skip the name.
		int	NameLength = fgetc(fp) | 1;	// NameLength must be odd, so that total including size byte is even.
		fseek(fp, NameLength, SEEK_CUR);

		// Get the size of the data block.
		int	DataSize = Read32(fp);
		if (DataSize & 1) {
			DataSize += 1;	// Block size must be even.
		}

		// Account for header size.
		ByteCount -= 11 + NameLength;

		// If this block is a ResolutionInfo structure, then get the resolution.
		if (ID == 0x03ED) {
			// Read ResolutionInfo.
			int	HResFixed = Read32(fp);
			int	junk = Read16(fp);	// display units of hres.
			junk = Read16(fp);	// display units of width.
			int	VResFixed = Read32(fp);
			junk = Read16(fp);	// display units of vres.
			junk = Read16(fp);	// display units of height.

			ByteCount -= DataSize;
			DataSize -= 16;
			// Skip any extra bytes at the end of this block...
			if (DataSize > 0) {
				fseek(fp, DataSize, SEEK_CUR);
			}

			// Need to convert resolution figures from fixed point, pixels/inch to floating point,
			// pixels/meter.
			static const float	InchesPerMeter = 39.4;
			*HRes = HResFixed * (InchesPerMeter / 65536.0);
			*VRes = VResFixed * (InchesPerMeter / 65536.0);
			
		} else {
			// Skip the rest of this block.
			fseek(fp, DataSize, SEEK_CUR);
			ByteCount -= DataSize;
		}
	}
}


bitmap16*	ReadImageData16(const char* filename, float* WidthPtr, float* HeightPtr)
// Reads the image from the specified filename, which must be in Photoshop .PSD format,
// and creates a new 16-bpp image containing the image data.  Creates a new bitmap to
// contain the image, and returns a pointer to the new bitmap.
// !!! The caller is responsible for freeing the bitmap.
// Returns NULL if the file can't be read or the image can't be created.
// If the given Width and/or Height parameters are not NULL, then stores the
// width and height of the image in the referenced locations, as encoded in the .PSD
// file but converted so that 1 cm in Photoshop == 1 meter here.
{
//	*data = NULL;

	// Open the data file for input.
	FILE*	fp = fopen(filename, "rb");
	if (fp == NULL) {
		return NULL;
	}

	// Check file type signature.
	uint32	sig = Read32(fp);
	if (sig != 0x38425053 /* "8BPS" */) {
		// Not .PSD format.
		fclose(fp);
		return NULL;
	}

	// Check file type version.
	if (Read16(fp) != 1) {
		fclose(fp);
		return NULL;
	}

	// 6 reserved bytes.
	Read32(fp);
	Read16(fp);

	// Read the number of channels (R, G, B, A, etc).
	int	ChannelCount = Read16(fp);
	if (ChannelCount < 0 || ChannelCount > 16) {
		fclose(fp);
		return NULL;
	}

	// Read the rows and columns of the image.
	int	height = Read32(fp);
	int	width = Read32(fp);

	// Make sure the depth is 8 bits.
	if (Read16(fp) != 8) {
		fclose(fp);
		return NULL;
	}

	// Make sure the color mode is RGB.
	// Valid options are:
	//   0: Bitmap
	//   1: Grayscale
	//   2: Indexed color
	//   3: RGB color
	//   4: CMYK color
	//   7: Multichannel
	//   8: Duotone
	//   9: Lab color
	if (Read16(fp) != 3) {
		fclose(fp);
		return NULL;
	}

	// Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
	int	ModeDataCount = Read32(fp);
	if (ModeDataCount) {
		fseek(fp, ModeDataCount, SEEK_CUR);
	}

	// Process the image resources.  (resolution, pen tool paths, etc)
	int	ResourceDataCount = Read32(fp);
	if (ResourceDataCount) {
		// Read the image resources, looking for the info in the resolution block.
		float	HRes = 1.0;
		float	VRes = 1.0;
		ScanForResolution(&HRes, &VRes, fp, ResourceDataCount);

		// Set returns values for bitmap height/width.
		if (WidthPtr) {
			*WidthPtr = width / HRes * 100.0;	// Compute size in m, then multiply by 100 since we want 1 Photoshop cm == 1 Soul Ride meter.
		}
		if (HeightPtr) {
			*HeightPtr = height / VRes * 100.0;
		}
		
//		fseek(fp, ResourceDataCount, SEEK_CUR);
	}

	// Skip the reserved data.
	int	ReservedDataCount = Read32(fp);
	if (ReservedDataCount) {
		fseek(fp, ReservedDataCount, SEEK_CUR);
	}

	// Find out if the data is compressed.
	// Known values:
	//   0: no compression
	//   1: RLE compressed
	int	Compression = Read16(fp);
	if (Compression > 1) {
		// Unknown compression type.
		fclose(fp);
		return NULL;
	}

	// Some formatting information about the channels.
	const struct ChannelInfo {
		int	Shift, Mask, Default;
	} Channel[4] = {
		{  1, 0x7C00, 0 },	// Red.
		{  6, 0x03E0, 0 },	// Green.
		{ 11, 0x001F, 0 },	// Blue.
		{  0, 0x8000, 255 }	// Alpha
	};

	// Create the destination bitmap.
	bitmap16*	b = new bitmap16(width, height);
	int	PixelCount = height * width;
//	*data = new uint16[PixelCount];

	// Initialize the data to zero.
	uint16*	p = b->GetData();
	for (int i = 0; i < PixelCount; i++) {
		*p++ = 0;
	}
	
	// Finally, the image data.
	if (Compression) {
		// The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
		// which we're going to just skip.
		fseek(fp, height * ChannelCount * 2, SEEK_CUR);

		// Read the RLE data by channel.
		for (int channel = 0; channel < 4; channel++) {
			const ChannelInfo&	c = Channel[channel];
			
			uint16*	p = b->GetData();
			if (channel >= ChannelCount) {
				// Fill this channel with default data.
				uint16	def = (c.Default << 8 >> c.Shift) & c.Mask;
				for (int i = 0; i < PixelCount; i++) {
					*p++ |= def;
				}
			} else {
				// Read the RLE data.
				int	count = 0;
				while (count < PixelCount) {
					int	len = fgetc(fp);
					if (len == 128) {
						// No-op.
					} else if (len < 128) {
						// Copy next len+1 bytes literally.
						len++;
						count += len;
						while (len) {
							*p++ |= ((fgetc(fp) << 8 >> c.Shift) & c.Mask);
							len--;
						}
					} else if (len > 128) {
						// Next -len+1 bytes in the dest are replicated from next source byte.
						// (Interpret len as a negative 8-bit int.)
						len ^= 0x0FF;
						len += 2;
						uint16	val = (fgetc(fp) << 8 >> c.Shift) & c.Mask;
						count += len;
						while (len) {
							*p++ |= val;
							len--;
						}
					}
				}
			}
		}
		
	} else {
		// We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
		// where each channel consists of an 8-bit value for each pixel in the image.
		
		// Read the data by channel.
		for (int channel = 0; channel < 4; channel++) {
			const ChannelInfo&	c = Channel[channel];
			
			uint16*	p = b->GetData();
			if (channel > ChannelCount) {
				// Fill this channel with default data.
				uint16	def = (c.Default << 8 >> c.Shift) & c.Mask;
				for (int i = 0; i < PixelCount; i++) {
					*p++ |= def;
				}
			} else {
				// Read the data.
				int	count = 0;
				for (int i = 0; i < PixelCount; i++) {
					*p++ |= (fgetc(fp) << 8 >> c.Shift) & c.Mask;
				}
			}
		}
	}
	
	fclose(fp);

	return b;
}


bitmap32*	ReadImageData32(const char* filename)
// Reads the image from the specified filename, which must be in Photoshop .PSD format,
// and creates a new 32-bpp image containing the image data.  Creates a new bitmap to
// contain the image, and returns a pointer to the new bitmap.
// !!! The caller is responsible for freeing the bitmap.
// Returns NULL if the file can't be read or the image can't be created.
{
	// Open the data file for input.
	FILE*	fp = fopen(filename, "rb");
	if (fp == NULL) {
		return NULL;
	}

	// Check file type signature.
	uint32	sig = Read32(fp);
	if (sig != 0x38425053 /* "8BPS" */) {
		// Not .PSD format.
		fclose(fp);
		return NULL;
	}

	// Check file type version.
	if (Read16(fp) != 1) {
		fclose(fp);
		return NULL;
	}

	// 6 reserved bytes.
	Read32(fp);
	Read16(fp);

	// Read the number of channels (R, G, B, A, etc).
	int	ChannelCount = Read16(fp);
	if (ChannelCount < 0 || ChannelCount > 16) {
		fclose(fp);
		return NULL;
	}

	// Read the rows and columns of the image.
	int	height = Read32(fp);
	int	width = Read32(fp);

	// Make sure the depth is 8 bits.
	if (Read16(fp) != 8) {
		fclose(fp);
		return NULL;
	}

	// Make sure the color mode is RGB.
	// Valid options are:
	//   0: Bitmap
	//   1: Grayscale
	//   2: Indexed color
	//   3: RGB color
	//   4: CMYK color
	//   7: Multichannel
	//   8: Duotone
	//   9: Lab color
	if (Read16(fp) != 3) {
		fclose(fp);
		return NULL;
	}

	// Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
	int	ModeDataCount = Read32(fp);
	if (ModeDataCount) {
		fseek(fp, ModeDataCount, SEEK_CUR);
	}

	// Skip the image resources.  (resolution, pen tool paths, etc)
	int	ResourceDataCount = Read32(fp);
	if (ResourceDataCount) {
		fseek(fp, ResourceDataCount, SEEK_CUR);
	}

	// Skip the reserved data.
	int	ReservedDataCount = Read32(fp);
	if (ReservedDataCount) {
		fseek(fp, ReservedDataCount, SEEK_CUR);
	}

	// Find out if the data is compressed.
	// Known values:
	//   0: no compression
	//   1: RLE compressed
	int	Compression = Read16(fp);
	if (Compression > 1) {
		// Unknown compression type.
		fclose(fp);
		return NULL;
	}

	// Some formatting information about the channels.
	const struct ChannelInfo {
		int	Shift, Mask, Default;
	} Channel[4] = {
		{ 16, 0x00FF0000, 0 },	// Red.
		{  8, 0x0000FF00, 0 },	// Green.
		{  0, 0x000000FF, 0 },	// Blue.
		{ 24, 0xFF000000, 255 }	// Alpha.
	};

	// Create the destination bitmap.
	bitmap32*	b = new bitmap32(width, height);
	int	PixelCount = height * width;

	// Initialize the data to zero.
	uint32*	p = b->GetData();
	for (int i = 0; i < PixelCount; i++) {
		*p++ = 0;
	}
	
	// Finally, the image data.
	if (Compression) {
		// The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
		// which we're going to just skip.
		fseek(fp, height * ChannelCount * 2, SEEK_CUR);

		// Read the RLE data by channel.
		for (int channel = 0; channel < 4; channel++) {
			const ChannelInfo&	c = Channel[channel];
			
			uint32*	p = b->GetData();
			if (channel >= ChannelCount) {
				// Fill this channel with default data.
				uint32	def = (c.Default << c.Shift) & c.Mask;
				for (int i = 0; i < PixelCount; i++) {
					*p++ |= def;
				}
			} else {
				// Read the RLE data.
				int	count = 0;
				while (count < PixelCount) {
					int	len = fgetc(fp);
					if (len == 128) {
						// No-op.
					} else if (len < 128) {
						// Copy next len+1 bytes literally.
						len++;
						count += len;
						while (len) {
							*p++ |= ((fgetc(fp) << c.Shift) & c.Mask);
							len--;
						}
					} else if (len > 128) {
						// Next -len+1 bytes in the dest are replicated from next source byte.
						// (Interpret len as a negative 8-bit int.)
						len ^= 0x0FF;
						len += 2;
						uint32	val = (fgetc(fp) << c.Shift) & c.Mask;
						count += len;
						while (len) {
							*p++ |= val;
							len--;
						}
					}
				}
			}
		}
		
	} else {
		// We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
		// where each channel consists of an 8-bit value for each pixel in the image.
		
		// Read the data by channel.
		for (int channel = 0; channel < 4; channel++) {
			const ChannelInfo&	c = Channel[channel];
			
			uint32*	p = b->GetData();
			if (channel > ChannelCount) {
				// Fill this channel with default data.
				uint32	def = (c.Default << c.Shift) & c.Mask;
				for (int i = 0; i < PixelCount; i++) {
					*p++ |= def;
				}
			} else {
				// Read the data.
				int	count = 0;
				for (int i = 0; i < PixelCount; i++) {
					*p++ |= (fgetc(fp) << c.Shift) & c.Mask;
				}
			}
		}
	}
	
	fclose(fp);

	return b;
}


//
// RLE as used by .PSD and .TIFF
//

//Loop until you get the number of unpacked bytes you are expecting:
//    Read the next source byte into n.
//    If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
//    Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
//    Else if n is 128, noop.
//Endloop


}; // end namespace PSDRead

