summaryrefslogtreecommitdiff
path: root/indra/llimage/llimagej2c.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llimage/llimagej2c.cpp')
-rw-r--r--indra/llimage/llimagej2c.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
new file mode 100644
index 0000000000..ad07700a37
--- /dev/null
+++ b/indra/llimage/llimagej2c.cpp
@@ -0,0 +1,249 @@
+/**
+ * @file llimagej2c.cpp
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#ifndef LL_USE_KDU
+#define LL_USE_KDU 1
+#endif // LL_USE_KDU
+
+#include "llimagej2c.h"
+#include "llmemory.h"
+#if LL_USE_KDU
+#include "llimagej2ckdu.h"
+#endif
+
+#include "llimagej2coj.h"
+
+
+LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
+ mMaxBytes(0),
+ mRawDiscardLevel(-1),
+ mRate(0.0f)
+{
+#if LL_USE_KDU
+ mImpl = new LLImageJ2CKDU();
+#else
+ mImpl = new LLImageJ2COJ();
+#endif
+}
+
+// virtual
+LLImageJ2C::~LLImageJ2C()
+{
+ delete mImpl;
+}
+
+// virtual
+S8 LLImageJ2C::getRawDiscardLevel()
+{
+ return mRawDiscardLevel;
+}
+
+BOOL LLImageJ2C::updateData()
+{
+ resetLastError();
+
+ // Check to make sure that this instance has been initialized with data
+ if (!getData() || (getDataSize() < 16))
+ {
+ setLastError("LLImageJ2C uninitialized");
+ return FALSE;
+ }
+
+ if (!mImpl->getMetadata(*this))
+ {
+ return FALSE;
+ }
+ // SJB: override discard based on mMaxBytes elsewhere
+ S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize();
+ S32 discard = calcDiscardLevelBytes(max_bytes);
+ setDiscardLevel(discard);
+
+ return TRUE;
+}
+
+
+BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
+{
+ return decode(raw_imagep, decode_time, 0, 4);
+}
+
+
+BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
+{
+ LLMemType mt1((LLMemType::EMemType)mMemType);
+
+ resetLastError();
+
+ // Check to make sure that this instance has been initialized with data
+ if (!getData() || (getDataSize() < 16))
+ {
+ setLastError("LLImageJ2C uninitialized");
+ return FALSE;
+ }
+
+ // Update the raw discard level
+ updateRawDiscardLevel();
+
+ return mImpl->decodeImpl(*this, *raw_imagep, decode_time, 0, 4);
+}
+
+
+BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time)
+{
+ return encode(raw_imagep, NULL, encode_time);
+}
+
+
+BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time)
+{
+ LLMemType mt1((LLMemType::EMemType)mMemType);
+ return mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time);
+}
+
+//static
+S32 LLImageJ2C::calcHeaderSizeJ2C()
+{
+ return 600; //2048; // ??? hack... just needs to be >= actual header size...
+}
+
+//static
+S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate)
+{
+ if (rate <= 0.f) rate = .125f;
+ while (discard_level > 0)
+ {
+ if (w < 1 || h < 1)
+ break;
+ w >>= 1;
+ h >>= 1;
+ discard_level--;
+ }
+ S32 bytes = (S32)((F32)(w*h*comp)*rate);
+ bytes = llmax(bytes, calcHeaderSizeJ2C());
+ return bytes;
+}
+
+S32 LLImageJ2C::calcHeaderSize()
+{
+ return calcHeaderSizeJ2C();
+}
+
+S32 LLImageJ2C::calcDataSize(S32 discard_level)
+{
+ return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate);
+}
+
+S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes)
+{
+ llassert(bytes >= 0);
+ S32 discard_level = 0;
+ if (bytes == 0)
+ {
+ return MAX_DISCARD_LEVEL;
+ }
+ while (1)
+ {
+ S32 bytes_needed = calcDataSize(discard_level); // virtual
+ if (bytes >= bytes_needed - (bytes_needed>>2)) // For J2c, up the res at 75% of the optimal number of bytes
+ {
+ break;
+ }
+ discard_level++;
+ if (discard_level >= MAX_DISCARD_LEVEL)
+ {
+ break;
+ }
+ }
+ return discard_level;
+}
+
+void LLImageJ2C::setRate(F32 rate)
+{
+ mRate = rate;
+}
+
+void LLImageJ2C::setMaxBytes(S32 max_bytes)
+{
+ mMaxBytes = max_bytes;
+}
+// NOT USED
+// void LLImageJ2C::setReversible(const BOOL reversible)
+// {
+// mReversible = reversible;
+// }
+
+
+BOOL LLImageJ2C::loadAndValidate(const LLString &filename)
+{
+ resetLastError();
+
+ S32 file_size = 0;
+ apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size);
+ if (!apr_file)
+ {
+ setLastError("Unable to open file for reading", filename);
+ return FALSE;
+ }
+ if (file_size == 0)
+ {
+ setLastError("File is empty",filename);
+ apr_file_close(apr_file);
+ return FALSE;
+ }
+
+ U8 *data = new U8[file_size];
+ apr_size_t bytes_read = file_size;
+ apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
+ if (s != APR_SUCCESS || bytes_read != file_size)
+ {
+ delete[] data;
+ setLastError("Unable to read entire file");
+ return FALSE;
+ }
+ apr_file_close(apr_file);
+
+ return validate(data, file_size);
+}
+
+
+BOOL LLImageJ2C::validate(U8 *data, U32 file_size)
+{
+ LLMemType mt1((LLMemType::EMemType)mMemType);
+ // Taken from setData()
+
+ BOOL res = LLImageFormatted::setData(data, file_size);
+ if ( !res )
+ {
+ return FALSE;
+ }
+
+ // Check to make sure that this instance has been initialized with data
+ if (!getData() || (0 == getDataSize()))
+ {
+ setLastError("LLImageJ2C uninitialized");
+ return FALSE;
+ }
+
+ return mImpl->getMetadata(*this);
+}
+
+void LLImageJ2C::setDecodingDone(BOOL complete)
+{
+ mDecoding = FALSE;
+ mDecoded = complete;
+}
+
+void LLImageJ2C::updateRawDiscardLevel()
+{
+ mRawDiscardLevel = mMaxBytes ? calcDiscardLevelBytes(mMaxBytes) : mDiscardLevel;
+}
+
+LLImageJ2CImpl::~LLImageJ2CImpl()
+{
+}