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
compress_bitmap_zlib(const BBitmap * bitmap,void ** buffer,unsigned * size)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*
decompress_bitmap_zlib(const void * buffer,unsigned int size,BRect frame,color_space format)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
archive_bitmap(const BBitmap * bitmap,BMessage * into,const char * fieldName)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
extract_bitmap(BBitmap ** bitmap,const BMessage * from,const char * fieldName)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