summaryrefslogtreecommitdiff
path: root/indra/llkdu
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llkdu')
-rw-r--r--indra/llkdu/CMakeLists.txt20
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp510
-rw-r--r--indra/llkdu/llimagej2ckdu.h11
-rw-r--r--indra/llkdu/llkdumem.cpp22
-rw-r--r--indra/llkdu/llkdumem.h44
-rw-r--r--indra/llkdu/tests/llimagej2ckdu_test.cpp248
6 files changed, 585 insertions, 270 deletions
diff --git a/indra/llkdu/CMakeLists.txt b/indra/llkdu/CMakeLists.txt
index b8b44b44fc..046629b514 100644
--- a/indra/llkdu/CMakeLists.txt
+++ b/indra/llkdu/CMakeLists.txt
@@ -19,6 +19,7 @@ include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLIMAGE_INCLUDE_DIRS}
${KDU_INCLUDE_DIR}
+ ${LLKDU_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
)
@@ -42,4 +43,23 @@ list(APPEND llkdu_SOURCE_FILES ${llkdu_HEADER_FILES})
if (USE_KDU)
add_library (${LLKDU_LIBRARIES} ${llkdu_SOURCE_FILES})
+ # Add tests
+ if (LL_TESTS)
+ include(LLAddBuildTest)
+ include(Tut)
+ SET(llkdu_TEST_SOURCE_FILES
+ llimagej2ckdu.cpp
+ )
+ SET(llkdu_test_additional_HEADER_FILES
+ llimagej2ckdu.h
+ llkdumem.h
+ lltut.h
+ )
+ SET(llkdu_test_additional_INCLUDE_DIRS
+ ${KDU_INCLUDE_DIR}
+ ${LLKDU_INCLUDE_DIRS}
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llkdu "${llkdu_TEST_SOURCE_FILES}")
+ endif (LL_TESTS)
+
endif (USE_KDU)
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 1a286d1406..ae456a48be 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -34,35 +34,35 @@
class kdc_flow_control {
-public: // Member functions
- kdc_flow_control(kdu_image_in_base *img_in, kdu_codestream codestream);
- ~kdc_flow_control();
- bool advance_components();
- void process_components();
+public:
+ kdc_flow_control(kdu_image_in_base *img_in, kdu_codestream codestream);
+ ~kdc_flow_control();
+ bool advance_components();
+ void process_components();
+
+private:
-private: // Data
-
- struct kdc_component_flow_control {
- public: // Data
- 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_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;
};
//
@@ -72,7 +72,8 @@ void set_default_colour_weights(kdu_params *siz);
const char* engineInfoLLImageJ2CKDU()
{
- return "KDU v6.4.1";
+ std::string version = llformat("KDU %s", KDU_CORE_VERSION);
+ return version.c_str();
}
LLImageJ2CKDU* createLLImageJ2CKDU()
@@ -105,7 +106,11 @@ const char* fallbackEngineInfoLLImageJ2CImpl()
class LLKDUDecodeState
{
public:
+ LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
+ ~LLKDUDecodeState();
+ BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
+private:
S32 mNumComponents;
BOOL mUseYCC;
kdu_dims mDims;
@@ -113,22 +118,12 @@ public:
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.
-
+ 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;
-
- LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
- ~LLKDUDecodeState();
- BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
-
-public:
- int *AssignLayerBytes(siz_params *siz, int &num_specs);
-
- void setupCodeStream(BOOL keep_codestream, LLImageJ2CKDU::ECodeStreamMode mode);
- BOOL initDecode(LLImageRaw &raw_image, F32 decode_time, LLImageJ2CKDU::ECodeStreamMode mode, S32 first_channel, S32 max_channel_count );
};
void ll_kdu_error( void )
@@ -153,7 +148,7 @@ class LLKDUMessageError : public kdu_message
public:
/*virtual*/ void put_text(const char *s);
/*virtual*/ void put_text(const kdu_uint16 *s);
- /*virtual*/ void flush(bool end_of_message=false);
+ /*virtual*/ void flush(bool end_of_message = false);
static LLKDUMessageError sDefaultMessage;
};
@@ -179,7 +174,7 @@ void LLKDUMessageError::put_text(const kdu_uint16 *s)
void LLKDUMessageError::flush(bool end_of_message)
{
- if( end_of_message )
+ if (end_of_message)
{
throw "KDU throwing an exception";
}
@@ -195,7 +190,9 @@ mCodeStreamp(NULL),
mTPosp(NULL),
mTileIndicesp(NULL),
mRawImagep(NULL),
-mDecodeState(NULL)
+mDecodeState(NULL),
+mBlocksSize(-1),
+mPrecinctsSize(-1)
{
}
@@ -210,7 +207,7 @@ void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision);
void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode)
{
S32 data_size = base.getDataSize();
- S32 max_bytes = base.getMaxBytes() ? base.getMaxBytes() : data_size;
+ S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
//
// Initialization
@@ -229,16 +226,17 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECod
mCodeStreamp = NULL;
}
- if (!mInputp)
+ if (!mInputp && base.getData())
{
- llassert(base.getData());
// The compressed data has been loaded
- // Setup the source for the codestrea
+ // Setup the source for the codestream
mInputp = new LLKDUMemSource(base.getData(), data_size);
}
- llassert(mInputp);
- mInputp->reset();
+ if (mInputp)
+ {
+ mInputp->reset();
+ }
mCodeStreamp = new kdu_codestream;
mCodeStreamp->create(mInputp);
@@ -246,21 +244,21 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECod
// Set the maximum number of bytes to use from the codestream
mCodeStreamp->set_max_bytes(max_bytes);
- // If you want to flip or rotate the image for some reason, change
+ // 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
+ // 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
+ // 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
+ // 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 )
+ switch (mode)
{
case MODE_FAST:
mCodeStreamp->set_fast();
@@ -325,7 +323,19 @@ void LLImageJ2CKDU::cleanupCodeStream()
mTileIndicesp = NULL;
}
-BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count )
+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);
+}
+
+BOOL LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size)
+{
+ mBlocksSize = blocks_size;
+ mPrecinctsSize = precincts_size;
+ return TRUE;
+}
+
+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)
{
base.resetLastError();
@@ -338,17 +348,36 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
mRawImagep = &raw_image;
mCodeStreamp->change_appearance(false, true, false);
- mCodeStreamp->apply_input_restrictions(first_channel,max_channel_count,base.getRawDiscardLevel(),0,NULL);
- kdu_dims dims; mCodeStreamp->get_dims(0,dims);
- S32 channels = base.getComponents() - first_channel;
- if( channels > max_channel_count )
+ // Apply loading discard level and cropping if required
+ kdu_dims* region_kdu = NULL;
+ if (region != NULL)
{
- channels = max_channel_count;
+ 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());
+
+ // 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);
+ // llinfos << "Resizing raw_image to " << dims.size.x << ":" << dims.size.y << llendl;
- // llinfos << "Resizing to " << dims.size.x << ":" << dims.size.y << llendl;
if (!mTileIndicesp)
{
mTileIndicesp = new kdu_dims;
@@ -425,7 +454,7 @@ BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
// 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 )
+ if (channels > max_channel_count)
{
channels = max_channel_count;
}
@@ -451,14 +480,14 @@ BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
return FALSE;
}
}
- catch( const char* msg )
+ catch (const char* msg)
{
base.setLastError(ll_safe_string(msg));
base.decodeFailed();
cleanupCodeStream();
return TRUE; // done
}
- catch( ... )
+ catch (...)
{
base.setLastError( "Unknown J2C error" );
base.decodeFailed();
@@ -481,28 +510,17 @@ BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, BOOL reversible)
{
- // Collect simple arguments.
- bool transpose, vflip, hflip;
- bool allow_rate_prediction, mem, quiet, no_weights;
- int cpu_iterations;
- std::ostream *record_stream;
-
- transpose = false;
- record_stream = NULL;
- allow_rate_prediction = true;
- no_weights = false;
- cpu_iterations = -1;
- mem = false;
- quiet = false;
- vflip = true;
- hflip = false;
+ // Declare and set simple arguments
+ bool transpose = false;
+ bool vflip = true;
+ bool hflip = false;
try
{
- // Set up input image files.
+ // Set up input image files
siz_params siz;
- // Should set rate someplace here.
+ // Should set rate someplace here
LLKDUMemIn mem_in(raw_image.getData(),
raw_image.getDataSize(),
raw_image.getWidth(),
@@ -520,26 +538,17 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
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-strea
+ 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.
-
+ // Construct the `kdu_codestream' object and parse all remaining arguments
U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents();
- if (max_output_size < 1000)
- {
- max_output_size = 1000;
- }
+ max_output_size = (max_output_size < 1000 ? 1000 : max_output_size);
U8 *output_buffer = new U8[max_output_size];
-
- U32 output_size = max_output_size; // gets modified
- LLKDUMemTarget output(output_buffer, output_size, base.getWidth()*base.getHeight()*base.getComponents());
- if (output_size > max_output_size)
- {
- llerrs << llformat("LLImageJ2C::encode output_size(%d) > max_output_size(%d)",
- output_size,max_output_size) << llendl;
- }
+ 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);
@@ -557,16 +566,22 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
kdu_long layer_bytes[64];
U32 max_bytes = 0;
- if ((num_components >= 3) && !no_weights)
+ 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());
}
if (reversible)
{
- // If we're doing reversible, assume we're not using quality layers.
- // Yes, I know this is incorrect!
codestream.access_siz()->parse_string("Creversible=yes");
+ // *TODO: we should use yuv in reversible mode and one level since those images are small.
+ // Don't turn this on now though as both create problems on decoding for the moment
+ //codestream.access_siz()->parse_string("Clevels=1");
+ //codestream.access_siz()->parse_string("Cycc=no");
+ // If we're doing reversible (i.e. lossless compression), assumes we're not using quality layers.
+ // *TODO: this is incorrect and unecessary. Try using the regular layer setting.
codestream.access_siz()->parse_string("Clayers=1");
num_layer_specs = 1;
layer_bytes[0] = 0;
@@ -576,6 +591,7 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
// Rate is the argument passed into the LLImageJ2C which
// specifies the target compression rate. The default is 8:1.
// Possibly if max_bytes < 500, we should just use the default setting?
+ // *TODO: mRate is actually always 8:1 in the viewer. Test different values. Also force to reversible for small (< 500 bytes) textures.
if (base.mRate != 0.f)
{
max_bytes = (U32)(base.mRate*base.getWidth()*base.getHeight()*base.getComponents());
@@ -616,42 +632,56 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
codestream.access_siz()->parse_string(layer_string.c_str());
}
}
- codestream.access_siz()->finalize_all();
- if (cpu_iterations >= 0)
+
+ // Set up data ordering, markers, etc... if precincts or blocks specified
+ if ((mBlocksSize != -1) || (mPrecinctsSize != -1))
{
- codestream.collect_timing_stats(cpu_iterations);
+ 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=RPCL");
+ 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());
}
+
+ 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
- done = true;
- if (tile->advance_components())
- {
- done = false;
- tile->process_components();
- }
- }
+ 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,num_layer_specs);
+ codestream.flush(layer_bytes,num_layer_specs);
// Cleanup
- delete tile;
-
+ delete tile;
codestream.destroy();
- if (record_stream != NULL)
- {
- delete record_stream;
- }
// 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;
@@ -673,19 +703,19 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
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
+ // then bombs. To regain control, we throw an exception, and
// catch it here.
try
{
setupCodeStream(base, FALSE, MODE_FAST);
return TRUE;
}
- catch( const char* msg )
+ catch (const char* msg)
{
base.setLastError(ll_safe_string(msg));
return FALSE;
}
- catch( ... )
+ catch (...)
{
base.setLastError( "Unknown J2C error" );
return FALSE;
@@ -698,37 +728,49 @@ void set_default_colour_weights(kdu_params *siz)
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++)
+ 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);
+ 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);
+ 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))
+ {
+ 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))
- return; // Weights already specified explicitly.
+ 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. */
+ // 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},"
@@ -774,7 +816,7 @@ all necessary level shifting, type conversion, rounding and truncation. */
val += 128;
if (val & ((-1)<<8))
{
- val = (val<0)?0:255;
+ val = (val < 0 ? 0 : 255);
}
*dest = (kdu_byte) val;
}
@@ -792,7 +834,7 @@ all necessary level shifting, type conversion, rounding and truncation. */
val += 128;
if (val & ((-1)<<8))
{
- val = (val<0)?0:255;
+ val = (val < 0 ? 0 : 255);
}
*dest = (kdu_byte) val;
}
@@ -815,7 +857,7 @@ all necessary level shifting, type conversion, rounding and truncation. */
val += 128;
if (val & ((-1)<<8))
{
- val = (val<0)?0:255;
+ val = (val < 0 ? 0 : 255);
}
*dest = (kdu_byte) val;
}
@@ -834,7 +876,7 @@ all necessary level shifting, type conversion, rounding and truncation. */
val += 128;
if (val & ((-1)<<8))
{
- val = (val<0)?0:(256-(1<<upshift));
+ val = (val < 0 ? 0 : 256 - (1<<upshift));
}
*dest = (kdu_byte) val;
}
@@ -856,7 +898,7 @@ all necessary level shifting, type conversion, rounding and truncation. */
val += 128;
if (val & ((-1)<<8))
{
- val = (val<0)?0:255;
+ val = (val < 0 ? 0 : 255);
}
*dest = (kdu_byte) val;
}
@@ -872,7 +914,7 @@ all necessary level shifting, type conversion, rounding and truncation. */
val += 128;
if (val & ((-1)<<8))
{
- val = (val<0)?0:(256-(1<<upshift));
+ val = (val < 0 ? 0 : 256 - (1<<upshift));
}
*dest = (kdu_byte) val;
}
@@ -891,17 +933,17 @@ LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap)
mNumComponents = tile.get_num_components();
- llassert(mNumComponents<=4);
+ llassert(mNumComponents <= 4);
mUseYCC = tile.get_ycc();
- for (c=0; c<4; ++c)
+ 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++)
+ for (c = 0; c < mNumComponents; c++)
{
mComps[c] = mTile.access_component(c);
mReversible[c] = mComps[c].get_reversible();
@@ -928,7 +970,7 @@ LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap)
}
}
mAllocator.finalize(); // Actually creates buffering resources
- for (c=0; c < mNumComponents; c++)
+ for (c = 0; c < mNumComponents; c++)
{
mLines[c].create(); // Grabs resources from the allocator.
}
@@ -936,13 +978,11 @@ LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap)
LLKDUDecodeState::~LLKDUDecodeState()
{
- S32 c;
// Cleanup
- for (c=0; c < mNumComponents; c++)
+ for (S32 c = 0; c < mNumComponents; c++)
{
mEngines[c].destroy(); // engines are interfaces; no default destructors
}
-
mTile.close();
}
@@ -961,7 +1001,7 @@ separation between consecutive rows in the real buffer. */
LLTimer decode_timer;
while (mDims.size.y--)
{
- for (c=0; c < mNumComponents; c++)
+ for (c = 0; c < mNumComponents; c++)
{
mEngines[c].pull(mLines[c],true);
}
@@ -969,7 +1009,7 @@ separation between consecutive rows in the real buffer. */
{
kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
}
- for (c=0; c < mNumComponents; c++)
+ for (c = 0; c < mNumComponents; c++)
{
transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]);
}
@@ -989,96 +1029,100 @@ separation between consecutive rows in the real buffer. */
kdc_flow_control::kdc_flow_control (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);
+ 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;
+ }
+ }
+ }
+ 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 03f289f8b1..9fce58b762 100644
--- a/indra/llkdu/llimagej2ckdu.h
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -50,26 +50,29 @@ public:
MODE_RESILIENT = 1,
MODE_FUSSY = 2
};
-
-public:
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);
+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();
- BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count );
// Encode variable
LLKDUMemSource *mInputp;
kdu_codestream *mCodeStreamp;
kdu_coords *mTPosp; // tile position
kdu_dims *mTileIndicesp;
+ int mBlocksSize;
+ int mPrecinctsSize;
// Temporary variables for in-progress decodes...
LLImageRaw *mRawImagep;
diff --git a/indra/llkdu/llkdumem.cpp b/indra/llkdu/llkdumem.cpp
index 1f549cbbe0..0347475559 100644
--- a/indra/llkdu/llkdumem.cpp
+++ b/indra/llkdu/llkdumem.cpp
@@ -47,12 +47,12 @@ LLKDUMemIn::LLKDUMemIn(const U8 *data,
num_components = in_num_components;
alignment_bytes = 0;
- for (n=0; n<3; ++n)
+ for (n = 0; n < 3; ++n)
{
precision[n] = 0;
}
- for (n=0; n < num_components; ++n)
+ for (n = 0; n < num_components; ++n)
{
siz->set(Sdims,n,0,rows);
siz->set(Sdims,n,1,cols);
@@ -80,12 +80,12 @@ LLKDUMemIn::~LLKDUMemIn()
}
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;
}
@@ -98,16 +98,16 @@ bool LLKDUMemIn::get(int comp_idx, kdu_line_buf &line, int x_tnum)
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)
- {
+ 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.
+ { // Need to read a new image line.
assert(x_tnum == 0); // Must consume in very specific order.
if (num_unread_rows == 0)
{
@@ -134,7 +134,7 @@ bool LLKDUMemIn::get(int comp_idx, kdu_line_buf &line, int x_tnum)
num_unread_rows--;
scan->accessed_samples = 0;
scan->next_x_tnum = 0;
- }
+ }
assert((cols-scan->accessed_samples) >= line.get_width());
@@ -161,7 +161,7 @@ bool LLKDUMemIn::get(int comp_idx, kdu_line_buf &line, int x_tnum)
}
}
else
- {
+ {
kdu_sample16 *dp = line.get_buf16();
if (line.is_absolute())
{ // 16-bit absolute integers
@@ -177,7 +177,7 @@ bool LLKDUMemIn::get(int comp_idx, kdu_line_buf &line, int x_tnum)
dp->ival = (((kdu_int16)(*sp)) - 128) << (KDU_FIX_POINT-8);
}
}
- }
+ }
scan->next_x_tnum++;
if (idx == (num_components-1))
diff --git a/indra/llkdu/llkdumem.h b/indra/llkdu/llkdumem.h
index 7064de4408..9d923fc367 100644
--- a/indra/llkdu/llkdumem.h
+++ b/indra/llkdu/llkdumem.h
@@ -39,7 +39,7 @@
class LLKDUMemSource: public kdu_compressed_source
{
-public: // Member functions
+public:
LLKDUMemSource(U8 *input_buffer, U32 size)
{
mData = input_buffer;
@@ -47,11 +47,11 @@ public: // Member functions
mCurPos = 0;
}
- ~LLKDUMemSource()
+ ~LLKDUMemSource()
{
}
- int read(kdu_byte *buf, int num_bytes)
+ int read(kdu_byte *buf, int num_bytes)
{
U32 num_out;
num_out = num_bytes;
@@ -70,7 +70,7 @@ public: // Member functions
mCurPos = 0;
}
-private: // Data
+private:
U8 *mData;
U32 mSize;
U32 mCurPos;
@@ -78,7 +78,7 @@ private: // Data
class LLKDUMemTarget: public kdu_compressed_target
{
-public: // Member functions
+public:
LLKDUMemTarget(U8 *output_buffer, U32 &output_size, const U32 buffer_size)
{
mData = output_buffer;
@@ -87,11 +87,11 @@ public: // Member functions
mOutputSize = &output_size;
}
- ~LLKDUMemTarget()
- {
+ ~LLKDUMemTarget()
+ {
}
- bool write(const kdu_byte *buf, int num_bytes)
+ bool write(const kdu_byte *buf, int num_bytes)
{
U32 num_out;
num_out = num_bytes;
@@ -108,7 +108,7 @@ public: // Member functions
return true;
}
-private: // Data
+private:
U8 *mData;
U32 mSize;
U32 mCurPos;
@@ -117,27 +117,27 @@ private: // Data
class LLKDUMemIn : public kdu_image_in_base
{
-public: // Member functions
- LLKDUMemIn(const U8 *data,
+public:
+ LLKDUMemIn(const U8 *data,
const U32 size,
const U16 rows,
const U16 cols,
U8 in_num_components,
siz_params *siz);
- ~LLKDUMemIn();
+ ~LLKDUMemIn();
- bool get(int comp_idx, kdu_line_buf &line, int x_tnum);
+ bool get(int comp_idx, kdu_line_buf &line, int x_tnum);
-private: // Data
+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];
- image_line_buf *incomplete_lines; // Each "sample" represents a full pixel
- image_line_buf *free_lines;
- int num_unread_rows;
+ 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];
+ image_line_buf *incomplete_lines; // Each "sample" represents a full pixel
+ image_line_buf *free_lines;
+ int num_unread_rows;
U32 mCurPos;
U32 mDataSize;
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
new file mode 100644
index 0000000000..7ac24a969a
--- /dev/null
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -0,0 +1,248 @@
+/**
+ * @file llimagej2ckdu_test.cpp
+ * @author Merov Linden
+ * @date 2010-12-17
+ *
+ * $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
+#include "llimagej2ckdu.h"
+#include "llkdumem.h"
+// Tut header
+#include "lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// 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)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+// Stubb the LL Image Classes
+LLImageRaw::LLImageRaw() { }
+LLImageRaw::~LLImageRaw() { }
+U8* LLImageRaw::allocateData(S32 ) { return NULL; }
+void LLImageRaw::deleteData() { }
+U8* LLImageRaw::reallocateData(S32 ) { return NULL; }
+BOOL LLImageRaw::resize(U16, U16, S8) { return TRUE; } // this method always returns TRUE...
+
+LLImageBase::LLImageBase()
+: mData(NULL),
+mDataSize(0),
+mWidth(0),
+mHeight(0),
+mComponents(0),
+mBadBufferAllocation(false),
+mAllowOverSize(false),
+mMemType(LLMemType::MTYPE_IMAGEBASE)
+{ }
+LLImageBase::~LLImageBase() { }
+U8* LLImageBase::allocateData(S32 ) { return NULL; }
+void LLImageBase::deleteData() { }
+void LLImageBase::dump() { }
+const U8* LLImageBase::getData() const { return NULL; }
+U8* LLImageBase::getData() { return NULL; }
+U8* LLImageBase::reallocateData(S32 ) { return NULL; }
+void LLImageBase::sanityCheck() { }
+void LLImageBase::setSize(S32 , S32 , S32 ) { }
+
+LLImageJ2CImpl::~LLImageJ2CImpl() { }
+
+LLImageFormatted::LLImageFormatted(S8 ) { }
+LLImageFormatted::~LLImageFormatted() { }
+U8* LLImageFormatted::allocateData(S32 ) { return NULL; }
+S32 LLImageFormatted::calcDataSize(S32 ) { return 0; }
+S32 LLImageFormatted::calcDiscardLevelBytes(S32 ) { return 0; }
+BOOL LLImageFormatted::decodeChannels(LLImageRaw*, F32, S32, S32) { return FALSE; }
+BOOL LLImageFormatted::copyData(U8 *, S32) { return TRUE; } // this method always returns TRUE...
+void LLImageFormatted::deleteData() { }
+void LLImageFormatted::dump() { }
+U8* LLImageFormatted::reallocateData(S32 ) { return NULL; }
+void LLImageFormatted::resetLastError() { }
+void LLImageFormatted::sanityCheck() { }
+void LLImageFormatted::setLastError(const std::string& , const std::string& ) { }
+
+LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C) { }
+LLImageJ2C::~LLImageJ2C() { }
+S32 LLImageJ2C::calcDataSize(S32 ) { return 0; }
+S32 LLImageJ2C::calcDiscardLevelBytes(S32 ) { return 0; }
+S32 LLImageJ2C::calcHeaderSize() { return 0; }
+BOOL LLImageJ2C::decode(LLImageRaw*, F32) { return FALSE; }
+BOOL LLImageJ2C::decodeChannels(LLImageRaw*, F32, S32, S32 ) { return FALSE; }
+void LLImageJ2C::decodeFailed() { }
+BOOL LLImageJ2C::encode(const LLImageRaw*, F32) { return FALSE; }
+S8 LLImageJ2C::getRawDiscardLevel() { return 0; }
+void LLImageJ2C::resetLastError() { }
+void LLImageJ2C::setLastError(const std::string&, const std::string&) { }
+BOOL LLImageJ2C::updateData() { return FALSE; }
+void LLImageJ2C::updateRawDiscardLevel() { }
+
+LLKDUMemIn::LLKDUMemIn(const U8*, const U32, const U16, const U16, const U8, siz_params*) { }
+LLKDUMemIn::~LLKDUMemIn() { }
+bool LLKDUMemIn::get(int, kdu_line_buf&, int) { return false; }
+
+// Stub Kakadu Library calls
+kdu_tile_comp kdu_tile::access_component(int ) { kdu_tile_comp a; return a; }
+void kdu_tile::close(kdu_thread_env* ) { }
+int kdu_tile::get_num_components() { return 0; }
+bool kdu_tile::get_ycc() { return false; }
+void kdu_tile::set_components_of_interest(int , const int* ) { }
+kdu_resolution kdu_tile_comp::access_resolution() { kdu_resolution a; return a; }
+int kdu_tile_comp::get_bit_depth(bool ) { return 8; }
+bool kdu_tile_comp::get_reversible() { return false; }
+kdu_subband kdu_resolution::access_subband(int ) { kdu_subband a; return a; }
+void kdu_resolution::get_dims(kdu_dims& ) { }
+int kdu_resolution::which() { return 0; }
+kdu_decoder::kdu_decoder(kdu_subband , kdu_sample_allocator*, bool , float, int, kdu_thread_env*, kdu_thread_queue*) { }
+kdu_synthesis::kdu_synthesis(kdu_resolution, kdu_sample_allocator*, bool, float, kdu_thread_env*, kdu_thread_queue*) { }
+kdu_params::kdu_params(const char*, bool, bool, bool, bool, bool) { }
+kdu_params::~kdu_params() { }
+void kdu_params::set(const char* , int , int , bool ) { }
+void kdu_params::set(const char* , int , int , int ) { }
+void kdu_params::finalize_all(bool ) { }
+void kdu_params::copy_from(kdu_params*, int, int, int, int, int, bool, bool, bool) { }
+bool kdu_params::parse_string(const char*) { return false; }
+bool kdu_params::get(const char*, int, int, bool&, bool, bool, bool) { return false; }
+bool kdu_params::get(const char*, int, int, float&, bool, bool, bool) { return false; }
+bool kdu_params::get(const char*, int, int, int&, bool, bool, bool) { return false; }
+kdu_params* kdu_params::access_relation(int, int, int, bool) { return NULL; }
+kdu_params* kdu_params::access_cluster(const char*) { return NULL; }
+void kdu_codestream::set_fast() { }
+void kdu_codestream::set_fussy() { }
+void kdu_codestream::get_dims(int, kdu_dims&, bool ) { }
+void kdu_codestream::change_appearance(bool, bool, bool) { }
+void kdu_codestream::get_tile_dims(kdu_coords, int, kdu_dims&, bool ) { }
+void kdu_codestream::destroy() { }
+void kdu_codestream::collect_timing_stats(int ) { }
+void kdu_codestream::set_max_bytes(kdu_long, bool, bool ) { }
+void kdu_codestream::get_valid_tiles(kdu_dims& ) { }
+void kdu_codestream::create(siz_params*, kdu_compressed_target*, kdu_dims*, int, kdu_long ) { }
+void kdu_codestream::create(kdu_compressed_source*, kdu_thread_env*) { }
+void kdu_codestream::apply_input_restrictions( int, int, int, int, kdu_dims*, kdu_component_access_mode ) { }
+void kdu_codestream::get_subsampling(int , kdu_coords&, bool ) { }
+void kdu_codestream::flush(kdu_long *, int , kdu_uint16 *, bool, bool, double, kdu_thread_env*) { }
+void kdu_codestream::set_resilient(bool ) { }
+int kdu_codestream::get_num_components(bool ) { return 0; }
+siz_params* kdu_codestream::access_siz() { return NULL; }
+kdu_tile kdu_codestream::open_tile(kdu_coords , kdu_thread_env* ) { kdu_tile a; return a; }
+kdu_codestream_comment kdu_codestream::add_comment() { kdu_codestream_comment a; return a; }
+bool kdu_codestream_comment::put_text(const char*) { return false; }
+void kdu_customize_warnings(kdu_message*) { }
+void kdu_customize_errors(kdu_message*) { }
+void kdu_convert_ycc_to_rgb(kdu_line_buf&, kdu_line_buf&, kdu_line_buf&, int) { }
+kdu_long kdu_multi_analysis::create(kdu_codestream, kdu_tile, bool, kdu_roi_image*, bool, int, kdu_thread_env*, kdu_thread_queue*, bool ) { kdu_long a = 0; return a; }
+siz_params::siz_params() : kdu_params(NULL, false, false, false, false, false) { }
+void siz_params::finalize(bool ) { }
+void siz_params::copy_with_xforms(kdu_params*, int, int, bool, bool, bool) { }
+int siz_params::write_marker_segment(kdu_output*, kdu_params*, int) { return 0; }
+bool siz_params::check_marker_segment(kdu_uint16, int, kdu_byte a[], int&) { return false; }
+bool siz_params::read_marker_segment(kdu_uint16, int, kdu_byte a[], int) { return false; }
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+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 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 == TRUE);
+ }
+
+ // 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 == TRUE);
+ }
+
+ // 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 == TRUE);
+ }
+}