Skip to content

Commit 533390a

Browse files
authored
2k image resize (#4444)
* Fix spelling error in variable name * Resize images larger than allowed before upload * Resize bulk images if they are larger than the allow size * Fix indentation error caused by Visual Studio * Fix bulk upload cost calculation
1 parent afdcd35 commit 533390a

File tree

4 files changed

+248
-40
lines changed

4 files changed

+248
-40
lines changed

indra/newview/llfloaterimagepreview.cpp

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "llimagetga.h"
3333
#include "llimagejpeg.h"
3434
#include "llimagepng.h"
35+
#include "llimagej2c.h"
3536

3637
#include "llagent.h"
3738
#include "llagentbenefits.h"
@@ -43,6 +44,10 @@
4344
#include "llrender.h"
4445
#include "llface.h"
4546
#include "llfocusmgr.h"
47+
#include "llfilesystem.h"
48+
#include "llfloaterperms.h"
49+
#include "llnotificationsutil.h"
50+
#include "llstatusbar.h" // can_afford_transaction()
4651
#include "lltextbox.h"
4752
#include "lltoolmgr.h"
4853
#include "llui.h"
@@ -52,6 +57,7 @@
5257
#include "llvoavatar.h"
5358
#include "pipeline.h"
5459
#include "lluictrlfactory.h"
60+
#include "llviewermenufile.h" // upload_new_resource()
5561
#include "llviewershadermgr.h"
5662
#include "llviewertexturelist.h"
5763
#include "llstring.h"
@@ -140,7 +146,7 @@ bool LLFloaterImagePreview::postBuild()
140146
}
141147
}
142148

143-
getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnOK, this));
149+
getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterImagePreview::onBtnOK, this));
144150

145151
return true;
146152
}
@@ -243,6 +249,59 @@ void LLFloaterImagePreview::clearAllPreviewTextures()
243249
}
244250
}
245251

252+
//-----------------------------------------------------------------------------
253+
// onBtnOK()
254+
//-----------------------------------------------------------------------------
255+
void LLFloaterImagePreview::onBtnOK()
256+
{
257+
getChildView("ok_btn")->setEnabled(false); // don't allow inadvertent extra uploads
258+
259+
S32 expected_upload_cost = getExpectedUploadCost();
260+
if (can_afford_transaction(expected_upload_cost))
261+
{
262+
LL_INFOS() << "saving texture: " << mRawImagep->getWidth() << "x" << mRawImagep->getHeight() << LL_ENDL;
263+
// gen a new uuid for this asset
264+
LLTransactionID tid;
265+
tid.generate();
266+
LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
267+
268+
LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
269+
270+
if (formatted->encode(mRawImagep, 0.0f))
271+
{
272+
LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE);
273+
fmt_file.write(formatted->getData(), formatted->getDataSize());
274+
275+
LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo(
276+
tid, LLAssetType::AT_TEXTURE,
277+
getChild<LLUICtrl>("name_form")->getValue().asString(),
278+
getChild<LLUICtrl>("description_form")->getValue().asString(),
279+
0,
280+
LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
281+
LLFloaterPerms::getNextOwnerPerms("Uploads"),
282+
LLFloaterPerms::getGroupPerms("Uploads"),
283+
LLFloaterPerms::getEveryonePerms("Uploads"),
284+
expected_upload_cost
285+
));
286+
287+
upload_new_resource(assetUploadInfo);
288+
}
289+
else
290+
{
291+
LLNotificationsUtil::add("ErrorEncodingImage");
292+
LL_WARNS() << "Error encoding image" << LL_ENDL;
293+
}
294+
}
295+
else
296+
{
297+
LLSD args;
298+
args["COST"] = llformat("%d", expected_upload_cost);
299+
LLNotificationsUtil::add("ErrorCannotAffordUpload", args);
300+
}
301+
302+
closeFloater(false);
303+
}
304+
246305
//-----------------------------------------------------------------------------
247306
// draw()
248307
//-----------------------------------------------------------------------------
@@ -364,19 +423,6 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
364423
return false;
365424
}
366425

