// // Created by sfd on 25-8-5. // #include "ImageReader.h" #include #include "lz4.h" namespace PKG { #include std::vector Lz4Decompress(const unsigned char* compressedData, size_t compressedSize, size_t decompressedSize) { // 准备输出缓冲区 std::vector output(decompressedSize); // 执行解压缩 int result = LZ4_decompress_safe( reinterpret_cast(compressedData), reinterpret_cast(output.data()), static_cast(compressedSize), static_cast(decompressedSize) ); // 检查解压结果 if (result < 0 || static_cast(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 ImageReader::ReadBytes(BinaryReader& reader) { int count = reader.ReadInt32(); std::vector 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; } }