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