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
compareTypes(const void * a,const void * b)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
ICNSFormat(float width,float height,color_space colors)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
ICNSLoader(BPositionIO * stream)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
~ICNSLoader()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
IsLoaded(void)119 ICNSLoader::IsLoaded(void)
120 {
121 return fLoaded;
122 }
123
124
125 int
IconsCount(void)126 ICNSLoader::IconsCount(void)
127 {
128 return fIconsCount;
129 }
130
131
132 int
GetIcon(BPositionIO * target,int index)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
ICNSSaver(BPositionIO * stream,uint32 rowBytes,icns_type_t type)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
~ICNSSaver()293 ICNSSaver::~ICNSSaver()
294 {
295 if (fIconFamily != NULL)
296 free(fIconFamily);
297 }
298
299
300 int
SaveData(BPositionIO * target)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
IsCreated(void)315 ICNSSaver::IsCreated(void)
316 {
317 return fCreated;
318 }
319