diff options
Diffstat (limited to 'linden/indra/llimagej2coj/llimagej2coj.cpp')
-rw-r--r-- | linden/indra/llimagej2coj/llimagej2coj.cpp | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/linden/indra/llimagej2coj/llimagej2coj.cpp b/linden/indra/llimagej2coj/llimagej2coj.cpp new file mode 100644 index 0000000..f292da9 --- /dev/null +++ b/linden/indra/llimagej2coj/llimagej2coj.cpp | |||
@@ -0,0 +1,375 @@ | |||
1 | /** | ||
2 | * @file llimagej2coj.cpp | ||
3 | * @brief This is an implementation of JPEG2000 encode/decode using OpenJPEG. | ||
4 | * | ||
5 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | #include "llimagej2coj.h" | ||
30 | |||
31 | #include "openjpeg/openjpeg.h" | ||
32 | |||
33 | #include "lltimer.h" | ||
34 | #include "llmemory.h" | ||
35 | |||
36 | LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl() | ||
37 | { | ||
38 | return new LLImageJ2COJ(); | ||
39 | } | ||
40 | |||
41 | void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl) | ||
42 | { | ||
43 | delete impl; | ||
44 | impl = NULL; | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | sample error callback expecting a FILE* client object | ||
49 | */ | ||
50 | void error_callback(const char *msg, void *client_data) { | ||
51 | FILE *stream = (FILE*)client_data; | ||
52 | fprintf(stream, "[ERROR] %s", msg); | ||
53 | } | ||
54 | /** | ||
55 | sample warning callback expecting a FILE* client object | ||
56 | */ | ||
57 | void warning_callback(const char *msg, void *client_data) { | ||
58 | FILE *stream = (FILE*)client_data; | ||
59 | fprintf(stream, "[WARNING] %s", msg); | ||
60 | } | ||
61 | /** | ||
62 | sample debug callback expecting no client object | ||
63 | */ | ||
64 | void info_callback(const char *msg, void *client_data) { | ||
65 | fprintf(stdout, "[INFO] %s", msg); | ||
66 | } | ||
67 | |||
68 | |||
69 | LLImageJ2COJ::LLImageJ2COJ() : LLImageJ2CImpl() | ||
70 | { | ||
71 | } | ||
72 | |||
73 | |||
74 | LLImageJ2COJ::~LLImageJ2COJ() | ||
75 | { | ||
76 | } | ||
77 | |||
78 | |||
79 | BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) | ||
80 | { | ||
81 | // | ||
82 | // FIXME: Get the comment field out of the texture | ||
83 | // | ||
84 | |||
85 | LLTimer decode_timer; | ||
86 | |||
87 | opj_dparameters_t parameters; /* decompression parameters */ | ||
88 | opj_event_mgr_t event_mgr; /* event manager */ | ||
89 | opj_image_t *image = NULL; | ||
90 | |||
91 | opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ | ||
92 | opj_cio_t *cio = NULL; | ||
93 | |||
94 | |||
95 | /* configure the event callbacks (not required) */ | ||
96 | memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); | ||
97 | event_mgr.error_handler = error_callback; | ||
98 | event_mgr.warning_handler = warning_callback; | ||
99 | event_mgr.info_handler = info_callback; | ||
100 | |||
101 | /* set decoding parameters to default values */ | ||
102 | opj_set_default_decoder_parameters(¶meters); | ||
103 | |||
104 | parameters.cp_reduce = base.getRawDiscardLevel(); | ||
105 | |||
106 | /* decode the code-stream */ | ||
107 | /* ---------------------- */ | ||
108 | |||
109 | /* JPEG-2000 codestream */ | ||
110 | |||
111 | /* get a decoder handle */ | ||
112 | dinfo = opj_create_decompress(CODEC_J2K); | ||
113 | |||
114 | /* catch events using our callbacks and give a local context */ | ||
115 | opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); | ||
116 | |||
117 | /* setup the decoder decoding parameters using user parameters */ | ||
118 | opj_setup_decoder(dinfo, ¶meters); | ||
119 | |||
120 | /* open a byte stream */ | ||
121 | cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); | ||
122 | |||
123 | /* decode the stream and fill the image structure */ | ||
124 | image = opj_decode(dinfo, cio); | ||
125 | if(!image) | ||
126 | { | ||
127 | fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); | ||
128 | opj_destroy_decompress(dinfo); | ||
129 | opj_cio_close(cio); | ||
130 | return 1; | ||
131 | } | ||
132 | |||
133 | /* close the byte stream */ | ||
134 | opj_cio_close(cio); | ||
135 | |||
136 | |||
137 | /* free remaining structures */ | ||
138 | if(dinfo) { | ||
139 | opj_destroy_decompress(dinfo); | ||
140 | } | ||
141 | |||
142 | // Copy image data into our raw image format (instead of the separate channel format | ||
143 | S32 width = 0; | ||
144 | S32 height = 0; | ||
145 | |||
146 | S32 img_components = image->numcomps; | ||
147 | S32 channels = img_components - first_channel; | ||
148 | if( channels > max_channel_count ) | ||
149 | { | ||
150 | channels = max_channel_count; | ||
151 | } | ||
152 | width = image->x1 - image->x0; | ||
153 | height = image->y1 - image->y0; | ||
154 | raw_image.resize(width, height, channels); | ||
155 | U8 *rawp = raw_image.getData(); | ||
156 | |||
157 | for (S32 comp = first_channel; comp < first_channel + channels; comp++) | ||
158 | { | ||
159 | S32 offset = comp; | ||
160 | for (S32 y = (height - 1); y >= 0; y--) | ||
161 | { | ||
162 | for (S32 x = 0; x < width; x++) | ||
163 | { | ||
164 | rawp[offset] = image->comps[comp].data[y*width + x]; | ||
165 | offset += channels; | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
170 | /* free image data structure */ | ||
171 | opj_image_destroy(image); | ||
172 | |||
173 | base.setDecodingDone(); | ||
174 | return TRUE; | ||
175 | } | ||
176 | |||
177 | |||
178 | BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time) | ||
179 | { | ||
180 | const S32 MAX_COMPS = 5; | ||
181 | opj_cparameters_t parameters; /* compression parameters */ | ||
182 | opj_event_mgr_t event_mgr; /* event manager */ | ||
183 | |||
184 | |||
185 | /* | ||
186 | configure the event callbacks (not required) | ||
187 | setting of each callback is optional | ||
188 | */ | ||
189 | memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); | ||
190 | event_mgr.error_handler = error_callback; | ||
191 | event_mgr.warning_handler = warning_callback; | ||
192 | event_mgr.info_handler = info_callback; | ||
193 | |||
194 | /* set encoding parameters to default values */ | ||
195 | opj_set_default_encoder_parameters(¶meters); | ||
196 | parameters.tcp_rates[0] = 0; | ||
197 | parameters.tcp_numlayers++; | ||
198 | parameters.cp_disto_alloc = 1; | ||
199 | parameters.cod_format = 0; | ||
200 | if (!comment_text) | ||
201 | { | ||
202 | parameters.cp_comment = ""; | ||
203 | } | ||
204 | else | ||
205 | { | ||
206 | // Awful hacky cast, too lazy to copy right now. | ||
207 | parameters.cp_comment = (char *)comment_text; | ||
208 | } | ||
209 | |||
210 | // | ||
211 | // Fill in the source image from our raw image | ||
212 | // | ||
213 | OPJ_COLOR_SPACE color_space = CLRSPC_SRGB; | ||
214 | opj_image_cmptparm_t cmptparm[MAX_COMPS]; | ||
215 | opj_image_t * image = NULL; | ||
216 | S32 numcomps = raw_image.getComponents(); | ||
217 | S32 width = raw_image.getWidth(); | ||
218 | S32 height = raw_image.getHeight(); | ||
219 | |||
220 | memset(&cmptparm[0], 0, MAX_COMPS * sizeof(opj_image_cmptparm_t)); | ||
221 | for(S32 c = 0; c < numcomps; c++) { | ||
222 | cmptparm[c].prec = 8; | ||
223 | cmptparm[c].bpp = 8; | ||
224 | cmptparm[c].sgnd = 0; | ||
225 | cmptparm[c].dx = parameters.subsampling_dx; | ||
226 | cmptparm[c].dy = parameters.subsampling_dy; | ||
227 | cmptparm[c].w = width; | ||
228 | cmptparm[c].h = height; | ||
229 | } | ||
230 | |||
231 | /* create the image */ | ||
232 | image = opj_image_create(numcomps, &cmptparm[0], color_space); | ||
233 | |||
234 | image->x1 = width; | ||
235 | image->y1 = height; | ||
236 | |||
237 | S32 i = 0; | ||
238 | const U8 *src_datap = raw_image.getData(); | ||
239 | for (S32 y = height - 1; y >= 0; y--) | ||
240 | { | ||
241 | for (S32 x = 0; x < width; x++) | ||
242 | { | ||
243 | const U8 *pixel = src_datap + (y*width + x) * numcomps; | ||
244 | for (S32 c = 0; c < numcomps; c++) | ||
245 | { | ||
246 | image->comps[c].data[i] = *pixel; | ||
247 | pixel++; | ||
248 | } | ||
249 | i++; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | |||
254 | |||
255 | /* encode the destination image */ | ||
256 | /* ---------------------------- */ | ||
257 | |||
258 | int codestream_length; | ||
259 | opj_cio_t *cio = NULL; | ||
260 | |||
261 | /* get a J2K compressor handle */ | ||
262 | opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); | ||
263 | |||
264 | /* catch events using our callbacks and give a local context */ | ||
265 | opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); | ||
266 | |||
267 | /* setup the encoder parameters using the current image and using user parameters */ | ||
268 | opj_setup_encoder(cinfo, ¶meters, image); | ||
269 | |||
270 | /* open a byte stream for writing */ | ||
271 | /* allocate memory for all tiles */ | ||
272 | cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); | ||
273 | |||
274 | /* encode the image */ | ||
275 | bool bSuccess = opj_encode(cinfo, cio, image, parameters.index); | ||
276 | if (!bSuccess) { | ||
277 | opj_cio_close(cio); | ||
278 | fprintf(stderr, "failed to encode image\n"); | ||
279 | return FALSE; | ||
280 | } | ||
281 | codestream_length = cio_tell(cio); | ||
282 | |||
283 | base.copyData(cio->buffer, codestream_length); | ||
284 | |||
285 | /* close and free the byte stream */ | ||
286 | opj_cio_close(cio); | ||
287 | |||
288 | /* free remaining compression structures */ | ||
289 | opj_destroy_compress(cinfo); | ||
290 | |||
291 | |||
292 | /* free user parameters structure */ | ||
293 | if(parameters.cp_matrice) free(parameters.cp_matrice); | ||
294 | |||
295 | /* free image data */ | ||
296 | opj_image_destroy(image); | ||
297 | return TRUE; | ||
298 | } | ||
299 | |||
300 | BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base) | ||
301 | { | ||
302 | // | ||
303 | // FIXME: We get metadata by decoding the ENTIRE image. | ||
304 | // | ||
305 | |||
306 | // Update the raw discard level | ||
307 | base.updateRawDiscardLevel(); | ||
308 | |||
309 | opj_dparameters_t parameters; /* decompression parameters */ | ||
310 | opj_event_mgr_t event_mgr; /* event manager */ | ||
311 | opj_image_t *image = NULL; | ||
312 | |||
313 | opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ | ||
314 | opj_cio_t *cio = NULL; | ||
315 | |||
316 | |||
317 | /* configure the event callbacks (not required) */ | ||
318 | memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); | ||
319 | event_mgr.error_handler = error_callback; | ||
320 | event_mgr.warning_handler = warning_callback; | ||
321 | event_mgr.info_handler = info_callback; | ||
322 | |||
323 | /* set decoding parameters to default values */ | ||
324 | opj_set_default_decoder_parameters(¶meters); | ||
325 | |||
326 | //parameters.cp_reduce = mRawDiscardLevel; | ||
327 | |||
328 | /* decode the code-stream */ | ||
329 | /* ---------------------- */ | ||
330 | |||
331 | /* JPEG-2000 codestream */ | ||
332 | |||
333 | /* get a decoder handle */ | ||
334 | dinfo = opj_create_decompress(CODEC_J2K); | ||
335 | |||
336 | /* catch events using our callbacks and give a local context */ | ||
337 | opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); | ||
338 | |||
339 | /* setup the decoder decoding parameters using user parameters */ | ||
340 | opj_setup_decoder(dinfo, ¶meters); | ||
341 | |||
342 | /* open a byte stream */ | ||
343 | cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); | ||
344 | |||
345 | /* decode the stream and fill the image structure */ | ||
346 | image = opj_decode(dinfo, cio); | ||
347 | if(!image) | ||
348 | { | ||
349 | fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); | ||
350 | opj_destroy_decompress(dinfo); | ||
351 | opj_cio_close(cio); | ||
352 | return 1; | ||
353 | } | ||
354 | |||
355 | /* close the byte stream */ | ||
356 | opj_cio_close(cio); | ||
357 | |||
358 | |||
359 | /* free remaining structures */ | ||
360 | if(dinfo) { | ||
361 | opj_destroy_decompress(dinfo); | ||
362 | } | ||
363 | |||
364 | // Copy image data into our raw image format (instead of the separate channel format | ||
365 | S32 width = 0; | ||
366 | S32 height = 0; | ||
367 | |||
368 | S32 img_components = image->numcomps; | ||
369 | width = image->x1 - image->x0; | ||
370 | height = image->y1 - image->y0; | ||
371 | base.setSize(width, height, img_components); | ||
372 | |||
373 | /* free image data structure */ | ||
374 | opj_image_destroy(image); return TRUE; | ||
375 | } | ||