From 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Fri, 15 Aug 2008 23:44:46 -0500 Subject: Second Life viewer sources 1.13.2.12 --- linden/indra/llimagej2coj/llimagej2coj.cpp | 375 +++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 linden/indra/llimagej2coj/llimagej2coj.cpp (limited to 'linden/indra/llimagej2coj/llimagej2coj.cpp') 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 @@ +/** + * @file llimagej2coj.cpp + * @brief This is an implementation of JPEG2000 encode/decode using OpenJPEG. + * + * Copyright (c) 2006-2007, Linden Research, Inc. + * + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + */ + +#include "linden_common.h" +#include "llimagej2coj.h" + +#include "openjpeg/openjpeg.h" + +#include "lltimer.h" +#include "llmemory.h" + +LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl() +{ + return new LLImageJ2COJ(); +} + +void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl) +{ + delete impl; + impl = NULL; +} + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + fprintf(stdout, "[INFO] %s", msg); +} + + +LLImageJ2COJ::LLImageJ2COJ() : LLImageJ2CImpl() +{ +} + + +LLImageJ2COJ::~LLImageJ2COJ() +{ +} + + +BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) +{ + // + // FIXME: Get the comment field out of the texture + // + + LLTimer decode_timer; + + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *image = NULL; + + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + parameters.cp_reduce = base.getRawDiscardLevel(); + + /* decode the code-stream */ + /* ---------------------- */ + + /* JPEG-2000 codestream */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); + + /* decode the stream and fill the image structure */ + image = opj_decode(dinfo, cio); + if(!image) + { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + + /* free remaining structures */ + if(dinfo) { + opj_destroy_decompress(dinfo); + } + + // Copy image data into our raw image format (instead of the separate channel format + S32 width = 0; + S32 height = 0; + + S32 img_components = image->numcomps; + S32 channels = img_components - first_channel; + if( channels > max_channel_count ) + { + channels = max_channel_count; + } + width = image->x1 - image->x0; + height = image->y1 - image->y0; + raw_image.resize(width, height, channels); + U8 *rawp = raw_image.getData(); + + for (S32 comp = first_channel; comp < first_channel + channels; comp++) + { + S32 offset = comp; + for (S32 y = (height - 1); y >= 0; y--) + { + for (S32 x = 0; x < width; x++) + { + rawp[offset] = image->comps[comp].data[y*width + x]; + offset += channels; + } + } + } + + /* free image data structure */ + opj_image_destroy(image); + + base.setDecodingDone(); + return TRUE; +} + + +BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time) +{ + const S32 MAX_COMPS = 5; + opj_cparameters_t parameters; /* compression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + + + /* + configure the event callbacks (not required) + setting of each callback is optional + */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set encoding parameters to default values */ + opj_set_default_encoder_parameters(¶meters); + parameters.tcp_rates[0] = 0; + parameters.tcp_numlayers++; + parameters.cp_disto_alloc = 1; + parameters.cod_format = 0; + if (!comment_text) + { + parameters.cp_comment = ""; + } + else + { + // Awful hacky cast, too lazy to copy right now. + parameters.cp_comment = (char *)comment_text; + } + + // + // Fill in the source image from our raw image + // + OPJ_COLOR_SPACE color_space = CLRSPC_SRGB; + opj_image_cmptparm_t cmptparm[MAX_COMPS]; + opj_image_t * image = NULL; + S32 numcomps = raw_image.getComponents(); + S32 width = raw_image.getWidth(); + S32 height = raw_image.getHeight(); + + memset(&cmptparm[0], 0, MAX_COMPS * sizeof(opj_image_cmptparm_t)); + for(S32 c = 0; c < numcomps; c++) { + cmptparm[c].prec = 8; + cmptparm[c].bpp = 8; + cmptparm[c].sgnd = 0; + cmptparm[c].dx = parameters.subsampling_dx; + cmptparm[c].dy = parameters.subsampling_dy; + cmptparm[c].w = width; + cmptparm[c].h = height; + } + + /* create the image */ + image = opj_image_create(numcomps, &cmptparm[0], color_space); + + image->x1 = width; + image->y1 = height; + + S32 i = 0; + const U8 *src_datap = raw_image.getData(); + for (S32 y = height - 1; y >= 0; y--) + { + for (S32 x = 0; x < width; x++) + { + const U8 *pixel = src_datap + (y*width + x) * numcomps; + for (S32 c = 0; c < numcomps; c++) + { + image->comps[c].data[i] = *pixel; + pixel++; + } + i++; + } + } + + + + /* encode the destination image */ + /* ---------------------------- */ + + int codestream_length; + opj_cio_t *cio = NULL; + + /* get a J2K compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr); + + /* setup the encoder parameters using the current image and using user parameters */ + opj_setup_encoder(cinfo, ¶meters, image); + + /* open a byte stream for writing */ + /* allocate memory for all tiles */ + cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + + /* encode the image */ + bool bSuccess = opj_encode(cinfo, cio, image, parameters.index); + if (!bSuccess) { + opj_cio_close(cio); + fprintf(stderr, "failed to encode image\n"); + return FALSE; + } + codestream_length = cio_tell(cio); + + base.copyData(cio->buffer, codestream_length); + + /* close and free the byte stream */ + opj_cio_close(cio); + + /* free remaining compression structures */ + opj_destroy_compress(cinfo); + + + /* free user parameters structure */ + if(parameters.cp_matrice) free(parameters.cp_matrice); + + /* free image data */ + opj_image_destroy(image); + return TRUE; +} + +BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base) +{ + // + // FIXME: We get metadata by decoding the ENTIRE image. + // + + // Update the raw discard level + base.updateRawDiscardLevel(); + + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *image = NULL; + + opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ + opj_cio_t *cio = NULL; + + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + //parameters.cp_reduce = mRawDiscardLevel; + + /* decode the code-stream */ + /* ---------------------- */ + + /* JPEG-2000 codestream */ + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); + + /* decode the stream and fill the image structure */ + image = opj_decode(dinfo, cio); + if(!image) + { + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n"); + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + + /* free remaining structures */ + if(dinfo) { + opj_destroy_decompress(dinfo); + } + + // Copy image data into our raw image format (instead of the separate channel format + S32 width = 0; + S32 height = 0; + + S32 img_components = image->numcomps; + width = image->x1 - image->x0; + height = image->y1 - image->y0; + base.setSize(width, height, img_components); + + /* free image data structure */ + opj_image_destroy(image); return TRUE; +} -- cgit v1.1