diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index c8a05e1faea6e0244ecc03f88c325bc7f5570879..18e08b94a63b0e2e5ba8d57e22a2300e3a4115b0 100755
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -449,18 +449,8 @@ void LLImageRaw::verticalFlip()
 void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
 {
 	// Find new sizes
-	S32 new_width = MIN_IMAGE_SIZE;
-	S32 new_height = MIN_IMAGE_SIZE;
-
-	while( (new_width < getWidth()) && (new_width < max_dim) )
-	{
-		new_width <<= 1;
-	}
-
-	while( (new_height < getHeight()) && (new_height < max_dim) )
-	{
-		new_height <<= 1;
-	}
+	S32 new_width  = expandDimToPowerOfTwo(getWidth(), max_dim);
+	S32 new_height = expandDimToPowerOfTwo(getHeight(), max_dim);
 
 	scale( new_width, new_height, scale_image );
 }
@@ -468,55 +458,61 @@ void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
 void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image)
 {
 	// Find new sizes
-	S32 new_width = max_dim;
-	S32 new_height = max_dim;
-
-	while( (new_width > getWidth()) && (new_width > MIN_IMAGE_SIZE) )
-	{
-		new_width >>= 1;
-	}
-
-	while( (new_height > getHeight()) && (new_height > MIN_IMAGE_SIZE) )
-	{
-		new_height >>= 1;
-	}
+	S32 new_width  = contractDimToPowerOfTwo(getWidth(), MIN_IMAGE_SIZE);
+	S32 new_height = contractDimToPowerOfTwo(getHeight(), MIN_IMAGE_SIZE);
 
 	scale( new_width, new_height, scale_image );
 }
 
-void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
+// static
+S32 LLImageRaw::biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim)
 {
 	// Strong bias towards rounding down (to save bandwidth)
 	// No bias would mean THRESHOLD == 1.5f;
-	const F32 THRESHOLD = 1.75f; 
-
+	const F32 THRESHOLD = 1.75f;
+    
 	// Find new sizes
-	S32 larger_w = max_dim;	// 2^n >= mWidth
-	S32 smaller_w = max_dim;	// 2^(n-1) <= mWidth
-	while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) )
+	S32 larger_dim  = max_dim;	// 2^n >= curr_dim
+	S32 smaller_dim = max_dim;	// 2^(n-1) <= curr_dim
+	while( (smaller_dim > curr_dim) && (smaller_dim > MIN_IMAGE_SIZE) )
 	{
-		larger_w = smaller_w;
-		smaller_w >>= 1;
+		larger_dim = smaller_dim;
+		smaller_dim >>= 1;
 	}
-	S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w;
+	return ( ((F32)curr_dim / (F32)smaller_dim) > THRESHOLD ) ? larger_dim : smaller_dim;
+}
 
+// static
+S32 LLImageRaw::expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim)
+{
+	S32 new_dim = MIN_IMAGE_SIZE;
+	while( (new_dim < curr_dim) && (new_dim < max_dim) )
+	{
+		new_dim <<= 1;
+	}
+    return new_dim;
+}
 
-	S32 larger_h = max_dim;	// 2^m >= mHeight
-	S32 smaller_h = max_dim;	// 2^(m-1) <= mHeight
-	while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) )
+// static
+S32 LLImageRaw::contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim)
+{
+	S32 new_dim = MAX_IMAGE_SIZE;
+	while( (new_dim > curr_dim) && (new_dim > min_dim) )
 	{
-		larger_h = smaller_h;
-		smaller_h >>= 1;
+		new_dim >>= 1;
 	}
-	S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h;
+    return new_dim;
+}
 
+void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
+{
+	// Find new sizes
+	S32 new_width  = biasedDimToPowerOfTwo(getWidth(),max_dim);
+	S32 new_height = biasedDimToPowerOfTwo(getHeight(),max_dim);
 
 	scale( new_width, new_height );
 }
 