367-
S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
368-
S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
369-
370-
if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
371-
{
372-
LLStringUtil::format_map_t args;
373-
args["WIDTH"] = llformat("%d", max_width);
374-
args["HEIGHT"] = llformat("%d", max_height);
375-
376-
mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
377-
return false;
378-
}
379-
380426
// Load the image
381427
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
382428
if (image.isNull())
@@ -399,6 +445,46 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
399445
image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
400446
return false;
401447
}
448+
// Downscale images to fit the max_texture_dimensions_*
449+
S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
450+
S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
451+
452+
S32 orig_width = raw_image->getWidth();
453+
S32 orig_height = raw_image->getHeight();
454+
455+
if (orig_width > max_width || orig_height > max_height)
456+
{
457+
// Calculate scale factors
458+
F32 width_scale = (F32)max_width / (F32)orig_width;
459+
F32 height_scale = (F32)max_height / (F32)orig_height;
460+
F32 scale = llmin(width_scale, height_scale);
461+
462+
// Calculate new dimensions, preserving aspect ratio
463+
S32 new_width = LLImageRaw::contractDimToPowerOfTwo(
464+
llclamp((S32)llroundf(orig_width * scale), 4, max_width)
465+
);
466+
S32 new_height = LLImageRaw::contractDimToPowerOfTwo(
467+
llclamp((S32)llroundf(orig_height * scale), 4, max_height)
468+
);
469+
470+
if (!raw_image->scale(new_width, new_height))
471+
{
472+
LL_WARNS() << "Failed to scale image from "
473+
<< orig_width << "x" << orig_height
474+
<< " to " << new_width << "x" << new_height << LL_ENDL;
475+
return false;
476+
}
477+
478+
// Inform the resident about the resized image
479+
LLSD subs;
480+
subs["[ORIGINAL_WIDTH]"] = orig_width;
481+
subs["[ORIGINAL_HEIGHT]"] = orig_height;
482+
subs["[NEW_WIDTH]"] = new_width;
483+
subs["[NEW_HEIGHT]"] = new_height;
484+
subs["[MAX_WIDTH]"] = max_width;
485+
subs["[MAX_HEIGHT]"] = max_height;
486+
LLNotificationsUtil::add("ImageUploadResized", subs);
487+
}
402488

403489
raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
404490
mRawImagep = raw_image;

indra/newview/llfloaterimagepreview.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ class LLFloaterImagePreview : public LLFloaterNameDesc
126126

127127
void clearAllPreviewTextures();
128128

129+
void onBtnOK();
130+
129131
protected:
130132
static void onPreviewTypeCommit(LLUICtrl*,void*);
131133
void draw() override;

indra/newview/llviewermenufile.cpp

Lines changed: 135 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#include "llviewerassetupload.h"
7070

