1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Copyright (C) 2000-2009 by Denton Woods
5 // Last modified: 03/07/2009
6 //
7 // Filename: src-IL/src/il_pcd.c
8 //
9 // Description: Reads from a Kodak PhotoCD (.pcd) file.
10 //		Note:  The code here is sloppy - I had to convert it from Pascal,
11 //				which I've never even attempted to read before...enjoy! =)
12 //
13 //-----------------------------------------------------------------------------
14 
15 
16 #include "il_internal.h"
17 #ifndef IL_NO_PCD
18 #include "il_manip.h"
19 
20 
21 ILboolean iLoadPcdInternal(void);
22 
23 //! Reads a .pcd file
ilLoadPcd(ILconst_string FileName)24 ILboolean ilLoadPcd(ILconst_string FileName)
25 {
26 	ILHANDLE	PcdFile;
27 	ILboolean	bPcd = IL_FALSE;
28 
29 	PcdFile = iopenr(FileName);
30 	if (PcdFile == NULL) {
31 		ilSetError(IL_COULD_NOT_OPEN_FILE);
32 		return bPcd;
33 	}
34 
35 	bPcd = ilLoadPcdF(PcdFile);
36 	icloser(PcdFile);
37 
38 	return bPcd;
39 }
40 
41 
42 //! Reads an already-opened .pcd file
ilLoadPcdF(ILHANDLE File)43 ILboolean ilLoadPcdF(ILHANDLE File)
44 {
45 	ILuint		FirstPos;
46 	ILboolean	bRet;
47 
48 	iSetInputFile(File);
49 	FirstPos = itell();
50 	bRet = iLoadPcdInternal();
51 	iseek(FirstPos, IL_SEEK_SET);
52 
53 	return bRet;
54 }
55 
56 
57 //! Reads from a memory "lump" that contains a .pcd file
ilLoadPcdL(const void * Lump,ILuint Size)58 ILboolean ilLoadPcdL(const void *Lump, ILuint Size)
59 {
60 	iSetInputLump(Lump, Size);
61 	return iLoadPcdInternal();
62 }
63 
64 
YCbCr2RGB(ILubyte Y,ILubyte Cb,ILubyte Cr,ILubyte * r,ILubyte * g,ILubyte * b)65 void YCbCr2RGB(ILubyte Y, ILubyte Cb, ILubyte Cr, ILubyte *r, ILubyte *g, ILubyte *b)
66 {
67 	static const ILdouble c11 = 0.0054980*256;
68 	static const ILdouble c12 = 0.0000000*256;
69 	static const ILdouble c13 = 0.0051681*256;
70 	static const ILdouble c21 = 0.0054980*256;
71 	static const ILdouble c22 =-0.0015446*256;
72 	static const ILdouble c23 =-0.0026325*256;
73 	static const ILdouble c31 = 0.0054980*256;
74 	static const ILdouble c32 = 0.0079533*256;
75 	static const ILdouble c33 = 0.0000000*256;
76 	ILint r1, g1, b1;
77 
78 	r1 = (ILint)(c11*Y + c12*(Cb-156) + c13*(Cr-137));
79 	g1 = (ILint)(c21*Y + c22*(Cb-156) + c23*(Cr-137));
80 	b1 = (ILint)(c31*Y + c32*(Cb-156) + c33*(Cr-137));
81 
82 	if (r1 < 0)
83 		*r = 0;
84 	else if (r1 > 255)
85 		*r = 255;
86 	else
87 		*r = r1;
88 
89 	if (g1 < 0)
90 		*g = 0;
91 	else if (g1 > 255)
92 		*g = 255;
93 	else
94 		*g = g1;
95 
96 	if (b1 < 0)
97 		*b = 0;
98 	else if (b1 > 255)
99 		*b = 255;
100 	else
101 		*b = b1;
102 
103 	return;
104 }
105 
106 
iLoadPcdInternal()107 ILboolean iLoadPcdInternal()
108 {
109 	ILubyte	VertOrientation;
110 	ILuint	Width, Height, i, Total, x, CurPos = 0;
111 	ILubyte	*Y1=NULL, *Y2=NULL, *CbCr=NULL, r = 0, g = 0, b = 0;
112 	ILuint	PicNum;
113 
114 	if (iCurImage == NULL) {
115 		ilSetError(IL_ILLEGAL_OPERATION);
116 		return IL_FALSE;
117 	}
118 
119 	iseek(72, IL_SEEK_CUR);
120 	if (iread(&VertOrientation, 1, 1) != 1)
121 		return IL_FALSE;
122 
123 	iseek(-72, IL_SEEK_CUR);  // Can't rewind
124 
125 	PicNum = iGetInt(IL_PCD_PICNUM);
126 
127 	switch (PicNum)
128 	{
129 		case 0:
130 			iseek(0x02000, IL_SEEK_CUR);
131 			Width = 192;
132 			Height = 128;
133 			break;
134 		case 1:
135 			iseek(0x0b800, IL_SEEK_CUR);
136 			Width = 384;
137 			Height = 256;
138 			break;
139 		case 2:
140 			iseek(0x30000, IL_SEEK_CUR);
141 			Width = 768;
142 			Height = 512;
143 			break;
144 		default:
145 			ilSetError(IL_INVALID_PARAM);
146 			return IL_FALSE;
147 	}
148 
149 	if (itell() == IL_EOF)  // Supposed to have data here.
150 		return IL_FALSE;
151 
152 	Y1 = (ILubyte*)ialloc(Width);
153 	Y2 = (ILubyte*)ialloc(Width);
154 	CbCr = (ILubyte*)ialloc(Width);
155 	if (Y1 == NULL || Y2 == NULL || CbCr == NULL) {
156 		ifree(Y1);
157 		ifree(Y2);
158 		ifree(CbCr);
159 		return IL_FALSE;
160 	}
161 
162 	if (!ilTexImage(Width, Height, 1, 3, IL_RGB, IL_UNSIGNED_BYTE, NULL)) {
163 		return IL_FALSE;
164 	}
165 	iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
166 
167 	Total = Height >> 1;
168 	for (i = 0; i < Total; i++) {
169 		iread(Y1, 1, Width);
170 		iread(Y2, 1, Width);
171 		if (iread(CbCr, 1, Width) != Width) {  // Only really need to check the last one.
172 			ifree(Y1);
173 			ifree(Y2);
174 			ifree(CbCr);
175 			return IL_FALSE;
176 		}
177 
178 		for (x = 0; x < Width; x++) {
179 			YCbCr2RGB(Y1[x], CbCr[x / 2], CbCr[(Width / 2) + (x / 2)], &r, &g, &b);
180 			iCurImage->Data[CurPos++] = r;
181 			iCurImage->Data[CurPos++] = g;
182 			iCurImage->Data[CurPos++] = b;
183 		}
184 
185 		for (x = 0; x < Width; x++) {
186 			YCbCr2RGB(Y2[x], CbCr[x / 2], CbCr[(Width / 2) + (x / 2)], &r, &g, &b);
187 			iCurImage->Data[CurPos++] = r;
188 			iCurImage->Data[CurPos++] = g;
189 			iCurImage->Data[CurPos++] = b;
190 		}
191 	}
192 
193 	ifree(Y1);
194 	ifree(Y2);
195 	ifree(CbCr);
196 
197 	// Not sure how it is...the documentation is hard to understand
198 	if ((VertOrientation & 0x3F) != 8)
199 		iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
200 	else
201 		iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
202 
203 	return ilFixImage();
204 }
205 
206 
207 #endif//IL_NO_PCD
208