d6cfb1f1创建于 4月27日历史提交
/*
 * Copyright (c) 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 "napi/native_api.h"
#include <unordered_map>
#include <mutex>
#include <cstring>
#include "Log.h"
#include "ApngDecoder.h"
#include "Error.h"
#include "StreamSourceHarmony.h"
#include "ApngImage.h"
#ifdef BUILD_DEBUG
#include <chrono>
#endif

// Include native_image API for PixelMap creation
// Try to include if available, otherwise we'll use alternative methods
#ifdef __cplusplus
extern "C" {
#endif
// Forward declarations for native_image API
#ifdef __cplusplus
}
#endif

namespace apng_drawable {

// CreatePixelMapFromBuffer 函数参数个数
constexpr size_t ARG_COUNT_CREATE_PIXEL_MAP = 5;
// 纳秒转毫秒的转换因子 (1ms = 1,000,000ns)
constexpr int64_t NS_PER_MS = 1000000;

static void RgbaToBgraInPlace(uint8_t *pixels, size_t byteCount)
{
    for (size_t i = 0; i + CHANNEL_4_BYTE_SIZE <= byteCount; i += CHANNEL_4_BYTE_SIZE) {
        uint8_t t = pixels[i + CHANNEL_INDEX_R];
        pixels[i + CHANNEL_INDEX_R] = pixels[i + CHANNEL_INDEX_B];
        pixels[i + CHANNEL_INDEX_B] = t;
    }
}

// 全局图像映射表
static std::unordered_map<int32_t, std::shared_ptr<ApngImage>> gImageMap;
static std::mutex g_lock;
static uint32_t g_idCounter = 0;

// NAPI辅助函数:将图像存入映射表并返回图像ID
static int32_t StoreImage(std::shared_ptr<ApngImage> image)
{
    int32_t imageId;
    std::lock_guard<std::mutex> lock(g_lock);
    g_idCounter++;
    imageId = static_cast<int32_t>(g_idCounter);
    gImageMap.emplace(imageId, std::move(image));
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi",
        "Decode: Stored image with id=%{public}d, total images=%{public}zu", imageId, gImageMap.size());
    LOGV(" | total images: %ld", gImageMap.size());
    return imageId;
}

// NAPI辅助函数:解析Decode函数的ArrayBuffer参数
struct DecodeParams {
    void* data = nullptr;
    size_t length = 0;
    bool valid = false;
};

static DecodeParams ParseDecodeParams(napi_env env, napi_callback_info info)
{
    DecodeParams params;
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Decode: argc=%{public}zu", argc);

    if (argc < 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Decode: Expected ArrayBuffer argument but argc=%{public}zu", argc);
        napi_throw_error(env, nullptr, "Expected ArrayBuffer argument");
        return params;
    }

    // 检查是否为ArrayBuffer
    bool isArrayBuffer = false;
    napi_is_arraybuffer(env, args[0], &isArrayBuffer);
    if (!isArrayBuffer) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Decode: Argument is not an ArrayBuffer");
        napi_throw_type_error(env, nullptr, "Argument must be an ArrayBuffer");
        return params;
    }

    // 获取ArrayBuffer数据
    napi_get_arraybuffer_info(env, args[0], &params.data, &params.length);
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Decode: ArrayBuffer size=%{public}zu bytes",
        params.length);

    params.valid = true;
    return params;
}
static napi_value CreateDecodeErrorResult(napi_env env, int32_t errorCode)
{
    napi_value result;
    napi_create_object(env, &result);

    // 设置id为错误码(负数)
    napi_value idValue;
    napi_create_int32(env, errorCode, &idValue);
    napi_set_named_property(env, result, "id", idValue);

        // 设置其他字段为默认值
        napi_value zeroValue;
        napi_create_int32(env, 0, &zeroValue);
        napi_set_named_property(env, result, "width", zeroValue);
        napi_set_named_property(env, result, "height", zeroValue);
        napi_set_named_property(env, result, "frameCount", zeroValue);
        napi_set_named_property(env, result, "loopCount", zeroValue);
        napi_set_named_property(env, result, "allFrameByteCount", zeroValue);

        // 设置空的frameDurations数组
        napi_value emptyArray;
        napi_create_array_with_length(env, 0, &emptyArray);
        napi_set_named_property(env, result, "frameDurations", emptyArray);

    return result;
}

// NAPI辅助函数:创建成功结果对象
static napi_value CreateDecodeResult(napi_env env, const std::shared_ptr<ApngImage> &image, int32_t id)
{
    napi_value result;
    napi_create_object(env, &result);
    // 设置id
    napi_value idValue;
    napi_create_int32(env, id, &idValue);
    napi_set_named_property(env, result, "id", idValue);
    // 设置width
    napi_value widthValue;
    napi_create_int32(env, image->GetWidth(), &widthValue);
    napi_set_named_property(env, result, "width", widthValue);
    // 设置height
    napi_value heightValue;
    napi_create_int32(env, image-> GetHeight(), &heightValue);
    napi_set_named_property(env, result, "height", heightValue);
    // 设置frameCount
    napi_value frameCountValue;
    napi_create_int32(env, image->GetFrameCount(), &frameCountValue);
    napi_set_named_property(env, result, "frameCount", frameCountValue);
    // 设置loopCount
    napi_value loopCountValue;
    napi_create_int32(env, image->GetRepeatCount(), &loopCountValue);
    napi_set_named_property(env, result, "loopCount", loopCountValue);
    // 设置allFrameByteCount
    napi_value allFrameByteCountValue;
    napi_create_int64(env, image->GetAllFrameByteCount(), &allFrameByteCountValue);
    napi_set_named_property(env, result, "allFrameByteCount", allFrameByteCountValue);
    // 设置frameDurations数组
    uint32_t frameCount = image->GetFrameCount();
    napi_value frameDurationsArray;
    napi_create_array_with_length(env, frameCount, &frameDurationsArray);
    for (uint32_t i = 0; i < frameCount; ++i) {
        std::shared_ptr<ApngFrame> frame = image->GetFrame(i);
        if (!frame) {
            break;
        }
        napi_value durationValue;
        napi_create_int32(env, static_cast<int32_t>(frame->GetDuration()), &durationValue);
        napi_set_element(env, frameDurationsArray, i, durationValue);
    }
    napi_set_named_property(env, result, "frameDurations", frameDurationsArray);
    return result;
}

// decode函数:从ArrayBuffer解码APNG
static napi_value Decode(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Decode function called");
    LOGV("Decode start");

#ifdef BUILD_DEBUG
    std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
#endif

    // 解析并验证参数
    DecodeParams decodeParams = ParseDecodeParams(env, info);
    if (!decodeParams.valid) {
        return nullptr;
    }

    // 创建StreamSourceHarmony
    std::unique_ptr<StreamSourceBase> source =
        std::make_unique<StreamSourceHarmony>(static_cast<const uint8_t *>(decodeParams.data), decodeParams.length);

    // 调用ApngDecoder::decode(核心解码逻辑,完全复用!)
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Decode: Calling ApngDecoder::Decode");
    int32_t resultCode;
    std::shared_ptr<ApngImage> image = std::move(ApngDecoder::Decode(std::move(source), resultCode));

    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Decode: Decode result code=%{public}d",
        resultCode);
    LOGV(" | Decode result: %d", resultCode);

    if (resultCode != SUCCESS || !image) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Decode: Failed with code=%{public}d, image=%{public}p", resultCode, image.get());
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Decode: Returning error result with id=%{public}d", resultCode);
        return CreateDecodeErrorResult(env, resultCode);
    }

    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi",
        "Decode: Success, width=%{public}d, height=%{public}d, frames=%{public}u", image->GetWidth(),
        image-> GetHeight(), image->GetFrameCount());

#ifdef BUILD_DEBUG
    std::chrono::system_clock::time_point end = std::chrono::system_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
    LOGV(" | time: %lld ns (%lld ms)", elapsed, elapsed / NS_PER_MS);
#endif

    // 将图像存入映射表
    int32_t imageId = StoreImage(std::move(image));

    // 创建并返回结果对象
    napi_value result = CreateDecodeResult(env, gImageMap[imageId], imageId);
    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Decode: Completed successfully, id=%{public}d",
        imageId);
    LOGV("Decode end");
    return result;
}

// isApng函数:检查是否为APNG格式
static napi_value IsApng(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "IsApng function called");

    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "IsApng: Expected ArrayBuffer argument but argc=%{public}zu", argc);
        napi_throw_error(env, nullptr, "Expected ArrayBuffer argument");
        return nullptr;
    }

    bool isArrayBuffer = false;
    napi_is_arraybuffer(env, args[0], &isArrayBuffer);
    if (!isArrayBuffer) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi", "IsApng: Argument is not an ArrayBuffer");
        napi_throw_type_error(env, nullptr, "Argument must be an ArrayBuffer");
        return nullptr;
    }

    void *data = nullptr;
    size_t length = 0;
    napi_get_arraybuffer_info(env, args[0], &data, &length);
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "IsApng: ArrayBuffer size=%{public}zu bytes",
        length);

    // 创建临时StreamSource检查签名
    std::unique_ptr<StreamSourceBase> source =
        std::make_unique<StreamSourceHarmony>(static_cast<const uint8_t *>(data), length);

    // 调用ApngDecoder::isApng(核心逻辑,完全复用!)
    bool result = ApngDecoder::IsApng(std::move(source));
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "IsApng: result=%{public}s",
        result ? "true" : "false");

    napi_value resultValue;
    napi_get_boolean(env, result, &resultValue);
    return resultValue;
}

// 辅助结构体:解析后的参数
struct DrawParams {
    int32_t id = -1;
    int32_t index = -1;
    bool valid = false;
    napi_value args[3];  // 保存原始参数,用于后续 buffer 操作
    size_t argc = 0;
};

// 1. 解析并校验参数
static DrawParams ParseDrawParams(napi_env env, napi_callback_info info)
{
    DrawParams params;
    #define EXPECTED_ARG_COUNT 3
    params.argc = EXPECTED_ARG_COUNT;
    napi_status status = napi_get_cb_info(env, info, &params.argc, params.args, nullptr, nullptr);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Draw: napi_get_cb_info failed, status=%{public}d", status);
        napi_throw_error(env, nullptr, "napi_get_cb_info failed");
        return params;
    }
    
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Draw: argc=%{public}zu", params.argc);
    if (params.argc < EXPECTED_ARG_COUNT) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Draw: Expected (id, index, outputBuffer) arguments but argc=%{public}zu", params.argc);
        napi_throw_error(env, nullptr, "Expected (id, index, outputBuffer) arguments");
        return params;
    }

    status = napi_get_value_int32(env, params.args[0], &params.id);
    if (status != napi_ok || params.id < 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Draw: Invalid id=%{public}d", params.id);
        napi_throw_error(env, nullptr, "Invalid id");
        return params;
    }

    status = napi_get_value_int32(env, params.args[1], &params.index);
    if (status != napi_ok || params.index < 0) {
        napi_throw_error(env, nullptr, "Invalid index");
        return params;
    }

    params.valid = true;
    return params;
}

// 2. 根据 id 获取图像
static std::shared_ptr<ApngImage> GetImageById(int32_t id)
{
    std::lock_guard<std::mutex> lock(g_lock);
    auto it = gImageMap.find(id);
    if (it != gImageMap.end()) {
        return it->second;
    }
    return nullptr;
}

// 3. 验证输出 buffer 并获取指针和长度
static bool ValidateOutputBuffer(napi_env env, napi_value bufferArg, void*& outData, size_t& outLength)
{
    bool isArrayBuffer = false;
    napi_status status = napi_is_arraybuffer(env, bufferArg, &isArrayBuffer);
    if (status != napi_ok || !isArrayBuffer) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Draw: Third argument is not an ArrayBuffer");
        napi_throw_type_error(env, nullptr, "Third argument must be an ArrayBuffer");
        return false;
    }

    status = napi_get_arraybuffer_info(env, bufferArg, &outData, &outLength);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Draw: napi_get_arraybuffer_info failed, status=%{public}d", status);
        napi_throw_error(env, nullptr, "napi_get_arraybuffer_info failed");
        return false;
    }
    return true;
}

// 主函数:行数控制在 50 以内
static napi_value Draw(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Draw function called");

    DrawParams params = ParseDrawParams(env, info);
    if (!params.valid) {
        return nullptr;
    }

    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Draw: id=%{public}d, index=%{public}d",
        params.id, params.index);

    std::shared_ptr<ApngImage> image = GetImageById(params.id);
    if (!image) {
        napi_throw_error(env, nullptr, "Image not found");
        return nullptr;
    }

    std::shared_ptr<ApngFrame> frame = image->GetFrame(static_cast<uint32_t>(params.index));
    if (!frame) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Draw: Frame not found, id=%{public}d, index=%{public}d", params.id, params.index);
        napi_throw_error(env, nullptr, "Frame not found");
        return nullptr;
    }

    // 验证输出 buffer
    void* outputData = nullptr;
    size_t outputLength = 0;
    const int outputIndex = 2;
    if (!ValidateOutputBuffer(env, params.args[outputIndex], outputData, outputLength)) {
        return nullptr;
    }

    // 检查 buffer 大小
    uint32_t frameByteCount = image->GetFrameByteCount();
    if (outputLength < frameByteCount) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Draw: Output buffer too small, required=%{public}u, provided=%{public}zu", frameByteCount, outputLength);
        napi_throw_error(env, nullptr, "Output buffer too small");
        return nullptr;
    }

    // 复制帧数据
    std::copy_n(reinterpret_cast<uint8_t*>(frame->GetRawPixels()), frameByteCount, static_cast<uint8_t*>(outputData));
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi",
        "Draw: Successfully copied frame data, size=%{public}u bytes", frameByteCount);

    napi_value success;
    napi_get_boolean(env, true, &success);
    return success;
}

// recycle函数:释放图像资源
static napi_value Recycle(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Recycle function called");

    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Recycle: Expected id argument but argc=%{public}zu", argc);
        napi_throw_error(env, nullptr, "Expected id argument");
        return nullptr;
    }

    int32_t id;
    napi_get_value_int32(env, args[0], &id);

    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Recycle: id=%{public}d", id);
    LOGV("recycle start. id : %d", id);

    if (id < 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Recycle: Invalid id=%{public}d", id);
        napi_value errorCode;
        napi_create_int32(env, ERR_NOT_EXIST_IMAGE, &errorCode);
        return errorCode;
    }

    std::lock_guard<std::mutex> lock(g_lock);
    auto const & it = gImageMap.find(id);
    if (it == gImageMap.end()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Recycle: Image not found for id=%{public}d", id);
        napi_value errorCode;
        napi_create_int32(env, ERR_NOT_EXIST_IMAGE, &errorCode);
        return errorCode;
    }

    gImageMap.erase(it);
    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi",
        "Recycle: Successfully removed image id=%{public}d, remaining images=%{public}zu", id, gImageMap.size());
    LOGV(" | removed from map. remaining: %ld", gImageMap.size());
    LOGV("recycle end");

    napi_value success;
    napi_create_int32(env, SUCCESS, &success);
    return success;
}

// copy函数:复制图像
static napi_value Copy(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Copy: argc=%{public}zu", argc);
    if (argc < 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Copy: Expected id argument but argc=%{public}zu", argc);
        napi_throw_error(env, nullptr, "Expected id argument");
        return nullptr;
    }
    int32_t id;
    napi_get_value_int32(env, args[0], &id);
    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Copy: id=%{public}d", id);
    LOGV("copy start. id : %d", id);
    if (id < 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Copy: Invalid id=%{public}d", id);
        napi_value errorCode;
        napi_create_int32(env, ERR_NOT_EXIST_IMAGE, &errorCode);
        return errorCode;
    }
    std::shared_ptr<ApngImage> copyPtr = nullptr;
    {
        std::lock_guard<std::mutex> lock(g_lock);
        auto const & it = gImageMap.find(id);
        if (it == gImageMap.end()) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
                "Copy: Image not found for id=%{public}d", id);
            napi_value errorCode;
            napi_create_int32(env, ERR_NOT_EXIST_IMAGE, &errorCode);
            return errorCode;
        }
        copyPtr = it->second;
    }
    int32_t resultId;
    {
        std::lock_guard<std::mutex> lock(g_lock);
        resultId = static_cast<int32_t>(++g_idCounter);
        gImageMap.emplace(resultId, copyPtr);
        OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "Copy: Created copy with id=%{public}d from source id=%{public}d, total images=%{public}zu", resultId, id,
            gImageMap.size());
    }
    napi_value result = CreateDecodeResult(env, copyPtr, resultId);
    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi",
        "Copy: Completed successfully, new id=%{public}d", resultId);
    LOGV("copy end");
    return result;
}

// 辅助结构体,用于封装解析后的参数
struct ParsedParams {
    void* data = nullptr;
    size_t length = 0;
    int32_t width = 0;
    int32_t height = 0;
    int32_t targetWidth = 0;
    int32_t targetHeight = 0;
    bool valid = false;
};

static ParsedParams ParseAndValidateParams(napi_env env, napi_callback_info info)
{
    ParsedParams params;
    size_t argc = ARG_COUNT_CREATE_PIXEL_MAP;
    napi_value args[ARG_COUNT_CREATE_PIXEL_MAP];
    napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    if (status != napi_ok) {
        napi_throw_error(env, nullptr, "napi_get_cb_info failed");
        return params;
    }
    if (argc < ARG_COUNT_CREATE_PIXEL_MAP) {
        napi_throw_error(env, nullptr, "Expected (buffer, width, height, targetWidth, targetHeight) arguments");
        return params;
    }

    bool isArrayBuffer = false;
    status = napi_is_arraybuffer(env, args[0], &isArrayBuffer);
    if (!isArrayBuffer) {
        napi_throw_type_error(env, nullptr, "First argument must be an ArrayBuffer");
        return params;
    }

    status = napi_get_arraybuffer_info(env, args[0], &params.data, &params.length);
    if (status != napi_ok) {
        napi_throw_error(env, nullptr, "napi_get_arraybuffer_info failed");
        return params;
    }
    status = napi_get_value_int32(env, args[ARG_INDEX_WIDTH], &params.width);
    status = (status == napi_ok) ? napi_get_value_int32(env, args[ARG_INDEX_HEIGHT], &params.height)
                            : status;
    status = (status == napi_ok) ? napi_get_value_int32(env, args[ARG_INDEX_TARGET_WIDTH], &params.targetWidth)
                            : status;
    status = (status == napi_ok) ? napi_get_value_int32(env, args[ARG_INDEX_TARGET_HEIGHT], &params.targetHeight)
                            : status;
    if (status != napi_ok) {
        napi_throw_error(env, nullptr, "napi_get_value_int32 failed");
        return params;
    }
    size_t expectedSize = static_cast<size_t>(params.width) * static_cast<size_t>(params.height) * CHANNEL_4_BYTE_SIZE;
    if (params.length < expectedSize) {
        napi_throw_error(env, nullptr, "Buffer size is too small");
        return params;
    }

    params.valid = true;
    return params;
}

static napi_value CreatePixelBuffer(napi_env env, const ParsedParams& params, size_t& outDataSize)
{
    napi_value pixelBuffer = nullptr;
    void* pixelData = nullptr;
    size_t expectedSize = static_cast<size_t>(params.width) * static_cast<size_t>(params.height) * CHANNEL_4_BYTE_SIZE;

    if (params.targetWidth == params.width && params.targetHeight == params.height) {
        outDataSize = expectedSize;
        napi_status status = napi_create_arraybuffer(env, outDataSize, &pixelData, &pixelBuffer);
        if (status != napi_ok) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
                "CreatePixelMapFromBuffer: napi_create_arraybuffer failed, status=%{public}d", status);
            napi_throw_error(env, nullptr, "napi_create_arraybuffer failed");
            return nullptr;
        }
        std::copy_n((unsigned char*)params.data, outDataSize, (unsigned char*)pixelData);
        RgbaToBgraInPlace(static_cast<uint8_t*>(pixelData), outDataSize);
    } else {
        size_t targetDataSize = static_cast<size_t>(params.targetWidth) *
                                static_cast<size_t>(params.targetHeight) *
                                CHANNEL_4_BYTE_SIZE;
        outDataSize = targetDataSize;
        napi_status status = napi_create_arraybuffer(env, targetDataSize, &pixelData, &pixelBuffer);
        if (status != napi_ok) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
                "CreatePixelMapFromBuffer: napi_create_arraybuffer failed for scaled image, status=%{public}d", status);
            napi_throw_error(env, nullptr, "napi_create_arraybuffer failed");
            return nullptr;
        }

        uint8_t* src = static_cast<uint8_t*>(params.data);
        uint8_t* dst = static_cast<uint8_t*>(pixelData);
        for (int32_t y = 0; y < params.targetHeight; ++y) {
            int32_t srcY = (y * params.height) / params.targetHeight;
            for (int32_t x = 0; x < params.targetWidth; ++x) {
                int32_t srcX = (x * params.width) / params.targetWidth;
                size_t srcOffset = (srcY * params.width + srcX) * CHANNEL_4_BYTE_SIZE;
                size_t dstOffset = (y * params.targetWidth + x) * CHANNEL_4_BYTE_SIZE;
                dst[dstOffset + CHANNEL_INDEX_R] = src[srcOffset + CHANNEL_INDEX_R];
                dst[dstOffset + CHANNEL_INDEX_G] = src[srcOffset + CHANNEL_INDEX_G];
                dst[dstOffset + CHANNEL_INDEX_B] = src[srcOffset + CHANNEL_INDEX_B];
                dst[dstOffset + CHANNEL_INDEX_A] = src[srcOffset + CHANNEL_INDEX_A];
            }
        }
        RgbaToBgraInPlace(static_cast<uint8_t*>(pixelData), targetDataSize);
        OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "CreatePixelMapFromBuffer: Scaling completed, output size=%{public}zu bytes", targetDataSize);
    }
    return pixelBuffer;
}

static bool SetPixelMapProperties(napi_env env,
                                  napi_value pixelMapObj,
                                  napi_value pixelBuffer,
                                  const ParsedParams& params)
{
    napi_value widthValue;
    napi_value heightValue;
    napi_value targetWidthValue;
    napi_value targetHeightValue;
    napi_status status = napi_create_int32(env, params.targetWidth, &widthValue);
    status = (status == napi_ok) ? napi_create_int32(env, params.targetHeight, &heightValue)
                            : status;
    status = (status == napi_ok) ? napi_create_int32(env, params.targetWidth, &targetWidthValue)
                            : status;
    status = (status == napi_ok) ? napi_create_int32(env, params.targetHeight, &targetHeightValue)
                            : status;
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "CreatePixelMapFromBuffer: napi_create_int32 failed, status=%{public}d", status);
        napi_throw_error(env, nullptr, "napi_create_int32 failed");
        return false;
    }

    status = napi_set_named_property(env, pixelMapObj, "pixelBuffer", pixelBuffer);
    status = (status == napi_ok) ? napi_set_named_property(env, pixelMapObj, "width", widthValue)
                            : status;
    status = (status == napi_ok) ? napi_set_named_property(env, pixelMapObj, "height", heightValue)
                            : status;
    status = (status == napi_ok) ? napi_set_named_property(env, pixelMapObj, "targetWidth", targetWidthValue)
                            : status;
    status = (status == napi_ok) ? napi_set_named_property(env, pixelMapObj, "targetHeight", targetHeightValue)
                            : status;
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "CreatePixelMapFromBuffer: napi_set_named_property failed, status=%{public}d", status);
        napi_throw_error(env, nullptr, "napi_set_named_property failed");
        return false;
    }
    return true;
}

// 原函数(修改后):圈复杂度 = 4(≤20)
static napi_value CreatePixelMapFromBuffer(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi", "CreatePixelMapFromBuffer function called");

    ParsedParams params = ParseAndValidateParams(env, info);
    if (!params.valid) {
        return nullptr;
    }

    napi_value pixelMapObj;
    napi_status status = napi_create_object(env, &pixelMapObj);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "CreatePixelMapFromBuffer: napi_create_object failed, status=%{public}d", status);
        napi_throw_error(env, nullptr, "napi_create_object failed");
        return nullptr;
    }

    size_t pixelDataSize = 0;
    napi_value pixelBuffer = CreatePixelBuffer(env, params, pixelDataSize);
    if (pixelBuffer == nullptr) {
        return nullptr;
    }

    if (!SetPixelMapProperties(env, pixelMapObj, pixelBuffer, params)) {
        return nullptr;
    }

    OH_LOG_Print(LOG_APP, LOG_DEBUG, APNG_LOG_DOMAIN, "ApngDecoderNapi",
        "CreatePixelMapFromBuffer: Created PixelMap wrapper object");
    return pixelMapObj;
}

// 模块初始化函数
extern "C" napi_value InitApngDrawable(napi_env env, napi_value exports)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi",
        "========== APNG MODULE INIT CALLED ==========");
    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi", "Initializing apng_drawable module");

    napi_property_descriptor desc[] = {
    { "decode", nullptr, Decode, nullptr, nullptr, nullptr, napi_default, nullptr },
    { "isApng", nullptr, IsApng, nullptr, nullptr, nullptr, napi_default, nullptr },
    { "draw", nullptr, Draw, nullptr, nullptr, nullptr, napi_default, nullptr },
    { "recycle", nullptr, Recycle, nullptr, nullptr, nullptr, napi_default, nullptr },
    { "copy", nullptr, Copy, nullptr, nullptr, nullptr, napi_default, nullptr },
    { "createPixelMapFromBuffer", nullptr, CreatePixelMapFromBuffer, nullptr, nullptr, nullptr, napi_default, nullptr }
  };

    napi_status status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, APNG_LOG_DOMAIN, "ApngDecoderNapi",
            "InitApngDrawable: napi_define_properties failed, status=%{public}d", status);
        return exports;
    }

    OH_LOG_Print(LOG_APP, LOG_INFO, APNG_LOG_DOMAIN, "ApngDecoderNapi",
        "apng_drawable module initialized successfully with %{public}zu properties", sizeof(desc) / sizeof(desc[0]));
    return exports;
}
} // namespace apng_drawable