7171
// linden libraries
72+
#include "llfilesystem.h"
7273
#include "llnotificationsutil.h"
7374
#include "llsdserialize.h"
7475
#include "llsdutil.h"
@@ -544,16 +545,9 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)
544545
if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec))
545546
{
546547
bool resource_upload = false;
547-
if (asset_type == LLAssetType::AT_TEXTURE && allow_2k)
548+
if (asset_type == LLAssetType::AT_TEXTURE)
548549
{
549-
LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec);
550-
if (gDirUtilp->fileExists(filename) && image_frmted && image_frmted->load(filename))
551-
{
552-
S32 biased_width = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getWidth(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
553-
S32 biased_height = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getHeight(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
554-
expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(biased_width, biased_height);
555-
resource_upload = true;
556-
}
550+
resource_upload = true;
557551
}
558552
else if (LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost))
559553
{
@@ -562,23 +556,115 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)
562556

563557
if (resource_upload)
564558
{
565-
LLNewFileResourceUploadInfo* info_p = new LLNewFileResourceUploadInfo(
566-
filename,
567-
asset_name,
568-
asset_name, 0,
569-
LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
570-
LLFloaterPerms::getNextOwnerPerms("Uploads"),
571-
LLFloaterPerms::getGroupPerms("Uploads"),
572-
LLFloaterPerms::getEveryonePerms("Uploads"),
573-
expected_upload_cost);
574-
575-
if (!allow_2k)
559+
if (asset_type == LLAssetType::AT_TEXTURE)
576560
{
577-
info_p->setMaxImageSize(1024);
578-
}
579-
LLResourceUploadInfo::ptr_t uploadInfo(info_p);
561+
std::string exten = gDirUtilp->getExtension(filename);
562+
U32 codec = LLImageBase::getCodecFromExtension(exten);
563+
564+
// Load the image
565+
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
566+
if (image.isNull())
567+
{
568+
LL_WARNS() << "Failed to create image container for " << filename << LL_ENDL;
569+
continue;
570+
}
571+
if (!image->load(filename))
572+
{
573+
LL_WARNS() << "Failed to load image: " << filename << LL_ENDL;
574+
continue;
575+
}
576+
// Decompress or expand it in a raw image structure
577+
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
578+
if (!image->decode(raw_image, 0.0f))
579+
{
580+
LL_WARNS() << "Failed to decode image: " << filename << LL_ENDL;
581+
continue;
582+
}
583+
// Check the image constraints
584+
if ((image->getComponents() != 3) && (image->getComponents() != 4))
585+
{
586+
LL_WARNS() << "Attempted to upload a texture that has " << image->getComponents()
587+
<< " components, but only 3 (RGB) or 4 (RGBA) are allowed." << LL_ENDL;
588+
continue;
589+
}
590+
// Downscale images to fit the max_texture_dimensions_*, or 1024 if allow_2k is false
591+
S32 max_width = allow_2k ? gSavedSettings.getS32("max_texture_dimension_X") : 1024;
592+
S32 max_height = allow_2k ? gSavedSettings.getS32("max_texture_dimension_Y") : 1024;
593+
594+
S32 orig_width = raw_image->getWidth();
595+
S32 orig_height = raw_image->getHeight();
596+
597+
if (orig_width > max_width || orig_height > max_height)
598+
{
599+
// Calculate scale factors
600+
F32 width_scale = (F32)max_width / (F32)orig_width;
601+
F32 height_scale = (F32)max_height / (F32)orig_height;
602+
F32 scale = llmin(width_scale, height_scale);
603+
604+
// Calculate new dimensions, preserving aspect ratio
605+
S32 new_width = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_width * scale), 4, max_width));
606+
S32 new_height = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_height * scale), 4, max_height));
607+
608+
if (!raw_image->scale(new_width, new_height))
609+
{
610+
LL_WARNS() << "Failed to scale image from " << orig_width << "x" << orig_height << " to " << new_width << "x"
611+
<< new_height << LL_ENDL;
612+
continue;
613+
}
614+
615+
// Inform the resident about the resized image
616+
LLSD subs;
617+
subs["[ORIGINAL_WIDTH]"] = orig_width;
618+
subs["[ORIGINAL_HEIGHT]"] = orig_height;
619+
subs["[NEW_WIDTH]"] = new_width;
620+
subs["[NEW_HEIGHT]"] = new_height;
621+
subs["[MAX_WIDTH]"] = max_width;
622+
subs["[MAX_HEIGHT]"] = max_height;
623+
LLNotificationsUtil::add("ImageUploadResized", subs);
624+
}
625+
626+
raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
627+
628+
LLTransactionID tid;
629+
tid.generate();
630+
LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
580631

