summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xindra/integration_tests/llimage_libtest/CMakeLists.txt3
-rwxr-xr-xindra/integration_tests/llimage_libtest/llimage_libtest.cpp262
-rwxr-xr-xindra/llimage/llimage.cpp463
-rwxr-xr-xindra/llimage/llimage.h49
-rwxr-xr-xindra/newview/app_settings/filters/Gotham.xml30
-rwxr-xr-xindra/newview/app_settings/filters/Hefe.xml23
-rwxr-xr-xindra/newview/app_settings/filters/Inkwell.xml14
-rwxr-xr-xindra/newview/app_settings/filters/Lomofi.xml23
-rwxr-xr-xindra/newview/app_settings/filters/Poprocket.xml25
-rwxr-xr-xindra/newview/app_settings/filters/Sutro.xml19
-rwxr-xr-xindra/newview/app_settings/filters/Toaster.xml23
-rw-r--r--indra/newview/llfloaterflickr.cpp32
-rw-r--r--indra/newview/llfloaterflickr.h1
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp16
-rw-r--r--indra/newview/llsnapshotlivepreview.h3
-rw-r--r--indra/newview/skins/default/xui/en/panel_flickr_photo.xml31
16 files changed, 978 insertions, 39 deletions
diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt
index 36a7d38bb7..8a83ac498f 100755
--- a/indra/integration_tests/llimage_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt
@@ -7,6 +7,7 @@ project (llimage_libtest)
include(00-Common)
include(LLCommon)
include(LLImage)
+include(LLMath)
include(LLImageJ2COJ)
include(LLKDU)
include(LLVFS)
@@ -15,6 +16,7 @@ include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLVFS_INCLUDE_DIRS}
${LLIMAGE_INCLUDE_DIRS}
+ ${LLMATH_INCLUDE_DIRS}
)
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
@@ -64,6 +66,7 @@ endif (DARWIN)
target_link_libraries(llimage_libtest
${LLCOMMON_LIBRARIES}
${LLVFS_LIBRARIES}
+ ${LLMATH_LIBRARIES}
${LLIMAGE_LIBRARIES}
${LLKDU_LIBRARIES}
${KDU_LIBRARY}
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
index 034c816742..009be0941e 100755
--- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
+++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
@@ -39,6 +39,8 @@
#include "llimagej2c.h"
#include "lldir.h"
#include "lldiriterator.h"
+#include "v4coloru.h"
+#include "llsdserialize.h"
// system libraries
#include <iostream>
@@ -83,6 +85,24 @@ static const char USAGE[] = "\n"
" -rev, --reversible\n"
" Set the compression to be lossless (reversible in j2c parlance).\n"
" Only valid for output j2c images.\n"
+" -f, --filter <name> [<param>]\n"
+" Apply the filter <name> to the input images using the optional <param> value. Admissible names:\n"
+" - 'grayscale' converts to grayscale (no param).\n"
+" - 'sepia' converts to sepia (no param).\n"
+" - 'saturate' changes color saturation according to <param>: < 1.0 will desaturate, > 1.0 will saturate.\n"
+" - 'rotate' rotates the color hue according to <param> (in degree, positive value only).\n"
+" - 'gamma' applies gamma curve <param> to all channels: > 1.0 will darken, < 1.0 will lighten.\n"
+" - 'colorize' applies a red tint to the image using <param> as an alpha (transparency between 0.0 and 1.0) value.\n"
+" - 'contrast' modifies the contrast according to <param> : > 1.0 will enhance the contrast, <1.0 will flatten it.\n"
+" - 'brighten' adds <param> light to the image (<param> between 0 and 255).\n"
+" - 'darken' substracts <param> light to the image (<param> between 0 and 255).\n"
+" - 'linearize' optimizes the contrast using the brightness histogram. <param> is the fraction (between 0.0 and 1.0) of discarded tail of the histogram.\n"
+" - 'posterize' redistributes the colors between <param> classes per channel (<param> between 2 and 255).\n"
+" - Any other value will be interpreted as a file name describing a sequence of filters and parameters to be applied to the input images\n"
+" -v, --vignette <name> [<feather> <min>]\n"
+" Apply a circular central vignette <name> to the filter using the optional <feather> and <min> values. Admissible names:\n"
+" - 'blend' : the filter is applied with full intensity in the center and blends with the image to the periphery.\n"
+" - 'fade' : the filter is applied with full intensity in the center and fades to black to the periphery.\n"
" -log, --logmetrics <metric>\n"
" Log performance data for <metric>. Results in <metric>.slp\n"
" Note: so far, only ImageCompressionTester has been tested.\n"
@@ -96,10 +116,110 @@ static const char USAGE[] = "\n"
// true when all image loading is done. Used by metric logging thread to know when to stop the thread.
static bool sAllDone = false;
+// Load filter from file
+LLSD load_filter_from_file(const std::string& file_path)
+{
+ std::cout << "Loading filter settings from : " << file_path << std::endl;
+
+ llifstream filter_xml(file_path);
+ if (filter_xml.is_open())
+ {
+ // load and parse it
+ LLSD filter_data(LLSD::emptyArray());
+ LLPointer<LLSDParser> parser = new LLSDXMLParser();
+ parser->parse(filter_xml, filter_data, LLSDSerialize::SIZE_UNLIMITED);
+ filter_xml.close();
+ return filter_data;
+ }
+ else
+ {
+ return LLSD();
+ }
+}
+
+// Apply the filter data to the image passed as parameter
+void execute_filter(const LLSD& filter_data, LLPointer<LLImageRaw> raw_image)
+{
+ //std::cout << "Filter : size = " << filter_data.size() << std::endl;
+ for (S32 i = 0; i < filter_data.size(); ++i)
+ {
+ std::string filter_name = filter_data[i][0].asString();
+ // Dump out the filter values (for debug)
+ //std::cout << "Filter : name = " << filter_data[i][0].asString() << ", params = ";
+ //for (S32 j = 1; j < filter_data[i].size(); ++j)
+ //{
+ // std::cout << filter_data[i][j].asString() << ", ";
+ //}
+ //std::cout << std::endl;
+
+ // Execute the filter described on this line
+ if (filter_name == "blend")
+ {
+ raw_image->setVignette(VIGNETTE_MODE_BLEND,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal()));
+ }
+ else if (filter_name == "fade")
+ {
+ raw_image->setVignette(VIGNETTE_MODE_FADE,(float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal()));
+ }
+ else if (filter_name == "sepia")
+ {
+ raw_image->filterSepia();
+ }
+ else if (filter_name == "grayscale")
+ {
+ raw_image->filterGrayScale();
+ }
+ else if (filter_name == "saturate")
+ {
+ raw_image->filterSaturate((float)(filter_data[i][1].asReal()));
+ }
+ else if (filter_name == "rotate")
+ {
+ raw_image->filterRotate((float)(filter_data[i][1].asReal()));
+ }
+ else if (filter_name == "gamma")
+ {
+ LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal()));
+ raw_image->filterGamma((float)(filter_data[i][1].asReal()),color);
+ }
+ else if (filter_name == "colorize")
+ {
+ LLColor3 color((float)(filter_data[i][1].asReal()),(float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()));
+ LLColor3 alpha((F32)(filter_data[i][4].asReal()),(float)(filter_data[i][5].asReal()),(float)(filter_data[i][6].asReal()));
+ raw_image->filterColorize(color,alpha);
+ }
+ else if (filter_name == "contrast")
+ {
+ LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal()));
+ raw_image->filterContrast((float)(filter_data[i][1].asReal()),color);
+ }
+ else if (filter_name == "brighten")
+ {
+ LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal()));
+ raw_image->filterBrightness((S32)(filter_data[i][1].asReal()),color);
+ }
+ else if (filter_name == "darken")
+ {
+ LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal()));
+ raw_image->filterBrightness((S32)(-filter_data[i][1].asReal()),color);
+ }
+ else if (filter_name == "linearize")
+ {
+ LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal()));
+ raw_image->filterLinearize((float)(filter_data[i][1].asReal()),color);
+ }
+ else if (filter_name == "posterize")
+ {
+ LLColor3 color((float)(filter_data[i][2].asReal()),(float)(filter_data[i][3].asReal()),(float)(filter_data[i][4].asReal()));
+ raw_image->filterEqualize((S32)(filter_data[i][1].asReal()),color);
+ }
+ }
+}
+
// Create an empty formatted image instance of the correct type from the filename
LLPointer<LLImageFormatted> create_image(const std::string &filename)
{
- std::string exten = gDirUtilp->getExtension(filename);
+ std::string exten = gDirUtilp->getExtension(filename);
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromExtension(exten);
return image;
}
@@ -350,6 +470,11 @@ int main(int argc, char** argv)
int blocks_size = -1;
int levels = 0;
bool reversible = false;
+ std::string filter_name = "";
+ double filter_param = 0.0;
+ std::string vignette_name = "";
+ double vignette_param_1 = 1.0;
+ double vignette_param_2 = 0.0;
// Init whatever is necessary
ll_init_apr();
@@ -523,7 +648,73 @@ int main(int argc, char** argv)
break;
}
}
- else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
+ else if (!strcmp(argv[arg], "--filter") || !strcmp(argv[arg], "-f"))
+ {
+ // '--filter' needs to be specified with a named filter argument
+ if ((arg + 1) < argc)
+ {
+ filter_name = argv[arg+1];
+ }
+ if (((arg + 1) >= argc) || (filter_name[0] == '-'))
+ {
+ // We don't have an argument left in the arg list or the next argument is another option
+ std::cout << "No --filter argument given, no filter will be applied" << std::endl;
+ }
+ else
+ {
+ arg += 1; // Skip that arg now we know it's a valid test name
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ // --filter can also have an optional parameter
+ std::string value_str;
+ value_str = argv[arg+1]; // Check the next arg
+ if (value_str[0] != '-') // If it's not another argument, it's a filter parameter value
+ {
+ filter_param = atof(value_str.c_str());
+ arg += 1; // Skip that arg now we used it as a valid filter param
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ }
+ }
+ }
+ else if (!strcmp(argv[arg], "--vignette") || !strcmp(argv[arg], "-v"))
+ {
+ // '--vignette' needs to be specified with a named vignette argument
+ if ((arg + 1) < argc)
+ {
+ vignette_name = argv[arg+1];
+ }
+ if (((arg + 1) >= argc) || (vignette_name[0] == '-'))
+ {
+ // We don't have an argument left in the arg list or the next argument is another option
+ std::cout << "No --vignette argument given, no vignette will be applied to filters" << std::endl;
+ }
+ else
+ {
+ arg += 1; // Skip that arg now we know it's a valid vignette name
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ // --vignette can also have optional parameters
+ std::string value_str;
+ value_str = argv[arg+1]; // Check the next arg
+ if (value_str[0] != '-') // If it's not another argument, it's a vignette parameter value
+ {
+ vignette_param_1 = atof(value_str.c_str());
+ arg += 1; // Skip that arg now we used it as a valid vignette param
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ value_str = argv[arg+1]; // Check the next arg
+ if (value_str[0] != '-') // If it's not another argument, it's a vignette parameter value
+ {
+ vignette_param_2 = atof(value_str.c_str());
+ arg += 1; // Skip that arg now we used it as a valid vignette param
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ }
+ }
+ }
+ }
+ else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
{
analyze_performance = true;
}
@@ -568,7 +759,72 @@ int main(int argc, char** argv)
std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl;
continue;
}
-
+
+ // Set the vignette if any
+ if (vignette_name == "blend")
+ {
+ raw_image->setVignette(VIGNETTE_MODE_BLEND,(float)(vignette_param_1),(float)(vignette_param_2));
+ }
+ else if (vignette_name == "fade")
+ {
+ raw_image->setVignette(VIGNETTE_MODE_FADE,(float)(vignette_param_1),(float)(vignette_param_2));
+ }
+
+ // Apply filter if any
+ if (filter_name == "sepia")
+ {
+ raw_image->filterSepia();
+ }
+ else if (filter_name == "grayscale")
+ {
+ raw_image->filterGrayScale();
+ }
+ else if (filter_name == "saturate")
+ {
+ raw_image->filterSaturate((float)(filter_param));
+ }
+ else if (filter_name == "rotate")
+ {
+ raw_image->filterRotate((float)(filter_param));
+ }
+ else if (filter_name == "gamma")
+ {
+ raw_image->filterGamma((float)(filter_param),LLColor3::white);
+ }
+ else if (filter_name == "colorize")
+ {
+ // For testing, we just colorize in the red channel, modulate by the alpha passed as a parameter
+ LLColor3 color(1.0,0.0,0.0);
+ LLColor3 alpha((F32)(filter_param),0.0,0.0);
+ raw_image->filterColorize(color,alpha);
+ }
+ else if (filter_name == "contrast")
+ {
+ raw_image->filterContrast((float)(filter_param),LLColor3::white);
+ }
+ else if (filter_name == "brighten")
+ {
+ raw_image->filterBrightness((S32)(filter_param),LLColor3::white);
+ }
+ else if (filter_name == "darken")
+ {
+ raw_image->filterBrightness((S32)(-filter_param),LLColor3::white);
+ }
+ else if (filter_name == "linearize")
+ {
+ raw_image->filterLinearize((float)(filter_param),LLColor3::white);
+ }
+ else if (filter_name == "posterize")
+ {
+ raw_image->filterEqualize((S32)(filter_param),LLColor3::white);
+ }
+ else if (filter_name != "")
+ {
+ // We're interpreting the filter as a filter file name
+ LLSD filter_data = load_filter_from_file(filter_name);
+ execute_filter(filter_data,raw_image);
+ }
+
// Save file
if (out_file != out_end)
{
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index c8a05e1fae..977bb09b63 100755
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -29,7 +29,10 @@
#include "llimage.h"
#include "llmath.h"
+#include "v3color.h"
#include "v4coloru.h"
+#include "m3math.h"
+#include "v3math.h"
#include "llimagebmp.h"
#include "llimagetga.h"
@@ -95,7 +98,14 @@ LLImageBase::LLImageBase()
mHeight(0),
mComponents(0),
mBadBufferAllocation(false),
- mAllowOverSize(false)
+ mAllowOverSize(false),
+ mHistoRed(NULL),
+ mHistoGreen(NULL),
+ mHistoBlue(NULL),
+ mHistoBrightness(NULL),
+ mVignetteMode(VIGNETTE_MODE_NONE),
+ mVignetteGamma(1.0),
+ mVignetteMin(0.0)
{
}
@@ -103,10 +113,14 @@ LLImageBase::LLImageBase()
LLImageBase::~LLImageBase()
{
deleteData(); // virtual
+ ll_aligned_free_16(mHistoRed);
+ ll_aligned_free_16(mHistoGreen);
+ ll_aligned_free_16(mHistoBlue);
+ ll_aligned_free_16(mHistoBrightness);
}
-//static
-void LLImageBase::createPrivatePool()
+//static
+void LLImageBase::createPrivatePool()
{
if(!sPrivatePoolp)
{
@@ -933,6 +947,449 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
return TRUE ;
}
+// Filter Operations
+void LLImageRaw::filterGrayScale()
+{
+ LLMatrix3 gray_scale;
+ LLVector3 luminosity(0.2125, 0.7154, 0.0721);
+ gray_scale.setRows(luminosity, luminosity, luminosity);
+ gray_scale.transpose();
+ colorTransform(gray_scale);
+}
+
+void LLImageRaw::filterSepia()
+{
+ LLMatrix3 sepia;
+ sepia.setRows(LLVector3(0.3588, 0.7044, 0.1368),
+ LLVector3(0.2990, 0.5870, 0.1140),
+ LLVector3(0.2392, 0.4696, 0.0912));
+ sepia.transpose();
+ colorTransform(sepia);
+}
+
+void LLImageRaw::filterSaturate(F32 saturation)
+{
+ // Matrix to Lij
+ LLMatrix3 r_a;
+ LLMatrix3 r_b;
+
+ // 45 degre rotation around z
+ r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0),
+ LLVector3(-OO_SQRT2, OO_SQRT2, 0.0),
+ LLVector3( 0.0, 0.0, 1.0));
+ // 54.73 degre rotation around y
+ float oo_sqrt3 = 1.0f / F_SQRT3;
+ float sin_54 = F_SQRT2 * oo_sqrt3;
+ r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54),
+ LLVector3(0.0, 1.0, 0.0),
+ LLVector3(sin_54, 0.0, oo_sqrt3));
+
+ // Coordinate conversion
+ LLMatrix3 Lij = r_b * r_a;
+ LLMatrix3 Lij_inv = Lij;
+ Lij_inv.transpose();
+
+ // Local saturation transform
+ LLMatrix3 s;
+ s.setRows(LLVector3(saturation, 0.0, 0.0),
+ LLVector3(0.0, saturation, 0.0),
+ LLVector3(0.0, 0.0, 1.0));
+
+ // Global saturation transform
+ LLMatrix3 transfo = Lij_inv * s * Lij;
+ colorTransform(transfo);
+}
+
+void LLImageRaw::filterRotate(F32 alpha)
+{
+ // Matrix to Lij
+ LLMatrix3 r_a;
+ LLMatrix3 r_b;
+
+ // 45 degre rotation around z
+ r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0),
+ LLVector3(-OO_SQRT2, OO_SQRT2, 0.0),
+ LLVector3( 0.0, 0.0, 1.0));
+ // 54.73 degre rotation around y
+ float oo_sqrt3 = 1.0f / F_SQRT3;
+ float sin_54 = F_SQRT2 * oo_sqrt3;
+ r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54),
+ LLVector3(0.0, 1.0, 0.0),
+ LLVector3(sin_54, 0.0, oo_sqrt3));
+
+ // Coordinate conversion
+ LLMatrix3 Lij = r_b * r_a;
+ LLMatrix3 Lij_inv = Lij;
+ Lij_inv.transpose();
+
+ // Local color rotation transform
+ LLMatrix3 r;
+ alpha *= DEG_TO_RAD;
+ r.setRows(LLVector3( cosf(alpha), sinf(alpha), 0.0),
+ LLVector3(-sinf(alpha), cosf(alpha), 0.0),
+ LLVector3( 0.0, 0.0, 1.0));
+
+ // Global color rotation transform
+ LLMatrix3 transfo = Lij_inv * r * Lij;
+ colorTransform(transfo);
+}
+
+void LLImageRaw::filterGamma(F32 gamma, const LLColor3& alpha)
+{
+ U8 gamma_red_lut[256];
+ U8 gamma_green_lut[256];
+ U8 gamma_blue_lut[256];
+
+ for (S32 i = 0; i < 256; i++)
+ {
+ F32 gamma_i = llclampf((float)(pow((float)(i)/255.0,gamma)));
+ // Blend in with alpha values
+ gamma_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * 255.0 * gamma_i);
+ gamma_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * 255.0 * gamma_i);
+ gamma_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * 255.0 * gamma_i);
+ }
+
+ colorCorrect(gamma_red_lut,gamma_green_lut,gamma_blue_lut);
+}
+
+void LLImageRaw::filterLinearize(F32 tail, const LLColor3& alpha)
+{
+ // Get the histogram
+ U32* histo = getBrightnessHistogram();
+
+ // Compute cumulated histogram
+ U32 cumulated_histo[256];
+ cumulated_histo[0] = histo[0];
+ for (S32 i = 1; i < 256; i++)
+ {
+ cumulated_histo[i] = cumulated_histo[i-1] + histo[i];
+ }
+
+ // Compute min and max counts minus tail
+ tail = llclampf(tail);
+ S32 total = cumulated_histo[255];
+ S32 min_c = (S32)((F32)(total) * tail);
+ S32 max_c = (S32)((F32)(total) * (1.0 - tail));
+
+ // Find min and max values
+ S32 min_v = 0;
+ while (cumulated_histo[min_v] < min_c)
+ {
+ min_v++;
+ }
+ S32 max_v = 255;
+ while (cumulated_histo[max_v] > max_c)
+ {
+ max_v--;
+ }
+
+ // Compute linear lookup table
+ U8 linear_red_lut[256];
+ U8 linear_green_lut[256];
+ U8 linear_blue_lut[256];
+ if (max_v == min_v)
+ {
+ // Degenerated binary split case
+ for (S32 i = 0; i < 256; i++)
+ {
+ U8 value_i = (i < min_v ? 0 : 255);
+ // Blend in with alpha values
+ linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
+ linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
+ linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
+ }
+ }
+ else
+ {
+ // Linearize between min and max
+ F32 slope = 255.0 / (F32)(max_v - min_v);
+ F32 translate = -min_v * slope;
+ for (S32 i = 0; i < 256; i++)
+ {
+ U8 value_i = (U8)(llclampb((S32)(slope*i + translate)));
+ // Blend in with alpha values
+ linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
+ linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
+ linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
+ }
+ }
+
+ // Apply lookup table
+ colorCorrect(linear_red_lut,linear_green_lut,linear_blue_lut);
+}
+
+void LLImageRaw::filterEqualize(S32 nb_classes, const LLColor3& alpha)
+{
+ // Regularize the parameter: must be between 2 and 255
+ nb_classes = llmax(nb_classes,2);
+ nb_classes = llclampb(nb_classes);
+
+ // Get the histogram
+ U32* histo = getBrightnessHistogram();
+
+ // Compute cumulated histogram
+ U32 cumulated_histo[256];
+ cumulated_histo[0] = histo[0];
+ for (S32 i = 1; i < 256; i++)
+ {
+ cumulated_histo[i] = cumulated_histo[i-1] + histo[i];
+ }
+
+ // Compute deltas
+ S32 total = cumulated_histo[255];
+ S32 delta_count = total / nb_classes;
+ S32 current_count = delta_count;
+ S32 delta_value = 256 / (nb_classes - 1);
+ S32 current_value = 0;
+
+ // Compute equalized lookup table
+ U8 equalize_red_lut[256];
+ U8 equalize_green_lut[256];
+ U8 equalize_blue_lut[256];
+ for (S32 i = 0; i < 256; i++)
+ {
+ // Blend in current_value with alpha values
+ equalize_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * current_value);
+ equalize_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * current_value);
+ equalize_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * current_value);
+ if (cumulated_histo[i] >= current_count)
+ {
+ current_count += delta_count;
+ current_value += delta_value;
+ current_value = llclampb(current_value);
+ }
+ }
+
+ // Apply lookup table
+ colorCorrect(equalize_red_lut,equalize_green_lut,equalize_blue_lut);
+}
+
+void LLImageRaw::filterColorize(const LLColor3& color, const LLColor3& alpha)
+{
+ U8 red_lut[256];
+ U8 green_lut[256];
+ U8 blue_lut[256];
+
+ F32 red_composite = 255.0 * alpha.mV[0] * color.mV[0];
+ F32 green_composite = 255.0 * alpha.mV[1] * color.mV[1];
+ F32 blue_composite = 255.0 * alpha.mV[2] * color.mV[2];
+
+ for (S32 i = 0; i < 256; i++)
+ {
+ red_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[0]) * (F32)(i) + red_composite)));
+ green_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[1]) * (F32)(i) + green_composite)));
+ blue_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[2]) * (F32)(i) + blue_composite)));
+ }
+
+ colorCorrect(red_lut,green_lut,blue_lut);
+}
+
+void LLImageRaw::filterContrast(F32 slope, const LLColor3& alpha)
+{
+ U8 contrast_red_lut[256];
+ U8 contrast_green_lut[256];
+ U8 contrast_blue_lut[256];
+
+ F32 translate = 128.0 * (1.0 - slope);
+
+ for (S32 i = 0; i < 256; i++)
+ {
+ U8 value_i = (U8)(llclampb((S32)(slope*i + translate)));
+ // Blend in with alpha values
+ contrast_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
+ contrast_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
+ contrast_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
+ }
+
+ colorCorrect(contrast_red_lut,contrast_green_lut,contrast_blue_lut);
+}
+
+void LLImageRaw::filterBrightness(S32 add, const LLColor3& alpha)
+{
+ U8 brightness_red_lut[256];
+ U8 brightness_green_lut[256];
+ U8 brightness_blue_lut[256];
+
+ for (S32 i = 0; i < 256; i++)
+ {
+ U8 value_i = (U8)(llclampb((S32)((S32)(i) + add)));
+ // Blend in with alpha values
+ brightness_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i);
+ brightness_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i);
+ brightness_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i);
+ }
+
+ colorCorrect(brightness_red_lut,brightness_green_lut,brightness_blue_lut);
+}
+
+// Filter Primitives
+void LLImageRaw::colorTransform(const LLMatrix3 &transform)
+{
+ const S32 components = getComponents();
+ llassert( components >= 1 && components <= 4 );
+
+ S32 width = getWidth();
+ S32 height = getHeight();
+
+ U8* dst_data = getData();
+ for (S32 j = 0; j < height; j++)
+ {
+ for (S32 i = 0; i < width; i++)
+ {
+ LLVector3 src((F32)(dst_data[VRED]),(F32)(dst_data[VGREEN]),(F32)(dst_data[VBLUE]));
+ LLVector3 dst = src * transform;
+ dst.clamp(0.0f,255.0f);
+ if (mVignetteMode == VIGNETTE_MODE_NONE)
+ {
+ dst_data[VRED] = dst.mV[VRED];
+ dst_data[VGREEN] = dst.mV[VGREEN];
+ dst_data[VBLUE] = dst.mV[VBLUE];
+ }
+ else
+ {
+ F32 alpha = getVignetteAlpha(i,j);
+ if (mVignetteMode == VIGNETTE_MODE_BLEND)
+ {
+ // Blends with the source image on the edges
+ F32 inv_alpha = 1.0 - alpha;
+ dst_data[VRED] = inv_alpha * src.mV[VRED] + alpha * dst.mV[VRED];
+ dst_data[VGREEN] = inv_alpha * src.mV[VGREEN] + alpha * dst.mV[VGREEN];
+ dst_data[VBLUE] = inv_alpha * src.mV[VBLUE] + alpha * dst.mV[VBLUE];
+ }
+ else // VIGNETTE_MODE_FADE
+ {
+ // Fade to black on the edges
+ dst_data[VRED] = alpha * dst.mV[VRED];
+ dst_data[VGREEN] = alpha * dst.mV[VGREEN];
+ dst_data[VBLUE] = alpha * dst.mV[VBLUE];
+ }
+ }
+ dst_data += components;
+ }
+ }
+}
+
+void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue)
+{
+ const S32 components = getComponents();
+ llassert( components >= 1 && components <= 4 );
+
+ S32 width = getWidth();
+ S32 height = getHeight();
+
+ U8* dst_data = getData();
+ for (S32 j = 0; j < height; j++)
+ {
+ for (S32 i = 0; i < width; i++)
+ {
+ if (mVignetteMode == VIGNETTE_MODE_NONE)
+ {
+ dst_data[VRED] = lut_red[dst_data[VRED]];
+ dst_data[VGREEN] = lut_green[dst_data[VGREEN]];
+ dst_data[VBLUE] = lut_blue[dst_data[VBLUE]];
+ }
+ else
+ {
+ F32 alpha = getVignetteAlpha(i,j);
+ if (mVignetteMode == VIGNETTE_MODE_BLEND)
+ {
+ // Blends with the source image on the edges
+ F32 inv_alpha = 1.0 - alpha;
+ dst_data[VRED] = inv_alpha * dst_data[VRED] + alpha * lut_red[dst_data[VRED]];
+ dst_data[VGREEN] = inv_alpha * dst_data[VGREEN] + alpha * lut_green[dst_data[VGREEN]];
+ dst_data[VBLUE] = inv_alpha * dst_data[VBLUE] + alpha * lut_blue[dst_data[VBLUE]];
+ }
+ else // VIGNETTE_MODE_FADE
+ {
+ // Fade to black on the edges
+ dst_data[VRED] = alpha * lut_red[dst_data[VRED]];
+ dst_data[VGREEN] = alpha * lut_green[dst_data[VGREEN]];
+ dst_data[VBLUE] = alpha * lut_blue[dst_data[VBLUE]];
+ }
+ }
+ dst_data += components;
+ }
+ }
+}
+
+void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min)
+{
+ mVignetteMode = mode;
+ mVignetteGamma = gamma;
+ mVignetteMin = llclampf(min);
+ // We always center the vignette on the image and fits it in the image smallest dimension
+ mVignetteCenterX = getWidth()/2;
+ mVignetteCenterY = getHeight()/2;
+ mVignetteWidth = llmin(getWidth()/2,getHeight()/2);
+}
+
+F32 LLImageRaw::getVignetteAlpha(S32 i, S32 j)
+{
+ // alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges
+ // The gamma parameter controls the intensity of the drop down from alpha 1.0 (center) to 0.0
+ F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY);
+ F32 alpha = powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f));
+ // We rescale alpha between min and 1.0 so to avoid complete fading if so desired.
+ return (mVignetteMin + alpha * (1.0 - mVignetteMin));
+}
+
+U32* LLImageRaw::getBrightnessHistogram()
+{
+ if (!mHistoBrightness)
+ {
+ computeHistograms();
+ }
+ return mHistoBrightness;
+}
+
+void LLImageRaw::computeHistograms()
+{
+ const S32 components = getComponents();
+ llassert( components >= 1 && components <= 4 );
+
+ // Allocate memory for the histograms
+ if (!mHistoRed)
+ {
+ mHistoRed = (U32*) ll_aligned_malloc_16(256*sizeof(U32));
+ }
+ if (!mHistoGreen)
+ {
+ mHistoGreen = (U32*) ll_aligned_malloc_16(256*sizeof(U32));
+ }
+ if (!mHistoBlue)
+ {
+ mHistoBlue = (U32*) ll_aligned_malloc_16(256*sizeof(U32));
+ }
+ if (!mHistoBrightness)
+ {
+ mHistoBrightness = (U32*) ll_aligned_malloc_16(256*sizeof(U32));
+ }
+
+ // Initialize them
+ for (S32 i = 0; i < 256; i++)
+ {
+ mHistoRed[i] = 0;
+ mHistoGreen[i] = 0;
+ mHistoBlue[i] = 0;
+ mHistoBrightness[i] = 0;
+ }
+
+ // Compute them
+ S32 pixels = getWidth() * getHeight();
+ U8* dst_data = getData();
+ for (S32 i = 0; i < pixels; i++)
+ {
+ mHistoRed[dst_data[VRED]]++;
+ mHistoGreen[dst_data[VGREEN]]++;
+ mHistoBlue[dst_data[VBLUE]]++;
+ // Note: this is a very simple shorthand for brightness but it's OK for our use
+ S32 brightness = ((S32)(dst_data[VRED]) + (S32)(dst_data[VGREEN]) + (S32)(dst_data[VBLUE])) / 3;
+ mHistoBrightness[brightness]++;
+ // next pixel...
+ dst_data += components;
+ }
+}
+
void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step )
{
const S32 components = getComponents();
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 2277afc585..cc91f95624 100755
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -71,6 +71,8 @@ const S32 HTTP_PACKET_SIZE = 1496;
class LLImageFormatted;
class LLImageRaw;
class LLColor4U;
+class LLColor3;
+class LLMatrix3;
class LLPrivateMemoryPool;
typedef enum e_image_codec
@@ -86,6 +88,13 @@ typedef enum e_image_codec
IMG_CODEC_EOF = 8
} EImageCodec;
+typedef enum e_vignette_mode
+{
+ VIGNETTE_MODE_NONE = 0,
+ VIGNETTE_MODE_BLEND = 1,
+ VIGNETTE_MODE_FADE = 2
+} EVignetteMode;
+
//============================================================================
// library initialization class
@@ -150,6 +159,20 @@ protected:
// special accessor to allow direct setting of mData and mDataSize by LLImageFormatted
void setDataAndSize(U8 *data, S32 size);
+ // Histograms (if we ever happen to need them)
+ U32 *mHistoRed;
+ U32 *mHistoGreen;
+ U32 *mHistoBlue;
+ U32 *mHistoBrightness;
+
+ // Vignette filtering
+ EVignetteMode mVignetteMode;
+ S32 mVignetteCenterX;
+ S32 mVignetteCenterY;
+ S32 mVignetteWidth;
+ F32 mVignetteGamma;
+ F32 mVignetteMin;
+
public:
static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
@@ -255,6 +278,29 @@ public:
// Src and dst are same size. Src has 4 components. Dst has 3 components.
void compositeUnscaled4onto3( LLImageRaw* src );
+
+ // Filter Operations : Transforms
+ void filterGrayScale(); // Convert to grayscale
+ void filterSepia(); // Convert to sepia
+ void filterSaturate(F32 saturation); // < 1.0 desaturates, > 1.0 saturates
+ void filterRotate(F32 alpha); // Rotates hue according to alpha, alpha is an angle in degrees
+
+ // Filter Operations : Color Corrections
+ // When specified, the LLColor3 alpha parameter indicates the intensity of the effect for each color channel
+ // acting in effect as an alpha blending factor different for each channel. For instance (1.0,0.0,0.0) will apply
+ // the effect only to the Red channel. Intermediate values blends the effect with the source color.
+ void filterGamma(F32 gamma, const LLColor3& alpha); // Apply gamma to each channel
+ void filterLinearize(F32 tail, const LLColor3& alpha); // Use histogram to linearize constrast between min and max values minus tail
+ void filterEqualize(S32 nb_classes, const LLColor3& alpha); // Use histogram to equalize constrast between nb_classes throughout the image
+ void filterColorize(const LLColor3& color, const LLColor3& alpha); // Colorize with color and alpha per channel
+ void filterContrast(F32 slope, const LLColor3& alpha); // Change contrast according to slope: > 1.0 more contrast, < 1.0 less contrast
+ void filterBrightness(S32 add, const LLColor3& alpha); // Change brightness according to add: > 0 brighter, < 0 darker
+
+ // Filter Primitives
+ void colorTransform(const LLMatrix3 &transform);
+ void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue);
+ void setVignette(EVignetteMode mode, F32 gamma, F32 min);
+ U32* getBrightnessHistogram();
protected:
// Create an image from a local file (generally used in tools)
@@ -267,6 +313,9 @@ protected:
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
+ void computeHistograms();
+ F32 getVignetteAlpha(S32 i, S32 j);
+
public:
static S32 sGlobalRawMemory;
static S32 sRawImageCount;
diff --git a/indra/newview/app_settings/filters/Gotham.xml b/indra/newview/app_settings/filters/Gotham.xml
new file mode 100755
index 0000000000..eb0725e6bf
--- /dev/null
+++ b/indra/newview/app_settings/filters/Gotham.xml
@@ -0,0 +1,30 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>gamma</string>
+ <real>1.5</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>colorize</string>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>grayscale</string>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Hefe.xml b/indra/newview/app_settings/filters/Hefe.xml
new file mode 100755
index 0000000000..527aaee847
--- /dev/null
+++ b/indra/newview/app_settings/filters/Hefe.xml
@@ -0,0 +1,23 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>blend</string>
+ <real>4.0</real>
+ <real>0.5</real>
+ </array>
+ <array>
+ <string>contrast</string>
+ <real>2.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Inkwell.xml b/indra/newview/app_settings/filters/Inkwell.xml
new file mode 100755
index 0000000000..77c88b5fbb
--- /dev/null
+++ b/indra/newview/app_settings/filters/Inkwell.xml
@@ -0,0 +1,14 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.05</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>grayscale</string>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Lomofi.xml b/indra/newview/app_settings/filters/Lomofi.xml
new file mode 100755
index 0000000000..f5ec911e59
--- /dev/null
+++ b/indra/newview/app_settings/filters/Lomofi.xml
@@ -0,0 +1,23 @@
+<llsd>
+ <array>
+ <array>
+ <string>blend</string>
+ <real>4.0</real>
+ <real>0.0</real>
+ </array>
+ <array>
+ <string>linearize</string>
+ <real>0.2</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>brighten</string>
+ <real>20.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Poprocket.xml b/indra/newview/app_settings/filters/Poprocket.xml
new file mode 100755
index 0000000000..7e64003908
--- /dev/null
+++ b/indra/newview/app_settings/filters/Poprocket.xml
@@ -0,0 +1,25 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>fade</string>
+ <real>4.0</real>
+ <real>0.5</real>
+ </array>
+ <array>
+ <string>colorize</string>
+ <real>1.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.4</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Sutro.xml b/indra/newview/app_settings/filters/Sutro.xml
new file mode 100755
index 0000000000..3b0a58f01e
--- /dev/null
+++ b/indra/newview/app_settings/filters/Sutro.xml
@@ -0,0 +1,19 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.05</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>fade</string>
+ <real>4.0</real>
+ <real>0.5</real>
+ </array>
+ <array>
+ <string>sepia</string>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/newview/app_settings/filters/Toaster.xml b/indra/newview/app_settings/filters/Toaster.xml
new file mode 100755
index 0000000000..170a1183ed
--- /dev/null
+++ b/indra/newview/app_settings/filters/Toaster.xml
@@ -0,0 +1,23 @@
+<llsd>
+ <array>
+ <array>
+ <string>contrast</string>
+ <real>0.8</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>fade</string>
+ <real>4.0</real>
+ <real>0.5</real>
+ </array>
+ <array>
+ <string>brighten</string>
+ <real>10.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp
index 0a4c3f091b..675266143d 100644
--- a/indra/newview/llfloaterflickr.cpp
+++ b/indra/newview/llfloaterflickr.cpp
@@ -92,6 +92,8 @@ BOOL LLFlickrPhotoPanel::postBuild()
mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel");
mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox");
mResolutionComboBox->setCommitCallback(boost::bind(&LLFlickrPhotoPanel::updateResolution, this, TRUE));
+ mFilterComboBox = getChild<LLUICtrl>("filters_combobox");
+ mFilterComboBox->setCommitCallback(boost::bind(&LLFlickrPhotoPanel::updateResolution, this, TRUE));
mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
mWorkingLabel = getChild<LLUICtrl>("working_lbl");
mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
@@ -301,33 +303,18 @@ void LLFlickrPhotoPanel::clearAndClose()
void LLFlickrPhotoPanel::updateControls()
{
LLSnapshotLivePreview* previewp = getPreviewView();
- BOOL got_bytes = previewp && previewp->getDataSize() > 0;
BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
- LLSnapshotLivePreview::ESnapshotType shot_type = (previewp ? previewp->getSnapshotType() : LLSnapshotLivePreview::SNAPSHOT_POSTCARD);
// *TODO: Separate maximum size for Web images from postcards
lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
- LLLocale locale(LLLocale::USER_LOCALE);
- std::string bytes_string;
- if (got_snap)
- {
- LLResMgr::getInstance()->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 );
- }
-
- //getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : getString("unknown")); <---uses localized string
- getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : "unknown");
- getChild<LLUICtrl>("file_size_label")->setColor(
- shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD
- && got_bytes
- && previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" ));
-
updateResolution(FALSE);
}
void LLFlickrPhotoPanel::updateResolution(BOOL do_update)
{
- LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
+ LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
+ LLComboBox* filterbox = static_cast<LLComboBox *>(mFilterComboBox);
std::string sdstring = combobox->getSelectedValue();
LLSD sdres;
@@ -336,6 +323,9 @@ void LLFlickrPhotoPanel::updateResolution(BOOL do_update)
S32 width = sdres[0];
S32 height = sdres[1];
+
+ const std::string& filter_name = filterbox->getSimple();
+ llinfos << "Merov : filter name is : " << filter_name << llendl;
LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
if (previewp && combobox->getCurrentIndex() >= 0)
@@ -359,10 +349,16 @@ void LLFlickrPhotoPanel::updateResolution(BOOL do_update)
checkAspectRatio(width);
previewp->getSize(width, height);
+ // Merov :
+ // Get the old filter, compare to the current one "filter_name" and set if changed
+ // If changed, also force the updateSnapshot() here under
+ S32 original_filter = previewp->getFilter();
+ S32 filter = ("Gray Scale" == filter_name ? 1 : 0);
- if(original_width != width || original_height != height)
+ if ((original_width != width) || (original_height != height) || (original_filter != filter))
{
previewp->setSize(width, height);
+ previewp->setFilter(filter);
// hide old preview as the aspect ratio could be wrong
lldebugs << "updating thumbnail" << llendl;
diff --git a/indra/newview/llfloaterflickr.h b/indra/newview/llfloaterflickr.h
index 9a329d4451..1d9e649899 100644
--- a/indra/newview/llfloaterflickr.h
+++ b/indra/newview/llfloaterflickr.h
@@ -63,6 +63,7 @@ private:
LLUICtrl * mSnapshotPanel;
LLUICtrl * mResolutionComboBox;
+ LLUICtrl * mFilterComboBox;
LLUICtrl * mRefreshBtn;
LLUICtrl * mWorkingLabel;
LLUICtrl * mThumbnailPlaceholder;
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 7f578975db..2931178ace 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -89,7 +89,8 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Param
mCameraPos(LLViewerCamera::getInstance()->getOrigin()),
mCameraRot(LLViewerCamera::getInstance()->getQuaternion()),
mSnapshotActive(FALSE),
- mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR)
+ mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR),
+ mFilterType(0)
{
setSnapshotQuality(gSavedSettings.getS32("SnapshotQuality"));
mSnapshotDelayTimer.setTimerExpirySec(0.0f);
@@ -585,7 +586,12 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update)
if(raw)
{
raw->expandToPowerOfTwo();
- mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
+ // Merov : Filter also the thumbnail?
+ if (getFilter() == 1)
+ {
+ raw->filterGrayScale();
+ }
+ mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
mThumbnailUpToDate = TRUE ;
}
@@ -689,6 +695,12 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
}
else
{
+ // Merov : Time to apply the filter to mPreviewImage!!!
+ if (previewp->getFilter() == 1)
+ {
+ previewp->mPreviewImage->filterGrayScale();
+ }
+
// delete any existing image
previewp->mFormattedImage = NULL;
// now create the new one of the appropriate format.
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index 0c63bf47c7..d5ae3b491b 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -95,6 +95,8 @@ public:
void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat type) { mSnapshotFormat = type; }
bool setSnapshotQuality(S32 quality, bool set_by_user = true);
void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; }
+ void setFilter(S32 filter) { mFilterType = filter; }
+ S32 getFilter() { return mFilterType; }
void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f);
void saveWeb();
void saveTexture();
@@ -154,6 +156,7 @@ private:
LLQuaternion mCameraRot;
BOOL mSnapshotActive;
LLViewerWindow::ESnapshotType mSnapshotBufferType;
+ S32 mFilterType; // *TODO: eventually use a string and a named filter
public:
static std::set<LLSnapshotLivePreview*> sList;
diff --git a/indra/newview/skins/default/xui/en/panel_flickr_photo.xml b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml
index b3af271f34..28e3557e15 100644
--- a/indra/newview/skins/default/xui/en/panel_flickr_photo.xml
+++ b/indra/newview/skins/default/xui/en/panel_flickr_photo.xml
@@ -40,19 +40,24 @@
name="1024x768"
value="[i1024,i768]" />
</combo_box>
- <text
- follows="left|top"
- font="SansSerifSmall"
- height="14"
- left="208"
- length="1"
- halign="right"
- name="file_size_label"
- top="9"
- type="string"
- width="50">
- [SIZE] KB
- </text>
+ <combo_box
+ control_name="SocialPhotoFilters"
+ follows="right|top"
+ name="filters_combobox"
+ tool_tip="Image filters"
+ top="6"
+ left="165"
+ height="21"
+ width="135">
+ <combo_box.item
+ label="No Filter"
+ name="NoFilter"
+ value="NoFilter" />
+ <combo_box.item
+ label="Gray Scale"
+ name="GrayScale"
+ value="GrayScale" />
+ </combo_box>
<panel
height="150"
width="250"