summaryrefslogtreecommitdiff
path: root/indra/llimagej2coj/llimagej2coj.cpp
diff options
context:
space:
mode:
authorJon Wolk <jwolk@lindenlab.com>2007-01-10 21:54:56 +0000
committerJon Wolk <jwolk@lindenlab.com>2007-01-10 21:54:56 +0000
commit0fe36daf5636db0e3d1efad7824419924704eaf0 (patch)
tree2760b820452be2b3fe421183416af3bfb8da8574 /indra/llimagej2coj/llimagej2coj.cpp
parent8c344f4da02105428c5933501d028a4a8908a657 (diff)
svn merge svn+ssh://svn.lindenlab.com/svn/linden/release@56631 svn+ssh://svn.lindenlab.com/svn/linden/branches/abstract-kdu@56647 --ignore-ancestry
Diffstat (limited to 'indra/llimagej2coj/llimagej2coj.cpp')
-rw-r--r--indra/llimagej2coj/llimagej2coj.cpp356
1 files changed, 356 insertions, 0 deletions
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
new file mode 100644
index 0000000000..823d2a8dd4
--- /dev/null
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -0,0 +1,356 @@
+/**
+ * @file llimagej2coj.cpp
+ * @brief This is an implementation of JPEG2000 encode/decode using OpenJPEG.
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#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(&parameters);
+
+ 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, &parameters);
+
+ /* 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(&parameters);
+ 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, &parameters, 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(&parameters);
+
+ //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, &parameters);
+
+ /* 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;
+}