/* * Copyright 2006, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus */ #include #include #include #include #include #include enum { COMPRESSION_NONE = 0, COMPRESSION_ZLIB = 2, }; // compress_bitmap_zlib bool compress_bitmap_zlib(const BBitmap* bitmap, void** buffer, unsigned* size) { bool result = false; if (bitmap) { Bytef* src = (Bytef*)bitmap->Bits(); uLong srcLength = bitmap->BitsLength(); *size = (unsigned)ceilf(srcLength * 1.01) + 12; *buffer = malloc(*size); if (*buffer) { int ret = compress2((Bytef*)*buffer, (uLongf*)size, src, srcLength, 3); if (ret == Z_OK) { // printf("zlib compressed %ld bytes bitmap into %d bytes (%f%%)\n", // srcLength, *size, ((float)*size / (float)srcLength) * 100.0); if ((unsigned)ceilf(srcLength * 1.01) + 12 != *size) { void* tmpBuffer = realloc(*buffer, *size); if (tmpBuffer) { *buffer = tmpBuffer; result = true; } } } if (ret != Z_OK || !result) { // error compressing free(*buffer); *buffer = NULL; *size = 0; fprintf(stderr, "zlib compression error: %d\n", ret); } } else *size = 0; } return result; } // decompress_bitmap_zlib BBitmap* decompress_bitmap_zlib(const void* buffer, unsigned int size, BRect frame, color_space format) { BBitmap* bitmap = new BBitmap(frame, 0, format); if (bitmap->IsValid()) { if (buffer) { Bytef* dst = (Bytef*)bitmap->Bits(); uLongf dstLength = bitmap->BitsLength(); int ret = uncompress(dst, &dstLength, (const Bytef*)buffer, (uLong)size); if (ret != Z_OK || dstLength != (uint32)bitmap->BitsLength()) { // decompression error! fprintf(stderr, "decompress_bitmap_zlib() failed " "- corrupted input buffer or file!\n"); } } else { memset(bitmap->Bits(), 0, bitmap->BitsLength()); } } else { delete bitmap; bitmap = NULL; } return bitmap; } // archive_bitmap status_t archive_bitmap(const BBitmap* bitmap, BMessage* into, const char* fieldName) { status_t ret = B_BAD_VALUE; if (bitmap && bitmap->IsValid() && into) { void* buffer; unsigned size; if (compress_bitmap_zlib(bitmap, &buffer, &size)) { ret = into->AddData(fieldName, B_RAW_TYPE, buffer, size); if (ret >= B_OK) ret = into->AddInt32("compression", COMPRESSION_ZLIB); if (ret >= B_OK) ret = into->AddRect("construction bounds", bitmap->Bounds()); if (ret >= B_OK) ret = into->AddInt32("format", bitmap->ColorSpace()); free(buffer); } } return ret; } // extract_bitmap status_t extract_bitmap(BBitmap** bitmap, const BMessage* from, const char* fieldName) { status_t ret = B_BAD_VALUE; if (bitmap && from) { *bitmap = NULL; // no compression (flattened BBitmap archive) BMessage bitmapArchive; if ((ret = from->FindMessage(fieldName, &bitmapArchive)) >= B_OK) { *bitmap = new BBitmap(&bitmapArchive); } // compression if (!*bitmap) { const void* compressedData = NULL; ssize_t compressedSize = 0; compressedData = NULL; compressedSize = 0; BRect bounds; color_space format; uint32 compression; if (((ret = from->FindData(fieldName, B_RAW_TYPE, &compressedData, &compressedSize)) >= B_OK // this is for backward compatibility || (ret = from->FindData("current compressed data", B_RAW_TYPE, &compressedData, &compressedSize)) >= B_OK) && (ret = from->FindRect("construction bounds", &bounds)) >= B_OK) { // compression defaults to NONE for backward compatibility if (from->FindInt32("compression", (int32*)&compression) < B_OK) compression = COMPRESSION_NONE; // format defaults to B_RGBA32 for backward compatibility if (from->FindInt32("format", (int32*)&format) < B_OK) format = B_RGBA32; switch (compression) { case COMPRESSION_ZLIB: *bitmap = decompress_bitmap_zlib(compressedData, compressedSize, bounds, format); break; } } } if (*bitmap) ret = (*bitmap)->InitCheck(); else if (ret >= B_OK) ret = B_NO_MEMORY; if (ret < B_OK) { delete *bitmap; *bitmap = NULL; } } return ret; }