-
-
-
 // Calculates (U8)(255*(a/255.f)*(b/255.f) + 0.5f).  Thanks, Jim Blinn!
 inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b )
 {
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 2277afc5852b6f21d4e1cc7e5b8bd72ad0ae6501..c1ba1e3c2172f9f7463fdeb1fc6710c6a1bab07f 100755
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -205,6 +205,9 @@ class LLImageRaw : public LLImageBase
 
 	void verticalFlip();
 
+    static S32 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
+    static S32 expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
+    static S32 contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim = MIN_IMAGE_SIZE);
 	void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
 	void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
 	void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
diff --git a/indra/newview/llfloaterfacebook.cpp b/indra/newview/llfloaterfacebook.cpp
index 7bf74ef6ba82f179839ddffac3e18ea725522d47..9676dfaf936340513137385980f096291ff7f0f4 100644
--- a/indra/newview/llfloaterfacebook.cpp
+++ b/indra/newview/llfloaterfacebook.cpp
@@ -257,8 +257,6 @@ void LLFacebookPhotoPanel::draw()
 		gl_draw_scaled_image(offset_x, offset_y, 
 			thumbnail_w, thumbnail_h,
 			previewp->getThumbnailImage(), color % alpha);
-
-		previewp->drawPreviewRect(offset_x, offset_y) ;
 	}
 
     // Update the visibility of the working (computing preview) label
@@ -303,6 +301,7 @@ void LLFacebookPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
 			previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
 			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
 			previewp->setSnapshotQuality(mQuality, false);
+            previewp->setThumbnailSubsampled(TRUE);     // We want the preview to reflect the *saved* image
 			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
 
 			updateControls();
diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp
index c34124caf57e52d8d1e79eeed582842585672cdf..fbf4d758bef337419c7edc7b6d2da7ff5741165a 100644
--- a/indra/newview/llfloaterflickr.cpp
+++ b/indra/newview/llfloaterflickr.cpp
@@ -160,8 +160,6 @@ void LLFlickrPhotoPanel::draw()
 		gl_draw_scaled_image(offset_x, offset_y, 
 			thumbnail_w, thumbnail_h,
 			previewp->getThumbnailImage(), color % alpha);
-
-		previewp->drawPreviewRect(offset_x, offset_y) ;
 	}
 
     // Update the visibility of the working (computing preview) label
@@ -204,7 +202,7 @@ void LLFlickrPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
 
 			previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
 			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
-			//previewp->setSnapshotQuality(98);
+            previewp->setThumbnailSubsampled(TRUE);     // We want the preview to reflect the *saved* image
 			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
 
 			updateControls();
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index c3efc26991c8663870190fddd5e6dc95646b64f8..7ba5fc7b872c6c9bd33162fa3310e0c154f218f1 100755
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -436,9 +436,8 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
 	image_res_tb->setVisible(got_snap);
 	if (got_snap)
 	{
-		LLPointer<LLImageRaw> img = previewp->getEncodedImage();
-		image_res_tb->setTextArg("[WIDTH]", llformat("%d", img->getWidth()));
-		image_res_tb->setTextArg("[HEIGHT]", llformat("%d", img->getHeight()));
+		image_res_tb->setTextArg("[WIDTH]", llformat("%d", previewp->getEncodedImageWidth()));
+		image_res_tb->setTextArg("[HEIGHT]", llformat("%d", previewp->getEncodedImageHeight()));
 	}
 
 	floater->getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : floater->getString("unknown"));
diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp
index ea263566a63f7e021017d699114fe2ea1ece9740..68bc4f1c3cf9b97b64ec86477b336b729ee48355 100644
--- a/indra/newview/llfloatertwitter.cpp
+++ b/indra/newview/llfloatertwitter.cpp
@@ -150,8 +150,6 @@ void LLTwitterPhotoPanel::draw()
 		gl_draw_scaled_image(offset_x, offset_y, 
 			thumbnail_w, thumbnail_h,
 			previewp->getThumbnailImage(), color % alpha);
-
-		previewp->drawPreviewRect(offset_x, offset_y) ;
 	}
 
     // Update the visibility of the working (computing preview) label
@@ -190,11 +188,11 @@ void LLTwitterPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
 			LLSnapshotLivePreview::Params p;
 			p.rect(full_screen_rect);
 			LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
