* Copyright 2006, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <zlib.h>
#include <Bitmap.h>
#include <Message.h>
enum {
COMPRESSION_NONE = 0,
COMPRESSION_ZLIB = 2,
};
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) {
if ((unsigned)ceilf(srcLength * 1.01) + 12 != *size) {
void* tmpBuffer = realloc(*buffer, *size);
if (tmpBuffer) {
*buffer = tmpBuffer;
result = true;
}
}
}
if (ret != Z_OK || !result) {
free(*buffer);
*buffer = NULL;
*size = 0;
fprintf(stderr, "zlib compression error: %d\n", ret);
}
} else
*size = 0;
}
return result;
}
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()) {
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;
}
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;
}
status_t
extract_bitmap(BBitmap** bitmap, const BMessage* from, const char* fieldName)
{
status_t ret = B_BAD_VALUE;
if (bitmap && from) {
*bitmap = NULL;
BMessage bitmapArchive;
if ((ret = from->FindMessage(fieldName, &bitmapArchive)) >= B_OK) {
*bitmap = new BBitmap(&bitmapArchive);
}
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
|| (ret = from->FindData("current compressed data",
B_RAW_TYPE, &compressedData,
&compressedSize)) >= B_OK)
&& (ret = from->FindRect("construction bounds",
&bounds)) >= B_OK) {
if (from->FindInt32("compression", (int32*)&compression) < B_OK)
compression = COMPRESSION_NONE;
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;
}