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