xref: /haiku/src/add-ons/translators/icns/ICNSLoader.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
1 /*
2  * Copyright 2012, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "ICNSLoader.h"
7 #include "BaseTranslator.h"
8 
9 
10 static int compareTypes(const void *a, const void *b)
11 {
12 	icns_type_t **typeItemA = (icns_type_t**)a;
13 	icns_type_t **typeItemB = (icns_type_t**)b;
14 
15 	icns_icon_info_t imageInfoA = icns_get_image_info_for_type(**typeItemA);
16 	icns_icon_info_t imageInfoB = icns_get_image_info_for_type(**typeItemB);
17 
18 	return imageInfoB.iconWidth - imageInfoA.iconWidth;
19 }
20 
21 
22 icns_type_t
23 ICNSFormat(float width, float height, color_space colors)
24 {
25 	int imageWidth = (int)ceil(width);
26 	int imageHeight = (int)ceil(height);
27 
28 	if (imageWidth != imageHeight)
29 		return ICNS_NULL_TYPE;
30 
31 	//other colors depth not supported now
32 	if (colors != B_RGB32 && colors != B_RGBA32)
33 		return ICNS_NULL_TYPE;
34 
35 	switch (imageWidth) {
36 		case 16:
37 			return ICNS_16x16_32BIT_DATA;
38 		case 32:
39 			return ICNS_32x32_32BIT_DATA;
40 		case 48:
41 			return ICNS_48x48_32BIT_DATA;
42 		case 128:
43 			return ICNS_128X128_32BIT_DATA;
44 		case 256:
45 			return ICNS_256x256_32BIT_ARGB_DATA;
46 		case 512:
47 			return ICNS_512x512_32BIT_ARGB_DATA;
48 		case 1024:
49 			return ICNS_1024x1024_32BIT_ARGB_DATA;
50 	}
51 	return ICNS_NULL_TYPE;
52 }
53 
54 
55 ICNSLoader::ICNSLoader(BPositionIO *stream)
56 {
57 	fLoaded = false;
58 	fIconsCount = 0;
59 
60 	stream->Seek(0, SEEK_END);
61 	fStreamSize = stream->Position();
62 	stream->Seek(0, SEEK_SET);
63 
64 	if (fStreamSize <= 0)
65 		return;
66 
67 	uint8* icnsDataBuffer = new uint8[fStreamSize];
68 	size_t readedBytes = stream->Read(icnsDataBuffer,fStreamSize);
69 
70 	fIconFamily = NULL;
71 	int status = icns_import_family_data(readedBytes, icnsDataBuffer,
72 		&fIconFamily);
73 
74 	if (status != 0) {
75 		delete[] icnsDataBuffer;
76 		return;
77 	}
78 
79 	icns_byte_t *dataPtr = (icns_byte_t*)fIconFamily;
80 	off_t dataOffset = sizeof(icns_type_t) + sizeof(icns_size_t);
81 
82 	while ((dataOffset+8) < fIconFamily->resourceSize) {
83 		icns_element_t	 iconElement;
84 		icns_size_t      iconDataSize;
85 
86 		memcpy(&iconElement, (dataPtr + dataOffset), 8);
87 		iconDataSize = iconElement.elementSize - 8;
88 
89 		if (IS_SPUPPORTED_TYPE(iconElement.elementType)) {
90 				icns_type_t* newTypeItem = new icns_type_t;
91 				*newTypeItem = iconElement.elementType;
92 				fFormatList.AddItem(newTypeItem);
93 				fIconsCount++;
94 		}
95 		dataOffset += iconElement.elementSize;
96 	}
97 
98 	fFormatList.SortItems(compareTypes);
99 
100 	delete[] icnsDataBuffer;
101 
102 	fLoaded = true;
103 }
104 
105 
106 ICNSLoader::~ICNSLoader()
107 {
108 	if (fIconFamily != NULL)
109 		free(fIconFamily);
110 
111 	icns_type_t* item;
112 	for (int32 i = 0; (item = (icns_type_t*)fFormatList.ItemAt(i)) != NULL; i++)
113    		delete item;
114    	fFormatList.MakeEmpty();
115 }
116 
117 
118 bool
119 ICNSLoader::IsLoaded(void)
120 {
121 	return fLoaded;
122 }
123 
124 
125 int
126 ICNSLoader::IconsCount(void)
127 {
128 	return fIconsCount;
129 }
130 
131 
132 int
133 ICNSLoader::GetIcon(BPositionIO *target, int index)
134 {
135 	if (index < 1 || index > fIconsCount || !fLoaded)
136 		return B_NO_TRANSLATOR;
137 
138 	icns_image_t iconImage;
139 	memset(&iconImage, 0, sizeof(icns_image_t));
140 
141 	icns_type_t typeItem = *((icns_type_t*)fFormatList.ItemAt(index - 1));
142 	int status = icns_get_image32_with_mask_from_family(fIconFamily,
143 		typeItem, &iconImage);
144 
145 	if (status != 0)
146 		return B_NO_TRANSLATOR;
147 
148 	TranslatorBitmap bitsHeader;
149 	bitsHeader.magic = B_TRANSLATOR_BITMAP;
150 	bitsHeader.bounds.left = 0;
151 	bitsHeader.bounds.top = 0;
152 	bitsHeader.bounds.right = iconImage.imageWidth - 1;
153 	bitsHeader.bounds.bottom = iconImage.imageHeight - 1;
154 	bitsHeader.rowBytes = sizeof(uint32) * iconImage.imageWidth;
155 	bitsHeader.colors = B_RGBA32;
156 	bitsHeader.dataSize = bitsHeader.rowBytes * iconImage.imageHeight;
157 	if (swap_data(B_UINT32_TYPE, &bitsHeader,
158 		sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) {
159 		icns_free_image(&iconImage);
160 		return B_NO_TRANSLATOR;
161 	}
162 	target->Write(&bitsHeader, sizeof(TranslatorBitmap));
163 
164 	uint8 *rowBuff = new uint8[iconImage.imageWidth * sizeof(uint32)];
165 	for (uint32 i = 0; i < iconImage.imageHeight; i++) {
166 		uint8 *rowData = iconImage.imageData
167 			+ (i * iconImage.imageWidth * sizeof(uint32));
168 		uint8 *rowBuffPtr = rowBuff;
169 		for (uint32 j=0; j < iconImage.imageWidth; j++) {
170 			rowBuffPtr[0] = rowData[2];
171 			rowBuffPtr[1] = rowData[1];
172 			rowBuffPtr[2] = rowData[0];
173 			rowBuffPtr[3] = rowData[3];
174 			rowBuffPtr += sizeof(uint32);
175 			rowData += sizeof(uint32);
176 		}
177 		target->Write(rowBuff, iconImage.imageWidth * sizeof(uint32));
178 	}
179 	delete[] rowBuff;
180 	icns_free_image(&iconImage);
181 
182 	return B_OK;
183 }
184 
185 
186 ICNSSaver::ICNSSaver(BPositionIO *stream, uint32 rowBytes, icns_type_t type)
187 {
188 	fCreated = false;
189 
190 	icns_icon_info_t imageTypeInfo = icns_get_image_info_for_type(type);
191 	int iconWidth = imageTypeInfo.iconWidth;
192 	int iconHeight = imageTypeInfo.iconHeight;
193 	int bpp = 32;
194 
195 	uint8 *bits = new uint8[iconWidth * iconHeight * sizeof(uint32)];
196 
197 	uint8 *rowPtr = bits;
198 	for (int i = 0; i < iconHeight; i++) {
199 		stream->Read(rowPtr, rowBytes);
200 		uint8 *bytePtr = rowPtr;
201 		for (int j=0; j < iconWidth; j++) {
202 			uint8 temp = bytePtr[0];
203 			bytePtr[0] = bytePtr[2];
204 			bytePtr[2] = temp;
205 			bytePtr += sizeof(uint32);
206 		}
207 		rowPtr += iconWidth * sizeof(uint32);
208 	}
209 
210 	icns_create_family(&fIconFamily);
211 
212 	icns_image_t icnsImage;
213 	icnsImage.imageWidth = iconWidth;
214 	icnsImage.imageHeight = iconHeight;
215 	icnsImage.imageChannels = 4;
216 	icnsImage.imagePixelDepth = 8;
217 	icnsImage.imageDataSize = iconWidth * iconHeight * 4;
218 	icnsImage.imageData = bits;
219 
220 	icns_icon_info_t iconInfo;
221 	iconInfo.isImage = 1;
222 	iconInfo.iconWidth = icnsImage.imageWidth;
223 	iconInfo.iconHeight = icnsImage.imageHeight;
224 	iconInfo.iconBitDepth = bpp;
225 	iconInfo.iconChannels = (bpp == 32 ? 4 : 1);
226 	iconInfo.iconPixelDepth = bpp / iconInfo.iconChannels;
227 
228 	icns_type_t iconType = icns_get_type_from_image_info(iconInfo);
229 
230 	if (iconType == ICNS_NULL_TYPE) {
231 		delete[] bits;
232 		free(fIconFamily);
233 		fIconFamily = NULL;
234 		return;
235 	}
236 
237 	icns_element_t *iconElement = NULL;
238 	int icnsErr = icns_new_element_from_image(&icnsImage, iconType,
239 		&iconElement);
240 
241 	if (iconElement != NULL) {
242 		if (icnsErr == ICNS_STATUS_OK) {
243 			icns_set_element_in_family(&fIconFamily, iconElement);
244 			fCreated = true;
245 		}
246 		free(iconElement);
247 	}
248 
249 	if (iconType != ICNS_1024x1024_32BIT_ARGB_DATA
250 		&& iconType != ICNS_512x512_32BIT_ARGB_DATA
251 		&& iconType != ICNS_256x256_32BIT_ARGB_DATA) {
252 		icns_type_t maskType =
253 			icns_get_mask_type_for_icon_type(iconType);
254 
255 		icns_image_t icnsMask;
256 		icns_init_image_for_type(maskType, &icnsMask);
257 
258 		uint32 iconDataOffset = 0;
259 		uint32 maskDataOffset = 0;
260 
261 		while (iconDataOffset < icnsImage.imageDataSize
262 			&& maskDataOffset < icnsMask.imageDataSize) {
263 			icnsMask.imageData[maskDataOffset] =
264 				icnsImage.imageData[iconDataOffset + 3];
265 			iconDataOffset += 4;
266 			maskDataOffset += 1;
267 		}
268 
269 		icns_element_t *maskElement = NULL;
270 		icnsErr = icns_new_element_from_mask(&icnsMask, maskType,
271 			&maskElement);
272 
273 		if (maskElement != NULL) {
274 			if (icnsErr == ICNS_STATUS_OK) {
275 				icns_set_element_in_family(&fIconFamily,
276 					maskElement);
277 			} else
278 				fCreated = false;
279 			free(maskElement);
280 		}
281 		icns_free_image(&icnsMask);
282 	}
283 
284 	if (!fCreated) {
285 		free(fIconFamily);
286 		fIconFamily = NULL;
287 	}
288 
289 	delete[] bits;
290 }
291 
292 
293 ICNSSaver::~ICNSSaver()
294 {
295 	if (fIconFamily != NULL)
296 		free(fIconFamily);
297 }
298 
299 
300 int
301 ICNSSaver::SaveData(BPositionIO *target)
302 {
303 	icns_size_t dataSize;
304 	icns_byte_t *dataPtrOut;
305 	icns_export_family_data(fIconFamily, &dataSize, &dataPtrOut);
306 	if (dataSize != 0 && dataPtrOut != NULL) {
307 		if (target->Write(dataPtrOut, dataSize) == dataSize)
308 			return B_OK;
309 	}
310 	return B_ERROR;
311 }
312 
313 
314 bool
315 ICNSSaver::IsCreated(void)
316 {
317 	return fCreated;
318 }
319