-			mPreviewHandle = previewp->getHandle();	
+			mPreviewHandle = previewp->getHandle();
 
 			previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
 			previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
-			//previewp->setSnapshotQuality(98);
+            previewp->setThumbnailSubsampled(TRUE);     // We want the preview to reflect the *saved* image
 			previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
 
 			updateControls();
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index ee74dbdb0f2b65fed59af2d893dac4c6f9290a21..4463dfdc389edb3850bce5253961d485576544d2 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -78,6 +78,7 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Param
 	mThumbnailImage(NULL) ,
 	mThumbnailWidth(0),
 	mThumbnailHeight(0),
+    mThumbnailSubsampled(FALSE),
 	mPreviewImageEncoded(NULL),
 	mFormattedImage(NULL),
 	mShineCountdown(0),
@@ -126,14 +127,7 @@ LLSnapshotLivePreview::~LLSnapshotLivePreview()
 
 void LLSnapshotLivePreview::setMaxImageSize(S32 size) 
 {
-	if(size < MAX_SNAPSHOT_IMAGE_SIZE)
-	{
-		mMaxImageSize = size;
-	}
-	else
-	{
-		mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ;
-	}
+    mMaxImageSize = llmin(size,(S32)(MAX_SNAPSHOT_IMAGE_SIZE));
 }
 
 LLViewerTexture* LLSnapshotLivePreview::getCurrentImage()
@@ -141,32 +135,17 @@ LLViewerTexture* LLSnapshotLivePreview::getCurrentImage()
 	return mViewerImage[mCurImageIndex];
 }
 
-F32 LLSnapshotLivePreview::getAspect()
-{
-	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
-	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
-
-	if (!mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
-	{
-		return image_aspect_ratio;
-	}
-	else
-	{
-		return window_aspect_ratio;
-	}
-}
-
 F32 LLSnapshotLivePreview::getImageAspect()
 {
 	if (!getCurrentImage())
 	{
 		return 0.f;
 	}
-
-	return getAspect() ;	
+	// mKeepAspectRatio) == gSavedSettings.getBOOL("KeepAspectForSnapshot"))
+    return (mKeepAspectRatio ? ((F32)getRect().getWidth()) / ((F32)getRect().getHeight()) : ((F32)getWidth()) / ((F32)getHeight()));
 }
 
-void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay) 
+void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay)
 {
 	// Invalidate current image.
 	lldebugs << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << llendl;
@@ -483,58 +462,49 @@ BOOL LLSnapshotLivePreview::setThumbnailImageSize()
 	{
 		return FALSE ;
 	}
-	S32 window_width = gViewerWindow->getWindowWidthRaw() ;
-	S32 window_height = gViewerWindow->getWindowHeightRaw() ;
+	S32 width  = (mThumbnailSubsampled ? mPreviewImage->getWidth()  : gViewerWindow->getWindowWidthRaw());
+	S32 height = (mThumbnailSubsampled ? mPreviewImage->getHeight() : gViewerWindow->getWindowHeightRaw()) ;
 
-	F32 window_aspect_ratio = ((F32)window_width) / ((F32)window_height);
+	F32 aspect_ratio = ((F32)width) / ((F32)height);
 
 	// UI size for thumbnail
 	// *FIXME: the rect does not change, so maybe there's no need to recalculate max w/h.
-	const LLRect& thumbnail_rect = mThumbnailPlaceholderRect;
-	S32 max_width = thumbnail_rect.getWidth();
-	S32 max_height = thumbnail_rect.getHeight();
+	//const LLRect& thumbnail_rect = mThumbnailPlaceholderRect;
+	S32 max_width  = mThumbnailPlaceholderRect.getWidth();
+	S32 max_height = mThumbnailPlaceholderRect.getHeight();
 
-	if (window_aspect_ratio > (F32)max_width / max_height)
+	if (aspect_ratio > (F32)max_width / (F32)max_height)
 	{
 		// image too wide, shrink to width
 		mThumbnailWidth = max_width;
-		mThumbnailHeight = llround((F32)max_width / window_aspect_ratio);
+		mThumbnailHeight = llround((F32)max_width / aspect_ratio);
 	}
 	else
 	{
 		// image too tall, shrink to height
 		mThumbnailHeight = max_height;
-		mThumbnailWidth = llround((F32)max_height * window_aspect_ratio);
+		mThumbnailWidth = llround((F32)max_height * aspect_ratio);
 	}
 
-	if(mThumbnailWidth > window_width || mThumbnailHeight > window_height)
+	if (mThumbnailWidth > width || mThumbnailHeight > height)
 	{
 		return FALSE ;//if the window is too small, ignore thumbnail updating.
 	}
 
 	S32 left = 0 , top = mThumbnailHeight, right = mThumbnailWidth, bottom = 0 ;
-	if(!mKeepAspectRatio)
+	if(!mKeepAspectRatio && !mThumbnailSubsampled)
 	{
-		F32 ratio_x = (F32)getWidth() / window_width ;
-		F32 ratio_y = (F32)getHeight() / window_height ;
+		F32 ratio_x = (F32)getWidth()  / width ;
+		F32 ratio_y = (F32)getHeight() / height ;
 
-		//if(getWidth() > window_width ||
-		//	getHeight() > window_height )
-		{
-			if(ratio_x > ratio_y)
-			{
-				top = (S32)(top * ratio_y / ratio_x) ;
-			}
-			else
-			{
-				right = (S32)(right * ratio_x / ratio_y) ;
-			}			
-		}
-		//else
-		//{
-		//	right = (S32)(right * ratio_x) ;
-		//	top = (S32)(top * ratio_y) ;
-		//}
+        if (ratio_x > ratio_y)
+        {
+            top = (S32)(top * ratio_y / ratio_x) ;
+        }
+        else
+        {
+            right = (S32)(right * ratio_x / ratio_y) ;
+        }
 		left = (S32)((mThumbnailWidth - right) * 0.5f) ;
 		bottom = (S32)((mThumbnailHeight - top) * 0.5f) ;
 		top += bottom ;
@@ -576,18 +546,41 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update)
 	}		
 
 	LLPointer<LLImageRaw> raw = new LLImageRaw;
