text: //-----------------------------------------------------------------------------
  //
  // ImageLib Sources
  // Copyright (C) 2000-2009 by Denton Woods
  // Last modified: 03/07/2009
  //
  // Filename: src-IL/src/il_pcd.c
  //
  // Description: Reads from a Kodak PhotoCD (.pcd) file.
  //		Note:  The code here is sloppy - I had to convert it from Pascal,
  //				which I've never even attempted to read before...enjoy! =)
  //
  //-----------------------------------------------------------------------------
  
  
  #include "il_internal.h"
  #ifndef IL_NO_PCD
  #include "il_manip.h"
  
  
  ILboolean iLoadPcdInternal(void);
  
  //! Reads a .pcd file
  ILboolean ilLoadPcd(ILconst_string FileName)
  {
  	ILHANDLE	PcdFile;
  	ILboolean	bPcd = IL_FALSE;
  
  	PcdFile = iopenr(FileName);
  	if (PcdFile == NULL) {
  		ilSetError(IL_COULD_NOT_OPEN_FILE);
  		return bPcd;
  	}
  
  	bPcd = ilLoadPcdF(PcdFile);
  	icloser(PcdFile);
  
  	return bPcd;
  }
  
  
  //! Reads an already-opened .pcd file
  ILboolean ilLoadPcdF(ILHANDLE File)
  {
  	ILuint		FirstPos;
  	ILboolean	bRet;
  
  	iSetInputFile(File);
  	FirstPos = itell();
  	bRet = iLoadPcdInternal();
  	iseek(FirstPos, IL_SEEK_SET);
  
  	return bRet;
  }
  
  
  //! Reads from a memory "lump" that contains a .pcd file
  ILboolean ilLoadPcdL(const void *Lump, ILuint Size)
  {
  	iSetInputLump(Lump, Size);
  	return iLoadPcdInternal();
  }
  
  
  void YCbCr2RGB(ILubyte Y, ILubyte Cb, ILubyte Cr, ILubyte *r, ILubyte *g, ILubyte *b)
  {
  	static const ILdouble c11 = 0.0054980*256;
  	static const ILdouble c12 = 0.0000000*256;
  	static const ILdouble c13 = 0.0051681*256;
  	static const ILdouble c21 = 0.0054980*256;
  	static const ILdouble c22 =-0.0015446*256;
  	static const ILdouble c23 =-0.0026325*256;
  	static const ILdouble c31 = 0.0054980*256;
  	static const ILdouble c32 = 0.0079533*256;
  	static const ILdouble c33 = 0.0000000*256;
  	ILint r1, g1, b1;
  
  	r1 = (ILint)(c11*Y + c12*(Cb-156) + c13*(Cr-137));
  	g1 = (ILint)(c21*Y + c22*(Cb-156) + c23*(Cr-137));
  	b1 = (ILint)(c31*Y + c32*(Cb-156) + c33*(Cr-137));
  
  	if (r1 < 0)
  		*r = 0;
  	else if (r1 > 255)
  		*r = 255;
  	else
  		*r = r1;
  
  	if (g1 < 0)
  		*g = 0;
  	else if (g1 > 255)
  		*g = 255;
  	else
  		*g = g1;
  
  	if (b1 < 0)
  		*b = 0;
  	else if (b1 > 255)
  		*b = 255;
  	else
  		*b = b1;
  
  	return;
  }
  
  
  ILboolean iLoadPcdInternal()
  {
  	ILubyte	VertOrientation;
  	ILuint	Width, Height, i, Total, x, CurPos = 0;
  	ILubyte	*Y1=NULL, *Y2=NULL, *CbCr=NULL, r = 0, g = 0, b = 0;
  	ILuint	PicNum;
  
  	if (iCurImage == NULL) {
  		ilSetError(IL_ILLEGAL_OPERATION);
  		return IL_FALSE;
  	}
  
  	iseek(72, IL_SEEK_CUR);
  	if (iread(&VertOrientation, 1, 1) != 1)
  		return IL_FALSE;
  
  	iseek(-72, IL_SEEK_CUR);  // Can't rewind
  
  	PicNum = iGetInt(IL_PCD_PICNUM);
  
  	switch (PicNum)
  	{
  		case 0:
  			iseek(0x02000, IL_SEEK_CUR);
  			Width = 192;
  			Height = 128;
  			break;
  		case 1:
  			iseek(0x0b800, IL_SEEK_CUR);
  			Width = 384;
  			Height = 256;
  			break;
  		case 2:
  			iseek(0x30000, IL_SEEK_CUR);
  			Width = 768;
  			Height = 512;
  			break;
  		default:
  			ilSetError(IL_INVALID_PARAM);
  			return IL_FALSE;
  	}
  
  	if (itell() == IL_EOF)  // Supposed to have data here.
  		return IL_FALSE;
  
  	Y1 = (ILubyte*)ialloc(Width);
  	Y2 = (ILubyte*)ialloc(Width);
  	CbCr = (ILubyte*)ialloc(Width);
  	if (Y1 == NULL || Y2 == NULL || CbCr == NULL) {
  		ifree(Y1);
  		ifree(Y2);
  		ifree(CbCr);
  		return IL_FALSE;
  	}
  
  	if (!ilTexImage(Width, Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL)) {
  		return IL_FALSE;
  	}
  	iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  
  	Total = Height >> 1;
  	for (i = 0; i < Total; i++) {
  		iread(Y1, 1, Width);
  		iread(Y2, 1, Width);
  		if (iread(CbCr, 1, Width) != Width) {  // Only really need to check the last one.
  			ifree(Y1);
  			ifree(Y2);
  			ifree(CbCr);
  			return IL_FALSE;
  		}
  
  		for (x = 0; x < Width; x++) {
  			YCbCr2RGB(Y1[x], CbCr[x / 2], CbCr[(Width / 2) + (x / 2)], &r, &g, &b);
  			iCurImage->Data[CurPos++] = r;
  			iCurImage->Data[CurPos++] = g;
  			iCurImage->Data[CurPos++] = b;
  		}
  
  		for (x = 0; x < Width; x++) {
  			YCbCr2RGB(Y2[x], CbCr[x / 2], CbCr[(Width / 2) + (x / 2)], &r, &g, &b);
  			iCurImage->Data[CurPos++] = r;
  			iCurImage->Data[CurPos++] = g;
  			iCurImage->Data[CurPos++] = b;
  		}
  	}
  
  	ifree(Y1);
  	ifree(Y2);
  	ifree(CbCr);
  
  	// Not sure how it is...the documentation is hard to understand
  	if ((VertOrientation & 0x3F) != 8)
  		iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  	else
  		iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
  
  	return ilFixImage();
  }
  
  
  #endif//IL_NO_PCD
  