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