-	if(!gViewerWindow->thumbnailSnapshot(raw,
-		mThumbnailWidth, mThumbnailHeight,
-		gSavedSettings.getBOOL("RenderUIInSnapshot"),
-		FALSE,
-		mSnapshotBufferType) )								
-	{
-		raw = NULL ;
-	}
-
-	if(raw)
+    
+    if (mThumbnailSubsampled)
+    {
+        // The thumbnail is be a subsampled version of the preview (used in SL Share previews, i.e. Flickr, Twitter, Facebook)
+		raw->resize( mPreviewImage->getWidth(),
+                     mPreviewImage->getHeight(),
+                     mPreviewImage->getComponents());
+        raw->copy(mPreviewImage);
+        // Scale to the thumbnal size modulo a power of 2
+        S32 width  = LLImageRaw::expandDimToPowerOfTwo(mThumbnailWidth,MAX_IMAGE_SIZE);
+        S32 height = LLImageRaw::expandDimToPowerOfTwo(mThumbnailHeight,MAX_IMAGE_SIZE);
+        if (!raw->scale(width, height))
+        {
+            raw = NULL ;
+        }
+    }
+    else
+    {
+        // The thumbnail is a screen view with screen grab positioning preview
+        if(!gViewerWindow->thumbnailSnapshot(raw,
+                                         mThumbnailWidth, mThumbnailHeight,
+                                         gSavedSettings.getBOOL("RenderUIInSnapshot"),
+                                         FALSE,
+                                         mSnapshotBufferType) )
+        {
+            raw = NULL ;
+        }
+        else
+        {
+            raw->expandToPowerOfTwo();
+        }
+    }
+    
+	if (raw)
 	{
-		raw->expandToPowerOfTwo();
         // Filter the thumbnail
         if (getFilter() != "")
         {
@@ -650,26 +643,22 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 	}
 
 	// time to produce a snapshot
-	previewp->setThumbnailImageSize();
+    //previewp->setThumbnailImageSize();
 
 	lldebugs << "producing snapshot" << llendl;
+	llinfos << "Merov : producing snapshot" << llendl;
 	if (!previewp->mPreviewImage)
 	{
 		previewp->mPreviewImage = new LLImageRaw;
 	}
 
-	if (!previewp->mPreviewImageEncoded)
-	{
-		previewp->mPreviewImageEncoded = new LLImageRaw;
-	}
-
 	previewp->setVisible(FALSE);
 	previewp->setEnabled(FALSE);
 
 	previewp->getWindow()->incBusyCount();
 	previewp->setImageScaled(FALSE);
 
-	// grab the raw image and encode it into desired format
+	// grab the raw image
 	if(gViewerWindow->rawSnapshot(
 		previewp->mPreviewImage,
 		previewp->getWidth(),
@@ -681,123 +670,60 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 		previewp->mSnapshotBufferType,
 		previewp->getMaxImageSize()))
 	{
-		previewp->mPreviewImageEncoded->resize(
-			previewp->mPreviewImage->getWidth(), 
-			previewp->mPreviewImage->getHeight(), 
-			previewp->mPreviewImage->getComponents());
+        // Invalidate/delete any existing encoded image
+        previewp->mPreviewImageEncoded = NULL;
+        // Invalidate/delete any existing formatted image
+        previewp->mFormattedImage = NULL;
+        // Update the data size
+        previewp->estimateDataSize();
 
-		if(previewp->getSnapshotType() == SNAPSHOT_TEXTURE)
-		{
-			lldebugs << "Encoding new image of format J2C" << llendl;
-			LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
-			LLPointer<LLImageRaw> scaled = new LLImageRaw(
-				previewp->mPreviewImage->getData(),
-				previewp->mPreviewImage->getWidth(),
-				previewp->mPreviewImage->getHeight(),
-				previewp->mPreviewImage->getComponents());
-
-			scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
-			previewp->setImageScaled(TRUE);
-			if (formatted->encode(scaled, 0.f))
-			{
-				previewp->mDataSize = formatted->getDataSize();
-				formatted->decode(previewp->mPreviewImageEncoded, 0);
-			}
-		}
-		else
-		{
-            // Apply the filter to mPreviewImage
-            if (previewp->getFilter() != "")
+        // Full size preview is set: get the decoded image result and save it for animation
+        if (gSavedSettings.getBOOL("UseFreezeFrame"))
+        {
+            // Get the decoded version of the formatted image
+            previewp->getEncodedImage();
+            
+            // We need to scale that a bit for display...
+            LLPointer<LLImageRaw> scaled = new LLImageRaw(
+                previewp->mPreviewImageEncoded->getData(),
+                previewp->mPreviewImageEncoded->getWidth(),
+			    previewp->mPreviewImageEncoded->getHeight(),
+			    previewp->mPreviewImageEncoded->getComponents());
+
+            if (!scaled->isBufferInvalid())
             {
-                std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(previewp->getFilter());
-                if (filter_path != "")
+                // leave original image dimensions, just scale up texture buffer
+                if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
                 {
-                    LLImageFilter filter(filter_path);
-                    filter.executeFilter(previewp->mPreviewImage);
+                    // go ahead and shrink image to appropriate power of 2 for display
+                    scaled->biasedScaleToPowerOfTwo(1024);
+                    previewp->setImageScaled(TRUE);
                 }
                 else
                 {
-                    llwarns << "Couldn't find a path to the following filter : " << previewp->getFilter() << llendl;
+                    // expand image but keep original image data intact
+                    scaled->expandToPowerOfTwo(1024, FALSE);
                 }
-            }
-            
-			// delete any existing image
-			previewp->mFormattedImage = NULL;
-			// now create the new one of the appropriate format.
-			LLFloaterSnapshot::ESnapshotFormat format = previewp->getSnapshotFormat();
-			lldebugs << "Encoding new image of format " << format << llendl;
 
-			switch(format)
-			{
-			case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
-				previewp->mFormattedImage = new LLImagePNG(); 
-				break;
-			case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
-				previewp->mFormattedImage = new LLImageJPEG(previewp->mSnapshotQuality); 
-				break;
-			case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
-				previewp->mFormattedImage = new LLImageBMP(); 
-				break;
-			}
-			if (previewp->mFormattedImage->encode(previewp->mPreviewImage, 0))
-			{
-				previewp->mDataSize = previewp->mFormattedImage->getDataSize();
-				// special case BMP to copy instead of decode otherwise decode will crash.
-				if(format == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP)
-				{
-					previewp->mPreviewImageEncoded->copy(previewp->mPreviewImage);
-				}
-				else
-				{
-					previewp->mFormattedImage->decode(previewp->mPreviewImageEncoded, 0);
-				}
-			}
-		}
+                previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
+                LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
+                gGL.getTexUnit(0)->bind(curr_preview_image);
+                curr_preview_image->setFilteringOption(previewp->getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
+                curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
 
-		LLPointer<LLImageRaw> scaled = new LLImageRaw(
-			previewp->mPreviewImageEncoded->getData(),
-			previewp->mPreviewImageEncoded->getWidth(),
-			previewp->mPreviewImageEncoded->getHeight(),
-			previewp->mPreviewImageEncoded->getComponents());
-
-		if(!scaled->isBufferInvalid())
-		{
-			// leave original image dimensions, just scale up texture buffer
-			if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
-			{
-				// go ahead and shrink image to appropriate power of 2 for display
-				scaled->biasedScaleToPowerOfTwo(1024);
-				previewp->setImageScaled(TRUE);
-			}
-			else
-			{
-				// expand image but keep original image data intact
-				scaled->expandToPowerOfTwo(1024, FALSE);
-			}
-
-			previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
-			LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
-			gGL.getTexUnit(0)->bind(curr_preview_image);
-			if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE)
-			{
-				curr_preview_image->setFilteringOption(LLTexUnit::TFO_POINT);
-			}
-			else
-			{
-				curr_preview_image->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
-			}
-			curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
-
-			previewp->mSnapshotUpToDate = TRUE;
-			previewp->generateThumbnailImage(TRUE) ;
-
-			previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
-			previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
-		}
+                previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
+                previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
+            }
+        }
+        // K, the snapshot is updated...
+        previewp->mSnapshotUpToDate = TRUE;
+        
+        // We need to update the thumbnail though
+        previewp->setThumbnailImageSize();
+        previewp->generateThumbnailImage(TRUE) ;
 	}
 	previewp->getWindow()->decBusyCount();
