summaryrefslogtreecommitdiff
path: root/indra/llkdu
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2024-05-15 16:35:49 +0300
committerGitHub <noreply@github.com>2024-05-15 16:35:49 +0300
commite49dcb8d0c9f539997effb640e350d9d0689aae6 (patch)
tree1bf99eaccce6de17c62f13c6595f7f497548dc5c /indra/llkdu
parent531cd34f670170ade57f8813fe48012b61a1d3c2 (diff)
parent5f8a7374b9f18e0112d6749a9c845bd077a81acb (diff)
Merge pull request #1476 from secondlife/marchcat/x-b-merge
Maint X -> Maint B merge
Diffstat (limited to 'indra/llkdu')
-rw-r--r--indra/llkdu/include_kdu_xxxx.h4
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp2324
-rw-r--r--indra/llkdu/llimagej2ckdu.h158
-rw-r--r--indra/llkdu/llkdumem.cpp306
-rw-r--r--indra/llkdu/llkdumem.h180
-rw-r--r--indra/llkdu/tests/llimagej2ckdu_test.cpp164
6 files changed, 1568 insertions, 1568 deletions
diff --git a/indra/llkdu/include_kdu_xxxx.h b/indra/llkdu/include_kdu_xxxx.h
index 61204b5689..3db417a6cb 100644
--- a/indra/llkdu/include_kdu_xxxx.h
+++ b/indra/llkdu/include_kdu_xxxx.h
@@ -2,8 +2,8 @@
* @file include_kdu_xxxx.h
* @author Nat Goodspeed
* @date 2016-04-25
- * @brief
- *
+ * @brief
+ *
* $LicenseInfo:firstyear=2016&license=viewerlgpl$
* Copyright (c) 2016, Linden Research, Inc.
* $/LicenseInfo$
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 2ad42d6b87..c51650a470 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -1,25 +1,25 @@
-/**
+/**
* @file llimagej2ckdu.cpp
* @brief This is an implementation of JPEG2000 encode/decode using Kakadu
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -51,8 +51,8 @@ namespace kdu_core
inline
std::ostream& operator<<(std::ostream& out, const kdu_dims& dims)
{
- return out << "(" << dims.pos.x << "," << dims.pos.y << "),"
- "[" << dims.size.x << "x" << dims.size.y << "]";
+ return out << "(" << dims.pos.x << "," << dims.pos.y << "),"
+ "[" << dims.size.x << "x" << dims.size.y << "]";
}
} // namespace kdu_core
@@ -103,36 +103,36 @@ std::string report_kdu_exception(kdu_exception mb)
class kdc_flow_control {
-
+
public:
- kdc_flow_control(kdu_supp::kdu_image_in_base *img_in, kdu_codestream codestream);
- ~kdc_flow_control();
- bool advance_components();
- void process_components();
-
+ kdc_flow_control(kdu_supp::kdu_image_in_base *img_in, kdu_codestream codestream);
+ ~kdc_flow_control();
+ bool advance_components();
+ void process_components();
+
private:
-
- struct kdc_component_flow_control {
- public:
- kdu_supp::kdu_image_in_base *reader;
- int vert_subsampling;
- int ratio_counter; /* Initialized to 0, decremented by `count_delta';
+
+ struct kdc_component_flow_control {
+ public:
+ kdu_supp::kdu_image_in_base *reader;
+ int vert_subsampling;
+ int ratio_counter; /* Initialized to 0, decremented by `count_delta';
when < 0, a new line must be processed, after
which it is incremented by `vert_subsampling'. */
- int initial_lines;
- int remaining_lines;
- kdu_line_buf *line;
- };
-
- kdu_codestream codestream;
- kdu_dims valid_tile_indices;
- kdu_coords tile_idx;
- kdu_tile tile;
- int num_components;
- kdc_component_flow_control *components;
- int count_delta; // Holds the minimum of the `vert_subsampling' fields
- kdu_multi_analysis engine;
- kdu_long max_buffer_memory;
+ int initial_lines;
+ int remaining_lines;
+ kdu_line_buf *line;
+ };
+
+ kdu_codestream codestream;
+ kdu_dims valid_tile_indices;
+ kdu_coords tile_idx;
+ kdu_tile tile;
+ int num_components;
+ kdc_component_flow_control *components;
+ int count_delta; // Holds the minimum of the `vert_subsampling' fields
+ kdu_multi_analysis engine;
+ kdu_long max_buffer_memory;
};
//
@@ -143,73 +143,73 @@ void set_default_colour_weights(kdu_params *siz);
// Factory function: see declaration in llimagej2c.cpp
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
{
- return new LLImageJ2CKDU();
+ return new LLImageJ2CKDU();
}
std::string LLImageJ2CKDU::getEngineInfo() const
{
- return llformat("KDU %s", KDU_CORE_VERSION);
+ return llformat("KDU %s", KDU_CORE_VERSION);
}
class LLKDUDecodeState
{
public:
- LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap,
- kdu_codestream* codestreamp);
- ~LLKDUDecodeState();
- bool processTileDecode(F32 decode_time, bool limit_time = true);
+ LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap,
+ kdu_codestream* codestreamp);
+ ~LLKDUDecodeState();
+ bool processTileDecode(F32 decode_time, bool limit_time = true);
private:
- S32 mNumComponents;
- bool mUseYCC;
- kdu_dims mDims;
- kdu_sample_allocator mAllocator;
- kdu_tile_comp mComps[4];
- kdu_line_buf mLines[4];
- kdu_pull_ifc mEngines[4];
- bool mReversible[4]; // Some components may be reversible and others not
- int mBitDepths[4]; // Original bit-depth may be quite different from 8
-
- kdu_tile mTile;
- kdu_byte *mBuf;
- S32 mRowGap;
+ S32 mNumComponents;
+ bool mUseYCC;
+ kdu_dims mDims;
+ kdu_sample_allocator mAllocator;
+ kdu_tile_comp mComps[4];
+ kdu_line_buf mLines[4];
+ kdu_pull_ifc mEngines[4];
+ bool mReversible[4]; // Some components may be reversible and others not
+ int mBitDepths[4]; // Original bit-depth may be quite different from 8
+
+ kdu_tile mTile;
+ kdu_byte *mBuf;
+ S32 mRowGap;
};
// Stuff for new kdu error handling
class LLKDUMessage: public kdu_message
{
public:
- LLKDUMessage(const std::string& type):
- mType(type)
- {}
-
- virtual void put_text(const char *s)
- {
- LL_INFOS() << "KDU " << mType << ": " << s << LL_ENDL;
- }
-
- virtual void put_text(const kdu_uint16 *s)
- {
- // The previous implementation simply streamed 's' to the log. So
- // either this put_text() override was never called -- or it produced
- // some baffling log messages -- because I assert that streaming a
- // const kdu_uint16* to a std::ostream will display only the hex value
- // of the pointer.
- LL_INFOS() << "KDU " << mType << ": "
- << utf16str_to_utf8str(llutf16string(s)) << LL_ENDL;
- }
+ LLKDUMessage(const std::string& type):
+ mType(type)
+ {}
+
+ virtual void put_text(const char *s)
+ {
+ LL_INFOS() << "KDU " << mType << ": " << s << LL_ENDL;
+ }
+
+ virtual void put_text(const kdu_uint16 *s)
+ {
+ // The previous implementation simply streamed 's' to the log. So
+ // either this put_text() override was never called -- or it produced
+ // some baffling log messages -- because I assert that streaming a
+ // const kdu_uint16* to a std::ostream will display only the hex value
+ // of the pointer.
+ LL_INFOS() << "KDU " << mType << ": "
+ << utf16str_to_utf8str(llutf16string(s)) << LL_ENDL;
+ }
private:
- std::string mType;
+ std::string mType;
};
struct LLKDUMessageWarning : public LLKDUMessage
{
- LLKDUMessageWarning():
- LLKDUMessage("Warning")
- {
- kdu_customize_warnings(this);
- }
+ LLKDUMessageWarning():
+ LLKDUMessage("Warning")
+ {
+ kdu_customize_warnings(this);
+ }
};
// Instantiating LLKDUMessageWarning calls kdu_customize_warnings() with the
// new instance. Make it static so this only happens once.
@@ -217,55 +217,55 @@ static LLKDUMessageWarning sWarningHandler;
struct LLKDUMessageError : public LLKDUMessage
{
- LLKDUMessageError():
- LLKDUMessage("Error")
- {
- kdu_customize_errors(this);
- }
-
- virtual void flush(bool end_of_message = false)
- {
- // According to the documentation nat found:
- // http://pirlwww.lpl.arizona.edu/resources/guide/software/Kakadu/html_pages/globals__kdu$mize_errors.html
- // "If a kdu_error object is destroyed, handler→flush will be called with
- // an end_of_message argument equal to true and the process will
- // subsequently be terminated through exit. The termination may be
- // avoided, however, by throwing an exception from within the message
- // terminating handler→flush call."
- // So throwing an exception here isn't arbitrary: we MUST throw an
- // exception if we want to recover from a KDU error.
- // Because this confused me: the above quote specifically refers to
- // the kdu_error class, which is constructed internally within KDU at
- // the point where a fatal error is discovered and reported. It is NOT
- // talking about the kdu_message subclass passed to
- // kdu_customize_errors(). Destroying this static object at program
- // shutdown will NOT engage the behavior described above.
- if (end_of_message)
- {
- LLTHROW(KDUError("LLKDUMessageError::flush()"));
- }
- }
+ LLKDUMessageError():
+ LLKDUMessage("Error")
+ {
+ kdu_customize_errors(this);
+ }
+
+ virtual void flush(bool end_of_message = false)
+ {
+ // According to the documentation nat found:
+ // http://pirlwww.lpl.arizona.edu/resources/guide/software/Kakadu/html_pages/globals__kdu$mize_errors.html
+ // "If a kdu_error object is destroyed, handler→flush will be called with
+ // an end_of_message argument equal to true and the process will
+ // subsequently be terminated through exit. The termination may be
+ // avoided, however, by throwing an exception from within the message
+ // terminating handler→flush call."
+ // So throwing an exception here isn't arbitrary: we MUST throw an
+ // exception if we want to recover from a KDU error.
+ // Because this confused me: the above quote specifically refers to
+ // the kdu_error class, which is constructed internally within KDU at
+ // the point where a fatal error is discovered and reported. It is NOT
+ // talking about the kdu_message subclass passed to
+ // kdu_customize_errors(). Destroying this static object at program
+ // shutdown will NOT engage the behavior described above.
+ if (end_of_message)
+ {
+ LLTHROW(KDUError("LLKDUMessageError::flush()"));
+ }
+ }
};
// Instantiating LLKDUMessageError calls kdu_customize_errors() with the new
// instance. Make it static so this only happens once.
static LLKDUMessageError sErrorHandler;
LLImageJ2CKDU::LLImageJ2CKDU() : LLImageJ2CImpl(),
- mInputp(),
- mCodeStreamp(),
- mTPosp(),
- mTileIndicesp(),
- mRawImagep(NULL),
- mDecodeState(),
- mBlocksSize(-1),
- mPrecinctsSize(-1),
- mLevels(0)
+ mInputp(),
+ mCodeStreamp(),
+ mTPosp(),
+ mTileIndicesp(),
+ mRawImagep(NULL),
+ mDecodeState(),
+ mBlocksSize(-1),
+ mPrecinctsSize(-1),
+ mLevels(0)
{
}
LLImageJ2CKDU::~LLImageJ2CKDU()
{
- cleanupCodeStream(); // in case destroyed before decode completed
+ cleanupCodeStream(); // in case destroyed before decode completed
}
// Stuff for new simple decode
@@ -277,114 +277,114 @@ void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision);
// as well, when that still existed, with keep_codestream true and MODE_FAST.
void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECodeStreamMode mode)
{
- S32 data_size = base.getDataSize();
- S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
-
- //
- // Initialization
- //
- mCodeStreamp.reset();
-
- // It's not clear to nat under what circumstances we would reuse a
- // pre-existing LLKDUMemSource instance. As of 2016-08-05, it consists of
- // two U32s and a pointer, so it's not as if it would be a huge overhead
- // to allocate a new one every time.
- // Also -- why is base.getData() tested specifically here? If that returns
- // NULL, shouldn't we bail out of the whole method?
- if (!mInputp && base.getData())
- {
- // The compressed data has been loaded
- // Setup the source for the codestream
- mInputp.reset(new LLKDUMemSource(base.getData(), data_size));
- }
-
- if (mInputp)
- {
- // This is LLKDUMemSource::reset(), not boost::scoped_ptr::reset().
- mInputp->reset();
- }
-
- mCodeStreamp->create(mInputp.get());
-
- // Set the maximum number of bytes to use from the codestream
- // *TODO: This seems to be wrong. The base class should have no idea of
- // how j2c compression works so no good way of computing what's the byte
- // range to be used.
- mCodeStreamp->set_max_bytes(max_bytes,true);
-
- // If you want to flip or rotate the image for some reason, change
- // the resolution, or identify a restricted region of interest, this is
- // the place to do it. You may use "kdu_codestream::change_appearance"
- // and "kdu_codestream::apply_input_restrictions" for this purpose.
- // If you wish to truncate the code-stream prior to decompression, you
- // may use "kdu_codestream::set_max_bytes".
- // If you wish to retain all compressed data so that the material
- // can be decompressed multiple times, possibly with different appearance
- // parameters, you should call "kdu_codestream::set_persistent" here.
- // There are a variety of other features which must be enabled at
- // this point if you want to take advantage of them. See the
- // descriptions appearing with the "kdu_codestream" interface functions
- // in "kdu_compressed.h" for an itemized account of these capabilities.
-
- switch (mode)
- {
- case MODE_FAST:
- mCodeStreamp->set_fast();
- break;
- case MODE_RESILIENT:
- mCodeStreamp->set_resilient();
- break;
- case MODE_FUSSY:
- mCodeStreamp->set_fussy();
- break;
- default:
- llassert(0);
- mCodeStreamp->set_fast();
- }
-
- kdu_dims dims;
- mCodeStreamp->get_dims(0,dims);
-
- S32 components = mCodeStreamp->get_num_components();
-
- // Check that components have consistent dimensions (for PPM file)
- for (int idx = 1; idx < components; ++idx)
- {
- kdu_dims other_dims;
- mCodeStreamp->get_dims(idx, other_dims);
- if (other_dims != dims)
- {
- // This method is only called from methods that catch KDUError.
- // We want to fail the image load, not crash the viewer.
- LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions "
- << stringize(other_dims)
- << " do not match component 0 dimensions "
- << stringize(dims) << "!")));
- }
- }
-
- // Get the number of resolution levels in that image
- mLevels = mCodeStreamp->get_min_dwt_levels();
-
- // Set the base dimensions
- base.setSize(dims.size.x, dims.size.y, components);
- base.setLevels(mLevels);
-
- if (!keep_codestream)
- {
- mCodeStreamp.reset();
- mInputp.reset();
- }
+ S32 data_size = base.getDataSize();
+ S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
+
+ //
+ // Initialization
+ //
+ mCodeStreamp.reset();
+
+ // It's not clear to nat under what circumstances we would reuse a
+ // pre-existing LLKDUMemSource instance. As of 2016-08-05, it consists of
+ // two U32s and a pointer, so it's not as if it would be a huge overhead
+ // to allocate a new one every time.
+ // Also -- why is base.getData() tested specifically here? If that returns
+ // NULL, shouldn't we bail out of the whole method?
+ if (!mInputp && base.getData())
+ {
+ // The compressed data has been loaded
+ // Setup the source for the codestream
+ mInputp.reset(new LLKDUMemSource(base.getData(), data_size));
+ }
+
+ if (mInputp)
+ {
+ // This is LLKDUMemSource::reset(), not boost::scoped_ptr::reset().
+ mInputp->reset();
+ }
+
+ mCodeStreamp->create(mInputp.get());
+
+ // Set the maximum number of bytes to use from the codestream
+ // *TODO: This seems to be wrong. The base class should have no idea of
+ // how j2c compression works so no good way of computing what's the byte
+ // range to be used.
+ mCodeStreamp->set_max_bytes(max_bytes,true);
+
+ // If you want to flip or rotate the image for some reason, change
+ // the resolution, or identify a restricted region of interest, this is
+ // the place to do it. You may use "kdu_codestream::change_appearance"
+ // and "kdu_codestream::apply_input_restrictions" for this purpose.
+ // If you wish to truncate the code-stream prior to decompression, you
+ // may use "kdu_codestream::set_max_bytes".
+ // If you wish to retain all compressed data so that the material
+ // can be decompressed multiple times, possibly with different appearance
+ // parameters, you should call "kdu_codestream::set_persistent" here.
+ // There are a variety of other features which must be enabled at
+ // this point if you want to take advantage of them. See the
+ // descriptions appearing with the "kdu_codestream" interface functions
+ // in "kdu_compressed.h" for an itemized account of these capabilities.
+
+ switch (mode)
+ {
+ case MODE_FAST:
+ mCodeStreamp->set_fast();
+ break;
+ case MODE_RESILIENT:
+ mCodeStreamp->set_resilient();
+ break;
+ case MODE_FUSSY:
+ mCodeStreamp->set_fussy();
+ break;
+ default:
+ llassert(0);
+ mCodeStreamp->set_fast();
+ }
+
+ kdu_dims dims;
+ mCodeStreamp->get_dims(0,dims);
+
+ S32 components = mCodeStreamp->get_num_components();
+
+ // Check that components have consistent dimensions (for PPM file)
+ for (int idx = 1; idx < components; ++idx)
+ {
+ kdu_dims other_dims;
+ mCodeStreamp->get_dims(idx, other_dims);
+ if (other_dims != dims)
+ {
+ // This method is only called from methods that catch KDUError.
+ // We want to fail the image load, not crash the viewer.
+ LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions "
+ << stringize(other_dims)
+ << " do not match component 0 dimensions "
+ << stringize(dims) << "!")));
+ }
+ }
+
+ // Get the number of resolution levels in that image
+ mLevels = mCodeStreamp->get_min_dwt_levels();
+
+ // Set the base dimensions
+ base.setSize(dims.size.x, dims.size.y, components);
+ base.setLevels(mLevels);
+
+ if (!keep_codestream)
+ {
+ mCodeStreamp.reset();
+ mInputp.reset();
+ }
}
void LLImageJ2CKDU::cleanupCodeStream()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- mInputp.reset();
- mDecodeState.reset();
- mCodeStreamp.reset();
- mTPosp.reset();
- mTileIndicesp.reset();
+ mInputp.reset();
+ mDecodeState.reset();
+ mCodeStreamp.reset();
+ mTPosp.reset();
+ mTileIndicesp.reset();
}
// This is the protected virtual method called by LLImageJ2C::initDecode().
@@ -392,34 +392,34 @@ void LLImageJ2CKDU::cleanupCodeStream()
// llimage_libtest.cpp's load_image() function. No detectable production use.
bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
{
- return initDecode(base,raw_image,0.0f,MODE_FAST,0,4,discard_level,region);
+ return initDecode(base,raw_image,0.0f,MODE_FAST,0,4,discard_level,region);
}
bool LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
{
- mPrecinctsSize = precincts_size;
- if (mPrecinctsSize != -1)
- {
- mPrecinctsSize = get_lower_power_two(mPrecinctsSize,MAX_PRECINCT_SIZE);
- mPrecinctsSize = llmax(mPrecinctsSize,MIN_PRECINCT_SIZE);
- }
- mBlocksSize = blocks_size;
- if (mBlocksSize != -1)
- {
- mBlocksSize = get_lower_power_two(mBlocksSize,MAX_BLOCK_SIZE);
- mBlocksSize = llmax(mBlocksSize,MIN_BLOCK_SIZE);
- if (mPrecinctsSize != -1)
- {
- mBlocksSize = llmin(mBlocksSize,mPrecinctsSize); // blocks *must* be smaller than precincts
- }
- }
- mLevels = levels;
- if (mLevels != 0)
- {
- mLevels = llclamp(mLevels,MIN_DECOMPOSITION_LEVELS,MAX_DECOMPOSITION_LEVELS);
- base.setLevels(mLevels);
- }
- return true;
+ mPrecinctsSize = precincts_size;
+ if (mPrecinctsSize != -1)
+ {
+ mPrecinctsSize = get_lower_power_two(mPrecinctsSize,MAX_PRECINCT_SIZE);
+ mPrecinctsSize = llmax(mPrecinctsSize,MIN_PRECINCT_SIZE);
+ }
+ mBlocksSize = blocks_size;
+ if (mBlocksSize != -1)
+ {
+ mBlocksSize = get_lower_power_two(mBlocksSize,MAX_BLOCK_SIZE);
+ mBlocksSize = llmax(mBlocksSize,MIN_BLOCK_SIZE);
+ if (mPrecinctsSize != -1)
+ {
+ mBlocksSize = llmin(mBlocksSize,mPrecinctsSize); // blocks *must* be smaller than precincts
+ }
+ }
+ mLevels = levels;
+ if (mLevels != 0)
+ {
+ mLevels = llclamp(mLevels,MIN_DECOMPOSITION_LEVELS,MAX_DECOMPOSITION_LEVELS);
+ base.setLevels(mLevels);
+ }
+ return true;
}
// This is the real (private) initDecode() called both by the protected
@@ -428,83 +428,83 @@ bool LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int bloc
bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level, int* region)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- base.resetLastError();
-
- // *FIX: kdu calls our callback function if there's an error, and then bombs.
- // To regain control, we throw an exception, and catch it here.
- try
- {
- // Merov : Test!! DO NOT COMMIT!!
- //findDiscardLevelsBoundaries(base);
-
- base.updateRawDiscardLevel();
- setupCodeStream(base, true, mode);
-
- mRawImagep = &raw_image;
- mCodeStreamp->change_appearance(false, true, false);
-
- // Apply loading discard level and cropping if required
- kdu_dims* region_kdu = NULL;
- if (region != NULL)
- {
- region_kdu = new kdu_dims;
- region_kdu->pos.x = region[0];
- region_kdu->pos.y = region[1];
- region_kdu->size.x = region[2] - region[0];
- region_kdu->size.y = region[3] - region[1];
- }
- int discard = (discard_level != -1 ? discard_level : base.getRawDiscardLevel());
- //LL_INFOS() << "Merov debug : initDecode, discard used = " << discard << ", asked = " << discard_level << LL_ENDL;
- // Apply loading restrictions
- mCodeStreamp->apply_input_restrictions( first_channel, max_channel_count, discard, 0, region_kdu);
-
- // Clean-up
- if (region_kdu)
- {
- delete region_kdu;
- region_kdu = NULL;
- }
-
- // Resize raw_image according to the image to be decoded
- kdu_dims dims; mCodeStreamp->get_dims(0,dims);
- S32 channels = base.getComponents() - first_channel;
- channels = llmin(channels,max_channel_count);
- raw_image.resize(dims.size.x, dims.size.y, channels);
-
- if (!mTileIndicesp)
- {
- mTileIndicesp.reset(new kdu_dims);
- }
- mCodeStreamp->get_valid_tiles(*mTileIndicesp);
- if (!mTPosp)
- {
- mTPosp.reset(new kdu_coords);
- mTPosp->y = 0;
- mTPosp->x = 0;
- }
- }
- catch (const KDUError& msg)
- {
- base.setLastError(msg.what());
- return false;
- }
- catch (kdu_exception kdu_value)
- {
- // KDU internally throws kdu_exception. It's possible that such an
- // exception might leak out into our code. Catch kdu_exception
- // specially because boost::current_exception_diagnostic_information()
- // could do nothing with it.
- base.setLastError(report_kdu_exception(kdu_value));
- return false;
- }
- catch (...)
- {
- base.setLastError("Unknown J2C error: " +
- boost::current_exception_diagnostic_information());
- return false;
- }
-
- return true;
+ base.resetLastError();
+
+ // *FIX: kdu calls our callback function if there's an error, and then bombs.
+ // To regain control, we throw an exception, and catch it here.
+ try
+ {
+ // Merov : Test!! DO NOT COMMIT!!
+ //findDiscardLevelsBoundaries(base);
+
+ base.updateRawDiscardLevel();
+ setupCodeStream(base, true, mode);
+
+ mRawImagep = &raw_image;
+ mCodeStreamp->change_appearance(false, true, false);
+
+ // Apply loading discard level and cropping if required
+ kdu_dims* region_kdu = NULL;
+ if (region != NULL)
+ {
+ region_kdu = new kdu_dims;
+ region_kdu->pos.x = region[0];
+ region_kdu->pos.y = region[1];
+ region_kdu->size.x = region[2] - region[0];
+ region_kdu->size.y = region[3] - region[1];
+ }
+ int discard = (discard_level != -1 ? discard_level : base.getRawDiscardLevel());
+ //LL_INFOS() << "Merov debug : initDecode, discard used = " << discard << ", asked = " << discard_level << LL_ENDL;
+ // Apply loading restrictions
+ mCodeStreamp->apply_input_restrictions( first_channel, max_channel_count, discard, 0, region_kdu);
+
+ // Clean-up
+ if (region_kdu)
+ {
+ delete region_kdu;
+ region_kdu = NULL;
+ }
+
+ // Resize raw_image according to the image to be decoded
+ kdu_dims dims; mCodeStreamp->get_dims(0,dims);
+ S32 channels = base.getComponents() - first_channel;
+ channels = llmin(channels,max_channel_count);
+ raw_image.resize(dims.size.x, dims.size.y, channels);
+
+ if (!mTileIndicesp)
+ {
+ mTileIndicesp.reset(new kdu_dims);
+ }
+ mCodeStreamp->get_valid_tiles(*mTileIndicesp);
+ if (!mTPosp)
+ {
+ mTPosp.reset(new kdu_coords);
+ mTPosp->y = 0;
+ mTPosp->x = 0;
+ }
+ }
+ catch (const KDUError& msg)
+ {
+ base.setLastError(msg.what());
+ return false;
+ }
+ catch (kdu_exception kdu_value)
+ {
+ // KDU internally throws kdu_exception. It's possible that such an
+ // exception might leak out into our code. Catch kdu_exception
+ // specially because boost::current_exception_diagnostic_information()
+ // could do nothing with it.
+ base.setLastError(report_kdu_exception(kdu_value));
+ return false;
+ }
+ catch (...)
+ {
+ base.setLastError("Unknown J2C error: " +
+ boost::current_exception_diagnostic_information());
+ return false;
+ }
+
+ return true;
}
@@ -512,344 +512,344 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- ECodeStreamMode mode = MODE_FAST;
-
- LLTimer decode_timer;
-
- if (!mCodeStreamp->exists())
- {
- if (!initDecode(base, raw_image, decode_time, mode, first_channel, max_channel_count))
- {
- // Initializing the J2C decode failed, bail out.
- cleanupCodeStream();
- return true; // done
- }
- }
-
- // These can probably be grabbed from what's saved in the class.
- kdu_dims dims;
- mCodeStreamp->get_dims(0,dims);
-
- // Now we are ready to walk through the tiles processing them one-by-one.
- kdu_byte *buffer = raw_image.getData();
- if (!buffer)
- {
- base.setLastError("Memory error");
- base.decodeFailed();
- cleanupCodeStream();
- return true; // done
- }
-
- while (mTPosp->y < mTileIndicesp->size.y)
- {
- while (mTPosp->x < mTileIndicesp->size.x)
- {
- try
- {
- if (!mDecodeState)
- {
- kdu_tile tile = mCodeStreamp->open_tile(*(mTPosp)+mTileIndicesp->pos);
-
- // Find the region of the buffer occupied by this
- // tile. Note that we have no control over
- // sub-sampling factors which might have been used
- // during compression and so it can happen that tiles
- // (at the image component level) actually have
- // different dimensions. For this reason, we cannot
- // figure out the buffer region occupied by a tile
- // directly from the tile indices. Instead, we query
- // the highest resolution of the first tile-component
- // concerning its location and size on the canvas --
- // the `dims' object already holds the location and
- // size of the entire image component on the same
- // canvas coordinate system. Comparing the two tells
- // us where the current tile is in the buffer.
- S32 channels = base.getComponents() - first_channel;
- if (channels > max_channel_count)
- {
- channels = max_channel_count;
- }
- kdu_resolution res = tile.access_component(0).access_resolution();
- kdu_dims tile_dims; res.get_dims(tile_dims);
- kdu_coords offset = tile_dims.pos - dims.pos;
- int row_gap = channels*dims.size.x; // inter-row separation
- kdu_byte *buf = buffer + offset.y*row_gap + offset.x*channels;
- mDecodeState.reset(new LLKDUDecodeState(tile, buf, row_gap,
- mCodeStreamp.get()));
- }
- // Do the actual processing
- F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32();
- // This is where we do the actual decode. If we run out of time, return false.
- if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f)))
- {
- mDecodeState.reset();
- }
- else
- {
- // Not finished decoding yet.
- // setLastError("Ran out of time while decoding");
- return false;
- }
- }
- catch (const KDUError& msg)
- {
- base.setLastError(msg.what());
- base.decodeFailed();
- cleanupCodeStream();
- return true; // done
- }
- catch (kdu_exception kdu_value)
- {
- // KDU internally throws kdu_exception. It's possible that such an
- // exception might leak out into our code. Catch kdu_exception
- // specially because boost::current_exception_diagnostic_information()
- // could do nothing with it.
- base.setLastError(report_kdu_exception(kdu_value));
- base.decodeFailed();
- cleanupCodeStream();
- return true; // done
- }
- catch (...)
- {
- base.setLastError("Unknown J2C error: " +
- boost::current_exception_diagnostic_information());
- base.decodeFailed();
- cleanupCodeStream();
- return true; // done
- }
-
-
- mTPosp->x++;
- }
- mTPosp->y++;
- mTPosp->x = 0;
- }
-
- cleanupCodeStream();
-
- return true;
+ ECodeStreamMode mode = MODE_FAST;
+
+ LLTimer decode_timer;
+
+ if (!mCodeStreamp->exists())
+ {
+ if (!initDecode(base, raw_image, decode_time, mode, first_channel, max_channel_count))
+ {
+ // Initializing the J2C decode failed, bail out.
+ cleanupCodeStream();
+ return true; // done
+ }
+ }
+
+ // These can probably be grabbed from what's saved in the class.
+ kdu_dims dims;
+ mCodeStreamp->get_dims(0,dims);
+
+ // Now we are ready to walk through the tiles processing them one-by-one.
+ kdu_byte *buffer = raw_image.getData();
+ if (!buffer)
+ {
+ base.setLastError("Memory error");
+ base.decodeFailed();
+ cleanupCodeStream();
+ return true; // done
+ }
+
+ while (mTPosp->y < mTileIndicesp->size.y)
+ {
+ while (mTPosp->x < mTileIndicesp->size.x)
+ {
+ try
+ {
+ if (!mDecodeState)
+ {
+ kdu_tile tile = mCodeStreamp->open_tile(*(mTPosp)+mTileIndicesp->pos);
+
+ // Find the region of the buffer occupied by this
+ // tile. Note that we have no control over
+ // sub-sampling factors which might have been used
+ // during compression and so it can happen that tiles
+ // (at the image component level) actually have
+ // different dimensions. For this reason, we cannot
+ // figure out the buffer region occupied by a tile
+ // directly from the tile indices. Instead, we query
+ // the highest resolution of the first tile-component
+ // concerning its location and size on the canvas --
+ // the `dims' object already holds the location and
+ // size of the entire image component on the same
+ // canvas coordinate system. Comparing the two tells
+ // us where the current tile is in the buffer.
+ S32 channels = base.getComponents() - first_channel;
+ if (channels > max_channel_count)
+ {
+ channels = max_channel_count;
+ }
+ kdu_resolution res = tile.access_component(0).access_resolution();
+ kdu_dims tile_dims; res.get_dims(tile_dims);
+ kdu_coords offset = tile_dims.pos - dims.pos;
+ int row_gap = channels*dims.size.x; // inter-row separation
+ kdu_byte *buf = buffer + offset.y*row_gap + offset.x*channels;
+ mDecodeState.reset(new LLKDUDecodeState(tile, buf, row_gap,
+ mCodeStreamp.get()));
+ }
+ // Do the actual processing
+ F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32();
+ // This is where we do the actual decode. If we run out of time, return false.
+ if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f)))
+ {
+ mDecodeState.reset();
+ }
+ else
+ {
+ // Not finished decoding yet.
+ // setLastError("Ran out of time while decoding");
+ return false;
+ }
+ }
+ catch (const KDUError& msg)
+ {
+ base.setLastError(msg.what());
+ base.decodeFailed();
+ cleanupCodeStream();
+ return true; // done
+ }
+ catch (kdu_exception kdu_value)
+ {
+ // KDU internally throws kdu_exception. It's possible that such an
+ // exception might leak out into our code. Catch kdu_exception
+ // specially because boost::current_exception_diagnostic_information()
+ // could do nothing with it.
+ base.setLastError(report_kdu_exception(kdu_value));
+ base.decodeFailed();
+ cleanupCodeStream();
+ return true; // done
+ }
+ catch (...)
+ {
+ base.setLastError("Unknown J2C error: " +
+ boost::current_exception_diagnostic_information());
+ base.decodeFailed();
+ cleanupCodeStream();
+ return true; // done
+ }
+
+
+ mTPosp->x++;
+ }
+ mTPosp->y++;
+ mTPosp->x = 0;
+ }
+
+ cleanupCodeStream();
+
+ return true;
}
bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible)
{
- // Declare and set simple arguments
- bool transpose = false;
- bool vflip = true;
- bool hflip = false;
-
- try
- {
- // Set up input image files
- siz_params siz;
-
- // Should set rate someplace here
- LLKDUMemIn mem_in(raw_image.getData(),
- raw_image.getDataSize(),
- raw_image.getWidth(),
- raw_image.getHeight(),
- raw_image.getComponents(),
- &siz);
-
- base.setSize(raw_image.getWidth(), raw_image.getHeight(), raw_image.getComponents());
-
- int num_components = raw_image.getComponents();
-
- siz.set(Scomponents,0,0,num_components);
- siz.set(Sdims,0,0,base.getHeight()); // Height of first image component
- siz.set(Sdims,0,1,base.getWidth()); // Width of first image component
- siz.set(Sprecision,0,0,8); // Image samples have original bit-depth of 8
- siz.set(Ssigned,0,0,false); // Image samples are originally unsigned
-
- kdu_params *siz_ref = &siz;
- siz_ref->finalize();
- siz_params transformed_siz; // Use this one to construct code-stream
- transformed_siz.copy_from(&siz,-1,-1,-1,0,transpose,false,false);
-
- // Construct the `kdu_codestream' object and parse all remaining arguments
- U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents();
- max_output_size = (max_output_size < 1000 ? 1000 : max_output_size);
- U8 *output_buffer = new U8[max_output_size];
- U32 output_size = 0; // Address updated by LLKDUMemTarget to give the final compressed buffer size
- LLKDUMemTarget output(output_buffer, output_size, max_output_size);
-
- kdu_codestream codestream;
- codestream.create(&transformed_siz,&output);
-
- if (comment_text)
- {
- // Set the comments for the codestream
- kdu_codestream_comment comment = codestream.add_comment();
- comment.put_text(comment_text);
- }
-
- if (num_components >= 3)
- {
- // Note that we always use YCC and not YUV
- // *TODO: Verify this doesn't screws up reversible textures (like sculpties) as YCC is not reversible but YUV is...
- set_default_colour_weights(codestream.access_siz());
- }
-
- // Set codestream options
- int nb_layers = 0;
- kdu_long layer_bytes[MAX_NB_LAYERS];
- U32 max_bytes = (U32)(base.getWidth() * base.getHeight() * base.getComponents());
-
- // Rate is the argument passed into the LLImageJ2C which specifies the target compression rate. The default is 8:1.
- // *TODO: mRate is actually always 8:1 in the viewer. Test different values.
- llassert (base.mRate > 0.f);
- max_bytes = (U32)((F32)(max_bytes) * base.mRate);
-
- // This code is where we specify the target number of bytes for each quality layer.
- // We're using a logarithmic spacing rule that fits with our way of fetching texture data.
- // Note: For more info on this layers business, read kdu_codestream::flush() doc in kdu_compressed.h
- layer_bytes[nb_layers++] = FIRST_PACKET_SIZE;
- U32 i = MIN_LAYER_SIZE;
- while ((i < max_bytes) && (nb_layers < (MAX_NB_LAYERS-1)))
- {
- layer_bytes[nb_layers++] = i;
- i *= 4;
- }
- // Note: for small images, we can have (max_bytes < FIRST_PACKET_SIZE), hence the test
- if (layer_bytes[nb_layers-1] < max_bytes)
- {
- // Set the last quality layer so to fit the preset compression ratio
- layer_bytes[nb_layers++] = max_bytes;
- }
-
- if (reversible)
- {
- // Use 0 for a last quality layer for reversible images so all remaining code blocks will be flushed
- // Hack: KDU encoding for reversible images has a bug for small images that leads to j2c images that
- // cannot be open or are very blurry. Avoiding that last layer prevents the problem to happen.
- if ((base.getWidth() >= 32) || (base.getHeight() >= 32))
- {
- layer_bytes[nb_layers++] = 0;
- }
- codestream.access_siz()->parse_string("Creversible=yes");
- // *TODO: we should use yuv in reversible mode
- // Don't turn this on now though as it creates problems on decoding for the moment
- //codestream.access_siz()->parse_string("Cycc=no");
- }
-
- std::string layer_string = llformat("Clayers=%d",nb_layers);
- codestream.access_siz()->parse_string(layer_string.c_str());
-
- // Set up data ordering, markers, etc... if precincts or blocks specified
- if ((mBlocksSize != -1) || (mPrecinctsSize != -1))
- {
- if (mPrecinctsSize != -1)
- {
- std::string precincts_string = llformat("Cprecincts={%d,%d}",mPrecinctsSize,mPrecinctsSize);
- codestream.access_siz()->parse_string(precincts_string.c_str());
- }
- if (mBlocksSize != -1)
- {
- std::string blocks_string = llformat("Cblk={%d,%d}",mBlocksSize,mBlocksSize);
- codestream.access_siz()->parse_string(blocks_string.c_str());
- }
- std::string ordering_string = llformat("Corder=LRCP");
- codestream.access_siz()->parse_string(ordering_string.c_str());
- std::string PLT_string = llformat("ORGgen_plt=yes");
- codestream.access_siz()->parse_string(PLT_string.c_str());
- std::string Parts_string = llformat("ORGtparts=R");
- codestream.access_siz()->parse_string(Parts_string.c_str());
- }
-
- // Set the number of wavelets subresolutions (aka levels)
- if (mLevels != 0)
- {
- std::string levels_string = llformat("Clevels=%d",mLevels);
- codestream.access_siz()->parse_string(levels_string.c_str());
- }
-
- // Complete the encode settings
- codestream.access_siz()->finalize_all();
- codestream.change_appearance(transpose,vflip,hflip);
-
- // Now we are ready for sample data processing
- kdc_flow_control *tile = new kdc_flow_control(&mem_in,codestream);
- bool done = false;
- while (!done)
- {
- // Process line by line
- if (tile->advance_components())
- {
- tile->process_components();
- }
- else
- {
- done = true;
- }
- }
-
- // Produce the compressed output
- codestream.flush(layer_bytes,nb_layers);
-
- // Cleanup
- delete tile;
- codestream.destroy();
-
- // Now that we're done encoding, create the new data buffer for the compressed
- // image and stick it there.
- base.copyData(output_buffer, output_size);
- base.updateData(); // set width, height
- delete[] output_buffer;
- }
- catch(const KDUError& msg)
- {
- base.setLastError(msg.what());
- return false;
- }
- catch (kdu_exception kdu_value)
- {
- // KDU internally throws kdu_exception. It's possible that such an
- // exception might leak out into our code. Catch kdu_exception
- // specially because boost::current_exception_diagnostic_information()
- // could do nothing with it.
- base.setLastError(report_kdu_exception(kdu_value));
- return false;
- }
- catch( ... )
- {
- base.setLastError("Unknown J2C error: " +
- boost::current_exception_diagnostic_information());
- return false;
- }
-
- return true;
+ // Declare and set simple arguments
+ bool transpose = false;
+ bool vflip = true;
+ bool hflip = false;
+
+ try
+ {
+ // Set up input image files
+ siz_params siz;
+
+ // Should set rate someplace here
+ LLKDUMemIn mem_in(raw_image.getData(),
+ raw_image.getDataSize(),
+ raw_image.getWidth(),
+ raw_image.getHeight(),
+ raw_image.getComponents(),
+ &siz);
+
+ base.setSize(raw_image.getWidth(), raw_image.getHeight(), raw_image.getComponents());
+
+ int num_components = raw_image.getComponents();
+
+ siz.set(Scomponents,0,0,num_components);
+ siz.set(Sdims,0,0,base.getHeight()); // Height of first image component
+ siz.set(Sdims,0,1,base.getWidth()); // Width of first image component
+ siz.set(Sprecision,0,0,8); // Image samples have original bit-depth of 8
+ siz.set(Ssigned,0,0,false); // Image samples are originally unsigned
+
+ kdu_params *siz_ref = &siz;
+ siz_ref->finalize();
+ siz_params transformed_siz; // Use this one to construct code-stream
+ transformed_siz.copy_from(&siz,-1,-1,-1,0,transpose,false,false);
+
+ // Construct the `kdu_codestream' object and parse all remaining arguments
+ U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents();
+ max_output_size = (max_output_size < 1000 ? 1000 : max_output_size);
+ U8 *output_buffer = new U8[max_output_size];
+ U32 output_size = 0; // Address updated by LLKDUMemTarget to give the final compressed buffer size
+ LLKDUMemTarget output(output_buffer, output_size, max_output_size);
+
+ kdu_codestream codestream;
+ codestream.create(&transformed_siz,&output);
+
+ if (comment_text)
+ {
+ // Set the comments for the codestream
+ kdu_codestream_comment comment = codestream.add_comment();
+ comment.put_text(comment_text);
+ }
+
+ if (num_components >= 3)
+ {
+ // Note that we always use YCC and not YUV
+ // *TODO: Verify this doesn't screws up reversible textures (like sculpties) as YCC is not reversible but YUV is...
+ set_default_colour_weights(codestream.access_siz());
+ }
+
+ // Set codestream options
+ int nb_layers = 0;
+ kdu_long layer_bytes[MAX_NB_LAYERS];
+ U32 max_bytes = (U32)(base.getWidth() * base.getHeight() * base.getComponents());
+
+ // Rate is the argument passed into the LLImageJ2C which specifies the target compression rate. The default is 8:1.
+ // *TODO: mRate is actually always 8:1 in the viewer. Test different values.
+ llassert (base.mRate > 0.f);
+ max_bytes = (U32)((F32)(max_bytes) * base.mRate);
+
+ // This code is where we specify the target number of bytes for each quality layer.
+ // We're using a logarithmic spacing rule that fits with our way of fetching texture data.
+ // Note: For more info on this layers business, read kdu_codestream::flush() doc in kdu_compressed.h
+ layer_bytes[nb_layers++] = FIRST_PACKET_SIZE;
+ U32 i = MIN_LAYER_SIZE;
+ while ((i < max_bytes) && (nb_layers < (MAX_NB_LAYERS-1)))
+ {
+ layer_bytes[nb_layers++] = i;
+ i *= 4;
+ }
+ // Note: for small images, we can have (max_bytes < FIRST_PACKET_SIZE), hence the test
+ if (layer_bytes[nb_layers-1] < max_bytes)
+ {
+ // Set the last quality layer so to fit the preset compression ratio
+ layer_bytes[nb_layers++] = max_bytes;
+ }
+
+ if (reversible)
+ {
+ // Use 0 for a last quality layer for reversible images so all remaining code blocks will be flushed
+ // Hack: KDU encoding for reversible images has a bug for small images that leads to j2c images that
+ // cannot be open or are very blurry. Avoiding that last layer prevents the problem to happen.
+ if ((base.getWidth() >= 32) || (base.getHeight() >= 32))
+ {
+ layer_bytes[nb_layers++] = 0;
+ }
+ codestream.access_siz()->parse_string("Creversible=yes");
+ // *TODO: we should use yuv in reversible mode
+ // Don't turn this on now though as it creates problems on decoding for the moment
+ //codestream.access_siz()->parse_string("Cycc=no");
+ }
+
+ std::string layer_string = llformat("Clayers=%d",nb_layers);
+ codestream.access_siz()->parse_string(layer_string.c_str());
+
+ // Set up data ordering, markers, etc... if precincts or blocks specified
+ if ((mBlocksSize != -1) || (mPrecinctsSize != -1))
+ {
+ if (mPrecinctsSize != -1)
+ {
+ std::string precincts_string = llformat("Cprecincts={%d,%d}",mPrecinctsSize,mPrecinctsSize);
+ codestream.access_siz()->parse_string(precincts_string.c_str());
+ }
+ if (mBlocksSize != -1)
+ {
+ std::string blocks_string = llformat("Cblk={%d,%d}",mBlocksSize,mBlocksSize);
+ codestream.access_siz()->parse_string(blocks_string.c_str());
+ }
+ std::string ordering_string = llformat("Corder=LRCP");
+ codestream.access_siz()->parse_string(ordering_string.c_str());
+ std::string PLT_string = llformat("ORGgen_plt=yes");
+ codestream.access_siz()->parse_string(PLT_string.c_str());
+ std::string Parts_string = llformat("ORGtparts=R");
+ codestream.access_siz()->parse_string(Parts_string.c_str());
+ }
+
+ // Set the number of wavelets subresolutions (aka levels)
+ if (mLevels != 0)
+ {
+ std::string levels_string = llformat("Clevels=%d",mLevels);
+ codestream.access_siz()->parse_string(levels_string.c_str());
+ }
+
+ // Complete the encode settings
+ codestream.access_siz()->finalize_all();
+ codestream.change_appearance(transpose,vflip,hflip);
+
+ // Now we are ready for sample data processing
+ kdc_flow_control *tile = new kdc_flow_control(&mem_in,codestream);
+ bool done = false;
+ while (!done)
+ {
+ // Process line by line
+ if (tile->advance_components())
+ {
+ tile->process_components();
+ }
+ else
+ {
+ done = true;
+ }
+ }
+
+ // Produce the compressed output
+ codestream.flush(layer_bytes,nb_layers);
+
+ // Cleanup
+ delete tile;
+ codestream.destroy();
+
+ // Now that we're done encoding, create the new data buffer for the compressed
+ // image and stick it there.
+ base.copyData(output_buffer, output_size);
+ base.updateData(); // set width, height
+ delete[] output_buffer;
+ }
+ catch(const KDUError& msg)
+ {
+ base.setLastError(msg.what());
+ return false;
+ }
+ catch (kdu_exception kdu_value)
+ {
+ // KDU internally throws kdu_exception. It's possible that such an
+ // exception might leak out into our code. Catch kdu_exception
+ // specially because boost::current_exception_diagnostic_information()
+ // could do nothing with it.
+ base.setLastError(report_kdu_exception(kdu_value));
+ return false;
+ }
+ catch( ... )
+ {
+ base.setLastError("Unknown J2C error: " +
+ boost::current_exception_diagnostic_information());
+ return false;
+ }
+
+ return true;
}
bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
{
- // *FIX: kdu calls our callback function if there's an error, and
- // then bombs. To regain control, we throw an exception, and
- // catch it here.
- try
- {
- setupCodeStream(base, false, MODE_FAST);
- return true;
- }
- catch (const KDUError& msg)
- {
- base.setLastError(msg.what());
- return false;
- }
- catch (kdu_exception kdu_value)
- {
- // KDU internally throws kdu_exception. It's possible that such an
- // exception might leak out into our code. Catch kdu_exception
- // specially because boost::current_exception_diagnostic_information()
- // could do nothing with it.
- base.setLastError(report_kdu_exception(kdu_value));
- return false;
- }
- catch (...)
- {
- base.setLastError("Unknown J2C error: " +
- boost::current_exception_diagnostic_information());
- return false;
- }
+ // *FIX: kdu calls our callback function if there's an error, and
+ // then bombs. To regain control, we throw an exception, and
+ // catch it here.
+ try
+ {
+ setupCodeStream(base, false, MODE_FAST);
+ return true;
+ }
+ catch (const KDUError& msg)
+ {
+ base.setLastError(msg.what());
+ return false;
+ }
+ catch (kdu_exception kdu_value)
+ {
+ // KDU internally throws kdu_exception. It's possible that such an
+ // exception might leak out into our code. Catch kdu_exception
+ // specially because boost::current_exception_diagnostic_information()
+ // could do nothing with it.
+ base.setLastError(report_kdu_exception(kdu_value));
+ return false;
+ }
+ catch (...)
+ {
+ base.setLastError("Unknown J2C error: " +
+ boost::current_exception_diagnostic_information());
+ return false;
+ }
}
/*****************************************************************************/
@@ -860,31 +860,31 @@ bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
// Only called by copy_tile(), which is itself commented out
static void copy_block(kdu_block *in, kdu_block *out)
{
- if (in->K_max_prime != out->K_max_prime)
- {
- std::cout << "Cannot copy blocks belonging to subbands with different quantization parameters." << std::endl;
- return;
- }
- if ((in->size.x != out->size.x) || (in->size.y != out->size.y))
- {
- std::cout << "Cannot copy code-blocks with different dimensions." << std::endl;
- return;
- }
- out->missing_msbs = in->missing_msbs;
- if (out->max_passes < (in->num_passes+2)) // Gives us enough to round up
- out->set_max_passes(in->num_passes+2,false); // to the next whole bit-plane
- out->num_passes = in->num_passes;
- int num_bytes = 0;
- for (int z=0; z < in->num_passes; z++)
+ if (in->K_max_prime != out->K_max_prime)
+ {
+ std::cout << "Cannot copy blocks belonging to subbands with different quantization parameters." << std::endl;
+ return;
+ }
+ if ((in->size.x != out->size.x) || (in->size.y != out->size.y))
+ {
+ std::cout << "Cannot copy code-blocks with different dimensions." << std::endl;
+ return;
+ }
+ out->missing_msbs = in->missing_msbs;
+ if (out->max_passes < (in->num_passes+2)) // Gives us enough to round up
+ out->set_max_passes(in->num_passes+2,false); // to the next whole bit-plane
+ out->num_passes = in->num_passes;
+ int num_bytes = 0;
+ for (int z=0; z < in->num_passes; z++)
{
- num_bytes += (out->pass_lengths[z] = in->pass_lengths[z]);
- out->pass_slopes[z] = in->pass_slopes[z];
+ num_bytes += (out->pass_lengths[z] = in->pass_lengths[z]);
+ out->pass_slopes[z] = in->pass_slopes[z];
}
-
+
// Just copy compressed code-bytes. Block transcoding not supported.
- if (out->max_bytes < num_bytes)
- out->set_max_bytes(num_bytes,false);
- memcpy(out->byte_buffer,in->byte_buffer,(size_t) num_bytes);
+ if (out->max_bytes < num_bytes)
+ out->set_max_bytes(num_bytes,false);
+ memcpy(out->byte_buffer,in->byte_buffer,(size_t) num_bytes);
}
|*==========================================================================*/
@@ -896,56 +896,56 @@ static void copy_block(kdu_block *in, kdu_block *out)
// Only called by findDiscardLevelsBoundaries(), which is itself commented out
static void
copy_tile(kdu_tile tile_in, kdu_tile tile_out, int tnum_in, int tnum_out,
- kdu_params *siz_in, kdu_params *siz_out, int skip_components,
- int &num_blocks)
+ kdu_params *siz_in, kdu_params *siz_out, int skip_components,
+ int &num_blocks)
{
- int num_components = tile_out.get_num_components();
- int new_tpart=0, next_tpart = 1;
-
- for (int c=0; c < num_components; c++)
+ int num_components = tile_out.get_num_components();
+ int new_tpart=0, next_tpart = 1;
+
+ for (int c=0; c < num_components; c++)
{
- kdu_tile_comp comp_in, comp_out;
- comp_in = tile_in.access_component(c);
- comp_out = tile_out.access_component(c);
- int num_resolutions = comp_out.get_num_resolutions();
- //std::cout << " Copying tile : num_resolutions = " << num_resolutions << std::endl;
- for (int r=0; r < num_resolutions; r++)
+ kdu_tile_comp comp_in, comp_out;
+ comp_in = tile_in.access_component(c);
+ comp_out = tile_out.access_component(c);
+ int num_resolutions = comp_out.get_num_resolutions();
+ //std::cout << " Copying tile : num_resolutions = " << num_resolutions << std::endl;
+ for (int r=0; r < num_resolutions; r++)
{
- kdu_resolution res_in; res_in = comp_in.access_resolution(r);
- kdu_resolution res_out; res_out = comp_out.access_resolution(r);
- int b, min_band;
- int num_bands = res_in.get_valid_band_indices(min_band);
- std::cout << " Copying tile : num_bands = " << num_bands << std::endl;
- for (b=min_band; num_bands > 0; num_bands--, b++)
+ kdu_resolution res_in; res_in = comp_in.access_resolution(r);
+ kdu_resolution res_out; res_out = comp_out.access_resolution(r);
+ int b, min_band;
+ int num_bands = res_in.get_valid_band_indices(min_band);
+ std::cout << " Copying tile : num_bands = " << num_bands << std::endl;
+ for (b=min_band; num_bands > 0; num_bands--, b++)
{
- kdu_subband band_in; band_in = res_in.access_subband(b);
- kdu_subband band_out; band_out = res_out.access_subband(b);
- kdu_dims blocks_in; band_in.get_valid_blocks(blocks_in);
- kdu_dims blocks_out; band_out.get_valid_blocks(blocks_out);
- if ((blocks_in.size.x != blocks_out.size.x) ||
- (blocks_in.size.y != blocks_out.size.y))
- {
- std::cout << "Transcoding operation cannot proceed: Code-block partitions for the input and output code-streams do not agree." << std::endl;
- return;
- }
- kdu_coords idx;
- //std::cout << " Copying tile : block indices, x = " << blocks_out.size.x << " and y = " << blocks_out.size.y << std::endl;
- for (idx.y=0; idx.y < blocks_out.size.y; idx.y++)
- {
- for (idx.x=0; idx.x < blocks_out.size.x; idx.x++)
- {
- kdu_block *in =
- band_in.open_block(idx+blocks_in.pos,&new_tpart);
- for (; next_tpart <= new_tpart; next_tpart++)
- siz_out->copy_from(siz_in,tnum_in,tnum_out,next_tpart,
- skip_components);
- kdu_block *out = band_out.open_block(idx+blocks_out.pos);
- copy_block(in,out);
- band_in.close_block(in);
- band_out.close_block(out);
- num_blocks++;
- }
- }
+ kdu_subband band_in; band_in = res_in.access_subband(b);
+ kdu_subband band_out; band_out = res_out.access_subband(b);
+ kdu_dims blocks_in; band_in.get_valid_blocks(blocks_in);
+ kdu_dims blocks_out; band_out.get_valid_blocks(blocks_out);
+ if ((blocks_in.size.x != blocks_out.size.x) ||
+ (blocks_in.size.y != blocks_out.size.y))
+ {
+ std::cout << "Transcoding operation cannot proceed: Code-block partitions for the input and output code-streams do not agree." << std::endl;
+ return;
+ }
+ kdu_coords idx;
+ //std::cout << " Copying tile : block indices, x = " << blocks_out.size.x << " and y = " << blocks_out.size.y << std::endl;
+ for (idx.y=0; idx.y < blocks_out.size.y; idx.y++)
+ {
+ for (idx.x=0; idx.x < blocks_out.size.x; idx.x++)
+ {
+ kdu_block *in =
+ band_in.open_block(idx+blocks_in.pos,&new_tpart);
+ for (; next_tpart <= new_tpart; next_tpart++)
+ siz_out->copy_from(siz_in,tnum_in,tnum_out,next_tpart,
+ skip_components);
+ kdu_block *out = band_out.open_block(idx+blocks_out.pos);
+ copy_block(in,out);
+ band_in.close_block(in);
+ band_out.close_block(out);
+ num_blocks++;
+ }
+ }
}
}
}
@@ -959,174 +959,174 @@ copy_tile(kdu_tile tile_in, kdu_tile tile_out, int tnum_in, int tnum_out,
// See comments in header file for why this is commented out.
void LLImageJ2CKDU::findDiscardLevelsBoundaries(LLImageJ2C &base)
{
- // We need the number of levels in that image before starting.
- getMetadata(base);
-
- for (int discard_level = 0; discard_level < mLevels; discard_level++)
- {
- //std::cout << "Parsing discard level = " << discard_level << std::endl;
- // Create the input codestream object.
- setupCodeStream(base, true, MODE_FAST);
- mCodeStreamp->apply_input_restrictions(0, 4, discard_level, 0, NULL);
- mCodeStreamp->set_max_bytes(KDU_LONG_MAX,true);
- siz_params *siz_in = mCodeStreamp->access_siz();
-
- // Create the output codestream object.
- siz_params siz;
- siz.copy_from(siz_in,-1,-1,-1,0,discard_level,false,false,false);
- siz.set(Scomponents,0,0,mCodeStreamp->get_num_components());
-
- U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents();
- max_output_size = (max_output_size < 1000 ? 1000 : max_output_size);
- U8 *output_buffer = new U8[max_output_size];
- U32 output_size = 0; // Address updated by LLKDUMemTarget to give the final compressed buffer size
- LLKDUMemTarget output(output_buffer, output_size, max_output_size);
- kdu_codestream codestream_out;
- codestream_out.create(&siz,&output);
- //codestream_out.share_buffering(*mCodeStreamp);
- siz_params *siz_out = codestream_out.access_siz();
- siz_out->copy_from(siz_in,-1,-1,-1,0,discard_level,false,false,false);
- codestream_out.access_siz()->finalize_all(-1);
-
- // Set up rate control variables
- kdu_long max_bytes = KDU_LONG_MAX;
- kdu_params *cod = siz_out->access_cluster(COD_params);
- int total_layers; cod->get(Clayers,0,0,total_layers);
- kdu_long *layer_bytes = new kdu_long[total_layers];
- int nel, non_empty_layers = 0;
-
- // Now ready to perform the transfer of compressed data between streams
- int flush_counter = INT_MAX;
- kdu_dims tile_indices_in;
- mCodeStreamp->get_valid_tiles(tile_indices_in);
- kdu_dims tile_indices_out;
- codestream_out.get_valid_tiles(tile_indices_out);
- assert((tile_indices_in.size.x == tile_indices_out.size.x) &&
- (tile_indices_in.size.y == tile_indices_out.size.y));
- int num_blocks=0;
-
- kdu_coords idx;
- //std::cout << "Parsing tiles : x = " << tile_indices_out.size.x << " to y = " << tile_indices_out.size.y << std::endl;
- for (idx.y=0; idx.y < tile_indices_out.size.y; idx.y++)
- {
- for (idx.x=0; idx.x < tile_indices_out.size.x; idx.x++)
- {
- kdu_tile tile_in = mCodeStreamp->open_tile(idx+tile_indices_in.pos);
- int tnum_in = tile_in.get_tnum();
- int tnum_out = idx.x + idx.y*tile_indices_out.size.x;
- siz_out->copy_from(siz_in,tnum_in,tnum_out,0,0,discard_level,false,false,false);
- siz_out->finalize_all(tnum_out);
- // Note: do not open the output tile without first copying any tile-specific code-stream parameters
- kdu_tile tile_out = codestream_out.open_tile(idx+tile_indices_out.pos);
- assert(tnum_out == tile_out.get_tnum());
- copy_tile(tile_in,tile_out,tnum_in,tnum_out,siz_in,siz_out,0,num_blocks);
- tile_in.close();
- tile_out.close();
- flush_counter--;
- if ((flush_counter <= 0) && codestream_out.ready_for_flush())
- {
- flush_counter = INT_MAX;
- nel = codestream_out.trans_out(max_bytes,layer_bytes,total_layers);
- non_empty_layers = (nel > non_empty_layers)?nel:non_empty_layers;
- }
- }
- }
-
- // Generate the output code-stream
- if (codestream_out.ready_for_flush())
- {
- nel = codestream_out.trans_out(max_bytes,layer_bytes,total_layers);
- non_empty_layers = (nel > non_empty_layers)?nel:non_empty_layers;
- }
- if (non_empty_layers > total_layers)
- non_empty_layers = total_layers; // Can happen if a tile has more layers
-
- // Print out stats
- std::cout << "Code stream parsing for discard level = " << discard_level << std::endl;
- std::cout << " Total compressed memory in = " << mCodeStreamp->get_compressed_data_memory() << " bytes" << std::endl;
- std::cout << " Total compressed memory out = " << codestream_out.get_compressed_data_memory() << " bytes" << std::endl;
- //std::cout << " Output contains " << total_layers << " quality layers" << std::endl;
- std::cout << " Transferred " << num_blocks << " code-blocks from in to out" << std::endl;
- //std::cout << " Read " << mCodeStreamp->get_num_tparts() << " tile-part(s) from a total of " << (int) tile_indices_in.area() << " tile(s)" << std::endl;
- std::cout << " Total bytes read = " << mCodeStreamp->get_total_bytes() << std::endl;
- //std::cout << " Wrote " << codestream_out.get_num_tparts() << " tile-part(s) in a total of " << (int) tile_indices_out.area() << " tile(s)" << std::endl;
- std::cout << " Total bytes written = " << codestream_out.get_total_bytes() << std::endl;
- std::cout << "-------------" << std::endl;
-
- // Clean-up
- cleanupCodeStream();
- codestream_out.destroy();
- delete[] output_buffer;
- }
- return;
+ // We need the number of levels in that image before starting.
+ getMetadata(base);
+
+ for (int discard_level = 0; discard_level < mLevels; discard_level++)
+ {
+ //std::cout << "Parsing discard level = " << discard_level << std::endl;
+ // Create the input codestream object.
+ setupCodeStream(base, true, MODE_FAST);
+ mCodeStreamp->apply_input_restrictions(0, 4, discard_level, 0, NULL);
+ mCodeStreamp->set_max_bytes(KDU_LONG_MAX,true);
+ siz_params *siz_in = mCodeStreamp->access_siz();
+
+ // Create the output codestream object.
+ siz_params siz;
+ siz.copy_from(siz_in,-1,-1,-1,0,discard_level,false,false,false);
+ siz.set(Scomponents,0,0,mCodeStreamp->get_num_components());
+
+ U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents();
+ max_output_size = (max_output_size < 1000 ? 1000 : max_output_size);
+ U8 *output_buffer = new U8[max_output_size];
+ U32 output_size = 0; // Address updated by LLKDUMemTarget to give the final compressed buffer size
+ LLKDUMemTarget output(output_buffer, output_size, max_output_size);
+ kdu_codestream codestream_out;
+ codestream_out.create(&siz,&output);
+ //codestream_out.share_buffering(*mCodeStreamp);
+ siz_params *siz_out = codestream_out.access_siz();
+ siz_out->copy_from(siz_in,-1,-1,-1,0,discard_level,false,false,false);
+ codestream_out.access_siz()->finalize_all(-1);
+
+ // Set up rate control variables
+ kdu_long max_bytes = KDU_LONG_MAX;
+ kdu_params *cod = siz_out->access_cluster(COD_params);
+ int total_layers; cod->get(Clayers,0,0,total_layers);
+ kdu_long *layer_bytes = new kdu_long[total_layers];
+ int nel, non_empty_layers = 0;
+
+ // Now ready to perform the transfer of compressed data between streams
+ int flush_counter = INT_MAX;
+ kdu_dims tile_indices_in;
+ mCodeStreamp->get_valid_tiles(tile_indices_in);
+ kdu_dims tile_indices_out;
+ codestream_out.get_valid_tiles(tile_indices_out);
+ assert((tile_indices_in.size.x == tile_indices_out.size.x) &&
+ (tile_indices_in.size.y == tile_indices_out.size.y));
+ int num_blocks=0;
+
+ kdu_coords idx;
+ //std::cout << "Parsing tiles : x = " << tile_indices_out.size.x << " to y = " << tile_indices_out.size.y << std::endl;
+ for (idx.y=0; idx.y < tile_indices_out.size.y; idx.y++)
+ {
+ for (idx.x=0; idx.x < tile_indices_out.size.x; idx.x++)
+ {
+ kdu_tile tile_in = mCodeStreamp->open_tile(idx+tile_indices_in.pos);
+ int tnum_in = tile_in.get_tnum();
+ int tnum_out = idx.x + idx.y*tile_indices_out.size.x;
+ siz_out->copy_from(siz_in,tnum_in,tnum_out,0,0,discard_level,false,false,false);
+ siz_out->finalize_all(tnum_out);
+ // Note: do not open the output tile without first copying any tile-specific code-stream parameters
+ kdu_tile tile_out = codestream_out.open_tile(idx+tile_indices_out.pos);
+ assert(tnum_out == tile_out.get_tnum());
+ copy_tile(tile_in,tile_out,tnum_in,tnum_out,siz_in,siz_out,0,num_blocks);
+ tile_in.close();
+ tile_out.close();
+ flush_counter--;
+ if ((flush_counter <= 0) && codestream_out.ready_for_flush())
+ {
+ flush_counter = INT_MAX;
+ nel = codestream_out.trans_out(max_bytes,layer_bytes,total_layers);
+ non_empty_layers = (nel > non_empty_layers)?nel:non_empty_layers;
+ }
+ }
+ }
+
+ // Generate the output code-stream
+ if (codestream_out.ready_for_flush())
+ {
+ nel = codestream_out.trans_out(max_bytes,layer_bytes,total_layers);
+ non_empty_layers = (nel > non_empty_layers)?nel:non_empty_layers;
+ }
+ if (non_empty_layers > total_layers)
+ non_empty_layers = total_layers; // Can happen if a tile has more layers
+
+ // Print out stats
+ std::cout << "Code stream parsing for discard level = " << discard_level << std::endl;
+ std::cout << " Total compressed memory in = " << mCodeStreamp->get_compressed_data_memory() << " bytes" << std::endl;
+ std::cout << " Total compressed memory out = " << codestream_out.get_compressed_data_memory() << " bytes" << std::endl;
+ //std::cout << " Output contains " << total_layers << " quality layers" << std::endl;
+ std::cout << " Transferred " << num_blocks << " code-blocks from in to out" << std::endl;
+ //std::cout << " Read " << mCodeStreamp->get_num_tparts() << " tile-part(s) from a total of " << (int) tile_indices_in.area() << " tile(s)" << std::endl;
+ std::cout << " Total bytes read = " << mCodeStreamp->get_total_bytes() << std::endl;
+ //std::cout << " Wrote " << codestream_out.get_num_tparts() << " tile-part(s) in a total of " << (int) tile_indices_out.area() << " tile(s)" << std::endl;
+ std::cout << " Total bytes written = " << codestream_out.get_total_bytes() << std::endl;
+ std::cout << "-------------" << std::endl;
+
+ // Clean-up
+ cleanupCodeStream();
+ codestream_out.destroy();
+ delete[] output_buffer;
+ }
+ return;
}
|*==========================================================================*/
void set_default_colour_weights(kdu_params *siz)
{
- kdu_params *cod = siz->access_cluster(COD_params);
- assert(cod != NULL);
-
- bool can_use_ycc = true;
- bool rev0 = false;
- int depth0 = 0, sub_x0 = 1, sub_y0 = 1;
- for (int c = 0; c < 3; c++)
- {
- int depth = 0; siz->get(Sprecision,c,0,depth);
- int sub_y = 1; siz->get(Ssampling,c,0,sub_y);
- int sub_x = 1; siz->get(Ssampling,c,1,sub_x);
- kdu_params *coc = cod->access_relation(-1,c);
- bool rev = false; coc->get(Creversible,0,0,rev);
- if (c == 0)
- {
- rev0 = rev; depth0 = depth; sub_x0 = sub_x; sub_y0 = sub_y;
- }
- else if ((rev != rev0) || (depth != depth0) ||
- (sub_x != sub_x0) || (sub_y != sub_y0))
- {
- can_use_ycc = false;
- }
- }
- if (!can_use_ycc)
- {
- return;
- }
-
- bool use_ycc;
- if (!cod->get(Cycc,0,0,use_ycc))
- {
- cod->set(Cycc,0,0,use_ycc=true);
- }
- if (!use_ycc)
- {
- return;
- }
- float weight;
- if (cod->get(Clev_weights,0,0,weight) || cod->get(Cband_weights,0,0,weight))
- {
- // Weights already specified explicitly -> nothing to do
- return;
- }
-
- // These example weights are adapted from numbers generated by Marcus Nadenau
- // at EPFL, for a viewing distance of 15 cm and a display resolution of
- // 300 DPI.
-
- cod->parse_string("Cband_weights:C0="
- "{0.0901},{0.2758},{0.2758},"
- "{0.7018},{0.8378},{0.8378},{1}");
- cod->parse_string("Cband_weights:C1="
- "{0.0263},{0.0863},{0.0863},"
- "{0.1362},{0.2564},{0.2564},"
- "{0.3346},{0.4691},{0.4691},"
- "{0.5444},{0.6523},{0.6523},"
- "{0.7078},{0.7797},{0.7797},{1}");
- cod->parse_string("Cband_weights:C2="
- "{0.0773},{0.1835},{0.1835},"
- "{0.2598},{0.4130},{0.4130},"
- "{0.5040},{0.6464},{0.6464},"
- "{0.7220},{0.8254},{0.8254},"
- "{0.8769},{0.9424},{0.9424},{1}");
+ kdu_params *cod = siz->access_cluster(COD_params);
+ assert(cod != NULL);
+
+ bool can_use_ycc = true;
+ bool rev0 = false;
+ int depth0 = 0, sub_x0 = 1, sub_y0 = 1;
+ for (int c = 0; c < 3; c++)
+ {
+ int depth = 0; siz->get(Sprecision,c,0,depth);
+ int sub_y = 1; siz->get(Ssampling,c,0,sub_y);
+ int sub_x = 1; siz->get(Ssampling,c,1,sub_x);
+ kdu_params *coc = cod->access_relation(-1,c);
+ bool rev = false; coc->get(Creversible,0,0,rev);
+ if (c == 0)
+ {
+ rev0 = rev; depth0 = depth; sub_x0 = sub_x; sub_y0 = sub_y;
+ }
+ else if ((rev != rev0) || (depth != depth0) ||
+ (sub_x != sub_x0) || (sub_y != sub_y0))
+ {
+ can_use_ycc = false;
+ }
+ }
+ if (!can_use_ycc)
+ {
+ return;
+ }
+
+ bool use_ycc;
+ if (!cod->get(Cycc,0,0,use_ycc))
+ {
+ cod->set(Cycc,0,0,use_ycc=true);
+ }
+ if (!use_ycc)
+ {
+ return;
+ }
+ float weight;
+ if (cod->get(Clev_weights,0,0,weight) || cod->get(Cband_weights,0,0,weight))
+ {
+ // Weights already specified explicitly -> nothing to do
+ return;
+ }
+
+ // These example weights are adapted from numbers generated by Marcus Nadenau
+ // at EPFL, for a viewing distance of 15 cm and a display resolution of
+ // 300 DPI.
+
+ cod->parse_string("Cband_weights:C0="
+ "{0.0901},{0.2758},{0.2758},"
+ "{0.7018},{0.8378},{0.8378},{1}");
+ cod->parse_string("Cband_weights:C1="
+ "{0.0263},{0.0863},{0.0863},"
+ "{0.1362},{0.2564},{0.2564},"
+ "{0.3346},{0.4691},{0.4691},"
+ "{0.5444},{0.6523},{0.6523},"
+ "{0.7078},{0.7797},{0.7797},{1}");
+ cod->parse_string("Cband_weights:C2="
+ "{0.0773},{0.1835},{0.1835},"
+ "{0.2598},{0.4130},{0.4130},"
+ "{0.5040},{0.6464},{0.6464},"
+ "{0.7220},{0.8254},{0.8254},"
+ "{0.8769},{0.9424},{0.9424},{1}");
}
/******************************************************************************/
@@ -1139,192 +1139,192 @@ byte buffer, spacing successive output samples apart by `gap' bytes
(to allow for interleaving of colour components). The function performs
all necessary level shifting, type conversion, rounding and truncation. */
{
- int width = src.get_width();
- if (src.get_buf32() != NULL)
- { // Decompressed samples have a 32-bit representation (integer or float)
- assert(precision >= 8); // Else would have used 16 bit representation
- kdu_sample32 *sp = src.get_buf32();
- if (!src.is_absolute())
- { // Transferring normalized floating point data.
- float scale16 = (float)(1<<16);
- kdu_int32 val;
-
- for (; width > 0; width--, sp++, dest+=gap)
- {
- val = (kdu_int32)(sp->fval*scale16);
- val = (val+128)>>8; // May be faster than true rounding
- val += 128;
- if (val & ((0xffffffffU)<<8))
- {
- val = (val < 0 ? 0 : 255);
- }
- *dest = (kdu_byte) val;
- }
- }
- else
- { // Transferring 32-bit absolute integers.
- kdu_int32 val;
- kdu_int32 downshift = precision-8;
- kdu_int32 offset = (1<<downshift)>>1;
-
- for (; width > 0; width--, sp++, dest+=gap)
- {
- val = sp->ival;
- val = (val+offset)>>downshift;
- val += 128;
- if (val & ((0xffffffffU)<<8))
- {
- val = (val < 0 ? 0 : 255);
- }
- *dest = (kdu_byte) val;
- }
- }
- }
- else
- { // Source data is 16 bits.
- kdu_sample16 *sp = src.get_buf16();
- if (!src.is_absolute())
- { // Transferring 16-bit fixed point quantities
- kdu_int16 val;
-
- if (precision >= 8)
- { // Can essentially ignore the bit-depth.
- for (; width > 0; width--, sp++, dest+=gap)
- {
- val = sp->ival;
- val += (1<<(KDU_FIX_POINT-8))>>1;
- val >>= (KDU_FIX_POINT-8);
- val += 128;
- if (val & ((0xffffffffU)<<8))
- {
- val = (val < 0 ? 0 : 255);
- }
- *dest = (kdu_byte) val;
- }
- }
- else
- { // Need to force zeros into one or more least significant bits.
- kdu_int16 downshift = KDU_FIX_POINT-precision;
- kdu_int16 upshift = 8-precision;
- kdu_int16 offset = 1<<(downshift-1);
-
- for (; width > 0; width--, sp++, dest+=gap)
- {
- val = sp->ival;
- val = (val+offset)>>downshift;
- val <<= upshift;
- val += 128;
- if (val & ((0xffffffffU)<<8))
- {
- val = (val < 0 ? 0 : 256 - (1<<upshift));
- }
- *dest = (kdu_byte) val;
- }
- }
- }
- else
- { // Transferring 16-bit absolute integers.
- kdu_int16 val;
-
- if (precision >= 8)
- {
- kdu_int16 downshift = precision-8;
- kdu_int16 offset = (1<<downshift)>>1;
-
- for (; width > 0; width--, sp++, dest+=gap)
- {
- val = sp->ival;
- val = (val+offset)>>downshift;
- val += 128;
- if (val & ((0xffffffffU)<<8))
- {
- val = (val < 0 ? 0 : 255);
- }
- *dest = (kdu_byte) val;
- }
- }
- else
- {
- kdu_int16 upshift = 8-precision;
-
- for (; width > 0; width--, sp++, dest+=gap)
- {
- val = sp->ival;
- val <<= upshift;
- val += 128;
- if (val & ((0xffffffffU)<<8))
- {
- val = (val < 0 ? 0 : 256 - (1<<upshift));
- }
- *dest = (kdu_byte) val;
- }
- }
- }
- }
+ int width = src.get_width();
+ if (src.get_buf32() != NULL)
+ { // Decompressed samples have a 32-bit representation (integer or float)
+ assert(precision >= 8); // Else would have used 16 bit representation
+ kdu_sample32 *sp = src.get_buf32();
+ if (!src.is_absolute())
+ { // Transferring normalized floating point data.
+ float scale16 = (float)(1<<16);
+ kdu_int32 val;
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = (kdu_int32)(sp->fval*scale16);
+ val = (val+128)>>8; // May be faster than true rounding
+ val += 128;
+ if (val & ((0xffffffffU)<<8))
+ {
+ val = (val < 0 ? 0 : 255);
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ else
+ { // Transferring 32-bit absolute integers.
+ kdu_int32 val;
+ kdu_int32 downshift = precision-8;
+ kdu_int32 offset = (1<<downshift)>>1;
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val = (val+offset)>>downshift;
+ val += 128;
+ if (val & ((0xffffffffU)<<8))
+ {
+ val = (val < 0 ? 0 : 255);
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ }
+ else
+ { // Source data is 16 bits.
+ kdu_sample16 *sp = src.get_buf16();
+ if (!src.is_absolute())
+ { // Transferring 16-bit fixed point quantities
+ kdu_int16 val;
+
+ if (precision >= 8)
+ { // Can essentially ignore the bit-depth.
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val += (1<<(KDU_FIX_POINT-8))>>1;
+ val >>= (KDU_FIX_POINT-8);
+ val += 128;
+ if (val & ((0xffffffffU)<<8))
+ {
+ val = (val < 0 ? 0 : 255);
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ else
+ { // Need to force zeros into one or more least significant bits.
+ kdu_int16 downshift = KDU_FIX_POINT-precision;
+ kdu_int16 upshift = 8-precision;
+ kdu_int16 offset = 1<<(downshift-1);
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val = (val+offset)>>downshift;
+ val <<= upshift;
+ val += 128;
+ if (val & ((0xffffffffU)<<8))
+ {
+ val = (val < 0 ? 0 : 256 - (1<<upshift));
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ }
+ else
+ { // Transferring 16-bit absolute integers.
+ kdu_int16 val;
+
+ if (precision >= 8)
+ {
+ kdu_int16 downshift = precision-8;
+ kdu_int16 offset = (1<<downshift)>>1;
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val = (val+offset)>>downshift;
+ val += 128;
+ if (val & ((0xffffffffU)<<8))
+ {
+ val = (val < 0 ? 0 : 255);
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ else
+ {
+ kdu_int16 upshift = 8-precision;
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val <<= upshift;
+ val += 128;
+ if (val & ((0xffffffffU)<<8))
+ {
+ val = (val < 0 ? 0 : 256 - (1<<upshift));
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ }
+ }
}
LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap,
- kdu_codestream* codestreamp)
+ kdu_codestream* codestreamp)
{
- S32 c;
-
- mTile = tile;
- mBuf = buf;
- mRowGap = row_gap;
-
- mNumComponents = tile.get_num_components();
-
- llassert(mNumComponents <= 4);
- mUseYCC = tile.get_ycc();
-
- for (c = 0; c < 4; ++c)
- {
- mReversible[c] = false;
- mBitDepths[c] = 0;
- }
-
- // Open tile-components and create processing engines and resources
- for (c = 0; c < mNumComponents; c++)
- {
- mComps[c] = mTile.access_component(c);
- mReversible[c] = mComps[c].get_reversible();
- mBitDepths[c] = mComps[c].get_bit_depth();
- kdu_resolution res = mComps[c].access_resolution(); // Get top resolution
- kdu_dims comp_dims; res.get_dims(comp_dims);
- if (c == 0)
- {
- mDims = comp_dims;
- }
- else
- {
- llassert(mDims == comp_dims); // Safety check; the caller has ensured this
- }
- bool use_shorts = (mComps[c].get_bit_depth(true) <= 16);
- mLines[c].pre_create(&mAllocator,mDims.size.x,mReversible[c],use_shorts,0,0);
- if (res.which() == 0) // No DWT levels used
- {
- mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,use_shorts);
- }
- else
- {
- mEngines[c] = kdu_synthesis(res,&mAllocator,use_shorts);
- }
- }
- mAllocator.finalize(*codestreamp); // Actually creates buffering resources
- for (c = 0; c < mNumComponents; c++)
- {
- mLines[c].create(); // Grabs resources from the allocator.
- }
+ S32 c;
+
+ mTile = tile;
+ mBuf = buf;
+ mRowGap = row_gap;
+
+ mNumComponents = tile.get_num_components();
+
+ llassert(mNumComponents <= 4);
+ mUseYCC = tile.get_ycc();
+
+ for (c = 0; c < 4; ++c)
+ {
+ mReversible[c] = false;
+ mBitDepths[c] = 0;
+ }
+
+ // Open tile-components and create processing engines and resources
+ for (c = 0; c < mNumComponents; c++)
+ {
+ mComps[c] = mTile.access_component(c);
+ mReversible[c] = mComps[c].get_reversible();
+ mBitDepths[c] = mComps[c].get_bit_depth();
+ kdu_resolution res = mComps[c].access_resolution(); // Get top resolution
+ kdu_dims comp_dims; res.get_dims(comp_dims);
+ if (c == 0)
+ {
+ mDims = comp_dims;
+ }
+ else
+ {
+ llassert(mDims == comp_dims); // Safety check; the caller has ensured this
+ }
+ bool use_shorts = (mComps[c].get_bit_depth(true) <= 16);
+ mLines[c].pre_create(&mAllocator,mDims.size.x,mReversible[c],use_shorts,0,0);
+ if (res.which() == 0) // No DWT levels used
+ {
+ mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,use_shorts);
+ }
+ else
+ {
+ mEngines[c] = kdu_synthesis(res,&mAllocator,use_shorts);
+ }
+ }
+ mAllocator.finalize(*codestreamp); // Actually creates buffering resources
+ for (c = 0; c < mNumComponents; c++)
+ {
+ mLines[c].create(); // Grabs resources from the allocator.
+ }
}
LLKDUDecodeState::~LLKDUDecodeState()
{
- // Cleanup
- for (S32 c = 0; c < mNumComponents; c++)
- {
- mEngines[c].destroy(); // engines are interfaces; no default destructors
- }
- mTile.close();
+ // Cleanup
+ for (S32 c = 0; c < mNumComponents; c++)
+ {
+ mEngines[c].destroy(); // engines are interfaces; no default destructors
+ }
+ mTile.close();
}
bool LLKDUDecodeState::processTileDecode(F32 decode_time, bool limit_time)
@@ -1336,13 +1336,13 @@ multiple tiles. For this reason, `row_gap' is needed to identify the
separation between consecutive rows in the real buffer. */
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- S32 c;
- // Now walk through the lines of the buffer, recovering them from the
- // relevant tile-component processing engines.
+ S32 c;
+ // Now walk through the lines of the buffer, recovering them from the
+ // relevant tile-component processing engines.
- LLTimer decode_timer;
- while (mDims.size.y--)
- {
+ LLTimer decode_timer;
+ while (mDims.size.y--)
+ {
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - pull");
for (c = 0; c < mNumComponents; c++)
@@ -1351,11 +1351,11 @@ separation between consecutive rows in the real buffer. */
}
}
- if ((mNumComponents >= 3) && mUseYCC)
- {
+ if ((mNumComponents >= 3) && mUseYCC)
+ {
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - convert");
- kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
- }
+ kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
+ }
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - transfer");
@@ -1364,116 +1364,116 @@ separation between consecutive rows in the real buffer. */
transfer_bytes(mBuf + c, mLines[c], mNumComponents, mBitDepths[c]);
}
}
- mBuf += mRowGap;
- if (mDims.size.y % 10)
- {
- if (limit_time && decode_timer.getElapsedTimeF32() > decode_time)
- {
- return false;
- }
- }
- }
- return true;
+ mBuf += mRowGap;
+ if (mDims.size.y % 10)
+ {
+ if (limit_time && decode_timer.getElapsedTimeF32() > decode_time)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
}
-// kdc_flow_control
+// kdc_flow_control
kdc_flow_control::kdc_flow_control (kdu_supp::kdu_image_in_base *img_in, kdu_codestream codestream)
{
- int n;
-
- this->codestream = codestream;
- codestream.get_valid_tiles(valid_tile_indices);
- tile_idx = valid_tile_indices.pos;
- tile = codestream.open_tile(tile_idx,NULL);
-
- // Set up the individual components
- num_components = codestream.get_num_components(true);
- components = new kdc_component_flow_control[num_components];
- count_delta = 0;
- kdc_component_flow_control *comp = components;
- for (n = 0; n < num_components; n++, comp++)
- {
- comp->line = NULL;
- comp->reader = img_in;
- kdu_coords subsampling;
- codestream.get_subsampling(n,subsampling,true);
- kdu_dims dims;
- codestream.get_tile_dims(tile_idx,n,dims,true);
- comp->vert_subsampling = subsampling.y;
- if ((n == 0) || (comp->vert_subsampling < count_delta))
- {
- count_delta = comp->vert_subsampling;
- }
- comp->ratio_counter = 0;
- comp->remaining_lines = comp->initial_lines = dims.size.y;
- }
- assert(num_components >= 0);
-
- tile.set_components_of_interest(num_components);
- max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false);
+ int n;
+
+ this->codestream = codestream;
+ codestream.get_valid_tiles(valid_tile_indices);
+ tile_idx = valid_tile_indices.pos;
+ tile = codestream.open_tile(tile_idx,NULL);
+
+ // Set up the individual components
+ num_components = codestream.get_num_components(true);
+ components = new kdc_component_flow_control[num_components];
+ count_delta = 0;
+ kdc_component_flow_control *comp = components;
+ for (n = 0; n < num_components; n++, comp++)
+ {
+ comp->line = NULL;
+ comp->reader = img_in;
+ kdu_coords subsampling;
+ codestream.get_subsampling(n,subsampling,true);
+ kdu_dims dims;
+ codestream.get_tile_dims(tile_idx,n,dims,true);
+ comp->vert_subsampling = subsampling.y;
+ if ((n == 0) || (comp->vert_subsampling < count_delta))
+ {
+ count_delta = comp->vert_subsampling;
+ }
+ comp->ratio_counter = 0;
+ comp->remaining_lines = comp->initial_lines = dims.size.y;
+ }
+ assert(num_components >= 0);
+
+ tile.set_components_of_interest(num_components);
+ max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false);
}
kdc_flow_control::~kdc_flow_control()
{
- if (components != NULL)
- {
- delete[] components;
- }
- if (engine.exists())
- {
- engine.destroy();
- }
+ if (components != NULL)
+ {
+ delete[] components;
+ }
+ if (engine.exists())
+ {
+ engine.destroy();
+ }
}
bool kdc_flow_control::advance_components()
{
- bool found_line = false;
- while (!found_line)
- {
- bool all_done = true;
- kdc_component_flow_control *comp = components;
- for (int n = 0; n < num_components; n++, comp++)
- {
- assert(comp->ratio_counter >= 0);
- if (comp->remaining_lines > 0)
- {
- all_done = false;
- comp->ratio_counter -= count_delta;
- if (comp->ratio_counter < 0)
- {
- found_line = true;
- comp->line = engine.exchange_line(n,NULL,NULL);
- assert(comp->line != NULL);
- if (comp->line->get_width())
- {
- comp->reader->get(n,*(comp->line),0);
- }
- }
- }
- }
- if (all_done)
- {
- return false;
- }
- }
- return true;
+ bool found_line = false;
+ while (!found_line)
+ {
+ bool all_done = true;
+ kdc_component_flow_control *comp = components;
+ for (int n = 0; n < num_components; n++, comp++)
+ {
+ assert(comp->ratio_counter >= 0);
+ if (comp->remaining_lines > 0)
+ {
+ all_done = false;
+ comp->ratio_counter -= count_delta;
+ if (comp->ratio_counter < 0)
+ {
+ found_line = true;
+ comp->line = engine.exchange_line(n,NULL,NULL);
+ assert(comp->line != NULL);
+ if (comp->line->get_width())
+ {
+ comp->reader->get(n,*(comp->line),0);
+ }
+ }
+ }
+ }
+ if (all_done)
+ {
+ return false;
+ }
+ }
+ return true;
}
void kdc_flow_control::process_components()
{
- kdc_component_flow_control *comp = components;
- for (int n = 0; n < num_components; n++, comp++)
- {
- if (comp->ratio_counter < 0)
- {
- comp->ratio_counter += comp->vert_subsampling;
- assert(comp->ratio_counter >= 0);
- assert(comp->remaining_lines > 0);
- comp->remaining_lines--;
- assert(comp->line != NULL);
- engine.exchange_line(n,comp->line,NULL);
- comp->line = NULL;
- }
- }
+ kdc_component_flow_control *comp = components;
+ for (int n = 0; n < num_components; n++, comp++)
+ {
+ if (comp->ratio_counter < 0)
+ {
+ comp->ratio_counter += comp->vert_subsampling;
+ assert(comp->ratio_counter >= 0);
+ assert(comp->remaining_lines > 0);
+ comp->remaining_lines--;
+ assert(comp->line != NULL);
+ engine.exchange_line(n,comp->line,NULL);
+ comp->line = NULL;
+ }
+ }
}
diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h
index fe3902380c..8037c81868 100644
--- a/indra/llkdu/llimagej2ckdu.h
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -1,25 +1,25 @@
-/**
+/**
* @file llimagej2ckdu.h
* @brief This is an implementation of JPEG2000 encode/decode using Kakadu
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -48,84 +48,84 @@ class LLKDUDecodeState;
class LLKDUMemSource;
class LLImageJ2CKDU : public LLImageJ2CImpl
-{
+{
public:
- enum ECodeStreamMode
- {
- MODE_FAST = 0,
- MODE_RESILIENT = 1,
- MODE_FUSSY = 2
- };
- LLImageJ2CKDU();
- virtual ~LLImageJ2CKDU();
-
+ enum ECodeStreamMode
+ {
+ MODE_FAST = 0,
+ MODE_RESILIENT = 1,
+ MODE_FUSSY = 2
+ };
+ LLImageJ2CKDU();
+ virtual ~LLImageJ2CKDU();
+
protected:
- virtual bool getMetadata(LLImageJ2C &base);
- virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
- virtual bool encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
- bool reversible=false);
- virtual bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
- virtual bool initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
- virtual std::string getEngineInfo() const;
+ virtual bool getMetadata(LLImageJ2C &base);
+ virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
+ virtual bool encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
+ bool reversible=false);
+ virtual bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
+ virtual bool initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
+ virtual std::string getEngineInfo() const;
private:
- bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL);
- void setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECodeStreamMode mode);
- void cleanupCodeStream();
-
- // This method was public, but the only call to it is commented out in our
- // own initDecode() method. I (nat 2016-08-04) don't know what it does or
- // why. Even if it should be uncommented, it should probably still be
- // private.
-// void findDiscardLevelsBoundaries(LLImageJ2C &base);
-
- // Helper class to hold a kdu_codestream, which is a handle to the
- // underlying implementation object. When CodeStreamHolder is reset() or
- // destroyed, it calls kdu_codestream::destroy() -- which kdu_codestream
- // itself does not.
- //
- // Call through it like a smart pointer using operator->().
- //
- // Every RAII class must be noncopyable. For this we don't need move
- // support.
- class CodeStreamHolder: public boost::noncopyable
- {
- public:
- ~CodeStreamHolder()
- {
- reset();
- }
-
- void reset()
- {
- if (mCodeStream.exists())
- {
- mCodeStream.destroy();
- }
- }
-
- // for those few times when you need a raw kdu_codestream*
- kdu_core::kdu_codestream* get() { return &mCodeStream; }
- kdu_core::kdu_codestream* operator->() { return &mCodeStream; }
-
- private:
- kdu_core::kdu_codestream mCodeStream;
- };
-
- // Encode variable
- std::unique_ptr<LLKDUMemSource> mInputp;
- CodeStreamHolder mCodeStreamp;
- std::unique_ptr<kdu_core::kdu_coords> mTPosp; // tile position
- std::unique_ptr<kdu_core::kdu_dims> mTileIndicesp;
- int mBlocksSize;
- int mPrecinctsSize;
- int mLevels;
-
- // Temporary variables for in-progress decodes...
- // We don't own this LLImageRaw. We're simply pointing to an instance
- // passed into initDecode().
- LLImageRaw *mRawImagep;
- std::unique_ptr<LLKDUDecodeState> mDecodeState;
+ bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL);
+ void setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECodeStreamMode mode);
+ void cleanupCodeStream();
+
+ // This method was public, but the only call to it is commented out in our
+ // own initDecode() method. I (nat 2016-08-04) don't know what it does or
+ // why. Even if it should be uncommented, it should probably still be
+ // private.
+// void findDiscardLevelsBoundaries(LLImageJ2C &base);
+
+ // Helper class to hold a kdu_codestream, which is a handle to the
+ // underlying implementation object. When CodeStreamHolder is reset() or
+ // destroyed, it calls kdu_codestream::destroy() -- which kdu_codestream
+ // itself does not.
+ //
+ // Call through it like a smart pointer using operator->().
+ //
+ // Every RAII class must be noncopyable. For this we don't need move
+ // support.
+ class CodeStreamHolder: public boost::noncopyable
+ {
+ public:
+ ~CodeStreamHolder()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ if (mCodeStream.exists())
+ {
+ mCodeStream.destroy();
+ }
+ }
+
+ // for those few times when you need a raw kdu_codestream*
+ kdu_core::kdu_codestream* get() { return &mCodeStream; }
+ kdu_core::kdu_codestream* operator->() { return &mCodeStream; }
+
+ private:
+ kdu_core::kdu_codestream mCodeStream;
+ };
+
+ // Encode variable
+ std::unique_ptr<LLKDUMemSource> mInputp;
+ CodeStreamHolder mCodeStreamp;
+ std::unique_ptr<kdu_core::kdu_coords> mTPosp; // tile position
+ std::unique_ptr<kdu_core::kdu_dims> mTileIndicesp;
+ int mBlocksSize;
+ int mPrecinctsSize;
+ int mLevels;
+
+ // Temporary variables for in-progress decodes...
+ // We don't own this LLImageRaw. We're simply pointing to an instance
+ // passed into initDecode().
+ LLImageRaw *mRawImagep;
+ std::unique_ptr<LLKDUDecodeState> mDecodeState;
};
#endif
diff --git a/indra/llkdu/llkdumem.cpp b/indra/llkdu/llkdumem.cpp
index 96e9da25d8..04ab033093 100644
--- a/indra/llkdu/llkdumem.cpp
+++ b/indra/llkdu/llkdumem.cpp
@@ -1,25 +1,25 @@
- /**
+ /**
* @file llkdumem.cpp
* @brief Helper class for kdu memory management
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -36,164 +36,164 @@ using kd_supp_image_local::image_line_buf;
#endif
LLKDUMemIn::LLKDUMemIn(const U8 *data,
- const U32 size,
- const U16 width,
- const U16 height,
- const U8 in_num_components,
- siz_params *siz)
+ const U32 size,
+ const U16 width,
+ const U16 height,
+ const U8 in_num_components,
+ siz_params *siz)
{
- U8 n;
-
- first_comp_idx = 0;
- rows = height;
- cols = width;
- num_components = in_num_components;
- alignment_bytes = 0;
-
- for (n = 0; n < 3; ++n)
- {
- precision[n] = 0;
- }
-
- for (n = 0; n < num_components; ++n)
- {
- siz->set(Sdims,n,0,rows);
- siz->set(Sdims,n,1,cols);
- siz->set(Ssigned,n,0,false);
- siz->set(Sprecision,n,0,8);
- }
- incomplete_lines = NULL;
- free_lines = NULL;
- num_unread_rows = rows;
-
- mData = data;
- mDataSize = size;
- mCurPos = 0;
+ U8 n;
+
+ first_comp_idx = 0;
+ rows = height;
+ cols = width;
+ num_components = in_num_components;
+ alignment_bytes = 0;
+
+ for (n = 0; n < 3; ++n)
+ {
+ precision[n] = 0;
+ }
+
+ for (n = 0; n < num_components; ++n)
+ {
+ siz->set(Sdims,n,0,rows);
+ siz->set(Sdims,n,1,cols);
+ siz->set(Ssigned,n,0,false);
+ siz->set(Sprecision,n,0,8);
+ }
+ incomplete_lines = NULL;
+ free_lines = NULL;
+ num_unread_rows = rows;
+
+ mData = data;
+ mDataSize = size;
+ mCurPos = 0;
}
LLKDUMemIn::~LLKDUMemIn()
{
- if ((num_unread_rows > 0) || (incomplete_lines != NULL))
- {
- kdu_warning w;
- w << "Not all rows of image components "
- << first_comp_idx << " through "
- << first_comp_idx+num_components-1
- << " were consumed!";
- }
- image_line_buf *tmp;
- while ((tmp=incomplete_lines) != NULL)
- {
- incomplete_lines = tmp->next;
- delete tmp;
- }
- while ((tmp=free_lines) != NULL)
- {
- free_lines = tmp->next;
- delete tmp;
- }
+ if ((num_unread_rows > 0) || (incomplete_lines != NULL))
+ {
+ kdu_warning w;
+ w << "Not all rows of image components "
+ << first_comp_idx << " through "
+ << first_comp_idx+num_components-1
+ << " were consumed!";
+ }
+ image_line_buf *tmp;
+ while ((tmp=incomplete_lines) != NULL)
+ {
+ incomplete_lines = tmp->next;
+ delete tmp;
+ }
+ while ((tmp=free_lines) != NULL)
+ {
+ free_lines = tmp->next;
+ delete tmp;
+ }
}
bool LLKDUMemIn::get(int comp_idx, kdu_line_buf &line, int x_tnum)
{
- int idx = comp_idx - this->first_comp_idx;
- assert((idx >= 0) && (idx < num_components));
- x_tnum = x_tnum*num_components+idx;
- image_line_buf *scan, *prev=NULL;
- for (scan = incomplete_lines; scan != NULL; prev = scan, scan = scan->next)
- {
- assert(scan->next_x_tnum >= x_tnum);
- if (scan->next_x_tnum == x_tnum)
- {
- break;
- }
- }
- if (scan == NULL)
- { // Need to read a new image line.
- assert(x_tnum == 0); // Must consume in very specific order.
- if (num_unread_rows == 0)
- {
- return false;
- }
- if ((scan = free_lines) == NULL)
- {
- scan = new image_line_buf(cols+3,num_components);
- }
- free_lines = scan->next;
- if (prev == NULL)
- {
- incomplete_lines = scan;
- }
- else
- {
- prev->next = scan;
- }
-
- // Copy from image buffer into scan.
- memcpy(scan->buf, mData+mCurPos, cols*num_components);
- mCurPos += cols*num_components;
-
- num_unread_rows--;
- scan->accessed_samples = 0;
- scan->next_x_tnum = 0;
- }
-
- assert((cols-scan->accessed_samples) >= line.get_width());
-
- int comp_offset = idx;
- kdu_byte *sp = scan->buf+num_components*scan->accessed_samples + comp_offset;
- int n=line.get_width();
-
- if (line.get_buf32() != NULL)
- {
- kdu_sample32 *dp = line.get_buf32();
- if (line.is_absolute())
- { // 32-bit absolute integers
- for (; n > 0; n--, sp+=num_components, dp++)
- {
- dp->ival = ((kdu_int32)(*sp)) - 128;
- }
- }
- else
- { // true 32-bit floats
- for (; n > 0; n--, sp+=num_components, dp++)
- {
- dp->fval = (((float)(*sp)) / 256.0F) - 0.5F;
- }
- }
- }
- else
- {
- kdu_sample16 *dp = line.get_buf16();
- if (line.is_absolute())
- { // 16-bit absolute integers
- for (; n > 0; n--, sp+=num_components, dp++)
- {
- dp->ival = ((kdu_int16)(*sp)) - 128;
- }
- }
- else
- { // 16-bit normalized representation.
- for (; n > 0; n--, sp+=num_components, dp++)
- {
- dp->ival = (((kdu_int16)(*sp)) - 128) << (KDU_FIX_POINT-8);
- }
- }
- }
-
- scan->next_x_tnum++;
- if (idx == (num_components-1))
- {
- scan->accessed_samples += line.get_width();
- }
- if (scan->accessed_samples == cols)
- { // Send empty line to free list.
- assert(scan == incomplete_lines);
- incomplete_lines = scan->next;
- scan->next = free_lines;
- free_lines = scan;
- }
+ int idx = comp_idx - this->first_comp_idx;
+ assert((idx >= 0) && (idx < num_components));
+ x_tnum = x_tnum*num_components+idx;
+ image_line_buf *scan, *prev=NULL;
+ for (scan = incomplete_lines; scan != NULL; prev = scan, scan = scan->next)
+ {
+ assert(scan->next_x_tnum >= x_tnum);
+ if (scan->next_x_tnum == x_tnum)
+ {
+ break;
+ }
+ }
+ if (scan == NULL)
+ { // Need to read a new image line.
+ assert(x_tnum == 0); // Must consume in very specific order.
+ if (num_unread_rows == 0)
+ {
+ return false;
+ }
+ if ((scan = free_lines) == NULL)
+ {
+ scan = new image_line_buf(cols+3,num_components);
+ }
+ free_lines = scan->next;
+ if (prev == NULL)
+ {
+ incomplete_lines = scan;
+ }
+ else
+ {
+ prev->next = scan;
+ }
+
+ // Copy from image buffer into scan.
+ memcpy(scan->buf, mData+mCurPos, cols*num_components);
+ mCurPos += cols*num_components;
+
+ num_unread_rows--;
+ scan->accessed_samples = 0;
+ scan->next_x_tnum = 0;
+ }
+
+ assert((cols-scan->accessed_samples) >= line.get_width());
+
+ int comp_offset = idx;
+ kdu_byte *sp = scan->buf+num_components*scan->accessed_samples + comp_offset;
+ int n=line.get_width();
+
+ if (line.get_buf32() != NULL)
+ {
+ kdu_sample32 *dp = line.get_buf32();
+ if (line.is_absolute())
+ { // 32-bit absolute integers
+ for (; n > 0; n--, sp+=num_components, dp++)
+ {
+ dp->ival = ((kdu_int32)(*sp)) - 128;
+ }
+ }
+ else
+ { // true 32-bit floats
+ for (; n > 0; n--, sp+=num_components, dp++)
+ {
+ dp->fval = (((float)(*sp)) / 256.0F) - 0.5F;
+ }
+ }
+ }
+ else
+ {
+ kdu_sample16 *dp = line.get_buf16();
+ if (line.is_absolute())
+ { // 16-bit absolute integers
+ for (; n > 0; n--, sp+=num_components, dp++)
+ {
+ dp->ival = ((kdu_int16)(*sp)) - 128;
+ }
+ }
+ else
+ { // 16-bit normalized representation.
+ for (; n > 0; n--, sp+=num_components, dp++)
+ {
+ dp->ival = (((kdu_int16)(*sp)) - 128) << (KDU_FIX_POINT-8);
+ }
+ }
+ }
+
+ scan->next_x_tnum++;
+ if (idx == (num_components-1))
+ {
+ scan->accessed_samples += line.get_width();
+ }
+ if (scan->accessed_samples == cols)
+ { // Send empty line to free list.
+ assert(scan == incomplete_lines);
+ incomplete_lines = scan->next;
+ scan->next = free_lines;
+ free_lines = scan;
+ }
return true;
}
diff --git a/indra/llkdu/llkdumem.h b/indra/llkdu/llkdumem.h
index 09d81f38de..177a8ea976 100644
--- a/indra/llkdu/llkdumem.h
+++ b/indra/llkdu/llkdumem.h
@@ -1,25 +1,25 @@
-/**
+/**
* @file llkdumem.h
* @brief Helper class for kdu memory management
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -47,106 +47,106 @@
class LLKDUMemSource: public kdu_core::kdu_compressed_source
{
public:
- LLKDUMemSource(U8 *input_buffer, U32 size)
- {
- mData = input_buffer;
- mSize = size;
- mCurPos = 0;
- }
-
- ~LLKDUMemSource()
- {
- }
-
- int read(kdu_core::kdu_byte *buf, int num_bytes)
- {
- U32 num_out;
- num_out = num_bytes;
-
- if ((mSize - mCurPos) < (U32)num_bytes)
- {
- num_out = mSize -mCurPos;
- }
- memcpy(buf, mData + mCurPos, num_out);
- mCurPos += num_out;
- return num_out;
- }
-
- void reset()
- {
- mCurPos = 0;
- }
+ LLKDUMemSource(U8 *input_buffer, U32 size)
+ {
+ mData = input_buffer;
+ mSize = size;
+ mCurPos = 0;
+ }
+
+ ~LLKDUMemSource()
+ {
+ }
+
+ int read(kdu_core::kdu_byte *buf, int num_bytes)
+ {
+ U32 num_out;
+ num_out = num_bytes;
+
+ if ((mSize - mCurPos) < (U32)num_bytes)
+ {
+ num_out = mSize -mCurPos;
+ }
+ memcpy(buf, mData + mCurPos, num_out);
+ mCurPos += num_out;
+ return num_out;
+ }
+
+ void reset()
+ {
+ mCurPos = 0;
+ }
private:
- U8 *mData;
- U32 mSize;
- U32 mCurPos;
+ U8 *mData;
+ U32 mSize;
+ U32 mCurPos;
};
class LLKDUMemTarget: public kdu_core::kdu_compressed_target
{
public:
- LLKDUMemTarget(U8 *output_buffer, U32 &output_size, const U32 buffer_size)
- {
- mData = output_buffer;
- mSize = buffer_size;
- mCurPos = 0;
- mOutputSize = &output_size;
- }
-
- ~LLKDUMemTarget()
- {
- }
-
- bool write(const kdu_core::kdu_byte *buf, int num_bytes)
- {
- U32 num_out;
- num_out = num_bytes;
-
- if ((mSize - mCurPos) < (U32)num_bytes)
- {
- num_out = mSize - mCurPos;
- memcpy(mData + mCurPos, buf, num_out);
- return false;
- }
- memcpy(mData + mCurPos, buf, num_out);
- mCurPos += num_out;
- *mOutputSize = mCurPos;
- return true;
- }
-
+ LLKDUMemTarget(U8 *output_buffer, U32 &output_size, const U32 buffer_size)
+ {
+ mData = output_buffer;
+ mSize = buffer_size;
+ mCurPos = 0;
+ mOutputSize = &output_size;
+ }
+
+ ~LLKDUMemTarget()
+ {
+ }
+
+ bool write(const kdu_core::kdu_byte *buf, int num_bytes)
+ {
+ U32 num_out;
+ num_out = num_bytes;
+
+ if ((mSize - mCurPos) < (U32)num_bytes)
+ {
+ num_out = mSize - mCurPos;
+ memcpy(mData + mCurPos, buf, num_out);
+ return false;
+ }
+ memcpy(mData + mCurPos, buf, num_out);
+ mCurPos += num_out;
+ *mOutputSize = mCurPos;
+ return true;
+ }
+
private:
- U8 *mData;
- U32 mSize;
- U32 mCurPos;
- U32 *mOutputSize;
+ U8 *mData;
+ U32 mSize;
+ U32 mCurPos;
+ U32 *mOutputSize;
};
class LLKDUMemIn : public kdu_supp::kdu_image_in_base
{
public:
- LLKDUMemIn(const U8 *data,
- const U32 size,
- const U16 rows,
- const U16 cols,
- U8 in_num_components,
- kdu_core::siz_params *siz);
- ~LLKDUMemIn();
+ LLKDUMemIn(const U8 *data,
+ const U32 size,
+ const U16 rows,
+ const U16 cols,
+ U8 in_num_components,
+ kdu_core::siz_params *siz);
+ ~LLKDUMemIn();
- bool get(int comp_idx, kdu_core::kdu_line_buf &line, int x_tnum);
+ bool get(int comp_idx, kdu_core::kdu_line_buf &line, int x_tnum);
private:
- const U8 *mData;
- int first_comp_idx;
- int num_components;
- int rows, cols;
- int alignment_bytes; // Number of 0's at end of each line.
- int precision[3];
- kd_supp_image_local::image_line_buf *incomplete_lines; // Each "sample" represents a full pixel
- kd_supp_image_local::image_line_buf *free_lines;
- int num_unread_rows;
-
- U32 mCurPos;
- U32 mDataSize;
+ const U8 *mData;
+ int first_comp_idx;
+ int num_components;
+ int rows, cols;
+ int alignment_bytes; // Number of 0's at end of each line.
+ int precision[3];
+ kd_supp_image_local::image_line_buf *incomplete_lines; // Each "sample" represents a full pixel
+ kd_supp_image_local::image_line_buf *free_lines;
+ int num_unread_rows;
+
+ U32 mCurPos;
+ U32 mDataSize;
};
#endif
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
index 16213b7f45..db81d60d9e 100644
--- a/indra/llkdu/tests/llimagej2ckdu_test.cpp
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* @file llimagej2ckdu_test.cpp
* @author Merov Linden
* @date 2010-12-17
@@ -6,27 +6,27 @@
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
-// Class to test
+// Class to test
#include "llimagej2ckdu.h"
#if __clang__
@@ -44,7 +44,7 @@
// -------------------------------------------------------------------------------------------
// Stubbing: Declarations required to link and run the class being tested
-// Notes:
+// Notes:
// * Add here stubbed implementation of the few classes and methods used in the class to be tested
// * Add as little as possible (let the link errors guide you)
// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
@@ -53,7 +53,7 @@
// End Stubbing
// -------------------------------------------------------------------------------------------
// Stub the LL Image Classes
-//LLTrace::MemStatHandle LLImageBase::sMemStat("LLImage");
+//LLTrace::MemStatHandle LLImageBase::sMemStat("LLImage");
LLImageRaw::LLImageRaw() { }
LLImageRaw::~LLImageRaw() { }
@@ -241,81 +241,81 @@ void kdu_params::operator delete(void *) {}
namespace tut
{
- // Test wrapper declarations
- struct llimagej2ckdu_test
- {
- // Derived test class
- class LLTestImageJ2CKDU : public LLImageJ2CKDU
- {
- public:
- // Provides public access to some protected methods for testing
- bool callGetMetadata(LLImageJ2C &base) { return getMetadata(base); }
- bool callDecodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
- {
- return decodeImpl(base, raw_image, decode_time, first_channel, max_channel_count);
- }
- bool callEncodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text)
- {
- return encodeImpl(base, raw_image, comment_text);
- }
- };
- // Instance to be tested
- LLTestImageJ2CKDU* mImage;
-
- // Constructor and destructor of the test wrapper
- llimagej2ckdu_test()
- {
- mImage = new LLTestImageJ2CKDU;
- }
- ~llimagej2ckdu_test()
- {
- delete mImage;
- }
- };
-
- // Tut templating thingamagic: test group, object and test instance
- typedef test_group<llimagej2ckdu_test> llimagej2ckdu_t;
- typedef llimagej2ckdu_t::object llimagej2ckdu_object_t;
- tut::llimagej2ckdu_t tut_llimagej2ckdu("LLImageJ2CKDU");
-
- // ---------------------------------------------------------------------------------------
- // Test functions
- // Notes:
- // * Test as many as you possibly can without requiring a full blown simulation of everything
- // * The tests are executed in sequence so the test instance state may change between calls
- // * Remember that you cannot test private methods with tut
- // ---------------------------------------------------------------------------------------
+ // Test wrapper declarations
+ struct llimagej2ckdu_test
+ {
+ // Derived test class
+ class LLTestImageJ2CKDU : public LLImageJ2CKDU
+ {
+ public:
+ // Provides public access to some protected methods for testing
+ bool callGetMetadata(LLImageJ2C &base) { return getMetadata(base); }
+ bool callDecodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+ {
+ return decodeImpl(base, raw_image, decode_time, first_channel, max_channel_count);
+ }
+ bool callEncodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text)
+ {
+ return encodeImpl(base, raw_image, comment_text);
+ }
+ };
+ // Instance to be tested
+ LLTestImageJ2CKDU* mImage;
+
+ // Constructor and destructor of the test wrapper
+ llimagej2ckdu_test()
+ {
+ mImage = new LLTestImageJ2CKDU;
+ }
+ ~llimagej2ckdu_test()
+ {
+ delete mImage;
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<llimagej2ckdu_test> llimagej2ckdu_t;
+ typedef llimagej2ckdu_t::object llimagej2ckdu_object_t;
+ tut::llimagej2ckdu_t tut_llimagej2ckdu("LLImageJ2CKDU");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
- // Test 1 : test getMetadata()
- template<> template<>
- void llimagej2ckdu_object_t::test<1>()
- {
- LLImageJ2C* image = new LLImageJ2C();
- bool res = mImage->callGetMetadata(*image);
- // Trying to set up a data stream with all NIL values and stubbed KDU will "work" and return true
- // Note that is linking with KDU, that call will throw an exception and fail, returning false
- ensure("getMetadata() test failed", res);
- }
+ // Test 1 : test getMetadata()
+ template<> template<>
+ void llimagej2ckdu_object_t::test<1>()
+ {
+ LLImageJ2C* image = new LLImageJ2C();
+ bool res = mImage->callGetMetadata(*image);
+ // Trying to set up a data stream with all NIL values and stubbed KDU will "work" and return true
+ // Note that is linking with KDU, that call will throw an exception and fail, returning false
+ ensure("getMetadata() test failed", res);
+ }
- // Test 2 : test decodeImpl()
- template<> template<>
- void llimagej2ckdu_object_t::test<2>()
- {
- LLImageJ2C* image = new LLImageJ2C();
- LLImageRaw* raw = new LLImageRaw();
- bool res = mImage->callDecodeImpl(*image, *raw, 0.0, 0, 0);
- // Decoding returns true whenever there's nothing else to do, including if decoding failed, so we'll get true here
- ensure("decodeImpl() test failed", res);
- }
+ // Test 2 : test decodeImpl()
+ template<> template<>
+ void llimagej2ckdu_object_t::test<2>()
+ {
+ LLImageJ2C* image = new LLImageJ2C();
+ LLImageRaw* raw = new LLImageRaw();
+ bool res = mImage->callDecodeImpl(*image, *raw, 0.0, 0, 0);
+ // Decoding returns true whenever there's nothing else to do, including if decoding failed, so we'll get true here
+ ensure("decodeImpl() test failed", res);
+ }
- // Test 3 : test encodeImpl()
- template<> template<>
- void llimagej2ckdu_object_t::test<3>()
- {
- LLImageJ2C* image = new LLImageJ2C();
- LLImageRaw* raw = new LLImageRaw();
- bool res = mImage->callEncodeImpl(*image, *raw, NULL);
- // Encoding returns true unless an exception was raised, so we'll get true here though nothing really was done
- ensure("encodeImpl() test failed", res);
- }
+ // Test 3 : test encodeImpl()
+ template<> template<>
+ void llimagej2ckdu_object_t::test<3>()
+ {
+ LLImageJ2C* image = new LLImageJ2C();
+ LLImageRaw* raw = new LLImageRaw();
+ bool res = mImage->callEncodeImpl(*image, *raw, NULL);
+ // Encoding returns true unless an exception was raised, so we'll get true here though nothing really was done
+ ensure("encodeImpl() test failed", res);
+ }
}