/*
 * Copyright (C) 2021-2026 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "pixel_map.h"
#ifdef EXT_PIXEL
#include "pixel_yuv_ext.h"
#endif
#include <algorithm>
#include <charconv>
#include <chrono>
#include <iostream>
#include <unistd.h>
#if !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
#include <linux/dma-buf.h>
#endif
#include <sys/ioctl.h>

#include "image_log.h"
#include "image_system_properties.h"
#include "image_trace.h"
#include "image_type_converter.h"
#include "image_utils.h"
#include "memory_manager.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkImage.h"
#include "hitrace_meter.h"
#include "media_errors.h"
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
#include "pixel_astc.h"
#endif
#include "pixel_convert.h"
#include "pixel_convert_adapter.h"
#include "pixel_map_utils.h"
#include "post_proc.h"
#include "parcel.h"
#include "pubdef.h"
#include "exif_metadata.h"
#include "image_mdk_common.h"
#include "pixel_yuv.h"
#include "color_utils.h"

#ifndef _WIN32
#include "securec.h"
#else
#include "memory.h"
#endif

#ifdef IMAGE_PURGEABLE_PIXELMAP
#include "purgeable_resource_manager.h"
#endif

#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
#include <sys/mman.h>
#include "ashmem.h"
#include "buffer_handle_parcel.h"
#include "ipc_file_descriptor.h"
#include "surface_buffer.h"
#include "v1_0/buffer_handle_meta_key_type.h"
#include "v1_0/cm_color_space.h"
#include "v1_0/hdr_static_metadata.h"
#include "vpe_utils.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavcodec/avcodec.h"
#ifdef __cplusplus
}
#endif

#undef LOG_DOMAIN
#define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE

#undef LOG_TAG
#define LOG_TAG "PixelMap"

#define BUF_NAME_LEN 255
#define PREFIX_NAME_LEN 11
#define DMA_BUF_SET_LEAK_TYPE _IOW(DMA_BUF_BASE, 5, const char *)

namespace OHOS {
namespace Media {
using namespace std;
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
using namespace HDI::Display::Graphic::Common::V1_0;
#endif
constexpr int32_t MAX_DIMENSION = INT32_MAX >> 2;
constexpr int32_t ASTC_MAX_DIMENSION = 8192;
constexpr int8_t INVALID_ALPHA_INDEX = -1;
constexpr uint8_t ARGB_ALPHA_INDEX = 0;
constexpr uint8_t BGRA_ALPHA_INDEX = 3;
constexpr uint8_t ALPHA_BYTES = 1;
constexpr uint8_t BGRA_BYTES = 4;
constexpr uint8_t RGBA_F16_BYTES = 8;
constexpr uint8_t PER_PIXEL_LEN = 1;
constexpr uint32_t MAX_READ_COUNT = 2048;
constexpr uint8_t FILL_NUMBER = 3;
constexpr uint8_t ALIGN_NUMBER = 4;
constexpr uint8_t YUV420_P010_Y_BYTES = 2; // Bytes per pixel for Y plane

static constexpr uint8_t NUM_1 = 1;
static constexpr uint8_t NUM_2 = 2;
static constexpr uint8_t NUM_3 = 3;
static constexpr uint8_t NUM_4 = 4;
static constexpr uint8_t NUM_5 = 5;
static constexpr uint8_t NUM_6 = 6;
static constexpr uint8_t NUM_7 = 7;
static constexpr uint8_t NUM_8 = 8;
static constexpr float ALPHA_F16_MAX_VALUE = 1.0f;

static uint8_t AlphaF16ToUInt8(const uint8_t *pixel);
static void UInt8ToAlphaF16(uint8_t alpha, uint8_t *pixel);
static float HalfTranslate(const uint8_t* ui);

struct HdrInfo {
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    CM_ColorSpaceType colorSpaceType;
    CM_HDR_Metadata_Type metadataType;
    vector<uint8_t> staticMetadata;
    vector<uint8_t> dynamicMetadata;
#endif
};

struct TlvDecodeInfo {
    int32_t allocType = static_cast<int32_t>(AllocatorType::DEFAULT);
    int32_t isHdr = -1;
    HdrInfo hdrInfo;
    ImageInfo info;
    int32_t csm = -1;
    std::unique_ptr<AbsMemory> dstMemory = nullptr;

    ~TlvDecodeInfo()
    {
        if (dstMemory != nullptr) {
            dstMemory->Release();
            dstMemory.reset();
        }
    }
};

std::atomic<uint32_t> PixelMap::currentId = 0;

PixelMap::~PixelMap()
{
    IMAGE_LOGD("PixelMap::~PixelMap_id:%{public}d width:%{public}d height:%{public}d",
        GetUniqueId(), imageInfo_.size.width, imageInfo_.size.height);
    FreePixelMap();
}

void PixelMap::FreePixelMap() __attribute__((no_sanitize("cfi")))
{
    // remove PixelMap from purgeable LRU if it is purgeable PixelMap
#ifdef IMAGE_PURGEABLE_PIXELMAP
    if (purgeableMemPtr_) {
        PurgeableMem::PurgeableResourceManager::GetInstance().RemoveResource(purgeableMemPtr_);
        purgeableMemPtr_.reset();
        purgeableMemPtr_ = nullptr;
    }
#endif

    auto notifyFreePixelMap = [this]() {
        // SetFreePixelMapProc is a lifecycle hook used by external instrumentation when PixelMap is released.
        // It must not release allocator-owned memory; allocator-specific code below owns the actual cleanup.
        if (freePixelMapProc_ != nullptr) {
            freePixelMapProc_(data_, context_, pixelsSize_);
        }
    };

    if (allocatorType_ == AllocatorType::SHARE_MEM_ALLOC) {
        std::lock_guard<std::mutex> lock(*unmapMutex_);
        if (!isUnMap_ && data_ == nullptr && !displayOnly_) {
            return;
        }
        notifyFreePixelMap();
        ReleaseSharedMemory(data_, context_, pixelsSize_);
        data_ = nullptr;
        context_ = nullptr;
        return;
    }

    notifyFreePixelMap();
    if (data_ == nullptr && context_ == nullptr) {
        return;
    }

    switch (allocatorType_) {
        case AllocatorType::HEAP_ALLOC: {
            if (data_ != nullptr) {
                free(data_);
                data_ = nullptr;
            }
            break;
        }
        case AllocatorType::CUSTOM_ALLOC: {
            if (custFreePixelMap_ != nullptr) {
                custFreePixelMap_(data_, context_, pixelsSize_);
            }
            data_ = nullptr;
            context_ = nullptr;
            break;
        }
        case AllocatorType::DMA_ALLOC: {
#if !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
            ImageUtils::SurfaceBuffer_Unreference(static_cast<SurfaceBuffer*>(context_));
            data_ = nullptr;
            context_ = nullptr;
#endif
            break;
        }
        default: {
            IMAGE_LOGE("unknown allocator type:[%{public}d].", allocatorType_);
            return;
        }
    }
}

void PixelMap::ReleaseSharedMemory(void *addr, void *context, uint32_t size)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    int *fd = static_cast<int *>(context);
    if (!isUnMap_ && addr != nullptr) {
        ::munmap(addr, size);
    }
    if (fd != nullptr) {
        ::close(*fd);
        delete fd;
    }
#endif
}

void PixelMap::SetFreePixelMapProc(CustomFreePixelMap func)
{
    freePixelMapProc_ = func;
}

void PixelMap::SetTransformered(bool isTransformered)
{
    std::unique_lock<std::mutex> lock(*transformMutex_);
    isTransformered_ = isTransformered;
}

void PixelMap::SetPixelsAddr(void *addr, void *context, uint32_t size, AllocatorType type, CustomFreePixelMap func)
{
    std::unique_lock<std::shared_mutex> lock(*pixelDataMutex_);
    if (type < AllocatorType::DEFAULT || type > AllocatorType::DMA_ALLOC) {
        IMAGE_LOGE("SetPixelsAddr error: invalid allocatorType");
        return;
    }
    if (data_ != nullptr) {
        IMAGE_LOGD("SetPixelsAddr release the existed data first");
        FreePixelMap();
    }
    if (type == AllocatorType::SHARE_MEM_ALLOC && context == nullptr) {
        IMAGE_LOGE("SetPixelsAddr error type %{public}d ", type);
    }
    data_ = static_cast<uint8_t *>(addr);
    isUnMap_ = false;
    context_ = context;
    pixelsSize_ = size;
    allocatorType_ = type;
    custFreePixelMap_ = func;
    if (type == AllocatorType::DMA_ALLOC && rowDataSize_ != 0) {
        UpdateImageInfo();
    }
    ImageUtils::FlushSurfaceBuffer(this);
    if (!isUnmarshalling_) {
        MarkPropertiesDirty();
    }
}

void PixelMap::SetPixelsAddr(void *addr, void *context, uint32_t size, AllocatorType type, bool displayOnly)
{
    if (type < AllocatorType::DEFAULT || type > AllocatorType::DMA_ALLOC) {
        IMAGE_LOGE("Unmarshalling setPixelsAddr error invalid allocatorType");
        return;
    }
    if (data_ != nullptr) {
        IMAGE_LOGD("Unmarshalling setPixelsAddr release the existed data first");
        FreePixelMap();
    }
    if (type == AllocatorType::SHARE_MEM_ALLOC && context == nullptr) {
        IMAGE_LOGE("Unmarshalling setPixelsAddr error type %{public}d ", type);
    }
    data_ = static_cast<uint8_t *>(addr);
    isUnMap_ = false;
    context_ = context;
    pixelsSize_ = size;
    allocatorType_ = type;
    custFreePixelMap_ = nullptr;
    if (type == AllocatorType::DMA_ALLOC && rowDataSize_ != 0) {
        UpdateImageInfo();
    }
    if (!displayOnly) {
        ImageUtils::FlushSurfaceBuffer(this);
    }
}

static bool g_setImageInfoAndValidate(std::unique_ptr<PixelMap> &pixelMap, ImageInfo &imageInfo)
{
    if (pixelMap == nullptr) {
        IMAGE_LOGE("pixelmap is nullptr");
        return false;
    }
    if (pixelMap->SetImageInfo(imageInfo) != SUCCESS) {
        IMAGE_LOGE("set image info failed");
        return false;
    }
    int32_t bufferSize = pixelMap->GetByteCount();
    if (bufferSize <= 0 || (pixelMap->GetAllocatorType() == AllocatorType::HEAP_ALLOC &&
        bufferSize > PIXEL_MAP_MAX_RAM_SIZE)) {
        IMAGE_LOGE("Invalid byte count");
        return false;
    }
    return true;
}

unique_ptr<PixelMap> PixelMap::Create(const uint32_t *colors, uint32_t colorLength, const InitializationOptions &opts)
{
    IMAGE_LOGD("PixelMap::Create1 enter");
    return Create(colors, colorLength, 0, opts.size.width, opts);
}

unique_ptr<PixelMap> PixelMap::Create(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t width,
                                      const InitializationOptions &opts)
{
    IMAGE_LOGD("PixelMap::Create2 enter");
    return Create(colors, colorLength, 0, opts.size.width, opts, true);
}

unique_ptr<PixelMap> PixelMap::Create(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t width,
                                      const InitializationOptions &opts, bool useCustomFormat)
{
    int errorCode;
    BUILD_PARAM info;
    info.offset_ = offset;
    info.width_ = width;
    info.flag_ = useCustomFormat;
    return Create(colors, colorLength, info, opts, errorCode);
}

static AVPixelFormat PixelFormatToAVPixelFormat(const PixelFormat &pixelFormat)
{
    auto formatSearch = PixelConvertAdapter::FFMPEG_PIXEL_FORMAT_MAP.find(pixelFormat);
    return (formatSearch != PixelConvertAdapter::FFMPEG_PIXEL_FORMAT_MAP.end()) ?
        formatSearch->second : AVPixelFormat::AV_PIX_FMT_NONE;
}

bool IsYUV(const PixelFormat &format)
{
    return format == PixelFormat::NV12 || format == PixelFormat::NV21 ||
        format == PixelFormat::YCBCR_P010 || format == PixelFormat::YCRCB_P010 ||
        format == PixelFormat::Y8;
}

bool IsYuvP010(const PixelFormat &format)
{
    return format == PixelFormat::YCBCR_P010 || format == PixelFormat::YCRCB_P010;
}

static PixelFormat ResolveCreateFromPixelsSrcPixelFormat(const InitializationOptions &options)
{
    return options.srcPixelFormat == PixelFormat::UNKNOWN ? PixelFormat::BGRA_8888 : options.srcPixelFormat;
}

static PixelFormat ResolveCreateFromPixelsDstPixelFormat(const InitializationOptions &options)
{
    return options.pixelFormat == PixelFormat::UNKNOWN ? PixelFormat::RGBA_8888 : options.pixelFormat;
}

static bool ValidateCreateFromPixelsOptions(const InitializationOptions &options, PixelFormat srcPixelFormat)
{
    PixelFormat dstPixelFormat = ResolveCreateFromPixelsDstPixelFormat(options);
    if (options.allocatorType == AllocatorType::DMA_ALLOC) {
        InitializationOptions opts = options;
        opts.pixelFormat = dstPixelFormat;
        if (!ImageUtils::SetInitializationOptionDmaMem(opts)) {
            return false;
        }
    }
    if (!ImageUtils::PixelMapCreateCheckFormat(srcPixelFormat) ||
        !ImageUtils::PixelMapCreateCheckFormat(dstPixelFormat)) {
        IMAGE_LOGE("[CreateFromPixels] Check format failed, src format: %{public}d, dst format: %{public}d",
            static_cast<uint32_t>(srcPixelFormat), static_cast<uint32_t>(dstPixelFormat));
        return false;
    }
    if (options.size.width <= 0 || options.size.height <= 0 ||
        options.size.width > MAX_DIMENSION || options.size.height > MAX_DIMENSION) {
        IMAGE_LOGE("[CreateFromPixels] Invalid size in options, width: %{public}d, height: %{public}d",
            options.size.width, options.size.height);
        return false;
    }
    if (options.convertColorSpace.srcYuvConversion < YuvConversion::BT601 ||
        options.convertColorSpace.srcYuvConversion >= YuvConversion::BT_MAX ||
        options.convertColorSpace.dstYuvConversion < YuvConversion::BT601 ||
        options.convertColorSpace.dstYuvConversion >= YuvConversion::BT_MAX) {
        IMAGE_LOGE("Invalid convertColorSpace yuvConversion from %{public}d to %{public}d",
            options.convertColorSpace.srcYuvConversion, options.convertColorSpace.dstYuvConversion);
        return false;
    }
    return true;
}

static int64_t GetCreateFromPixelsRequiredByteSize(const InitializationOptions &options, PixelFormat srcPixelFormat)
{
    ImageInfo srcImageInfo = MakeImageInfo(options.size.width, options.size.height, srcPixelFormat,
        AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    int32_t width = srcImageInfo.size.width;
    int32_t height = srcImageInfo.size.height;
    int32_t bytesPerPixel = IsYuvP010(srcPixelFormat) ? YUV420_P010_Y_BYTES : ImageUtils::GetPixelBytes(srcPixelFormat);
    if (width <= 0 || height <= 0 || bytesPerPixel <= 0) {
        return -1;
    }

    if (options.srcRowStride == 0) {
        return PixelMap::GetAllocatedByteCount(srcImageInfo);
    }

    int64_t minRowStride = static_cast<int64_t>(width) * bytesPerPixel;
    int64_t srcRowStride = options.srcRowStride;
    if (srcRowStride <= 0 || srcRowStride < minRowStride) {
        IMAGE_LOGE("[CreateFromPixels] Row stride (%{public}d) is less than "
            "width (%{public}d) * bytes per pixel (%{public}d)", options.srcRowStride, width, bytesPerPixel);
        return -1;
    }

    if (IsYUV(srcPixelFormat)) {
        if (srcPixelFormat == PixelFormat::Y8) {
            return srcRowStride * static_cast<int64_t>(height);
        }
        int64_t uvHeight = static_cast<int64_t>(height + 1) / NUM_2;
        return srcRowStride * (static_cast<int64_t>(height) + uvHeight);
    }

    int32_t activeRowBytes = PixelMap::GetRGBxRowDataSize(srcImageInfo);
    if (activeRowBytes <= 0) {
        return -1;
    }
    return (static_cast<int64_t>(height) - 1) * srcRowStride + activeRowBytes;
}

static bool ValidateCreateFromPixelsInput(const uint8_t *pixels, uint32_t byteSize,
    const InitializationOptions &options, PixelFormat srcPixelFormat)
{
    if (!ValidateCreateFromPixelsOptions(options, srcPixelFormat)) {
        return false;
    }
    if (pixels == nullptr || byteSize == 0 || byteSize > INT32_MAX) {
        IMAGE_LOGE("[CreateFromPixels] Invalid pixel buffer or size (%{public}u)", byteSize);
        return false;
    }
    int64_t requiredSize = GetCreateFromPixelsRequiredByteSize(options, srcPixelFormat);
    if (requiredSize <= 0 || requiredSize > static_cast<int64_t>(byteSize)) {
        IMAGE_LOGE("[CreateFromPixels] Invalid pixels size: %{public}u", byteSize);
        return false;
    }
    return true;
}

int32_t PixelMap::GetRGBxRowDataSize(const ImageInfo& info)
{
    if ((info.pixelFormat <= PixelFormat::UNKNOWN || info.pixelFormat >= PixelFormat::EXTERNAL_MAX) ||
        IsYUV(info.pixelFormat)) {
        IMAGE_LOGE("[ImageUtil]unsupported pixel format");
        return -1;
    }
    int32_t pixelBytes = ImageUtils::GetPixelBytes(info.pixelFormat);
    if (pixelBytes < 0 || (pixelBytes != 0 && info.size.width > INT32_MAX / pixelBytes)) {
        IMAGE_LOGE("[ImageUtil]obtained an out of range value for rgbx pixel bytes");
        return -1;
    }
    return pixelBytes * info.size.width;
}

int32_t PixelMap::GetRGBxByteCount(const ImageInfo& info)
{
    if (IsYUV(info.pixelFormat)) {
        IMAGE_LOGE("[ImageUtil]unsupported pixel format");
        return -1;
    }
    int32_t rowDataSize = GetRGBxRowDataSize(info);
    if (rowDataSize < 0 || (rowDataSize != 0 && info.size.height > INT32_MAX / rowDataSize)) {
        IMAGE_LOGE("[ImageUtil]obtained an out of range value for rgbx row data size");
        return -1;
    }
    return rowDataSize * info.size.height;
}

int32_t PixelMap::GetYUVByteCount(const ImageInfo& info)
{
    if (!IsYUV(info.pixelFormat)) {
        IMAGE_LOGE("[ImageUtil]unsupported pixel format");
        return -1;
    }
    if (info.size.width <= 0 || info.size.height <= 0) {
        IMAGE_LOGE("[ImageUtil]image size error");
        return -1;
    }
    AVPixelFormat avPixelFormat = PixelFormatToAVPixelFormat(info.pixelFormat);
    if (avPixelFormat == AVPixelFormat::AV_PIX_FMT_NONE) {
        IMAGE_LOGE("[ImageUtil]pixel format to ffmpeg pixel format failed");
        return -1;
    }
    return av_image_get_buffer_size(avPixelFormat, info.size.width, info.size.height, 1);
}

// Computes the required allocation size from ImageInfo only.
// This is a static size calculation helper and does not inspect any PixelMap instance state.
int32_t PixelMap::GetAllocatedByteCount(const ImageInfo& info)
{
    if (IsYUV(info.pixelFormat)) {
        return GetYUVByteCount(info);
    } else {
        return GetRGBxByteCount(info);
    }
}

static PixelMap* NewPixelMapByFormat(PixelFormat pixelFormat)
{
    if (IsYUV(pixelFormat)) {
#ifdef EXT_PIXEL
        return new (std::nothrow) PixelYuvExt();
#else
        return new (std::nothrow) PixelYuv();
#endif
    }
    if (ImageUtils::IsAstc(pixelFormat)) {
#if !defined(CROSS_PLATFORM)
        return new (std::nothrow) PixelAstc();
#else
        return nullptr;
#endif
    }
    return new (std::nothrow) PixelMap();
}

static bool ChoosePixelmap(unique_ptr<PixelMap> &dstPixelMap, PixelFormat pixelFormat, int &errorCode)
{
    dstPixelMap.reset(NewPixelMapByFormat(pixelFormat));
    if (dstPixelMap == nullptr) {
        IMAGE_LOGE("[image]Create: make pixelmap failed!");
        errorCode = IMAGE_RESULT_PLUGIN_REGISTER_FAILED;
        return false;
    }
    return true;
}

static void SetYUVDataInfoToPixelMap(unique_ptr<PixelMap> &dstPixelMap)
{
#if !defined(CROSS_PLATFORM)
    ImageUtils::UpdateYUVDataInfo(dstPixelMap);
#endif
}

static int AllocPixelMapMemory(std::unique_ptr<AbsMemory> &dstMemory, int32_t &dstRowStride,
    const ImageInfo &dstImageInfo, const InitializationOptions &opts, bool &isUseDefaultDmaNopadding)
{
    int64_t rowDataSize = ImageUtils::GetRowDataSizeByPixelFormat(dstImageInfo.size.width, dstImageInfo.pixelFormat);
    if (rowDataSize <= 0) {
        IMAGE_LOGE("[PixelMap] AllocPixelMapMemory: Get row data size failed");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    int64_t bufferSize = rowDataSize * dstImageInfo.size.height;
    if (bufferSize > UINT32_MAX) {
        IMAGE_LOGE("[PixelMap]Create: pixelmap size too large: width = %{public}d, height = %{public}d",
            dstImageInfo.size.width, dstImageInfo.size.height);
        return ERR_IMAGE_INVALID_PARAMETER;
    }

    if (IsYUV(dstImageInfo.pixelFormat)) {
        bufferSize = PixelMap::GetYUVByteCount(dstImageInfo);
    }

    MemoryData memoryData = {nullptr, static_cast<size_t>(bufferSize), "Create PixelMap", dstImageInfo.size,
        dstImageInfo.pixelFormat};
    AllocatorType allocType = opts.allocatorType == AllocatorType::DEFAULT ?
        ImageUtils::GetPixelMapAllocatorType(dstImageInfo.size, dstImageInfo.pixelFormat, opts.useDMA,
            memoryData.usage, isUseDefaultDmaNopadding) : opts.allocatorType;
    dstMemory = MemoryManager::CreateMemory(allocType, memoryData);
    if (dstMemory == nullptr) {
        IMAGE_LOGE("[PixelMap]Create: allocate memory failed");
        return ERR_IMAGE_MALLOC_ABNORMAL;
    }

    dstRowStride = dstImageInfo.size.width * ImageUtils::GetPixelBytes(dstImageInfo.pixelFormat);
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (dstMemory->GetType() == AllocatorType::DMA_ALLOC) {
        SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(dstMemory->extend.data);
        if (sbBuffer == nullptr) {
            IMAGE_LOGE("get SurfaceBuffer failed");
            return ERR_IMAGE_MALLOC_ABNORMAL;
        }
        dstRowStride = sbBuffer->GetStride();
    }
#endif

    return IMAGE_RESULT_SUCCESS;
}

unique_ptr<PixelMap> PixelMap::Create(const uint32_t *colors, uint32_t colorLength, BUILD_PARAM &info,
    const InitializationOptions &opts, int &errorCode)
{
    int offset = info.offset_;
    if (!CheckParams(colors, colorLength, offset, info.width_, opts)) {
        errorCode = IMAGE_RESULT_BAD_PARAMETER;
        return nullptr;
    }
    unique_ptr<PixelMap> dstPixelMap;
    if (!ChoosePixelmap(dstPixelMap, opts.pixelFormat, errorCode)) {
        return nullptr;
    }
    PixelFormat format = PixelFormat::BGRA_8888;
    if (info.flag_) {
        format = ((opts.srcPixelFormat == PixelFormat::UNKNOWN) ? PixelFormat::BGRA_8888 : opts.srcPixelFormat);
    }
    ImageInfo srcImageInfo = MakeImageInfo(info.width_, opts.size.height, format, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    PixelFormat dstPixelFormat = opts.pixelFormat == PixelFormat::UNKNOWN ? PixelFormat::RGBA_8888 : opts.pixelFormat;
    AlphaType dstAlphaType =
        opts.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN ? AlphaType::IMAGE_ALPHA_TYPE_PREMUL : opts.alphaType;
    dstAlphaType = ImageUtils::GetValidAlphaTypeByFormat(dstAlphaType, dstPixelFormat);
    ImageInfo dstImageInfo = MakeImageInfo(opts.size.width, opts.size.height, dstPixelFormat, dstAlphaType);
    if (!g_setImageInfoAndValidate(dstPixelMap, dstImageInfo)) {
        IMAGE_LOGE("[PixelMap]Create: check pixelmap failed!");
        errorCode = IMAGE_RESULT_DATA_ABNORMAL;
        return nullptr;
    }

    std::unique_ptr<AbsMemory> dstMemory = nullptr;
    int32_t dstRowStride = 0;
    errorCode = AllocPixelMapMemory(dstMemory, dstRowStride, dstImageInfo, opts,
        dstPixelMap->isUseDefaultDmaNopadding_);
    if (errorCode != IMAGE_RESULT_SUCCESS) {
        return nullptr;
    }

    BufferInfo srcInfo = {const_cast<void*>(static_cast<const void*>(colors + offset)), opts.srcRowStride,
        srcImageInfo, opts.convertColorSpace.srcRange, colorLength, opts.convertColorSpace.srcYuvConversion};
    BufferInfo dstInfo = {dstMemory->data.data, dstRowStride, dstImageInfo, opts.convertColorSpace.dstRange,
        dstMemory->data.size, opts.convertColorSpace.dstYuvConversion};
    int32_t dstLength =
        PixelConvert::PixelsConvert(srcInfo, dstInfo, colorLength, dstMemory->GetType() == AllocatorType::DMA_ALLOC);
    if (dstLength < 0) {
        IMAGE_LOGE("[PixelMap]Create: pixel convert failed.");
        dstMemory->Release();
        errorCode = IMAGE_RESULT_THIRDPART_SKIA_ERROR;
        return nullptr;
    }
    dstPixelMap->SetEditable(opts.editable);
    dstPixelMap->SetPixelsAddr(dstMemory->data.data, dstMemory->extend.data, dstMemory->data.size, dstMemory->GetType(),
        nullptr);
    ImageUtils::DumpPixelMapIfDumpEnabled(dstPixelMap);
    SetYUVDataInfoToPixelMap(dstPixelMap);
    ImageUtils::FlushSurfaceBuffer(const_cast<PixelMap*>(dstPixelMap.get()));
    return dstPixelMap;
}

static bool CheckY8FormatConversion(PixelFormat srcFormat, PixelFormat dstFormat)
{
    if (srcFormat == PixelFormat::Y8 || dstFormat == PixelFormat::Y8) {
        if (srcFormat != dstFormat) {
            IMAGE_LOGE("[PixelMap] Y8 format only supports same format conversion currently.");
            return false;
        }
    }
    return true;
}

pair<unique_ptr<PixelMap>, int32_t> PixelMap::CreateFromPixels(const uint8_t *pixels, uint32_t byteSize,
    const InitializationOptions &options)
{
    int32_t errorCode = SUCCESS;
    PixelFormat srcPixelFormat = ResolveCreateFromPixelsSrcPixelFormat(options);
    PixelFormat dstPixelFormat = ResolveCreateFromPixelsDstPixelFormat(options);
    if (!ValidateCreateFromPixelsInput(pixels, byteSize, options, srcPixelFormat)) {
        return {nullptr, ERR_IMAGE_INVALID_PARAMETER};
    }
    if (srcPixelFormat == PixelFormat::Y8 || dstPixelFormat == PixelFormat::Y8) {
        return {nullptr, ERR_IMAGE_INVALID_PARAMETER};
    }

    unique_ptr<PixelMap> dstPixelMap;
    if (!ChoosePixelmap(dstPixelMap, dstPixelFormat, errorCode)) {
        return {nullptr, errorCode};
    }

    ImageInfo srcImageInfo =
        MakeImageInfo(options.size.width, options.size.height, srcPixelFormat, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    AlphaType dstAlphaType = options.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN ?
        AlphaType::IMAGE_ALPHA_TYPE_PREMUL : options.alphaType;
    dstAlphaType = ImageUtils::GetValidAlphaTypeByFormat(dstAlphaType, dstPixelFormat);
    ImageInfo dstImageInfo = MakeImageInfo(options.size.width, options.size.height, dstPixelFormat, dstAlphaType);
    if (!g_setImageInfoAndValidate(dstPixelMap, dstImageInfo)) {
        return {nullptr, ERR_IMAGE_DATA_ABNORMAL};
    }

    unique_ptr<AbsMemory> dstMemory = nullptr;
    int32_t dstRowStride = 0;
    errorCode = AllocPixelMapMemory(dstMemory, dstRowStride, dstImageInfo, options,
        dstPixelMap->isUseDefaultDmaNopadding_);
    if (errorCode != IMAGE_RESULT_SUCCESS) {
        return {nullptr, errorCode};
    }

    BufferInfo srcInfo = {const_cast<void*>(static_cast<const void*>(pixels)), options.srcRowStride, srcImageInfo,
        options.convertColorSpace.srcRange, byteSize, options.convertColorSpace.srcYuvConversion};
    BufferInfo dstInfo = {dstMemory->data.data, dstRowStride, dstImageInfo, options.convertColorSpace.dstRange,
        dstMemory->data.size, options.convertColorSpace.dstYuvConversion};
    int32_t dstLength =
        PixelConvert::PixelsConvert(srcInfo, dstInfo, byteSize, dstMemory->GetType() == AllocatorType::DMA_ALLOC);
    if (dstLength < 0) {
        IMAGE_LOGE("[CreateFromPixels] Pixel convert failed");
        dstMemory->Release();
        return {nullptr, IMAGE_RESULT_THIRDPART_SKIA_ERROR};
    }

    dstPixelMap->SetEditable(options.editable);
    dstPixelMap->SetPixelsAddr(dstMemory->data.data, dstMemory->extend.data, dstMemory->data.size, dstMemory->GetType(),
        nullptr);
    ImageUtils::DumpPixelMapIfDumpEnabled(dstPixelMap);
    SetYUVDataInfoToPixelMap(dstPixelMap);
    ImageUtils::FlushSurfaceBuffer(dstPixelMap.get());
    return {std::move(dstPixelMap), SUCCESS};
}

void PixelMap::ReleaseBuffer(AllocatorType allocatorType, int fd, uint64_t dataSize, void **buffer)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
        if (buffer != nullptr && *buffer != nullptr) {
            ::munmap(*buffer, dataSize);
            ::close(fd);
        }
        return;
    }
#endif

    if (allocatorType == AllocatorType::HEAP_ALLOC) {
        if (buffer != nullptr && *buffer != nullptr) {
            free(*buffer);
            *buffer = nullptr;
        }
        return;
    }
}

uint32_t PixelMap::SetMemoryName(std::string pixelMapName)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (GetFd() == nullptr) {
        return ERR_MEMORY_NOT_SUPPORT;
    }
    AllocatorType allocatorType = GetAllocatorType();
    if (pixelMapName.empty() ||
        (pixelMapName.size() > BUF_NAME_LEN && allocatorType == AllocatorType::DMA_ALLOC) ||
        (pixelMapName.size() > BUF_NAME_LEN - PREFIX_NAME_LEN && allocatorType == AllocatorType::SHARE_MEM_ALLOC)) {
        return COMMON_ERR_INVALID_PARAMETER;
    }

    if (allocatorType == AllocatorType::DMA_ALLOC) {
        SurfaceBuffer *sbBuffer = static_cast<SurfaceBuffer*>(GetFd());
        int fd = sbBuffer->GetFileDescriptor();
        if (fd < 0) {
            return ERR_MEMORY_NOT_SUPPORT;
        }
        int ret = TEMP_FAILURE_RETRY(ioctl(fd, DMA_BUF_SET_NAME_A, pixelMapName.c_str()));
        if (ret != 0) {
            return ERR_MEMORY_NOT_SUPPORT;
        }
        ret = TEMP_FAILURE_RETRY(ioctl(fd, DMA_BUF_SET_LEAK_TYPE, "pixelmap"));
        if (ret != 0) {
            IMAGE_LOGD("[PixelMap] set dma buf leak type failed");
        }
        return SUCCESS;
    }

    if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
        int *fd = static_cast<int*>(GetFd());
        if (fd == nullptr || *fd < 0) {
            return ERR_MEMORY_NOT_SUPPORT;
        }
        int ret = TEMP_FAILURE_RETRY(ioctl(*fd, ASHMEM_SET_NAME, pixelMapName.c_str()));
        if (ret != 0) {
            IMAGE_LOGE("set ashmem name failed");
            return ERR_MEMORY_NOT_SUPPORT;
        }
        return SUCCESS;
    }
    return ERR_MEMORY_NOT_SUPPORT;
#else
    IMAGE_LOGE("[PixelMap] not support on crossed platform");
    return ERR_MEMORY_NOT_SUPPORT;
#endif
}

void *PixelMap::AllocSharedMemory(const uint64_t bufferSize, int &fd, uint32_t uniqueId)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    std::string name = "PixelMap RawData, uniqueId: " + std::to_string(getpid()) + '_' + std::to_string(uniqueId);
    fd = AshmemCreate(name.c_str(), bufferSize);
    if (fd < 0) {
        IMAGE_LOGE("AllocSharedMemory fd error");
        return nullptr;
    }
    int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
    if (result < 0) {
        IMAGE_LOGE("AshmemSetProt error");
        ::close(fd);
        return nullptr;
    }
    void* ptr = ::mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (ptr == MAP_FAILED) {
        IMAGE_LOGE("mmap error, errno: %{public}s, fd %{public}d, bufferSize %{public}lld",
            strerror(errno), fd, (long long)bufferSize);
        ::close(fd);
        return nullptr;
    }
    return ptr;
#else
    return malloc(bufferSize);
#endif
}

static bool CheckColorSpaceConversion(const InitializationOptions &opts)
{
    if (opts.convertColorSpace.srcYuvConversion < YuvConversion::BT601 ||
        opts.convertColorSpace.srcYuvConversion >= YuvConversion::BT_MAX ||
        opts.convertColorSpace.dstYuvConversion < YuvConversion::BT601 ||
        opts.convertColorSpace.dstYuvConversion >= YuvConversion::BT_MAX) {
        IMAGE_LOGE("convertColorSpace yuvConversion:%{public}d,%{public}d error",
            opts.convertColorSpace.srcYuvConversion, opts.convertColorSpace.dstYuvConversion);
        return false;
    }
    return true;
}

bool DmaAllocCheck(const InitializationOptions &opts)
{
    if (opts.allocatorType == AllocatorType::DMA_ALLOC) {
        InitializationOptions opt = opts;
        if (!ImageUtils::SetInitializationOptionDmaMem(opt)) {
            return false;
        }
    }
    return true;
}

bool PixelMap::CheckParams(const uint32_t *colors, uint32_t colorLength, int32_t offset, int32_t width,
    const InitializationOptions &opts)
{
    if (!DmaAllocCheck(opts)) {
        return false;
    }
    if (!ImageUtils::PixelMapCreateCheckFormat(opts.srcPixelFormat) ||
        !ImageUtils::PixelMapCreateCheckFormat(opts.pixelFormat)) {
        IMAGE_LOGE("[PixelMap] Check format failed. src format: %{public}d, dst format: %{public}d",
            static_cast<uint32_t>(opts.srcPixelFormat), static_cast<uint32_t>(opts.pixelFormat));
        return false;
    }
    if (!CheckY8FormatConversion(opts.srcPixelFormat, opts.pixelFormat)) {
        return false;
    }
    if (colors == nullptr || colorLength <= 0) {
        IMAGE_LOGE("colors invalid");
        return false;
    }
    int32_t dstWidth = opts.size.width;
    int32_t dstHeight = opts.size.height;
    if (dstWidth <= 0 || dstHeight <= 0) {
        IMAGE_LOGE("initial options size invalid");
        return false;
    }
    if (width < dstWidth) {
        IMAGE_LOGE("width: %{public}d must >= width: %{public}d", width, dstWidth);
        return false;
    }
    if (width > MAX_DIMENSION) {
        IMAGE_LOGE("stride %{public}d is out of range", width);
        return false;
    }
    if (opts.srcRowStride != 0 && opts.srcRowStride < width * ImageUtils::GetPixelBytes(opts.srcPixelFormat)) {
        IMAGE_LOGE("row stride %{public}d must be >= width (%{public}d) * row bytes (%{public}d)",
            opts.srcRowStride, width, ImageUtils::GetPixelBytes(opts.srcPixelFormat));
        return false;
    }
    int64_t lastLine = static_cast<int64_t>(dstHeight - 1) * width + offset;
    if (offset < 0 || static_cast<int64_t>(offset) + dstWidth > colorLength || lastLine + dstWidth > colorLength) {
        IMAGE_LOGE("colors length: %{public}u, offset: %{public}d, width: %{public}d  is invalid",
            colorLength, offset, width);
        return false;
    }
    return CheckColorSpaceConversion(opts);
}

static bool CheckPixelMap(unique_ptr<PixelMap>& dstPixelMap, const InitializationOptions &opts)
{
    if (ImageUtils::IsAstc(opts.pixelFormat)) {
        IMAGE_LOGE("Create PixelMap does not support ASTC format");
        return false;
    }
    dstPixelMap.reset(NewPixelMapByFormat(opts.pixelFormat));
    if (dstPixelMap == nullptr) {
        IMAGE_LOGE("create pixelMap pointer fail");
        return false;
    }
    return true;
}

unique_ptr<PixelMap> PixelMap::Create(const InitializationOptions &opts)
{
    unique_ptr<PixelMap> dstPixelMap;
    if (!CheckPixelMap(dstPixelMap, opts)) {
        return nullptr;
    }
    PixelFormat dstPixelFormat = (opts.pixelFormat == PixelFormat::UNKNOWN ? PixelFormat::RGBA_8888 : opts.pixelFormat);
    AlphaType dstAlphaType =
        (opts.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) ? AlphaType::IMAGE_ALPHA_TYPE_PREMUL : opts.alphaType;
    dstAlphaType = ImageUtils::GetValidAlphaTypeByFormat(dstAlphaType, dstPixelFormat);
    ImageInfo dstImageInfo = MakeImageInfo(opts.size.width, opts.size.height, dstPixelFormat, dstAlphaType);
    if (dstPixelMap->SetImageInfo(dstImageInfo) != SUCCESS) {
        IMAGE_LOGE("set image info failed");
        return nullptr;
    }

    std::unique_ptr<AbsMemory> dstMemory = nullptr;
    int32_t dstRowStride = 0;
    int errorCode = AllocPixelMapMemory(dstMemory, dstRowStride, dstImageInfo, opts,
        dstPixelMap->isUseDefaultDmaNopadding_);
    if (errorCode != IMAGE_RESULT_SUCCESS) {
        return nullptr;
    }
    // update alpha opaque
    UpdatePixelsAlpha(dstImageInfo.alphaType, dstImageInfo.pixelFormat,
                      static_cast<uint8_t *>(dstMemory->data.data), *dstPixelMap.get());
    dstPixelMap->SetEditable(opts.editable);
    dstPixelMap->SetPixelsAddr(dstMemory->data.data, dstMemory->extend.data, dstMemory->data.size, dstMemory->GetType(),
        nullptr);
    ImageUtils::DumpPixelMapIfDumpEnabled(dstPixelMap);
    return dstPixelMap;
}

void PixelMap::UpdatePixelsAlpha(const AlphaType &alphaType, const PixelFormat &pixelFormat, uint8_t *dstPixels,
                                 PixelMap &dstPixelMap)
{
    if (dstPixels == nullptr) {
        IMAGE_LOGE("UpdatePixelsAlpha invalid input parameter: dstPixels is null");
        return;
    }

    if (alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) {
        int8_t alphaIndex = -1;
        if (pixelFormat == PixelFormat::RGBA_8888 || pixelFormat == PixelFormat::BGRA_8888) {
            alphaIndex = BGRA_ALPHA_INDEX;
        } else if (pixelFormat == PixelFormat::ARGB_8888) {
            alphaIndex = 0;
        }
        if (alphaIndex != -1) {
            uint32_t pixelBytes = static_cast<uint32_t>(dstPixelMap.GetPixelBytes());
            int32_t bufferSize = dstPixelMap.GetByteCount();
            if (bufferSize <= 0) {
                IMAGE_LOGE("UpdatePixelsAlpha invalid byte count: %{public}d", bufferSize);
                return;
            }
            uint32_t uBufferSize = static_cast<uint32_t>(bufferSize);
            for (uint32_t i = alphaIndex; i < uBufferSize; i += pixelBytes) {
                dstPixels[i] = ALPHA_OPAQUE;
            }
        }
    }
}

static int32_t BuildPixelMap(unique_ptr<PixelMap> &dstPixelMap, const CropValue &cropType,
    ImageInfo &dstImageInfo, const Rect &sRect, const ImageInfo &srcImageInfo)
{
    dstPixelMap = make_unique<PixelMap>();
    if (dstPixelMap == nullptr) {
        IMAGE_LOGE("create pixelmap pointer fail");
        return IMAGE_RESULT_PLUGIN_REGISTER_FAILED;
    }

    if (cropType == CropValue::VALID) {
        dstImageInfo.size.width = sRect.width;
        dstImageInfo.size.height = sRect.height;
    } else {
        dstImageInfo.size = srcImageInfo.size;
    }
    if (dstPixelMap->SetImageInfo(dstImageInfo) != SUCCESS) {
        return IMAGE_RESULT_DATA_ABNORMAL;
    }
    return SUCCESS;
}

unique_ptr<PixelMap> PixelMap::Create(PixelMap &source, const InitializationOptions &opts)
{
    IMAGE_LOGD("PixelMap::Create4 enter");
    Rect rect;
    return Create(source, rect, opts);
}

unique_ptr<PixelMap> PixelMap::Create(PixelMap &source, const Rect &srcRect, const InitializationOptions &opts)
{
    int error;
    return Create(source, srcRect, opts, error);
}

static unique_ptr<PixelMap> CreateFromAstc(PixelMap &source, const Rect &srcRect, const InitializationOptions &opts,
    int32_t &errorCode, CropValue type)
{
    auto pixelAstc = source.Clone(errorCode);
    if (!(errorCode == SUCCESS && pixelAstc != nullptr)) {
        IMAGE_LOGE("clone Astc failed");
        return nullptr;
    }
    if (type == CropValue::VALID && pixelAstc->crop(srcRect) != SUCCESS) {
        IMAGE_LOGE("astc clone crop failed");
        return nullptr;
    }
    if ((opts.size.width != 0 && opts.size.height != 0) &&
        (opts.size.width != pixelAstc->GetWidth() || opts.size.height != pixelAstc->GetHeight())) {
        pixelAstc->scale(static_cast<float>(opts.size.width) / pixelAstc->GetWidth(),
            static_cast<float>(opts.size.height) / pixelAstc->GetHeight());
    }
    errorCode = SUCCESS;
    return pixelAstc;
}

static bool ValidateCreateParams(PixelMap &source, const InitializationOptions &opts, const ImageInfo &srcImageInfo,
    int32_t &errorCode)
{
    if (IsYUV(srcImageInfo.pixelFormat) || IsYUV(opts.pixelFormat)) {
        IMAGE_LOGE("PixelMap::Create does not support yuv format.");
        errorCode = IMAGE_RESULT_DECODE_FAILED;
        return false;
    }
    return true;
}

static CropValue ValidateCropRange(Rect &srcRect, const Size &srcSize, int32_t &errorCode)
{
    CropValue cropType = PostProc::ValidCropValue(srcRect, srcSize);
    if (cropType == CropValue::INVALID) {
        IMAGE_LOGE("src crop range is invalid");
        errorCode = IMAGE_RESULT_DECODE_FAILED;
    }
    return cropType;
}

unique_ptr<PixelMap> PixelMap::Create(PixelMap &source, const Rect &srcRect, const InitializationOptions &opts,
    int32_t &errorCode)
{
    ImageInfo srcImageInfo;
    source.GetImageInfo(srcImageInfo);
    if (!ValidateCreateParams(source, opts, srcImageInfo, errorCode)) {
        return nullptr;
    }
    PostProc postProc;
    Rect sRect = srcRect;
    CropValue cropType = ValidateCropRange(sRect, srcImageInfo.size, errorCode);
    if (cropType == CropValue::INVALID) {
        return nullptr;
    }
    if (ImageUtils::IsAstc(source.GetPixelFormat()) &&
        ImageUtils::IsAstc(opts.pixelFormat) && ImageUtils::IsAstc(opts.srcPixelFormat)) {
        return CreateFromAstc(source, srcRect, opts, errorCode, cropType);
    }
    ImageInfo dstImageInfo;
    InitDstImageInfo(opts, srcImageInfo, dstImageInfo);
    if (!CheckY8FormatConversion(srcImageInfo.pixelFormat, dstImageInfo.pixelFormat)) {
        errorCode = IMAGE_RESULT_DECODE_FAILED;
        return nullptr;
    }
    Size targetSize = dstImageInfo.size;
    // use source if match
    bool isHasConvert = postProc.HasPixelConvert(srcImageInfo, dstImageInfo);
    if (opts.useSourceIfMatch && !source.IsEditable() && !opts.editable && (cropType == CropValue::NOCROP) &&
        !isHasConvert && IsSameSize(srcImageInfo.size, dstImageInfo.size)) {
        source.useSourceAsResponse_ = true;
        return unique_ptr<PixelMap>(&source);
    }
    unique_ptr<PixelMap> dstPixelMap = nullptr;
    if ((errorCode = BuildPixelMap(dstPixelMap, cropType, dstImageInfo, sRect, srcImageInfo)) != SUCCESS) {
        return nullptr;
    }
    // dst pixelmap is source crop and convert pixelmap
    if ((cropType == CropValue::VALID) || isHasConvert) {
        if (!SourceCropAndConvert(source, srcImageInfo, dstImageInfo, sRect, *dstPixelMap.get())) {
            errorCode = IMAGE_RESULT_FORMAT_CONVERT_FAILED;
            return nullptr;
        }
    } else {
        // only maybe size changed, copy source as scale operation
        if (!CopyPixelMap(source, *dstPixelMap.get(), errorCode)) {
            return nullptr;
        }
    }
    if (!ScalePixelMap(targetSize, dstImageInfo.size, opts.scaleMode, *dstPixelMap.get())) {
        return nullptr;
    }
    dstPixelMap->SetEditable(opts.editable);
    ImageUtils::DumpPixelMapIfDumpEnabled(dstPixelMap);
    return dstPixelMap;
}

bool PixelMap::SourceCropAndConvert(PixelMap &source, const ImageInfo &srcImageInfo, const ImageInfo &dstImageInfo,
    const Rect &srcRect, PixelMap &dstPixelMap)
{
    int32_t bufferSize = dstPixelMap.GetByteCount();
    if (bufferSize <= 0 || (source.GetAllocatorType() == AllocatorType::HEAP_ALLOC &&
        bufferSize > PIXEL_MAP_MAX_RAM_SIZE)) {
        IMAGE_LOGE("SourceCropAndConvert  parameter bufferSize:[%{public}d] error.", bufferSize);
        return false;
    }
    size_t uBufferSize = static_cast<size_t>(bufferSize);
    int fd = -1;
    void *dstPixels = nullptr;
    if (source.GetAllocatorType() == AllocatorType::SHARE_MEM_ALLOC) {
        dstPixels = AllocSharedMemory(uBufferSize, fd, dstPixelMap.GetUniqueId());
    } else {
        dstPixels = malloc(uBufferSize);
    }
    if (dstPixels == nullptr) {
        IMAGE_LOGE("source crop allocate memory fail allocatetype: %{public}d ", source.GetAllocatorType());
        return false;
    }
    if (memset_s(dstPixels, uBufferSize, 0, uBufferSize) != EOK) {
        IMAGE_LOGE("dstPixels memset_s failed.");
    }
    Position srcPosition { srcRect.left, srcRect.top };
    if (!PixelConvertAdapter::ReadPixelsConvert(source.GetPixels(), srcPosition, source.GetRowStride(), srcImageInfo,
        dstPixels, dstPixelMap.GetRowStride(), dstImageInfo)) {
        IMAGE_LOGE("pixel convert in adapter failed.");
        ReleaseBuffer(fd >= 0 ? AllocatorType::SHARE_MEM_ALLOC : AllocatorType::HEAP_ALLOC,
            fd, uBufferSize, &dstPixels);
        return false;
    }
    if (fd < 0) {
        dstPixelMap.SetPixelsAddr(dstPixels, nullptr, uBufferSize, AllocatorType::HEAP_ALLOC, nullptr);
        return true;
    }
#ifdef IMAGE_COLORSPACE_FLAG
    OHOS::ColorManager::ColorSpace colorspace = source.InnerGetGrColorSpace();
    dstPixelMap.InnerSetColorSpace(colorspace);
#endif
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    void *fdBuffer = new int32_t();
    *static_cast<int32_t *>(fdBuffer) = fd;
    dstPixelMap.SetPixelsAddr(dstPixels, fdBuffer, uBufferSize, AllocatorType::SHARE_MEM_ALLOC, nullptr);
#else
    dstPixelMap.SetPixelsAddr(dstPixels, nullptr, uBufferSize, AllocatorType::HEAP_ALLOC, nullptr);
#endif
    return true;
}

bool PixelMap::ScalePixelMap(const Size &targetSize, const Size &dstSize, const ScaleMode &scaleMode,
                             PixelMap &dstPixelMap)
{
    if (dstSize.width == targetSize.width && dstSize.height == targetSize.height) {
        return true;
    }
    PostProc postProc;
    if (scaleMode == ScaleMode::FIT_TARGET_SIZE) {
        if (!postProc.ScalePixelMap(targetSize, dstPixelMap)) {
            IMAGE_LOGE("scale FIT_TARGET_SIZE fail");
            return false;
        }
    }
    if (scaleMode == ScaleMode::CENTER_CROP) {
        if (!postProc.CenterScale(targetSize, dstPixelMap)) {
            IMAGE_LOGE("scale CENTER_CROP fail");
            return false;
        }
    }
    return true;
}

void PixelMap::InitDstImageInfo(const InitializationOptions &opts, const ImageInfo &srcImageInfo,
                                ImageInfo &dstImageInfo)
{
    dstImageInfo.size = opts.size;
    if (dstImageInfo.size.width == 0 && dstImageInfo.size.height == 0) {
        dstImageInfo.size = srcImageInfo.size;
    }
    dstImageInfo.pixelFormat = opts.pixelFormat;
    if (dstImageInfo.pixelFormat == PixelFormat::UNKNOWN) {
        dstImageInfo.pixelFormat = srcImageInfo.pixelFormat;
    }
    dstImageInfo.alphaType = opts.alphaType;
    if (dstImageInfo.alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
        dstImageInfo.alphaType = srcImageInfo.alphaType;
    }
}

bool PixelMap::CopyPixMapToDst(PixelMap &source, void* &dstPixels, uint32_t bufferSize)
{
    if (source.GetAllocatorType() == AllocatorType::DMA_ALLOC) {
        ImageInfo imageInfo;
        source.GetImageInfo(imageInfo);
        for (int i = 0; i < imageInfo.size.height; ++i) {
            errno_t ret = memcpy_s(dstPixels, source.GetRowBytes(),
                                   source.GetPixels() + i * source.GetRowStride(), source.GetRowBytes());
            if (ret != 0) {
                IMAGE_LOGE("copy source memory size %{public}u fail", bufferSize);
                return false;
            }
            // Move the destination buffer pointer to the next row
            dstPixels = static_cast<uint8_t *>(dstPixels) + source.GetRowStride();
        }
    } else {
        if (memcpy_s(dstPixels, bufferSize, source.GetPixels(), bufferSize) != 0) {
            IMAGE_LOGE("copy source memory size %{public}u fail", bufferSize);
            return false;
        }
    }
    return true;
}

bool PixelMap::CopyPixelMap(PixelMap &source, PixelMap &dstPixelMap)
{
    int32_t error;
    return CopyPixelMap(source, dstPixelMap, error);
}

static void SetDstPixelMapInfo(PixelMap &source, PixelMap &dstPixelMap, void* dstPixels, unique_ptr<AbsMemory>& memory)
{
    dstPixelMap.SetPixelsAddr(dstPixels, memory->extend.data, memory->data.size, memory->GetType(), nullptr);
    if (source.GetAllocatorType() == AllocatorType::DMA_ALLOC) {
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
        sptr<SurfaceBuffer> sourceSurfaceBuffer(static_cast<SurfaceBuffer*> (source.GetFd()));
        sptr<SurfaceBuffer> dstSurfaceBuffer(static_cast<SurfaceBuffer*> (dstPixelMap.GetFd()));
        VpeUtils::CopySurfaceBufferInfo(sourceSurfaceBuffer, dstSurfaceBuffer);
#endif
    }
#ifdef IMAGE_COLORSPACE_FLAG
    OHOS::ColorManager::ColorSpace colorspace = source.InnerGetGrColorSpace();
    dstPixelMap.InnerSetColorSpace(colorspace);
#endif
}

bool PixelMap::CopyPixelMap(PixelMap &source, PixelMap &dstPixelMap, int32_t &error)
{
    if (source.GetPixels() == nullptr) {
        IMAGE_LOGE("source pixelMap data invalid");
        error = IMAGE_RESULT_GET_DATA_ABNORMAL;
        return false;
    }
    int32_t bufferSize = source.GetByteCount();
    if (bufferSize <= 0 || (source.GetAllocatorType() == AllocatorType::HEAP_ALLOC &&
        bufferSize > PIXEL_MAP_MAX_RAM_SIZE)) {
        IMAGE_LOGE("CopyPixelMap parameter bufferSize:[%{public}d] error.", bufferSize);
        error = IMAGE_RESULT_DATA_ABNORMAL;
        return false;
    }
    size_t uBufferSize = static_cast<size_t>(bufferSize);
    void *dstPixels = nullptr;
    ImageInfo dstImageInfo;
    dstPixelMap.GetImageInfo(dstImageInfo);
    MemoryData memoryData = {nullptr, uBufferSize, "Copy ImageData", dstImageInfo.size, dstImageInfo.pixelFormat,
        source.GetNoPaddingUsage()};
    AllocatorType allocType = source.GetAllocatorType();
    if (source.GetAllocatorType() == AllocatorType::DEFAULT ||
        source.GetAllocatorType() == AllocatorType::CUSTOM_ALLOC) {
        allocType = ImageUtils::GetPixelMapAllocatorType(dstImageInfo.size, dstImageInfo.pixelFormat, false,
            memoryData.usage, dstPixelMap.isUseDefaultDmaNopadding_);
    }
    unique_ptr<AbsMemory> memory = MemoryManager::CreateMemory(allocType, memoryData);
    if (memory == nullptr) {
        return false;
    }
    dstPixels = memory->data.data;
    if (dstPixels == nullptr) {
        IMAGE_LOGE("source crop allocate memory fail allocatetype: %{public}d ", source.GetAllocatorType());
        error = IMAGE_RESULT_MALLOC_ABNORMAL;
        return false;
    }
    void *tmpDstPixels = dstPixels;
    if (!CopyPixMapToDst(source, tmpDstPixels, uBufferSize)) {
        memory->Release();
        error = IMAGE_RESULT_ERR_SHAMEM_DATA_ABNORMAL;
        return false;
    }
    SetDstPixelMapInfo(source, dstPixelMap, dstPixels, memory);
    return true;
}

bool CheckImageInfo(const ImageInfo &imageInfo, int32_t &errorCode, AllocatorType type, int32_t rowDataSize)
{
    if (IsYUV(imageInfo.pixelFormat)) {
        errorCode = IMAGE_RESULT_DATA_UNSUPPORT;
        IMAGE_LOGE("[PixelMap] PixelMap type does not support clone");
        return false;
    }
    if (static_cast<uint64_t>(rowDataSize) * static_cast<uint64_t>(imageInfo.size.height) >
        (type == AllocatorType::HEAP_ALLOC ? PIXEL_MAP_MAX_RAM_SIZE : INT_MAX)) {
        errorCode = IMAGE_RESULT_TOO_LARGE;
        IMAGE_LOGE("[PixelMap] PixelMap size too large");
        return false;
    }
    errorCode = SUCCESS;
    return true;
}

static unique_ptr<PixelMap> CloneAstc(PixelMap *srcAstc, int32_t &errorCode)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    unique_ptr<PixelMap> dstAstc = make_unique<PixelAstc>();
    ImageInfo srcAstcInfo;
    srcAstc->GetImageInfo(srcAstcInfo);
    dstAstc->SetImageInfo(srcAstcInfo);

    Size astcRealSize;
    srcAstc->GetAstcRealSize(astcRealSize);
    dstAstc->SetAstcRealSize(astcRealSize);

    dstAstc->SetAstcHdr(srcAstc->IsHdr());
    dstAstc->SetRowStride(srcAstc->GetRowStride());
    dstAstc->SetAstc(true);

    AllocatorType allocType = srcAstc->GetAllocatorType();
    uint32_t astcSize = srcAstc->GetCapacity();

    MemoryData memoryData = {nullptr, static_cast<size_t>(astcSize), "CloneAstc", {astcSize, 1},
        srcAstcInfo.pixelFormat};
    auto dstMemory = MemoryManager::CreateMemory(allocType, memoryData);
    if (dstMemory == nullptr || dstMemory->data.data == nullptr) {
        IMAGE_LOGE("CloneAstc create memory failed");
        return nullptr;
    }
    if (memcpy_s(dstMemory->data.data, astcSize, srcAstc->GetPixels(), astcSize) != 0) {
        dstMemory->Release();
        IMAGE_LOGE("CloneAstc source memory size %{public}u", astcSize);
        return nullptr;
    }
    dstAstc->SetPixelsAddr(dstMemory->data.data, dstMemory->extend.data, dstMemory->data.size, dstMemory->GetType(),
        nullptr);
#ifdef IMAGE_COLORSPACE_FLAG
    OHOS::ColorManager::ColorSpace colorspace = srcAstc->InnerGetGrColorSpace();
    dstAstc->InnerSetColorSpace(colorspace);
#endif
    return dstAstc;
#endif
    return nullptr;
}

unique_ptr<PixelMap> PixelMap::Clone(int32_t &errorCode)
{
    return clone(errorCode);
}

unique_ptr<PixelMap> PixelMap::clone(int32_t &errorCode)
{
    if (!CheckImageInfo(imageInfo_, errorCode, allocatorType_, rowDataSize_)) {
        return nullptr;
    }
    unique_ptr<PixelMap> pixelMap = nullptr;
    if (isAstc_ && ImageUtils::IsAstc(imageInfo_.pixelFormat)) {
        pixelMap = CloneAstc(this, errorCode);
    } else {
        InitializationOptions opts;
        opts.srcPixelFormat = imageInfo_.pixelFormat;
        opts.pixelFormat = imageInfo_.pixelFormat;
        opts.alphaType = imageInfo_.alphaType;
        opts.size = imageInfo_.size;
        opts.srcRowStride = rowStride_;
        opts.editable = editable_;
        opts.useDMA = allocatorType_ == AllocatorType::DMA_ALLOC;
        pixelMap = PixelMap::Create(opts);
        if (bool notNull = (pixelMap != nullptr); notNull && !CopyPixelMap(*this, *(pixelMap.get()), errorCode)) {
            errorCode = IMAGE_RESULT_MALLOC_ABNORMAL;
            IMAGE_LOGE("[PixelMap] Copy PixelMap data failed");
            return nullptr;
        }
    }
    if (!pixelMap) {
        errorCode = IMAGE_RESULT_INIT_ABNORMAL;
        IMAGE_LOGE("[PixelMap] Initial a empty PixelMap failed");
        return nullptr;
    }
    if (!ImageUtils::IsAstc(pixelMap->GetPixelFormat())) {
        pixelMap->SetTransformered(isTransformered_);
    }
    TransformData transformData;
    GetTransformData(transformData);
    pixelMap->SetTransformData(transformData);
    pixelMap->SetHdrType(GetHdrType());
    pixelMap->SetHdrMetadata(GetHdrMetadata());
    errorCode = SUCCESS;
    return pixelMap;
}

bool PixelMap::IsSameSize(const Size &src, const Size &dst)
{
    return (src.width == dst.width) && (src.height == dst.height);
}

bool PixelMap::GetPixelFormatDetail(const PixelFormat format)
{
    switch (format) {
        case PixelFormat::RGBA_8888: {
            pixelBytes_ = ARGB_8888_BYTES;
            colorProc_ = RGBA8888ToARGB;
            break;
        }
        case PixelFormat::RGBA_1010102: {
            pixelBytes_ = ARGB_8888_BYTES;
            break;
        }
        case PixelFormat::BGRA_8888: {
            pixelBytes_ = ARGB_8888_BYTES;
            colorProc_ = BGRA8888ToARGB;
            break;
        }
        case PixelFormat::ARGB_8888: {
            pixelBytes_ = ARGB_8888_BYTES;
            colorProc_ = ARGB8888ToARGB;
            break;
        }
        case PixelFormat::ALPHA_8:
        case PixelFormat::ALPHA_U8: {
            pixelBytes_ = ALPHA_8_BYTES;
            colorProc_ = ALPHA8ToARGB;
            break;
        }
        case PixelFormat::ALPHA_F16: {
            pixelBytes_ = ALPHA_F16_BYTES;
            colorProc_ = ALPHAF16ToARGB;
            break;
        }
        case PixelFormat::Y8: {
            pixelBytes_ = Y8_BYTES;
            break;
        }
        case PixelFormat::RGB_565: {
            pixelBytes_ = RGB_565_BYTES;
            colorProc_ = RGB565ToARGB;
            break;
        }
        case PixelFormat::RGB_888: {
            pixelBytes_ = RGB_888_BYTES;
            colorProc_ = RGB888ToARGB;
            break;
        }
        case PixelFormat::NV12:
        case PixelFormat::NV21: {
            pixelBytes_ = YUV420_BYTES;
            break;
        }
        case PixelFormat::YCBCR_P010:
        case PixelFormat::YCRCB_P010: {
            pixelBytes_ = YUV420_P010_BYTES;
            break;
        }
        case PixelFormat::CMYK:
            pixelBytes_ = ARGB_8888_BYTES;
            break;
        case PixelFormat::RGBA_F16:
            pixelBytes_ = BGRA_F16_BYTES;
            break;
        case PixelFormat::ASTC_4x4:
        case PixelFormat::ASTC_6x6:
        case PixelFormat::ASTC_8x8:
            pixelBytes_ = ASTC_4x4_BYTES;
            break;
        default: {
            IMAGE_LOGE("pixel format:[%{public}d] not supported.", format);
            return false;
        }
    }
    return true;
}

void PixelMap::SetRowStride(uint32_t stride)
{
    rowStride_ = static_cast<int32_t>(stride);
}

bool PixelMap::CheckValidParam(int32_t x, int32_t y)
{
    const int32_t height = imageInfo_.size.height;
    if (isUnMap_ || data_ == nullptr || height <= 0 || rowDataSize_ <= 0 || x >= imageInfo_.size.width || x < 0 ||
        y >= height || y < 0) {
        return false;
    }
    const uint64_t requiredSize = static_cast<uint64_t>(rowDataSize_) * static_cast<uint64_t>(height);
    return pixelsSize_ >= requiredSize && CheckPixelMapDataSize(this);
}

void PixelMap::UpdateImageInfo()
{
    SetImageInfo(imageInfo_, true);
}

uint32_t PixelMap::SetImageInfo(ImageInfo &info)
{
    return SetImageInfo(info, false);
}

uint32_t PixelMap::SetRowDataSizeForImageInfo(ImageInfo info)
{
    rowDataSize_ = ImageUtils::GetRowDataSizeByPixelFormat(info.size.width, info.pixelFormat);
    if (rowDataSize_ <= 0) {
        IMAGE_LOGE("set imageInfo failed, rowDataSize_ invalid");
        return rowDataSize_ < 0 ? ERR_IMAGE_TOO_LARGE : ERR_IMAGE_DATA_ABNORMAL;
    }

    if (ImageUtils::IsAlpha8(info.pixelFormat) || info.pixelFormat == PixelFormat::ALPHA_F16) {
        SetRowStride(rowDataSize_);
        IMAGE_LOGI("Alpha format rowDataSize_ = %{public}d", rowDataSize_);
    } else if (!ImageUtils::IsAstc(info.pixelFormat)) {
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
        if (allocatorType_ == AllocatorType::DMA_ALLOC) {
            if (context_ == nullptr) {
                IMAGE_LOGE("set imageInfo failed, context_ is null");
                return ERR_IMAGE_DATA_ABNORMAL;
            }
            SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(context_);
            SetRowStride(sbBuffer->GetStride());
        } else {
            SetRowStride(rowDataSize_);
        }
#else
        SetRowStride(rowDataSize_);
#endif
    }
    return SUCCESS;
}

uint32_t PixelMap::SetImageInfo(ImageInfo &info, bool isReused)
{
    if (info.size.width <= 0 || info.size.height <= 0) {
        IMAGE_LOGE("PixelMap width (%{public}d) or height (%{public}d) invalid.", info.size.width, info.size.height);
        return ERR_IMAGE_DATA_ABNORMAL;
    }

    if (!GetPixelFormatDetail(info.pixelFormat)) {
        return ERR_IMAGE_DATA_UNSUPPORT;
    }
    if (pixelBytes_ <= 0) {
        ResetPixelMap();
        IMAGE_LOGE("PixelMap pixel bytes (%{public}d) invalid.", pixelBytes_);
        return ERR_IMAGE_DATA_ABNORMAL;
    }

    uint32_t ret = SetRowDataSizeForImageInfo(info);
    if (ret != SUCCESS) {
        IMAGE_LOGE("PixelMap set rowDataSize error (%{public}d).", ret);
        return ret;
    }

    int64_t totalSize = static_cast<int64_t>(std::max(rowDataSize_, GetRowStride())) * info.size.height;
    if (totalSize > (allocatorType_ == AllocatorType::HEAP_ALLOC ? PIXEL_MAP_MAX_RAM_SIZE : INT32_MAX)) {
        ResetPixelMap();
        IMAGE_LOGE("PixelMap total size (%{public}lld) out of range.", static_cast<long long>(totalSize));
        return ERR_IMAGE_TOO_LARGE;
    }

    if (!isReused) {
        FreePixelMap();
    }
    imageInfo_ = info;
    if (!isUnmarshalling_) {
        MarkPropertiesDirty();
    }
    return SUCCESS;
}

const uint8_t *PixelMap::GetPixel8(int32_t x, int32_t y)
{
    if (!CheckValidParam(x, y) || (pixelBytes_ != ALPHA_8_BYTES && pixelBytes_ != Y8_BYTES)) {
        IMAGE_LOGE("get addr8 pixel position:(%{public}d, %{public}d) pixel bytes:%{public}d invalid.", x, y,
            pixelBytes_);
        return nullptr;
    }
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    return (data_ + y * rowStride_ + x);
#else
    return (data_ + y * rowDataSize_  + x);
#endif
}

const uint16_t *PixelMap::GetPixel16(int32_t x, int32_t y)
{
    if (!CheckValidParam(x, y) || (pixelBytes_ != RGB_565_BYTES && pixelBytes_ != ALPHA_F16_BYTES)) {
        IMAGE_LOGE("get addr16 pixel position:(%{public}d, %{public}d) pixel bytes:%{public}d invalid.", x, y,
            pixelBytes_);
        return nullptr;
    }
    // convert uint8_t* to uint16_t*
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    return reinterpret_cast<uint16_t *>(data_ + y * rowStride_ + (static_cast<uint32_t>(x) << RGB_565_SHIFT));
#else
    return reinterpret_cast<uint16_t *>(data_ + y * rowDataSize_ + (static_cast<uint32_t>(x) << RGB_565_SHIFT));
#endif
}

const uint32_t *PixelMap::GetPixel32(int32_t x, int32_t y)
{
    if (!CheckValidParam(x, y) || (pixelBytes_ != ARGB_8888_BYTES)) {
        IMAGE_LOGE("get addr32 pixel position:(%{public}d, %{public}d) pixel bytes:%{public}d invalid.", x, y,
            pixelBytes_);
        return nullptr;
    }
    // convert uint8_t* to uint32_t*
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    return reinterpret_cast<uint32_t *>(data_ + y * rowStride_ + (static_cast<uint32_t>(x) << ARGB_8888_SHIFT));
#else
    return reinterpret_cast<uint32_t *>(data_ + y * rowDataSize_ + (static_cast<uint32_t>(x) << ARGB_8888_SHIFT));
#endif
}

const uint8_t *PixelMap::GetPixel(int32_t x, int32_t y)
{
    if (isAstc_ || IsYUV(imageInfo_.pixelFormat)) {
        IMAGE_LOGE("GetPixel does not support astc and yuv pixel format.");
        return nullptr;
    }
    if (!CheckValidParam(x, y)) {
        IMAGE_LOGE("input pixel position:(%{public}d, %{public}d) invalid.", x, y);
        return nullptr;
    }
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    return (data_ + y * rowStride_ + (static_cast<uint32_t>(x) * pixelBytes_));
#else
    return (data_ + y * rowDataSize_ + (static_cast<uint32_t>(x) * pixelBytes_));
#endif
}

bool PixelMap::GetARGB32Color(int32_t x, int32_t y, uint32_t &color)
{
    if (colorProc_ == nullptr) {
        IMAGE_LOGE("pixel format not supported.");
        return false;
    }
    const uint8_t *src = GetPixel(x, y);
    if (src == nullptr) {
        IMAGE_LOGE("get pixel color error.");
        return false;
    }
    // use founction point for frequently called interface
    return colorProc_(src, ONE_PIXEL_SIZE * pixelBytes_, &color, ONE_PIXEL_SIZE);
}

bool PixelMap::GetRGBA1010102Color(int32_t x, int32_t y, uint32_t &color)
{
    if (imageInfo_.pixelFormat != PixelFormat::RGBA_1010102) {
        IMAGE_LOGE("%{public}s pixel format not supported, format: %{public}d", __func__, imageInfo_.pixelFormat);
        return false;
    }
    const uint8_t *src = GetPixel(x, y);
    if (src == nullptr) {
        IMAGE_LOGE("%{public}s get pixel color error.", __func__);
        return false;
    }
    color = *reinterpret_cast<const uint32_t*>(src);
    return true;
}

uint32_t PixelMap::ModifyImageProperty(const std::string &key, const std::string &value)
{
    if (exifMetadata_ == nullptr) {
        return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
    }

    if (!exifMetadata_->SetValue(key, value)) {
        return ERR_MEDIA_VALUE_INVALID;
    }

    return SUCCESS;
}

uint32_t PixelMap::GetImagePropertyInt(const std::string &key, int32_t &value)
{
    if (exifMetadata_ == nullptr) {
        return ERR_MEDIA_NO_EXIF_DATA;
    }

    std::string strValue;
    int  ret = exifMetadata_->GetValue(key, strValue);
    if (ret != SUCCESS) {
        return ret;
    }

    std::from_chars_result res = std::from_chars(strValue.data(), strValue.data() + strValue.size(), value);
    if (res.ec != std::errc()) {
        return ERR_IMAGE_SOURCE_DATA;
    }

    return SUCCESS;
}

uint32_t PixelMap::GetImagePropertyString(const std::string &key, std::string &value)
{
    if (exifMetadata_ == nullptr) {
        return ERR_MEDIA_NO_EXIF_DATA;
    }

    return exifMetadata_->GetValue(key, value);
}

bool PixelMap::ALPHA8ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount)
{
    if (in == nullptr || out == nullptr) {
        IMAGE_LOGE("ALPHA8ToARGB invalid input parameter: in or out is null");
        return false;
    }
    if (inCount != outCount) {
        IMAGE_LOGE("input count:%{public}u is not match to output count:%{public}u.", inCount, outCount);
        return false;
    }
    const uint8_t *src = in;
    for (uint32_t i = 0; i < outCount; i++) {
        *out++ = GetColorARGB(*src++, BYTE_ZERO, BYTE_ZERO, BYTE_ZERO);
    }
    return true;
}

bool PixelMap::ALPHAF16ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount)
{
    if (in == nullptr || out == nullptr) {
        IMAGE_LOGE("ALPHAF16ToARGB invalid input parameter: in or out is null");
        return false;
    }
    if (((inCount / ALPHA_F16_BYTES) != outCount) || ((inCount % ALPHA_F16_BYTES) != 0)) {
        IMAGE_LOGE("input count:%{public}u is not match to output count:%{public}u.", inCount, outCount);
        return false;
    }
    const uint8_t *src = in;
    for (uint32_t i = 0; i < outCount; i++) {
        float alpha = HalfTranslate(src);
        alpha = std::clamp(alpha, 0.0f, ALPHA_F16_MAX_VALUE);
        *out++ = GetColorARGB(static_cast<uint8_t>(alpha * UINT8_MAX + HALF_ONE), BYTE_ZERO, BYTE_ZERO, BYTE_ZERO);
        src += ALPHA_F16_BYTES;
    }
    return true;
}

bool PixelMap::RGB565ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount)
{
    if (in == nullptr || out == nullptr) {
        IMAGE_LOGE("RGB565ToARGB invalid input parameter: in or out is null");
        return false;
    }
    if (((inCount / RGB_565_BYTES) != outCount) || ((inCount % RGB_565_BYTES) != 0)) {
        IMAGE_LOGE("input count:%{public}u is not match to output count:%{public}u.", inCount, outCount);
        return false;
    }
    const uint16_t *src = reinterpret_cast<const uint16_t *>(in);
    for (uint32_t i = 0; i < outCount; i++) {
        uint16_t color = *src++;
        *out++ = GetColorARGB(BYTE_FULL, RGB565ToR32(color), RGB565ToG32(color), RGB565ToB32(color));
    }
    return true;
}

bool PixelMap::ARGB8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount)
{
    if (in == nullptr || out == nullptr) {
        IMAGE_LOGE("ARGB8888ToARGB invalid input parameter: in or out is null");
        return false;
    }
    if (((inCount / ARGB_8888_BYTES) != outCount) && ((inCount % ARGB_8888_BYTES) != 0)) {
        IMAGE_LOGE("input count:%{public}u is not match to output count:%{public}u.", inCount, outCount);
        return false;
    }
    const uint32_t *src = reinterpret_cast<const uint32_t *>(in);
    for (uint32_t i = 0; i < outCount; i++) {
        uint32_t color = *src++;
        *out++ = GetColorARGB(GetColorComp(color, ARGB32_A_SHIFT), GetColorComp(color, ARGB32_R_SHIFT),
                              GetColorComp(color, ARGB32_G_SHIFT), GetColorComp(color, ARGB32_B_SHIFT));
    }
    return true;
}

bool PixelMap::RGBA8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount)
{
    if (in == nullptr || out == nullptr) {
        IMAGE_LOGE("RGBA8888ToARGB invalid input parameter: in or out is null");
        return false;
    }
    if (((inCount / ARGB_8888_BYTES) != outCount) && ((inCount % ARGB_8888_BYTES) != 0)) {
        IMAGE_LOGE("input count:%{public}u is not match to output count:%{public}u.", inCount, outCount);
        return false;
    }
    const uint32_t *src = reinterpret_cast<const uint32_t *>(in);
    for (uint32_t i = 0; i < outCount; i++) {
        uint32_t color = *src++;
        *out++ = GetColorARGB(GetColorComp(color, RGBA32_A_SHIFT), GetColorComp(color, RGBA32_R_SHIFT),
                              GetColorComp(color, RGBA32_G_SHIFT), GetColorComp(color, RGBA32_B_SHIFT));
    }
    return true;
}

bool PixelMap::BGRA8888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount)
{
    if (in == nullptr || out == nullptr) {
        IMAGE_LOGE("BGRA8888ToARGB invalid input parameter: in or out is null");
        return false;
    }
    if (((inCount / ARGB_8888_BYTES) != outCount) && ((inCount % ARGB_8888_BYTES) != 0)) {
        IMAGE_LOGE("input count:%{public}u is not match to output count:%{public}u.", inCount, outCount);
        return false;
    }
    const uint32_t *src = reinterpret_cast<const uint32_t *>(in);
    for (uint32_t i = 0; i < outCount; i++) {
        uint32_t color = *src++;
        *out++ = GetColorARGB(GetColorComp(color, BGRA32_A_SHIFT), GetColorComp(color, BGRA32_R_SHIFT),
                              GetColorComp(color, BGRA32_G_SHIFT), GetColorComp(color, BGRA32_B_SHIFT));
    }
    return true;
}

bool PixelMap::RGB888ToARGB(const uint8_t *in, uint32_t inCount, uint32_t *out, uint32_t outCount)
{
    if (in == nullptr || out == nullptr) {
        IMAGE_LOGE("RGB888ToARGB invalid input parameter: in or out is null");
        return false;
    }
    if (((inCount / RGB_888_BYTES) != outCount) || ((inCount % RGB_888_BYTES) != 0)) {
        IMAGE_LOGE("input count:%{public}u is not match to output count:%{public}u.", inCount, outCount);
        return false;
    }
    const uint8_t *src = in;
    for (uint32_t i = 0; i < outCount; i++) {
        uint8_t colorR = *src++;
        uint8_t colorG = *src++;
        uint8_t colorB = *src++;
        *out++ = GetColorARGB(BYTE_FULL, colorR, colorG, colorB);
    }
    return true;
}

int32_t PixelMap::GetPixelBytes()
{
    return pixelBytes_;
}

int32_t PixelMap::GetRowBytes()
{
    return rowDataSize_;
}

int32_t PixelMap::GetByteCount()
{
    IMAGE_LOGD("GetByteCount");
    if (IsYUV(imageInfo_.pixelFormat)) {
        return GetYUVByteCount(imageInfo_);
    }

    int64_t rowDataSize = rowDataSize_;
    int64_t height = imageInfo_.size.height;
    if (isAstc_) {
        Size realSize;
        GetAstcRealSize(realSize);
        rowDataSize = ImageUtils::GetRowDataSizeByPixelFormat(realSize.width, imageInfo_.pixelFormat);
        height = realSize.height;
    }
    int64_t byteCount = rowDataSize * height;
    if (rowDataSize <= 0 || byteCount > INT32_MAX) {
        IMAGE_LOGE("[PixelMap] GetByteCount failed: invalid rowDataSize or byteCount overflowed");
        return 0;
    }
    return static_cast<int32_t>(byteCount);
}

// Returns the actual allocation size owned by this PixelMap instance.
// This may come from instance-backed storage such as pixelsSize_ or a DMA SurfaceBuffer.
uint32_t PixelMap::GetAllocationByteCount()
{
    uint32_t allocatedBytes = pixelsSize_;
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (allocatorType_ == AllocatorType::DMA_ALLOC) {
        if (context_ == nullptr) {
            IMAGE_LOGE("[PixelMap] GetAllocationByteCount failed: context_ is null");
            return 0;
        }
        SurfaceBuffer* sb = static_cast<SurfaceBuffer*>(context_);
        allocatedBytes = sb->GetSize();
    }
#endif
    return allocatedBytes;
}

int32_t PixelMap::GetWidth()
{
    return imageInfo_.size.width;
}

int32_t PixelMap::GetHeight()
{
    return imageInfo_.size.height;
}

void PixelMap::GetTransformData(TransformData &transformData)
{
    transformData = transformData_;
}

void PixelMap::SetTransformData(TransformData transformData)
{
    transformData_ = transformData;
}

int32_t PixelMap::GetBaseDensity()
{
    return imageInfo_.baseDensity;
}

void PixelMap::GetImageInfo(ImageInfo &imageInfo)
{
    imageInfo = imageInfo_;
}

PixelFormat PixelMap::GetPixelFormat()
{
    return imageInfo_.pixelFormat;
}

ColorSpace PixelMap::GetColorSpace()
{
    return imageInfo_.colorSpace;
}

AlphaType PixelMap::GetAlphaType()
{
    return imageInfo_.alphaType;
}

const uint8_t *PixelMap::GetPixels()
{
    if (!AttachAddrBySurfaceBuffer()) {
        IMAGE_LOGE("GetPixels failed: AttachAddrBySurfaceBuffer failed.");
        return nullptr;
    }
    return data_;
}

void PixelMap::SetAstcHdr(bool astcHdr)
{
    astcHdr_ = astcHdr;
}

bool PixelMap::IsHdr()
{
    if (imageInfo_.pixelFormat == PixelFormat::ASTC_4x4 && astcHdr_) {
        return true;
    }
    if (imageInfo_.pixelFormat != PixelFormat::RGBA_1010102 && imageInfo_.pixelFormat != PixelFormat::YCRCB_P010 &&
        imageInfo_.pixelFormat != PixelFormat::YCBCR_P010) {
        return false;
    }
#ifdef IMAGE_COLORSPACE_FLAG
    OHOS::ColorManager::ColorSpace colorSpace = InnerGetGrColorSpace();
    if (colorSpace.GetColorSpaceName() != ColorManager::BT2020 &&
        colorSpace.GetColorSpaceName() != ColorManager::BT2020_HLG &&
        colorSpace.GetColorSpaceName() != ColorManager::BT2020_PQ &&
        colorSpace.GetColorSpaceName() != ColorManager::BT2020_HLG_LIMIT &&
        colorSpace.GetColorSpaceName() != ColorManager::BT2020_PQ_LIMIT) {
        return false;
    }
#endif
    return true;
}

uint8_t PixelMap::GetARGB32ColorA(uint32_t color)
{
    return (color >> ARGB_A_SHIFT) & ARGB_MASK;
}

uint8_t PixelMap::GetARGB32ColorR(uint32_t color)
{
    return (color >> ARGB_R_SHIFT) & ARGB_MASK;
}

uint8_t PixelMap::GetARGB32ColorG(uint32_t color)
{
    return (color >> ARGB_G_SHIFT) & ARGB_MASK;
}

uint8_t PixelMap::GetARGB32ColorB(uint32_t color)
{
    return (color >> ARGB_B_SHIFT) & ARGB_MASK;
}

bool PixelMap::IsSameImage(const PixelMap &other)
{
    if (isUnMap_ || data_ == nullptr || other.data_ == nullptr) {
        IMAGE_LOGE("IsSameImage data_ is nullptr, isUnMap %{public}d.", isUnMap_);
        return false;
    }
    if (imageInfo_.size.width != other.imageInfo_.size.width ||
        imageInfo_.size.height != other.imageInfo_.size.height ||
        imageInfo_.pixelFormat != other.imageInfo_.pixelFormat || imageInfo_.alphaType != other.imageInfo_.alphaType) {
        IMAGE_LOGI("IsSameImage imageInfo is not same");
        return false;
    }
    if (ImageUtils::CheckMulOverflow(rowDataSize_, imageInfo_.size.height)) {
        IMAGE_LOGI("IsSameImage imageInfo is invalid");
        return false;
    }
    uint64_t size = static_cast<uint64_t>(rowDataSize_) * static_cast<uint64_t>(imageInfo_.size.height);
    if (memcmp(data_, other.data_, size) != 0) {
        IMAGE_LOGI("IsSameImage memcmp is not same");
        return false;
    }
    return true;
}

uint32_t PixelMap::ReadPixels(const uint64_t &bufferSize, uint8_t *dst)
{
    ImageTrace imageTrace("ReadPixels by bufferSize");
    std::shared_lock<std::shared_mutex> lock(*pixelDataMutex_);
    if (dst == nullptr) {
        IMAGE_LOGE("read pixels by buffer input dst address is null.");
        return ERR_IMAGE_READ_PIXELMAP_FAILED;
    }
    if (isUnMap_ || data_ == nullptr) {
        IMAGE_LOGE("read pixels by buffer current PixelMap data is null, isUnMap %{public}d.", isUnMap_);
        return ERR_IMAGE_READ_PIXELMAP_FAILED;
    }
    if (bufferSize < static_cast<uint64_t>(pixelsSize_)) {
        IMAGE_LOGE("read pixels by buffer input dst buffer(%{public}llu) < current pixelmap size(%{public}u).",
            static_cast<unsigned long long>(bufferSize), pixelsSize_);
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if (IsYUV(imageInfo_.pixelFormat)) {
        uint64_t tmpSize = 0;
        uint64_t readSize = MAX_READ_COUNT;
        while (tmpSize < bufferSize && tmpSize < pixelsSize_) {
            if (tmpSize + MAX_READ_COUNT > bufferSize) {
                readSize = bufferSize - tmpSize;
            } else if (tmpSize + MAX_READ_COUNT > pixelsSize_) {
                readSize = pixelsSize_ - tmpSize;
            }
            errno_t ret = memcpy_s(dst + tmpSize, readSize, data_ + tmpSize, readSize);
            if (ret != 0) {
                IMAGE_LOGE("read pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret);
                return ERR_IMAGE_READ_PIXELMAP_FAILED;
            }
            tmpSize += readSize;
        }
    } else {
        // Copy the actual pixel data without padding bytes
        for (int i = 0; i < imageInfo_.size.height; ++i) {
            errno_t ret = memcpy_s(dst, rowDataSize_, data_ + i * rowStride_, rowDataSize_);
            if (ret != 0) {
                IMAGE_LOGE("read pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret);
                return ERR_IMAGE_READ_PIXELMAP_FAILED;
            }
            dst += rowDataSize_; // Move the destination buffer pointer to the next row
        }
    }
    return SUCCESS;
}

static bool IsSupportConvertToARGB(PixelFormat pixelFormat)
{
    return pixelFormat == PixelFormat::RGB_565 || pixelFormat == PixelFormat::RGBA_8888 ||
        pixelFormat == PixelFormat::BGRA_8888 || pixelFormat == PixelFormat::RGB_888 ||
        pixelFormat == PixelFormat::NV21 || pixelFormat == PixelFormat::NV12 ||
        pixelFormat == PixelFormat::RGBA_1010102 || pixelFormat == PixelFormat::ALPHA_F16;
}

static bool RGBA10BitGetSDRBufferInfo(PixelMap* hdrPixelMap,
    unique_ptr<PixelMap>& sdrPixelMap, BufferInfo& srcInfo)
{
    int32_t errorCode = -1;
    sdrPixelMap = hdrPixelMap->Clone(errorCode);
    if (errorCode != 0 || sdrPixelMap == nullptr) {
        IMAGE_LOGE("ReadARGBPixels from RGBA1010102 failed, because of clone failing");
        return false;
    }
    if (0 != sdrPixelMap->ToSdr()) {
        IMAGE_LOGE("ReadARGBPixels from RGBA1010102 failed, because of toSdr failing");
        return false;
    }
    ImageInfo tmpInfo;
    sdrPixelMap->GetImageInfo(tmpInfo);
    srcInfo = {sdrPixelMap->GetWritablePixels(), sdrPixelMap->GetRowStride(), tmpInfo};
    return true;
}

uint32_t PixelMap::ReadARGBPixels(const uint64_t &bufferSize, uint8_t *dst)
{
    ImageTrace imageTrace("ReadARGBPixels by bufferSize");
    if (isAstc_) {
        IMAGE_LOGE("ReadARGBPixels does not support astc");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if (dst == nullptr) {
        IMAGE_LOGE("Read ARGB pixels: input dst address is null.");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if (isUnMap_ || data_ == nullptr) {
        IMAGE_LOGE("Read ARGB pixels: current PixelMap data is null, isUnMap %{public}d.", isUnMap_);
        return ERR_IMAGE_READ_PIXELMAP_FAILED;
    }
    if (!IsSupportConvertToARGB(imageInfo_.pixelFormat)) {
        IMAGE_LOGE("Read ARGB pixels: does not support PixelMap with pixel format %{public}d.", imageInfo_.pixelFormat);
        return ERR_IMAGE_COLOR_CONVERT;
    }
    uint64_t minBufferSize = static_cast<uint64_t>(ARGB_8888_BYTES) *
        static_cast<uint64_t>(imageInfo_.size.width) * static_cast<uint64_t>(imageInfo_.size.height);
    if (bufferSize < minBufferSize || bufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
        IMAGE_LOGE(
            "Read ARGB pixels: input dst buffer (%{public}llu) < required buffer size (%{public}llu), or too large.",
            static_cast<unsigned long long>(bufferSize), static_cast<unsigned long long>(minBufferSize));
        return ERR_IMAGE_INVALID_PARAMETER;
    }

    if (imageInfo_.pixelFormat == PixelFormat::ALPHA_F16) {
        uint32_t *out = reinterpret_cast<uint32_t *>(dst);
        for (int32_t y = 0; y < imageInfo_.size.height; ++y) {
            const uint8_t *srcRow = data_ + y * rowStride_;
            for (int32_t x = 0; x < imageInfo_.size.width; ++x) {
                uint8_t alpha = AlphaF16ToUInt8(srcRow + x * ALPHA_F16_BYTES);
                *out++ = GetColorARGB(alpha, BYTE_ZERO, BYTE_ZERO, BYTE_ZERO);
            }
        }
        return SUCCESS;
    }

    ImageInfo dstImageInfo = MakeImageInfo(imageInfo_.size.width, imageInfo_.size.height, PixelFormat::ARGB_8888,
        AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    BufferInfo srcInfo = {data_, GetRowStride(), imageInfo_};
    unique_ptr<PixelMap> sdrPixelMap = nullptr;
    if (imageInfo_.pixelFormat == PixelFormat::RGBA_1010102 && IsHdr()) {
        if (!RGBA10BitGetSDRBufferInfo(const_cast<PixelMap *>(this), sdrPixelMap, srcInfo)) {
            IMAGE_LOGE("ReadARGBPixels from RGBA1010102 failed, because of RGBA10BitGetSDRBufferInfo failing");
            return ERR_IMAGE_READ_PIXELMAP_FAILED;
        }
    }
    BufferInfo dstInfo = {dst, 0, dstImageInfo};
    int32_t dstLength = PixelConvert::PixelsConvert(srcInfo, dstInfo, bufferSize, IsStrideAlignment() &&
        !GetNoPaddingUsage());
    if (dstLength < 0) {
        IMAGE_LOGE("ReadARGBPixels pixel convert to ARGB failed.");
        return ERR_IMAGE_READ_PIXELMAP_FAILED;
    }
    ImageUtils::DumpDataIfDumpEnabled(reinterpret_cast<const char*>(dst), bufferSize, "dat", uniqueId_);
    return SUCCESS;
}

uint32_t PixelMap::ReadPixels(const RWPixelsOptions &opts)
{
    if (!ImageUtils::CheckPixelsInput(this, opts)) {
        IMAGE_LOGE("read pixels by rect input parameter fail.");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if (isUnMap_ || data_ == nullptr) {
        IMAGE_LOGE("read pixels by rect this pixel data is null, isUnMap %{public}d.", isUnMap_);
        return ERR_IMAGE_READ_PIXELMAP_FAILED;
    }
    ImageInfo dstImageInfo =
        MakeImageInfo(opts.region.width, opts.region.height, opts.pixelFormat, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    Position srcPosition { opts.region.left, opts.region.top };
    uint8_t *pixels = const_cast<uint8_t *>(opts.pixels);
    if (imageInfo_.pixelFormat == PixelFormat::ARGB_8888) {
        int32_t srcRowBytes = imageInfo_.size.width * ImageUtils::GetPixelBytes(imageInfo_.pixelFormat);
        std::unique_ptr<uint8_t[]> srcData = std::make_unique<uint8_t[]>(srcRowBytes * imageInfo_.size.height);
        if (srcData == nullptr) {
            IMAGE_LOGE("ReadPixels make srcData fail.");
            return ERR_IMAGE_READ_PIXELMAP_FAILED;
        }
        void* outData = srcData.get();
        ImageInfo tempInfo = MakeImageInfo(imageInfo_.size.width, imageInfo_.size.height,
            opts.pixelFormat, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
        BufferInfo srcInfo = {data_, GetRowStride(), imageInfo_};
        BufferInfo dstInfo = {outData, 0, tempInfo};
        int32_t dstLength = PixelConvert::PixelsConvert(srcInfo, dstInfo, IsStrideAlignment());
        if (dstLength < 0) {
            IMAGE_LOGE("ReadPixels PixelsConvert to format:%{public}d failed.", opts.pixelFormat);
            return ERR_IMAGE_READ_PIXELMAP_FAILED;
        }
        if (!PixelConvertAdapter::ReadPixelsConvert(outData, srcPosition, srcRowBytes, tempInfo,
            pixels + opts.offset, opts.stride, dstImageInfo)) {
            IMAGE_LOGE("read pixels by rect call ReadPixelsConvert fail.");
            return ERR_IMAGE_READ_PIXELMAP_FAILED;
        }
    } else {
        if (!PixelConvertAdapter::ReadPixelsConvert(data_, srcPosition, rowStride_, imageInfo_, pixels + opts.offset,
            opts.stride, dstImageInfo)) {
            IMAGE_LOGE("read pixels by rect call ReadPixelsConvert fail.");
            return ERR_IMAGE_READ_PIXELMAP_FAILED;
        }
    }
    return SUCCESS;
}

uint32_t PixelMap::ReadPixels(const uint64_t &bufferSize, const uint32_t &offset, const uint32_t &stride,
                              const Rect &region, uint8_t *dst)
{
    return ReadPixels(RWPixelsOptions{dst, bufferSize, offset, stride, region, PixelFormat::BGRA_8888});
}

uint32_t PixelMap::ReadPixel(const Position &pos, uint32_t &dst)
{
    if (pos.x < 0 || pos.y < 0 || pos.x >= GetWidth() || pos.y >= GetHeight()) {
        IMAGE_LOGE("read pixel by pos input invalid exception. [x(%{public}d), y(%{public}d)]", pos.x, pos.y);
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if (isUnMap_ || data_ == nullptr) {
        IMAGE_LOGE("%{public}d:read pixel by pos source data is null, isUnMap %{public}d.", uniqueId_, isUnMap_);
        return ERR_IMAGE_READ_PIXELMAP_FAILED;
    }
    if (imageInfo_.pixelFormat == PixelFormat::ALPHA_F16) {
        const uint8_t *pixel = GetPixel(pos.x, pos.y);
        if (pixel == nullptr) {
            IMAGE_LOGE("read pixel by pos get pixel failed.");
            return ERR_IMAGE_READ_PIXELMAP_FAILED;
        }
        dst = static_cast<uint32_t>(AlphaF16ToUInt8(pixel)) << BGRA32_A_SHIFT;
        return SUCCESS;
    }
    ImageInfo dstImageInfo =
        MakeImageInfo(PER_PIXEL_LEN, PER_PIXEL_LEN, PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    uint32_t dstRowBytes = BGRA_BYTES;
    Position srcPosition { pos.x, pos.y };
    if (!PixelConvertAdapter::ReadPixelsConvert(data_, srcPosition, rowStride_, imageInfo_, &dst, dstRowBytes,
        dstImageInfo)) {
        IMAGE_LOGE("read pixel by pos call ReadPixelsConvert fail.");
        return ERR_IMAGE_READ_PIXELMAP_FAILED;
    }
    return SUCCESS;
}

uint32_t PixelMap::ResetConfig(const Size &size, const PixelFormat &format)
{
    if (size.width <= 0 || size.height <= 0) {
        IMAGE_LOGE("ResetConfig reset input width(%{public}d) or height(%{public}d) is < 0.", size.width,
            size.height);
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    uint32_t bytesPerPixel = ImageUtils::GetPixelBytes(format);
    if (bytesPerPixel == 0) {
        IMAGE_LOGE("ResetConfig get bytes by per pixel fail.");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if (ImageUtils::CheckMulOverflow(size.width, size.height, bytesPerPixel)) {
        IMAGE_LOGE("ResetConfig reset input width(%{public}d) or height(%{public}d) is invalid.", size.width,
                   size.height);
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    uint64_t dstSize = static_cast<uint64_t>(size.width) * static_cast<uint64_t>(size.height) * bytesPerPixel;
    if (dstSize > static_cast<uint64_t>(pixelsSize_)) {
        IMAGE_LOGE("ResetConfig reset dstSize(%{public}llu) > current(%{public}u).",
            static_cast<unsigned long long>(dstSize), pixelsSize_);
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    AlphaType dstAlphaType = ImageUtils::GetValidAlphaTypeByFormat(GetAlphaType(), format);
    if (dstAlphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
        IMAGE_LOGE("ResetConfig Failed to get validate alpha type.");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    ImageInfo dstInfo = MakeImageInfo(size.width, size.height, format, dstAlphaType);
    uint32_t ret = SetImageInfo(dstInfo, true);
    if (ret != SUCCESS) {
        IMAGE_LOGE("ResetConfig call SetImageInfo Failed. ret:%{public}u", ret);
        return ERR_IMAGE_CONFIG_FAILED;
    }
    return SUCCESS;
}

bool PixelMap::SetAlphaType(const AlphaType &alphaType)
{
    AlphaType type = ImageUtils::GetValidAlphaTypeByFormat(alphaType, imageInfo_.pixelFormat);
    if (type == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
        IMAGE_LOGE("SetAlphaType Failed to get validate alpha type.");
        return false;
    }
    ImageInfo dstInfo = imageInfo_;
    dstInfo.alphaType = type;
    uint32_t ret = SetImageInfo(dstInfo, true);
    if (ret != SUCCESS) {
        IMAGE_LOGE("SetAlphaType call SetImageInfo Failed. ret:%{public}u", ret);
        return false;
    }
    return true;
}

uint32_t PixelMap::WritePixel(const Position &pos, const uint32_t &color)
{
    if (pos.x < 0 || pos.y < 0 || pos.x >= GetWidth() || pos.y >= GetHeight()) {
        IMAGE_LOGE(
            "write pixel by pos but input position is invalid. [x(%{public}d), y(%{public}d)]"\
            "Width() %{public}d,  Height() %{public}d, ", pos.x, pos.y, GetWidth(), GetHeight());
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if (!IsEditable() || !modifiable_) {
        IMAGE_LOGE("write pixel by pos pixelmap is not editable or modifiable.");
        return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY;
    }
    if (!ImageUtils::IsValidImageInfo(imageInfo_)) {
        IMAGE_LOGE("write pixel by pos current pixelmap image info is invalid.");
        return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
    }
    if (isUnMap_ || data_ == nullptr) {
        IMAGE_LOGE("write pixel by pos but current pixelmap data is nullptr, isUnMap %{public}d.", isUnMap_);
        return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
    }
    if (imageInfo_.pixelFormat == PixelFormat::ALPHA_F16) {
        uint8_t *pixel = const_cast<uint8_t *>(GetPixel(pos.x, pos.y));
        if (pixel == nullptr) {
            IMAGE_LOGE("write pixel by pos get pixel failed.");
            return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
        }
        UInt8ToAlphaF16(GetColorComp(color, BGRA32_A_SHIFT), pixel);
        MarkDirty();
        return SUCCESS;
    }
    ImageInfo srcImageInfo =
        MakeImageInfo(PER_PIXEL_LEN, PER_PIXEL_LEN, PixelFormat::BGRA_8888, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    uint32_t srcRowBytes = BGRA_BYTES;
    Position dstPosition { pos.x, pos.y };  // source is per pixel.
    if (!PixelConvertAdapter::WritePixelsConvert(&color, srcRowBytes, srcImageInfo, data_, dstPosition, rowStride_,
        imageInfo_)) {
        IMAGE_LOGE("write pixel by pos call WritePixelsConvert fail.");
        return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
    }
    return SUCCESS;
}

uint32_t PixelMap::CheckPixelMapForWritePixels()
{
    if (!IsEditable() || !modifiable_) {
        IMAGE_LOGE("write pixel by rect pixelmap data is not editable or modifiable.");
        return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY;
    }
    if (!ImageUtils::IsValidImageInfo(imageInfo_)) {
        IMAGE_LOGE("write pixel by rect current pixelmap image info is invalid.");
        return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
    }
    if (isUnMap_ || data_ == nullptr) {
        IMAGE_LOGE("write pixel by rect current pixel map data is null, isUnMap %{public}d.", isUnMap_);
        return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
    }
    int32_t bytesPerPixel = ImageUtils::GetPixelBytes(imageInfo_.pixelFormat);
    if (bytesPerPixel == 0) {
        IMAGE_LOGE("write pixel by rect get bytes by per pixel fail.");
        return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
    }
    return SUCCESS;
}

uint32_t PixelMap::WritePixels(const RWPixelsOptions &opts)
{
    if (!ImageUtils::CheckPixelsInput(this, opts)) {
        IMAGE_LOGE("write pixel by rect input parameter fail.");
        return ERR_IMAGE_INVALID_PARAMETER;
    }

    uint32_t ret = CheckPixelMapForWritePixels();
    if (ret != SUCCESS) {
        return ret;
    }

    Position dstPosition { opts.region.left, opts.region.top };
    ImageInfo srcInfo =
        MakeImageInfo(opts.region.width, opts.region.height, opts.pixelFormat, AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    if (imageInfo_.pixelFormat == PixelFormat::ARGB_8888) {
        std::unique_ptr<uint8_t[]> tempPixels = std::make_unique<uint8_t[]>(opts.bufferSize);
        if (tempPixels == nullptr) {
            IMAGE_LOGE("WritePixels make tempPixels failed.");
            return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
        }
        void *colors = tempPixels.get();
        ImageInfo tempInfo = MakeImageInfo(
            opts.region.width, opts.region.height, PixelFormat::ARGB_8888,
            AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
        BufferInfo dstInfo = {colors, 0, tempInfo};
        const void *pixels = opts.pixels;
        BufferInfo srcBufferInfo = {const_cast<void*>(pixels), 0, srcInfo};
        int32_t dstLength = PixelConvert::PixelsConvert(srcBufferInfo, dstInfo, false);
        if (dstLength < 0) {
            IMAGE_LOGE("WritePixels pixel convert to BGRA_8888 failed.");
            return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
        }
        if (!PixelConvertAdapter::WritePixelsConvert((uint8_t*)colors + opts.offset, opts.stride, tempInfo,
            data_, dstPosition, rowStride_, imageInfo_)) {
            IMAGE_LOGE("write pixel by rect call WritePixelsConvert fail.");
            return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
        }
    } else {
        if (!PixelConvertAdapter::WritePixelsConvert(opts.pixels + opts.offset, opts.stride, srcInfo,
            data_, dstPosition, rowStride_, imageInfo_)) {
            IMAGE_LOGE("write pixel by rect call WritePixelsConvert fail.");
            return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
        }
    }
    MarkDirty();
    return SUCCESS;
}

uint32_t PixelMap::WritePixels(const uint8_t *source, const uint64_t &bufferSize, const uint32_t &offset,
                               const uint32_t &stride, const Rect &region)
{
    return WritePixels(RWPixelsOptions{source, bufferSize, offset, stride, region, PixelFormat::BGRA_8888});
}

uint32_t PixelMap::WritePixels(const uint8_t *source, const uint64_t &bufferSize)
{
    ImageTrace imageTrace("WritePixels");
    if (source == nullptr || bufferSize < static_cast<uint64_t>(pixelsSize_)) {
        IMAGE_LOGE("write pixels by buffer source is nullptr or size(%{public}llu) < pixelSize(%{public}u).",
            static_cast<unsigned long long>(bufferSize), pixelsSize_);
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if (!IsEditable() || !modifiable_) {
        IMAGE_LOGE("write pixels by buffer pixelmap data is not editable or modifiable.");
        return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY;
    }
    if (!ImageUtils::IsValidImageInfo(imageInfo_)) {
        IMAGE_LOGE("write pixels by buffer current pixelmap image info is invalid.");
        return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
    }
    if (isUnMap_ || data_ == nullptr) {
        IMAGE_LOGE("write pixels by buffer current pixelmap data is nullptr, isUnMap %{public}d.", isUnMap_);
        return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
    }

    if (IsYUV(imageInfo_.pixelFormat)) {
        uint64_t tmpSize = 0;
        uint64_t readSize = MAX_READ_COUNT;
        while (tmpSize < bufferSize && tmpSize < pixelsSize_) {
            if (tmpSize + MAX_READ_COUNT > pixelsSize_) {
                readSize = pixelsSize_ - tmpSize;
            }
            errno_t ret = memcpy_s(data_ + tmpSize, pixelsSize_ - tmpSize, source + tmpSize, readSize);
            if (ret != 0) {
                IMAGE_LOGE("write pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret);
                return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
            }
            tmpSize += readSize;
        }
    } else {
        for (int i = 0; i < imageInfo_.size.height; ++i) {
            const uint8_t* sourceRow = source + i * rowDataSize_;
            errno_t ret = memcpy_s(data_ + i * rowStride_, rowDataSize_, sourceRow, rowDataSize_);
            if (ret != 0) {
                IMAGE_LOGE("write pixels by buffer memcpy the pixelmap data to dst fail, error:%{public}d", ret);
                return ERR_IMAGE_WRITE_PIXELMAP_FAILED;
            }
        }
    }
    MarkDirty();
    return SUCCESS;
}

bool PixelMap::WritePixels(const uint32_t &color)
{
    if (!IsEditable() || !modifiable_) {
        IMAGE_LOGE("erase pixels by color pixelmap data is not editable or modifiable.");
        return false;
    }
    if (!ImageUtils::IsValidImageInfo(imageInfo_)) {
        IMAGE_LOGE("erase pixels by color current pixelmap image info is invalid.");
        return false;
    }
    if (isUnMap_ || data_ == nullptr) {
        IMAGE_LOGE("erase pixels by color current pixel map data is null, %{public}d.", isUnMap_);
        return false;
    }
    if (imageInfo_.pixelFormat == PixelFormat::ALPHA_F16) {
        uint8_t alpha = GetColorComp(color, BGRA32_A_SHIFT);
        for (int32_t y = 0; y < imageInfo_.size.height; ++y) {
            uint8_t *row = data_ + y * rowStride_;
            for (int32_t x = 0; x < imageInfo_.size.width; ++x) {
                UInt8ToAlphaF16(alpha, row + x * ALPHA_F16_BYTES);
            }
        }
        return true;
    }
    ImageInfo srcInfo =
        MakeImageInfo(imageInfo_.size.width, imageInfo_.size.height, imageInfo_.pixelFormat, imageInfo_.alphaType);
    if (!PixelConvertAdapter::EraseBitmap(data_, rowStride_, srcInfo, color)) {
        IMAGE_LOGE("erase pixels by color call EraseBitmap fail.");
        return false;
    }
    return true;
}

bool PixelMap::IsStrideAlignment()
{
    if (allocatorType_ == AllocatorType::DMA_ALLOC && !GetNoPaddingUsage()) {
        IMAGE_LOGD("IsStrideAlignment allocatorType_ is DMA_ALLOC and not no-padding");
        return true;
    }
    return false;
}

AllocatorType PixelMap::GetAllocatorType()
{
    return allocatorType_;
}

void *PixelMap::GetFd() const
{
    return context_;
}

void PixelMap::ReleaseMemory(AllocatorType allocType, void *addr, void *context, uint32_t size)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    if (allocType == AllocatorType::SHARE_MEM_ALLOC) {
        if (context != nullptr) {
            int *fd = static_cast<int *>(context);
            if (addr != nullptr) {
                ::munmap(addr, size);
            }
            if (fd != nullptr) {
                ::close(*fd);
            }
            context = nullptr;
            addr = nullptr;
        }
    } else if (allocType == AllocatorType::HEAP_ALLOC) {
        if (addr != nullptr) {
            free(addr);
            addr = nullptr;
        }
    } else if (allocType == AllocatorType::DMA_ALLOC) {
        if (context != nullptr) {
            ImageUtils::SurfaceBuffer_Unreference(static_cast<SurfaceBuffer*>(context));
        }
        context = nullptr;
        addr = nullptr;
    }
#else
    if (addr != nullptr) {
        free(addr);
        addr = nullptr;
    }
#endif
}

bool PixelMap::WriteAshmemDataToParcel(Parcel &parcel, size_t size) const
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    const uint8_t *data = data_;
    uint32_t id = GetUniqueId();
    std::string name = "Parcel ImageData, uniqueId: " + std::to_string(getpid()) + '_' + std::to_string(id);
    int fd = AshmemCreate(name.c_str(), size);
    IMAGE_LOGI("AshmemCreate:[%{public}d], format:%{public}d, size:(%{public}d, %{public}d), "\
        "bufferSize:%{public}zu, Pid:%{public}s, Tid:%{public}s, PixelMapUID:%{public}d",
        fd, static_cast<int32_t>(imageInfo_.pixelFormat), imageInfo_.size.width, imageInfo_.size.height,
        size, std::to_string(getpid()).c_str(), std::to_string(gettid()).c_str(), GetUniqueId());
    if (fd < 0) {
        return false;
    }

    int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
    IMAGE_LOGD("AshmemSetProt:[%{public}d].", result);
    if (result < 0) {
        ::close(fd);
        return false;
    }
    void *ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (ptr == MAP_FAILED) {
        ::close(fd);
        IMAGE_LOGE("WriteAshmemData map failed, errno:%{public}d", errno);
        return false;
    }
    IMAGE_LOGD("mmap success");

    if (memcpy_s(ptr, size, data, size) != EOK) {
        ::munmap(ptr, size);
        ::close(fd);
        IMAGE_LOGE("WriteAshmemData memcpy_s error");
        return false;
    }

    if (!WriteFileDescriptor(parcel, fd)) {
        ::munmap(ptr, size);
        ::close(fd);
        IMAGE_LOGE("WriteAshmemData WriteFileDescriptor error");
        return false;
    }
    IMAGE_LOGD("WriteAshmemData WriteFileDescriptor success");
    ::munmap(ptr, size);
    ::close(fd);
    return true;
#endif
    IMAGE_LOGE("WriteAshmemData not support crossplatform");
    return false;
}

bool PixelMap::WriteImageData(Parcel &parcel, size_t size) const
{
    const uint8_t *data = data_;
    if (isUnMap_ || data == nullptr || size > MAX_IMAGEDATA_SIZE) {
        IMAGE_LOGE("WriteImageData failed, data is null or size bigger than 128M, isUnMap %{public}d.", isUnMap_);
        return false;
    }

    if (!parcel.WriteInt32(size)) {
        IMAGE_LOGE("WriteImageData size failed.");
        return false;
    }
    if (size <= MIN_IMAGEDATA_SIZE) {
        return parcel.WriteUnpadBuffer(data, size);
    }
    return WriteAshmemDataToParcel(parcel, size);
}

uint8_t *PixelMap::ReadHeapDataFromParcel(Parcel &parcel, int32_t bufferSize)
{
    uint8_t *base = nullptr;
    if (bufferSize <= 0) {
        IMAGE_LOGE("malloc parameter bufferSize:[%{public}d] error.", bufferSize);
        return nullptr;
    }

    const uint8_t *ptr = parcel.ReadUnpadBuffer(bufferSize);
    if (ptr == nullptr) {
        IMAGE_LOGE("read buffer from parcel failed, read buffer addr is null");
        return nullptr;
    }

    base = static_cast<uint8_t *>(malloc(bufferSize));
    if (base == nullptr) {
        IMAGE_LOGE("alloc output pixel memory size:[%{public}d] error.", bufferSize);
        return nullptr;
    }
    if (memcpy_s(base, bufferSize, ptr, bufferSize) != 0) {
        free(base);
        base = nullptr;
        IMAGE_LOGE("memcpy pixel data size:[%{public}d] error.", bufferSize);
        return nullptr;
    }
    return base;
}

uint8_t *PixelMap::ReadAshmemDataFromParcel(Parcel &parcel, int32_t bufferSize,
    std::function<int(Parcel &parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc)
{
    uint8_t *base = nullptr;
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    auto readFdDefaultFunc = [](Parcel &parcel) -> int { return ReadFileDescriptor(parcel); };
    int fd = ((readSafeFdFunc != nullptr) ? readSafeFdFunc(parcel, readFdDefaultFunc) : readFdDefaultFunc(parcel));
    if (!CheckAshmemSize(fd, bufferSize)) {
        ::close(fd);
        IMAGE_LOGE("ReadAshmemDataFromParcel check ashmem size failed, fd:[%{public}d].", fd);
        return nullptr;
    }
    if (bufferSize <= 0 || bufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
        ::close(fd);
        IMAGE_LOGE("malloc parameter bufferSize:[%{public}d] error.", bufferSize);
        return nullptr;
    }

    void *ptr = ::mmap(nullptr, bufferSize, PROT_READ, MAP_SHARED, fd, 0);
    if (ptr == MAP_FAILED) {
        ::close(fd);
        IMAGE_LOGE("ReadImageData map failed, errno:%{public}d", errno);
        return nullptr;
    }

    base = static_cast<uint8_t *>(malloc(bufferSize));
    if (base == nullptr) {
        ReleaseMemory(AllocatorType::SHARE_MEM_ALLOC, ptr, &fd, bufferSize);
        IMAGE_LOGE("alloc output pixel memory size:[%{public}d] error.", bufferSize);
        return nullptr;
    }
    if (memcpy_s(base, bufferSize, ptr, bufferSize) != 0) {
        ReleaseMemory(AllocatorType::SHARE_MEM_ALLOC, ptr, &fd, bufferSize);
        free(base);
        base = nullptr;
        IMAGE_LOGE("memcpy pixel data size:[%{public}d] error.", bufferSize);
        return nullptr;
    }

    ReleaseMemory(AllocatorType::SHARE_MEM_ALLOC, ptr, &fd, bufferSize);
#endif
    return base;
}

uint8_t *PixelMap::ReadImageData(Parcel &parcel, int32_t bufferSize,
    std::function<int(Parcel &parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc)
{
#if !defined(_WIN32) && !defined(_APPLE) &&!defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    if (static_cast<unsigned int>(bufferSize) <= MIN_IMAGEDATA_SIZE) {
        return ReadHeapDataFromParcel(parcel, bufferSize);
    } else {
        return ReadAshmemDataFromParcel(parcel, bufferSize, readSafeFdFunc);
    }
#else
    return ReadHeapDataFromParcel(parcel, bufferSize);
#endif
}

bool PixelMap::WriteFileDescriptor(Parcel &parcel, int fd)
{
#if !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    if (fd < 0) {
        IMAGE_LOGE("WriteFileDescriptor get fd failed, fd:[%{public}d].", fd);
        return false;
    }
    int dupFd = dup(fd);
    if (dupFd < 0) {
        IMAGE_LOGE("WriteFileDescriptor dup fd failed, dupFd:[%{public}d].", dupFd);
        return false;
    }
    sptr<IPCFileDescriptor> descriptor = new IPCFileDescriptor(dupFd);
    return parcel.WriteObject<IPCFileDescriptor>(descriptor);
#else
    IMAGE_LOGE("[Pixemap] Not support Cross-Platform");
    return false;
#endif
}

int PixelMap::ReadFileDescriptor(Parcel &parcel)
{
#if !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    sptr<IPCFileDescriptor> descriptor = parcel.ReadObject<IPCFileDescriptor>();
    if (descriptor == nullptr) {
        IMAGE_LOGE("ReadFileDescriptor get descriptor failed");
        return -1;
    }
    int fd = descriptor->GetFd();
    if (fd < 0) {
        IMAGE_LOGE("ReadFileDescriptor get fd failed, fd:[%{public}d].", fd);
        return -1;
    }
    int dupFd = dup(fd);
    if (dupFd < 0) {
        IMAGE_LOGE("ReadFileDescriptor dup fd failed, dupFd:[%{public}d].", dupFd);
        return -1;
    }
    return dupFd;
#else
    IMAGE_LOGE("[Pixemap] Not support Cross-Platform");
    return -1;
#endif
}

bool PixelMap::WriteImageInfo(Parcel &parcel) const
{
    if (imageInfo_.size.width <= 0 || !parcel.WriteInt32(imageInfo_.size.width)) {
        IMAGE_LOGE("write image info width:[%{public}d] to parcel failed.", imageInfo_.size.width);
        return false;
    }
    if (imageInfo_.size.height <= 0 || !parcel.WriteInt32(imageInfo_.size.height)) {
        IMAGE_LOGE("write image info height:[%{public}d] to parcel failed.", imageInfo_.size.height);
        return false;
    }
    if (!parcel.WriteInt32(static_cast<int32_t>(imageInfo_.pixelFormat))) {
        IMAGE_LOGE("write image info pixel format:[%{public}d] to parcel failed.", imageInfo_.pixelFormat);
        return false;
    }
    if (!parcel.WriteInt32(static_cast<int32_t>(imageInfo_.colorSpace))) {
        IMAGE_LOGE("write image info color space:[%{public}d] to parcel failed.", imageInfo_.colorSpace);
        return false;
    }
    if (!parcel.WriteInt32(static_cast<int32_t>(imageInfo_.alphaType))) {
        IMAGE_LOGE("write image info alpha type:[%{public}d] to parcel failed.", imageInfo_.alphaType);
        return false;
    }
    if (!parcel.WriteInt32(imageInfo_.baseDensity)) {
        IMAGE_LOGE("write image info base density:[%{public}d] to parcel failed.", imageInfo_.baseDensity);
        return false;
    }
    if (!parcel.WriteString(imageInfo_.encodedFormat)) {
        IMAGE_LOGE("write image info encoded format:[%{public}s] to parcel failed.", imageInfo_.encodedFormat.c_str());
        return false;
    }
    return true;
}

bool PixelMap::WritePropertiesToParcel(Parcel &parcel) const
{
    if (!WriteImageInfo(parcel)) {
        IMAGE_LOGE("write image info to parcel failed.");
        return false;
    }

    if (!parcel.WriteBool(editable_)) {
        IMAGE_LOGE("write pixel map editable to parcel failed.");
        return false;
    }

    if (!parcel.WriteBool(displayOnly_)) {
        IMAGE_LOGE("write pixel map displayOnly_ to parcel failed.");
        return false;
    }

    if (!parcel.WriteInt32(static_cast<int32_t>(allocatorType_))) {
        IMAGE_LOGE("write pixel map allocator type:[%{public}d] to parcel failed.", allocatorType_);
        return false;
    }

    if (!parcel.WriteInt32(static_cast<int32_t>(grColorSpace_ ?
            grColorSpace_->GetColorSpaceName() : ERR_MEDIA_INVALID_VALUE))) {
        IMAGE_LOGE("write pixel map grColorSpace to parcel failed.");
        return false;
    }

    if (!parcel.WriteInt32(static_cast<int32_t>(rowDataSize_))) {
        IMAGE_LOGE("write image info rowStride_:[%{public}d] to parcel failed.", rowDataSize_);
        return false;
    }

    if (!WriteAstcInfoToParcel(parcel)) {
        IMAGE_LOGE("write ASTC real size to parcel failed.");
        return false;
    }
    return true;
}

static bool WriteRecoveredAshMemToParcel(Parcel &parcel, const uint8_t *src, int32_t bufferSize)
{
#ifndef CROSS_PLATFORM
    if (src == nullptr || bufferSize <= 0) {
        IMAGE_LOGE("[PixelMap] WriteRecoveredAshMemToParcel invalid params, bufferSize=%{public}d",
            bufferSize);
        return false;
    }
    std::string name = "PixelMapRecovery_Pid" + std::to_string(getpid());
    int32_t newFd = AshmemCreate(name.c_str(), bufferSize);
    if (newFd < 0) {
        IMAGE_LOGE("[PixelMap] failed to create new ashmem for recovery");
        return false;
    }
    if (AshmemSetProt(newFd, PROT_READ | PROT_WRITE) < 0) {
        ::close(newFd);
        IMAGE_LOGE("[PixelMap] failed to set ashmem prot for recovery");
        return false;
    }
    void* newAddr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, newFd, 0);
    if (newAddr == MAP_FAILED) {
        ::close(newFd);
        IMAGE_LOGE("[PixelMap] failed to mmap mem for recovery, errno:%{public}d", errno);
        return false;
    }
    if (memcpy_s(newAddr, bufferSize, src, bufferSize) != 0) {
        ::close(newFd);
        ::munmap(newAddr, bufferSize);
        IMAGE_LOGE("[PixelMap] failed to copy mem for recovery, errno:%{public}d", errno);
        return false;
    }
    sptr<IPCFileDescriptor> descriptor = new IPCFileDescriptor(newFd);
    bool writeSuccess = parcel.WriteObject<IPCFileDescriptor>(descriptor);
    ::munmap(newAddr, bufferSize);
    if (!writeSuccess) {
        ::close(newFd);
        IMAGE_LOGE("[PixelMap] failed to write recovered fd to parcel");
        return false;
    }
    return true;
#else
    return false;
#endif
}

bool PixelMap::WriteMemInfoToParcel(Parcel &parcel, const int32_t &bufferSize) const
{
#if !defined(_WIN32) && !defined(_APPLE) &&!defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    if (allocatorType_ == AllocatorType::SHARE_MEM_ALLOC) {
        if (!parcel.WriteInt32(bufferSize)) {
            return false;
        }

        // Lock ordering: pixelDataMutex_ must be acquired before unmapMutex_.
        std::lock_guard<std::mutex> unmapLock(*unmapMutex_);
        int *fd = static_cast<int *>(context_);
        if (fd == nullptr || *fd < 0) {
            IMAGE_LOGE("write pixel map failed, fd is [%{public}d] or fd < 0.", fd == nullptr ? 1 : *fd);
            return false;
        }
        if (!CheckAshmemSize(*fd, bufferSize, isAstc_)) {
            IMAGE_LOGW("write pixel map fd %{public}d is invalid, trying to recover for parcel", *fd);
            if (isUnMap_ || data_ == nullptr || !WriteRecoveredAshMemToParcel(parcel, data_, bufferSize)) {
                IMAGE_LOGE("write pixel map check ashmem size and recovery failed, fd:[%{public}d].", *fd);
                return false;
            }
            return true;
        }
        if (!WriteFileDescriptor(parcel, *fd)) {
            IMAGE_LOGE("write pixel map fd:[%{public}d] to parcel failed.", *fd);
            return false;
        }
    } else if (allocatorType_ == AllocatorType::DMA_ALLOC) {
        if (!parcel.WriteInt32(bufferSize)) {
            return false;
        }
        SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(context_);
        if (sbBuffer == nullptr) {
            IMAGE_LOGE("write pixel map failed, surface buffer is null");
            return false;
        }
        GSError ret = sbBuffer->WriteToMessageParcel(static_cast<MessageParcel&>(parcel));
        if (ret != GSError::GSERROR_OK) {
            IMAGE_LOGE("write pixel map to message parcel failed: %{public}s.", GSErrorStr(ret).c_str());
            return false;
        }
    } else {
        if (!WriteImageData(parcel, bufferSize)) {
            IMAGE_LOGE("write pixel map buffer to parcel failed.");
            return false;
        }
    }
#else
    if (!WriteImageData(parcel, bufferSize)) {
        IMAGE_LOGE("write pixel map buffer to parcel failed.");
        return false;
    }
#endif
    return true;
}

bool PixelMap::WriteTransformDataToParcel(Parcel &parcel) const
{
    if (isAstc_) {
        if (!parcel.WriteFloat(static_cast<float>(transformData_.scaleX))) {
            IMAGE_LOGE("write scaleX:[%{public}f] to parcel failed.", transformData_.scaleX);
            return false;
        }
        if (!parcel.WriteFloat(static_cast<float>(transformData_.scaleY))) {
            IMAGE_LOGE("write scaleY:[%{public}f] to parcel failed.", transformData_.scaleY);
            return false;
        }
        if (!parcel.WriteFloat(static_cast<float>(transformData_.rotateD))) {
            IMAGE_LOGE("write rotateD:[%{public}f] to parcel failed.", transformData_.rotateD);
            return false;
        }
        if (!parcel.WriteFloat(static_cast<float>(transformData_.cropLeft))) {
            IMAGE_LOGE("write cropLeft:[%{public}f] to parcel failed.", transformData_.cropLeft);
            return false;
        }
        if (!parcel.WriteFloat(static_cast<float>(transformData_.cropTop))) {
            IMAGE_LOGE("write cropTop:[%{public}f] to parcel failed.", transformData_.cropTop);
            return false;
        }
        if (!parcel.WriteFloat(static_cast<float>(transformData_.cropWidth))) {
            IMAGE_LOGE("write cropWidth:[%{public}f] to parcel failed.", transformData_.cropWidth);
            return false;
        }
        if (!parcel.WriteFloat(static_cast<float>(transformData_.cropHeight))) {
            IMAGE_LOGE("write cropHeight:[%{public}f] to parcel failed.", transformData_.cropHeight);
            return false;
        }
        if (!parcel.WriteFloat(static_cast<float>(transformData_.translateX))) {
            IMAGE_LOGE("write translateX:[%{public}f] to parcel failed.", transformData_.translateX);
            return false;
        }
        if (!parcel.WriteFloat(static_cast<float>(transformData_.translateY))) {
            IMAGE_LOGE("write translateY:[%{public}f] to parcel failed.", transformData_.translateY);
            return false;
        }
        if (!parcel.WriteBool(static_cast<bool>(transformData_.flipX))) {
            IMAGE_LOGE("write astc transformData_.flipX to parcel failed.");
            return false;
        }
        if (!parcel.WriteBool(static_cast<bool>(transformData_.flipY))) {
            IMAGE_LOGE("write astc transformData_.flipY to parcel failed.");
            return false;
        }
    }
    return true;
}

bool PixelMap::WriteAstcInfoToParcel(Parcel &parcel) const
{
    if (isAstc_) {
        if (!parcel.WriteInt32(static_cast<int32_t>(astcrealSize_.width))) {
            IMAGE_LOGE("write astcrealSize_.width:[%{public}d] to parcel failed.", astcrealSize_.width);
            return false;
        }
        if (!parcel.WriteInt32(static_cast<int32_t>(astcrealSize_.height))) {
            IMAGE_LOGE("write astcrealSize_.height:[%{public}d] to parcel failed.", astcrealSize_.height);
            return false;
        }
        if (!parcel.WriteBool(astcHdr_)) {
            IMAGE_LOGE("write astc hdr flag to parcel failed.");
            return false;
        }
    }
    return true;
}

bool PixelMap::Marshalling(Parcel &parcel) const
{
    std::shared_lock<std::shared_mutex> lock(*pixelDataMutex_);
    int32_t PIXEL_MAP_INFO_MAX_LENGTH = 128;
    if (ImageUtils::CheckMulOverflow(imageInfo_.size.height, rowDataSize_)) {
        IMAGE_LOGE("pixelmap invalid params, height:%{public}d, rowDataSize:%{public}d.",
                   imageInfo_.size.height, rowDataSize_);
        return false;
    }
    int32_t bufferSize = rowDataSize_ * imageInfo_.size.height;
    if (isAstc_ || IsYUV(imageInfo_.pixelFormat) || imageInfo_.pixelFormat == PixelFormat::RGBA_F16) {
        bufferSize = pixelsSize_;
    }
    if (static_cast<size_t>(bufferSize) <= MIN_IMAGEDATA_SIZE &&
        static_cast<size_t>(bufferSize + PIXEL_MAP_INFO_MAX_LENGTH) > parcel.GetDataCapacity() &&
        !parcel.SetDataCapacity(bufferSize + PIXEL_MAP_INFO_MAX_LENGTH)) {
        IMAGE_LOGE("set parcel max capacity:[%{public}d] failed.", bufferSize + PIXEL_MAP_INFO_MAX_LENGTH);
        return false;
    }
    if (!WritePropertiesToParcel(parcel)) {
        IMAGE_LOGE("write info to parcel failed.");
        return false;
    }
    if (!WriteMemInfoToParcel(parcel, bufferSize)) {
        IMAGE_LOGE("write memory info to parcel failed.");
        return false;
    }

    if (!WriteTransformDataToParcel(parcel)) {
        IMAGE_LOGE("write transformData to parcel failed.");
        return false;
    }

    FlushCache();

    {
        std::lock_guard<std::mutex> lock(*propertiesDirtyMutex_);
        isPropertiesDirty_ = false;
    }
    return true;
}

void PixelMap::FlushCache() const
{
    if (isMemoryDirty_ || isUseDefaultDmaNopadding_) {
        ImageUtils::FlushSurfaceBuffer(const_cast<PixelMap *>(this));
        isMemoryDirty_ = false;
    }
}

bool PixelMap::ReadImageInfo(Parcel &parcel, ImageInfo &imgInfo)
{
    imgInfo.size.width = parcel.ReadInt32();
    IMAGE_LOGD("read pixel map width:[%{public}d] to parcel.", imgInfo.size.width);
    imgInfo.size.height = parcel.ReadInt32();
    IMAGE_LOGD("read pixel map height:[%{public}d] to parcel.", imgInfo.size.height);
    if (imgInfo.size.width <= 0 || imgInfo.size.height <= 0) {
        IMAGE_LOGE("invalid width:[%{public}d] or height:[%{public}d]", imgInfo.size.width, imgInfo.size.height);
        return false;
    }
    imgInfo.pixelFormat = static_cast<PixelFormat>(parcel.ReadInt32());
    IMAGE_LOGD("read pixel map pixelFormat:[%{public}d] to parcel.", imgInfo.pixelFormat);
    if (ImageUtils::GetPixelBytes(imgInfo.pixelFormat) == 0) {
        IMAGE_LOGE("invalid pixelFormat:[%{public}d]", imgInfo.pixelFormat);
        return false;
    }
    imgInfo.colorSpace = static_cast<ColorSpace>(parcel.ReadInt32());
    IMAGE_LOGD("read pixel map colorSpace:[%{public}d] to parcel.", imgInfo.colorSpace);
    imgInfo.alphaType = static_cast<AlphaType>(parcel.ReadInt32());
    IMAGE_LOGD("read pixel map alphaType:[%{public}d] to parcel.", imgInfo.alphaType);
    imgInfo.baseDensity = parcel.ReadInt32();
    imgInfo.encodedFormat = parcel.ReadString();
    return true;
}

bool PixelMap::ReadTransformData(Parcel &parcel, PixelMap *pixelMap)
{
    if (pixelMap == nullptr) {
        IMAGE_LOGE("ReadTransformData invalid input parameter: pixelMap is null");
        return false;
    }

    if (pixelMap->IsAstc()) {
        TransformData transformData;
        transformData.scaleX = parcel.ReadFloat();
        transformData.scaleY = parcel.ReadFloat();
        transformData.rotateD = parcel.ReadFloat();
        transformData.cropLeft = parcel.ReadFloat();
        transformData.cropTop = parcel.ReadFloat();
        transformData.cropWidth = parcel.ReadFloat();
        transformData.cropHeight = parcel.ReadFloat();
        transformData.translateX = parcel.ReadFloat();
        transformData.translateY = parcel.ReadFloat();
        transformData.flipX = parcel.ReadBool();
        transformData.flipY = parcel.ReadBool();
        pixelMap->SetTransformData(transformData);
    }
    return true;
}

bool PixelMap::ReadAstcInfo(Parcel &parcel, PixelMap *pixelMap)
{
    if (pixelMap == nullptr) {
        IMAGE_LOGE("%{public}s invalid input parameter: pixelMap is null", __func__);
        return false;
    }

    if (pixelMap->IsAstc()) {
        Size realSize;
        realSize.width = parcel.ReadInt32();
        realSize.height = parcel.ReadInt32();
        if (realSize.width <= 0 || realSize.height <= 0) {
            IMAGE_LOGE("%{public}s invalid astc real size: width=%{public}d, height=%{public}d",
                __func__, realSize.width, realSize.height);
            return false;
        }
        pixelMap->SetAstcRealSize(realSize);
        bool isHdr = parcel.ReadBool();
        pixelMap->SetAstcHdr(isHdr);
    }
    return true;
}

bool PixelMap::ReadPropertiesFromParcel(Parcel &parcel, ImageInfo &imgInfo,
    AllocatorType &allocatorType, int32_t &bufferSize, PIXEL_MAP_ERR &error)
{
    bool isEditable = parcel.ReadBool();
    SetEditable(isEditable);
    SetAstc(ImageUtils::IsAstc(imgInfo.pixelFormat));
    bool displayOnly = parcel.ReadBool();
    SetDisplayOnly(displayOnly);
    int32_t readAllocatorValue = parcel.ReadInt32();
    if (readAllocatorValue < static_cast<int32_t>(AllocatorType::DEFAULT) ||
        readAllocatorValue > static_cast<int32_t>(AllocatorType::DMA_ALLOC)) {
        IMAGE_LOGE("[PixelMap] ReadPropertiesFromParcel invalid allocatorType");
        return false;
    }
    allocatorType = static_cast<AllocatorType>(readAllocatorValue);
    if (allocatorType == AllocatorType::DEFAULT || allocatorType == AllocatorType::CUSTOM_ALLOC) {
        allocatorType = AllocatorType::HEAP_ALLOC;
    }

    int32_t csm = parcel.ReadInt32();
    if (csm != ERR_MEDIA_INVALID_VALUE) {
        OHOS::ColorManager::ColorSpaceName colorSpaceName = static_cast<OHOS::ColorManager::ColorSpaceName>(csm);
        OHOS::ColorManager::ColorSpace grColorSpace = OHOS::ColorManager::ColorSpace(colorSpaceName);
        InnerSetColorSpace(grColorSpace);
    }

    int32_t rowDataSize = parcel.ReadInt32();
    if (!ReadAstcInfo(parcel, this)) {
        IMAGE_LOGE("[PixelMap] ReadPropertiesFromParcel: read ASTC real size failed");
        return false;
    }
    if (!ImageUtils::CheckRowDataSizeIsVaild(rowDataSize, imgInfo)) {
        PixelMap::ConstructPixelMapError(error, ERR_IMAGE_PIXELMAP_CREATE_FAILED,
            "bytePerPixel or rowDataSize invalid");
        return false;
    }

    bufferSize = parcel.ReadInt32();
    // Skip buffer size check for YUV/RGBA_F16 format:
    // - YUV will be verified in CheckYuvPixelMapBufferSize()
    // - RGBA_F16 will be verified in CheckF16PixelMapBufferSize()
    if (IsYUV(imgInfo.pixelFormat) || imgInfo.pixelFormat == PixelFormat::RGBA_F16) {
        return true;
    }
    uint64_t expectedBufferSize = static_cast<uint64_t>(rowDataSize) * static_cast<uint64_t>(imgInfo.size.height);
    if (isAstc_) {
        ImageInfo astcImgInfo = {astcrealSize_, imgInfo.pixelFormat};
        expectedBufferSize = ImageUtils::GetAstcBytesCount(astcImgInfo);
    }
    if (!ImageUtils::CheckBufferSizeIsValid(bufferSize, expectedBufferSize, allocatorType)) {
        PixelMap::ConstructPixelMapError(error, ERR_IMAGE_PIXELMAP_CREATE_FAILED, "bufferSize invalid");
        IMAGE_LOGE("[PixelMap] Invalid bufferSize: %{public}d, format: %{public}d", bufferSize, imgInfo.pixelFormat);
        return false;
    }
    return true;
}

#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
static bool CheckDmaSurfaceBufferSize(const ImageInfo &imgInfo, const PixelMemInfo &pixelMemInfo,
    const sptr<SurfaceBuffer> &surfaceBuffer)
{
    // YUV and RGBA_F16 DMA buffer sizes are validated later by their format-specific checks.
    if (IsYUV(imgInfo.pixelFormat) || imgInfo.pixelFormat == PixelFormat::RGBA_F16) {
        return true;
    }

    uint32_t surfaceBufferSize = surfaceBuffer->GetSize();
    if (pixelMemInfo.bufferSize <= 0 || surfaceBufferSize == 0 ||
        static_cast<uint32_t>(pixelMemInfo.bufferSize) > surfaceBufferSize) {
        IMAGE_LOGE("ReadDmaMemInfoFromParcel invalid DMA buffer size, bufferSize:%{public}d, sbSize:%{public}u",
            pixelMemInfo.bufferSize, surfaceBufferSize);
        return false;
    }
    return true;
}

bool ReadDmaMemInfoFromParcel(Parcel &parcel, const ImageInfo &imgInfo, PixelMemInfo &pixelMemInfo,
    std::function<int(Parcel &parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc)
{
    sptr<SurfaceBuffer> surfaceBuffer = SurfaceBuffer::Create();
    if (surfaceBuffer == nullptr) {
        IMAGE_LOGE("SurfaceBuffer failed to be created");
        return false;
    }
    GSError ret = surfaceBuffer->ReadFromMessageParcel(static_cast<MessageParcel&>(parcel), readSafeFdFunc);
    if (ret != GSError::GSERROR_OK) {
        IMAGE_LOGE("SurfaceBuffer read from message parcel failed: %{public}s", GSErrorStr(ret).c_str());
        return false;
    }

    void* nativeBuffer = surfaceBuffer.GetRefPtr();
    int32_t refRet = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
    if (refRet != SUCCESS) {
        IMAGE_LOGE("SurfaceBuffer reference failed");
        return false;
    }
    if (!CheckDmaSurfaceBufferSize(imgInfo, pixelMemInfo, surfaceBuffer)) {
        ImageUtils::SurfaceBuffer_Unreference(nativeBuffer);
        return false;
    }
    if (!pixelMemInfo.displayOnly) {
        pixelMemInfo.base = surfaceBuffer->GetVirAddr() == nullptr
            ? nullptr
            : static_cast<uint8_t *>(surfaceBuffer->GetVirAddr());
    }
    pixelMemInfo.context = nativeBuffer;
    return true;
}
#endif

bool PixelMap::ReadMemInfoFromParcel(Parcel &parcel, const ImageInfo &imgInfo, PixelMemInfo &pixelMemInfo,
    PIXEL_MAP_ERR &error,
    std::function<int(Parcel &parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (pixelMemInfo.allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
        auto readFdDefaultFunc = [](Parcel &parcel) -> int { return ReadFileDescriptor(parcel); };
        int fd = ((readSafeFdFunc != nullptr) ? readSafeFdFunc(parcel, readFdDefaultFunc) : readFdDefaultFunc(parcel));
        if (!CheckAshmemSize(fd, pixelMemInfo.bufferSize, pixelMemInfo.isAstc)) {
            PixelMap::ConstructPixelMapError(error, ERR_IMAGE_GET_FD_BAD, "fd acquisition failed");
            ::close(fd);
            return false;
        }
        void* ptr = ::mmap(nullptr, pixelMemInfo.bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if (ptr == MAP_FAILED) {
            ptr = ::mmap(nullptr, pixelMemInfo.bufferSize, PROT_READ, MAP_SHARED, fd, 0);
            if (ptr == MAP_FAILED) {
                ::close(fd);
                IMAGE_LOGE("shared memory map in memalloc failed, errno:%{public}d", errno);
                PixelMap::ConstructPixelMapError(error, ERR_IMAGE_GET_FD_BAD, "shared memory map in memalloc failed");
                return false;
            }
        }
        pixelMemInfo.context = new(std::nothrow) int32_t();
        if (pixelMemInfo.context == nullptr) {
            ::munmap(ptr, pixelMemInfo.bufferSize);
            ::close(fd);
            return false;
        }
        *static_cast<int32_t *>(pixelMemInfo.context) = fd;
        pixelMemInfo.base = static_cast<uint8_t *>(ptr);
    } else if (pixelMemInfo.allocatorType == AllocatorType::DMA_ALLOC) {
        if (!ReadDmaMemInfoFromParcel(parcel, imgInfo, pixelMemInfo, readSafeFdFunc)) {
            PixelMap::ConstructPixelMapError(error, ERR_IMAGE_GET_DATA_ABNORMAL, "ReadFromMessageParcel failed");
            return false;
        }
    } else { // Any other allocator types will malloc HEAP memory
        pixelMemInfo.base = ReadImageData(parcel, pixelMemInfo.bufferSize, readSafeFdFunc);
        if (pixelMemInfo.base == nullptr) {
            PixelMap::ConstructPixelMapError(error, ERR_IMAGE_GET_DATA_ABNORMAL, "ReadImageData failed");
            return false;
        }
    }
#else
    pixelMemInfo.base = ReadImageData(parcel, pixelMemInfo.bufferSize);
    if (pixelMemInfo.base == nullptr) {
        IMAGE_LOGE("get pixel memory size:[%{public}d] error.", pixelMemInfo.bufferSize);
        return false;
    }
#endif
    return true;
}

bool PixelMap::UpdatePixelMapMemInfo(PixelMap *pixelMap, ImageInfo &imgInfo, PixelMemInfo &pixelMemInfo)
{
    if (pixelMap == nullptr) {
        IMAGE_LOGE("UpdatePixelMapMemInfo invalid input parameter: pixelMap is null");
        return false;
    }

    uint32_t ret = pixelMap->SetImageInfo(imgInfo);
    if (ret != SUCCESS) {
        if (pixelMap->freePixelMapProc_ != nullptr) {
            pixelMap->freePixelMapProc_(pixelMemInfo.base, pixelMemInfo.context, pixelMemInfo.bufferSize);
        }
        ReleaseMemory(pixelMemInfo.allocatorType, pixelMemInfo.base, pixelMemInfo.context, pixelMemInfo.bufferSize);
        if (pixelMemInfo.allocatorType == AllocatorType::SHARE_MEM_ALLOC && pixelMemInfo.context != nullptr) {
            delete static_cast<int32_t *>(pixelMemInfo.context);
            pixelMemInfo.context = nullptr;
        }
        IMAGE_LOGE("create pixel map from parcel failed, set image info error.");
        return false;
    }
    pixelMap->SetPixelsAddr(pixelMemInfo.base, pixelMemInfo.context,
        pixelMemInfo.bufferSize, pixelMemInfo.allocatorType, pixelMap->IsDisplayOnly());
    return true;
}

static bool CheckYuvPixelMapBufferSize(const ImageInfo& imgInfo, PixelMemInfo& pixelMemInfo, PixelMap *pixelMap)
{
#ifndef CROSS_PLATFORM
    bool cond = !IsYUV(imgInfo.pixelFormat);
    CHECK_ERROR_RETURN_RET(cond, true); // only check yuv format
    cond = pixelMap == nullptr;
    CHECK_ERROR_RETURN_RET_LOG(cond, false, "pixelMap is nullptr");
    int32_t memBufSizeInt = pixelMemInfo.bufferSize;
    ImageUtils::UpdateYUVDataInfo(*pixelMap);
    YUVDataInfo yDataInfo;
    pixelMap->GetImageYUVInfo(yDataInfo);
    uint32_t YuvPlaneSize = yDataInfo.yStride * yDataInfo.yHeight + yDataInfo.uvStride * yDataInfo.uvHeight;
    uint32_t calcSize = YuvPlaneSize;
    if (IsYuvP010(imgInfo.pixelFormat)) {
        cond = YuvPlaneSize > UINT32_MAX / NUM_2;
        CHECK_ERROR_RETURN_RET_LOG(cond, false, "Invalid YUV P010 buffer size: overflow (exceeds UINT32_MAX)");
        calcSize = YuvPlaneSize * NUM_2; // YuvP010 format: 10-bit per pixel (2 bytes actual, need double)
    }
    if (pixelMemInfo.allocatorType == AllocatorType::DMA_ALLOC && pixelMemInfo.context != nullptr) {
        SurfaceBuffer* sb = static_cast<SurfaceBuffer*>(pixelMemInfo.context);
        uint32_t sbSize = sb->GetSize();
        if (memBufSizeInt <= 0 || sbSize == 0) {
            IMAGE_LOGE("Invalid YUV buffer size: memBufSize[%{public}d]/sbSize[%{public}u]", memBufSizeInt, sbSize);
            return false;
        }
        cond = calcSize > sbSize;
        CHECK_ERROR_RETURN_RET_LOG(cond, false, "Invalid YUV buffer size:%{public}u > sbSize:%{public}u",
                                   calcSize, sbSize);

        uint32_t memBufSize = static_cast<uint32_t>(memBufSizeInt);
        int32_t pixelBytes = pixelMap->GetPixelBytes();
        cond = pixelBytes <= 0;
        CHECK_ERROR_RETURN_RET_LOG(cond, false, "Invalid YUV format, pixel bytes is 0");
        cond = ImageUtils::CheckMulOverflow(imgInfo.size.width, imgInfo.size.height, pixelBytes);
        CHECK_ERROR_RETURN_RET_LOG(cond, false, "Invalid pixelmap params width:%{public}d, height:%{public}d",
                                   imgInfo.size.width, imgInfo.size.height);
        // Yuv420 perl pixel 1.5 Bytes but return int so return 2
        uint32_t byteCount = static_cast<uint32_t>(imgInfo.size.width * imgInfo.size.height * pixelBytes);
        if (memBufSize != byteCount && memBufSize > sbSize) { // If return 2, the verification is skipped
            IMAGE_LOGE("Invalid YUV buffer size: memBufSize[%{public}u] > sbSize[%{public}u]", memBufSize, sbSize);
            return false;
        }
    } else {
        uint64_t expectedBufferSize = static_cast<uint64_t>(ImageUtils::GetByteCount(imgInfo));
        cond = static_cast<uint64_t>(calcSize) > expectedBufferSize;
        CHECK_ERROR_RETURN_RET_LOG(cond, false, "Invalid YUV buffer size:%{public}u > expect:%{public}" PRIu64,
                                   calcSize, expectedBufferSize);
        if (!ImageUtils::CheckBufferSizeIsValid(memBufSizeInt, expectedBufferSize, pixelMemInfo.allocatorType)) {
            IMAGE_LOGE("Invalid buffer size: memBufSize[%{public}d] mismatch expect[%{public}" PRIu64 "]",
                memBufSizeInt, expectedBufferSize);
            return false;
        }
    }
    return true;
#else
    return true;
#endif
}

static bool CheckF16PixelMapBufferSize(const ImageInfo& imgInfo, PixelMemInfo& pixelMemInfo, PixelMap *pixelMap)
{
#ifndef CROSS_PLATFORM
    bool cond = imgInfo.pixelFormat != PixelFormat::RGBA_F16;
    CHECK_ERROR_RETURN_RET(cond, true); // only check RGBA_F16 format
    cond = pixelMap == nullptr;
    CHECK_ERROR_RETURN_RET_LOG(cond, false, "pixelMap is nullptr");
    int32_t memBufSizeInt = pixelMemInfo.bufferSize;
    if (pixelMemInfo.allocatorType == AllocatorType::DMA_ALLOC && pixelMemInfo.context != nullptr) {
        SurfaceBuffer* sb = static_cast<SurfaceBuffer*>(pixelMemInfo.context);
        uint32_t sbSize = sb->GetSize();
        if (memBufSizeInt <= 0 || sbSize == 0) {
            IMAGE_LOGE("Invalid F16 buffer size: memBufSize[%{public}d]/sbSize[%{public}u]", memBufSizeInt, sbSize);
            return false;
        }
        uint32_t memBufSize = static_cast<uint32_t>(memBufSizeInt);
        if (memBufSize > sbSize) {
            IMAGE_LOGE("Invalid F16 buffer size: memBufSize[%{public}u] > sbSize[%{public}u]", memBufSize, sbSize);
            return false;
        }
    } else {
        uint64_t expectedBufferSizeOrg = static_cast<uint64_t>(ImageUtils::GetByteCount(imgInfo));
        uint64_t alignedWidth = ((static_cast<uint64_t>(imgInfo.size.width) + NUM_1) / NUM_2) * NUM_2;
        uint64_t expectedBufferSizeAlign = static_cast<uint64_t>(imgInfo.size.height) * alignedWidth * RGBA_F16_BYTES;
        if (!ImageUtils::CheckBufferSizeIsValid(memBufSizeInt, expectedBufferSizeOrg, pixelMemInfo.allocatorType) &&
            !ImageUtils::CheckBufferSizeIsValid(memBufSizeInt, expectedBufferSizeAlign, pixelMemInfo.allocatorType)) {
            IMAGE_LOGE("Invalid buffer size: memBufSize[%{public}d] mismatch expect[%{public}" PRIu64
                "]/Align[%{public}" PRIu64 "]",
                memBufSizeInt, expectedBufferSizeOrg, expectedBufferSizeAlign);
            return false;
        }
    }
    return true;
#else
    return true;
#endif
}

PixelMap *PixelMap::UnmarshallingWithIsDisplay(Parcel &parcel,
    std::function<int(Parcel &parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc, bool isDisplay)
{
    PIXEL_MAP_ERR error;
    PixelMap* dstPixelMap = PixelMap::Unmarshalling(parcel, error, readSafeFdFunc, isDisplay);
    if (dstPixelMap == nullptr || error.errorCode != SUCCESS) {
        IMAGE_LOGE("unmarshalling failed errorCode:%{public}d, errorInfo:%{public}s",
            error.errorCode, error.errorInfo.c_str());
    }
    return dstPixelMap;
}

PixelMap *PixelMap::Unmarshalling(Parcel &parcel,
    std::function<int(Parcel &parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc)
{
    PIXEL_MAP_ERR error;
    PixelMap* dstPixelMap = PixelMap::Unmarshalling(parcel, error, readSafeFdFunc, false);
    if (dstPixelMap == nullptr || error.errorCode != SUCCESS) {
        IMAGE_LOGE("unmarshalling failed errorCode:%{public}d, errorInfo:%{public}s",
            error.errorCode, error.errorInfo.c_str());
    }
    return dstPixelMap;
}

PixelMap *PixelMap::StartUnmarshalling(Parcel &parcel, ImageInfo &imgInfo,
    PixelMemInfo& pixelMemInfo, PIXEL_MAP_ERR &error, bool isDisplay)
{
    if (!ReadImageInfo(parcel, imgInfo)) {
        IMAGE_LOGE("read imageInfo fail");
        PixelMap::ConstructPixelMapError(error, ERR_IMAGE_PIXELMAP_CREATE_FAILED, "read imageInfo fail");
        return nullptr;
    }
    PixelMap *pixelMap = NewPixelMapByFormat(imgInfo.pixelFormat);
    if (pixelMap == nullptr) {
        PixelMap::ConstructPixelMapError(error, ERR_IMAGE_PIXELMAP_CREATE_FAILED, "pixelmap create failed");
        return nullptr;
    }
    pixelMap->isUnmarshalling_ = true;

    if (!pixelMap->ReadPropertiesFromParcel(
        parcel, imgInfo, pixelMemInfo.allocatorType, pixelMemInfo.bufferSize, error)) {
        IMAGE_LOGE("read properties fail");
        delete pixelMap;
        return nullptr;
    }

    if (isDisplay == true) {
        pixelMap->SetDisplayOnly(true);
    }
    pixelMemInfo.isAstc = pixelMap->IsAstc();
    pixelMemInfo.displayOnly = pixelMap->IsDisplayOnly();
    return pixelMap;
}

PixelMap *PixelMap::FinishUnmarshalling(PixelMap *pixelMap, Parcel &parcel,
    ImageInfo &imgInfo, PixelMemInfo &pixelMemInfo, PIXEL_MAP_ERR &error)
{
    if (!pixelMap) {
        return nullptr;
    }
    if (!UpdatePixelMapMemInfo(pixelMap, imgInfo, pixelMemInfo)) {
        IMAGE_LOGE("update pixelMap memInfo fail");
        delete pixelMap;
        return nullptr;
    }
    if (!CheckPixelMapDataSize(pixelMap)) {
        PixelMap::ConstructPixelMapError(error, ERR_IMAGE_PIXELMAP_CREATE_FAILED, "pixelMap data size invalid");
        IMAGE_LOGE("Unmarshalling: pixelMap data size invalid");
        delete pixelMap;
        return nullptr;
    }
    if (!pixelMap->ReadTransformData(parcel, pixelMap)) {
        IMAGE_LOGE("read transformData fail");
        delete pixelMap;
        return nullptr;
    }
    if (!CheckYuvPixelMapBufferSize(imgInfo, pixelMemInfo, pixelMap) ||
        !CheckF16PixelMapBufferSize(imgInfo, pixelMemInfo, pixelMap)) {
        IMAGE_LOGE("Unmarshalling: Check YUV/F16 PixelMap BufferSize fail");
        delete pixelMap;
        return nullptr;
    }
    pixelMap->isUnmarshalling_ = false;
    return pixelMap;
}

PixelMap *PixelMap::Unmarshalling(Parcel &parcel, PIXEL_MAP_ERR &error,
    std::function<int(Parcel &parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc, bool isDisplay)
{
    ImageInfo imgInfo;
    PixelMemInfo pixelMemInfo;
    PixelMap *pixelMap = StartUnmarshalling(parcel, imgInfo, pixelMemInfo, error, isDisplay);
    if (!pixelMap) {
        IMAGE_LOGE("StartUnmarshalling: get pixelmap failed");
        return nullptr;
    }
    if (!ReadMemInfoFromParcel(parcel, imgInfo, pixelMemInfo, error, readSafeFdFunc)) {
        IMAGE_LOGE("Unmarshalling: read memInfo failed");
        delete pixelMap;
        return nullptr;
    }
    return FinishUnmarshalling(pixelMap, parcel, imgInfo, pixelMemInfo, error);
}

uint8_t PixelMap::ReadUint8(std::vector<uint8_t> &buff, int32_t &cursor)
{
    if (static_cast<size_t>(cursor + 1) > buff.size()) {
        IMAGE_LOGE("ReadUint8 out of range");
        return TLV_END;
    }
    return buff[cursor++];
}

void PixelMap::WriteData(std::vector<uint8_t> &buff, const uint8_t *data,
    const int32_t &height, const int32_t &rowDataSize, const int32_t &rowStride) const
{
    if (data == nullptr) {
        IMAGE_LOGE("WriteData invalid input parameter: data is null");
        return;
    }

    if (allocatorType_ == AllocatorType::DMA_ALLOC) {
        for (int row = 0; row < height; row++) {
            for (int col = 0; col < rowDataSize; col++) {
                buff.push_back(*(data + row * rowStride + col));
            }
        }
    } else {
        int32_t size = pixelsSize_;
        buff.insert(buff.end(), data, data + size);
    }
}

static bool EncodeTlvHdrInfo(std::vector<uint8_t> &buff, AllocatorType allocatorType, PixelMap* pixelMap)
{
    if (pixelMap == nullptr) {
        return false;
    }
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (allocatorType == AllocatorType::DMA_ALLOC && pixelMap->IsHdr() &&
        pixelMap->InnerGetGrColorSpacePtr() != nullptr) {
        ImageUtils::WriteUint8(buff, TLV_IMAGE_HDR);
        ImageUtils::WriteVarint(buff, NUM_1);
        ImageUtils::WriteVarint(buff, NUM_1);
        ImageUtils::TlvWriteSurfaceInfo(pixelMap, buff);
        int32_t csm = static_cast<int32_t>(pixelMap->InnerGetGrColorSpacePtr()->GetColorSpaceName());
        ImageUtils::WriteUint8(buff, TLV_IMAGE_CSM);
        ImageUtils::WriteVarint(buff, ImageUtils::GetVarintLen(csm));
        ImageUtils::WriteVarint(buff, csm);
    }
    return true;
#endif
    return true;
}

bool PixelMap::EncodeTlv(std::vector<uint8_t> &buff) const
{
    if (!ImageUtils::CheckTlvSupportedFormat(imageInfo_.pixelFormat)) {
        IMAGE_LOGE("[PixelMap] EncodeTlv fail, format not supported, format: %{public}d", imageInfo_.pixelFormat);
        return false;
    }
    ImageUtils::WriteUint8(buff, TLV_IMAGE_WIDTH);
    ImageUtils::WriteVarint(buff, ImageUtils::GetVarintLen(imageInfo_.size.width));
    ImageUtils::WriteVarint(buff, imageInfo_.size.width);
    ImageUtils::WriteUint8(buff, TLV_IMAGE_HEIGHT);
    ImageUtils::WriteVarint(buff, ImageUtils::GetVarintLen(imageInfo_.size.height));
    ImageUtils::WriteVarint(buff, imageInfo_.size.height);
    ImageUtils::WriteUint8(buff, TLV_IMAGE_PIXELFORMAT);
    ImageUtils::WriteVarint(buff, ImageUtils::GetVarintLen(static_cast<int32_t>(imageInfo_.pixelFormat)));
    ImageUtils::WriteVarint(buff, static_cast<int32_t>(imageInfo_.pixelFormat));
    ImageUtils::WriteUint8(buff, TLV_IMAGE_COLORSPACE);
    ImageUtils::WriteVarint(buff, ImageUtils::GetVarintLen(static_cast<int32_t>(imageInfo_.colorSpace)));
    ImageUtils::WriteVarint(buff, static_cast<int32_t>(imageInfo_.colorSpace));
    ImageUtils::WriteUint8(buff, TLV_IMAGE_ALPHATYPE);
    ImageUtils::WriteVarint(buff, ImageUtils::GetVarintLen(static_cast<int32_t>(imageInfo_.alphaType)));
    ImageUtils::WriteVarint(buff, static_cast<int32_t>(imageInfo_.alphaType));
    ImageUtils::WriteUint8(buff, TLV_IMAGE_BASEDENSITY);
    ImageUtils::WriteVarint(buff, ImageUtils::GetVarintLen(imageInfo_.baseDensity));
    ImageUtils::WriteVarint(buff, imageInfo_.baseDensity);
    if (!EncodeTlvHdrInfo(buff, allocatorType_, const_cast<PixelMap*>(this))) {
        return false;
    }
    AllocatorType tmpAllocatorType = AllocatorType::HEAP_ALLOC;
    ImageUtils::WriteUint8(buff, TLV_IMAGE_ALLOCATORTYPE);
    ImageUtils::WriteVarint(buff, ImageUtils::GetVarintLen(static_cast<int32_t>(tmpAllocatorType)));
    ImageUtils::WriteVarint(buff, static_cast<int32_t>(tmpAllocatorType));
    ImageUtils::WriteUint8(buff, TLV_IMAGE_DATA);
    uint64_t dataSize = static_cast<uint64_t>(rowDataSize_) * static_cast<uint64_t>(imageInfo_.size.height);
    if (isUnMap_ || data_ == nullptr || dataSize > MAX_IMAGEDATA_SIZE) {
        ImageUtils::WriteVarint(buff, 0); // L is zero and no value
        ImageUtils::WriteUint8(buff, TLV_END); // end tag
        IMAGE_LOGE("[PixelMap] tlv encode fail: no data or invalid dataSize, isUnMap %{public}d", isUnMap_);
        return false;
    }
    ImageUtils::WriteVarint(buff, static_cast<int32_t>(dataSize));
    WriteData(buff, data_, imageInfo_.size.height, rowDataSize_, rowStride_);
    ImageUtils::WriteUint8(buff, TLV_END); // end tag
    return true;
}

static bool CheckTlvImageInfo(const ImageInfo &info, std::unique_ptr<AbsMemory>& dstMemory,
    bool isHdr, const HdrInfo& hdrInfo, int32_t& csm)
{
    if (info.size.width <= 0 || info.size.height <= 0 || dstMemory == nullptr || dstMemory->data.data == nullptr) {
        return false;
    }
    if (!isHdr && csm == -1) {
        return true;
    }
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (isHdr && csm != -1 && dstMemory->GetType() == AllocatorType::DMA_ALLOC) {
        sptr<SurfaceBuffer> sbBuffer(static_cast<SurfaceBuffer*>(dstMemory->extend.data));
        if (!VpeUtils::SetSbColorSpaceType(sbBuffer, hdrInfo.colorSpaceType)) {
            IMAGE_LOGE("[PixelMap] Tlv set ColorSpace failed");
            return false;
        }
        if (!VpeUtils::SetSbMetadataType(sbBuffer, hdrInfo.metadataType)) {
            IMAGE_LOGE("[PixelMap] Tlv set MetadataType failed");
            return false;
        }
        if (!VpeUtils::SetSbStaticMetadata(sbBuffer, hdrInfo.staticMetadata)) {
            IMAGE_LOGE("[PixelMap] Tlv set staticMetadata failed");
            return false;
        }
        if (!VpeUtils::SetSbDynamicMetadata(sbBuffer, hdrInfo.dynamicMetadata)) {
            IMAGE_LOGE("[PixelMap] Tlv set dynamicMetadata failed");
            return false;
        }
        return true;
    }
#endif
    IMAGE_LOGE("[PixelMap] tlv data invalid");
    return false;
}

static std::map<uint8_t, std::function<bool(TlvDecodeInfo&, vector<uint8_t>&, int32_t&, int32_t)>>
    TlvDecodeFunc = {
        {TLV_IMAGE_WIDTH, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.info.size.width = ImageUtils::ReadVarint(buff, cursor);
            return !(decodeInfo.info.size.width <= 0);
        }},
        {TLV_IMAGE_HEIGHT, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.info.size.height = ImageUtils::ReadVarint(buff, cursor);
            return !(decodeInfo.info.size.height <= 0);
        }},
        {TLV_IMAGE_PIXELFORMAT, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.info.pixelFormat = static_cast<PixelFormat>(ImageUtils::ReadVarint(buff, cursor));
            if (!ImageUtils::CheckTlvSupportedFormat(decodeInfo.info.pixelFormat)) {
                IMAGE_LOGE("[PixelMap] tlv decode unsupported pixelformat: %{public}d", decodeInfo.info.pixelFormat);
                return false;
            }
            return true;
        }},
        {TLV_IMAGE_COLORSPACE, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.info.colorSpace = static_cast<ColorSpace>(ImageUtils::ReadVarint(buff, cursor));
            return true;
        }},
        {TLV_IMAGE_ALPHATYPE, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.info.alphaType = static_cast<AlphaType>(ImageUtils::ReadVarint(buff, cursor));
            return true;
        }},
        {TLV_IMAGE_BASEDENSITY, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.info.baseDensity = ImageUtils::ReadVarint(buff, cursor);
            return true;
        }},
        {TLV_IMAGE_ALLOCATORTYPE, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.allocType = ImageUtils::ReadVarint(buff, cursor);
            if (decodeInfo.allocType != NUM_1) {
                IMAGE_LOGE("[PixelMap] tlv decode invalid allocatorType: %{public}d", decodeInfo.allocType);
                return false;
            }
            if (decodeInfo.isHdr == NUM_1) {
                decodeInfo.allocType = static_cast<int32_t>(AllocatorType::DMA_ALLOC);
            } else if (ImageUtils::IsSupportDefaultDmaNopadding(decodeInfo.info.size, decodeInfo.info.pixelFormat)) {
                decodeInfo.allocType = static_cast<int32_t>(AllocatorType::DEFAULT);
            }
            return true;
        }},
        {TLV_IMAGE_DATA, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.dstMemory = ImageUtils::ReadData(buff, len, cursor,
                static_cast<AllocatorType>(decodeInfo.allocType), decodeInfo.info);
            cursor += len; // skip data
            if (decodeInfo.dstMemory == nullptr) {
                return false;
            }
            return true;
        }},
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
        {TLV_IMAGE_HDR, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.isHdr = ImageUtils::ReadVarint(buff, cursor);
            return true;
        }},
        {TLV_IMAGE_COLORTYPE, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.hdrInfo.colorSpaceType =
                static_cast<CM_ColorSpaceType>(ImageUtils::ReadVarint(buff, cursor));
            return true;
        }},
        {TLV_IMAGE_METADATATYPE, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.hdrInfo.metadataType =
                static_cast<CM_HDR_Metadata_Type>(ImageUtils::ReadVarint(buff, cursor));
            return true;
        }},
        {TLV_IMAGE_STATICMETADATA, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.hdrInfo.staticMetadata.reserve(len);
            copy(buff.begin() + cursor, buff.begin() + cursor + len, back_inserter(decodeInfo.hdrInfo.staticMetadata));
            cursor += len;
            return true;
        }},
        {TLV_IMAGE_DYNAMICMETADATA, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.hdrInfo.dynamicMetadata.reserve(len);
            copy(buff.begin() + cursor, buff.begin() + cursor + len, back_inserter(decodeInfo.hdrInfo.dynamicMetadata));
            
            cursor += len;
            return true;
        }},
        {TLV_IMAGE_CSM, [](TlvDecodeInfo& decodeInfo, vector<uint8_t>& buff, int32_t& cursor, int32_t len) {
            decodeInfo.csm = ImageUtils::ReadVarint(buff, cursor);
            return true;
        }},
#endif
};

static std::map<uint8_t, bool> InitTlvReEntryCheckMap()
{
    std::map<uint8_t, bool> reEntryCheckMap = {
        {TLV_IMAGE_WIDTH, false},
        {TLV_IMAGE_HEIGHT, false},
        {TLV_IMAGE_PIXELFORMAT, false},
        {TLV_IMAGE_COLORSPACE, false},
        {TLV_IMAGE_ALPHATYPE, false},
        {TLV_IMAGE_BASEDENSITY, false},
        {TLV_IMAGE_ALLOCATORTYPE, false},
        {TLV_IMAGE_DATA, false},
        {TLV_IMAGE_HDR, false},
        {TLV_IMAGE_COLORTYPE, false},
        {TLV_IMAGE_METADATATYPE, false},
        {TLV_IMAGE_STATICMETADATA, false},
        {TLV_IMAGE_DYNAMICMETADATA, false},
        {TLV_IMAGE_CSM, false},
    };
    return reEntryCheckMap;
}

bool PixelMap::ReadTlvAttr(std::vector<uint8_t> &buff, ImageInfo &info,
    std::unique_ptr<AbsMemory>& dstMemory, int32_t& csm)
{
    TlvDecodeInfo tlvDecInfo;
    map<uint8_t, bool> tlvReEntryCheck = InitTlvReEntryCheckMap();
    int32_t cursor = 0;
    for (uint8_t tag = ReadUint8(buff, cursor); tag != TLV_END; tag = ReadUint8(buff, cursor)) {
        int32_t len = ImageUtils::ReadVarint(buff, cursor);
        if (len <= 0 || cursor > INT32_MAX - len || static_cast<size_t>(cursor + len) > buff.size()) {
            IMAGE_LOGE("[PixelMap] ReadTlvAttr out of range tag: %{public}d, len: %{public}d", tag, len);
            return false;
        }
        auto tlvDecFunc = TlvDecodeFunc.find(tag);
        if (tlvDecFunc == TlvDecodeFunc.end()) {
            cursor += len; // skip unknown tag
            IMAGE_LOGW("[PixelMap] ReadTlvAttr unsupported tag: %{public}d", tag);
        } else {
            auto it = tlvReEntryCheck.find(tag);
            if (it != tlvReEntryCheck.end() && it->second) {
                IMAGE_LOGE("[PixelMap] ReadTlvAttr re-entry tag: %{public}d", tag);
                return false;
            }
            it->second = true;
            if (!tlvDecFunc->second(tlvDecInfo, buff, cursor, len)) {
                IMAGE_LOGE("[PixelMap] ReadTlvAttr decode tag: %{public}d fail", tag);
                return false;
            }
        }
    }
    info = tlvDecInfo.info;
    csm = tlvDecInfo.csm;
    dstMemory = std::move(tlvDecInfo.dstMemory);
    return CheckTlvImageInfo(info, dstMemory, tlvDecInfo.isHdr == NUM_1, tlvDecInfo.hdrInfo, csm);
}

PixelMap *PixelMap::DecodeTlv(std::vector<uint8_t> &buff)
{
    ImageInfo imageInfo;
    std::unique_ptr<AbsMemory> dstMemory = nullptr;
    int32_t csm = -1;
    if (!ReadTlvAttr(buff, imageInfo, dstMemory, csm)) {
        if (dstMemory != nullptr) {
            dstMemory->Release();
        }
        IMAGE_LOGE("[PixelMap] tlv decode fail");
        return nullptr;
    }
    PixelMap *pixelMap = NewPixelMapByFormat(imageInfo.pixelFormat);
    if (pixelMap == nullptr) {
        dstMemory->Release();
        IMAGE_LOGE("[PixelMap] tlv decode fail: new pixelmap error");
        return nullptr;
    }
    uint32_t ret = pixelMap->SetImageInfo(imageInfo);
    if (ret != SUCCESS) {
        dstMemory->Release();
        delete pixelMap;
        IMAGE_LOGE("[PixelMap] tlv decode fail: set image info error [%{public}d]", ret);
        return nullptr;
    }
    if ((dstMemory->GetType() == AllocatorType::DMA_ALLOC &&
        dstMemory->data.size < static_cast<uint32_t>(pixelMap->GetByteCount())) ||
        (dstMemory->GetType() == AllocatorType::HEAP_ALLOC &&
        dstMemory->data.size != static_cast<uint32_t>(pixelMap->GetByteCount()))) {
        dstMemory->Release();
        delete pixelMap;
        IMAGE_LOGE("[PixelMap] tlv decode fail: size not match");
        return nullptr;
    }
    pixelMap->SetPixelsAddr(dstMemory->data.data, dstMemory->extend.data, dstMemory->data.size,
        dstMemory->GetType(), nullptr);
    if (csm != -1) {
        OHOS::ColorManager::ColorSpaceName colorSpaceName = static_cast<OHOS::ColorManager::ColorSpaceName>(csm);
        OHOS::ColorManager::ColorSpace grColorSpace = OHOS::ColorManager::ColorSpace(colorSpaceName);
        pixelMap->InnerSetColorSpace(grColorSpace);
    }
    return pixelMap;
}

bool PixelMap::IsYuvFormat(PixelFormat format)
{
    return format == PixelFormat::NV21 || format == PixelFormat::NV12 ||
        format == PixelFormat::YCBCR_P010 || format == PixelFormat::YCRCB_P010 ||
        format == PixelFormat::Y8;
}

bool PixelMap::IsYuvFormat() const
{
    return IsYuvFormat(imageInfo_.pixelFormat);
}

bool PixelMap::IsAstcOrY8Format() const
{
    return isAstc_ || imageInfo_.pixelFormat == PixelFormat::Y8;
}

static const string GetNamedAlphaType(const AlphaType alphaType)
{
    switch (alphaType) {
        case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
            return "Alpha Type Unknown";
        case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
            return "Alpha Type Opaque";
        case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
            return "Alpha Type Premul";
        case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
            return "Alpha Type Unpremul";
        default:
            return "Alpha Type Unknown";
    }
    return "Alpha Type Unknown";
}

static const string GetNamedPixelFormat(const PixelFormat pixelFormat)
{
    switch (pixelFormat) {
        case PixelFormat::UNKNOWN:
            return "Pixel Format UNKNOWN";
        case PixelFormat::RGB_565:
            return "Pixel Format RGB_565";
        case PixelFormat::RGB_888:
            return "Pixel Format RGB_888";
        case PixelFormat::NV21:
            return "Pixel Format NV21";
        case PixelFormat::NV12:
            return "Pixel Format NV12";
        case PixelFormat::YCBCR_P010:
            return "Pixel Format YCBCR_P010";
        case PixelFormat::YCRCB_P010:
            return "Pixel Format YCRCB_P010";
        case PixelFormat::CMYK:
            return "Pixel Format CMYK";
        case PixelFormat::ARGB_8888:
            return "Pixel Format ARGB_8888";
        case PixelFormat::ALPHA_8:
            return "Pixel Format ALPHA_8";
        case PixelFormat::ALPHA_U8:
            return "Pixel Format ALPHA_U8";
        case PixelFormat::ALPHA_F16:
            return "Pixel Format ALPHA_F16";
        case PixelFormat::RGBA_8888:
            return "Pixel Format RGBA_8888";
        case PixelFormat::BGRA_8888:
            return "Pixel Format BGRA_8888";
        case PixelFormat::RGBA_F16:
            return "Pixel Format RGBA_F16";
        case PixelFormat::ASTC_4x4:
            return "Pixel Format ASTC_4x4";
        case PixelFormat::ASTC_6x6:
            return "Pixel Format ASTC_6x6";
        case PixelFormat::ASTC_8x8:
            return "Pixel Format ASTC_8x8";
        case PixelFormat::RGBA_1010102:
            return "Pixel Format RGBA_1010102";
        default:
            return "Pixel Format UNKNOWN";
    }
}

constexpr uint8_t HALF_LOW_BYTE = 0;
constexpr uint8_t HALF_HIGH_BYTE = 1;

static float HalfTranslate(const uint8_t* ui)
{
    return HalfToFloat(U8ToU16(ui[HALF_HIGH_BYTE], ui[HALF_LOW_BYTE]));
}

static void HalfTranslate(const float pixel, uint8_t* ui)
{
    uint16_t val = FloatToHalf(pixel);
    ui[HALF_LOW_BYTE] = static_cast<uint8_t>(val & UINT8_MAX);
    ui[HALF_HIGH_BYTE] = static_cast<uint8_t>((val >> SHIFT_8_BIT) & UINT8_MAX);
}

static uint8_t AlphaF16ToUInt8(const uint8_t *pixel)
{
    if (pixel == nullptr) {
        return 0;
    }
    float alpha = HalfTranslate(pixel);
    alpha = std::clamp(alpha, 0.0f, ALPHA_F16_MAX_VALUE);
    return static_cast<uint8_t>(alpha * UINT8_MAX + HALF_ONE);
}

static void UInt8ToAlphaF16(uint8_t alpha, uint8_t *pixel)
{
    if (pixel == nullptr) {
        return;
    }
    HalfTranslate(static_cast<float>(alpha) / UINT8_MAX, pixel);
}

constexpr uint8_t RGBA_F16_R_OFFSET = 0;
constexpr uint8_t RGBA_F16_G_OFFSET = 2;
constexpr uint8_t RGBA_F16_B_OFFSET = 4;
constexpr uint8_t RGBA_F16_A_OFFSET = 6;

static constexpr float FLOAT_NUMBER_NEAR_ZERO = 0.000001;
static constexpr float FLOAT_ZERO = 0.0f;
static float ProcessPremulF16Pixel(float mulPixel, float alpha, const float percent)
{
    if (alpha < FLOAT_NUMBER_NEAR_ZERO && alpha > -FLOAT_NUMBER_NEAR_ZERO) {
        return FLOAT_ZERO;
    }
    float res = mulPixel * percent / alpha;
    return res > MAX_HALF ? MAX_HALF : res;
}

static void SetF16PixelAlpha(uint8_t *pixel, const float percent, bool isPixelPremul)
{
    if (pixel == nullptr) {
        IMAGE_LOGE("SetF16PixelAlpha invalid input parameter: pixel is null");
        return;
    }

    float a = HalfTranslate(pixel + RGBA_F16_A_OFFSET);
    if (isPixelPremul) {
        float r = HalfTranslate(pixel + RGBA_F16_R_OFFSET);
        float g = HalfTranslate(pixel + RGBA_F16_G_OFFSET);
        float b = HalfTranslate(pixel + RGBA_F16_B_OFFSET);
        r = ProcessPremulF16Pixel(r, a, percent);
        g = ProcessPremulF16Pixel(g, a, percent);
        b = ProcessPremulF16Pixel(b, a, percent);
        HalfTranslate(r, pixel + RGBA_F16_R_OFFSET);
        HalfTranslate(g, pixel + RGBA_F16_G_OFFSET);
        HalfTranslate(b, pixel + RGBA_F16_B_OFFSET);
    }
    a = percent * MAX_HALF;
    HalfTranslate(a, pixel + RGBA_F16_A_OFFSET);
}

static constexpr uint8_t U_ZERO = 0;
static uint8_t ProcessPremulPixel(uint8_t mulPixel, uint8_t alpha, const float percent)
{
    // mP = oP * oAlpha / UINT8_MAX
    // => oP = mP * UINT8_MAX / oAlpha
    // nP = oP * percent
    // => nP = mP * UINT8_MAX * percent / oAlpha
    if (alpha == 0) {
        return U_ZERO;
    }
    float nPixel = mulPixel * percent * UINT8_MAX / alpha;
    if ((nPixel + HALF_ONE) >= UINT8_MAX) {
        return UINT8_MAX;
    }
    return static_cast<uint8_t>(nPixel + HALF_ONE);
}

static void SetUintPixelAlpha(uint8_t *pixel, const float percent,
    uint8_t pixelByte, int8_t alphaIndex, bool isPixelPremul)
{
    if (pixel == nullptr) {
        IMAGE_LOGE("SetUintPixelAlpha invalid input parameter: pixel is null");
        return;
    }

    if (isPixelPremul) {
        for (int32_t pixelIndex = 0; pixelIndex < pixelByte; pixelIndex++) {
            if (pixelIndex != alphaIndex) {
                pixel[pixelIndex] = ProcessPremulPixel(pixel[pixelIndex],
                    pixel[alphaIndex], percent);
            }
        }
    }
    pixel[alphaIndex] = static_cast<uint8_t>(UINT8_MAX * percent + HALF_ONE);
}

static constexpr uint8_t UINT2_MAX = 3;
static constexpr uint16_t UINT10_MAX = 1023;
static void CheckPixel(uint16_t &pixel, uint16_t alpha, const float percent)
{
    if (alpha != 0) {
        float rPixel = pixel * percent * UINT2_MAX / alpha;
        if ((rPixel + HALF_ONE) >= UINT10_MAX) {
            pixel = UINT10_MAX;
        }
        pixel = static_cast<uint16_t>(rPixel + HALF_ONE);
    } else {
        pixel = 0;
    }
}

static void SetRGBA1010102PixelAlpha(uint8_t *src, const float percent, int8_t alphaIndex, bool isPixelPremul)
{
    if (src == nullptr) {
        IMAGE_LOGE("SetRGBA1010102PixelAlpha invalid input parameter: src is null");
        return;
    }
    if (isPixelPremul) {
        uint16_t r = 0;
        uint16_t g = 0;
        uint16_t b = 0;
        uint16_t a = 0;
        a = static_cast<uint16_t>((src[NUM_3] >> NUM_6) & 0x03);
        uint16_t rHigh = static_cast<uint16_t>(src[0] & 0xFF);
        r = (rHigh) + (static_cast<uint16_t>(src[1] << NUM_8) & 0x300);
        CheckPixel(r, a, percent);
        uint16_t gHigh = static_cast<uint16_t>(src[1] & 0xFF);
        g = (gHigh >> NUM_2) + (static_cast<uint16_t>(src[NUM_2] << NUM_6) & 0x3C0);
        CheckPixel(g, a, percent);
        uint16_t bHigh = static_cast<uint16_t>(src[NUM_2] & 0xFF);
        b = (bHigh >> NUM_4) + (static_cast<uint16_t>(src[NUM_3] << NUM_4) & 0x3F0);
        CheckPixel(b, a, percent);
        a = static_cast<uint16_t>(UINT2_MAX * percent + HALF_ONE);
        src[0] = static_cast<uint8_t>(r);
        src[1] = static_cast<uint8_t>(g << NUM_2 | r >> NUM_8);
        src[NUM_2] = static_cast<uint8_t>(b << NUM_4 | g >> NUM_6);
        src[NUM_3] = static_cast<uint8_t>(a << NUM_6 | b >> NUM_4);
    } else {
        uint8_t alpha = static_cast<uint8_t>(UINT2_MAX * percent + HALF_ONE);
        src[alphaIndex] = static_cast<uint8_t>((src[alphaIndex] & 0x3F) | (alpha << NUM_6));
    }
}

static int8_t GetAlphaIndex(const PixelFormat& pixelFormat)
{
    switch (pixelFormat) {
        case PixelFormat::ARGB_8888:
        case PixelFormat::ALPHA_8:
        case PixelFormat::ALPHA_U8:
        case PixelFormat::ALPHA_F16:
            return ARGB_ALPHA_INDEX;
        case PixelFormat::RGBA_8888:
        case PixelFormat::BGRA_8888:
        case PixelFormat::RGBA_F16:
        case PixelFormat::RGBA_1010102:
            return BGRA_ALPHA_INDEX;
        default:
            return INVALID_ALPHA_INDEX;
    }
}

static void ConvertUintPixelAlpha(uint8_t *rpixel,
    uint8_t pixelByte, int8_t alphaIndex, bool isPremul, uint8_t *wpixel)
{
    if (rpixel == nullptr || wpixel == nullptr) {
        IMAGE_LOGE("ConvertUintPixelAlpha invalid input parameter: rpixel or wpixel is null");
        return;
    }

    float alphaValue = static_cast<float>(rpixel[alphaIndex]) / UINT8_MAX;
    for (int32_t pixelIndex = 0; pixelIndex < pixelByte; pixelIndex++) {
        float pixelValue = static_cast<float>(rpixel[pixelIndex]);
        if (pixelIndex != alphaIndex) {
            float nPixel;
            if (isPremul) {
                nPixel = pixelValue * alphaValue;
            } else {
                nPixel = (alphaValue > 0) ? pixelValue / alphaValue : 0;
            }
            wpixel[pixelIndex] = static_cast<uint8_t>(nPixel + HALF_ONE);
        } else {
            wpixel[pixelIndex] = rpixel[pixelIndex];
        }
    }
}

static bool IsValidAlphaPixelBytes(PixelFormat pixelFormat, int32_t pixelBytes)
{
    if (ImageUtils::IsAlpha8(pixelFormat)) {
        return pixelBytes == ALPHA_BYTES;
    }
    if (pixelFormat == PixelFormat::ALPHA_F16) {
        return pixelBytes == ALPHA_F16_BYTES;
    }
    return true;
}

uint32_t PixelMap::CheckAlphaFormatInput(PixelMap &wPixelMap, const bool isPremul)
{
    ImageInfo dstImageInfo;
    wPixelMap.GetImageInfo(dstImageInfo);
    uint32_t dstPixelSize = wPixelMap.GetCapacity();
    int32_t dstPixelBytes = wPixelMap.GetPixelBytes();
    void* dstData = wPixelMap.GetWritablePixels();
    int32_t stride = wPixelMap.GetRowStride();

    if (isUnMap_ || dstData == nullptr || data_ == nullptr) {
        IMAGE_LOGE("read pixels by dstPixelMap or srcPixelMap data is null, isUnMap %{public}d.", isUnMap_);
        return ERR_IMAGE_READ_PIXELMAP_FAILED;
    }
    if (!((GetAlphaType() == AlphaType::IMAGE_ALPHA_TYPE_PREMUL && !isPremul) ||
        (GetAlphaType() == AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL && isPremul))) {
        IMAGE_LOGE("alpha type error");
        return COMMON_ERR_INVALID_PARAMETER;
    }
    if (imageInfo_.size.height != dstImageInfo.size.height || imageInfo_.size.width != dstImageInfo.size.width) {
        IMAGE_LOGE("dstPixelMap size mismtach srcPixelMap");
        return COMMON_ERR_INVALID_PARAMETER;
    }
    if (stride != GetRowStride() || dstPixelSize < pixelsSize_) {
        IMAGE_LOGE("stride or pixelsSize from dstPixelMap mismtach srcPixelMap");
        return COMMON_ERR_INVALID_PARAMETER;
    }

    PixelFormat srcFormat = GetPixelFormat();
    PixelFormat dstFormat = dstImageInfo.pixelFormat;
    if (srcFormat == PixelFormat::ALPHA_F16 && dstFormat == PixelFormat::ALPHA_F16) {
        if (pixelBytes_ != ALPHA_F16_BYTES || dstPixelBytes != ALPHA_F16_BYTES) {
            IMAGE_LOGE("Pixel format %{public}s and %{public}s mismatch pixelByte %{public}d and %{public}d",
                GetNamedPixelFormat(srcFormat).c_str(), GetNamedPixelFormat(dstFormat).c_str(), pixelBytes_,
                dstPixelBytes);
            return COMMON_ERR_INVALID_PARAMETER;
        }
        return SUCCESS;
    }
    int8_t srcAlphaIndex = GetAlphaIndex(srcFormat);
    int8_t dstAlphaIndex = GetAlphaIndex(dstFormat);
    if (srcFormat != dstFormat || srcAlphaIndex == INVALID_ALPHA_INDEX || srcFormat == PixelFormat::RGBA_F16 ||
        dstAlphaIndex == INVALID_ALPHA_INDEX || dstFormat == PixelFormat::RGBA_F16) {
        IMAGE_LOGE("Could not perform premultiply or nonpremultiply from %{public}s to %{public}s",
            GetNamedPixelFormat(srcFormat).c_str(), GetNamedPixelFormat(dstFormat).c_str());
        return ERR_IMAGE_DATA_UNSUPPORT;
    }

    if (!IsValidAlphaPixelBytes(srcFormat, pixelBytes_) || !IsValidAlphaPixelBytes(dstFormat, dstPixelBytes)) {
        IMAGE_LOGE("Pixel format %{public}s and %{public}s mismatch pixelByte %{public}d and %{public}d",
            GetNamedPixelFormat(srcFormat).c_str(), GetNamedPixelFormat(dstFormat).c_str(), pixelBytes_, dstPixelBytes);
        return COMMON_ERR_INVALID_PARAMETER;
    }
    return SUCCESS;
}

bool PixelMap::AttachAddrBySurfaceBuffer()
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (data_ == nullptr && displayOnly_ && context_ != nullptr &&
        allocatorType_ == AllocatorType::DMA_ALLOC) {
        SurfaceBuffer* sb = static_cast<SurfaceBuffer*>(context_);
        if (sb == nullptr) {
            IMAGE_LOGE("Get surface buffer failed");
            return false;
        }
        data_ = static_cast<uint8_t*>(sb->GetVirAddr());
        if (data_ == nullptr) {
            IMAGE_LOGE("Get vir addr failed");
            return false;
        }
    }
#endif
    return true;
}

uint32_t PixelMap::ConvertAlphaFormat(PixelMap &wPixelMap, const bool isPremul)
{
    uint32_t res = CheckAlphaFormatInput(wPixelMap, isPremul);
    if (res != SUCCESS) {
        return res;
    }
    if (IsAstcOrY8Format()) {
        IMAGE_LOGE("ConvertAlphaFormat does not support astc or Y8");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    ImageInfo dstImageInfo;
    wPixelMap.GetImageInfo(dstImageInfo);
    void* dstData = wPixelMap.GetWritablePixels();
    int32_t stride = wPixelMap.GetRowStride();

    PixelFormat srcPixelFormat = GetPixelFormat();
    if (srcPixelFormat == PixelFormat::ALPHA_F16) {
        for (int32_t i = 0; i < imageInfo_.size.height; ++i) {
            errno_t ret = memcpy_s(static_cast<uint8_t *>(dstData) + i * stride, stride,
                data_ + i * GetRowStride(), GetRowStride());
            if (ret != 0) {
                IMAGE_LOGE("ConvertAlphaFormat memcpy for alpha_f16 failed, error:%{public}d", ret);
                return ERR_IMAGE_READ_PIXELMAP_FAILED;
            }
        }
        wPixelMap.SetAlphaType(isPremul ? AlphaType::IMAGE_ALPHA_TYPE_PREMUL : AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
        return SUCCESS;
    }
    int8_t srcAlphaIndex = GetAlphaIndex(srcPixelFormat);
    int32_t index = 0;
    for (int32_t i = 0; i < imageInfo_.size.height; ++i) {
        for (int32_t j = 0; j < stride; j+=pixelBytes_) {
            index = i * stride + j;
            ConvertUintPixelAlpha(data_ + index, pixelBytes_, srcAlphaIndex, isPremul,
                static_cast<uint8_t*>(dstData) + index);
        }
    }
    if (isPremul == true) {
        wPixelMap.SetAlphaType(AlphaType::IMAGE_ALPHA_TYPE_PREMUL);
    } else {
        wPixelMap.SetAlphaType(AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
    }
    return SUCCESS;
}

static uint32_t ValidateSetAlpha(float percent, bool modifiable, AlphaType alphaType)
{
    if (!modifiable) {
        IMAGE_LOGE("[PixelMap] SetAlpha can't be performed: PixelMap is not modifiable");
        return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY;
    }
    if (alphaType == AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN || alphaType == AlphaType::IMAGE_ALPHA_TYPE_OPAQUE) {
        IMAGE_LOGE("[PixelMap] SetAlpha could not set alpha on %{public}s", GetNamedAlphaType(alphaType).c_str());
        return ERR_IMAGE_DATA_UNSUPPORT;
    }
    if (percent <= 0 || percent > 1) {
        IMAGE_LOGE("[PixelMap] SetAlpha input should satisfy (0 < input <= 1). Current input is %{public}f", percent);
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    return SUCCESS;
}

uint32_t PixelMap::SetAlpha(const float percent)
{
    auto alphaType = GetAlphaType();
    uint32_t retCode = ValidateSetAlpha(percent, modifiable_, alphaType);
    if (retCode != SUCCESS) {
        return retCode;
    }

    bool isPixelPremul = alphaType == AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
    auto pixelFormat = GetPixelFormat();
    int32_t pixelsSize = GetByteCount();
    if (pixelsSize <= 0) {
        IMAGE_LOGE("Invalid byte count: %{public}d", pixelsSize);
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    int8_t alphaIndex = GetAlphaIndex(pixelFormat);
    if (isUnMap_ || alphaIndex == INVALID_ALPHA_INDEX) {
        IMAGE_LOGE("Could not set alpha on %{public}s, isUnMap %{public}d",
            GetNamedPixelFormat(pixelFormat).c_str(), isUnMap_);
        return ERR_IMAGE_DATA_UNSUPPORT;
    }

    if ((ImageUtils::IsAlpha8(pixelFormat) && pixelBytes_ != ALPHA_BYTES) ||
        (pixelFormat == PixelFormat::ALPHA_F16 && pixelBytes_ != ALPHA_F16_BYTES) ||
        (pixelFormat == PixelFormat::RGBA_F16 && pixelBytes_ != RGBA_F16_BYTES)) {
        IMAGE_LOGE("Pixel format %{public}s mismatch pixelByte %{public}d",
            GetNamedPixelFormat(pixelFormat).c_str(), pixelBytes_);
        return ERR_IMAGE_INVALID_PARAMETER;
    }

    for (int i = 0; i < GetHeight(); i++) {
        for (int j = 0; j < rowDataSize_; j += pixelBytes_) {
            uint8_t* pixel = data_ + GetRowStride() * i + j;
            if (pixelFormat == PixelFormat::ALPHA_F16) {
                HalfTranslate(percent, pixel);
            } else if (pixelFormat == PixelFormat::RGBA_F16) {
                SetF16PixelAlpha(pixel, percent, isPixelPremul);
            } else if (pixelFormat == PixelFormat::RGBA_1010102) {
                SetRGBA1010102PixelAlpha(pixel, percent, alphaIndex, isPixelPremul);
            } else {
                SetUintPixelAlpha(pixel, percent, pixelBytes_, alphaIndex, isPixelPremul);
            }
        }
    }
    return SUCCESS;
}

static sk_sp<SkColorSpace> ToSkColorSpace(PixelMap *pixelmap)
{
#ifdef IMAGE_COLORSPACE_FLAG
    if (pixelmap == nullptr) {
        IMAGE_LOGE("ToSkColorSpace invalid input parameter: pixelmap is null");
        return nullptr;
    }
    if (pixelmap->InnerGetGrColorSpacePtr() == nullptr) {
        return nullptr;
    }
    return pixelmap->InnerGetGrColorSpacePtr()->ToSkColorSpace();
#else
    return nullptr;
#endif
}

static SkImageInfo ToSkImageInfo(ImageInfo &info, sk_sp<SkColorSpace> colorSpace)
{
    SkColorType colorType = ImageTypeConverter::ToSkColorType(info.pixelFormat);
    SkAlphaType alphaType = ImageTypeConverter::ToSkAlphaType(info.alphaType);
    IMAGE_LOGD("ToSkImageInfo w %{public}d, h %{public}d", info.size.width, info.size.height);
    IMAGE_LOGD(
        "ToSkImageInfo pf %{public}s, at %{public}s, skpf %{public}s, skat %{public}s",
        ImageTypeConverter::ToName(info.pixelFormat).c_str(),
        ImageTypeConverter::ToName(info.alphaType).c_str(),
        ImageTypeConverter::ToName(colorType).c_str(),
        ImageTypeConverter::ToName(alphaType).c_str()
    );
    return SkImageInfo::Make(info.size.width, info.size.height, colorType, alphaType, colorSpace);
}

static void ToImageInfo(ImageInfo &info, SkImageInfo &skInfo, bool sizeOnly = true)
{
    info.size.width = skInfo.width();
    info.size.height = skInfo.height();
    if (!sizeOnly) {
        info.alphaType = ImageTypeConverter::ToAlphaType(skInfo.alphaType());
        info.pixelFormat = ImageTypeConverter::ToPixelFormat(skInfo.colorType());
    }
}

struct SkTransInfo {
    SkRect r;
    SkImageInfo info;
    SkBitmap bitmap;
};

struct TransMemoryInfo {
    AllocatorType allocType;
    std::unique_ptr<AbsMemory> memory = nullptr;
};

constexpr float HALF = 0.5f;

static inline int FloatToInt(float a)
{
    return static_cast<int>(a + HALF);
}

#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
static void GenSrcTransInfo(SkTransInfo &srcInfo, ImageInfo &imageInfo, PixelMap* pixelmap,
    sk_sp<SkColorSpace> colorSpace)
{
    srcInfo.r = SkRect::MakeIWH(imageInfo.size.width, imageInfo.size.height);
    srcInfo.info = ToSkImageInfo(imageInfo, colorSpace);
    uint64_t rowStride = srcInfo.info.minRowBytes();
    if (pixelmap->GetAllocatorType() == AllocatorType::DMA_ALLOC) {
        if (pixelmap->GetFd() == nullptr) {
            IMAGE_LOGE("GenSrcTransInfo get surfacebuffer failed");
            return;
        }
        SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(pixelmap->GetFd());
        rowStride = static_cast<uint64_t>(sbBuffer->GetStride());
    }
    srcInfo.bitmap.installPixels(srcInfo.info, static_cast<uint8_t *>(pixelmap->GetWritablePixels()), rowStride);
}
#endif
static void GenSrcTransInfo(SkTransInfo &srcInfo, ImageInfo &imageInfo, uint8_t* pixels,
    sk_sp<SkColorSpace> colorSpace)
{
    srcInfo.r = SkRect::MakeIWH(imageInfo.size.width, imageInfo.size.height);
    srcInfo.info = ToSkImageInfo(imageInfo, colorSpace);
    srcInfo.bitmap.installPixels(srcInfo.info, pixels, srcInfo.info.minRowBytes());
}

static bool GenDstTransInfo(SkTransInfo &srcInfo, SkTransInfo &dstInfo, SkMatrix &matrix,
    TransMemoryInfo &memoryInfo, uint64_t usage)
{
    dstInfo.r = matrix.mapRect(srcInfo.r);
    int width = FloatToInt(dstInfo.r.width());
    int height = FloatToInt(dstInfo.r.height());
    if (matrix.isTranslate()) {
        width += dstInfo.r.fLeft;
        height += dstInfo.r.fTop;
    }
    dstInfo.info = srcInfo.info.makeWH(width, height);
    PixelFormat format = ImageTypeConverter::ToPixelFormat(srcInfo.info.colorType());
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    Size desiredSize = {dstInfo.info.width(), dstInfo.info.height()};
    MemoryData memoryData = {nullptr, dstInfo.info.computeMinByteSize(), "Trans ImageData", desiredSize, format};
    memoryData.usage = usage;
#else
    MemoryData memoryData = {nullptr, dstInfo.info.computeMinByteSize(), "Trans ImageData"};
    memoryData.format = format;
#endif
    std::unique_ptr<AbsMemory> dstMemory = MemoryManager::CreateMemory(memoryInfo.allocType, memoryData);
    if (dstMemory == nullptr) {
        IMAGE_LOGE("CreateMemory falied");
        return false;
    }
    memoryInfo.memory = std::move(dstMemory);
    if (memoryInfo.memory == nullptr) {
        return false;
    }
    if (memset_s(memoryInfo.memory->data.data, memoryInfo.memory->data.size,
        0, memoryInfo.memory->data.size) != 0) {
        memoryInfo.memory->Release();
        return false;
    }
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    uint64_t rowStride = dstInfo.info.minRowBytes();
    if (memoryInfo.allocType == AllocatorType::DMA_ALLOC) {
        if (memoryInfo.memory->extend.data == nullptr) {
            IMAGE_LOGE("GenDstTransInfo get surfacebuffer failed");
            return false;
        }
        SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(memoryInfo.memory->extend.data);
        rowStride = static_cast<uint64_t>(sbBuffer->GetStride());
    }
    dstInfo.bitmap.installPixels(dstInfo.info, memoryInfo.memory->data.data, rowStride);
#else
    dstInfo.bitmap.installPixels(dstInfo.info, memoryInfo.memory->data.data, dstInfo.info.minRowBytes());
#endif
    return true;
}

struct TransInfos {
    SkMatrix matrix;
};

SkSamplingOptions ToSkSamplingOption(const AntiAliasingOption &option)
{
    switch (option) {
        case AntiAliasingOption::NONE: return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
        case AntiAliasingOption::LOW: return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
        case AntiAliasingOption::MEDIUM: return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
        case AntiAliasingOption::HIGH: return SkSamplingOptions(SkCubicResampler { 1 / 3.0f, 1 / 3.0f });
        default: return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
    }
}

void DrawImage(bool rectStaysRect, const AntiAliasingOption &option, SkCanvas &canvas, sk_sp<SkImage> &skImage)
{
    if (rectStaysRect) {
        SkRect skrect = SkRect::MakeXYWH(0, 0, skImage->width(), skImage->height());
        SkPaint paint;
        paint.setAntiAlias(true);
        canvas.drawImageRect(skImage, skrect, ToSkSamplingOption(option), &paint);
    } else {
        canvas.drawImage(skImage, FLOAT_ZERO, FLOAT_ZERO, ToSkSamplingOption(option));
    }
}

uint32_t PixelMap::ApplyAffineTransform(TransInfos &infos, AntiAliasingOption option)
{
    if (!modifiable_) {
        IMAGE_LOGE("[ApplyAffineTransform] PixelMap is not modifiable");
        return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY;
    }

    std::lock_guard<std::mutex> lock(*translationMutex_);
    ImageInfo imageInfo;
    GetImageInfo(imageInfo);
    IMAGE_LOGD("[%{public}s] width = %{public}d, height = %{public}d, pixelFormat = %{public}d, alphaType = %{public}d",
        __func__, imageInfo.size.width, imageInfo.size.height, imageInfo.pixelFormat, imageInfo.alphaType);
    TransMemoryInfo dstMemory;
    // We don't know how custom alloc memory
    dstMemory.allocType = (allocatorType_ == AllocatorType::CUSTOM_ALLOC) ? AllocatorType::DEFAULT : allocatorType_;
    SkTransInfo src;
    std::unique_ptr<uint8_t[]> rgbxPixels = nullptr;
    if (imageInfo.pixelFormat == PixelFormat::RGB_888) {
        // Need this conversion because Skia uses 32-byte RGBX instead of 24-byte RGB when processing transforms
        if (!ExpandRGBToRGBX(data_, GetByteCount(), rgbxPixels)) {
            return ERR_IMAGE_COLOR_CONVERT;
        }
        GenSrcTransInfo(src, imageInfo, rgbxPixels.get(), ToSkColorSpace(this));
    } else {
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
        GenSrcTransInfo(src, imageInfo, this, ToSkColorSpace(this));
#else
        if (isUnMap_) {
            IMAGE_LOGE("[ApplyAffineTransform] Transform failed, isUnMap %{public}d", isUnMap_);
            return ERR_IMAGE_DATA_UNSUPPORT;
        }
        GenSrcTransInfo(src, imageInfo, data_, ToSkColorSpace(this));
#endif
    }

    SkTransInfo dst;
    if (!GenDstTransInfo(src, dst, infos.matrix, dstMemory, GetNoPaddingUsage())) {
        IMAGE_LOGE("[ApplyAffineTransform] GenDstTransInfo dstMemory failed");
        return ERR_IMAGE_MALLOC_ABNORMAL;
    }
    SkCanvas canvas(dst.bitmap);
    if (!infos.matrix.isTranslate() && (!EQUAL_TO_ZERO(dst.r.fLeft) || !EQUAL_TO_ZERO(dst.r.fTop))) {
        canvas.translate(-dst.r.fLeft, -dst.r.fTop);
    }
    canvas.concat(infos.matrix);
    src.bitmap.setImmutable();
#ifdef USE_M133_SKIA
    auto skimage = SkImages::RasterFromBitmap(src.bitmap);
#else
    auto skimage = SkImage::MakeFromBitmap(src.bitmap);
#endif
    if (skimage == nullptr) {
#ifdef USE_M133_SKIA
        IMAGE_LOGE("[ApplyAffineTransform] RasterFromBitmap failed with nullptr");
#else
        IMAGE_LOGE("[ApplyAffineTransform] MakeFromBitmap failed with nullptr");
#endif
        dstMemory.memory->Release();
        return ERR_IMAGE_TRANSFORM;
    }
    DrawImage(infos.matrix.rectStaysRect(), option, canvas, skimage);
    ToImageInfo(imageInfo, dst.info);
    auto m = dstMemory.memory.get();
    CopySurfaceBufferInfo(m->extend.data);

    std::unique_ptr<AbsMemory> shrinkedMemory = nullptr;
    if (imageInfo.pixelFormat == PixelFormat::RGB_888) {
        if (!ShrinkRGBXToRGB(dstMemory.memory, shrinkedMemory)) {
            dstMemory.memory->Release();
            return ERR_IMAGE_COLOR_CONVERT;
        }
        dstMemory.memory->Release();
        m = shrinkedMemory.get();
    }

    SetPixelsAddr(m->data.data, m->extend.data, m->data.size, m->GetType(), nullptr);
    SetImageInfo(imageInfo, true);
    ImageUtils::FlushSurfaceBuffer(this);
    return SUCCESS;
}

void PixelMap::scale(float xAxis, float yAxis)
{
    ImageTrace imageTrace("PixelMap scale xAxis = %f, yAxis = %f", xAxis, yAxis);
    if (imageInfo_.pixelFormat == PixelFormat::Y8) {
        IMAGE_LOGE("scale does not support Y8");
        return;
    }
    if ((static_cast<int32_t>(round(imageInfo_.size.width * xAxis)) - imageInfo_.size.width) == 0 &&
        (static_cast<int32_t>(round(imageInfo_.size.height * yAxis)) - imageInfo_.size.height) == 0) {
        return;
    }
    TransInfos infos;
    infos.matrix.setScale(xAxis, yAxis);
    if (ApplyAffineTransform(infos) != SUCCESS) {
        IMAGE_LOGE("scale failed");
        return;
    }
    ImageUtils::DumpPixelMapIfDumpEnabled(*this, __func__);
}

void PixelMap::scale(float xAxis, float yAxis, const AntiAliasingOption &option)
{
    Scale(xAxis, yAxis, option);
}

uint32_t PixelMap::Scale(float xAxis, float yAxis, AntiAliasingOption option)
{
    if (xAxis == 0 || yAxis == 0) {
        IMAGE_LOGE("Invalid scale ratio: 0");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    if ((static_cast<int32_t>(round(imageInfo_.size.width * xAxis)) - imageInfo_.size.width) == 0 &&
        (static_cast<int32_t>(round(imageInfo_.size.height * yAxis)) - imageInfo_.size.height) == 0) {
        return SUCCESS;
    }
    if (IsAstcOrY8Format()) {
        IMAGE_LOGE("Scale does not support astc or Y8");
        return ERR_IMAGE_DATA_UNSUPPORT;
    }

    ImageTrace imageTrace("PixelMap scale xAxis = %f, yAxis = %f, option = %d", xAxis, yAxis, option);
    if (imageInfo_.pixelFormat == PixelFormat::ALPHA_F16 && option == AntiAliasingOption::SLR) {
        option = AntiAliasingOption::HIGH;
    }
    if (option == AntiAliasingOption::SLR) {
        uint32_t errCode = ScaleWithSLR(xAxis, yAxis);
        if (errCode != SUCCESS) {
            return errCode;
        }
    } else {
        TransInfos infos;
        infos.matrix.setScale(xAxis, yAxis);
        uint32_t errCode = ApplyAffineTransform(infos, option);
        if (errCode != SUCCESS) {
            IMAGE_LOGE("Scale failed");
            return errCode;
        }
    }
    ImageUtils::DumpPixelMapIfDumpEnabled(*this, __func__);
    return SUCCESS;
}

uint32_t PixelMap::ScaleWithSLR(float xAxis, float yAxis)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (!modifiable_) {
        IMAGE_LOGE("[PixelMap] scale can't be performed: PixelMap is not modifiable");
        return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY;
    }
    auto start = std::chrono::high_resolution_clock::now();
    ImageInfo tmpInfo;
    GetImageInfo(tmpInfo);
    Size desiredSize;
    desiredSize.width = static_cast<int32_t>(imageInfo_.size.width * xAxis);
    desiredSize.height = static_cast<int32_t>(imageInfo_.size.height * yAxis);

    PostProc postProc;
    if (!postProc.ScalePixelMapWithSLR(desiredSize, *this)) {
        IMAGE_LOGE("PixelMap::scale with SLR failed");
        return ERR_IMAGE_TRANSFORM;
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    IMAGE_LOGI("PixelMap::scale with SLR %{public}d, srcSize: [%{public}d, %{public}d], "
        "dstSize: [%{public}d, %{public}d], cost: %{public}llu",
        uniqueId_, tmpInfo.size.width, tmpInfo.size.height, desiredSize.width, desiredSize.height, duration.count());
    return SUCCESS;
#else
    IMAGE_LOGE("Scale with SLR is not supported on this platform");
    return ERR_MEDIA_UNSUPPORT_OPERATION;
#endif
}

bool PixelMap::resize(float xAxis, float yAxis)
{
    if (IsYUV(imageInfo_.pixelFormat)) {
        IMAGE_LOGE("resize temp disabled for YUV data");
        return true;
    }
    ImageTrace imageTrace("PixelMap resize");
    TransInfos infos;
    infos.matrix.setScale(xAxis, yAxis);
    if (ApplyAffineTransform(infos) != SUCCESS) {
        IMAGE_LOGE("resize falied");
        return false;
    }
    ImageUtils::DumpPixelMapIfDumpEnabled(*this, __func__);
    return true;
}

void PixelMap::translate(float xAxis, float yAxis)
{
    Translate(xAxis, yAxis);
}

uint32_t PixelMap::Translate(float xAxis, float yAxis)
{
    if (imageInfo_.pixelFormat == PixelFormat::Y8) {
        IMAGE_LOGE("Translate does not support Y8");
        return ERR_IMAGE_DATA_UNSUPPORT;
    }
    ImageTrace imageTrace("PixelMap translate xAxis = %f, yAxis = %f", xAxis, yAxis);
    TransInfos infos;
    infos.matrix.setTranslate(xAxis, yAxis);
    uint32_t errCode = ApplyAffineTransform(infos);
    if (errCode != SUCCESS) {
        IMAGE_LOGE("Translate failed");
        return errCode;
    }
    ImageUtils::DumpPixelMapIfDumpEnabled(*this, __func__);
    return SUCCESS;
}

void PixelMap::rotate(float degrees)
{
    Rotate(degrees);
}

uint32_t PixelMap::Rotate(float degrees)
{
    if (ImageUtils::FloatEqual(degrees, 0.0f)) {
        return SUCCESS;
    }
    if (imageInfo_.pixelFormat == PixelFormat::Y8) {
        IMAGE_LOGE("Rotate does not support Y8");
        return ERR_IMAGE_DATA_UNSUPPORT;
    }
    ImageTrace imageTrace("PixelMap rotate degrees = %f", degrees);
    TransInfos infos;
    infos.matrix.setRotate(degrees);
    uint32_t errCode = ApplyAffineTransform(infos);
    if (errCode != SUCCESS) {
        IMAGE_LOGE("rotate failed");
        return errCode;
    }
    ImageUtils::DumpPixelMapIfDumpEnabled(*this, __func__);
    return SUCCESS;
}

void PixelMap::flip(bool xAxis, bool yAxis)
{
    Flip(xAxis, yAxis);
}

uint32_t PixelMap::Flip(bool xAxis, bool yAxis)
{
    ImageTrace imageTrace("PixelMap flip");
    if (xAxis == false && yAxis == false) {
        return SUCCESS;
    }
    if (imageInfo_.pixelFormat == PixelFormat::Y8) {
        IMAGE_LOGE("Flip does not support Y8");
        return ERR_IMAGE_DATA_UNSUPPORT;
    }
    return Scale(xAxis ? -1 : 1, yAxis ? -1 : 1, AntiAliasingOption::NONE);
}

void PixelMap::CopySurfaceBufferInfo(void *data)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (allocatorType_ != AllocatorType::DMA_ALLOC) {
        return;
    }
    if (data == nullptr) {
        IMAGE_LOGE("CopySurfaceBufferInfo failed, data is nullptr");
        return;
    }
    if (GetFd() == nullptr) {
        IMAGE_LOGE("CopySurfaceBufferInfo failed: source surfacebuffer is nullptr");
        return;
    }
    sptr<SurfaceBuffer> sourceSurfaceBuffer(static_cast<SurfaceBuffer*>(GetFd()));
    sptr<SurfaceBuffer> dstSurfaceBuffer(static_cast<SurfaceBuffer*>(data));
    VpeUtils::CopySurfaceBufferInfo(sourceSurfaceBuffer, dstSurfaceBuffer);
#endif
}

uint32_t PixelMap::crop(const Rect &rect)
{
    if (Crop(rect) != SUCCESS) {
        return ERR_IMAGE_CROP;
    }
    return SUCCESS;
}

uint32_t PixelMap::Crop(const Rect &rect)
{
    if (!modifiable_) {
        IMAGE_LOGE("[PixelMap] crop can't be performed: PixelMap is not modifiable");
        return ERR_IMAGE_PIXELMAP_NOT_ALLOW_MODIFY;
    }
    if (imageInfo_.pixelFormat == PixelFormat::Y8) {
        IMAGE_LOGE("Crop does not support Y8");
        return ERR_IMAGE_DATA_UNSUPPORT;
    }
    ImageTrace imageTrace("PixelMap crop");
    ImageInfo imageInfo;
    GetImageInfo(imageInfo);
    SkTransInfo src;

    if (imageInfo.pixelFormat == PixelFormat::RGB_888) {
        // Need this conversion because Skia uses 32-byte RGBX instead of 24-byte RGB when processing crops
        std::unique_ptr<uint8_t[]> rgbxPixels = nullptr;
        if (!ExpandRGBToRGBX(data_, GetByteCount(), rgbxPixels)) {
            return ERR_IMAGE_COLOR_CONVERT;
        }
        GenSrcTransInfo(src, imageInfo, rgbxPixels.get(), ToSkColorSpace(this));
    } else {
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
        GenSrcTransInfo(src, imageInfo, this, ToSkColorSpace(this));
#else
        if (isUnMap_) {
            IMAGE_LOGE("PixelMap::crop falied, isUnMap %{public}d", isUnMap_);
            return ERR_IMAGE_DATA_UNSUPPORT;
        }
        GenSrcTransInfo(src, imageInfo, data_, ToSkColorSpace(this));
#endif
    }

    SkTransInfo dst;
    SkIRect dstIRect = SkIRect::MakeXYWH(rect.left, rect.top, rect.width, rect.height);
    dst.r = SkRect::Make(dstIRect);
    if (dst.r == src.r) {
        return SUCCESS;
    }

    if (!src.r.contains(dst.r)) {
        IMAGE_LOGE("Invalid crop rect");
        return ERR_IMAGE_INVALID_PARAMETER;
    }
    dst.info = src.info.makeWH(dstIRect.width(), dstIRect.height());
    Size desiredSize = {dst.info.width(), dst.info.height()};
    MemoryData memoryData = {nullptr, dst.info.computeMinByteSize(), "Trans ImageData", desiredSize,
                             imageInfo.pixelFormat};
    memoryData.usage = GetNoPaddingUsage();
    auto dstMemory = MemoryManager::CreateMemory(allocatorType_, memoryData);
    if (dstMemory == nullptr || dstMemory->data.data == nullptr) {
        return ERR_IMAGE_MALLOC_ABNORMAL;
    }
    uint64_t rowStride = dst.info.minRowBytes();
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (allocatorType_ == AllocatorType::DMA_ALLOC) {
        if (dstMemory->extend.data == nullptr) {
            IMAGE_LOGE("GenDstTransInfo get surfacebuffer failed");
            return ERR_IMAGE_MALLOC_ABNORMAL;
        }
        rowStride = static_cast<uint64_t>(static_cast<SurfaceBuffer*>(dstMemory->extend.data)->GetStride());
    }
#endif
    if (!src.bitmap.readPixels(dst.info, dstMemory->data.data, rowStride, dstIRect.fLeft, dstIRect.fTop)) {
        dstMemory->Release();
        IMAGE_LOGE("ReadPixels failed");
        return ERR_IMAGE_CROP;
    }
    ToImageInfo(imageInfo, dst.info);
    CopySurfaceBufferInfo(dstMemory->extend.data);

    auto m = dstMemory.get();
    std::unique_ptr<AbsMemory> shrinkedMemory = nullptr;
    if (imageInfo.pixelFormat == PixelFormat::RGB_888) {
        if (!ShrinkRGBXToRGB(dstMemory, shrinkedMemory)) {
            dstMemory->Release();
            return ERR_IMAGE_COLOR_CONVERT;
        }
        dstMemory->Release();
        m = shrinkedMemory.get();
    }

    SetPixelsAddr(m->data.data, m->extend.data, m->data.size, m->GetType(), nullptr);
    SetImageInfo(imageInfo, true);
#if !defined(CROSS_PLATFORM)
    ImageUtils::UpdateYUVDataInfo(*this);
#endif
    ImageUtils::FlushSurfaceBuffer(this);
    ImageUtils::DumpPixelMapIfDumpEnabled(*this, __func__);
    return SUCCESS;
}

#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
static bool DecomposeImage(sptr<SurfaceBuffer>& hdr, sptr<SurfaceBuffer>& sdr, bool isSRGB = false)
{
    ImageTrace imageTrace("PixelMap decomposeImage");
    if (hdr == nullptr || sdr == nullptr) {
        IMAGE_LOGE("hdr or sdr is empty");
        return false;
    }
    VpeUtils::SetSbMetadataType(hdr, HDI::Display::Graphic::Common::V1_0::CM_IMAGE_HDR_VIVID_SINGLE);
    VpeUtils::SetSbMetadataType(sdr, HDI::Display::Graphic::Common::V1_0::CM_IMAGE_HDR_VIVID_DUAL);
    VpeUtils::SetSbColorSpaceType(sdr,
        isSRGB ? HDI::Display::Graphic::Common::V1_0::CM_SRGB_FULL : HDI::Display::Graphic::Common::V1_0::CM_P3_FULL);
    std::unique_ptr<VpeUtils> utils = std::make_unique<VpeUtils>();
    int32_t res = utils->ColorSpaceConverterImageProcess(hdr, sdr);
    if (res != VPE_ERROR_OK || sdr == nullptr) {
        return false;
    }
    return true;
}
#endif

void PixelMap::SetToSdrColorSpaceIsSRGB(bool isSRGB)
{
    toSdrColorIsSRGB_ = isSRGB;
}

bool PixelMap::GetToSdrColorSpaceIsSRGB()
{
    return toSdrColorIsSRGB_;
}

std::unique_ptr<AbsMemory> PixelMap::CreateSdrMemory(ImageInfo &imageInfo, PixelFormat format,
                                                     AllocatorType dstType, uint32_t &errorCode, bool toSRGB)
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    PixelFormat outFormat = format;
    if (format != PixelFormat::NV12 && format != PixelFormat::NV21 && format != PixelFormat::RGBA_8888) {
        outFormat = PixelFormat::RGBA_8888;
    }

    ImageInfo outImageInfo = {imageInfo.size, outFormat};
    int32_t dataSize = GetAllocatedByteCount(outImageInfo);
    if (dataSize <= 0) {
        IMAGE_LOGI("sdr memory get dataSize failed.");
        errorCode = IMAGE_RESULT_GET_SURFAC_FAILED;
        return nullptr;
    }
    MemoryData sdrData = {nullptr, static_cast<size_t>(dataSize), "Trans ImageData", imageInfo.size, outFormat};
    auto sdrMemory = MemoryManager::CreateMemory(dstType, sdrData);
    if (sdrMemory == nullptr) {
        IMAGE_LOGI("sdr memory alloc failed.");
        errorCode = IMAGE_RESULT_GET_SURFAC_FAILED;
        return nullptr;
    }
    sptr<SurfaceBuffer> hdrSurfaceBuffer(static_cast<SurfaceBuffer*> (GetFd()));
    sptr<SurfaceBuffer> sdrSurfaceBuffer(static_cast<SurfaceBuffer*>(sdrMemory->extend.data));
    HDI::Display::Graphic::Common::V1_0::CM_ColorSpaceType colorspaceType;
    VpeUtils::GetSbColorSpaceType(hdrSurfaceBuffer, colorspaceType);
    if ((static_cast<uint32_t>(colorspaceType) & HDI::Display::Graphic::Common::V1_0::CM_PRIMARIES_MASK) !=
        HDI::Display::Graphic::Common::V1_0::COLORPRIMARIES_BT2020) {
#ifdef IMAGE_COLORSPACE_FLAG
        colorspaceType = ColorUtils::ConvertToCMColor(InnerGetGrColorSpace().GetColorSpaceName());
        VpeUtils::SetSbColorSpaceType(hdrSurfaceBuffer, colorspaceType);
#endif
    }
    ImageUtils::DumpHdrBufferEnabled(hdrSurfaceBuffer, "decompose-HDR");
    if (!DecomposeImage(hdrSurfaceBuffer, sdrSurfaceBuffer, toSRGB)) {
        sdrMemory->Release();
        IMAGE_LOGE("HDR-IMAGE ToSdr decompose failed, CM_ColorType : %{public}d",
            static_cast<uint32_t>(colorspaceType));
        errorCode = IMAGE_RESULT_GET_SURFAC_FAILED;
        return nullptr;
    }
    ImageUtils::DumpHdrBufferEnabled(sdrSurfaceBuffer, "decompose-SDR");
    errorCode = SUCCESS;
    return sdrMemory;
#else
    errorCode = ERR_MEDIA_INVALID_OPERATION;
    return nullptr;
#endif
}

bool PixelMap::UnMap()
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    if (allocatorType_ != AllocatorType::SHARE_MEM_ALLOC) {
        return false;
    }
    std::lock_guard<std::mutex> lock(*unmapMutex_);
    if (!isUnMap_ && useCount_ == 1) {
        isUnMap_ = true;
        if (data_ != nullptr) {
            ::munmap(data_, pixelsSize_);
            data_ = nullptr;
        }
    }
    return isUnMap_;
#else
    return false;
#endif
}

bool PixelMap::ReMap()
{
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
    if (allocatorType_ != AllocatorType::SHARE_MEM_ALLOC) {
        return false;
    }
    std::lock_guard<std::mutex> lock(*unmapMutex_);
    if (!isUnMap_) {
        return true;
    }

    int *fd = static_cast<int *>(context_);
    if (fd == nullptr) {
        return false;
    }

    void *ptr = ::mmap(nullptr, pixelsSize_, PROT_READ, MAP_SHARED, *fd, 0);
    if (ptr == MAP_FAILED) {
        return false;
    }

    data_ = (uint8_t *)ptr;

    isUnMap_ = false;
    return true;
#else
    return false;
#endif
}

uint32_t PixelMap::ToSdr()
{
    ImageInfo imageInfo;
    GetImageInfo(imageInfo);
    PixelFormat outFormat = PixelFormat::RGBA_8888;
    if (imageInfo.pixelFormat == PixelFormat::YCBCR_P010) {
        outFormat = PixelFormat::NV12;
    } else if (imageInfo.pixelFormat == PixelFormat::YCRCB_P010) {
        outFormat = PixelFormat::NV21;
    }
    return ToSdr(outFormat, toSdrColorIsSRGB_);
}

uint32_t PixelMap::ToSdr(PixelFormat format, bool toSRGB)
{
    if (IsAstcOrY8Format()) {
        IMAGE_LOGE("ToSdr does not support astc or Y8");
        return ERR_IMAGE_DATA_UNSUPPORT;
    }
#if defined(_WIN32) || defined(_APPLE) || defined(IOS_PLATFORM) || defined(ANDROID_PLATFORM)
    IMAGE_LOGI("tosdr is not supported");
    return ERR_MEDIA_INVALID_OPERATION;
#else
    ImageTrace imageTrace("PixelMap ToSdr");
    if (allocatorType_ != AllocatorType::DMA_ALLOC || !IsHdr()) {
        IMAGE_LOGI("pixelmap is not support tosdr");
        return ERR_MEDIA_INVALID_OPERATION;
    }
    AllocatorType dstType = AllocatorType::DMA_ALLOC;
    ImageInfo imageInfo;
    GetImageInfo(imageInfo);
    uint32_t ret = SUCCESS;
    auto sdrMemory = CreateSdrMemory(imageInfo, format, dstType, ret, toSRGB);
    if (ret != SUCCESS) {
        return ret;
    }
    SetPixelsAddr(sdrMemory->data.data, sdrMemory->extend.data, sdrMemory->data.size, dstType, nullptr);
    imageInfo.pixelFormat = sdrMemory->data.format;
    SetImageInfo(imageInfo, true);
    YUVStrideInfo dstStrides;
    ImageUtils::UpdateSdrYuvStrides(imageInfo, dstStrides, sdrMemory->extend.data, dstType);
    ImageUtils::UpdateYUVDataInfo(*this);
#ifdef IMAGE_COLORSPACE_FLAG
    InnerSetColorSpace(OHOS::ColorManager::ColorSpace(toSRGB ? ColorManager::SRGB : ColorManager::DISPLAY_P3));
#endif
    return SUCCESS;
#endif
}

#ifdef IMAGE_COLORSPACE_FLAG
void PixelMap::InnerSetColorSpace(const OHOS::ColorManager::ColorSpace &grColorSpace, bool direct)
{
    std::lock_guard<std::mutex> lock(*colorSpaceMutex_);
    if (direct) {
        grColorSpace_ = std::make_shared<OHOS::ColorManager::ColorSpace>(grColorSpace);
    } else {
        grColorSpace_ = std::make_shared<OHOS::ColorManager::ColorSpace>(grColorSpace.ToSkColorSpace(),
            grColorSpace.GetColorSpaceName());
    }
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (allocatorType_ == AllocatorType::DMA_ALLOC && GetFd() != nullptr) {
        sptr<SurfaceBuffer> buffer = sptr<SurfaceBuffer>(reinterpret_cast<SurfaceBuffer*>(GetFd()));
        HDI::Display::Graphic::Common::V1_0::CM_ColorSpaceType sbColorspaceType;
        VpeUtils::GetSbColorSpaceType(buffer, sbColorspaceType);
        if (static_cast<uint32_t>(sbColorspaceType) != HDI::Display::Graphic::Common::V1_0::CM_COLORSPACE_NONE) {
            IMAGE_LOGI("InnerSetColorSpace colorspaceType not sync because of surfacebuffer's colorspace is not none");
            return;
        }
        ColorManager::ColorSpaceName name = grColorSpace.GetColorSpaceName();
        HDI::Display::Graphic::Common::V1_0::CM_ColorSpaceType colorspaceType = ColorUtils::ConvertToCMColor(name);
        VpeUtils::SetSbColorSpaceType(buffer, colorspaceType);
        IMAGE_LOGD("InnerSetColorSpace colorspaceType is %{public}d", colorspaceType);
    }
#endif
    if (!isUnmarshalling_) {
        MarkPropertiesDirty();
    }
}

OHOS::ColorManager::ColorSpace PixelMap::InnerGetGrColorSpace()
{
    std::lock_guard<std::mutex> lock(*colorSpaceMutex_);
    if (grColorSpace_ == nullptr) {
        grColorSpace_ =
            std::make_shared<OHOS::ColorManager::ColorSpace>(OHOS::ColorManager::ColorSpaceName::SRGB);
    }
    return *grColorSpace_;
}

static bool isSameColorSpace(const OHOS::ColorManager::ColorSpace &src,
    const OHOS::ColorManager::ColorSpace &dst)
{
    auto skSrc = src.ToSkColorSpace();
    auto skDst = dst.ToSkColorSpace();
    return SkColorSpace::Equals(skSrc.get(), skDst.get());
}

uint32_t PixelMap::ApplyColorSpace(const OHOS::ColorManager::ColorSpace &grColorSpace)
{
    if (IsAstcOrY8Format()) {
        IMAGE_LOGE("ApplyColorSpace does not support astc or Y8");
        return ERR_IMAGE_COLOR_CONVERT;
    }
    auto grName = grColorSpace.GetColorSpaceName();
    if (grColorSpace_ != nullptr && isSameColorSpace(*grColorSpace_, grColorSpace)) {
        if (grColorSpace_->GetColorSpaceName() != grName) {
            InnerSetColorSpace(grColorSpace);
        }
        return SUCCESS;
    }
    ImageInfo imageInfo;
    GetImageInfo(imageInfo);
    // Build sk source infomation
    SkTransInfo src;
    src.info = ToSkImageInfo(imageInfo, ToSkColorSpace(this));
    uint64_t rowStride = src.info.minRowBytes();
    uint8_t* srcData = data_;
#if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
    if (isUnMap_) {
        IMAGE_LOGE("PixelMap::ApplyColorSpace falied, isUnMap %{public}d", isUnMap_);
        return ERR_IMAGE_COLOR_CONVERT;
    }
    if (GetAllocatorType() == AllocatorType::DMA_ALLOC && GetFd() != nullptr) {
        SurfaceBuffer* sbBuffer = static_cast<SurfaceBuffer*>(GetFd());
        rowStride = static_cast<uint64_t>(sbBuffer->GetStride());
    }
    srcData = static_cast<uint8_t *>(GetWritablePixels());
#endif
    src.bitmap.installPixels(src.info, srcData, rowStride);
    // Build sk target infomation
    SkTransInfo dst;
    dst.info = ToSkImageInfo(imageInfo, grColorSpace.ToSkColorSpace());
    MemoryData memoryData = {nullptr, dst.info.computeMinByteSize(), "Trans ImageData",
        {dst.info.width(), dst.info.height()}, imageInfo.pixelFormat, GetNoPaddingUsage()};
    auto m = MemoryManager::CreateMemory(allocatorType_, memoryData);
    if (m == nullptr) {
        IMAGE_LOGE("applyColorSpace CreateMemory failed");
        return ERR_IMAGE_COLOR_CONVERT;
    }
    // Transfor pixels by readPixels
    if (!src.bitmap.readPixels(dst.info, m->data.data, rowStride, 0, 0)) {
        m->Release();
        IMAGE_LOGE("ReadPixels failed");
        return ERR_IMAGE_COLOR_CONVERT;
    }
    // Restore target infomation into pixelmap
    ToImageInfo(imageInfo, dst.info);
    InnerSetColorSpace(OHOS::ColorManager::ColorSpace(dst.info.refColorSpace(), grName), true);
    SetPixelsAddr(m->data.data, m->extend.data, m->data.size, m->GetType(), nullptr);
    SetImageInfo(imageInfo, true);
    return SUCCESS;
}
#endif

std::unique_ptr<PixelMap> PixelMap::ConvertFromAstc(PixelMap *source, uint32_t &errorCode, PixelFormat destFormat)
{
    if (destFormat != PixelFormat::ALPHA_F16) {
        return PixelConvert::AstcToRgba(source, errorCode, destFormat);
    }
    std::unique_ptr<PixelMap> rgbaPixelMap = PixelConvert::AstcToRgba(source, errorCode, PixelFormat::RGBA_8888);
    if (rgbaPixelMap == nullptr) {
        return nullptr;
    }
    ImageInfo imageInfo;
    rgbaPixelMap->GetImageInfo(imageInfo);
    InitializationOptions opts;
    opts.size = imageInfo.size;
    opts.pixelFormat = PixelFormat::ALPHA_F16;
    opts.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
    std::unique_ptr<PixelMap> result = PixelMap::Create(*rgbaPixelMap, opts);
    if (result == nullptr) {
        errorCode = ERR_IMAGE_DECODE_FAILED;
    }
    return result;
}

uint64_t PixelMap::GetNoPaddingUsage()
{
#if !defined(CROSS_PLATFORM)
    if (allocatorType_ != AllocatorType::DMA_ALLOC || GetFd() == nullptr) {
        return 0;
    }
    SurfaceBuffer* sbBuffer = reinterpret_cast<SurfaceBuffer*>(GetFd());
    if (sbBuffer->GetUsage() & BUFFER_USAGE_PREFER_NO_PADDING) {
        return BUFFER_USAGE_PREFER_NO_PADDING | BUFFER_USAGE_ALLOC_NO_IPC;
    }
    return 0;
#else
    return 0;
#endif
}
} // namespace Media
} // namespace OHOS