Files
ExPkg/expkg/src/BinaryOPT/ImageReader.cpp
2025-08-06 18:06:30 +08:00

266 lines
8.9 KiB
C++

//
// Created by sfd on 25-8-5.
//
#include "ImageReader.h"
#include <iostream>
#include "lz4.h"
namespace PKG
{
#include <vector>
std::vector<unsigned char> Lz4Decompress(const unsigned char* compressedData,
size_t compressedSize,
size_t decompressedSize)
{
// 准备输出缓冲区
std::vector<unsigned char> output(decompressedSize);
// 执行解压缩
int result = LZ4_decompress_safe(
reinterpret_cast<const char*>(compressedData),
reinterpret_cast<char*>(output.data()),
static_cast<int>(compressedSize),
static_cast<int>(decompressedSize)
);
// 检查解压结果
if (result < 0 || static_cast<size_t>(result) != decompressedSize) {
throw std::runtime_error("LZ4 decompression failed");
}
return output;
}
TexImage ImageReader::ReadFrom(BinaryReader& reader, const TexImageContainer& container, const TexFormat format)
{
int mipMapCount = reader.ReadInt32();
auto aFormat = GetFormatFromTex(container.ImageFormat, format);
TexImage image{};
for (int i = 0; i < mipMapCount; i++)
{
TexMipMap mipmap;
switch (container.ImageContainerVersion)
{
case ImageContainerVersion::VERSION1:
mipmap = ReadMipMapV1(reader); break;
case ImageContainerVersion::VERSION2:
case ImageContainerVersion::VERSION3:
mipmap = ReadMipMapV2AndV3(reader); break;
case ImageContainerVersion::VERSION4:
mipmap = ReadMipMapV4(reader); break;
}
mipmap.Format = aFormat;
if (mipmap.IsZ4Compressed)
{
mipmap.Data = Lz4Decompress(mipmap.Data.data(), mipmap.Data.size(), mipmap.DecompressedDataCount);
mipmap.IsZ4Compressed = false;
}
image.Mipmaps.push_back(mipmap);
}
return image;
}
TexImageContainer ImageReader::ImageContainerReaderReadFrom(BinaryReader& reader, TexFormat texFormat)
{
TexImageContainer container;
container.Magic = reader.ReadNString();
int imageCount = reader.ReadInt32();
if (container.Magic == "TEXB0001")
{
}
else if (container.Magic == "TEXB0002")
{
}
else if (container.Magic == "TEXB0003")
{
container.ImageFormat = (FreeImageFormat)reader.ReadInt32();
}
else if (container.Magic == "TEXB0004")
{
auto format = (FreeImageFormat)reader.ReadInt32();
bool isVideoMp4 = reader.ReadInt32();
if (format == FreeImageFormat::FIF_UNKNOWN)
{
if (isVideoMp4)
format = FreeImageFormat::FIF_MP4;
}
container.ImageFormat = format;
}
else
{
std::cerr << "bad image format" << std::endl;
}
int version = std::stoi(container.Magic.substr(4, 4));
container.ImageContainerVersion = (ImageContainerVersion)version;
if (container.ImageContainerVersion == ImageContainerVersion::VERSION4 && container.ImageFormat != FreeImageFormat::FIF_MP4)
{
container.ImageContainerVersion = ImageContainerVersion::VERSION3;
}
for (int i = 0; i < imageCount; i++)
{
container.Images.push_back(ReadFrom(reader, container, texFormat));
}
return container;
}
TexMipMap ImageReader::ReadMipMapV1(BinaryReader& reader)
{
TexMipMap mipmap{};
mipmap.Width = reader.ReadInt32();
mipmap.Height = reader.ReadInt32();
mipmap.Data = ReadBytes(reader);
return mipmap;
}
TexMipMap ImageReader::ReadMipMapV2AndV3(BinaryReader& reader)
{
TexMipMap mipmap{};
mipmap.Width = reader.ReadInt32();
mipmap.Height = reader.ReadInt32();
mipmap.IsZ4Compressed = reader.ReadInt32() == 1;
mipmap.DecompressedDataCount = reader.ReadInt32();
mipmap.Data = ReadBytes(reader);
return mipmap;
}
TexMipMap ImageReader::ReadMipMapV4(BinaryReader& reader)
{
int param1 = reader.ReadInt32();
if (param1 != 1)
{
std::cerr << "ReadMipmapV4 unknow param1: " << param1 << std::endl;
}
int param2 = reader.ReadInt32();
if (param2 != 2)
{
std::cerr << "ReadMipmapV4 unknow param2: " << param1 << std::endl;
}
std::string condition = reader.ReadNString();
int param3 = reader.ReadInt32();
if (param3 != 1)
{
std::cerr << "ReadMipmapV4 unknow param3: " << param1 << std::endl;
}
TexMipMap mipmap{};
mipmap.Width = reader.ReadInt32();
mipmap.Height = reader.ReadInt32();
mipmap.IsZ4Compressed = reader.ReadInt32() == 1;
mipmap.DecompressedDataCount = reader.ReadInt32();
mipmap.Data = ReadBytes(reader);
return mipmap;
}
std::vector<uint8_t> ImageReader::ReadBytes(BinaryReader& reader)
{
int count = reader.ReadInt32();
std::vector<uint8_t> bytes;
reader.ReadData(bytes, count);
return bytes;
}
MipmapFormat ImageReader::GetFormatFromTex(FreeImageFormat imageFormat, TexFormat format)
{
if (imageFormat != FreeImageFormat::FIF_UNKNOWN)
{
return FreeImageFormatToMipmapFormat(imageFormat);
}
switch (format)
{
case TexFormat::RGBA8888: return MipmapFormat::RGBA8888;
case TexFormat::DXT5: return MipmapFormat::CompressedDXT5;
case TexFormat::DXT3: return MipmapFormat::CompressedDXT3;
case TexFormat::DXT1: return MipmapFormat::CompressedDXT1;
case TexFormat::RG88: return MipmapFormat::RG88;
case TexFormat::R8: return MipmapFormat::R8;
}
std::cerr << "unknow format" << std::endl;
return MipmapFormat::Invalid;
}
MipmapFormat ImageReader::FreeImageFormatToMipmapFormat(FreeImageFormat imageFormat)
{
switch (imageFormat)
{
case FreeImageFormat::FIF_BMP: return MipmapFormat::ImageBMP;
case FreeImageFormat::FIF_ICO: return MipmapFormat::ImageICO;
case FreeImageFormat::FIF_JPEG: return MipmapFormat::ImageJPEG;
case FreeImageFormat::FIF_JNG: return MipmapFormat::ImageJNG;
case FreeImageFormat::FIF_KOALA: return MipmapFormat::ImageKOALA;
case FreeImageFormat::FIF_LBM: return MipmapFormat::ImageLBM;
case FreeImageFormat::FIF_MNG: return MipmapFormat::ImageMNG;
case FreeImageFormat::FIF_PBM: return MipmapFormat::ImagePBM;
case FreeImageFormat::FIF_PBMRAW: return MipmapFormat::ImagePBMRAW;
case FreeImageFormat::FIF_PCD: return MipmapFormat::ImagePCD;
case FreeImageFormat::FIF_PCX: return MipmapFormat::ImagePCX;
case FreeImageFormat::FIF_PGM: return MipmapFormat::ImagePGM;
case FreeImageFormat::FIF_PGMRAW: return MipmapFormat::ImagePGMRAW;
case FreeImageFormat::FIF_PNG: return MipmapFormat::ImagePNG;
case FreeImageFormat::FIF_PPM: return MipmapFormat::ImagePPM;
case FreeImageFormat::FIF_PPMRAW: return MipmapFormat::ImagePPMRAW;
case FreeImageFormat::FIF_RAS: return MipmapFormat::ImageRAS;
case FreeImageFormat::FIF_TARGA: return MipmapFormat::ImageTARGA;
case FreeImageFormat::FIF_TIFF: return MipmapFormat::ImageTIFF;
case FreeImageFormat::FIF_WBMP: return MipmapFormat::ImageWBMP;
case FreeImageFormat::FIF_PSD: return MipmapFormat::ImagePSD;
case FreeImageFormat::FIF_CUT: return MipmapFormat::ImageCUT;
case FreeImageFormat::FIF_XBM: return MipmapFormat::ImageXBM;
case FreeImageFormat::FIF_XPM: return MipmapFormat::ImageXPM;
case FreeImageFormat::FIF_DDS: return MipmapFormat::ImageDDS;
case FreeImageFormat::FIF_GIF: return MipmapFormat::ImageGIF;
case FreeImageFormat::FIF_HDR: return MipmapFormat::ImageHDR;
case FreeImageFormat::FIF_FAXG3: return MipmapFormat::ImageFAXG3;
case FreeImageFormat::FIF_SGI: return MipmapFormat::ImageSGI;
case FreeImageFormat::FIF_EXR: return MipmapFormat::ImageEXR;
case FreeImageFormat::FIF_J2K: return MipmapFormat::ImageJ2K;
case FreeImageFormat::FIF_JP2: return MipmapFormat::ImageJP2;
case FreeImageFormat::FIF_PFM: return MipmapFormat::ImagePFM;
case FreeImageFormat::FIF_PICT: return MipmapFormat::ImagePICT;
case FreeImageFormat::FIF_RAW: return MipmapFormat::ImageRAW;
case FreeImageFormat::FIF_MP4: return MipmapFormat::VideoMp4;
}
std::cerr << "unknown format" << std::endl;
return MipmapFormat::Invalid;
}
}