-	// only show fullscreen preview when in freeze frame mode
-	previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame"));
+	previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame")); // only show fullscreen preview when in freeze frame mode
 	previewp->mSnapshotDelayTimer.stop();
 	previewp->mSnapshotActive = FALSE;
 
@@ -806,6 +732,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 		previewp->generateThumbnailImage() ;
 	}
 	lldebugs << "done creating snapshot" << llendl;
+	llinfos << "Merov : Done creating snapshot" << llendl;
 	LLFloaterSnapshot::postUpdate();
 	LLFloaterFacebook::postUpdate();
 	LLFloaterFlickr::postUpdate();
@@ -814,6 +741,153 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 	return TRUE;
 }
 
+S32 LLSnapshotLivePreview::getEncodedImageWidth() const
+{
+    S32 width = getWidth();
+    if (getSnapshotType() == SNAPSHOT_TEXTURE)
+    {
+        width = LLImageRaw::biasedDimToPowerOfTwo(width,MAX_TEXTURE_SIZE);
+    }
+    return width;
+}
+S32 LLSnapshotLivePreview::getEncodedImageHeight() const
+{
+    S32 height = getHeight();
+    if (getSnapshotType() == SNAPSHOT_TEXTURE)
+    {
+        height = LLImageRaw::biasedDimToPowerOfTwo(height,MAX_TEXTURE_SIZE);
+    }
+    return height;
+}
+
+LLPointer<LLImageRaw> LLSnapshotLivePreview::getEncodedImage()
+{
+	if (!mPreviewImageEncoded)
+	{
+		mPreviewImageEncoded = new LLImageRaw;
+    
+		mPreviewImageEncoded->resize(
+            mPreviewImage->getWidth(),
+            mPreviewImage->getHeight(),
+            mPreviewImage->getComponents());
+        
+		if (getSnapshotType() == SNAPSHOT_TEXTURE)
+		{
+            // We don't store the intermediate formatted image in mFormattedImage in the J2C case 
+			lldebugs << "Encoding new image of format J2C" << llendl;
+			LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
+            // Copy the preview
+			LLPointer<LLImageRaw> scaled = new LLImageRaw(
+                                                          mPreviewImage->getData(),
+                                                          mPreviewImage->getWidth(),
+                                                          mPreviewImage->getHeight(),
+                                                          mPreviewImage->getComponents());
+            // Scale it as required by J2C
+			scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
+			setImageScaled(TRUE);
+            // Compress to J2C
+			if (formatted->encode(scaled, 0.f))
+			{
+                // We can update the data size precisely at that point
+				mDataSize = formatted->getDataSize();
+                // Decompress back
+				formatted->decode(mPreviewImageEncoded, 0);
+			}
+		}
+		else
+		{
+            // Update mFormattedImage if necessary
+            getFormattedImage();
+            if (getSnapshotFormat() == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP)
+            {
+                // BMP hack : copy instead of decode otherwise decode will crash.
+                mPreviewImageEncoded->copy(mPreviewImage);
+            }
+            else
+            {
+                // Decode back
+                mFormattedImage->decode(mPreviewImageEncoded, 0);
+            }
+		}
+	}
+    return mPreviewImageEncoded;
+}
+
+// We actually estimate the data size so that we do not require actual compression when showing the preview
+// Note : whenever formatted image is computed, mDataSize will be updated to reflect the true size
+void LLSnapshotLivePreview::estimateDataSize()
+{
+    // Compression ratio
+    F32 ratio = 1.0;
+    
+    if (getSnapshotType() == SNAPSHOT_TEXTURE)
+    {
+        ratio = 8.0;    // This is what we shoot for when compressing to J2C
+    }
+    else
+    {
+        LLFloaterSnapshot::ESnapshotFormat format = getSnapshotFormat();
+        switch (format)
+        {
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
+                ratio = 3.0;    // Average observed PNG compression ratio
+                break;
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
+                // Observed from JPG compression tests
+                ratio = (110 - mSnapshotQuality) / 2;
+                break;
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
+                ratio = 1.0;    // No compression with BMP
+                break;
+        }
+    }
+    mDataSize = (S32)((F32)mPreviewImage->getDataSize() / ratio);
+}
+
+LLPointer<LLImageFormatted>	LLSnapshotLivePreview::getFormattedImage()
+{
+    if (!mFormattedImage)
+    {
+        // Apply the filter to mPreviewImage
+        if (getFilter() != "")
+        {
+            std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(getFilter());
+            if (filter_path != "")
+            {
+                LLImageFilter filter(filter_path);
+                filter.executeFilter(mPreviewImage);
+            }
+            else
+            {
+                llwarns << "Couldn't find a path to the following filter : " << getFilter() << llendl;
+            }
+        }
+        
+        // Create the new formatted image of the appropriate format.
+        LLFloaterSnapshot::ESnapshotFormat format = getSnapshotFormat();
+        lldebugs << "Encoding new image of format " << format << llendl;
+            
+        switch (format)
+        {
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
+                mFormattedImage = new LLImagePNG();
+                break;
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
+                mFormattedImage = new LLImageJPEG(mSnapshotQuality);
+                break;
+            case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
+                mFormattedImage = new LLImageBMP();
+                break;
+        }
+        if (mFormattedImage->encode(mPreviewImage, 0))
+        {
+            // We can update the data size precisely at that point
+            mDataSize = mFormattedImage->getDataSize();
+        }
+    }
+    return mFormattedImage;
+}
+
 void LLSnapshotLivePreview::setSize(S32 w, S32 h)
 {
 	lldebugs << "setSize(" << w << ", " << h << ")" << llendl;
@@ -875,12 +949,14 @@ void LLSnapshotLivePreview::saveTexture()
 	}
 
 	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_SNAPSHOT_COUNT );
