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 free(buffer); 105 } 106 } 107 return ret; 108 } 109 110 // extract_bitmap 111 status_t 112 extract_bitmap(BBitmap** bitmap, const BMessage* from, const char* fieldName) 113 { 114 status_t ret = B_BAD_VALUE; 115 if (bitmap && from) { 116 *bitmap = NULL; 117 // no compression (flattened BBitmap archive) 118 BMessage bitmapArchive; 119 if ((ret = from->FindMessage(fieldName, &bitmapArchive)) >= B_OK) { 120 *bitmap = new BBitmap(&bitmapArchive); 121 } 122 // compression 123 if (!*bitmap) { 124 const void* compressedData = NULL; 125 ssize_t compressedSize = 0; 126 compressedData = NULL; 127 compressedSize = 0; 128 BRect bounds; 129 color_space format; 130 uint32 compression; 131 if (((ret = from->FindData(fieldName, 132 B_RAW_TYPE, &compressedData, 133 &compressedSize)) >= B_OK 134 // this is for backward compatibility 135 || (ret = from->FindData("current compressed data", 136 B_RAW_TYPE, &compressedData, 137 &compressedSize)) >= B_OK) 138 && (ret = from->FindRect("construction bounds", 139 &bounds)) >= B_OK) { 140 141 // compression defaults to NONE for backward compatibility 142 if (from->FindInt32("compression", (int32*)&compression) < B_OK) 143 compression = COMPRESSION_NONE; 144 // format defaults to B_RGBA32 for backward compatibility 145 if (from->FindInt32("format", (int32*)&format) < B_OK) 146 format = B_RGBA32; 147 148 switch (compression) { 149 case COMPRESSION_ZLIB: 150 *bitmap = decompress_bitmap_zlib(compressedData, 151 compressedSize, 152 bounds, format); 153 break; 154 } 155 } 156 } 157 if (*bitmap) 158 ret = (*bitmap)->InitCheck(); 159 else if (ret >= B_OK) 160 ret = B_NO_MEMORY; 161 if (ret < B_OK) { 162 delete *bitmap; 163 *bitmap = NULL; 164 } 165 } 166 return ret; 167 } 168