From e2f0b8a6bc747355f5f5cf146f305a19226a2804 Mon Sep 17 00:00:00 2001 From: zhaona45 Date: Mon, 18 Aug 2025 15:59:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BC=A9=E7=95=A5=E5=9B=BE?= =?UTF-8?q?=E7=BC=96=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhaona45 Change-Id: I00f6b14517b91e81240f833ec369b59cad19162d --- .../accessor/src/exif_metadata.cpp | 11 + .../innerkitsimpl/codec/src/image_source.cpp | 316 ++++++++++++++++-- .../picture/auxiliary_generator.cpp | 21 +- .../innerkitsimpl/utils/include/image_utils.h | 3 +- .../innerkitsimpl/utils/src/image_utils.cpp | 29 +- .../kits/js/common/auxiliary_picture_napi.cpp | 6 +- .../kits/js/common/image_source_napi.cpp | 157 ++++++++- .../js/common/ndk/image_source_native.cpp | 106 ++++++ frameworks/kits/js/common/picture_napi.cpp | 3 +- .../innerkits/include/auxiliary_generator.h | 4 + interfaces/innerkits/include/exif_metadata.h | 1 + interfaces/innerkits/include/image_source.h | 12 + interfaces/innerkits/include/image_type.h | 10 +- .../js/common/include/image_source_napi.h | 2 + .../include/image/image_source_native.h | 92 +++++ .../native/include/image/picture_native.h | 4 + .../include/heif_impl/HeifDecoderImpl.h | 1 + .../image/libextplugin/src/ext_decoder.cpp | 3 + .../image/libextplugin/src/ext_encoder.cpp | 4 +- .../src/heif_impl/HeifDecoderImpl.cpp | 22 ++ 20 files changed, 752 insertions(+), 55 deletions(-) diff --git a/frameworks/innerkitsimpl/accessor/src/exif_metadata.cpp b/frameworks/innerkitsimpl/accessor/src/exif_metadata.cpp index e589360ea..c5d6fb786 100644 --- a/frameworks/innerkitsimpl/accessor/src/exif_metadata.cpp +++ b/frameworks/innerkitsimpl/accessor/src/exif_metadata.cpp @@ -323,6 +323,17 @@ std::shared_ptr ExifMetadata::Clone() return exifDataPtr; } +bool ExifMetadata::GetThumbnail(uint8_t *&data, uint32_t &size) +{ + data = reinterpret_cast(exifData_->data); + size = static_cast(exifData_->size); + IMAGE_LOGD("%{public}s: size: %{public}u", __func__, size); + if (data == nullptr || size == 0) { + return false; + } + return true; +} + ExifEntry *ExifMetadata::CreateEntry(const std::string &key, const ExifTag &tag, const size_t valueLen) { ExifEntry *entry = exif_entry_new(); diff --git a/frameworks/innerkitsimpl/codec/src/image_source.cpp b/frameworks/innerkitsimpl/codec/src/image_source.cpp index 7e700b8ac..c0107e142 100644 --- a/frameworks/innerkitsimpl/codec/src/image_source.cpp +++ b/frameworks/innerkitsimpl/codec/src/image_source.cpp @@ -173,6 +173,8 @@ constexpr int32_t SHARE_MEMORY_ALLOC = 2; constexpr int32_t AUTO_ALLOC = 0; static constexpr uint8_t JPEG_SOI[] = { 0xFF, 0xD8, 0xFF }; constexpr uint8_t PIXEL_BYTES = 4; +static constexpr int32_t THUMBNAIL_SHORT_SIDE_SIZE = 350; +static constexpr int32_t THUMBNAIL_LONG_SIDE_MULTIPLIER = 3; struct StreamInfo { uint8_t* buffer = nullptr; @@ -5069,6 +5071,11 @@ void ImageSource::DecodeHeifAuxiliaryPictures( mainInfo.hdrType = sourceHdrType_; picture->GetMainPixel()->GetImageInfo(mainInfo.imageInfo); for (auto& auxType : auxTypes) { + if (auxType == AuxiliaryPictureType::THUMBNAIL) { + IMAGE_LOGI("%{public}s: Set thumbnail for Picture", __func__); + SetThumbnailForPicture(picture, IMAGE_HEIF_FORMAT); + continue; + } if (!mainDecoder_->CheckAuxiliaryMap(auxType)) { IMAGE_LOGE("The auxiliary picture type does not exist! Type: %{public}d", auxType); continue; @@ -5158,6 +5165,66 @@ bool ImageSource::CheckJpegSourceStream(StreamInfo &streamInfo) return true; } +void ImageSource::SetThumbnailForPicture(std::unique_ptr &picture, const std::string &mimeType) +{ + uint32_t auxErrorCode = ERROR; + if (picture == nullptr || picture->GetMainPixel() == nullptr) { + IMAGE_LOGE("%{public}s failed. picture or mainPixelMap is nullptr", __func__); + return; + } + DecodingOptionsForThumbnail opts; + std::shared_ptr pixelMap = CreateThumbnail(opts, auxErrorCode); + std::shared_ptr auxPicture = AuxiliaryPicture::Create(pixelMap, AuxiliaryPictureType::THUMBNAIL); + if (auxPicture == nullptr || auxPicture->GetContentPixel() == nullptr) { + IMAGE_LOGE("%{public}s failed. Create thumbnail auxiliary picture failed", __func__); + return; + } + AuxiliaryPictureInfo auxPictureInfo = auxPicture->GetAuxiliaryPictureInfo(); + if (mimeType == IMAGE_JPEG_FORMAT) { + IMAGE_LOGI("%{public}s set jpeg tag for auxiliary info", __func__); + auxPictureInfo.jpegTagName = AUXILIARY_TAG_THUMBNAIL; + } + auxPicture->SetAuxiliaryPictureInfo(auxPictureInfo); + auxPicture->GetContentPixel()->SetEditable(true); + picture->SetAuxiliaryPicture(auxPicture); +} + +void ImageSource::DecodeSingleJpegAuxiliaryPicture(std::unique_ptr &picture, MainPictureInfo &mainInfo, + const SingleJpegImage &auxInfo, StreamInfo &streamInfo) +{ + uint32_t auxErrorCode = ERROR; + if (picture == nullptr || streamInfo.buffer == nullptr || streamInfo.GetCurrentSize() == 0) { + IMAGE_LOGE("%{public}s failed. picture or streamBuffer is invalid", __func__); + return; + } + if (ImageUtils::HasOverflowed(auxInfo.offset, auxInfo.size) || + auxInfo.offset + auxInfo.size > streamInfo.GetCurrentSize()) { + IMAGE_LOGW("Invalid auxType: %{public}d, offset: %{public}u, size: %{public}u, streamSize: %{public}u", + auxInfo.auxType, auxInfo.offset, auxInfo.size, streamInfo.GetCurrentSize()); + return; + } + IMAGE_LOGI("Jpeg auxiliary picture has found. Type: %{public}d", auxInfo.auxType); + std::unique_ptr auxStream = + BufferSourceStream::CreateSourceStream((streamInfo.GetCurrentAddress() + auxInfo.offset), auxInfo.size); + if (auxStream == nullptr) { + IMAGE_LOGE("Create auxiliary stream fail, auxiliary offset is %{public}u", auxInfo.offset); + return; + } + auto auxDecoder = std::unique_ptr( + DoCreateDecoder(InnerFormat::IMAGE_EXTENDED_CODEC, pluginServer_, *auxStream, auxErrorCode)); + auto auxPicture = AuxiliaryGenerator::GenerateJpegAuxiliaryPicture( + mainInfo, auxInfo.auxType, auxStream, auxDecoder, auxErrorCode); + if (auxPicture != nullptr) { + AuxiliaryPictureInfo auxPictureInfo = auxPicture->GetAuxiliaryPictureInfo(); + auxPictureInfo.jpegTagName = auxInfo.auxTagName; + auxPicture->SetAuxiliaryPictureInfo(auxPictureInfo); + auxPicture->GetContentPixel()->SetEditable(true); + picture->SetAuxiliaryPicture(auxPicture); + } else { + IMAGE_LOGE("Generate jpeg auxiliary picture failed!, error: %{public}d", auxErrorCode); + } +} + void ImageSource::DecodeJpegAuxiliaryPicture( std::set &auxTypes, std::unique_ptr &picture, uint32_t &errorCode) { @@ -5176,34 +5243,235 @@ void ImageSource::DecodeJpegAuxiliaryPicture( if (auxTypes.find(auxInfo.auxType) == auxTypes.end()) { continue; } - if (ImageUtils::HasOverflowed(auxInfo.offset, auxInfo.size) - || auxInfo.offset + auxInfo.size > streamInfo.GetCurrentSize()) { - IMAGE_LOGW("Invalid auxType: %{public}d, offset: %{public}u, size: %{public}u, streamSize: %{public}u", - auxInfo.auxType, auxInfo.offset, auxInfo.size, streamInfo.GetCurrentSize()); - continue; + DecodeSingleJpegAuxiliaryPicture(picture, mainInfo, auxInfo, streamInfo); + } + SetThumbnailForPicture(picture, IMAGE_JPEG_FORMAT); +} + +static void SetThumbnailDecodeOptions(std::unique_ptr &thumbDecoder, + const DecodingOptionsForThumbnail &opts, PlImageInfo &plInfo, uint32_t &errorCode) +{ + if (thumbDecoder == nullptr) { + IMAGE_LOGE("%{public}s: thumbDecoder is nullptr!", __func__); + errorCode = ERR_IMAGE_INVALID_PARAMETER; + return; + } + if (opts.desiredSize.width < 0 || opts.desiredSize.height < 0) { + IMAGE_LOGE("%{public}s: invalid opts.desiredSize: (%{public}d,%{public}d)", + __func__, opts.desiredSize.width, opts.desiredSize.height); + errorCode = ERR_IMAGE_INVALID_PARAMETER; + return; + } + Size imageSize{}; + errorCode = thumbDecoder->GetImageSize(FIRST_FRAME, imageSize); + if (errorCode != SUCCESS || !IsSizeVailed(imageSize)) { + IMAGE_LOGE("%{public}s: Get image size failed!", __func__); + return; + } + + PixelDecodeOptions plOptions; + plOptions.desiredSize = imageSize; + plOptions.desiredPixelFormat = PixelFormat::RGBA_8888; + errorCode = thumbDecoder->SetDecodeOptions(FIRST_FRAME, plOptions, plInfo); + if (errorCode != SUCCESS) { + IMAGE_LOGE("%{public}s: Set decode options failed!", __func__); + return; + } +} + +static void CalculateDefaultScaleFactor(Size &size, const int32_t &shortSideSize, + const int32_t &longSideMultiplier) +{ + if (!IsSizeVailed(size)) { + IMAGE_LOGW("Default size is invalid: (%{public}d,%{public}d)", size.width, size.height); + return; + } + if (ImageUtils::CheckFloatMulOverflow(shortSideSize, longSideMultiplier)) { + IMAGE_LOGW("%{public}s: shortSideSize * longSideMultiplier overflow!", __func__); + return; + } + float longSideBoundary = static_cast(shortSideSize) * longSideMultiplier; + float xScale = 1.0f; + float yScale = 1.0f; + if (size.width < size.height) { + xScale = static_cast(shortSideSize) / size.width; + if (ImageUtils::CheckFloatMulOverflow(size.height, xScale)) { + IMAGE_LOGW("%{public}s: height * xScale overflow!", __func__); + return; } - IMAGE_LOGI("Jpeg auxiliary picture has found. Type: %{public}d", auxInfo.auxType); - std::unique_ptr auxStream = - BufferSourceStream::CreateSourceStream((streamInfo.GetCurrentAddress() + auxInfo.offset), auxInfo.size); - if (auxStream == nullptr) { - IMAGE_LOGE("Create auxiliary stream fail, auxiliary offset is %{public}u", auxInfo.offset); - continue; + yScale = (size.height * xScale > longSideBoundary) ? longSideBoundary / size.height : xScale; + size.width = shortSideSize; + size.height = (size.height * xScale > longSideBoundary) ? longSideBoundary : size.height * xScale; + } else { + yScale = static_cast(shortSideSize) / size.height; + if (ImageUtils::CheckFloatMulOverflow(size.width, yScale)) { + IMAGE_LOGW("%{public}s: width * yScale overflow!", __func__); + return; } - auto auxDecoder = std::unique_ptr( - DoCreateDecoder(InnerFormat::IMAGE_EXTENDED_CODEC, pluginServer_, *auxStream, errorCode)); - uint32_t auxErrorCode = ERROR; - auto auxPicture = AuxiliaryGenerator::GenerateJpegAuxiliaryPicture( - mainInfo, auxInfo.auxType, auxStream, auxDecoder, auxErrorCode); - if (auxPicture != nullptr && auxPicture->GetContentPixel() != nullptr) { - AuxiliaryPictureInfo auxPictureInfo = auxPicture->GetAuxiliaryPictureInfo(); - auxPictureInfo.jpegTagName = auxInfo.auxTagName; - auxPicture->SetAuxiliaryPictureInfo(auxPictureInfo); - auxPicture->GetContentPixel()->SetEditable(true); - picture->SetAuxiliaryPicture(auxPicture); - } else { - IMAGE_LOGE("Generate jpeg auxiliary picture failed!, error: %{public}d", auxErrorCode); + xScale = (size.width * yScale > longSideBoundary) ? longSideBoundary / size.width : yScale; + size.width = (size.width * yScale > longSideBoundary) ? longSideBoundary : size.width * yScale; + size.height = shortSideSize; + } +} + +static void ScaleThumbnail(std::unique_ptr &pixelMap, const Size &desiredSize, bool useDefaultScale = false) +{ + if (pixelMap == nullptr) { + IMAGE_LOGW("%{public}s: pixelMap is nullptr!", __func__); + return; + } + ImageInfo imageInfo; + pixelMap->GetImageInfo(imageInfo); + Size &size = imageInfo.size; + if (!IsSizeVailed(size)) { + IMAGE_LOGW("%{public}s: pixelMap size is invalid, size: (%{public}d,%{public}d)", + __func__, size.width, size.height); + return; + } + PostProc postProc; + if (IsSizeVailed(desiredSize)) { + if (!postProc.ScalePixelMapWithGPU(*(pixelMap.get()), desiredSize, AntiAliasingOption::HIGH, true)) { + IMAGE_LOGE("Fail to scale thumbnail, ScalePixelMapWithGPU failed, desiredSize: %{public}d * %{public}d", + desiredSize.width, desiredSize.height); + return; } + if (!postProc.CenterScale(desiredSize, *(pixelMap.get()))) { + IMAGE_LOGE("CenterScale failed"); + return; + } + } else if (useDefaultScale) { + CalculateDefaultScaleFactor(size, THUMBNAIL_SHORT_SIDE_SIZE, THUMBNAIL_LONG_SIDE_MULTIPLIER); + if (!postProc.ScalePixelMapWithGPU(*(pixelMap.get()), size, AntiAliasingOption::HIGH, true)) { + IMAGE_LOGE("Fail to scale thumbnail, ScalePixelMapWithGPU failed, size: %{public}d * %{public}d", + size.width, size.height); + return; + } + if (!postProc.CenterScale(size, *(pixelMap.get()))) { + IMAGE_LOGE("CenterScale failed"); + return; + } + } + pixelMap->GetImageInfo(imageInfo); + IMAGE_LOGI("%{public}s: desiredSize: (%{public}d,%{public}d), scaledSize:(%{public}d,%{public}d)", + __func__, desiredSize.width, desiredSize.height, size.width, size.height); +} + +std::unique_ptr ImageSource::DecodeHeifParserThumbnail(const DecodingOptionsForThumbnail &opts, + DecodeContext &context, const std::string &format, uint32_t &errorCode) +{ + if (mainDecoder_ == nullptr) { + IMAGE_LOGE("%{public}s: mainDecoder_ is nullptr!", __func__); + return nullptr; + } + if (!mainDecoder_->CheckAuxiliaryMap(AuxiliaryPictureType::THUMBNAIL)) { + IMAGE_LOGE("%{public}s: heifParser has not thumbnail Images", __func__); + return nullptr; + } + SetThumbnailDecodeOptions(mainDecoder_, opts, context.info, errorCode); + if (errorCode != SUCCESS) { + IMAGE_LOGE("%{public}s: SetThumbnailDecodeOptions failed!, errorCode: %{public}u", __func__, errorCode); + return nullptr; + } + if (!mainDecoder_->DecodeHeifAuxiliaryMap(context, AuxiliaryPictureType::THUMBNAIL)) { + errorCode = ERR_IMAGE_DECODE_FAILED; + IMAGE_LOGE("%{public}s: SetDecodeOptions failed!", __func__); + return nullptr; + } + + std::unique_ptr pixelMap = + AuxiliaryGenerator::CreatePixelMapByContext(context, mainDecoder_, format, errorCode); + ScaleThumbnail(pixelMap, opts.desiredSize); + return pixelMap; +} + +std::unique_ptr ImageSource::GenerateThumbnail(const DecodingOptionsForThumbnail &opts, uint32_t &errorCode) +{ + DecodeOptions tmpOpts; + tmpOpts.desiredDynamicRange = DecodeDynamicRange::SDR; + std::unique_ptr pixelMap = CreatePixelMap(tmpOpts, errorCode); + if (errorCode != SUCCESS || pixelMap == nullptr) { + IMAGE_LOGE("%{public}s: CreatePixelMap failed!", __func__); + return nullptr; + } + ScaleThumbnail(pixelMap, opts.desiredSize, true); + IMAGE_LOGI("%{public}s: desiredSize: (%{public}d, %{public}d), after scale size: (%{public}d, %{public}d)", + __func__, opts.desiredSize.width, opts.desiredSize.height, pixelMap->GetWidth(), pixelMap->GetHeight()); + return pixelMap; +} + +std::unique_ptr ImageSource::DecodeExifThumbnail(const DecodingOptionsForThumbnail &opts, + DecodeContext &context, const std::string &format, uint32_t &errorCode) +{ + uint8_t *data = nullptr; + uint32_t dataSize = 0; + errorCode = CreatExifMetadataByImageSource(); + if (errorCode != SUCCESS || exifMetadata_ == nullptr || !exifMetadata_->GetThumbnail(data, dataSize)) { + IMAGE_LOGW("%{public}s: Exif or exif-thumbnail does not exist!", __func__); + errorCode = ERR_MEDIA_NO_EXIF_DATA; + return nullptr; } + + std::unique_ptr thumbStream = BufferSourceStream::CreateSourceStream(data, dataSize); + if (thumbStream == nullptr) { + IMAGE_LOGE("Create thumbnail stream fail, thumbnail dataSize is %{public}u", dataSize); + return nullptr; + } + auto thumbDecoder = std::unique_ptr( + DoCreateDecoder(InnerFormat::IMAGE_EXTENDED_CODEC, pluginServer_, *thumbStream, errorCode)); + if (errorCode != SUCCESS || thumbDecoder == nullptr) { + IMAGE_LOGE("Create thumbnail decoder fail!"); + return nullptr; + } + SetThumbnailDecodeOptions(thumbDecoder, opts, context.info, errorCode); + if (errorCode != SUCCESS) { + IMAGE_LOGE("%{public}s: SetThumbnailDecodeOptions failed!, errorCode: %{public}u", __func__, errorCode); + return nullptr; + } + + ImageTrace imageTrace("%{public}s: size:(%d, %d)", __func__, context.info.size.width, context.info.size.height); + errorCode = thumbDecoder->Decode(FIRST_FRAME, context); + if (errorCode != SUCCESS) { + IMAGE_LOGE("Decode thumbnail failed!"); + FreeContextBuffer(context.freeFunc, context.allocatorType, context.pixelsBuffer); + return nullptr; + } + + std::unique_ptr pixelMap = + AuxiliaryGenerator::CreatePixelMapByContext(context, thumbDecoder, format, errorCode); + ScaleThumbnail(pixelMap, opts.desiredSize); + return pixelMap; +} + +std::unique_ptr ImageSource::CreateThumbnail(const DecodingOptionsForThumbnail &opts, uint32_t &errorCode) +{ + if (!ParseHdrType()) { + IMAGE_LOGE("%{public}s: Init mainDecoder_ failed!", __func__); + errorCode = ERR_IMAGE_PLUGIN_CREATE_FAILED; + return nullptr; + } + + DecodeContext context; + context.allocatorType = AllocatorType::DMA_ALLOC; + std::string format = GetExtendedCodecMimeType(mainDecoder_.get()); + std::unique_ptr pixelMap = nullptr; + if (format == IMAGE_HEIF_FORMAT || format == IMAGE_HEIC_FORMAT) { + pixelMap = DecodeHeifParserThumbnail(opts, context, format, errorCode); + if (errorCode == SUCCESS && pixelMap != nullptr) { + IMAGE_LOGI("%{public}s: DecodeHeifParserThumbnail success", __func__); + return pixelMap; + } else if (errorCode == ERR_IMAGE_INVALID_PARAMETER) { + IMAGE_LOGE("%{public}s: DecodeHeifParserThumbnail failed with parameter invaild", __func__); + return nullptr; + } + IMAGE_LOGW("%{public}s: DecodeHeifParserThumbnail failed, get thumbnail with other method", __func__); + } + + pixelMap = DecodeExifThumbnail(opts, context, format, errorCode); + if (opts.needGenerate && (errorCode != SUCCESS || pixelMap == nullptr)) { + IMAGE_LOGW("%{public}s: DecodeExifThumbnail failed, generate thumbnail by primary image", __func__); + return GenerateThumbnail(opts, errorCode); + } + return pixelMap; } #endif diff --git a/frameworks/innerkitsimpl/picture/auxiliary_generator.cpp b/frameworks/innerkitsimpl/picture/auxiliary_generator.cpp index 3a21b218a..64982aa42 100644 --- a/frameworks/innerkitsimpl/picture/auxiliary_generator.cpp +++ b/frameworks/innerkitsimpl/picture/auxiliary_generator.cpp @@ -117,7 +117,7 @@ static void FreeContextBuffer(const Media::CustomFreePixelMap &func, AllocatorTy #endif } -static ImageInfo MakeImageInfo(const Size &size, PixelFormat format, AlphaType alphaType, +ImageInfo AuxiliaryGenerator::MakeImageInfo(const Size &size, PixelFormat format, AlphaType alphaType, ColorSpace colorSpace, const std::string &encodedFormat) { ImageInfo info; @@ -182,7 +182,7 @@ static void SetNonDmaYuvInfo(int32_t width, int32_t height, YUVDataInfo &yuvInfo yuvInfo.uvOffset = static_cast(width) * static_cast(height); } -static void TrySetYUVDataInfo(std::shared_ptr &pixelMap) +static void TrySetYUVDataInfo(std::unique_ptr &pixelMap) { if (pixelMap == nullptr) { IMAGE_LOGE("%{public}s pixelMap is nullptr", __func__); @@ -204,26 +204,26 @@ static void TrySetYUVDataInfo(std::shared_ptr &pixelMap) pixelMap->SetImageYUVInfo(info); } -static std::shared_ptr CreatePixelMapByContext(DecodeContext &context, +std::unique_ptr AuxiliaryGenerator::CreatePixelMapByContext(DecodeContext &context, std::unique_ptr &decoder, const std::string &encodedFormat, uint32_t &errorCode) { - std::shared_ptr pixelMap; + std::unique_ptr pixelMap; if (ImageSource::IsYuvFormat(context.info.pixelFormat)) { #ifdef EXT_PIXEL - pixelMap = std::make_shared(); + pixelMap = std::make_unique(); #else - pixelMap = std::make_shared(); + pixelMap = std::make_unique(); #endif } else { - pixelMap = std::make_shared(); + pixelMap = std::make_unique(); } if (pixelMap == nullptr) { errorCode = ERR_IMAGE_ADD_PIXEL_MAP_FAILED; return nullptr; } - ImageInfo imageinfo = MakeImageInfo(context.outInfo.size, context.info.pixelFormat, - context.info.alphaType, context.colorSpace, encodedFormat); + ImageInfo imageinfo = AuxiliaryGenerator::MakeImageInfo(context.outInfo.size, context.info.pixelFormat, + context.info.alphaType, context.colorSpace, encodedFormat); pixelMap->SetImageInfo(imageinfo, true); PixelMapAddrInfos addrInfos; @@ -375,7 +375,8 @@ static std::unique_ptr GenerateAuxiliaryPicture(const MainPict } std::string encodedFormat = ImageUtils::IsAuxiliaryPictureEncoded(type) ? format : ""; - std::shared_ptr pixelMap = CreatePixelMapByContext(context, extDecoder, encodedFormat, errorCode); + std::shared_ptr pixelMap = AuxiliaryGenerator::CreatePixelMapByContext( + context, extDecoder, encodedFormat, errorCode); bool cond = pixelMap == nullptr || errorCode != SUCCESS; CHECK_ERROR_RETURN_RET_LOG(cond, nullptr, "%{public}s CreatePixelMapByContext failed!", __func__); auto auxPicture = AuxiliaryPicture::Create(pixelMap, type, context.outInfo.size); diff --git a/frameworks/innerkitsimpl/utils/include/image_utils.h b/frameworks/innerkitsimpl/utils/include/image_utils.h index 4968f232f..c5ed4728e 100644 --- a/frameworks/innerkitsimpl/utils/include/image_utils.h +++ b/frameworks/innerkitsimpl/utils/include/image_utils.h @@ -58,6 +58,7 @@ public: static MultimediaPlugin::PluginServer& GetPluginServer(); static bool CheckMulOverflow(int32_t width, int32_t bytesPerPixel); static bool CheckMulOverflow(int32_t width, int32_t height, int32_t bytesPerPixel); + static bool CheckFloatMulOverflow(float num1, float num2); static void BGRAToARGB(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount); static void ARGBToBGRA(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount); static int32_t SurfaceBuffer_Reference(void* buffer); @@ -90,7 +91,7 @@ public: static bool IsAuxiliaryPictureTypeSupported(AuxiliaryPictureType auxiliaryPictureType); static bool IsAuxiliaryPictureEncoded(AuxiliaryPictureType type); static bool IsMetadataTypeSupported(MetadataType metadataType); - static const std::set GetAllAuxiliaryPictureType(); + static const std::set& GetAllAuxiliaryPictureType(); static size_t GetAstcBytesCount(const ImageInfo& imageInfo); static bool StrToUint32(const std::string& str, uint32_t& value); static bool IsInRange(uint32_t value, uint32_t minValue, uint32_t maxValue); diff --git a/frameworks/innerkitsimpl/utils/src/image_utils.cpp b/frameworks/innerkitsimpl/utils/src/image_utils.cpp index 6ef30c429..9045e31bf 100644 --- a/frameworks/innerkitsimpl/utils/src/image_utils.cpp +++ b/frameworks/innerkitsimpl/utils/src/image_utils.cpp @@ -101,6 +101,7 @@ constexpr int32_t FAULT_API_VERSION = -1; constexpr int32_t BUNDLE_MGR_SERVICE_SYS_ABILITY_ID = 401; constexpr int32_t BASE_EVEN_DIVISOR = 2; constexpr float EPSILON = 1e-6; +constexpr float FLOAT_1 = 1.0f; constexpr int MAX_DIMENSION = INT32_MAX >> 2; static bool g_pluginRegistered = false; static const uint8_t NUM_0 = 0; @@ -562,6 +563,18 @@ bool ImageUtils::CheckMulOverflow(int32_t width, int32_t height, int32_t bytesPe return false; } +bool ImageUtils::CheckFloatMulOverflow(float num1, float num2) +{ + if (fabs(num1) <= FLOAT_1 || fabs(num2) <= FLOAT_1) { + return false; + } + if (fabs(num1) > std::numeric_limits::max() / fabs(num2)) { + IMAGE_LOGE("num1 * num2 overflow! num1:%{public}f, num2:%{public}f", num1, num2); + return true; + } + return false; +} + static void ReversePixels(uint8_t* srcPixels, uint8_t* dstPixels, uint32_t byteCount) { if (byteCount % NUM_4 != NUM_0) { @@ -1074,14 +1087,16 @@ bool ImageUtils::IsMetadataTypeSupported(MetadataType metadataType) } } -const std::set ImageUtils::GetAllAuxiliaryPictureType() +const std::set& ImageUtils::GetAllAuxiliaryPictureType() { - static const std::set auxTypes = { - AuxiliaryPictureType::GAINMAP, - AuxiliaryPictureType::DEPTH_MAP, - AuxiliaryPictureType::UNREFOCUS_MAP, - AuxiliaryPictureType::LINEAR_MAP, - AuxiliaryPictureType::FRAGMENT_MAP}; + static const std::set auxTypes = [] { + std::set set; + for (int32_t type = static_cast(AuxiliaryPictureType::GAINMAP); + type < static_cast(AuxiliaryPictureType::MAX_AUXILIARY_PICTURE_TYPE); ++type) { + set.insert(static_cast(type)); + } + return set; + }(); return auxTypes; } diff --git a/frameworks/kits/js/common/auxiliary_picture_napi.cpp b/frameworks/kits/js/common/auxiliary_picture_napi.cpp index 216d5b13a..0f77947d5 100644 --- a/frameworks/kits/js/common/auxiliary_picture_napi.cpp +++ b/frameworks/kits/js/common/auxiliary_picture_napi.cpp @@ -322,7 +322,7 @@ static bool ParseBuffer(napi_env env, napi_value argValue, static AuxiliaryPictureType ParseAuxiliaryPictureType(int32_t val) { if (val >= static_cast(AuxiliaryPictureType::GAINMAP) - && val <= static_cast(AuxiliaryPictureType::FRAGMENT_MAP)) { + && val < static_cast(AuxiliaryPictureType::MAX_AUXILIARY_PICTURE_TYPE)) { return AuxiliaryPictureType(val); } return AuxiliaryPictureType::NONE; @@ -365,7 +365,7 @@ napi_value AuxiliaryPictureNapi::CreateAuxiliaryPicture(napi_env env, napi_callb status = napi_get_value_uint32(env, argValue[NUM_2], &auxiType); IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get auxiliary picture Type")); if (auxiType < static_cast(AuxiliaryPictureType::GAINMAP) - || auxiType > static_cast(AuxiliaryPictureType::FRAGMENT_MAP)) { + || auxiType >= static_cast(AuxiliaryPictureType::MAX_AUXILIARY_PICTURE_TYPE)) { IMAGE_LOGE("Auxiliary picture type is invalid"); return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args."); } @@ -398,7 +398,7 @@ napi_value AuxiliaryPictureNapi::GetType(napi_env env, napi_callback_info info) if (auxPictureNapi->nativeAuxiliaryPicture_ != nullptr) { auto auxType = auxPictureNapi->nativeAuxiliaryPicture_->GetType(); IMAGE_LOGD("AuxiliaryPictureNapi::GetType %{public}d", auxType); - if (static_cast(auxType) >= NUM_0 && auxType <= AuxiliaryPictureType::FRAGMENT_MAP) { + if (auxType >= AuxiliaryPictureType::GAINMAP && auxType < AuxiliaryPictureType::MAX_AUXILIARY_PICTURE_TYPE) { napi_create_int32(env, static_cast(auxType), &nVal.result); } } else { diff --git a/frameworks/kits/js/common/image_source_napi.cpp b/frameworks/kits/js/common/image_source_napi.cpp index 8f8ba3000..e367d1d6a 100644 --- a/frameworks/kits/js/common/image_source_napi.cpp +++ b/frameworks/kits/js/common/image_source_napi.cpp @@ -127,6 +127,7 @@ struct ImageSourceAsyncContext { DecodingOptionsForPicture decodingOptsForPicture; std::shared_ptr rPicture; #endif + DecodingOptionsForThumbnail decodingOptsForThumbnail; }; struct ImageSourceSyncContext { @@ -137,6 +138,7 @@ struct ImageSourceSyncContext { std::shared_ptr rPixelMap; std::string errMsg; std::multimap errMsgArray; + DecodingOptionsForThumbnail decodingOptsForThumbnail; }; struct ImageEnum { @@ -912,6 +914,8 @@ std::vector ImageSourceNapi::RegisterNapi() #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM) DECLARE_NAPI_FUNCTION("createPicture", CreatePicture), DECLARE_NAPI_FUNCTION("createPictureAtIndex", CreatePictureAtIndex), + DECLARE_NAPI_FUNCTION("createThumbnail", CreateThumbnail), + DECLARE_NAPI_FUNCTION("createThumbnailSync", CreateThumbnailSync), #endif }; @@ -1168,7 +1172,7 @@ static bool IsSupportPixelFormat(int32_t val) return false; } -static PixelFormat ParsePixlForamt(int32_t val) +static PixelFormat ParsePixelFormat(int32_t val) { if (IsAstc(val)) { return PixelFormat(val); @@ -1236,9 +1240,9 @@ static bool ParsePixelFormat(napi_env env, napi_value root, const char* name, } else { if (IsSupportPixelFormat(tmpNumber)) { if (strcmp(name, "desiredPixelFormat") == 0) { - opts->desiredPixelFormat = ParsePixlForamt(tmpNumber); + opts->desiredPixelFormat = ParsePixelFormat(tmpNumber); } else if (strcmp(name, "photoDesiredPixelFormat") == 0) { - opts->photoDesiredPixelFormat = ParsePixlForamt(tmpNumber); + opts->photoDesiredPixelFormat = ParsePixelFormat(tmpNumber); } } else { IMAGE_LOGD("Invalid %{public}s %{public}d", name, tmpNumber); @@ -1360,6 +1364,38 @@ static bool ParseDecodeOptions(napi_env env, napi_value root, DecodeOptions* opt return ParseDecodeOptions2(env, root, opts, error); } +static bool IsSizeInValid(const Size &size) +{ + return size.width < 0 || size.height < 0; +} + +static bool ParseDecodeOptionsForThumbnail(napi_env env, napi_value root, DecodingOptionsForThumbnail *opts, + std::string &error) +{ + napi_value tmpValue = nullptr; + + if (opts == nullptr) { + IMAGE_LOGE("opts is nullptr"); + return false; + } + + if (!GET_NODE_BY_NAME(root, "desiredSize", tmpValue)) { + IMAGE_LOGD("no desiredSize"); + } else { + if (!ParseSize(env, tmpValue, &(opts->desiredSize))) { + IMAGE_LOGD("ParseSize error"); + } + if (IsSizeInValid(opts->desiredSize)) { + IMAGE_LOGE("desiredSize is invalid"); + return false; + } + } + if (!GET_BOOL_BY_NAME(root, "needGenerate", opts->needGenerate)) { + IMAGE_LOGD("no needGenerate"); + } + return true; +} + static std::string FileUrlToRawPath(const std::string &path) { if (path.size() > FILE_URL_PREFIX.size() && @@ -1871,7 +1907,7 @@ static napi_value CreatePixelMapCompleteSync(napi_env env, napi_status status, I return result; } -static napi_value CreatePixelMapAllocatorTypeCompleteSync(napi_env env, napi_status status, +static napi_value CreatePixelMapThrowErrorCompleteSync(napi_env env, napi_status status, ImageSourceSyncContext *context) { napi_value result = nullptr; @@ -2153,7 +2189,7 @@ napi_value ImageSourceNapi::CreatePixelMapUsingAllocatorSync(napi_env env, napi_ std::string apiErrorMsg = GetErrorCodeMsg(apiErrorCode); syncContext->errMsgArray.emplace(apiErrorCode, apiErrorMsg); } - result = CreatePixelMapAllocatorTypeCompleteSync(env, status, + result = CreatePixelMapThrowErrorCompleteSync(env, status, static_cast((syncContext).get())); IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to create PixelMap.")); @@ -3448,7 +3484,7 @@ static bool ParseDecodingOptionsForPicture(napi_env env, napi_value root, Decodi IMAGE_LOGE("get type from element failed"); return false; } - if (type <= static_cast(AuxiliaryPictureType::FRAGMENT_MAP)) { + if (type < static_cast(AuxiliaryPictureType::MAX_AUXILIARY_PICTURE_TYPE)) { opts->desireAuxiliaryPictures.insert(AuxiliaryPictureType(type)); IMAGE_LOGD("desireAuxiliaryPictures[%{public}d]: %{public}d", i, type); } else { @@ -3485,7 +3521,7 @@ napi_value ImageSourceNapi::CreatePicture(napi_env env, napi_callback_info info) if (argCount == NUM_0) { for (int32_t type = static_cast(AuxiliaryPictureType::GAINMAP); - type <= static_cast(AuxiliaryPictureType::FRAGMENT_MAP); type++) { + type < static_cast(AuxiliaryPictureType::MAX_AUXILIARY_PICTURE_TYPE); type++) { asyncContext->decodingOptsForPicture.desireAuxiliaryPictures.insert(AuxiliaryPictureType(type)); } } else if (argCount == NUM_1) { @@ -3505,6 +3541,113 @@ napi_value ImageSourceNapi::CreatePicture(napi_env env, napi_callback_info info) nullptr, IMAGE_LOGE("fail to create async work")); return result; } + +static void CreateThumbnailExecute(napi_env env, void *data) +{ + IMAGE_LOGD("CreateThumbnailExecute IN"); + if (data == nullptr) { + IMAGE_LOGE("data is nullptr"); + return; + } + auto context = static_cast(data); + if (context == nullptr) { + IMAGE_LOGE("empty context"); + return; + } + + context->rPixelMap = context->rImageSource->CreateThumbnail(context->decodingOptsForThumbnail, context->status); + if (context->status != SUCCESS) { + Image_ErrorCode apiErrorCode = ConvertToErrorCode(context->status); + std::string apiErrorMsg = GetErrorCodeMsg(apiErrorCode); + context->errMsgArray.emplace(apiErrorCode, apiErrorMsg); + } + IMAGE_LOGD("CreateThumbnailExecute OUT"); +} + +napi_value ImageSourceNapi::CreateThumbnail(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[TWO_ARGS] = {0}; + size_t argCount = TWO_ARGS; + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, thisVar), nullptr, IMAGE_LOGE("fail to get thisVar")); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to napi_get_cb_info")); + + std::unique_ptr asyncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&asyncContext->constructor_)); + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_), + nullptr, IMAGE_LOGE("fail to unwrap context")); + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_->nativeImgSrc), + nullptr, IMAGE_LOGE("fail to unwrap nativeImgSrc")); + asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc; + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource), + nullptr, IMAGE_LOGE("empty native rImageSource")); + + if (argCount > 0) { + if (ImageNapiUtils::getType(env, argValue[DECODE_OPTS_INDEX_0]) == napi_object) { + if (!ParseDecodeOptionsForThumbnail(env, argValue[DECODE_OPTS_INDEX_0], + &(asyncContext->decodingOptsForThumbnail), asyncContext->errMsg)) { + IMAGE_LOGE("DecodeOptions mismatch"); + return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "DecodeOptions mismatch"); + } + } else { + return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "DecodeOptions type mismatch"); + } + } + napi_create_promise(env, &(asyncContext->deferred), &result); + ImageNapiUtils::HicheckerReport(); + IMG_CREATE_CREATE_ASYNC_WORK_WITH_QOS(env, status, "CreateThumbnail", CreateThumbnailExecute, + CreatePixelMapComplete, asyncContext, asyncContext->work, napi_qos_user_initiated); + + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to create async work")); + return result; +} + +napi_value ImageSourceNapi::CreateThumbnailSync(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + napi_get_undefined(env, &result); + napi_status status; + napi_value thisVar = nullptr; + napi_value argValue[TWO_ARGS] = {0}; + size_t argCount = TWO_ARGS; + IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar); + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, thisVar), nullptr, IMAGE_LOGE("fail to get thisVar")); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to napi_get_cb_info")); + std::unique_ptr syncContext = std::make_unique(); + status = napi_unwrap(env, thisVar, reinterpret_cast(&syncContext->constructor_)); + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, syncContext->constructor_), + nullptr, IMAGE_LOGE("fail to unwrap context")); + IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, syncContext->constructor_->nativeImgSrc), + nullptr, IMAGE_LOGE("fail to unwrap nativeImgSrc")); + + if (argCount > 0) { + if (ImageNapiUtils::getType(env, argValue[DECODE_OPTS_INDEX_0]) == napi_object) { + if (!ParseDecodeOptionsForThumbnail(env, argValue[DECODE_OPTS_INDEX_0], + &(syncContext->decodingOptsForThumbnail), syncContext->errMsg)) { + IMAGE_LOGE("DecodeOptions mismatch"); + return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "DecodeOptions mismatch"); + } + } else { + return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "DecodeOptions type mismatch"); + } + } + syncContext->rPixelMap = syncContext->constructor_->nativeImgSrc->CreateThumbnail( + syncContext->decodingOptsForThumbnail, syncContext->status); + if (syncContext->status != SUCCESS) { + Image_ErrorCode apiErrorCode = ConvertToErrorCode(syncContext->status); + std::string apiErrorMsg = GetErrorCodeMsg(apiErrorCode); + syncContext->errMsgArray.emplace(apiErrorCode, apiErrorMsg); + } + result = CreatePixelMapThrowErrorCompleteSync(env, status, + static_cast((syncContext).get())); + IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to create Thumbnail")); + return result; +} #endif } // namespace Media diff --git a/frameworks/kits/js/common/ndk/image_source_native.cpp b/frameworks/kits/js/common/ndk/image_source_native.cpp index 0785fa744..24391562e 100644 --- a/frameworks/kits/js/common/ndk/image_source_native.cpp +++ b/frameworks/kits/js/common/ndk/image_source_native.cpp @@ -56,6 +56,10 @@ static constexpr int32_t FORMAT_9 = 9; using JpegYuvDecodeError = OHOS::ImagePlugin::JpegYuvDecodeError; static Image_MimeType *IMAGE_SOURCE_SUPPORTED_FORMATS = nullptr; static size_t SUPPORTED_FORMATS_SIZE = 0; +struct OH_DecodingOptionsForThumbnail { + struct Image_Size desiredSize; + bool needGenerate = false; +}; struct OH_DecodingOptions { int32_t pixelFormat; @@ -523,6 +527,14 @@ static void ParseDecodingOps(DecodeOptions &decOps, struct OH_DecodingOptions *o } } +static void ParseDecodingOptsForThumbnail(DecodingOptionsForThumbnail &decOps, + struct OH_DecodingOptionsForThumbnail *ops) +{ + decOps.desiredSize.width = static_cast(ops->desiredSize.width); + decOps.desiredSize.height = static_cast(ops->desiredSize.height); + decOps.needGenerate = ops->needGenerate; +} + static void ParseImageSourceInfo(struct OH_ImageSource_Info *source, const ImageInfo &info) { if (source == nullptr) { @@ -748,6 +760,100 @@ Image_ErrorCode OH_ImageSourceNative_CreatePicture(OH_ImageSourceNative *source, return IMAGE_SUCCESS; } +MIDK_EXPORT +Image_ErrorCode OH_DecodingOptionsForThumbnail_Create(OH_DecodingOptionsForThumbnail **options) +{ + *options = new OH_DecodingOptionsForThumbnail(); + if (*options == nullptr) { + return IMAGE_BAD_PARAMETER; + } + return IMAGE_SUCCESS; +} + +MIDK_EXPORT +Image_ErrorCode OH_DecodingOptionsForThumbnail_GetDesiredSize(OH_DecodingOptionsForThumbnail *options, + Image_Size *desiredSize) +{ + if (options == nullptr || desiredSize == nullptr) { + return IMAGE_BAD_PARAMETER; + } + desiredSize->width = options->desiredSize.width; + desiredSize->height = options->desiredSize.height; + return IMAGE_SUCCESS; +} + +MIDK_EXPORT +Image_ErrorCode OH_DecodingOptionsForThumbnail_SetDesiredSize(OH_DecodingOptionsForThumbnail *options, + Image_Size *desiredSize) +{ + if (options == nullptr || desiredSize == nullptr) { + return IMAGE_BAD_PARAMETER; + } + options->desiredSize.width = desiredSize->width; + options->desiredSize.height = desiredSize->height; + return IMAGE_SUCCESS; +} + +Image_ErrorCode OH_DecodingOptionsForThumbnail_GetNeedGenerate(OH_DecodingOptionsForThumbnail *options, + bool *needGenerate) +{ + if (options == nullptr || needGenerate == nullptr) { + return IMAGE_BAD_PARAMETER; + } + *needGenerate = options->needGenerate; + return IMAGE_SUCCESS; +} + +Image_ErrorCode OH_DecodingOptionsForThumbnail_SetNeedGenerate(OH_DecodingOptionsForThumbnail *options, + bool *needGenerate) +{ + if (options == nullptr || needGenerate == nullptr) { + return IMAGE_BAD_PARAMETER; + } + options->needGenerate = *needGenerate; + return IMAGE_SUCCESS; +} + +MIDK_EXPORT +Image_ErrorCode OH_DecodingOptionsForThumbnail_Release(OH_DecodingOptionsForThumbnail *options) +{ + if (options == nullptr) { + return IMAGE_BAD_PARAMETER; + } + delete options; + options = nullptr; + return IMAGE_SUCCESS; +} + +static bool IsSizeInValid(const Size &size) +{ + return size.width < 0 || size.height < 0; +} + +MIDK_EXPORT +Image_ErrorCode OH_ImageSourceNative_CreateThumbnail(OH_ImageSourceNative *source, OH_DecodingOptionsForThumbnail *ops, + OH_PixelmapNative **pixelmap) +{ + if (source == nullptr || source->GetInnerImageSource() == nullptr || ops == nullptr || pixelmap == nullptr) { + return IMAGE_BAD_PARAMETER; + } + + DecodingOptionsForThumbnail decOps; + uint32_t errorCode = IMAGE_BAD_PARAMETER; + ParseDecodingOptsForThumbnail(decOps, ops); + if (IsSizeInValid(decOps.desiredSize)) { + return IMAGE_BAD_PARAMETER; + } + std::unique_ptr tmpPixelmap = source->GetInnerImageSource()->CreateThumbnail(decOps, errorCode); + if (tmpPixelmap == nullptr || errorCode != IMAGE_SUCCESS) { + return ConvertToErrorCode(errorCode); + } + std::shared_ptr nativePixelmap = std::move(tmpPixelmap); + OH_PixelmapNative *stPixMap = new OH_PixelmapNative(nativePixelmap); + *pixelmap = stPixMap; + return IMAGE_SUCCESS; +} + MIDK_EXPORT Image_ErrorCode OH_ImageSourceNative_CreatePictureAtIndex(OH_ImageSourceNative *source, uint32_t index, OH_PictureNative **picture) diff --git a/frameworks/kits/js/common/picture_napi.cpp b/frameworks/kits/js/common/picture_napi.cpp index 13471f6c6..335d2cce8 100644 --- a/frameworks/kits/js/common/picture_napi.cpp +++ b/frameworks/kits/js/common/picture_napi.cpp @@ -86,6 +86,7 @@ static std::vector auxiliaryPictureTypeMap = { {"UNREFOCUS_MAP", static_cast(AuxiliaryPictureType::UNREFOCUS_MAP), ""}, {"LINEAR_MAP", static_cast(AuxiliaryPictureType::LINEAR_MAP), ""}, {"FRAGMENT_MAP", static_cast(AuxiliaryPictureType::FRAGMENT_MAP), ""}, + {"THUMBNAIL", static_cast(AuxiliaryPictureType::THUMBNAIL), ""}, }; static std::vector metadataTypeMap = { @@ -372,7 +373,7 @@ napi_value PictureNapi::CreatePicture(napi_env env, std::shared_ptr &pi static AuxiliaryPictureType ParseAuxiliaryPictureType(int32_t val) { if (val >= static_cast(AuxiliaryPictureType::GAINMAP) - && val<= static_cast(AuxiliaryPictureType::FRAGMENT_MAP)) { + && val < static_cast(AuxiliaryPictureType::MAX_AUXILIARY_PICTURE_TYPE)) { return AuxiliaryPictureType(val); } diff --git a/interfaces/innerkits/include/auxiliary_generator.h b/interfaces/innerkits/include/auxiliary_generator.h index 162216ff2..9cde63c20 100644 --- a/interfaces/innerkits/include/auxiliary_generator.h +++ b/interfaces/innerkits/include/auxiliary_generator.h @@ -39,6 +39,10 @@ public: static std::shared_ptr GenerateJpegAuxiliaryPicture( const MainPictureInfo &mainInfo, AuxiliaryPictureType type, std::unique_ptr &auxStream, std::unique_ptr &extDecoder, uint32_t &errorCode); + static ImageInfo MakeImageInfo(const Size &size, PixelFormat format, AlphaType alphaType, + ColorSpace colorSpace, const std::string &encodedFormat); + static std::unique_ptr CreatePixelMapByContext(DecodeContext &context, + std::unique_ptr &decoder, const std::string &encodedFormat, uint32_t &errorCode); }; } // namespace Media } // namespace OHOS diff --git a/interfaces/innerkits/include/exif_metadata.h b/interfaces/innerkits/include/exif_metadata.h index bbfcdc68c..298713396 100644 --- a/interfaces/innerkits/include/exif_metadata.h +++ b/interfaces/innerkits/include/exif_metadata.h @@ -40,6 +40,7 @@ public: bool CreateExifdata(); NATIVEEXPORT std::shared_ptr Clone(); void GetFilterArea(const std::vector &exifKeys, std::vector> &ranges); + bool GetThumbnail(uint8_t *&data, uint32_t &size); bool Marshalling(Parcel &parcel) const override; static ExifMetadata *Unmarshalling(Parcel &parcel); static ExifMetadata *Unmarshalling(Parcel &parcel, PICTURE_ERR &error); diff --git a/interfaces/innerkits/include/image_source.h b/interfaces/innerkits/include/image_source.h index bcf81be0f..6e02523e2 100644 --- a/interfaces/innerkits/include/image_source.h +++ b/interfaces/innerkits/include/image_source.h @@ -158,6 +158,8 @@ struct HdrMetadata; class MetadataAccessor; class ExifMetadata; struct StreamInfo; +struct SingleJpegImage; +struct MainPictureInfo; class ImageSource { public: @@ -201,6 +203,8 @@ public: #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM) NATIVEEXPORT std::unique_ptr CreatePicture(const DecodingOptionsForPicture &opts, uint32_t &errorCode); NATIVEEXPORT std::unique_ptr CreatePictureAtIndex(uint32_t index, uint32_t &errorCode); + NATIVEEXPORT std::unique_ptr CreateThumbnail(const DecodingOptionsForThumbnail &opts, + uint32_t &errorCode); #endif // for incremental source. NATIVEEXPORT uint32_t UpdateData(const uint8_t *data, uint32_t size, bool isCompleted); @@ -388,11 +392,19 @@ private: void SetHdrMetadataForPicture(std::unique_ptr &picture); void DecodeHeifAuxiliaryPictures(const std::set &auxTypes, std::unique_ptr &picture, uint32_t &errorCode); + void DecodeSingleJpegAuxiliaryPicture(std::unique_ptr &picture, MainPictureInfo &mainInfo, + const SingleJpegImage &auxInfo, StreamInfo &streamInfo); void DecodeJpegAuxiliaryPicture(std::set &auxTypes, std::unique_ptr &picture, uint32_t &errorCode); bool CheckJpegSourceStream(StreamInfo &streamInfo); uint32_t CreatePictureAtIndexPreCheck(uint32_t index, const ImageInfo &info); uint32_t SetGifMetadataForPicture(std::unique_ptr &picture, uint32_t index); + std::unique_ptr GenerateThumbnail(const DecodingOptionsForThumbnail &opts, uint32_t &errorCode); + std::unique_ptr DecodeExifThumbnail(const DecodingOptionsForThumbnail &opts, + ImagePlugin::DecodeContext &context, const std::string &format, uint32_t &errorCode); + void SetThumbnailForPicture(std::unique_ptr &picture, const std::string &mimeType); + std::unique_ptr DecodeHeifParserThumbnail(const DecodingOptionsForThumbnail &opts, + ImagePlugin::DecodeContext &context, const std::string &format, uint32_t &errorCode); #endif const std::string NINE_PATCH = "ninepatch"; diff --git a/interfaces/innerkits/include/image_type.h b/interfaces/innerkits/include/image_type.h index 7debf06f2..a2daade60 100644 --- a/interfaces/innerkits/include/image_type.h +++ b/interfaces/innerkits/include/image_type.h @@ -39,13 +39,14 @@ namespace Media { #define GIF_METADATA_KEY_DELAY_TIME "GifDelayTime" #define GIF_METADATA_KEY_DISPOSAL_TYPE "GifDisposalType" -// There is no definite tag name for gainmap +// There is no definite tag name for gainmap and thumbnail #define AUXILIARY_TAG_GAINMAP "" #define AUXILIARY_TAG_DEPTH_MAP_BACK "DepthP" #define AUXILIARY_TAG_DEPTH_MAP_FRONT "VShapEn" #define AUXILIARY_TAG_UNREFOCUS_MAP "edof" #define AUXILIARY_TAG_LINEAR_MAP "HighBit" #define AUXILIARY_TAG_FRAGMENT_MAP "Fragmnt" +#define AUXILIARY_TAG_THUMBNAIL "" #define HEIF_AUXTTYPE_ID_GAINMAP "urn:iso:std:iso:ts:21496:-1" #define HEIF_AUXTTYPE_ID_DEPTH_MAP "urn:com:huawei:photo:5:0:0:aux:depthmap" @@ -399,6 +400,8 @@ enum class AuxiliaryPictureType { UNREFOCUS_MAP = 3, LINEAR_MAP = 4, FRAGMENT_MAP = 5, + THUMBNAIL = 6, + MAX_AUXILIARY_PICTURE_TYPE, }; struct AuxiliaryPictureInfo { @@ -423,6 +426,11 @@ struct DecodingOptionsForPicture { AllocatorType allocatorType = AllocatorType::DMA_ALLOC; }; +struct DecodingOptionsForThumbnail { + Size desiredSize; + bool needGenerate = false; +}; + typedef struct PictureError { uint32_t errorCode = 0; std::string errorInfo = ""; diff --git a/interfaces/kits/js/common/include/image_source_napi.h b/interfaces/kits/js/common/include/image_source_napi.h index e07d22755..d3cc22700 100644 --- a/interfaces/kits/js/common/include/image_source_napi.h +++ b/interfaces/kits/js/common/include/image_source_napi.h @@ -82,6 +82,8 @@ private: #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM) static napi_value CreatePicture(napi_env env, napi_callback_info info); static napi_value CreatePictureAtIndex(napi_env env, napi_callback_info info); + static napi_value CreateThumbnail(napi_env env, napi_callback_info info); + static napi_value CreateThumbnailSync(napi_env env, napi_callback_info info); #endif static napi_value CreatePixelMapUsingAllocator(napi_env env, napi_callback_info info); static napi_value CreatePixelMapUsingAllocatorSync(napi_env env, napi_callback_info info); diff --git a/interfaces/kits/native/include/image/image_source_native.h b/interfaces/kits/native/include/image/image_source_native.h index ecb4a8ab8..b6e78e5b5 100644 --- a/interfaces/kits/native/include/image/image_source_native.h +++ b/interfaces/kits/native/include/image/image_source_native.h @@ -204,6 +204,16 @@ Image_ErrorCode OH_ImageSourceInfo_Release(OH_ImageSource_Info *info); struct OH_DecodingOptions; typedef struct OH_DecodingOptions OH_DecodingOptions; +/** + * @brief Defines the options for decoding the image source. + * It is used in {@link OH_ImageSourceNative_CreateThumbnail}. + * + * @since 16 + */ +struct OH_DecodingOptionsForThumbnail; +typedef struct OH_DecodingOptionsForThumbnail OH_DecodingOptionsForThumbnail; + + /** * @brief Create a pointer for InitializationOtions struct. * @@ -541,6 +551,88 @@ Image_ErrorCode OH_ImageSourceNative_CreatePixelmapList(OH_ImageSourceNative *so Image_ErrorCode OH_ImageSourceNative_CreatePicture(OH_ImageSourceNative *source, OH_DecodingOptionsForPicture *options, OH_PictureNative **picture); +/** + * @brief Create Thumbnail pointer from ImageSource + * based on the specified {@link OH_DecodingOptionsForThumbnail} struct. + * + * @param source Indicates a void pointer(from ImageSource pointer convert). + * @param options Indicates a pointer to the options for decoding the image source. + * For details, see {@link OH_DecodingOptionsForThumbnail}. + * @param needGenerate Indicates whether the thumbnail needs to be generated. + * @param pixelMap Indicates a void pointer to the Thumbnail Pixelmap object obtained at the C++ native layer. + * @return Image functions result code. + * {@link IMAGE_SUCCESS} if the execution is successful. + * {@link IMAGE_BAD_PARAMETER} source is nullptr, or pixelmap is nullptr. + * {@link IMAGE_DECODE_FAILED} decode failed. + * @since 16 + */ +Image_ErrorCode OH_ImageSourceNative_CreateThumbnail(OH_ImageSourceNative *source, + OH_DecodingOptionsForThumbnail *options, OH_PixelmapNative **pixelmap); + +/** + * @brief Create a pointer for DecodingOptionsForThumbnail struct. + * + * @param options The DecodingOptionsForThumbnail pointer will be operated. + * @return Image functions result code. + * {@link IMAGE_SUCCESS} if the execution is successful. + * {@link IMAGE_BAD_PARAMETER} options is nullptr. + * @since 16 + */ +Image_ErrorCode OH_DecodingOptionsForThumbnail_Create(OH_DecodingOptionsForThumbnail **options); + +/** + * @brief Get desiredSize number for DecodingOptionsForThumbnail struct. + * + * @param options The DecodingOptionsForThumbnail pointer will be operated. + * @param desiredSize the number of image desiredSize. + * @return Returns {@link Image_ErrorCode} + * @since 16 + */ +Image_ErrorCode OH_DecodingOptionsForThumbnail_GetDesiredSize(OH_DecodingOptionsForThumbnail *options, + Image_Size *desiredSize); + +/** + * @brief Set desiredSize number for DecodingOptionsForThumbnail struct. + * + * @param options The DecodingOptionsForThumbnail pointer will be operated. + * @param desiredSize the number of image desiredSize. + * @return Returns {@link Image_ErrorCode} + * @since 16 + */ +Image_ErrorCode OH_DecodingOptionsForThumbnail_SetDesiredSize(OH_DecodingOptionsForThumbnail *options, + Image_Size *desiredSize); + +/** + * @brief Get needGenerate number for DecodingOptionsForThumbnail struct. + * + * @param options The DecodingOptionsForThumbnail pointer will be operated. + * @param needGenerate the number of image needGenerate. + * @return Returns {@link Image_ErrorCode} + * @since 16 + */ +Image_ErrorCode OH_DecodingOptionsForThumbnail_GetNeedGenerate(OH_DecodingOptionsForThumbnail *options, + bool *needGenerate); + +/** + * @brief Set needGenerate number for DecodingOptionsForThumbnail struct. + * + * @param options The DecodingOptionsForThumbnail pointer will be operated. + * @param needGenerate the number of image needGenerate. + * @return Returns {@link Image_ErrorCode} + * @since 16 + */ +Image_ErrorCode OH_DecodingOptionsForThumbnail_SetNeedGenerate(OH_DecodingOptionsForThumbnail *options, + bool *needGenerate); + +/** + * @brief delete DecodingOptionsForThumbnail pointer. + * + * @param options The DecodingOptionsForThumbnail pointer will be operated. + * @return Returns {@link Image_ErrorCode} + * @since 16 + */ +Image_ErrorCode OH_DecodingOptionsForThumbnail_Release(OH_DecodingOptionsForThumbnail *options); + /** * @brief Decodes an image at the specified index into a Picture object. * diff --git a/interfaces/kits/native/include/image/picture_native.h b/interfaces/kits/native/include/image/picture_native.h index 42eed5065..edeab70d8 100644 --- a/interfaces/kits/native/include/image/picture_native.h +++ b/interfaces/kits/native/include/image/picture_native.h @@ -114,6 +114,10 @@ typedef enum { * Fragment map */ AUXILIARY_PICTURE_TYPE_FRAGMENT_MAP = 5, + /* + * Thumbnail + */ + AUXILIARY_PICTURE_TYPE_THUMBNAIL = 6, } Image_AuxiliaryPictureType; /** diff --git a/plugins/common/libs/image/libextplugin/include/heif_impl/HeifDecoderImpl.h b/plugins/common/libs/image/libextplugin/include/heif_impl/HeifDecoderImpl.h index 1890418d0..19250d20e 100644 --- a/plugins/common/libs/image/libextplugin/include/heif_impl/HeifDecoderImpl.h +++ b/plugins/common/libs/image/libextplugin/include/heif_impl/HeifDecoderImpl.h @@ -69,6 +69,7 @@ public: void getErrMsg(std::string& errMsg) override; uint32_t getColorDepth() override; GridInfo GetGridInfo(); + bool ProcessThumbnailImage(); bool CheckAuxiliaryMap(Media::AuxiliaryPictureType type); bool setAuxiliaryMap(Media::AuxiliaryPictureType type); bool getAuxiliaryMapInfo(HeifFrameInfo* frameInfo); diff --git a/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp b/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp index de64961b5..359ffef39 100644 --- a/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp +++ b/plugins/common/libs/image/libextplugin/src/ext_decoder.cpp @@ -2876,6 +2876,9 @@ bool ExtDecoder::DecodeHeifAuxiliaryMap(DecodeContext& context, AuxiliaryPicture uint64_t byteCount = tempByteCount; context.info.size.width = static_cast(width); context.info.size.height = static_cast(height); + if (!SetOutPutFormat(context.info.pixelFormat, decoder)) { + return ERR_IMAGE_DATA_UNSUPPORT; + } cond = DmaMemAlloc(context, byteCount, dstInfo) != SUCCESS; CHECK_INFO_RETURN_RET_LOG(cond, false, "DmaMemAlloc execution failed."); auto* dstBuffer = static_cast(context.pixelsBuffer.buffer); diff --git a/plugins/common/libs/image/libextplugin/src/ext_encoder.cpp b/plugins/common/libs/image/libextplugin/src/ext_encoder.cpp index f67bfe38f..e85cbfcf5 100644 --- a/plugins/common/libs/image/libextplugin/src/ext_encoder.cpp +++ b/plugins/common/libs/image/libextplugin/src/ext_encoder.cpp @@ -206,6 +206,7 @@ static const std::map DEFAULT_AUXILIARY_TAG_M {AuxiliaryPictureType::UNREFOCUS_MAP, AUXILIARY_TAG_UNREFOCUS_MAP}, {AuxiliaryPictureType::LINEAR_MAP, AUXILIARY_TAG_LINEAR_MAP}, {AuxiliaryPictureType::FRAGMENT_MAP, AUXILIARY_TAG_FRAGMENT_MAP}, + {AuxiliaryPictureType::THUMBNAIL, AUXILIARY_TAG_THUMBNAIL}, }; static const uint8_t NUM_3 = 3; @@ -1959,7 +1960,8 @@ void ExtEncoder::EncodeJpegAuxiliaryPictures(SkWStream& skStream) for (AuxiliaryPictureType auxType : auxTypes) { auto auxPicture = picture_->GetAuxiliaryPicture(auxType); // Gainmap has been encoded before - if (auxPicture == nullptr || auxType == AuxiliaryPictureType::GAINMAP) { + if (auxPicture == nullptr || auxType == AuxiliaryPictureType::GAINMAP || + auxType == AuxiliaryPictureType::THUMBNAIL) { continue; } IMAGE_LOGI("%{public}s try to encode auxiliary picture type: %{public}d", __func__, auxType); diff --git a/plugins/common/libs/image/libextplugin/src/heif_impl/HeifDecoderImpl.cpp b/plugins/common/libs/image/libextplugin/src/heif_impl/HeifDecoderImpl.cpp index 1388cb3e9..88259b6a3 100644 --- a/plugins/common/libs/image/libextplugin/src/heif_impl/HeifDecoderImpl.cpp +++ b/plugins/common/libs/image/libextplugin/src/heif_impl/HeifDecoderImpl.cpp @@ -213,6 +213,22 @@ GridInfo HeifDecoderImpl::GetGridInfo() return gridInfo_; } +bool HeifDecoderImpl::ProcessThumbnailImage() +{ + if (primaryImage_ == nullptr) { + IMAGE_LOGE("Primary image is not init"); + return false; + } + auto thumbImages = primaryImage_->GetThumbnailImages(); + if (thumbImages.size() > 0) { + auxiliaryImage_ = thumbImages[0]; + } else { + IMAGE_LOGE("Heif parser has not thumbnail Images."); + return false; + } + return true; +} + bool HeifDecoderImpl::CheckAuxiliaryMap(AuxiliaryPictureType type) { if (parser_ == nullptr) { @@ -231,6 +247,12 @@ bool HeifDecoderImpl::CheckAuxiliaryMap(AuxiliaryPictureType type) case AuxiliaryPictureType::FRAGMENT_MAP: auxiliaryImage_ = parser_->GetAuxiliaryMapImage(iter->second); break; + case AuxiliaryPictureType::THUMBNAIL: { + if (!ProcessThumbnailImage()) { + return false; + } + break; + } default: auxiliaryImage_ = nullptr; IMAGE_LOGE("Invalid AuxiliaryPictureType: %{public}d", type); -- Gitee