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", 40 // srcLength, *size, ((float)*size / (float)srcLength) * 100.0); 41 if ((unsigned)ceilf(srcLength * 1.01) + 12 != *size) { 42 void* tmpBuffer = realloc(*buffer, *size); 43 if (tmpBuffer) { 44 *buffer = tmpBuffer; 45 result = true; 46 } 47 } 48 } 49 if (ret != Z_OK || !result) { 50 // error compressing 51 free(*buffer); 52 *buffer = NULL; 53 *size = 0; 54 fprintf(stderr, "zlib compression error: %d\n", ret); 55 } 56 } else 57 *size = 0; 58 } 59 return result; 60 } 61 62 // decompress_bitmap_zlib 63 BBitmap* 64 decompress_bitmap_zlib(const void* buffer, unsigned int size, 65 BRect frame, color_space format) 66 { 67 BBitmap* bitmap = new BBitmap(frame, 0, format); 68 if (bitmap->IsValid()) { 69 if (buffer) { 70 Bytef* dst = (Bytef*)bitmap->Bits(); 71 uLongf dstLength = bitmap->BitsLength(); 72 73 int ret = uncompress(dst, 74 &dstLength, 75 (const Bytef*)buffer, 76 (uLong)size); 77 if (ret != Z_OK || dstLength != (uint32)bitmap->BitsLength()) { 78 // decompression error! 79 fprintf(stderr, "decompress_bitmap_zlib() failed " 80 "- corrupted input buffer or file!\n"); 81 } 82 } else { 83 memset(bitmap->Bits(), 0, bitmap->BitsLength()); 84 } 85 } else { 86 delete bitmap; 87 bitmap = NULL; 88 } 89 return bitmap; 90 } 91 92 93 94 // archive_bitmap 95 status_t 96 archive_bitmap(const BBitmap* bitmap, BMessage* into, const char* fieldName) 97 { 98 status_t ret = B_BAD_VALUE; 99 if (bitmap && bitmap->IsValid() && into) { 100 void* buffer; 101 unsigned size; 102 if (compress_bitmap_zlib(bitmap, &buffer, &size)) { 103 ret = into->AddData(fieldName, B_RAW_TYPE, buffer, size); 104 if (ret >= B_OK) 105 ret = into->AddInt32("compression", COMPRESSION_ZLIB); 106 if (ret >= B_OK) 107 ret = into->AddRect("construction bounds", bitmap->Bounds()); 108 if (ret >= B_OK) 109 ret = into->AddInt32("format", bitmap->ColorSpace()); 110 free(buffer); 111 } 112 } 113 return ret; 114 } 115 116 // extract_bitmap 117 status_t 118 extract_bitmap(BBitmap** bitmap, const BMessage* from, const char* fieldName) 119 { 120 status_t ret = B_BAD_VALUE; 121 if (bitmap && from) { 122 *bitmap = NULL; 123 // no compression (flattened BBitmap archive) 124 BMessage bitmapArchive; 125 if ((ret = from->FindMessage(fieldName, &bitmapArchive)) >= B_OK) { 126 *bitmap = new BBitmap(&bitmapArchive); 127 } 128 // compression 129 if (!*bitmap) { 130 const void* compressedData = NULL; 131 ssize_t compressedSize = 0; 132 compressedData = NULL; 133 compressedSize = 0; 134 BRect bounds; 135 color_space format; 136 uint32 compression; 137 if (((ret = from->FindData(fieldName, 138 B_RAW_TYPE, &compressedData, 139 &compressedSize)) >= B_OK 140 // this is for backward compatibility 141 || (ret = from->FindData("current compressed data", 142 B_RAW_TYPE, &compressedData, 143 &compressedSize)) >= B_OK) 144 && (ret = from->FindRect("construction bounds", 145 &bounds)) >= B_OK) { 146 147 // compression defaults to NONE for backward compatibility 148 if (from->FindInt32("compression", (int32*)&compression) < B_OK) 149 compression = COMPRESSION_NONE; 150 // format defaults to B_RGBA32 for backward compatibility 151 if (from->FindInt32("format", (int32*)&format) < B_OK) 152 format = B_RGBA32; 153 154 switch (compression) { 155 case COMPRESSION_ZLIB: 156 *bitmap = decompress_bitmap_zlib(compressedData, 157 compressedSize, 158 bounds, format); 159 break; 160 } 161 } 162 } 163 if (*bitmap) 164 ret = (*bitmap)->InitCheck(); 165 else if (ret >= B_OK) 166 ret = B_NO_MEMORY; 167 if (ret < B_OK) { 168 delete *bitmap; 169 *bitmap = NULL; 170 } 171 } 172 return ret; 173 } 174