1 /* 2 * Copyright 2006, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include <malloc.h> 10 #include <stdio.h> 11 #include <string.h> 12 #include <zlib.h> 13 14 #include <Bitmap.h> 15 #include <Message.h> 16 17 enum { 18 COMPRESSION_NONE = 0, 19 COMPRESSION_ZLIB = 2, 20 }; 21 22 // compress_bitmap_zlib 23 bool 24 compress_bitmap_zlib(const BBitmap* bitmap, void** buffer, unsigned* size) 25 { 26 bool result = false; 27 if (bitmap) { 28 Bytef* src = (Bytef*)bitmap->Bits(); 29 uLong srcLength = bitmap->BitsLength(); 30 *size = (unsigned)ceilf(srcLength * 1.01) + 12; 31 *buffer = malloc(*size); 32 if (*buffer) { 33 int ret = compress2((Bytef*)*buffer, 34 (uLongf*)size, 35 src, 36 srcLength, 37 3); 38 if (ret == Z_OK) { 39 //printf("zlib compressed %ld bytes bitmap into %d bytes (%f%%)\n", srcLength, *size, ((float)*size / (float)srcLength) * 100.0); 40 if ((unsigned)ceilf(srcLength * 1.01) + 12 != *size) 41 *buffer = realloc(*buffer, *size); 42 result = true; 43 } else { 44 // error compressing 45 free(*buffer); 46 *buffer = NULL; 47 *size = 0; 48 fprintf(stderr, "zlib compression error: %d\n", ret); 49 } 50 } else 51 *size = 0; 52 } 53 return result; 54 } 55 56 // decompress_bitmap_zlib 57 BBitmap* 58 decompress_bitmap_zlib(const void* buffer, unsigned int size, 59 BRect frame, color_space format) 60 { 61 BBitmap* bitmap = new BBitmap(frame, 0, format); 62 if (bitmap->IsValid()) { 63 if (buffer) { 64 Bytef* dst = (Bytef*)bitmap->Bits(); 65 uLongf dstLength = bitmap->BitsLength(); 66 67 int ret = uncompress(dst, 68 &dstLength, 69 (const Bytef*)buffer, 70 (uLong)size); 71 if (ret != Z_OK || dstLength != (uint32)bitmap->BitsLength()) { 72 // decompression error! 73 fprintf(stderr, "decompress_bitmap_zlib() failed " 74 "- corrupted input buffer or file!\n"); 75 } 76 } else { 77 memset(bitmap->Bits(), 0, bitmap->BitsLength()); 78 } 79 } else { 80 delete bitmap; 81 bitmap = NULL; 82 } 83 return bitmap; 84 } 85 86 87 88 // archive_bitmap 89 status_t 90 archive_bitmap(const BBitmap* bitmap, BMessage* into, const char* fieldName) 91 { 92 status_t ret = B_BAD_VALUE; 93 if (bitmap && bitmap->IsValid() && into) { 94 void* buffer; 95 unsigned size; 96 if (compress_bitmap_zlib(bitmap, &buffer, &size)) { 97 ret = into->AddData(fieldName, B_RAW_TYPE, buffer, size); 98 if (ret >= B_OK) 99 ret = into->AddInt32("compression", COMPRESSION_ZLIB); 100 if (ret >= B_OK) 101 ret = into->AddRect("construction bounds", bitmap->Bounds()); 102 if (ret >= B_OK) 103 ret = into->AddInt32("format", bitmap->ColorSpace()); 104 } 105 } 106 return ret; 107 } 108 109 // extract_bitmap 110 status_t 111 extract_bitmap(BBitmap** bitmap, const BMessage* from, const char* fieldName) 112 { 113 status_t ret = B_BAD_VALUE; 114 if (bitmap && from) { 115 *bitmap = NULL; 116 // no compression (flattened BBitmap archive) 117 BMessage bitmapArchive; 118 if ((ret = from->FindMessage(fieldName, &bitmapArchive)) >= B_OK) { 119 *bitmap = new BBitmap(&bitmapArchive); 120 } 121 // compression 122 if (!*bitmap) { 123 const void* compressedData = NULL; 124 ssize_t compressedSize = 0; 125 compressedData = NULL; 126 compressedSize = 0; 127 BRect bounds; 128 color_space format; 129 uint32 compression; 130 if (((ret = from->FindData(fieldName, 131 B_RAW_TYPE, &compressedData, 132 &compressedSize)) >= B_OK 133 // this is for backward compatibility 134 || (ret = from->FindData("current compressed data", 135 B_RAW_TYPE, &compressedData, 136 &compressedSize)) >= B_OK) 137 && (ret = from->FindRect("construction bounds", 138 &bounds)) >= B_OK) { 139 140 // compression defaults to NONE for backward compatibility 141 if (from->FindInt32("compression", (int32*)&compression) < B_OK) 142 compression = COMPRESSION_NONE; 143 // format defaults to B_RGBA32 for backward compatibility 144 if (from->FindInt32("format", (int32*)&format) < B_OK) 145 format = B_RGBA32; 146 147 switch (compression) { 148 case COMPRESSION_ZLIB: 149 *bitmap = decompress_bitmap_zlib(compressedData, 150 compressedSize, 151 bounds, format); 152 break; 153 } 154 } 155 } 156 if (*bitmap) 157 ret = (*bitmap)->InitCheck(); 158 else if (ret >= B_OK) 159 ret = B_NO_MEMORY; 160 if (ret < B_OK) { 161 delete *bitmap; 162 *bitmap = NULL; 163 } 164 } 165 return ret; 166 } 167