-
-	mDataSize = 0;
 }
 
 BOOL LLSnapshotLivePreview::saveLocal()
 {
+    // Update mFormattedImage if necessary
+    getFormattedImage();
+    
+    // Save the formatted image
 	BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage);
 
 	if(success)
@@ -892,6 +968,9 @@ BOOL LLSnapshotLivePreview::saveLocal()
 
 void LLSnapshotLivePreview::saveWeb()
 {
+    // Update mFormattedImage if necessary
+    getFormattedImage();
+    
 	// *FIX: Will break if the window closes because of CloseSnapshotOnKeep!
 	// Needs to pass on ownership of the image.
 	LLImageJPEG* jpg = dynamic_cast<LLImageJPEG*>(mFormattedImage.get());
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index 6addc87de2e647108a8b05bffd8d2747f6d57b64..4fd6dedeed14c04b1b580b5655192305bc78e8ff 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -70,6 +70,9 @@ class LLSnapshotLivePreview : public LLView
 	void getSize(S32& w, S32& h) const;
 	S32 getWidth() const { return mWidth[mCurImageIndex]; }
 	S32 getHeight() const { return mHeight[mCurImageIndex]; }
+    S32 getEncodedImageWidth() const;
+    S32 getEncodedImageHeight() const;
+    void estimateDataSize();
 	S32 getDataSize() const { return mDataSize; }
 	void setMaxImageSize(S32 size) ;
 	S32  getMaxImageSize() {return mMaxImageSize ;}
@@ -83,9 +86,10 @@ class LLSnapshotLivePreview : public LLView
 	S32  getThumbnailHeight() const { return mThumbnailHeight ; }
 	BOOL getThumbnailLock() const { return mThumbnailUpdateLock ; }
 	BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;}
