Port libpngdec to libpng (#1555)
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions

* intial try to include libpng

* fixing libpng cmake

* cleanup structs and error codes

* building libpng , destroying pkg ;/

* fixed pkg with zlib_comp mode

* attemp to fix ci

* rewrote png encoder with libpng

* small corrections

* clang fix

* clang-fix?

* take alpha value from decode parameters

* more cleanup

* fix stride calculation

* libpng: avoid unnecessary allocation in decoding

* libpng: interlaced support

* libpng: lowered log level

* revert wrong merge

---------

Co-authored-by: Vinicius Rangel <me@viniciusrangel.dev>
This commit is contained in:
georgemoralis 2024-11-22 12:42:53 +02:00 committed by GitHub
parent 8f2d71d458
commit 8c9d7d1a08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 257 additions and 117 deletions

3
.gitmodules vendored
View File

@ -102,3 +102,6 @@
[submodule "externals/LibAtrac9"] [submodule "externals/LibAtrac9"]
path = externals/LibAtrac9 path = externals/LibAtrac9
url = https://github.com/shadps4-emu/ext-LibAtrac9.git url = https://github.com/shadps4-emu/ext-LibAtrac9.git
[submodule "externals/libpng"]
path = externals/libpng
url = https://github.com/pnggroup/libpng

View File

@ -830,7 +830,7 @@ endif()
create_target_directory_groups(shadps4) create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half) target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half zlib-ng::zlib png_static)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml) target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h") target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
@ -860,9 +860,9 @@ if (NOT ENABLE_QT_GUI)
endif() endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
target_link_libraries(shadps4 PRIVATE cryptoppwin zlib-ng::zlib) target_link_libraries(shadps4 PRIVATE cryptoppwin)
else() else()
target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp zlib-ng::zlib) target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp)
endif() endif()
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)

View File

@ -58,8 +58,10 @@ if (NOT TARGET zlib-ng::zlib)
set(WITH_GTEST OFF) set(WITH_GTEST OFF)
set(WITH_NEW_STRATEGIES ON) set(WITH_NEW_STRATEGIES ON)
set(WITH_NATIVE_INSTRUCTIONS ON) set(WITH_NATIVE_INSTRUCTIONS ON)
set(ZLIB_COMPAT ON CACHE BOOL "" FORCE)
add_subdirectory(zlib-ng) add_subdirectory(zlib-ng)
add_library(zlib-ng::zlib ALIAS zlib) add_library(zlib-ng::zlib ALIAS zlib)
add_library(ZLIB::ZLIB ALIAS zlib)
endif() endif()
# SDL3 # SDL3
@ -153,6 +155,17 @@ if (NOT TARGET half::half)
add_library(half::half ALIAS half) add_library(half::half ALIAS half)
endif() endif()
# libpng
set(PNG_SHARED OFF CACHE BOOL "" FORCE)
set(PNG_STATIC ON CACHE BOOL "" FORCE)
set(PNG_TESTS OFF CACHE BOOL "" FORCE)
set(PNG_TOOLS OFF CACHE BOOL "" FORCE)
set(SKIP_INSTALL_ALL OFF CACHE BOOL "" FORCE)
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zlib-ng" CACHE STRING "" FORCE)
set(ZLIB_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/zlib-ng/zlibstatic-ngd" CACHE STRING "" FORCE)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libpng/zlib.h" "#include \"../zlib-ng/zlib.h\"")
add_subdirectory(libpng)
if (APPLE) if (APPLE)
# date # date
if (NOT TARGET date::date-tz) if (NOT TARGET date::date-tz)

1
externals/libpng vendored Submodule

@ -0,0 +1 @@
Subproject commit c1cc0f3f4c3d4abd11ca68c59446a29ff6f95003

View File

