CXBTFFrame appendContent(CXBTFWriter &writer, int width, int height, unsigned char *data, unsigned int size, unsigned int format, bool hasAlpha, unsigned int flags) { CXBTFFrame frame; #ifdef USE_LZO_PACKING lzo_uint packedSize = size; if ((flags & FLAGS_USE_LZO) == FLAGS_USE_LZO) { // grab a temporary buffer for unpacking into packedSize = size + size / 16 + 64 + 3; // see simple.c in lzo unsigned char *packed = new unsigned char[packedSize]; unsigned char *working = new unsigned char[LZO1X_999_MEM_COMPRESS]; if (packed && working) { if (lzo1x_999_compress(data, size, packed, &packedSize, working) != LZO_E_OK || packedSize > size) { // compression failed, or compressed size is bigger than uncompressed, so store as uncompressed packedSize = size; writer.AppendContent(data, size); } else { // success lzo_uint optimSize = size; if (lzo1x_optimize(packed, packedSize, data, &optimSize, NULL) != LZO_E_OK || optimSize != size) { //optimisation failed packedSize = size; writer.AppendContent(data, size); } else { // success writer.AppendContent(packed, packedSize); } } delete[] working; delete[] packed; } } else #else unsigned int packedSize = size; #endif { writer.AppendContent(data, size); } frame.SetPackedSize(packedSize); frame.SetUnpackedSize(size); frame.SetWidth(width); frame.SetHeight(height); frame.SetFormat(hasAlpha ? format : format | XB_FMT_OPAQUE); frame.SetDuration(0); return frame; }
CXBTFFrame appendContent(CXBTFWriter &writer, int width, int height, unsigned char *data, unsigned int size, unsigned int format, unsigned int flags) { CXBTFFrame frame; lzo_uint compressedSize = size; if ((flags & FLAGS_USE_LZO) == FLAGS_USE_LZO) { // grab a temporary buffer for unpacking into squish::u8 *compressed = new squish::u8[size + size / 16 + 64 + 3]; // see simple.c in lzo squish::u8 *working = new squish::u8[LZO1X_999_MEM_COMPRESS]; if (compressed && working) { if (lzo1x_999_compress(data, size, compressed, (lzo_uint*)&compressedSize, working) != LZO_E_OK || compressedSize > size) { // compression failed, or compressed size is bigger than uncompressed, so store as uncompressed compressedSize = size; writer.AppendContent(data, size); } else { // success lzo_uint optimSize = size; lzo1x_optimize(compressed, compressedSize, data, &optimSize, NULL); writer.AppendContent(compressed, compressedSize); } delete[] working; delete[] compressed; } } else { writer.AppendContent(data, size); } frame.SetPackedSize(compressedSize); frame.SetUnpackedSize(size); frame.SetWidth(width); frame.SetHeight(height); frame.SetFormat(format); frame.SetDuration(0); return frame; }
int createBundle(const std::string& InputDir, const std::string& OutputFile, double maxMSE, unsigned int flags, bool dupecheck) { CXBTFWriter writer(OutputFile); if (!writer.Create()) { fprintf(stderr, "Error creating file\n"); return 1; } map<string,unsigned int> hashes; vector<unsigned int> dupes; CreateSkeletonHeader(writer, InputDir); std::vector<CXBTFFile> files = writer.GetFiles(); dupes.resize(files.size()); if (!dupecheck) { for (unsigned int i=0;i<dupes.size();++i) dupes[i] = i; } for (size_t i = 0; i < files.size(); i++) { struct MD5Context ctx; MD5Init(&ctx); CXBTFFile& file = files[i]; std::string fullPath = InputDir; fullPath += file.GetPath(); std::string output = file.GetPath(); output = output.substr(0, 40); while (output.size() < 46) output += ' '; DecodedFrames frames; bool loaded = DecoderManager::LoadFile(fullPath, frames); if (!loaded) { fprintf(stderr, "...unable to load image %s\n", file.GetPath().c_str()); continue; } printf("%s\n", output.c_str()); bool skip=false; if (dupecheck) { for (unsigned int j = 0; j < frames.frameList.size(); j++) MD5Update(&ctx, (const uint8_t*)frames.frameList[j].rgbaImage.pixels, frames.frameList[j].rgbaImage.height * frames.frameList[j].rgbaImage.pitch); if (checkDupe(&ctx,hashes,dupes,i)) { printf("**** duplicate of %s\n", files[dupes[i]].GetPath().c_str()); file.GetFrames().insert(file.GetFrames().end(), files[dupes[i]].GetFrames().begin(), files[dupes[i]].GetFrames().end()); skip = true; } } if (!skip) { for (unsigned int j = 0; j < frames.frameList.size(); j++) { printf(" frame %4i (delay:%4i) ", j, frames.frameList[j].delay); CXBTFFrame frame = createXBTFFrame(frames.frameList[j].rgbaImage, writer, maxMSE, flags); frame.SetDuration(frames.frameList[j].delay); file.GetFrames().push_back(frame); printf("%s%c (%d,%d @ %" PRIu64 " bytes)\n", GetFormatString(frame.GetFormat()), frame.HasAlpha() ? ' ' : '*', frame.GetWidth(), frame.GetHeight(), frame.GetUnpackedSize()); } } DecoderManager::FreeDecodedFrames(frames); file.SetLoop(0); writer.UpdateFile(file); } if (!writer.UpdateHeader(dupes)) { fprintf(stderr, "Error writing header to file\n"); return 1; } if (!writer.Close()) { fprintf(stderr, "Error closing file\n"); return 1; } return 0; }
bool CXBTFReader::Open(const std::string& path) { if (path.empty()) return false; m_path = path; #ifdef TARGET_WINDOWS std::wstring strPathW; g_charsetConverter.utf8ToW(CSpecialProtocol::TranslatePath(m_path), strPathW, false); m_file = _wfopen(strPathW.c_str(), L"rb"); #else m_file = fopen(m_path.c_str(), "rb"); #endif if (m_file == nullptr) return false; // read the magic word char magic[4]; if (!ReadString(m_file, magic, sizeof(magic))) return false; if (strncmp(XBTF_MAGIC.c_str(), magic, sizeof(magic)) != 0) return false; // read the version char version[1]; if (!ReadString(m_file, version, sizeof(version))) return false; if (strncmp(XBTF_VERSION.c_str(), version, sizeof(version)) != 0) return false; unsigned int nofFiles; if (!ReadUInt32(m_file, nofFiles)) return false; for (uint32_t i = 0; i < nofFiles; i++) { CXBTFFile xbtfFile; uint32_t u32; uint64_t u64; char path[CXBTFFile::MaximumPathLength]; memset(path, 0, sizeof(path)); if (!ReadString(m_file, path, sizeof(path))) return false; xbtfFile.SetPath(path); if (!ReadUInt32(m_file, u32)) return false; xbtfFile.SetLoop(u32); unsigned int nofFrames; if (!ReadUInt32(m_file, nofFrames)) return false; for (uint32_t j = 0; j < nofFrames; j++) { CXBTFFrame frame; if (!ReadUInt32(m_file, u32)) return false; frame.SetWidth(u32); if (!ReadUInt32(m_file, u32)) return false; frame.SetHeight(u32); if (!ReadUInt32(m_file, u32)) return false; frame.SetFormat(u32); if (!ReadUInt64(m_file, u64)) return false; frame.SetPackedSize(u64); if (!ReadUInt64(m_file, u64)) return false; frame.SetUnpackedSize(u64); if (!ReadUInt32(m_file, u32)) return false; frame.SetDuration(u32); if (!ReadUInt64(m_file, u64)) return false; frame.SetOffset(u64); xbtfFile.GetFrames().push_back(frame); } AddFile(xbtfFile); } // Sanity check uint64_t pos = static_cast<uint64_t>(ftell(m_file)); if (pos != GetHeaderSize()) return false; return true; }
bool CXBTFReader::Open(const std::string& fileName) { m_fileName = fileName; #ifdef TARGET_WINDOWS std::wstring strPathW; g_charsetConverter.utf8ToW(CSpecialProtocol::TranslatePath(m_fileName), strPathW, false); m_file = _wfopen(strPathW.c_str(), L"rb"); #else m_file = fopen(m_fileName.c_str(), "rb"); #endif if (m_file == NULL) { return false; } char magic[4]; READ_STR(magic, 4, m_file); if (strncmp(magic, XBTF_MAGIC, sizeof(magic)) != 0) { return false; } char version[1]; READ_STR(version, 1, m_file); if (strncmp(version, XBTF_VERSION, sizeof(version)) != 0) { return false; } unsigned int nofFiles; READ_U32(nofFiles, m_file); for (unsigned int i = 0; i < nofFiles; i++) { CXBTFFile file; unsigned int u32; uint64_t u64; READ_STR(file.GetPath(), 256, m_file); READ_U32(u32, m_file); file.SetLoop(u32); unsigned int nofFrames; READ_U32(nofFrames, m_file); for (unsigned int j = 0; j < nofFrames; j++) { CXBTFFrame frame; READ_U32(u32, m_file); frame.SetWidth(u32); READ_U32(u32, m_file); frame.SetHeight(u32); READ_U32(u32, m_file); frame.SetFormat(u32); READ_U64(u64, m_file); frame.SetPackedSize(u64); READ_U64(u64, m_file); frame.SetUnpackedSize(u64); READ_U32(u32, m_file); frame.SetDuration(u32); READ_U64(u64, m_file); frame.SetOffset(u64); file.GetFrames().push_back(frame); } m_xbtf.GetFiles().push_back(file); m_filesMap[file.GetPath()] = file; } // Sanity check int64_t pos = ftell(m_file); if (pos != (int64_t)m_xbtf.GetHeaderSize()) { printf("Expected header size (%" PRId64") != actual size (%" PRId64")\n", m_xbtf.GetHeaderSize(), pos); return false; } return true; }
int createBundle(const std::string& InputDir, const std::string& OutputFile, double maxMSE, unsigned int flags, bool dupecheck) { map<string,unsigned int> hashes; vector<unsigned int> dupes; CXBTF xbtf; CreateSkeletonHeader(xbtf, InputDir); dupes.resize(xbtf.GetFiles().size()); if (!dupecheck) { for (unsigned int i=0;i<dupes.size();++i) dupes[i] = i; } CXBTFWriter writer(xbtf, OutputFile); if (!writer.Create()) { printf("Error creating file\n"); return 1; } std::vector<CXBTFFile>& files = xbtf.GetFiles(); for (size_t i = 0; i < files.size(); i++) { struct MD5Context ctx; MD5Init(&ctx); CXBTFFile& file = files[i]; std::string fullPath = InputDir; fullPath += file.GetPath(); std::string output = file.GetPath(); output = output.substr(0, 40); while (output.size() < 46) output += ' '; if (!IsGIF(fullPath.c_str())) { // Load the image SDL_Surface* image = IMG_Load(fullPath.c_str()); if (!image) { printf("...unable to load image %s\n", file.GetPath()); continue; } bool skip=false; printf("%s", output.c_str()); if (dupecheck) { MD5Update(&ctx,(const uint8_t*)image->pixels,image->h*image->pitch); if (checkDupe(&ctx,hashes,dupes,i)) { printf("**** duplicate of %s\n", files[dupes[i]].GetPath()); file.GetFrames().insert(file.GetFrames().end(), files[dupes[i]].GetFrames().begin(), files[dupes[i]].GetFrames().end()); skip = true; } } if (!skip) { CXBTFFrame frame = createXBTFFrame(image, writer, maxMSE, flags); printf("%s%c (%d,%d @ %"PRIu64" bytes)\n", GetFormatString(frame.GetFormat()), frame.HasAlpha() ? ' ' : '*', frame.GetWidth(), frame.GetHeight(), frame.GetUnpackedSize()); file.SetLoop(0); file.GetFrames().push_back(frame); } SDL_FreeSurface(image); } else { int gnAG = AG_LoadGIF(fullPath.c_str(), NULL, 0); AG_Frame* gpAG = new AG_Frame[gnAG]; AG_LoadGIF(fullPath.c_str(), gpAG, gnAG); printf("%s\n", output.c_str()); bool skip=false; if (dupecheck) { for (int j = 0; j < gnAG; j++) MD5Update(&ctx, (const uint8_t*)gpAG[j].surface->pixels, gpAG[j].surface->h * gpAG[j].surface->pitch); if (checkDupe(&ctx,hashes,dupes,i)) { printf("**** duplicate of %s\n", files[dupes[i]].GetPath()); file.GetFrames().insert(file.GetFrames().end(), files[dupes[i]].GetFrames().begin(), files[dupes[i]].GetFrames().end()); skip = true; } } if (!skip) { for (int j = 0; j < gnAG; j++) { printf(" frame %4i ", j); CXBTFFrame frame = createXBTFFrame(gpAG[j].surface, writer, maxMSE, flags); frame.SetDuration(gpAG[j].delay); file.GetFrames().push_back(frame); printf("%s%c (%d,%d @ %"PRIu64" bytes)\n", GetFormatString(frame.GetFormat()), frame.HasAlpha() ? ' ' : '*', frame.GetWidth(), frame.GetHeight(), frame.GetUnpackedSize()); } } AG_FreeSurfaces(gpAG, gnAG); delete [] gpAG; file.SetLoop(0); } } if (!writer.UpdateHeader(dupes)) { printf("Error writing header to file\n"); return 1; } if (!writer.Close()) { printf("Error closing file\n"); return 1; } return 0; }