static int add_png_to_family(icns_family_t **iconFamily, char *pngname) { FILE *pngfile; int icnsErr = ICNS_STATUS_OK; icns_image_t icnsImage; icns_image_t icnsMask; icns_type_t iconType; icns_type_t maskType; icns_icon_info_t iconInfo; icns_element_t *iconElement = NULL; icns_element_t *maskElement = NULL; char iconStr[5] = {0,0,0,0,0}; char maskStr[5] = {0,0,0,0,0}; int iconDataOffset = 0; int maskDataOffset = 0; char isHiDPI = 0; int pngnamelen = strlen(pngname); int namea2xpng = pngnamelen - 7; png_bytep buffer; int width, height, bpp; if(namea2xpng > 0) { if(memcmp(&pngname[namea2xpng],"@2x.png",7) == 0) { isHiDPI = 1; } if(memcmp(&pngname[namea2xpng],"@2X.PNG",7) == 0) { isHiDPI = 1; } } pngfile = fopen(pngname, "rb"); if (pngfile == NULL) { fprintf(stderr, "Could not open '%s' for reading: %s\n", pngname, strerror(errno)); return FALSE; } if (!read_png(pngfile, &buffer, &bpp, &width, &height)) { fprintf(stderr, "Failed to read PNG file\n"); fclose(pngfile); return FALSE; } fclose(pngfile); icnsImage.imageWidth = width; icnsImage.imageHeight = height; icnsImage.imageChannels = 4; icnsImage.imagePixelDepth = 8; icnsImage.imageDataSize = width * height * 4; icnsImage.imageData = buffer; iconInfo.isImage = 1; iconInfo.iconWidth = icnsImage.imageWidth; iconInfo.iconHeight = icnsImage.imageHeight; iconInfo.iconBitDepth = bpp; iconInfo.iconChannels = (bpp == 32 ? 4 : 1); iconInfo.iconPixelDepth = bpp / iconInfo.iconChannels; iconType = icns_get_type_from_image_info_advanced(iconInfo,isHiDPI); maskType = icns_get_mask_type_for_icon_type(iconType); icns_type_str(iconType,iconStr); icns_type_str(maskType,maskStr); /* Only convert the icons that match sizes icns supports */ if (iconType == ICNS_NULL_TYPE) { fprintf(stderr, "Unable to determine icon type: PNG file '%s' is %dx%d\n", pngname, width, height); free(buffer); return FALSE; } if (bpp != 32) { fprintf(stderr, "Bit depth %d unsupported in '%s'\n", bpp, pngname); free(buffer); return FALSE; } icns_set_print_errors(0); if (icns_get_element_from_family(*iconFamily, iconType, &iconElement) == ICNS_STATUS_OK) { icns_set_print_errors(1); fprintf(stderr, "Duplicate icon element of type '%s' detected (%s)\n", iconStr, pngname); free(buffer); return FALSE; } icns_set_print_errors(1); #if DEBUG_ICNSUTIL if(maskType != ICNS_NULL_TYPE) { printf("Using icns type '%s', mask '%s' for '%s'\n", iconStr, maskStr, pngname); } else { printf("Using icns type '%s' (ARGB) for '%s'\n", iconStr, pngname); } #endif icnsErr = icns_new_element_from_image(&icnsImage, iconType, &iconElement); if (iconElement != NULL) { if (icnsErr == ICNS_STATUS_OK) { icns_set_element_in_family(iconFamily, iconElement); } free(iconElement); } if(maskType != ICNS_NULL_TYPE) { icns_init_image_for_type(maskType, &icnsMask); iconDataOffset = 0; maskDataOffset = 0; while ((iconDataOffset < icnsImage.imageDataSize) && (maskDataOffset < icnsMask.imageDataSize)) { icnsMask.imageData[maskDataOffset] = icnsImage.imageData[iconDataOffset+3]; iconDataOffset += 4; /* move to the next alpha byte */ maskDataOffset += 1; /* move to the next byte */ } icnsErr = icns_new_element_from_mask(&icnsMask, maskType, &maskElement); if (maskElement != NULL) { if (icnsErr == ICNS_STATUS_OK) { icns_set_element_in_family(iconFamily, maskElement); } free(maskElement); } icns_free_image(&icnsMask); } free(buffer); return TRUE; }
int icns_get_image32_with_mask_from_family(icns_family_t *iconFamily,icns_type_t iconType,icns_image_t *imageOut) { int error = ICNS_STATUS_OK; icns_type_t maskType = ICNS_NULL_TYPE; icns_element_t *iconElement = NULL; icns_element_t *maskElement = NULL; icns_image_t iconImage; icns_image_t maskImage; unsigned long dataCount = 0; icns_byte_t dataValue = 0; unsigned long pixelCount = 0; unsigned long pixelID = 0; icns_byte_t colorIndex = 0; memset ( &iconImage, 0, sizeof(icns_image_t) ); memset ( &maskImage, 0, sizeof(icns_image_t) ); if(iconFamily == NULL) { icns_print_err("icns_get_image32_with_mask_from_family: Icon family is NULL!\n"); return ICNS_STATUS_NULL_PARAM; } if(imageOut == NULL) { icns_print_err("icns_get_image32_with_mask_from_family: Icon image is NULL!\n"); return ICNS_STATUS_NULL_PARAM; } else { icns_free_image(imageOut); } #ifdef ICNS_DEBUG { char typeStr[5]; printf("Making 32-bit image...\n"); printf(" using icon type '%s'\n",icns_type_str(iconType,typeStr)); } #endif if((iconType == ICNS_128X128_8BIT_MASK) || \ (iconType == ICNS_48x48_8BIT_MASK) || \ (iconType == ICNS_32x32_8BIT_MASK) || \ (iconType == ICNS_16x16_8BIT_MASK) ) { icns_print_err("icns_get_image32_with_mask_from_family: Can't make an image with mask from a mask\n"); return ICNS_STATUS_INVALID_DATA; } // Preliminaries checked - carry on with the icon/mask merge // Load icon element then image error = icns_get_element_from_family(iconFamily,iconType,&iconElement); if(error) { icns_print_err("icns_get_image32_with_mask_from_family: Unable to load icon element from icon family!\n"); goto cleanup; } error = icns_get_image_from_element(iconElement,&iconImage); if(error) { icns_print_err("icns_get_image32_with_mask_from_family: Unable to load icon image data from icon element!\n"); goto cleanup; } // We used the jp2/png processor for these two, so we're done! if( (iconType == ICNS_128x128_32BIT_ARGB_DATA) || (iconType == ICNS_256x256_32BIT_ARGB_DATA) || (iconType == ICNS_512x512_32BIT_ARGB_DATA) || (iconType == ICNS_1024x1024_32BIT_ARGB_DATA) || (iconType == ICNS_16x16_2X_32BIT_ARGB_DATA) || (iconType == ICNS_32x32_2X_32BIT_ARGB_DATA) || (iconType == ICNS_128x128_2X_32BIT_ARGB_DATA) || (iconType == ICNS_256x256_2X_32BIT_ARGB_DATA) || (iconType == ICNS_512x512_2X_32BIT_ARGB_DATA) ) { memcpy(imageOut,&iconImage,sizeof(icns_image_t)); if(iconElement != NULL) { free(iconElement); iconElement = NULL; } return error; } maskType = icns_get_mask_type_for_icon_type(iconType); #ifdef ICNS_DEBUG { char typeStr[5]; printf(" using mask type '%s'\n",icns_type_str(maskType,typeStr)); } #endif if( (maskType == ICNS_NULL_DATA) ) { char typeStr[5]; icns_print_err("icns_get_image32_with_mask_from_family: Can't find mask for type '%s'\n",icns_type_str(iconType,typeStr)); return ICNS_STATUS_DATA_NOT_FOUND; } // Load mask element then image... error = icns_get_element_from_family(iconFamily,maskType,&maskElement); // Note that we could arguably recover from not having a mask // by creating a dummy blank mask. However, the icns data type // should always have the corresponding mask present. This // function was designed to retreive a VALID image... There are // other API functions better used if the goal is editing, data // recovery, etc. if(error) { icns_print_err("icns_get_image32_with_mask_from_family: Unable to load mask element from icon family!\n"); goto cleanup; } error = icns_get_mask_from_element(maskElement,&maskImage); if(error) { icns_print_err("icns_get_image32_with_mask_from_family: Unable to load mask image data from icon element!\n"); goto cleanup; } if(iconImage.imageWidth != maskImage.imageWidth) { icns_print_err("icns_get_image32_with_mask_from_family: icon and mask widths do not match! (%d != %d)\n",iconImage.imageWidth,maskImage.imageHeight); goto cleanup; } if(iconImage.imageHeight != maskImage.imageHeight) { icns_print_err("icns_get_image32_with_mask_from_family: icon and mask heights do not match! (%d != %d)\n",iconImage.imageHeight,maskImage.imageHeight); goto cleanup; } // Unpack image pixels if depth is < 32 if((iconImage.imagePixelDepth * iconImage.imageChannels) < 32) { icns_byte_t *oldData = NULL; icns_byte_t *newData = NULL; icns_uint32_t oldBitDepth = 0; unsigned long newBlockSize = 0; unsigned long newDataSize = 0; icns_colormap_rgb_t colorRGB; oldBitDepth = (iconImage.imagePixelDepth * iconImage.imageChannels); pixelCount = iconImage.imageWidth * iconImage.imageHeight; newBlockSize = iconImage.imageWidth * 32; newDataSize = newBlockSize * iconImage.imageHeight; oldData = iconImage.imageData; newData = (icns_byte_t *)malloc(newDataSize); if(newData == NULL) { icns_print_err("icns_get_image32_with_mask_from_family: Unable to allocate memory block of size: %d!\n",(int)newDataSize); return ICNS_STATUS_NO_MEMORY; } dataCount = 0; // 8-Bit Icon Image Data Types if((iconType == ICNS_48x48_8BIT_DATA) || \ (iconType == ICNS_32x32_8BIT_DATA) || \ (iconType == ICNS_16x16_8BIT_DATA) || \ (iconType == ICNS_16x12_8BIT_DATA) ) { if(oldBitDepth != 8) { icns_print_err("icns_get_image32_with_mask_from_family: Invalid bit depth - type mismatch!\n"); free(newData); error = ICNS_STATUS_INVALID_DATA; goto cleanup; } for(pixelID = 0; pixelID < pixelCount; pixelID++) { colorIndex = oldData[dataCount++]; colorRGB = icns_colormap_8[colorIndex]; newData[pixelID * 4 + 0] = colorRGB.r; newData[pixelID * 4 + 1] = colorRGB.g; newData[pixelID * 4 + 2] = colorRGB.b; newData[pixelID * 4 + 3] = 0xff; } } // 4-Bit Icon Image Data Types else if((iconType == ICNS_48x48_4BIT_DATA) || \ (iconType == ICNS_32x32_4BIT_DATA) || \ (iconType == ICNS_16x16_4BIT_DATA) || \ (iconType == ICNS_16x12_4BIT_DATA) ) { if(oldBitDepth != 4) { icns_print_err("icns_get_image32_with_mask_from_family: Invalid bit depth - type mismatch!\n"); free(newData); error = ICNS_STATUS_INVALID_DATA; goto cleanup; } for(pixelID = 0; pixelID < pixelCount; pixelID++) { if(pixelID % 2 == 0) dataValue = oldData[dataCount++]; colorIndex = (dataValue & 0xF0) >> 4; dataValue = dataValue << 4; colorRGB = icns_colormap_4[colorIndex]; newData[pixelID * 4 + 0] = colorRGB.r; newData[pixelID * 4 + 1] = colorRGB.g; newData[pixelID * 4 + 2] = colorRGB.b; newData[pixelID * 4 + 3] = 0xFF; } } // 1-Bit Icon Image Data Types else if((iconType == ICNS_48x48_1BIT_DATA) || \
ICNSSaver::ICNSSaver(BPositionIO *stream, uint32 rowBytes, icns_type_t type) { fCreated = false; icns_icon_info_t imageTypeInfo = icns_get_image_info_for_type(type); int iconWidth = imageTypeInfo.iconWidth; int iconHeight = imageTypeInfo.iconWidth; int bpp = 32; uint8 *bits = new uint8[iconWidth * iconHeight * sizeof(uint32)]; uint8 *rowPtr = bits; for (int i = 0; i < iconHeight; i++) { stream->Read(rowPtr, rowBytes); uint8 *bytePtr = rowPtr; for (int j=0; j < iconWidth; j++) { uint8 temp = bytePtr[0]; bytePtr[0] = bytePtr[2]; bytePtr[2] = temp; bytePtr += sizeof(uint32); } rowPtr += iconWidth * sizeof(uint32); } icns_create_family(&fIconFamily); icns_image_t icnsImage; icnsImage.imageWidth = iconWidth; icnsImage.imageHeight = iconHeight; icnsImage.imageChannels = 4; icnsImage.imagePixelDepth = 8; icnsImage.imageDataSize = iconWidth * iconHeight * 4; icnsImage.imageData = bits; icns_icon_info_t iconInfo; iconInfo.isImage = 1; iconInfo.iconWidth = icnsImage.imageWidth; iconInfo.iconHeight = icnsImage.imageHeight; iconInfo.iconBitDepth = bpp; iconInfo.iconChannels = (bpp == 32 ? 4 : 1); iconInfo.iconPixelDepth = bpp / iconInfo.iconChannels; icns_type_t iconType = icns_get_type_from_image_info(iconInfo); if (iconType == ICNS_NULL_TYPE) { delete bits; free(fIconFamily); fIconFamily = NULL; return; } icns_element_t *iconElement = NULL; int icnsErr = icns_new_element_from_image(&icnsImage, iconType, &iconElement); if (iconElement != NULL) { if (icnsErr == ICNS_STATUS_OK) { icns_set_element_in_family(&fIconFamily, iconElement); fCreated = true; } free(iconElement); } if (iconType != ICNS_1024x1024_32BIT_ARGB_DATA && iconType != ICNS_512x512_32BIT_ARGB_DATA && iconType != ICNS_256x256_32BIT_ARGB_DATA) { icns_type_t maskType = icns_get_mask_type_for_icon_type(iconType); icns_image_t icnsMask; icns_init_image_for_type(maskType, &icnsMask); uint32 iconDataOffset = 0; uint32 maskDataOffset = 0; while (iconDataOffset < icnsImage.imageDataSize && maskDataOffset < icnsMask.imageDataSize) { icnsMask.imageData[maskDataOffset] = icnsImage.imageData[iconDataOffset + 3]; iconDataOffset += 4; maskDataOffset += 1; } icns_element_t *maskElement = NULL; icnsErr = icns_new_element_from_mask(&icnsMask, maskType, &maskElement); if (maskElement != NULL) { if (icnsErr == ICNS_STATUS_OK) icns_set_element_in_family(&fIconFamily, maskElement); else fCreated = false; free(maskElement); } icns_free_image(&icnsMask); } if (!fCreated) { free(fIconFamily); fIconFamily = NULL; } delete bits; }