/*
* Copyright 2012, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "ICNSLoader.h"
#include "BaseTranslator.h"
static int compareTypes(const void *a, const void *b)
{
icns_type_t typeItemA = *((icns_type_t*)(*((icns_type_t*)a)));
icns_type_t typeItemB = *((icns_type_t*)(*((icns_type_t*)b)));
icns_icon_info_t imageInfoA = icns_get_image_info_for_type(typeItemA);
icns_icon_info_t imageInfoB = icns_get_image_info_for_type(typeItemB);
return imageInfoB.iconWidth - imageInfoA.iconWidth;
}
icns_type_t
ICNSFormat(float width, float height, color_space colors)
{
int imageWidth = (int)ceil(width);
int imageHeight = (int)ceil(height);
if (imageWidth != imageHeight)
return ICNS_NULL_TYPE;
//other colors depth not supported now
if (colors != B_RGB32 && colors != B_RGBA32)
return ICNS_NULL_TYPE;
switch (imageWidth) {
case 16:
return ICNS_16x16_32BIT_DATA;
case 32:
return ICNS_32x32_32BIT_DATA;
case 48:
return ICNS_48x48_32BIT_DATA;
case 128:
return ICNS_128X128_32BIT_DATA;
case 256:
return ICNS_256x256_32BIT_ARGB_DATA;
case 512:
return ICNS_512x512_32BIT_ARGB_DATA;
case 1024:
return ICNS_1024x1024_32BIT_ARGB_DATA;
}
return ICNS_NULL_TYPE;
}
ICNSLoader::ICNSLoader(BPositionIO *stream)
{
fLoaded = false;
fIconsCount = 0;
stream->Seek(0, SEEK_END);
fStreamSize = stream->Position();
stream->Seek(0, SEEK_SET);
if (fStreamSize <= 0)
return;
uint8* icnsDataBuffer = new uint8[fStreamSize];
size_t readedBytes = stream->Read(icnsDataBuffer,fStreamSize);
fIconFamily = NULL;
int status = icns_import_family_data(readedBytes, icnsDataBuffer,
&fIconFamily);
if (status != 0) {
delete[] icnsDataBuffer;
return;
}
icns_byte_t *dataPtr = (icns_byte_t*)fIconFamily;
off_t dataOffset = sizeof(icns_type_t) + sizeof(icns_size_t);
while ((dataOffset+8) < fIconFamily->resourceSize) {
icns_element_t iconElement;
icns_size_t iconDataSize;
memcpy(&iconElement, (dataPtr + dataOffset), 8);
iconDataSize = iconElement.elementSize - 8;
if (IS_SPUPPORTED_TYPE(iconElement.elementType)) {
icns_type_t* newTypeItem = new icns_type_t;
*newTypeItem = iconElement.elementType;
fFormatList.AddItem(newTypeItem);
fIconsCount++;
}
dataOffset += iconElement.elementSize;
}
fFormatList.SortItems(compareTypes);
delete[] icnsDataBuffer;
fLoaded = true;
}
ICNSLoader::~ICNSLoader()
{
if (fIconFamily != NULL)
free(fIconFamily);
icns_type_t* item;
for (int32 i = 0; (item = (icns_type_t*)fFormatList.ItemAt(i)) != NULL; i++)
delete item;
fFormatList.MakeEmpty();
}
bool
ICNSLoader::IsLoaded(void)
{
return fLoaded;
}
int
ICNSLoader::IconsCount(void)
{
return fIconsCount;
}
int
ICNSLoader::GetIcon(BPositionIO *target, int index)
{
if (index < 1 || index > fIconsCount || !fLoaded)
return B_NO_TRANSLATOR;
icns_image_t iconImage;
memset(&iconImage, 0, sizeof(icns_image_t));
icns_type_t typeItem = *((icns_type_t*)fFormatList.ItemAt(index - 1));
int status = icns_get_image32_with_mask_from_family(fIconFamily,
typeItem, &iconImage);
if (status != 0)
return B_NO_TRANSLATOR;
TranslatorBitmap bitsHeader;
bitsHeader.magic = B_TRANSLATOR_BITMAP;
bitsHeader.bounds.left = 0;
bitsHeader.bounds.top = 0;
bitsHeader.bounds.right = iconImage.imageWidth - 1;
bitsHeader.bounds.bottom = iconImage.imageHeight - 1;
bitsHeader.rowBytes = sizeof(uint32) * iconImage.imageWidth;
bitsHeader.colors = B_RGBA32;
bitsHeader.dataSize = bitsHeader.rowBytes * iconImage.imageHeight;
if (swap_data(B_UINT32_TYPE, &bitsHeader,
sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) {
icns_free_image(&iconImage);
return B_NO_TRANSLATOR;
}
target->Write(&bitsHeader, sizeof(TranslatorBitmap));
uint8 *rowBuff = new uint8[iconImage.imageWidth * sizeof(uint32)];
for (uint32 i = 0; i < iconImage.imageHeight; i++) {
uint8 *rowData = iconImage.imageData
+ (i * iconImage.imageWidth * sizeof(uint32));
uint8 *rowBuffPtr = rowBuff;
for (uint32 j=0; j < iconImage.imageWidth; j++) {
rowBuffPtr[0] = rowData[2];
rowBuffPtr[1] = rowData[1];
rowBuffPtr[2] = rowData[0];
rowBuffPtr[3] = rowData[3];
rowBuffPtr += sizeof(uint32);
rowData += sizeof(uint32);
}
target->Write(rowBuff, iconImage.imageWidth * sizeof(uint32));
}
delete[] rowBuff;
icns_free_image(&iconImage);
return B_OK;
}
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;
}
ICNSSaver::~ICNSSaver()
{
if (fIconFamily != NULL)
free(fIconFamily);
}
int
ICNSSaver::SaveData(BPositionIO *target)
{
icns_size_t dataSize;
icns_byte_t *dataPtrOut;
icns_export_family_data(fIconFamily, &dataSize, &dataPtrOut);
if (dataSize != 0 && dataPtrOut != NULL) {
if (target->Write(dataPtrOut, dataSize) == dataSize)
return B_OK;
}
return B_ERROR;
}
bool
ICNSSaver::IsCreated(void)
{
return fCreated;
}
↑ V547 Expression 'bpp == 32' is always true.