xref: /haiku/src/add-ons/translators/icns/ICNSLoader.cpp (revision a5a3b2d9a3d95cbae71eaf371708c73a1780ac0d)
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*)(*((icns_type_t*)a)));
13 	icns_type_t typeItemB = *((icns_type_t*)(*((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 	{
84 		icns_element_t	 iconElement;
85 		icns_size_t      iconDataSize;
86 
87 		memcpy(&iconElement, (dataPtr + dataOffset), 8);
88 		iconDataSize = iconElement.elementSize - 8;
89 
90 		if(IS_SPUPPORTED_TYPE(iconElement.elementType)) {
91 				icns_type_t* newTypeItem = new icns_type_t;
92 				*newTypeItem = iconElement.elementType;
93 				fFormatList.AddItem(newTypeItem);
94 				fIconsCount++;
95 		}
96 		dataOffset += iconElement.elementSize;
97 	}
98 
99 	fFormatList.SortItems(compareTypes);
100 
101 	delete[] icnsDataBuffer;
102 
103 	fLoaded = true;
104 }
105 
106 
107 ICNSLoader::~ICNSLoader()
108 {
109 	if (fIconFamily != NULL)
110 		free(fIconFamily);
111 
112 	icns_type_t* item;
113 	for (int32 i = 0; (item = (icns_type_t*)fFormatList.ItemAt(i)) != NULL; i++)
114    		delete item;
115    	fFormatList.MakeEmpty();
116 }
117 
118 
119 bool
120 ICNSLoader::IsLoaded(void)
121 {
122 	return fLoaded;
123 }
124 
125 
126 int
127 ICNSLoader::IconsCount(void)
128 {
129 	return fIconsCount;
130 }
131 
132 
133 int
134 ICNSLoader::GetIcon(BPositionIO *target, int index)
135 {
136 	if (index < 1 || index > fIconsCount || !fLoaded)
137 		return B_NO_TRANSLATOR;
138 
139 	icns_image_t iconImage;
140 	memset(&iconImage, 0, sizeof(icns_image_t));
141 
142 	icns_type_t typeItem = *((icns_type_t*)fFormatList.ItemAt(index - 1));
143 	int status = icns_get_image32_with_mask_from_family(fIconFamily,
144 		typeItem, &iconImage);
145 
146 	if (status != 0)
147 		return B_NO_TRANSLATOR;
148 
149 	TranslatorBitmap bitsHeader;
150 	bitsHeader.magic = B_TRANSLATOR_BITMAP;
151 	bitsHeader.bounds.left = 0;
152 	bitsHeader.bounds.top = 0;
153 	bitsHeader.bounds.right = iconImage.imageWidth - 1;
154 	bitsHeader.bounds.bottom = iconImage.imageHeight - 1;
155 	bitsHeader.rowBytes = sizeof(uint32) * iconImage.imageWidth;
156 	bitsHeader.colors = B_RGBA32;
157 	bitsHeader.dataSize = bitsHeader.rowBytes * iconImage.imageHeight;
158 	if (swap_data(B_UINT32_TYPE, &bitsHeader,
159 		sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) {
160 		icns_free_image(&iconImage);
161 		return B_NO_TRANSLATOR;
162 	}
163 	target->Write(&bitsHeader, sizeof(TranslatorBitmap));
164 
165 	uint8 *rowBuff = new uint8[iconImage.imageWidth * sizeof(uint32)];
166 	for (uint32 i = 0; i < iconImage.imageHeight; i++) {
167 		uint8 *rowData = iconImage.imageData
168 			+ (i * iconImage.imageWidth * sizeof(uint32));
169 		uint8 *rowBuffPtr = rowBuff;
170 		for (uint32 j=0; j < iconImage.imageWidth; j++) {
171 			rowBuffPtr[0] = rowData[2];
172 			rowBuffPtr[1] = rowData[1];
173 			rowBuffPtr[2] = rowData[0];
174 			rowBuffPtr[3] = rowData[3];
175 			rowBuffPtr += sizeof(uint32);
176 			rowData += sizeof(uint32);
177 		}
178 		target->Write(rowBuff, iconImage.imageWidth * sizeof(uint32));
179 	}
180 	delete[] rowBuff;
181 	icns_free_image(&iconImage);
182 
183 	return B_OK;
184 }
185 
186 
187 ICNSSaver::ICNSSaver(BPositionIO *stream, uint32 rowBytes, icns_type_t type)
188 {
189 	fCreated = false;
190 
191 	icns_icon_info_t imageTypeInfo = icns_get_image_info_for_type(type);
192 	int iconWidth = imageTypeInfo.iconWidth;
193 	int iconHeight = imageTypeInfo.iconWidth;
194 	int bpp = 32;
195 
196 	uint8 *bits = new uint8[iconWidth * iconHeight * sizeof(uint32)];
197 
198 	uint8 *rowPtr = bits;
199 	for (int i = 0; i < iconHeight; i++) {
200 		stream->Read(rowPtr, rowBytes);
201 		uint8 *bytePtr = rowPtr;
202 		for (int j=0; j < iconWidth; j++) {
203 			uint8 temp = bytePtr[0];
204 			bytePtr[0] = bytePtr[2];
205 			bytePtr[2] = temp;
206 			bytePtr += sizeof(uint32);
207 		}
208 		rowPtr += iconWidth * sizeof(uint32);
209 	}
210 
211 	icns_create_family(&fIconFamily);
212 
213 	icns_image_t icnsImage;
214 	icnsImage.imageWidth = iconWidth;
215 	icnsImage.imageHeight = iconHeight;
216 	icnsImage.imageChannels = 4;
217 	icnsImage.imagePixelDepth = 8;
218 	icnsImage.imageDataSize = iconWidth * iconHeight * 4;
219 	icnsImage.imageData = bits;
220 
221 	icns_icon_info_t iconInfo;
222 	iconInfo.isImage = 1;
223 	iconInfo.iconWidth = icnsImage.imageWidth;
224 	iconInfo.iconHeight = icnsImage.imageHeight;
225 	iconInfo.iconBitDepth = bpp;
226 	iconInfo.iconChannels = (bpp == 32 ? 4 : 1);
227 	iconInfo.iconPixelDepth = bpp / iconInfo.iconChannels;
228 
229 	icns_type_t iconType = icns_get_type_from_image_info(iconInfo);
230 
231 	if (iconType == ICNS_NULL_TYPE) {
232 		delete[] bits;
233 		free(fIconFamily);
234 		fIconFamily = NULL;
235 		return;
236 	}
237 
238 	icns_element_t *iconElement = NULL;
239 	int icnsErr = icns_new_element_from_image(&icnsImage, iconType,
240 		&iconElement);
241 
242 	if (iconElement != NULL) {
243 		if (icnsErr == ICNS_STATUS_OK) {
244 			icns_set_element_in_family(&fIconFamily, iconElement);
245 			fCreated = true;
246 		}
247 		free(iconElement);
248 	}
249 
250 	if (iconType != ICNS_1024x1024_32BIT_ARGB_DATA
251 		&& iconType != ICNS_512x512_32BIT_ARGB_DATA
252 		&& iconType != ICNS_256x256_32BIT_ARGB_DATA) {
253 		icns_type_t maskType =
254 			icns_get_mask_type_for_icon_type(iconType);
255 
256 		icns_image_t icnsMask;
257 		icns_init_image_for_type(maskType, &icnsMask);
258 
259 		uint32 iconDataOffset = 0;
260 		uint32 maskDataOffset = 0;
261 
262 		while (iconDataOffset < icnsImage.imageDataSize
263 			&& maskDataOffset < icnsMask.imageDataSize) {
264 			icnsMask.imageData[maskDataOffset] =
265 				icnsImage.imageData[iconDataOffset + 3];
266 			iconDataOffset += 4;
267 			maskDataOffset += 1;
268 		}
269 
270 		icns_element_t *maskElement = NULL;
271 		icnsErr = icns_new_element_from_mask(&icnsMask, maskType,
272 			&maskElement);
273 
274 		if (maskElement != NULL) {
275 			if (icnsErr == ICNS_STATUS_OK) {
276 				icns_set_element_in_family(&fIconFamily,
277 					maskElement);
278 			} else
279 				fCreated = false;
280 			free(maskElement);
281 		}
282 		icns_free_image(&icnsMask);
283 	}
284 
285 	if (!fCreated) {
286 		free(fIconFamily);
287 		fIconFamily = NULL;
288 	}
289 
290 	delete[] bits;
291 }
292 
293 
294 ICNSSaver::~ICNSSaver()
295 {
296 	if (fIconFamily != NULL)
297 		free(fIconFamily);
298 }
299 
300 
301 int
302 ICNSSaver::SaveData(BPositionIO *target)
303 {
304 	icns_size_t dataSize;
305 	icns_byte_t *dataPtrOut;
306 	icns_export_family_data(fIconFamily, &dataSize, &dataPtrOut);
307 	if (dataSize != 0 && dataPtrOut != NULL) {
308 		if (target->Write(dataPtrOut, dataSize) == dataSize)
309 			return B_OK;
310 	}
311 	return B_ERROR;
312 }
313 
314 
315 bool
316 ICNSSaver::IsCreated(void)
317 {
318 	return fCreated;
319 }
320