Automated merge with bundle:F:\code\viewer-experience+c:\users\richard\appdata\local\temp\thg.4vsiw5\ssh__richard@hg.lindenlab.com_richard_viewer-experience-merge_qwnptv.hg
commit
e1f2b2b3e8
|
|
@ -70,6 +70,10 @@ static const char USAGE[] = "\n"
|
|||
" be used. Blocks must be smaller than precincts. Like precincts, this option adds\n"
|
||||
" PLT, tile markers and uses RPCL.\n"
|
||||
" Only valid for output j2c images. Default is 64.\n"
|
||||
" -l, --levels <n>\n"
|
||||
" Number of decomposition levels (aka discard levels) in the output image.\n"
|
||||
" The maximum number of levels authorized is 32.\n"
|
||||
" Only valid for output j2c images. Default is 5.\n"
|
||||
" -rev, --reversible\n"
|
||||
" Set the compression to be lossless (reversible in j2c parlance).\n"
|
||||
" Only valid for output j2c images.\n"
|
||||
|
|
@ -147,7 +151,7 @@ LLPointer<LLImageRaw> load_image(const std::string &src_filename, int discard_le
|
|||
}
|
||||
|
||||
// Save a raw image instance into a file
|
||||
bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, int blocks_size, int precincts_size, bool reversible, bool output_stats)
|
||||
bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, int blocks_size, int precincts_size, int levels, bool reversible, bool output_stats)
|
||||
{
|
||||
LLPointer<LLImageFormatted> image = create_image(dest_filename);
|
||||
|
||||
|
|
@ -156,9 +160,9 @@ bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_imag
|
|||
{
|
||||
// That method doesn't exist (and likely, doesn't make sense) for any other image file format
|
||||
// hence the required cryptic cast.
|
||||
if ((blocks_size != -1) || (precincts_size != -1))
|
||||
if ((blocks_size != -1) || (precincts_size != -1) || (levels != 0))
|
||||
{
|
||||
((LLImageJ2C*)(image.get()))->initEncode(*raw_image, blocks_size, precincts_size);
|
||||
((LLImageJ2C*)(image.get()))->initEncode(*raw_image, blocks_size, precincts_size, levels);
|
||||
}
|
||||
((LLImageJ2C*)(image.get()))->setReversible(reversible);
|
||||
}
|
||||
|
|
@ -306,6 +310,7 @@ int main(int argc, char** argv)
|
|||
int discard_level = -1;
|
||||
int precincts_size = -1;
|
||||
int blocks_size = -1;
|
||||
int levels = 0;
|
||||
bool reversible = false;
|
||||
|
||||
// Init whatever is necessary
|
||||
|
|
@ -403,7 +408,6 @@ int main(int argc, char** argv)
|
|||
else
|
||||
{
|
||||
precincts_size = atoi(value_str.c_str());
|
||||
// *TODO: make sure precincts_size is a power of 2
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[arg], "--blocks") || !strcmp(argv[arg], "-b"))
|
||||
|
|
@ -420,7 +424,22 @@ int main(int argc, char** argv)
|
|||
else
|
||||
{
|
||||
blocks_size = atoi(value_str.c_str());
|
||||
// *TODO: make sure blocks_size is a power of 2
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[arg], "--levels") || !strcmp(argv[arg], "-l"))
|
||||
{
|
||||
std::string value_str;
|
||||
if ((arg + 1) < argc)
|
||||
{
|
||||
value_str = argv[arg+1];
|
||||
}
|
||||
if (((arg + 1) >= argc) || (value_str[0] == '-'))
|
||||
{
|
||||
std::cout << "No valid --levels argument given, default (5) will be used" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
levels = atoi(value_str.c_str());
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[arg], "--reversible") || !strcmp(argv[arg], "-rev"))
|
||||
|
|
@ -499,7 +518,7 @@ int main(int argc, char** argv)
|
|||
// Save file
|
||||
if (out_file != out_end)
|
||||
{
|
||||
if (!save_image(*out_file, raw_image, blocks_size, precincts_size, reversible, image_stats))
|
||||
if (!save_image(*out_file, raw_image, blocks_size, precincts_size, levels, reversible, image_stats))
|
||||
{
|
||||
std::cout << "Error: Image " << *out_file << " could not be saved" << std::endl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,8 +35,21 @@
|
|||
|
||||
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
|
||||
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
|
||||
|
||||
// *TODO : Use MAX_IMAGE_MIP as max discard level and modify j2c management so that the number
|
||||
// of levels is read from the header's file, not inferred from its size.
|
||||
const S32 MAX_DISCARD_LEVEL = 5;
|
||||
|
||||
// JPEG2000 size constraints
|
||||
// Those are declared here as they are germane to other image constraints used in the viewer
|
||||
// and declared right here. Some come from the JPEG2000 spec, some conventions specific to SL.
|
||||
const S32 MAX_DECOMPOSITION_LEVELS = 32; // Number of decomposition levels cannot exceed 32 according to jpeg2000 spec
|
||||
const S32 MIN_DECOMPOSITION_LEVELS = 5; // the SL viewer will *crash* trying to decode images with fewer than 5 decomposition levels (unless image is small that is)
|
||||
const S32 MAX_PRECINCT_SIZE = 2048; // No reason to be bigger than MAX_IMAGE_SIZE
|
||||
const S32 MIN_PRECINCT_SIZE = 4; // Can't be smaller than MIN_BLOCK_SIZE
|
||||
const S32 MAX_BLOCK_SIZE = 64; // Max total block size is 4096, hence 64x64 when using square blocks
|
||||
const S32 MIN_BLOCK_SIZE = 4; // Min block dim is 4 according to jpeg2000 spec
|
||||
|
||||
const S32 MIN_IMAGE_SIZE = (1<<MIN_IMAGE_MIP); // 4, only used for expand/contract power of 2
|
||||
const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048
|
||||
const S32 MIN_IMAGE_AREA = MIN_IMAGE_SIZE * MIN_IMAGE_SIZE;
|
||||
|
|
|
|||
|
|
@ -144,9 +144,9 @@ BOOL LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* regio
|
|||
return mImpl->initDecode(*this,raw_image,discard_level,region);
|
||||
}
|
||||
|
||||
BOOL LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size)
|
||||
BOOL LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
|
||||
{
|
||||
return mImpl->initEncode(*this,raw_image,blocks_size,precincts_size);
|
||||
return mImpl->initEncode(*this,raw_image,blocks_size,precincts_size,levels);
|
||||
}
|
||||
|
||||
BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public:
|
|||
/*virtual*/ void setLastError(const std::string& message, const std::string& filename = std::string());
|
||||
|
||||
BOOL initDecode(LLImageRaw &raw_image, int discard_level, int* region);
|
||||
BOOL initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size);
|
||||
BOOL initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels);
|
||||
|
||||
// Encode with comment text
|
||||
BOOL encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time=0.0);
|
||||
|
|
@ -120,7 +120,7 @@ protected:
|
|||
virtual BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
|
||||
BOOL reversible=FALSE) = 0;
|
||||
virtual BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL) = 0;
|
||||
virtual BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1) = 0;
|
||||
virtual BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0) = 0;
|
||||
|
||||
friend class LLImageJ2C;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ BOOL LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int disca
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size)
|
||||
BOOL LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
|
||||
{
|
||||
// No specific implementation for this method in the OpenJpeg case
|
||||
return FALSE;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ protected:
|
|||
/*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);
|
||||
/*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "lltimer.h"
|
||||
#include "llpointer.h"
|
||||
#include "llmath.h"
|
||||
#include "llkdumem.h"
|
||||
|
||||
|
||||
|
|
@ -192,7 +193,8 @@ mTileIndicesp(NULL),
|
|||
mRawImagep(NULL),
|
||||
mDecodeState(NULL),
|
||||
mBlocksSize(-1),
|
||||
mPrecinctsSize(-1)
|
||||
mPrecinctsSize(-1),
|
||||
mLevels(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -328,10 +330,29 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int disc
|
|||
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)
|
||||
BOOL LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
|
||||
{
|
||||
mBlocksSize = blocks_size;
|
||||
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,MIN_DECOMPOSITION_LEVELS);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -373,10 +394,12 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
|
|||
|
||||
// Resize raw_image according to the image to be decoded
|
||||
kdu_dims dims; mCodeStreamp->get_dims(0,dims);
|
||||
// *TODO: Use the real number of levels read from the file throughout the code instead of relying on an infered value from dimensions
|
||||
//S32 levels = mCodeStreamp->get_min_dwt_levels();
|
||||
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 << "j2c image dimension: width = " << dims.size.x << ", height = " << dims.size.y << ", channels = " << channels << ", levels = " << levels << llendl;
|
||||
|
||||
if (!mTileIndicesp)
|
||||
{
|
||||
|
|
@ -653,6 +676,11 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
|
|||
std::string Parts_string = llformat("ORGtparts=R");
|
||||
codestream.access_siz()->parse_string(Parts_string.c_str());
|
||||
}
|
||||
if (mLevels != 0)
|
||||
{
|
||||
std::string levels_string = llformat("Clevels=%d",mLevels);
|
||||
codestream.access_siz()->parse_string(levels_string.c_str());
|
||||
}
|
||||
|
||||
codestream.access_siz()->finalize_all();
|
||||
codestream.change_appearance(transpose,vflip,hflip);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ protected:
|
|||
/*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);
|
||||
/*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
|
||||
|
||||
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);
|
||||
|
|
@ -73,6 +73,7 @@ private:
|
|||
kdu_dims *mTileIndicesp;
|
||||
int mBlocksSize;
|
||||
int mPrecinctsSize;
|
||||
int mLevels;
|
||||
|
||||
// Temporary variables for in-progress decodes...
|
||||
LLImageRaw *mRawImagep;
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ 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 ) { }
|
||||
int kdu_codestream::get_min_dwt_levels() { return 5; }
|
||||
void kdu_codestream::change_appearance(bool, bool, bool) { }
|
||||
void kdu_codestream::get_tile_dims(kdu_coords, int, kdu_dims&, bool ) { }
|
||||
void kdu_codestream::destroy() { }
|
||||
|
|
|
|||
|
|
@ -4284,6 +4284,39 @@
|
|||
<key>Value</key>
|
||||
<real>0.25</real>
|
||||
</map>
|
||||
<key>Jpeg2000AdvancedCompression</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use advanced Jpeg2000 compression options (precincts, blocks, ordering, markers)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>Jpeg2000PrecinctsSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Size of image precincts. Assumed square and same for all levels. Must be power of 2.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>256</integer>
|
||||
</map>
|
||||
<key>Jpeg2000BlocksSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Size of encoding blocks. Assumed square and same for all levels. Must be power of 2. Max 64, Min 4.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>64</integer>
|
||||
</map>
|
||||
<key>KeepAspectForSnapshot</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,17 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LastPostcardRecipient</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Last recipient of postcard</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string />
|
||||
</map>
|
||||
<key>LogNearbyChat</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -932,16 +932,19 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
|
|||
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
|
||||
if (image.isNull())
|
||||
{
|
||||
image->setLastError("Couldn't open the image to be uploaded.");
|
||||
return FALSE;
|
||||
}
|
||||
if (!image->load(filename))
|
||||
{
|
||||
image->setLastError("Couldn't load the image to be uploaded.");
|
||||
return FALSE;
|
||||
}
|
||||
// Decompress or expand it in a raw image structure
|
||||
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
|
||||
if (!image->decode(raw_image, 0.0f))
|
||||
{
|
||||
image->setLastError("Couldn't decode the image to be uploaded.");
|
||||
return FALSE;
|
||||
}
|
||||
// Check the image constraints
|
||||
|
|
@ -952,8 +955,15 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
|
|||
}
|
||||
// Convert to j2c (JPEG2000) and save the file locally
|
||||
LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
|
||||
if (compressedImage.isNull())
|
||||
{
|
||||
image->setLastError("Couldn't convert the image to jpeg2000.");
|
||||
llinfos << "Couldn't convert to j2c, file : " << filename << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
if (!compressedImage->save(out_filename))
|
||||
{
|
||||
image->setLastError("Couldn't create the jpeg2000 image for upload.");
|
||||
llinfos << "Couldn't create output file : " << out_filename << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -961,6 +971,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
|
|||
LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
|
||||
if (!integrity_test->loadAndValidate( out_filename ))
|
||||
{
|
||||
image->setLastError("The created jpeg2000 image is corrupt.");
|
||||
llinfos << "Image file : " << out_filename << " is corrupt" << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -978,7 +989,25 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
|
|||
(raw_image->getWidth() * raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF))
|
||||
compressedImage->setReversible(TRUE);
|
||||
|
||||
compressedImage->encode(raw_image, 0.0f);
|
||||
|
||||
if (gSavedSettings.getBOOL("Jpeg2000AdvancedCompression"))
|
||||
{
|
||||
// This test option will create jpeg2000 images with precincts for each level, RPCL ordering
|
||||
// and PLT markers. The block size is also optionally modifiable.
|
||||
// Note: the images hence created are compatible with older versions of the viewer.
|
||||
// Read the blocks and precincts size settings
|
||||
S32 block_size = gSavedSettings.getS32("Jpeg2000BlocksSize");
|
||||
S32 precinct_size = gSavedSettings.getS32("Jpeg2000PrecinctsSize");
|
||||
llinfos << "Advanced JPEG2000 Compression: precinct = " << precinct_size << ", block = " << block_size << llendl;
|
||||
compressedImage->initEncode(*raw_image, block_size, precinct_size, 0);
|
||||
}
|
||||
|
||||
if (!compressedImage->encode(raw_image, 0.0f))
|
||||
{
|
||||
llinfos << "convertToUploadFile : encode returns with error!!" << llendl;
|
||||
// Clear up the pointer so we don't leak that one
|
||||
compressedImage = NULL;
|
||||
}
|
||||
|
||||
return compressedImage;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
Recipient's Email:
|
||||
</text>
|
||||
<line_editor
|
||||
control_name="LastPostcardRecipient"
|
||||
follows="left|top"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
|
|
|
|||
Loading…
Reference in New Issue