xref: /haiku/src/add-ons/translators/wonderbrush/support/bitmap_compression.cpp (revision 204dee708a999d5a71d0cb9497650ee7cef85d0a)
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