+    void setThumbnailSubsampled(BOOL subsampled) { mThumbnailSubsampled = subsampled; }
+
 	LLViewerTexture* getCurrentImage();
 	F32 getImageAspect();
-	F32 getAspect() ;
 	const LLRect& getImageRect() const { return mImageRect[mCurImageIndex]; }
 	BOOL isImageScaled() const { return mImageScaled[mCurImageIndex]; }
 	void setImageScaled(BOOL scaled) { mImageScaled[mCurImageIndex] = scaled; }
@@ -96,14 +100,14 @@ class LLSnapshotLivePreview : public LLView
 	bool setSnapshotQuality(S32 quality, bool set_by_user = true);
 	void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; }
     void setFilter(std::string filter_name) { mFilterName = filter_name; }
-    std::string  getFilter() { return mFilterName; }
+    std::string  getFilter() const { return mFilterName; }
 	void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f);
 	void saveWeb();
 	void saveTexture();
 	BOOL saveLocal();
 
-	LLPointer<LLImageFormatted>	getFormattedImage() const { return mFormattedImage; }
-	LLPointer<LLImageRaw>		getEncodedImage() const { return mPreviewImageEncoded; }
+	LLPointer<LLImageFormatted>	getFormattedImage();
+	LLPointer<LLImageRaw>		getEncodedImage();
 
 	/// Sets size of preview thumbnail image and thhe surrounding rect.
 	void setThumbnailPlaceholderRect(const LLRect& rect) {mThumbnailPlaceholderRect = rect; }
@@ -135,8 +139,10 @@ class LLSnapshotLivePreview : public LLView
 	BOOL                        mThumbnailUpdateLock ;
 	BOOL                        mThumbnailUpToDate ;
 	LLRect                      mThumbnailPlaceholderRect;
+    BOOL                        mThumbnailSubsampled; // TRUE is the thumbnail is a subsampled version of the mPreviewImage
 
 	S32							mCurImageIndex;
+    // The logic is mPreviewImage (raw frame) -> mFormattedImage (formatted / filtered) -> mPreviewImageEncoded (decoded back, to show artifacts)
 	LLPointer<LLImageRaw>		mPreviewImage;
 	LLPointer<LLImageRaw>		mPreviewImageEncoded;
 	LLPointer<LLImageFormatted>	mFormattedImage;