581-
upload_new_resource(uploadInfo);
632+
LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
633+
634+
if (formatted->encode(raw_image, 0.0f))
635+
{
636+
LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE);
637+
fmt_file.write(formatted->getData(), formatted->getDataSize());
638+
639+
LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo(
640+
tid, LLAssetType::AT_TEXTURE,
641+
asset_name,
642+
asset_name, 0,
643+
LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
644+
LLFloaterPerms::getNextOwnerPerms("Uploads"),
645+
LLFloaterPerms::getGroupPerms("Uploads"),
646+
LLFloaterPerms::getEveryonePerms("Uploads"),
647+
LLAgentBenefitsMgr::current().getTextureUploadCost(raw_image->getWidth(), raw_image->getHeight())
648+
));
649+
650+
upload_new_resource(assetUploadInfo);
651+
}
652+
}
653+
else
654+
{
655+
LLNewFileResourceUploadInfo* info_p = new LLNewFileResourceUploadInfo(
656+
filename,
657+
asset_name,
658+
asset_name, 0,
659+
LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
660+
LLFloaterPerms::getNextOwnerPerms("Uploads"),
661+
LLFloaterPerms::getGroupPerms("Uploads"),
662+
LLFloaterPerms::getEveryonePerms("Uploads"),
663+
expected_upload_cost);
664+
LLResourceUploadInfo::ptr_t uploadInfo(info_p);
665+
666+
upload_new_resource(uploadInfo);
667+
}
582668
}
583669
}
584670

@@ -647,8 +733,31 @@ bool get_bulk_upload_expected_cost(
647733
LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec);
648734
if (gDirUtilp->fileExists(filename) && image_frmted && image_frmted->load(filename))
649735
{
650-
S32 biased_width = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getWidth(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
651-
S32 biased_height = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getHeight(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
736+
S32 biased_width, biased_height;
737+
738+
S32 max_width = allow_2k ? gSavedSettings.getS32("max_texture_dimension_X") : 1024;
739+
S32 max_height = allow_2k ? gSavedSettings.getS32("max_texture_dimension_Y") : 1024;
740+
741+
S32 orig_width = image_frmted->getWidth();
742+
S32 orig_height = image_frmted->getHeight();
743+
744+
if (orig_width > max_width || orig_height > max_height)
745+
{
746+
// Calculate scale factors
747+
F32 width_scale = (F32)max_width / (F32)orig_width;
748+
F32 height_scale = (F32)max_height / (F32)orig_height;
749+
F32 scale = llmin(width_scale, height_scale);
750+
751+
// Calculate new dimensions, preserving aspect ratio
752+
biased_width = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_width * scale), 4, max_width));
753+
biased_height = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_height * scale), 4, max_height));
754+
}
755+
else
756+
{
757+
biased_width = LLImageRaw::biasedDimToPowerOfTwo(orig_width, LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
758+
biased_height = LLImageRaw::biasedDimToPowerOfTwo(orig_height, LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
759+
}
760+
652761
total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(biased_width, biased_height);
653762
S32 area = biased_width * biased_height;
654763
if (area >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)

indra/newview/skins/default/xui/en/notifications.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12619,4 +12619,15 @@ are wearing now.
1261912619
Unable to apply material to the water exclusion surface.
1262012620
<tag>fail</tag>
1262112621
</notification>
12622+
12623+
<notification
12624+
icon="notify.tga"
12625+
name="ImageUploadResized"
12626+
type="alertmodal">
12627+
The texture you are uploading has been resized from [ORIGINAL_WIDTH]x[ORIGINAL_HEIGHT] to [NEW_WIDTH]x[NEW_HEIGHT] in order to to fit the maximum size of [MAX_WIDTH]x[MAX_HEIGHT] pixels.
12628+
<usetemplate
12629+
ignoretext="Image Upload Resized"
12630+
name="okignore"
12631+
yestext="OK"/>
12632+
</notification>
1262212633
</notifications>

0 commit comments

Comments
 (0)