diff options
| author | Kyler "Félix" Eastridge <felix.wolfz@gmail.com> | 2025-07-26 20:18:26 +0100 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-26 12:18:26 -0700 | 
| commit | 533390a531fb1f82f7f14c6ab3bf3cfa6d806cd1 (patch) | |
| tree | 8aa7c42b1c5fe9cdef5cb2b80d55d4977d31df24 | |
| parent | afdcd356db0a496e8916645eeebc8a03755ee0bd (diff) | |
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
| -rw-r--r-- | indra/newview/llfloaterimagepreview.cpp | 114 | ||||
| -rw-r--r-- | indra/newview/llfloaterimagepreview.h | 2 | ||||
| -rw-r--r-- | indra/newview/llviewermenufile.cpp | 161 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 11 | 
4 files changed, 248 insertions, 40 deletions
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 989e1d8d04..49e557a6cb 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -32,6 +32,7 @@  #include "llimagetga.h"  #include "llimagejpeg.h"  #include "llimagepng.h" +#include "llimagej2c.h"  #include "llagent.h"  #include "llagentbenefits.h" @@ -43,6 +44,10 @@  #include "llrender.h"  #include "llface.h"  #include "llfocusmgr.h" +#include "llfilesystem.h" +#include "llfloaterperms.h" +#include "llnotificationsutil.h" +#include "llstatusbar.h"    // can_afford_transaction()  #include "lltextbox.h"  #include "lltoolmgr.h"  #include "llui.h" @@ -52,6 +57,7 @@  #include "llvoavatar.h"  #include "pipeline.h"  #include "lluictrlfactory.h" +#include "llviewermenufile.h"   // upload_new_resource()  #include "llviewershadermgr.h"  #include "llviewertexturelist.h"  #include "llstring.h" @@ -140,7 +146,7 @@ bool LLFloaterImagePreview::postBuild()          }      } -    getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnOK, this)); +    getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterImagePreview::onBtnOK, this));      return true;  } @@ -244,6 +250,59 @@ void LLFloaterImagePreview::clearAllPreviewTextures()  }  //----------------------------------------------------------------------------- +// onBtnOK() +//----------------------------------------------------------------------------- +void LLFloaterImagePreview::onBtnOK() +{ +    getChildView("ok_btn")->setEnabled(false); // don't allow inadvertent extra uploads + +    S32 expected_upload_cost = getExpectedUploadCost(); +    if (can_afford_transaction(expected_upload_cost)) +    { +        LL_INFOS() << "saving texture: " << mRawImagep->getWidth() << "x" << mRawImagep->getHeight() << LL_ENDL; +        // gen a new uuid for this asset +        LLTransactionID tid; +        tid.generate(); +        LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + +        LLPointer<LLImageJ2C> formatted = new LLImageJ2C; + +        if (formatted->encode(mRawImagep, 0.0f)) +        { +            LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE); +            fmt_file.write(formatted->getData(), formatted->getDataSize()); + +            LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo( +                tid, LLAssetType::AT_TEXTURE, +                getChild<LLUICtrl>("name_form")->getValue().asString(), +                getChild<LLUICtrl>("description_form")->getValue().asString(), +                0, +                LLFolderType::FT_NONE, LLInventoryType::IT_NONE, +                LLFloaterPerms::getNextOwnerPerms("Uploads"), +                LLFloaterPerms::getGroupPerms("Uploads"), +                LLFloaterPerms::getEveryonePerms("Uploads"), +                expected_upload_cost +            )); + +            upload_new_resource(assetUploadInfo); +        } +        else +        { +            LLNotificationsUtil::add("ErrorEncodingImage"); +            LL_WARNS() << "Error encoding image" << LL_ENDL; +        } +    } +    else +    { +        LLSD args; +        args["COST"] = llformat("%d", expected_upload_cost); +        LLNotificationsUtil::add("ErrorCannotAffordUpload", args); +    } + +    closeFloater(false); +} + +//-----------------------------------------------------------------------------  // draw()  //-----------------------------------------------------------------------------  void LLFloaterImagePreview::draw() @@ -364,19 +423,6 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)          return false;      } -    S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); -    S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); - -    if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) -    { -        LLStringUtil::format_map_t args; -        args["WIDTH"] = llformat("%d", max_width); -        args["HEIGHT"] = llformat("%d", max_height); - -        mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); -        return false; -    } -      // Load the image      LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);      if (image.isNull()) @@ -399,6 +445,46 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)          image->setLastError("Image files with less than 3 or more than 4 components are not supported.");          return false;      } +    // Downscale images to fit the max_texture_dimensions_* +    S32 max_width  = gSavedSettings.getS32("max_texture_dimension_X"); +    S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); + +    S32 orig_width  = raw_image->getWidth(); +    S32 orig_height = raw_image->getHeight(); + +    if (orig_width > max_width || orig_height > max_height) +    { +        // Calculate scale factors +        F32 width_scale  = (F32)max_width / (F32)orig_width; +        F32 height_scale = (F32)max_height / (F32)orig_height; +        F32 scale        = llmin(width_scale, height_scale); + +        // Calculate new dimensions, preserving aspect ratio +        S32 new_width  = LLImageRaw::contractDimToPowerOfTwo( +            llclamp((S32)llroundf(orig_width * scale), 4, max_width) +        ); +        S32 new_height = LLImageRaw::contractDimToPowerOfTwo( +            llclamp((S32)llroundf(orig_height * scale), 4, max_height) +        ); + +        if (!raw_image->scale(new_width, new_height)) +        { +            LL_WARNS() << "Failed to scale image from " +                       << orig_width << "x" << orig_height +                       << " to " << new_width << "x" << new_height << LL_ENDL; +            return false; +        } + +        // Inform the resident about the resized image +        LLSD subs; +        subs["[ORIGINAL_WIDTH]"]  = orig_width; +        subs["[ORIGINAL_HEIGHT]"] = orig_height; +        subs["[NEW_WIDTH]"]       = new_width; +        subs["[NEW_HEIGHT]"]      = new_height; +        subs["[MAX_WIDTH]"]       = max_width; +        subs["[MAX_HEIGHT]"]      = max_height; +        LLNotificationsUtil::add("ImageUploadResized", subs); +    }      raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);      mRawImagep = raw_image; diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h index ed395722de..0ebb96a768 100644 --- a/indra/newview/llfloaterimagepreview.h +++ b/indra/newview/llfloaterimagepreview.h @@ -126,6 +126,8 @@ public:      void clearAllPreviewTextures(); +    void onBtnOK(); +  protected:      static void     onPreviewTypeCommit(LLUICtrl*,void*);      void            draw() override; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 9743ec0c59..316f841717 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -69,6 +69,7 @@  #include "llviewerassetupload.h"  // linden libraries +#include "llfilesystem.h"  #include "llnotificationsutil.h"  #include "llsdserialize.h"  #include "llsdutil.h" @@ -544,16 +545,9 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)          if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec))          {              bool resource_upload = false; -            if (asset_type == LLAssetType::AT_TEXTURE && allow_2k) +            if (asset_type == LLAssetType::AT_TEXTURE)              { -                LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec); -                if (gDirUtilp->fileExists(filename) && image_frmted && image_frmted->load(filename)) -                { -                    S32 biased_width = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getWidth(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); -                    S32 biased_height = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getHeight(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); -                    expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(biased_width, biased_height); -                    resource_upload = true; -                } +                resource_upload = true;              }              else if (LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost))              { @@ -562,23 +556,115 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)              if (resource_upload)              { -                LLNewFileResourceUploadInfo* info_p = new LLNewFileResourceUploadInfo( -                    filename, -                    asset_name, -                    asset_name, 0, -                    LLFolderType::FT_NONE, LLInventoryType::IT_NONE, -                    LLFloaterPerms::getNextOwnerPerms("Uploads"), -                    LLFloaterPerms::getGroupPerms("Uploads"), -                    LLFloaterPerms::getEveryonePerms("Uploads"), -                    expected_upload_cost); - -                if (!allow_2k) +                if (asset_type == LLAssetType::AT_TEXTURE)                  { -                    info_p->setMaxImageSize(1024); -                } -                LLResourceUploadInfo::ptr_t uploadInfo(info_p); +                    std::string exten = gDirUtilp->getExtension(filename); +                    U32         codec = LLImageBase::getCodecFromExtension(exten); + +                    // Load the image +                    LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); +                    if (image.isNull()) +                    { +                        LL_WARNS() << "Failed to create image container for " << filename << LL_ENDL; +                        continue; +                    } +                    if (!image->load(filename)) +                    { +                        LL_WARNS() << "Failed to load image: " << filename << LL_ENDL; +                        continue; +                    } +                    // Decompress or expand it in a raw image structure +                    LLPointer<LLImageRaw> raw_image = new LLImageRaw; +                    if (!image->decode(raw_image, 0.0f)) +                    { +                        LL_WARNS() << "Failed to decode image: " << filename << LL_ENDL; +                        continue; +                    } +                    // Check the image constraints +                    if ((image->getComponents() != 3) && (image->getComponents() != 4)) +                    { +                        LL_WARNS() << "Attempted to upload a texture that has " << image->getComponents() +                                   << " components, but only 3 (RGB) or 4 (RGBA) are allowed." << LL_ENDL; +                        continue; +                    } +                    // Downscale images to fit the max_texture_dimensions_*, or 1024 if allow_2k is false +                    S32 max_width  = allow_2k ? gSavedSettings.getS32("max_texture_dimension_X") : 1024; +                    S32 max_height = allow_2k ? gSavedSettings.getS32("max_texture_dimension_Y") : 1024; + +                    S32 orig_width  = raw_image->getWidth(); +                    S32 orig_height = raw_image->getHeight(); + +                    if (orig_width > max_width || orig_height > max_height) +                    { +                        // Calculate scale factors +                        F32 width_scale  = (F32)max_width / (F32)orig_width; +                        F32 height_scale = (F32)max_height / (F32)orig_height; +                        F32 scale        = llmin(width_scale, height_scale); + +                        // Calculate new dimensions, preserving aspect ratio +                        S32 new_width  = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_width * scale), 4, max_width)); +                        S32 new_height = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_height * scale), 4, max_height)); + +                        if (!raw_image->scale(new_width, new_height)) +                        { +                            LL_WARNS() << "Failed to scale image from " << orig_width << "x" << orig_height << " to " << new_width << "x" +                                       << new_height << LL_ENDL; +                            continue; +                        } + +                        // Inform the resident about the resized image +                        LLSD subs; +                        subs["[ORIGINAL_WIDTH]"]  = orig_width; +                        subs["[ORIGINAL_HEIGHT]"] = orig_height; +                        subs["[NEW_WIDTH]"]       = new_width; +                        subs["[NEW_HEIGHT]"]      = new_height; +                        subs["[MAX_WIDTH]"]       = max_width; +                        subs["[MAX_HEIGHT]"]      = max_height; +                        LLNotificationsUtil::add("ImageUploadResized", subs); +                    } + +                    raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + +                    LLTransactionID tid; +                    tid.generate(); +                    LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); -                upload_new_resource(uploadInfo); +                    LLPointer<LLImageJ2C> formatted = new LLImageJ2C; + +                    if (formatted->encode(raw_image, 0.0f)) +                    { +                        LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE); +                        fmt_file.write(formatted->getData(), formatted->getDataSize()); + +                        LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo( +                            tid, LLAssetType::AT_TEXTURE, +                            asset_name, +                            asset_name, 0, +                            LLFolderType::FT_NONE, LLInventoryType::IT_NONE, +                            LLFloaterPerms::getNextOwnerPerms("Uploads"), +                            LLFloaterPerms::getGroupPerms("Uploads"), +                            LLFloaterPerms::getEveryonePerms("Uploads"), +                            LLAgentBenefitsMgr::current().getTextureUploadCost(raw_image->getWidth(), raw_image->getHeight()) +                        )); + +                        upload_new_resource(assetUploadInfo); +                    } +                } +                else +                { +                    LLNewFileResourceUploadInfo* info_p = new LLNewFileResourceUploadInfo( +                        filename, +                        asset_name, +                        asset_name, 0, +                        LLFolderType::FT_NONE, LLInventoryType::IT_NONE, +                        LLFloaterPerms::getNextOwnerPerms("Uploads"), +                        LLFloaterPerms::getGroupPerms("Uploads"), +                        LLFloaterPerms::getEveryonePerms("Uploads"), +                        expected_upload_cost); +                    LLResourceUploadInfo::ptr_t uploadInfo(info_p); + +                    upload_new_resource(uploadInfo); +                }              }          } @@ -647,8 +733,31 @@ bool get_bulk_upload_expected_cost(                  LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec);                  if (gDirUtilp->fileExists(filename) && image_frmted && image_frmted->load(filename))                  { -                    S32 biased_width = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getWidth(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); -                    S32 biased_height = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getHeight(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); +                    S32 biased_width, biased_height; + +                    S32 max_width  = allow_2k ? gSavedSettings.getS32("max_texture_dimension_X") : 1024; +                    S32 max_height = allow_2k ? gSavedSettings.getS32("max_texture_dimension_Y") : 1024; + +                    S32 orig_width  = image_frmted->getWidth(); +                    S32 orig_height = image_frmted->getHeight(); + +                    if (orig_width > max_width || orig_height > max_height) +                    { +                        // Calculate scale factors +                        F32 width_scale  = (F32)max_width / (F32)orig_width; +                        F32 height_scale = (F32)max_height / (F32)orig_height; +                        F32 scale        = llmin(width_scale, height_scale); + +                        // Calculate new dimensions, preserving aspect ratio +                        biased_width = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_width * scale), 4, max_width)); +                        biased_height = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_height * scale), 4, max_height)); +                    } +                    else +                    { +                        biased_width = LLImageRaw::biasedDimToPowerOfTwo(orig_width, LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); +                        biased_height = LLImageRaw::biasedDimToPowerOfTwo(orig_height, LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); +                    } +                      total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(biased_width, biased_height);                      S32 area = biased_width * biased_height;                      if (area >= LLAgentBenefits::MIN_2K_TEXTURE_AREA) diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index a51feeb7ab..93797c0b58 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12619,4 +12619,15 @@ are wearing now.      Unable to apply material to the water exclusion surface.      <tag>fail</tag>    </notification> + +  <notification +   icon="notify.tga" +   name="ImageUploadResized" +   type="alertmodal"> +      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. +      <usetemplate +          ignoretext="Image Upload Resized" +          name="okignore" +          yestext="OK"/> +  </notification>  </notifications>  | 
