diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-03-28 19:45:25 +0300 |
---|---|---|
committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-03-28 21:45:31 +0300 |
commit | 43fcf86b3b8863fa6f9eb00d0a18aca0a3d675ff (patch) | |
tree | f9e6bfd4dfac155e92c22ddfd65221dae8416030 | |
parent | b7bd7029eb7c38a70c20278298ee650e0dbbdfa1 (diff) |
SL-16937 New Profile capability, image uploader cap #6
-rw-r--r-- | indra/newview/llpanelprofile.cpp | 170 | ||||
-rw-r--r-- | indra/newview/llviewertexturelist.cpp | 9 | ||||
-rw-r--r-- | indra/newview/llviewertexturelist.h | 7 |
3 files changed, 91 insertions, 95 deletions
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 5986ef7171..d202f62910 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -296,7 +296,7 @@ enum EProfileImageType PROFILE_IMAGE_FL, }; -void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::string &path_to_image) +void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::string path_to_image) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t @@ -340,69 +340,28 @@ void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::s return; } - // Load the image + // Upload the image + LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders); + LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions); + S64 length; - // Convert and validate: the upload procedure is the same for all images, - U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(path_to_image)); - - LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); - if (image.isNull()) - { - LL_WARNS("AvatarProperties") << "Couldn't open the image to be uploaded." << LL_ENDL; - return; - } - if (!image->load(path_to_image)) - { - LL_WARNS("AvatarProperties") << "Couldn't load the image to be uploaded." << LL_ENDL; - return; - } - // Decompress or expand it in a raw image structure - LLPointer<LLImageRaw> raw_image = new LLImageRaw; - if (!image->decode(raw_image, 0.0f)) - { - LL_WARNS("AvatarProperties") << "Couldn't decode the image to be uploaded." << LL_ENDL; - return; - } - - // Check the image constraints - if ((image->getComponents() != 3) && (image->getComponents() != 4)) - { - LL_WARNS("AvatarProperties") << "Image files with less than 3 or more than 4 components are not supported." << LL_ENDL; - return; - } - - const S32 MAX_DIM = 256; - raw_image->biasedScaleToPowerOfTwo(MAX_DIM); // should it actually be power of two? - - // Convert to j2c (JPEG2000) - LLPointer<LLImageJ2C> j2cImage = LLViewerTextureList::convertToUploadFile(raw_image); - if (j2cImage.isNull()) - { - LL_WARNS("AvatarProperties") << "Couldn't convert the image to jpeg2000." << LL_ENDL; - return; - } - S32 data_size = j2cImage->getDataSize(); - /*U8 *data_start = compressedImage->getData(); - LLSD::Binary bin_data(data_start, data_start + data_size);*/ - LLCore::BufferArray::ptr_t bin_data(new LLCore::BufferArray); - LLCore::BufferArrayStream bas(bin_data.get()); - - U8* image_data = j2cImage->getData(); - for (S32 i = 0; i < j2cImage->getDataSize(); ++i) { - bas << image_data[i]; + llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate); + if (!instream.is_open()) + { + LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL; + return; + } + length = instream.tellg(); } - LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders); - LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions); - uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); - uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", data_size)); + uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional + uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required! uploaderhttpOpts->setFollowRedirects(true); - - result = httpAdapter->postAndSuspend(uploaderhttpRequest, uploader_cap, bin_data, uploaderhttpOpts, uploaderhttpHeaders); + result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders); httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -413,11 +372,44 @@ void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::s return; } - // Todo: - // handle 'message':'No Error','state':'failure' - // handle 'state':'complete' + if (result["state"].asString() != "complete") + { + if (result.has("message")) + { + LL_WARNS("AvatarProperties") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL; + } + else + { + LL_WARNS("AvatarProperties") << "Failed to upload image " << result << LL_ENDL; + } + return; + } + + LLFile::remove(path_to_image); +} - LL_WARNS() << result << LL_ENDL; +void launch_profile_image_coro(EProfileImageType type, const std::string &file_path) +{ + std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP); + if (!cap_url.empty()) + { + // todo: createUploadFile needs to be done when user picks up a file, + // not when user clicks 'ok', but coroutine should happen on 'ok'. + // but this waits for a UI update, the main point is a functional coroutine + std::string temp_file = gDirUtilp->getTempFilename(); + U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path)); + const S32 MAX_DIM = 256; + + if (LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM)) + { + LLCoros::instance().launch("postAgentUserImageCoro", + boost::bind(post_profile_image_coro, cap_url, type, temp_file)); + } + } + else + { + LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL; + } } ////////////////////////////////////////////////////////////////////////// @@ -726,7 +718,7 @@ void LLPanelProfileSecondLife::apply(LLAvatarData* data) } else { - LL_WARNS() << "Failed to update profile data, no cap found" << LL_ENDL; + LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; } } @@ -734,18 +726,9 @@ void LLPanelProfileSecondLife::apply(LLAvatarData* data) if (data->image_id != mSecondLifePic->getImageAssetID() && LLLocalBitmapMgr::getInstance()->isLocal(mSecondLifePic->getImageAssetID())) { - std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP); - if (!cap_url.empty()) - { - // Temp path, will add a proper one once UI updates to support this - std::string full_path = gDirUtilp->findSkinnedFilename("textures", "icons/Default_Outfit_Photo.png"); - LLCoros::instance().launch("postAgentUserImageCoro", - boost::bind(post_profile_image_coro, cap_url, PROFILE_IMAGE_SL, full_path)); - } - else - { - LL_WARNS() << "Failed to upload sl profile image, no cap found" << LL_ENDL; - } + // todo: temporary file, connect to UI + std::string file_path = gDirUtilp->findSkinnedFilename("textures", "icons/Default_Outfit_Photo.png"); + launch_profile_image_coro(PROFILE_IMAGE_SL, file_path); } } } @@ -1606,28 +1589,37 @@ void LLPanelProfileFirstLife::resetData() void LLPanelProfileFirstLife::apply(LLAvatarData* data) { - - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (getIsLoaded() && !cap_url.empty()) + LLSD params = LLSDMap(); + if (data->fl_image_id != mPicture->getImageAssetID() + && !LLLocalBitmapMgr::getInstance()->isLocal(mPicture->getImageAssetID())) { - LLSD params = LLSDMap(); - if (data->fl_image_id != mPicture->getImageAssetID()) - { - params["fl_image_id"] = mPicture->getImageAssetID(); - } - if (data->fl_about_text != mDescriptionEdit->getValue().asString()) - { - params["fl_about_text"] = mDescriptionEdit->getValue().asString(); - } - if (!params.emptyMap()) + params["fl_image_id"] = mPicture->getImageAssetID(); + } + if (data->fl_about_text != mDescriptionEdit->getValue().asString()) + { + params["fl_about_text"] = mDescriptionEdit->getValue().asString(); + } + if (!params.emptyMap()) + { + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (getIsLoaded() && !cap_url.empty()) { LLCoros::instance().launch("putAgentUserInfoCoro", boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params)); } + else + { + LL_WARNS("AvatarProperties") << "Failed to upload profile data " << PROFILE_PROPERTIES_CAP << " cap not found" << LL_ENDL; + } } - data->fl_image_id = mPicture->getImageAssetID(); - data->fl_about_text = mDescriptionEdit->getValue().asString(); + if (data->fl_image_id != mPicture->getImageAssetID() + && LLLocalBitmapMgr::getInstance()->isLocal(mPicture->getImageAssetID())) + { + // todo: temporary file, connect to UI + std::string file_path = gDirUtilp->findSkinnedFilename("textures", "icons/Default_Outfit_Photo.png"); + launch_profile_image_coro(PROFILE_IMAGE_FL, file_path); + } } void LLPanelProfileFirstLife::updateButtons() diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 37344056e1..7afc310fdd 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1257,7 +1257,8 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) BOOL LLViewerTextureList::createUploadFile(const std::string& filename, const std::string& out_filename, - const U8 codec) + const U8 codec, + const S32 max_image_dimentions) { // Load the image LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); @@ -1285,7 +1286,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, return FALSE; } // Convert to j2c (JPEG2000) and save the file locally - LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image); + LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions); if (compressedImage.isNull()) { image->setLastError("Couldn't convert the image to jpeg2000."); @@ -1310,9 +1311,9 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, } // note: modifies the argument raw_image!!!! -LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image) +LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions) { - raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + raw_image->biasedScaleToPowerOfTwo(max_image_dimentions); LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C(); if (gSavedSettings.getBOOL("LosslessJ2CUpload") && diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index fead2e52b2..6fb0d3552e 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -92,8 +92,11 @@ class LLViewerTextureList friend class LLLocalBitmap; public: - static BOOL createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec); - static LLPointer<LLImageJ2C> convertToUploadFile(LLPointer<LLImageRaw> raw_image); + static BOOL createUploadFile(const std::string& filename, + const std::string& out_filename, + const U8 codec, + const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + static LLPointer<LLImageJ2C> convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); static void processImageNotInDatabase( LLMessageSystem *msg, void **user_data ); static void receiveImageHeader(LLMessageSystem *msg, void **user_data); static void receiveImagePacket(LLMessageSystem *msg, void **user_data); |