/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginPCD.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // ========================================================== |
2 | | // Kodak PhotoCD Loader |
3 | | // |
4 | | // Design and implementation by |
5 | | // - Floris van den Berg (flvdberg@wxs.nl) |
6 | | // |
7 | | // Based on pascal code developed by Alex Kwak |
8 | | // |
9 | | // This file is part of FreeImage 3 |
10 | | // |
11 | | // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY |
12 | | // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES |
13 | | // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE |
14 | | // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED |
15 | | // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT |
16 | | // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY |
17 | | // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL |
18 | | // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
19 | | // THIS DISCLAIMER. |
20 | | // |
21 | | // Use at your own risk! |
22 | | // ========================================================== |
23 | | |
24 | | #include "FreeImage.h" |
25 | | #include "Utilities.h" |
26 | | |
27 | | // ========================================================== |
28 | | // Internal functions |
29 | | // ========================================================== |
30 | | |
31 | | static int |
32 | 0 | clamp(double x) { |
33 | 0 | int a = (int)floor(x + 0.5); |
34 | 0 | return (a < 0) ? 0 : (a > 255) ? 255 : a; |
35 | 0 | } |
36 | | |
37 | | static void |
38 | 0 | YUV2RGB(int y, int cb, int cr, int &r, int &g, int &b) { |
39 | 0 | double c11 = 0.0054980 * 256.0; |
40 | 0 | double c12 = 0.0000001 * 256.0; |
41 | 0 | double c13 = 0.0051681 * 256.0; |
42 | 0 | double c21 = 0.0054980 * 256.0; |
43 | 0 | double c22 = -0.0015446 * 256.0; |
44 | 0 | double c23 = -0.0026325 * 256.0; |
45 | 0 | double c31 = 0.0054980 * 256.0; |
46 | 0 | double c32 = 0.0079533 * 256.0; |
47 | 0 | double c33 = 0.0000001 * 256.0; |
48 | |
|
49 | 0 | r = clamp(c11 * y + c12 * (cb - 156) + c13 * (cr - 137)); |
50 | 0 | g = clamp(c21 * y + c22 * (cb - 156) + c23 * (cr - 137)); |
51 | 0 | b = clamp(c31 * y + c32 * (cb - 156) + c33 * (cr - 137)); |
52 | 0 | } |
53 | | |
54 | | static BOOL |
55 | 0 | VerticalOrientation(FreeImageIO *io, fi_handle handle) { |
56 | 0 | char buffer[128]; |
57 | |
|
58 | 0 | io->read_proc(buffer, 128, 1, handle); |
59 | |
|
60 | 0 | return (buffer[72] & 63) == 8; |
61 | 0 | } |
62 | | |
63 | | // ========================================================== |
64 | | // Plugin Interface |
65 | | // ========================================================== |
66 | | |
67 | | static int s_format_id; |
68 | | |
69 | | // ========================================================== |
70 | | // Plugin Implementation |
71 | | // ========================================================== |
72 | | |
73 | | static const char * DLL_CALLCONV |
74 | 2 | Format() { |
75 | 2 | return "PCD"; |
76 | 2 | } |
77 | | |
78 | | static const char * DLL_CALLCONV |
79 | 0 | Description() { |
80 | 0 | return "Kodak PhotoCD"; |
81 | 0 | } |
82 | | |
83 | | static const char * DLL_CALLCONV |
84 | 0 | Extension() { |
85 | 0 | return "pcd"; |
86 | 0 | } |
87 | | |
88 | | static const char * DLL_CALLCONV |
89 | 0 | RegExpr() { |
90 | 0 | return NULL; |
91 | 0 | } |
92 | | |
93 | | static const char * DLL_CALLCONV |
94 | 0 | MimeType() { |
95 | 0 | return "image/x-photo-cd"; |
96 | 0 | } |
97 | | |
98 | | static BOOL DLL_CALLCONV |
99 | 0 | SupportsExportDepth(int depth) { |
100 | 0 | return FALSE; |
101 | 0 | } |
102 | | |
103 | | static BOOL DLL_CALLCONV |
104 | 0 | SupportsExportType(FREE_IMAGE_TYPE type) { |
105 | 0 | return FALSE; |
106 | 0 | } |
107 | | |
108 | | static BOOL DLL_CALLCONV |
109 | 0 | SupportsNoPixels() { |
110 | 0 | return TRUE; |
111 | 0 | } |
112 | | |
113 | | // ---------------------------------------------------------- |
114 | | |
115 | | static FIBITMAP * DLL_CALLCONV |
116 | 0 | Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { |
117 | 0 | FIBITMAP *dib = NULL; |
118 | 0 | unsigned width; |
119 | 0 | unsigned height; |
120 | 0 | const unsigned bpp = 24; |
121 | 0 | int scan_line_add = 1; |
122 | 0 | int start_scan_line = 0; |
123 | | |
124 | 0 | BYTE *y1 = NULL, *y2 = NULL, *cbcr = NULL; |
125 | |
|
126 | 0 | BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; |
127 | | |
128 | | // to make absolute seeks possible we store the current position in the file |
129 | | |
130 | 0 | long offset_in_file = io->tell_proc(handle); |
131 | 0 | long seek = 0; |
132 | | |
133 | | // decide which bitmap in the cabinet to load |
134 | |
|
135 | 0 | switch (flags) { |
136 | 0 | case PCD_BASEDIV4 : |
137 | 0 | seek = 0x2000; |
138 | 0 | width = 192; |
139 | 0 | height = 128; |
140 | 0 | break; |
141 | | |
142 | 0 | case PCD_BASEDIV16 : |
143 | 0 | seek = 0xB800; |
144 | 0 | width = 384; |
145 | 0 | height = 256; |
146 | 0 | break; |
147 | | |
148 | 0 | default : |
149 | 0 | seek = 0x30000; |
150 | 0 | width = 768; |
151 | 0 | height = 512; |
152 | 0 | break; |
153 | 0 | } |
154 | | |
155 | 0 | try { |
156 | | // allocate the dib and write out the header |
157 | 0 | dib = FreeImage_AllocateHeader(header_only, width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); |
158 | 0 | if(!dib) throw FI_MSG_ERROR_DIB_MEMORY; |
159 | | |
160 | 0 | if(header_only) { |
161 | 0 | return dib; |
162 | 0 | } |
163 | | |
164 | | // check if the PCD is bottom-up |
165 | | |
166 | 0 | if (VerticalOrientation(io, handle)) { |
167 | 0 | scan_line_add = -1; |
168 | 0 | start_scan_line = height - 1; |
169 | 0 | } |
170 | | |
171 | | // temporary stuff to load PCD |
172 | |
|
173 | 0 | BYTE *y1 = (BYTE*)malloc(width * sizeof(BYTE)); |
174 | 0 | BYTE *y2 = (BYTE*)malloc(width * sizeof(BYTE)); |
175 | 0 | BYTE *cbcr = (BYTE*)malloc(width * sizeof(BYTE)); |
176 | 0 | if(!y1 || !y2 || !cbcr) throw FI_MSG_ERROR_MEMORY; |
177 | | |
178 | 0 | BYTE *yl[] = { y1, y2 }; |
179 | | |
180 | | // seek to the part where the bitmap data begins |
181 | |
|
182 | 0 | io->seek_proc(handle, offset_in_file, SEEK_SET); |
183 | 0 | io->seek_proc(handle, seek, SEEK_CUR); |
184 | | |
185 | | // read the data |
186 | |
|
187 | 0 | for (unsigned y = 0; y < height / 2; y++) { |
188 | 0 | io->read_proc(y1, width, 1, handle); |
189 | 0 | io->read_proc(y2, width, 1, handle); |
190 | 0 | io->read_proc(cbcr, width, 1, handle); |
191 | |
|
192 | 0 | for (int i = 0; i < 2; i++) { |
193 | 0 | BYTE *bits = FreeImage_GetScanLine(dib, start_scan_line); |
194 | 0 | for (unsigned x = 0; x < width; x++) { |
195 | 0 | int r, g, b; |
196 | |
|
197 | 0 | YUV2RGB(yl[i][x], cbcr[x / 2], cbcr[(width / 2) + (x / 2)], r, g, b); |
198 | |
|
199 | 0 | bits[FI_RGBA_BLUE] = (BYTE)b; |
200 | 0 | bits[FI_RGBA_GREEN] = (BYTE)g; |
201 | 0 | bits[FI_RGBA_RED] = (BYTE)r; |
202 | 0 | bits += 3; |
203 | 0 | } |
204 | |
|
205 | 0 | start_scan_line += scan_line_add; |
206 | 0 | } |
207 | 0 | } |
208 | |
|
209 | 0 | free(cbcr); |
210 | 0 | free(y2); |
211 | 0 | free(y1); |
212 | |
|
213 | 0 | return dib; |
214 | |
|
215 | 0 | } catch(const char *text) { |
216 | 0 | if(dib) FreeImage_Unload(dib); |
217 | 0 | if(cbcr) free(cbcr); |
218 | 0 | if(y2) free(y2); |
219 | 0 | if(y1) free(y1); |
220 | |
|
221 | 0 | FreeImage_OutputMessageProc(s_format_id, text); |
222 | |
|
223 | 0 | return NULL; |
224 | 0 | } |
225 | 0 | } |
226 | | |
227 | | // ========================================================== |
228 | | // Init |
229 | | // ========================================================== |
230 | | |
231 | | void DLL_CALLCONV |
232 | 2 | InitPCD(Plugin *plugin, int format_id) { |
233 | 2 | s_format_id = format_id; |
234 | | |
235 | 2 | plugin->format_proc = Format; |
236 | 2 | plugin->description_proc = Description; |
237 | 2 | plugin->extension_proc = Extension; |
238 | 2 | plugin->regexpr_proc = RegExpr; |
239 | 2 | plugin->open_proc = NULL; |
240 | 2 | plugin->close_proc = NULL; |
241 | 2 | plugin->pagecount_proc = NULL; |
242 | 2 | plugin->pagecapability_proc = NULL; |
243 | 2 | plugin->load_proc = Load; |
244 | 2 | plugin->save_proc = NULL; |
245 | 2 | plugin->validate_proc = NULL; |
246 | 2 | plugin->mime_proc = MimeType; |
247 | 2 | plugin->supports_export_bpp_proc = SupportsExportDepth; |
248 | 2 | plugin->supports_export_type_proc = SupportsExportType; |
249 | 2 | plugin->supports_icc_profiles_proc = NULL; |
250 | 2 | plugin->supports_no_pixels_proc = SupportsNoPixels; |
251 | 2 | } |