@ -1,31 +1,30 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <zlib-ng.h> #include <zlib.h>
#include "common/io_file.h" #include "common/io_file.h"
#include "common/logging/formatter.h" #include "common/logging/formatter.h"
#include "core/file_format/pkg.h" #include "core/file_format/pkg.h"
#include "core/file_format/pkg_type.h" #include "core/file_format/pkg_type.h"
static void DecompressPFSC(std::span<const char> compressed_data, static void DecompressPFSC(std::span<char> compressed_data, std::span<char> decompressed_data) {
std::span<char> decompressed_data) { z_stream decompressStream;
zng_stream decompressStream;
decompressStream.zalloc = Z_NULL; decompressStream.zalloc = Z_NULL;
decompressStream.zfree = Z_NULL; decompressStream.zfree = Z_NULL;
decompressStream.opaque = Z_NULL; decompressStream.opaque = Z_NULL;
if (zng_inflateInit(&decompressStream) != Z_OK) { if (inflateInit(&decompressStream) != Z_OK) {
// std::cerr << "Error initializing zlib for deflation." << std::endl; // std::cerr << "Error initializing zlib for deflation." << std::endl;
} }
decompressStream.avail_in = compressed_data.size(); decompressStream.avail_in = compressed_data.size();
decompressStream.next_in = reinterpret_cast<const Bytef*>(compressed_data.data()); decompressStream.next_in = reinterpret_cast<unsigned char*>(compressed_data.data());
decompressStream.avail_out = decompressed_data.size(); decompressStream.avail_out = decompressed_data.size();
decompressStream.next_out = reinterpret_cast<Bytef*>(decompressed_data.data()); decompressStream.next_out = reinterpret_cast<unsigned char*>(decompressed_data.data());
if (zng_inflate(&decompressStream, Z_FINISH)) { if (inflate(&decompressStream, Z_FINISH)) {
} }
if (zng_inflateEnd(&decompressStream) != Z_OK) { if (inflateEnd(&decompressStream) != Z_OK) {
// std::cerr << "Error ending zlib inflate" << std::endl; // std::cerr << "Error ending zlib inflate" << std::endl;
} }
} }

View File

@ -593,7 +593,6 @@ constexpr int ORBIS_VIDEODEC2_ERROR_INVALID_SEQUENCE = 0x811D0303;
constexpr int ORBIS_VIDEODEC2_ERROR_FATAL_STREAM = 0x811D0304; constexpr int ORBIS_VIDEODEC2_ERROR_FATAL_STREAM = 0x811D0304;
// Videodec library // Videodec library
constexpr int ORBIS_VIDEODEC_ERROR_API_FAIL = 0x80C10000; constexpr int ORBIS_VIDEODEC_ERROR_API_FAIL = 0x80C10000;
constexpr int ORBIS_VIDEODEC_ERROR_CODEC_TYPE = 0x80C10001; constexpr int ORBIS_VIDEODEC_ERROR_CODEC_TYPE = 0x80C10001;
constexpr int ORBIS_VIDEODEC_ERROR_STRUCT_SIZE = 0x80C10002; constexpr int ORBIS_VIDEODEC_ERROR_STRUCT_SIZE = 0x80C10002;
@ -616,3 +615,14 @@ constexpr int ORBIS_VIDEODEC_ERROR_MISMATCH_SPEC = 0x80C10012;
constexpr int ORBIS_VIDEODEC_ERROR_INVALID_SEQUENCE = 0x80C10013; constexpr int ORBIS_VIDEODEC_ERROR_INVALID_SEQUENCE = 0x80C10013;
constexpr int ORBIS_VIDEODEC_ERROR_FATAL_STREAM = 0x80C10014; constexpr int ORBIS_VIDEODEC_ERROR_FATAL_STREAM = 0x80C10014;
constexpr int ORBIS_VIDEODEC_ERROR_FATAL_STATE = 0x80C10015; constexpr int ORBIS_VIDEODEC_ERROR_FATAL_STATE = 0x80C10015;
// PngDec library
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_ADDR = 0x80690001;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_SIZE = 0x80690002;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_PARAM = 0x80690003;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_HANDLE = 0x80690004;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_WORK_MEMORY = 0x80690005;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_DATA = 0x80690010;
constexpr int ORBIS_PNG_DEC_ERROR_UNSUPPORT_DATA = 0x80690011;
constexpr int ORBIS_PNG_DEC_ERROR_DECODE_ERROR = 0x80690012;
constexpr int ORBIS_PNG_DEC_ERROR_FATAL = 0x80690020;

View File

