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