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