@ -1,55 +1,47 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <png.h>
#include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "externals/stb_image.h"
#include "pngdec.h" #include "pngdec.h"
namespace Libraries::PngDec { namespace Libraries::PngDec {
void setImageInfoParams(OrbisPngDecImageInfo* imageInfo, int width, int height, int channels, struct PngHandler {
bool isInterlaced, bool isTransparent) { png_structp png_ptr;
if (imageInfo != nullptr) { png_infop info_ptr;
imageInfo->imageWidth = width; };
imageInfo->imageHeight = height;
imageInfo->bitDepth = 8; // always 8? static inline OrbisPngDecColorSpace MapPngColor(int color) {
switch (channels) { // clut missing switch (color) {
case 1: case PNG_COLOR_TYPE_GRAY:
imageInfo->colorSpace = OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE; return OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE;
break;
case 2: case PNG_COLOR_TYPE_GRAY_ALPHA:
imageInfo->colorSpace = return OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE_ALPHA;
OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE_ALPHA;
break; case PNG_COLOR_TYPE_PALETTE:
case 3: return OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_CLUT;
imageInfo->colorSpace = OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_RGB;
break; case PNG_COLOR_TYPE_RGB:
case 4: return OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_RGB;
imageInfo->colorSpace = OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_RGBA;
break; case PNG_COLOR_TYPE_RGB_ALPHA:
default: return OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_RGBA;
imageInfo->colorSpace = OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_RGB;
break;
}
imageInfo->imageFlag = 0;
if (isInterlaced) {
imageInfo->imageFlag |= ORBIS_PNG_DEC_IMAGE_FLAG_ADAM7_INTERLACE;
}
if (isTransparent) {
imageInfo->imageFlag |= ORBIS_PNG_DEC_IMAGE_FLAG_TRNS_CHUNK_EXIST;
}
} }
UNREACHABLE_MSG("unknown png color type");
} }
bool checktRNS(const u8* png_raw, int size) { void PngDecError(png_structp png_ptr, png_const_charp error_message) {
for (int i = 30; i < size - 4; i += 4) { LOG_ERROR(Lib_Png, "PNG error {}", error_message);
if (std::memcmp(png_raw + i, "tRNS", 4) == 0) { }
return true;
} void PngDecWarning(png_structp png_ptr, png_const_charp error_message) {
} LOG_ERROR(Lib_Png, "PNG warning {}", error_message);
return false;
} }
s32 PS4_SYSV_ABI scePngDecCreate(const OrbisPngDecCreateParam* param, void* memoryAddress, s32 PS4_SYSV_ABI scePngDecCreate(const OrbisPngDecCreateParam* param, void* memoryAddress,
@ -66,11 +58,21 @@ s32 PS4_SYSV_ABI scePngDecCreate(const OrbisPngDecCreateParam* param, void* memo
LOG_ERROR(Lib_Png, "Invalid size! width = {}", param->maxImageWidth); LOG_ERROR(Lib_Png, "Invalid size! width = {}", param->maxImageWidth);
return ORBIS_PNG_DEC_ERROR_INVALID_SIZE; return ORBIS_PNG_DEC_ERROR_INVALID_SIZE;
} }
const OrbisPngDecCreateParam* nextParam = param + 1; auto pngh = (PngHandler*)memoryAddress;
int ret = (8 << (reinterpret_cast<uintptr_t>(nextParam) & 0x1f)) *
(param->maxImageWidth + 0x47U & 0xfffffff8) + pngh->png_ptr =
0xd000; png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PngDecError, PngDecWarning);
*handle = reinterpret_cast<OrbisPngDecHandle>(ret);
if (pngh->png_ptr == nullptr)
return ORBIS_PNG_DEC_ERROR_FATAL;
pngh->info_ptr = png_create_info_struct(pngh->png_ptr);
if (pngh->info_ptr == nullptr) {
png_destroy_read_struct(&pngh->png_ptr, nullptr, nullptr);
return false;
}
*handle = pngh;
return ORBIS_OK; return ORBIS_OK;
} }
@ -88,22 +90,91 @@ s32 PS4_SYSV_ABI scePngDecDecode(OrbisPngDecHandle handle, const OrbisPngDecDeco
LOG_ERROR(Lib_Png, "invalid image address!"); LOG_ERROR(Lib_Png, "invalid image address!");
return ORBIS_PNG_DEC_ERROR_INVALID_ADDR; return ORBIS_PNG_DEC_ERROR_INVALID_ADDR;
} }
LOG_TRACE(Lib_Png,
"pngMemSize = {} , imageMemSize = {} , pixelFormat = {} , alphaValue = {} , "
"imagePitch = {}",
param->pngMemSize, param->imageMemSize, param->pixelFormat, param->alphaValue,
param->imagePitch);
int width, height, channels; auto pngh = (PngHandler*)handle;
const u8* png_raw = (const u8*)param->pngMemAddr;
u8* img = stbi_load_from_memory(png_raw, param->pngMemSize, &width, &height, &channels, struct pngstruct {
STBI_rgb_alpha); // STBI_rgb_alpha? const u8* data;
if (!img) { size_t size;
LOG_ERROR(Lib_Png, "Decoding failed!"); u64 offset;
return ORBIS_PNG_DEC_ERROR_DECODE_ERROR; } pngdata = {
.data = (const u8*)param->pngMemAddr,
.size = param->pngMemSize,
.offset = 0,
};
// Read png from memory
png_set_read_fn(pngh->png_ptr, (void*)&pngdata,
[](png_structp ps, png_bytep data, png_size_t len) {
if (len == 0)
return;
auto pngdata = (pngstruct*)png_get_io_ptr(ps);
::memcpy(data, pngdata->data + pngdata->offset, len);
pngdata->offset += len;
});
u32 width, height;
int color_type, bit_depth;
png_read_info(pngh->png_ptr, pngh->info_ptr);
width = png_get_image_width(pngh->png_ptr, pngh->info_ptr);
height = png_get_image_height(pngh->png_ptr, pngh->info_ptr);
color_type = MapPngColor(png_get_color_type(pngh->png_ptr, pngh->info_ptr));
bit_depth = png_get_bit_depth(pngh->png_ptr, pngh->info_ptr);
if (imageInfo != nullptr) {
imageInfo->bitDepth = bit_depth;
imageInfo->imageWidth = width;
imageInfo->imageHeight = height;
imageInfo->colorSpace = color_type;
imageInfo->imageFlag = 0;
if (png_get_interlace_type(pngh->png_ptr, pngh->info_ptr) == 1) {
imageInfo->imageFlag |= OrbisPngDecImageFlag::ORBIS_PNG_DEC_IMAGE_FLAG_ADAM7_INTERLACE;
} }
bool isInterlaced = (png_raw[28] == 1); if (png_get_valid(pngh->png_ptr, pngh->info_ptr, PNG_INFO_tRNS)) {
bool isTransparent = checktRNS(png_raw, param->pngMemSize);
setImageInfoParams(imageInfo, width, height, channels, isInterlaced, isTransparent); imageInfo->imageFlag |= ORBIS_PNG_DEC_IMAGE_FLAG_TRNS_CHUNK_EXIST;
u8* imageBuffer = (u8*)(param->imageMemAddr); }
memcpy(imageBuffer, img, width * height * 4); // copy/pass decoded data }
stbi_image_free(img);
return 0; if (bit_depth == 16)
png_set_strip_16(pngh->png_ptr);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(pngh->png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(pngh->png_ptr);
if (png_get_valid(pngh->png_ptr, pngh->info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(pngh->png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(pngh->png_ptr);
if (param->pixelFormat == OrbisPngDecPixelFormat::ORBIS_PNG_DEC_PIXEL_FORMAT_B8G8R8A8)
png_set_bgr(pngh->png_ptr);
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_PALETTE)
png_set_add_alpha(pngh->png_ptr, param->alphaValue, PNG_FILLER_AFTER);
int pass = png_set_interlace_handling(pngh->png_ptr);
png_read_update_info(pngh->png_ptr, pngh->info_ptr);
auto const numChannels = png_get_channels(pngh->png_ptr, pngh->info_ptr);
auto horizontal_bytes = numChannels * width;
int stride = param->imagePitch > 0 ? param->imagePitch : horizontal_bytes;
for (int j = 0; j < pass; j++) { // interlaced
auto ptr = (png_bytep)param->imageMemAddr;
for (int y = 0; y < height; y++) {
png_read_row(pngh->png_ptr, ptr, nullptr);
ptr += stride;
}
}
return (width > 32767 || height > 32767) ? 0 : (width << 16) | height;
} }
s32 PS4_SYSV_ABI scePngDecDecodeWithInputControl() { s32 PS4_SYSV_ABI scePngDecDecodeWithInputControl() {
@ -112,8 +183,8 @@ s32 PS4_SYSV_ABI scePngDecDecodeWithInputControl() {
} }
s32 PS4_SYSV_ABI scePngDecDelete(OrbisPngDecHandle handle) { s32 PS4_SYSV_ABI scePngDecDelete(OrbisPngDecHandle handle) {
handle = nullptr; // ? auto pngh = *(PngHandler**)handle;
LOG_ERROR(Lib_Png, "(STUBBED)called"); png_destroy_read_struct(&pngh->png_ptr, &pngh->info_ptr, nullptr);
return ORBIS_OK; return ORBIS_OK;
} }
@ -123,16 +194,60 @@ s32 PS4_SYSV_ABI scePngDecParseHeader(const OrbisPngDecParseParam* param,
LOG_ERROR(Lib_Png, "Invalid param!"); LOG_ERROR(Lib_Png, "Invalid param!");
return ORBIS_PNG_DEC_ERROR_INVALID_PARAM; return ORBIS_PNG_DEC_ERROR_INVALID_PARAM;
} }
int width, height, channels;
const u8* png_raw = (const u8*)(param->pngMemAddr); u8 header[8];
int img = stbi_info_from_memory(png_raw, param->pngMemSize, &width, &height, &channels); memcpy(header, param->pngMemAddr, 8);
if (img == 0) { // Check if the header indicates a valid PNG file
LOG_ERROR(Lib_Png, "Decoding failed!"); if (png_sig_cmp(header, 0, 8)) {
return ORBIS_PNG_DEC_ERROR_DECODE_ERROR; LOG_ERROR(Lib_Png, "Memory doesn't contain a valid png file");
return ORBIS_PNG_DEC_ERROR_INVALID_DATA;
} }
bool isInterlaced = (png_raw[28] == 1); // Create a libpng structure, also pass our custom error/warning functions
bool isTransparent = checktRNS(png_raw, param->pngMemSize); auto png_ptr =
setImageInfoParams(imageInfo, width, height, channels, isInterlaced, isTransparent); png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PngDecError, PngDecWarning);
// Create a libpng info structure
auto info_ptr = png_create_info_struct(png_ptr);
struct pngstruct {
const u8* data;
size_t size;
u64 offset;
} pngdata = {
.data = (const u8*)param->pngMemAddr,
.size = param->pngMemSize,
.offset = 0,
};
png_set_read_fn(png_ptr, (void*)&pngdata, [](png_structp ps, png_bytep data, png_size_t len) {
auto pngdata = (pngstruct*)png_get_io_ptr(ps);
::memcpy(data, pngdata->data + pngdata->offset, len);
pngdata->offset += len;
});
// Now call png_read_info with our pngPtr as image handle, and infoPtr to receive the file
// info.
png_read_info(png_ptr, info_ptr);
imageInfo->imageWidth = png_get_image_width(png_ptr, info_ptr);
imageInfo->imageHeight = png_get_image_height(png_ptr, info_ptr);
imageInfo->colorSpace = MapPngColor(png_get_color_type(png_ptr, info_ptr));
imageInfo->bitDepth = png_get_bit_depth(png_ptr, info_ptr);
imageInfo->imageFlag = 0;
if (png_get_interlace_type(png_ptr, info_ptr) == 1) {
imageInfo->imageFlag |= OrbisPngDecImageFlag::ORBIS_PNG_DEC_IMAGE_FLAG_ADAM7_INTERLACE;
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
imageInfo->imageFlag |= ORBIS_PNG_DEC_IMAGE_FLAG_TRNS_CHUNK_EXIST;
}
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
LOG_TRACE(
Lib_Png,
"imageWidth = {} , imageHeight = {} , colorSpace = {} , bitDepth = {} , imageFlag = {}",
imageInfo->imageWidth, imageInfo->imageHeight, imageInfo->colorSpace, imageInfo->bitDepth,
imageInfo->imageFlag);
return ORBIS_OK; return ORBIS_OK;
} }
@ -149,9 +264,7 @@ s32 PS4_SYSV_ABI scePngDecQueryMemorySize(const OrbisPngDecCreateParam* param) {
LOG_ERROR(Lib_Png, "Invalid size! width = {}", param->maxImageWidth); LOG_ERROR(Lib_Png, "Invalid size! width = {}", param->maxImageWidth);
return ORBIS_PNG_DEC_ERROR_INVALID_SIZE; return ORBIS_PNG_DEC_ERROR_INVALID_SIZE;
} }
int ret = return sizeof(PngHandler);
(8 << ((u8)param->attribute & 0x1f)) * (param->maxImageWidth + 0x47U & 0xfffffff8) + 0xd090;
return ret;
} }
void RegisterlibScePngDec(Core::Loader::SymbolsResolver* sym) { void RegisterlibScePngDec(Core::Loader::SymbolsResolver* sym) {

View File

@ -8,54 +8,55 @@
namespace Core::Loader { namespace Core::Loader {
class SymbolsResolver; class SymbolsResolver;
} }
namespace Libraries::PngDec { namespace Libraries::PngDec {
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_ADDR = 0x80690001; enum OrbisPngDecColorSpace {
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_SIZE = 0x80690002;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_PARAM = 0x80690003;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_HANDLE = 0x80690004;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_WORK_MEMORY = 0x80690005;
constexpr int ORBIS_PNG_DEC_ERROR_INVALID_DATA = 0x80690010;
constexpr int ORBIS_PNG_DEC_ERROR_UNSUPPORT_DATA = 0x80690011;
constexpr int ORBIS_PNG_DEC_ERROR_DECODE_ERROR = 0x80690012;
constexpr int ORBIS_PNG_DEC_ERROR_FATAL = 0x80690020;
typedef struct OrbisPngDecParseParam {
const void* pngMemAddr;
u32 pngMemSize;
u32 reserved;
} OrbisPngDecParseParam;
typedef struct OrbisPngDecImageInfo {
u32 imageWidth;
u32 imageHeight;
u16 colorSpace;
u16 bitDepth;
u32 imageFlag;
} OrbisPngDecImageInfo;
typedef enum OrbisPngDecColorSpace {
ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE = 2, ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE = 2,
ORBIS_PNG_DEC_COLOR_SPACE_RGB, ORBIS_PNG_DEC_COLOR_SPACE_RGB,
ORBIS_PNG_DEC_COLOR_SPACE_CLUT, ORBIS_PNG_DEC_COLOR_SPACE_CLUT,
ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE_ALPHA = 18, ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE_ALPHA = 18,
ORBIS_PNG_DEC_COLOR_SPACE_RGBA ORBIS_PNG_DEC_COLOR_SPACE_RGBA
} ScePngDecColorSpace; };
typedef enum OrbisPngDecImageFlag { enum OrbisPngDecImageFlag {
ORBIS_PNG_DEC_IMAGE_FLAG_ADAM7_INTERLACE = 1, ORBIS_PNG_DEC_IMAGE_FLAG_ADAM7_INTERLACE = 1,
ORBIS_PNG_DEC_IMAGE_FLAG_TRNS_CHUNK_EXIST = 2 ORBIS_PNG_DEC_IMAGE_FLAG_TRNS_CHUNK_EXIST = 2
} OrbisPngDecImageFlag; };
typedef struct OrbisPngDecCreateParam { enum OrbisPngDecPixelFormat {
ORBIS_PNG_DEC_PIXEL_FORMAT_R8G8B8A8 = 0,
ORBIS_PNG_DEC_PIXEL_FORMAT_B8G8R8A8
};
enum OrbisPngDecAttribute {
ORBIS_PNG_DEC_ATTRIBUTE_NONE = 0,
ORBIS_PNG_DEC_ATTRIBUTE_BIT_DEPTH_16
};
struct OrbisPngDecParseParam {
const void* pngMemAddr;
u32 pngMemSize;
u32 reserved;
};
struct OrbisPngDecImageInfo {
u32 imageWidth;
u32 imageHeight;
u16 colorSpace;
u16 bitDepth;
u32 imageFlag;
};
struct OrbisPngDecCreateParam {
u32 thisSize; u32 thisSize;
u32 attribute; u32 attribute;
u32 maxImageWidth; u32 maxImageWidth;
} OrbisPngDecCreateParam; };
typedef void* OrbisPngDecHandle; typedef void* OrbisPngDecHandle;
typedef struct OrbisPngDecDecodeParam { struct OrbisPngDecDecodeParam {
const void* pngMemAddr; const void* pngMemAddr;
void* imageMemAddr; void* imageMemAddr;
u32 pngMemSize; u32 pngMemSize;
@ -63,7 +64,7 @@ typedef struct OrbisPngDecDecodeParam {
u16 pixelFormat; u16 pixelFormat;
u16 alphaValue; u16 alphaValue;
u32 imagePitch; u32 imagePitch;
} OrbisPngDecDecodeParam; };
s32 PS4_SYSV_ABI scePngDecCreate(const OrbisPngDecCreateParam* param, void* memoryAddress, s32 PS4_SYSV_ABI scePngDecCreate(const OrbisPngDecCreateParam* param, void* memoryAddress,
u32 memorySize, OrbisPngDecHandle* handle); u32 memorySize, OrbisPngDecHandle* handle);