Translator for Windows ICO files with read/write support. Not yet complete, but
seems to work for all cases I tested it with :) Now you can finally create favicon.ico files under BeOS :)) git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11288 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
883395b10f
commit
2b05778c88
@ -2,6 +2,7 @@ SubDir OBOS_TOP src add-ons translators ;
|
||||
|
||||
SubInclude OBOS_TOP src add-ons translators bmptranslator ;
|
||||
SubInclude OBOS_TOP src add-ons translators giftranslator ;
|
||||
SubInclude OBOS_TOP src add-ons translators icotranslator ;
|
||||
SubInclude OBOS_TOP src add-ons translators jpegtranslator ;
|
||||
SubInclude OBOS_TOP src add-ons translators jpeg2000translator ;
|
||||
SubInclude OBOS_TOP src add-ons translators libtifftranslator ;
|
||||
|
55
src/add-ons/translators/icotranslator/ConfigView.cpp
Normal file
55
src/add-ons/translators/icotranslator/ConfigView.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ConfigView.h"
|
||||
#include "ICOTranslator.h"
|
||||
|
||||
#include <StringView.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
ConfigView::ConfigView(const BRect &frame, uint32 resize, uint32 flags)
|
||||
: BView(frame, "ICOTranslator Settings", resize, flags)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
font_height fontHeight;
|
||||
be_bold_font->GetHeight(&fontHeight);
|
||||
float height = fontHeight.descent + fontHeight.ascent + fontHeight.leading;
|
||||
|
||||
BRect rect(10, 10, 200, 10 + height);
|
||||
BStringView *stringView = new BStringView(rect, "title", "Windows Icon Images");
|
||||
stringView->SetFont(be_bold_font);
|
||||
stringView->ResizeToPreferred();
|
||||
AddChild(stringView);
|
||||
|
||||
rect.OffsetBy(0, height + 10);
|
||||
char version[256];
|
||||
sprintf(version, "Version %d.%d.%d, %s",
|
||||
int(B_TRANSLATION_MAJOR_VERSION(ICO_TRANSLATOR_VERSION)),
|
||||
int(B_TRANSLATION_MINOR_VERSION(ICO_TRANSLATOR_VERSION)),
|
||||
int(B_TRANSLATION_REVISION_VERSION(ICO_TRANSLATOR_VERSION)),
|
||||
__DATE__);
|
||||
stringView = new BStringView(rect, "version", version);
|
||||
stringView->ResizeToPreferred();
|
||||
AddChild(stringView);
|
||||
|
||||
GetFontHeight(&fontHeight);
|
||||
height = fontHeight.descent + fontHeight.ascent + fontHeight.leading;
|
||||
|
||||
rect.OffsetBy(0, height + 5);
|
||||
stringView = new BStringView(rect, "copyright", B_UTF8_COPYRIGHT "2005 Haiku Inc.");
|
||||
stringView->ResizeToPreferred();
|
||||
AddChild(stringView);
|
||||
}
|
||||
|
||||
|
||||
ConfigView::~ConfigView()
|
||||
{
|
||||
}
|
||||
|
19
src/add-ons/translators/icotranslator/ConfigView.h
Normal file
19
src/add-ons/translators/icotranslator/ConfigView.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CONFIG_VIEW_H
|
||||
#define CONFIG_VIEW_H
|
||||
|
||||
|
||||
#include <View.h>
|
||||
|
||||
|
||||
class ConfigView : public BView {
|
||||
public:
|
||||
ConfigView(const BRect &frame, uint32 resize = B_FOLLOW_ALL,
|
||||
uint32 flags = B_WILL_DRAW);
|
||||
virtual ~ConfigView();
|
||||
};
|
||||
|
||||
#endif /* CONFIG_VIEW_H */
|
651
src/add-ons/translators/icotranslator/ICO.cpp
Normal file
651
src/add-ons/translators/icotranslator/ICO.cpp
Normal file
@ -0,0 +1,651 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
// ToDo: This definitely needs to be worked over for endian issues
|
||||
|
||||
#include <ICO.h>
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define TRACE_ICO
|
||||
#ifdef TRACE_ICO
|
||||
# define TRACE(x) printf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
using namespace ICO;
|
||||
|
||||
|
||||
class TempAllocator {
|
||||
public:
|
||||
TempAllocator() : fMemory(NULL) {}
|
||||
~TempAllocator() { free(fMemory); }
|
||||
|
||||
void *Allocate(size_t size) { return fMemory = malloc(size); }
|
||||
|
||||
private:
|
||||
void *fMemory;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
ico_header::SwapToHost()
|
||||
{
|
||||
swap_data(B_UINT16_TYPE, this, sizeof(ico_header), B_SWAP_LENDIAN_TO_HOST);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ico_header::SwapFromHost()
|
||||
{
|
||||
swap_data(B_UINT16_TYPE, this, sizeof(ico_header), B_SWAP_HOST_TO_LENDIAN);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
ico_dir_entry::SwapToHost()
|
||||
{
|
||||
swap_data(B_UINT16_TYPE, &planes, sizeof(uint16) * 2, B_SWAP_LENDIAN_TO_HOST);
|
||||
swap_data(B_UINT32_TYPE, &size, sizeof(uint32) * 2, B_SWAP_LENDIAN_TO_HOST);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ico_dir_entry::SwapFromHost()
|
||||
{
|
||||
swap_data(B_UINT16_TYPE, &planes, sizeof(uint16) * 2, B_SWAP_HOST_TO_LENDIAN);
|
||||
swap_data(B_UINT32_TYPE, &size, sizeof(uint32) * 2, B_SWAP_HOST_TO_LENDIAN);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
bool
|
||||
ico_bitmap_header::IsValid() const
|
||||
{
|
||||
return size == sizeof(ico_bitmap_header) && compression == 0
|
||||
&& (bits_per_pixel == 1 || bits_per_pixel == 4 || bits_per_pixel == 8
|
||||
|| bits_per_pixel == 16 || bits_per_pixel == 24 || bits_per_pixel == 32);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ico_bitmap_header::SwapToHost()
|
||||
{
|
||||
swap_data(B_UINT32_TYPE, &size, sizeof(uint32) * 3, B_SWAP_LENDIAN_TO_HOST);
|
||||
swap_data(B_UINT16_TYPE, &planes, sizeof(uint16) * 2, B_SWAP_LENDIAN_TO_HOST);
|
||||
swap_data(B_UINT32_TYPE, &compression, sizeof(uint32) * 6, B_SWAP_LENDIAN_TO_HOST);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ico_bitmap_header::SwapFromHost()
|
||||
{
|
||||
swap_data(B_UINT32_TYPE, &size, sizeof(uint32) * 3, B_SWAP_HOST_TO_LENDIAN);
|
||||
swap_data(B_UINT16_TYPE, &planes, sizeof(uint16) * 2, B_SWAP_HOST_TO_LENDIAN);
|
||||
swap_data(B_UINT32_TYPE, &compression, sizeof(uint32) * 6, B_SWAP_HOST_TO_LENDIAN);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static inline uint8 *
|
||||
get_data_row(uint8 *data, int32 dataSize, int32 rowBytes, int32 row)
|
||||
{
|
||||
return data + dataSize - (row + 1) * rowBytes;
|
||||
}
|
||||
|
||||
|
||||
static inline int32
|
||||
get_bytes_per_row(int32 width, int32 bitsPerPixel)
|
||||
{
|
||||
return (((bitsPerPixel * width + 7) / 8) + 3) & ~3;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
set_1_bit_per_pixel(uint8 *line, int32 x, int32 value)
|
||||
{
|
||||
int32 mask = 1 << (7 - (x & 7));
|
||||
if (value)
|
||||
line[x / 8] |= mask;
|
||||
else
|
||||
line[x / 8] &= ~mask;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
set_4_bits_per_pixel(uint8 *line, int32 x, int32 value)
|
||||
{
|
||||
int32 shift = x & 1 ? 0 : 4;
|
||||
int32 mask = ~0L & (0xf0 >> shift);
|
||||
|
||||
line[x / 2] &= mask;
|
||||
line[x / 2] |= value << shift;
|
||||
}
|
||||
|
||||
|
||||
static inline int32
|
||||
get_1_bit_per_pixel(uint8 *line, int32 x)
|
||||
{
|
||||
return (line[x / 8] >> (7 - (x & 7))) & 1;
|
||||
}
|
||||
|
||||
|
||||
static inline int32
|
||||
get_4_bits_per_pixel(uint8 *line, int32 x)
|
||||
{
|
||||
return (line[x / 2] >> (4 * ((x + 1) & 1))) & 0xf;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
is_valid_size(int32 size)
|
||||
{
|
||||
return size == 16 || size == 32 || size == 48;
|
||||
}
|
||||
|
||||
|
||||
static uint8
|
||||
get_alpha_value(color_space space, uint32 value)
|
||||
{
|
||||
// ToDo: support more color spaces
|
||||
if (space == B_RGBA32)
|
||||
return value >> 24;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
find_ico_color(ico_color *palette, int32 numColors, ico_color &color)
|
||||
{
|
||||
// ToDo: sorting and binary search?
|
||||
for (int32 i = 0; i < numColors; i++) {
|
||||
if (palette[i] == color)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static inline ico_color
|
||||
get_ico_color_from_bits(TranslatorBitmap &bitsHeader, uint8 *data, int32 x, int32 y)
|
||||
{
|
||||
data += bitsHeader.rowBytes * y;
|
||||
|
||||
switch (bitsHeader.colors) {
|
||||
case B_RGBA32:
|
||||
case B_RGB32:
|
||||
default:
|
||||
return *(ico_color *)(data + 4 * x);
|
||||
// ToDo: support some more color spaces...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
fill_palette(TranslatorBitmap &bitsHeader, uint8 *data, ico_color *palette)
|
||||
{
|
||||
int32 numColors = 0;
|
||||
|
||||
for (int32 y = 0; y < bitsHeader.bounds.IntegerHeight() + 1; y++) {
|
||||
for (int32 x = 0; x < bitsHeader.bounds.IntegerWidth() + 1; x++) {
|
||||
ico_color color = get_ico_color_from_bits(bitsHeader, data, x, y);
|
||||
|
||||
int32 index = find_ico_color(palette, numColors, color);
|
||||
if (index == -1) {
|
||||
// add this color if there is space left
|
||||
if (numColors == 256)
|
||||
return -1;
|
||||
|
||||
palette[numColors++] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return numColors;
|
||||
}
|
||||
|
||||
|
||||
/** This function is used to determine, if a true alpha channel has to
|
||||
* be used in order to preserve all information.
|
||||
*/
|
||||
|
||||
static bool
|
||||
has_true_alpha_channel(color_space space, uint8 *data,
|
||||
int32 width, int32 height, int32 bytesPerRow)
|
||||
{
|
||||
for (int32 y = 0; y < height; y++) {
|
||||
for (int32 x = 0; x < width; x++) {
|
||||
uint8 value = get_alpha_value(space, ((uint32 *)data)[x]);
|
||||
if (value != 0 && value != 255)
|
||||
return true;
|
||||
}
|
||||
|
||||
data += bytesPerRow;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
convert_data_to_bits(ico_dir_entry &entry, ico_bitmap_header &header,
|
||||
const uint32 *palette, BPositionIO &source,
|
||||
BPositionIO &target)
|
||||
{
|
||||
uint16 bitsPerPixel = header.bits_per_pixel;
|
||||
|
||||
// round row bytes to next 4 byte boundary
|
||||
int32 xorRowBytes = get_bytes_per_row(entry.width, header.bits_per_pixel);
|
||||
int32 andRowBytes = get_bytes_per_row(entry.width, 1);
|
||||
int32 outRowBytes = entry.width * 4;
|
||||
|
||||
// allocate buffers
|
||||
TempAllocator xorAllocator, andAllocator, rowAllocator;
|
||||
|
||||
int32 xorDataSize = xorRowBytes * entry.height;
|
||||
uint8 *xorData = (uint8 *)xorAllocator.Allocate(xorDataSize);
|
||||
if (xorData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
int32 andDataSize = andRowBytes * entry.height;
|
||||
uint8 *andData = (uint8 *)andAllocator.Allocate(andDataSize);
|
||||
if (andData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
uint32 *outRowData = (uint32 *)rowAllocator.Allocate(outRowBytes);
|
||||
if (outRowData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
ssize_t bytesRead = source.Read(xorData, xorDataSize);
|
||||
if (bytesRead != xorDataSize)
|
||||
return B_BAD_DATA;
|
||||
|
||||
bytesRead = source.Read(andData, andDataSize);
|
||||
if (bytesRead != andDataSize)
|
||||
return B_BAD_DATA;
|
||||
|
||||
for (uint32 row = 0; row < entry.height; row++) {
|
||||
for (uint32 x = 0; x < entry.width; x++) {
|
||||
uint8 *line = get_data_row(xorData, xorDataSize, xorRowBytes, row);
|
||||
|
||||
if (palette != NULL) {
|
||||
uint8 index;
|
||||
|
||||
switch (bitsPerPixel) {
|
||||
case 1:
|
||||
index = get_1_bit_per_pixel(line, x);
|
||||
break;
|
||||
case 4:
|
||||
index = get_4_bits_per_pixel(line, x);
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
index = line[x];
|
||||
break;
|
||||
}
|
||||
|
||||
outRowData[x] = palette[index];
|
||||
} else
|
||||
outRowData[x] = ((uint32 *)line)[x];
|
||||
|
||||
if (bitsPerPixel != 32) {
|
||||
// set alpha channel
|
||||
if (get_1_bit_per_pixel(get_data_row(andData, andDataSize, andRowBytes, row), x))
|
||||
outRowData[x] = B_TRANSPARENT_MAGIC_RGBA32;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t bytesWritten = target.Write(outRowData, outRowBytes);
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
if (bytesWritten != outRowBytes)
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
convert_bits_to_data(TranslatorBitmap &bitsHeader, uint8 *bitsData, ico_dir_entry &entry,
|
||||
ico_bitmap_header &header, ico_color *palette, BPositionIO &target)
|
||||
{
|
||||
int32 bitsPerPixel = header.bits_per_pixel;
|
||||
|
||||
// round row bytes to next 4 byte boundary
|
||||
int32 xorRowBytes = get_bytes_per_row(entry.width, bitsPerPixel);
|
||||
int32 andRowBytes = get_bytes_per_row(entry.width, 1);
|
||||
|
||||
TempAllocator xorAllocator, andAllocator;
|
||||
|
||||
uint8 *xorRowData = (uint8 *)xorAllocator.Allocate(xorRowBytes);
|
||||
if (xorRowData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
uint8 *andRowData = (uint8 *)andAllocator.Allocate(andRowBytes);
|
||||
if (andRowData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
int32 numColors = 1 << bitsPerPixel;
|
||||
|
||||
// write XOR data (the actual image data)
|
||||
// (ICO data is upside down, so we're starting at the last line)
|
||||
|
||||
for (uint32 row = entry.height; row-- > 0;) {
|
||||
for (uint32 x = 0; x < entry.width; x++) {
|
||||
ico_color color = get_ico_color_from_bits(bitsHeader, bitsData, x, row);
|
||||
|
||||
if (palette != NULL) {
|
||||
uint8 index = find_ico_color(palette, numColors, color);
|
||||
|
||||
switch (bitsPerPixel) {
|
||||
case 1:
|
||||
set_1_bit_per_pixel(xorRowData, x, index);
|
||||
break;
|
||||
case 4:
|
||||
set_4_bits_per_pixel(xorRowData, x, index);
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
xorRowData[x] = index;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// ToDo: true color modi
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t bytesWritten = target.Write(xorRowData, xorRowBytes);
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
if (bytesWritten != xorRowBytes)
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
if (bitsPerPixel == 32) {
|
||||
// the alpha channel has already been written with the image data
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// write AND data (the transparency bit)
|
||||
|
||||
for (uint32 row = entry.height; row-- > 0;) {
|
||||
for (uint32 x = 0; x < entry.width; x++) {
|
||||
ico_color color = get_ico_color_from_bits(bitsHeader, bitsData, x, row);
|
||||
bool transparent = *(uint32 *)&color == B_TRANSPARENT_MAGIC_RGBA32;
|
||||
|
||||
set_1_bit_per_pixel(andRowData, x, transparent ? 1 : 0);
|
||||
}
|
||||
|
||||
ssize_t bytesWritten = target.Write(andRowData, andRowBytes);
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
if (bytesWritten != andRowBytes)
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
ICO::identify(BPositionIO &stream, int32 &bitsPerPixel)
|
||||
{
|
||||
// read in the header
|
||||
|
||||
ico_header header;
|
||||
if (stream.Read(&header, sizeof(ico_header)) != (ssize_t)sizeof(ico_header))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
header.SwapToHost();
|
||||
|
||||
// check header
|
||||
|
||||
if (!header.IsValid())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// read in directory entries
|
||||
|
||||
for (uint32 i = 0; i < header.entry_count; i++) {
|
||||
ico_dir_entry entry;
|
||||
if (stream.Read(&entry, sizeof(ico_dir_entry)) != (ssize_t)sizeof(ico_dir_entry))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
entry.SwapToHost();
|
||||
TRACE(("width: %d, height: %d, planes: %d, color_count: %d, bits_per_pixel: %d, size: %ld, offset: %ld\n",
|
||||
entry.width, entry.height, entry.planes, entry.color_count, entry.bits_per_pixel,
|
||||
entry.size, entry.offset));
|
||||
|
||||
ico_bitmap_header bitmapHeader;
|
||||
if (stream.ReadAt(entry.offset, &bitmapHeader, sizeof(ico_bitmap_header)) != (ssize_t)sizeof(ico_bitmap_header))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
bitmapHeader.SwapToHost();
|
||||
TRACE(("size: %ld, width: %ld, height: %ld, bits_per_pixel: %d, x/y per meter: %ld:%ld, compression: %ld, image_size: %ld, colors used: %ld, important colors: %ld\n",
|
||||
bitmapHeader.size, bitmapHeader.width, bitmapHeader.height, bitmapHeader.bits_per_pixel,
|
||||
bitmapHeader.x_pixels_per_meter, bitmapHeader.y_pixels_per_meter,
|
||||
bitmapHeader.compression, bitmapHeader.image_size, bitmapHeader.colors_used,
|
||||
bitmapHeader.important_colors));
|
||||
|
||||
if (!bitmapHeader.IsValid())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
bitsPerPixel = bitmapHeader.bits_per_pixel;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ICO::convert_ico_to_bits(BPositionIO &source, BPositionIO &target)
|
||||
{
|
||||
ico_header header;
|
||||
if (source.Read(&header, sizeof(ico_header)) != (ssize_t)sizeof(ico_header))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
header.SwapToHost();
|
||||
|
||||
// check header
|
||||
|
||||
if (!header.IsValid())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// read in first entry
|
||||
|
||||
ico_dir_entry entry;
|
||||
if (source.Read(&entry, sizeof(ico_dir_entry)) != (ssize_t)sizeof(ico_dir_entry))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
source.Seek(entry.offset, SEEK_SET);
|
||||
|
||||
ico_bitmap_header bitmapHeader;
|
||||
if (source.Read(&bitmapHeader, sizeof(ico_bitmap_header)) != (ssize_t)sizeof(ico_bitmap_header))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
entry.SwapToHost();
|
||||
bitmapHeader.SwapToHost();
|
||||
|
||||
if (!bitmapHeader.IsValid())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (bitmapHeader.compression != 0)
|
||||
return EOPNOTSUPP;
|
||||
|
||||
TranslatorBitmap bitsHeader;
|
||||
bitsHeader.magic = B_TRANSLATOR_BITMAP;
|
||||
bitsHeader.bounds.left = 0;
|
||||
bitsHeader.bounds.top = 0;
|
||||
bitsHeader.bounds.right = entry.width - 1;
|
||||
bitsHeader.bounds.bottom = entry.height - 1;
|
||||
bitsHeader.bounds.Set(0, 0, entry.width - 1, entry.height - 1);
|
||||
bitsHeader.rowBytes = entry.width * 4;
|
||||
bitsHeader.colors = B_RGBA32;
|
||||
bitsHeader.dataSize = bitsHeader.rowBytes * entry.height;
|
||||
|
||||
// read in palette
|
||||
int32 numColors = 0;
|
||||
if (bitmapHeader.bits_per_pixel <= 8)
|
||||
numColors = 1L << bitmapHeader.bits_per_pixel;
|
||||
|
||||
uint32 palette[256];
|
||||
if (numColors > 0) {
|
||||
if (source.Read(palette, numColors * 4) != numColors * 4)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// clear alpha channel
|
||||
for (int32 i = 0; i < numColors; i++)
|
||||
palette[i] &= 0xffffff;
|
||||
}
|
||||
|
||||
// write out Be's Bitmap header
|
||||
swap_data(B_UINT32_TYPE, &bitsHeader, sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN);
|
||||
target.Write(&bitsHeader, sizeof(TranslatorBitmap));
|
||||
|
||||
return convert_data_to_bits(entry, bitmapHeader, numColors > 0 ? palette : NULL, source, target);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ICO::convert_bits_to_ico(BPositionIO &source, TranslatorBitmap &bitsHeader, BPositionIO &target)
|
||||
{
|
||||
int32 width = bitsHeader.bounds.IntegerWidth() + 1;
|
||||
int32 height = bitsHeader.bounds.IntegerHeight() + 1;
|
||||
if (!is_valid_size(width) || !is_valid_size(height))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
int32 bitsPerPixel;
|
||||
switch (bitsHeader.colors) {
|
||||
case B_RGBA32:
|
||||
bitsPerPixel = 32;
|
||||
break;
|
||||
case B_RGB32:
|
||||
bitsPerPixel = 24;
|
||||
break;
|
||||
case B_RGB16:
|
||||
bitsPerPixel = 16;
|
||||
break;
|
||||
case B_CMAP8:
|
||||
case B_GRAY8:
|
||||
bitsPerPixel = 8;
|
||||
break;
|
||||
case B_GRAY1:
|
||||
bitsPerPixel = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unsupported color space.\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
TempAllocator dataAllocator;
|
||||
uint8 *bitsData = (uint8 *)dataAllocator.Allocate(bitsHeader.rowBytes * height);
|
||||
if (bitsData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
ssize_t bytesRead = source.Read(bitsData, bitsHeader.rowBytes * height);
|
||||
if (bytesRead < B_OK)
|
||||
return bytesRead;
|
||||
|
||||
ico_color palette[256];
|
||||
if (bitsPerPixel > 8) {
|
||||
// it's a non-palette mode - but does it have to be?
|
||||
if (bitsHeader.colors != B_RGBA32
|
||||
|| !has_true_alpha_channel(bitsHeader.colors, bitsData,
|
||||
width, height, bitsHeader.rowBytes)) {
|
||||
// count colors
|
||||
int32 colors = fill_palette(bitsHeader, bitsData, palette);
|
||||
if (colors != -1) {
|
||||
// we fit into a palette mode
|
||||
if (colors > 16)
|
||||
bitsPerPixel = 8;
|
||||
else if (colors > 2)
|
||||
bitsPerPixel = 4;
|
||||
else
|
||||
bitsPerPixel = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ico_header header;
|
||||
header.type = B_HOST_TO_LENDIAN_INT16(1);
|
||||
header.entry_count = B_HOST_TO_LENDIAN_INT16(1);
|
||||
header.reserved = 0;
|
||||
|
||||
ssize_t bytesWritten = target.Write(&header, sizeof(ico_header));
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
|
||||
ico_dir_entry entry;
|
||||
entry.width = width;
|
||||
entry.height = height;
|
||||
entry.planes = 1;
|
||||
entry.bits_per_pixel = bitsPerPixel;
|
||||
entry.color_count = 0;
|
||||
if (bitsPerPixel <= 8)
|
||||
entry.color_count = 1 << bitsPerPixel;
|
||||
|
||||
// When bits_per_pixel == 32, the data already contains the alpha channel
|
||||
|
||||
int32 xorRowBytes = get_bytes_per_row(width, bitsPerPixel);
|
||||
int32 andRowBytes = 0;
|
||||
if (bitsPerPixel != 32)
|
||||
andRowBytes = get_bytes_per_row(width, 1);
|
||||
|
||||
entry.size = sizeof(ico_bitmap_header) + width * (xorRowBytes + andRowBytes);
|
||||
entry.offset = sizeof(ico_header) + sizeof(ico_dir_entry);
|
||||
entry.reserved = 0;
|
||||
|
||||
ico_bitmap_header bitmapHeader;
|
||||
memset(&bitmapHeader, 0, sizeof(ico_bitmap_header));
|
||||
bitmapHeader.size = sizeof(ico_bitmap_header);
|
||||
bitmapHeader.width = width;
|
||||
bitmapHeader.height = height + (bitsPerPixel == 32 ? 0 : height);
|
||||
bitmapHeader.bits_per_pixel = bitsPerPixel;
|
||||
bitmapHeader.planes = 1;
|
||||
bitmapHeader.image_size = 0;
|
||||
|
||||
entry.SwapFromHost();
|
||||
bitmapHeader.SwapFromHost();
|
||||
|
||||
bytesWritten = target.Write(&entry, sizeof(ico_dir_entry));
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
|
||||
bytesWritten = target.Write(&bitmapHeader, sizeof(ico_bitmap_header));
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
|
||||
// we'll need them in convert_bits_to_data()
|
||||
entry.SwapToHost();
|
||||
bitmapHeader.SwapToHost();
|
||||
|
||||
if (bitsPerPixel <= 8) {
|
||||
bytesWritten = target.Write(palette, (1L << bitsPerPixel) * sizeof(ico_color));
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
return convert_bits_to_data(bitsHeader, bitsData, entry, bitmapHeader,
|
||||
bitsPerPixel <= 8 ? palette : NULL, target);
|
||||
}
|
||||
|
82
src/add-ons/translators/icotranslator/ICO.h
Normal file
82
src/add-ons/translators/icotranslator/ICO.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ICO_H
|
||||
#define ICO_H
|
||||
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
#include <BufferIO.h>
|
||||
#include <TranslatorFormats.h>
|
||||
|
||||
|
||||
namespace ICO {
|
||||
|
||||
// All ICO structures are written in little endian format
|
||||
|
||||
struct ico_header {
|
||||
uint16 reserved;
|
||||
uint16 type;
|
||||
uint16 entry_count;
|
||||
|
||||
bool IsValid() const { return reserved == 0 && type == 1 && entry_count < 32; }
|
||||
void SwapToHost();
|
||||
void SwapFromHost();
|
||||
} _PACKED;
|
||||
|
||||
struct ico_dir_entry {
|
||||
uint8 width;
|
||||
uint8 height;
|
||||
uint8 color_count;
|
||||
uint8 reserved;
|
||||
|
||||
uint16 planes;
|
||||
uint16 bits_per_pixel;
|
||||
uint32 size;
|
||||
uint32 offset;
|
||||
|
||||
bool IsValid() const { return bits_per_pixel <= 24; }
|
||||
void SwapToHost();
|
||||
void SwapFromHost();
|
||||
} _PACKED;
|
||||
|
||||
struct ico_bitmap_header {
|
||||
uint32 size; // size of this structure
|
||||
uint32 width;
|
||||
uint32 height;
|
||||
uint16 planes;
|
||||
uint16 bits_per_pixel; // 1, 4, 8, 16, or 24 bits per pixel
|
||||
uint32 compression;
|
||||
uint32 image_size;
|
||||
uint32 x_pixels_per_meter; // aspect ratio
|
||||
uint32 y_pixels_per_meter;
|
||||
uint32 colors_used; // number of actually used colors
|
||||
uint32 important_colors; // number of important colors (zero = all)
|
||||
|
||||
bool IsValid() const;
|
||||
void SwapToHost();
|
||||
void SwapFromHost();
|
||||
} _PACKED;
|
||||
|
||||
struct ico_color {
|
||||
uint8 blue;
|
||||
uint8 green;
|
||||
uint8 red;
|
||||
uint8 alpha;
|
||||
|
||||
inline bool
|
||||
operator==(const ico_color& other) const
|
||||
{
|
||||
return *(const uint32 *)this == *(const uint32 *)&other;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern status_t identify(BPositionIO &stream, int32 &bitsPerPixel);
|
||||
extern status_t convert_ico_to_bits(BPositionIO &source, BPositionIO &target);
|
||||
extern status_t convert_bits_to_ico(BPositionIO &source, TranslatorBitmap &bitsHeader, BPositionIO &target);
|
||||
|
||||
} // namespace ICO
|
||||
|
||||
#endif /* ICO_H */
|
172
src/add-ons/translators/icotranslator/ICOTranslator.cpp
Normal file
172
src/add-ons/translators/icotranslator/ICOTranslator.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ICOTranslator.h"
|
||||
#include "ConfigView.h"
|
||||
#include "ICO.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define READ_BUFFER_SIZE 2048
|
||||
#define DATA_BUFFER_SIZE 64
|
||||
|
||||
|
||||
// The input formats that this translator supports.
|
||||
translation_format sInputFormats[] = {
|
||||
{
|
||||
ICO_IMAGE_FORMAT,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
ICO_IN_QUALITY,
|
||||
ICO_IN_CAPABILITY,
|
||||
"image/x-icon",
|
||||
"Windows Icon image"
|
||||
},
|
||||
{
|
||||
B_TRANSLATOR_BITMAP,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
BITS_IN_QUALITY,
|
||||
BITS_IN_CAPABILITY,
|
||||
"x-be-bitmap",
|
||||
"Be Bitmap image"
|
||||
},
|
||||
};
|
||||
|
||||
// The output formats that this translator supports.
|
||||
translation_format sOutputFormats[] = {
|
||||
{
|
||||
ICO_IMAGE_FORMAT,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
ICO_OUT_QUALITY,
|
||||
ICO_OUT_CAPABILITY,
|
||||
"image/x-icon",
|
||||
"Windows Icon image"
|
||||
},
|
||||
{
|
||||
B_TRANSLATOR_BITMAP,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
BITS_OUT_QUALITY,
|
||||
BITS_OUT_CAPABILITY,
|
||||
"x-be-bitmap",
|
||||
"Be Bitmap image"
|
||||
},
|
||||
};
|
||||
|
||||
// Default settings for the Translator
|
||||
static TranSetting sDefaultSettings[] = {
|
||||
{B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
|
||||
{B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false}
|
||||
};
|
||||
|
||||
const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
|
||||
const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
|
||||
const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
|
||||
|
||||
|
||||
ICOTranslator::ICOTranslator()
|
||||
: BaseTranslator("Windows Icon Images", "Windows Icon Translator",
|
||||
ICO_TRANSLATOR_VERSION,
|
||||
sInputFormats, kNumInputFormats,
|
||||
sOutputFormats, kNumOutputFormats,
|
||||
"ICOTranslator_Settings",
|
||||
sDefaultSettings, kNumDefaultSettings,
|
||||
B_TRANSLATOR_BITMAP, ICO_IMAGE_FORMAT)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ICOTranslator::~ICOTranslator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ICOTranslator::DerivedIdentify(BPositionIO *stream,
|
||||
const translation_format *format, BMessage *ioExtension,
|
||||
translator_info *info, uint32 outType)
|
||||
{
|
||||
if (!outType)
|
||||
outType = B_TRANSLATOR_BITMAP;
|
||||
if (outType != B_TRANSLATOR_BITMAP && outType != ICO_IMAGE_FORMAT)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
int32 bitsPerPixel;
|
||||
if (ICO::identify(*stream, bitsPerPixel) != B_OK)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
info->type = ICO_IMAGE_FORMAT;
|
||||
info->group = B_TRANSLATOR_BITMAP;
|
||||
info->quality = ICO_IN_QUALITY;
|
||||
info->capability = ICO_IN_CAPABILITY;
|
||||
snprintf(info->name, sizeof(info->name), "Windows Icon %ld bit image", bitsPerPixel);
|
||||
strcpy(info->MIME, "image/x-ico");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ICOTranslator::DerivedTranslate(BPositionIO *source,
|
||||
const translator_info *info, BMessage *ioExtension,
|
||||
uint32 outType, BPositionIO *target, int32 baseType)
|
||||
{
|
||||
if (!outType)
|
||||
outType = B_TRANSLATOR_BITMAP;
|
||||
if (outType != B_TRANSLATOR_BITMAP && outType != ICO_IMAGE_FORMAT)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
switch (baseType) {
|
||||
case 1:
|
||||
{
|
||||
if (outType != ICO_IMAGE_FORMAT)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
// Source is in bits format - this has to be done here, because
|
||||
// identify_bits_header() is a member of the BaseTranslator class...
|
||||
TranslatorBitmap bitsHeader;
|
||||
status_t status = identify_bits_header(source, NULL, &bitsHeader);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return ICO::convert_bits_to_ico(*source, bitsHeader, *target);
|
||||
}
|
||||
|
||||
case 0:
|
||||
{
|
||||
// source is NOT in bits format
|
||||
if (outType != B_TRANSLATOR_BITMAP)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
return ICO::convert_ico_to_bits(*source, *target);
|
||||
}
|
||||
|
||||
default:
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BView *
|
||||
ICOTranslator::NewConfigView(TranslatorSettings *settings)
|
||||
{
|
||||
return new ConfigView(BRect(0, 0, 225, 175));
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
BTranslator *
|
||||
make_nth_translator(int32 n, image_id you, uint32 flags, ...)
|
||||
{
|
||||
if (n != 0)
|
||||
return NULL;
|
||||
|
||||
return new ICOTranslator();
|
||||
}
|
||||
|
58
src/add-ons/translators/icotranslator/ICOTranslator.h
Normal file
58
src/add-ons/translators/icotranslator/ICOTranslator.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ICO_TRANSLATOR_H
|
||||
#define ICO_TRANSLATOR_H
|
||||
|
||||
|
||||
#include <BaseTranslator.h>
|
||||
|
||||
#include <Translator.h>
|
||||
#include <TranslatorFormats.h>
|
||||
#include <TranslationDefs.h>
|
||||
#include <GraphicsDefs.h>
|
||||
#include <InterfaceDefs.h>
|
||||
#include <DataIO.h>
|
||||
#include <File.h>
|
||||
#include <ByteOrder.h>
|
||||
|
||||
|
||||
#define ICO_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(0, 1, 0)
|
||||
#define ICO_IMAGE_FORMAT 'ICO '
|
||||
|
||||
#define ICO_IN_QUALITY 0.5
|
||||
#define ICO_IN_CAPABILITY 0.5
|
||||
#define BITS_IN_QUALITY 1
|
||||
#define BITS_IN_CAPABILITY 1
|
||||
|
||||
#define ICO_OUT_QUALITY 0.8
|
||||
#define ICO_OUT_CAPABILITY 0.8
|
||||
#define BITS_OUT_QUALITY 1
|
||||
#define BITS_OUT_CAPABILITY 0.9
|
||||
|
||||
|
||||
class ICOTranslator : public BaseTranslator {
|
||||
public:
|
||||
ICOTranslator();
|
||||
|
||||
virtual status_t DerivedIdentify(BPositionIO *inSource,
|
||||
const translation_format *inFormat, BMessage *ioExtension,
|
||||
translator_info *outInfo, uint32 outType);
|
||||
|
||||
virtual status_t DerivedTranslate(BPositionIO *inSource,
|
||||
const translator_info *inInfo, BMessage *ioExtension,
|
||||
uint32 outType, BPositionIO *outDestination, int32 baseType);
|
||||
|
||||
virtual BView *NewConfigView(TranslatorSettings *settings);
|
||||
|
||||
protected:
|
||||
virtual ~ICOTranslator();
|
||||
// this is protected because the object is deleted by the
|
||||
// Release() function instead of being deleted directly by
|
||||
// the user
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif /* ICO_TRANSLATOR_H */
|
24
src/add-ons/translators/icotranslator/Jamfile
Normal file
24
src/add-ons/translators/icotranslator/Jamfile
Normal file
@ -0,0 +1,24 @@
|
||||
SubDir OBOS_TOP src add-ons translators icotranslator ;
|
||||
|
||||
# Include code from shared translator directory
|
||||
SEARCH_SOURCE += [ FDirName $(OBOS_TOP) src add-ons translators shared ] ;
|
||||
|
||||
Translator ICOTranslator :
|
||||
# ICOTranslator classes
|
||||
main.cpp
|
||||
ICOTranslator.cpp
|
||||
ConfigView.cpp
|
||||
ICO.cpp
|
||||
|
||||
# shared classes
|
||||
BaseTranslator.cpp
|
||||
TranslatorSettings.cpp
|
||||
TranslatorWindow.cpp
|
||||
;
|
||||
|
||||
LinkSharedOSLibs ICOTranslator : be translation ;
|
||||
|
||||
Package haiku-translationkit-cvs :
|
||||
ICOTranslator
|
||||
: boot home config add-ons Translators
|
||||
;
|
32
src/add-ons/translators/icotranslator/main.cpp
Normal file
32
src/add-ons/translators/icotranslator/main.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ICOTranslator.h"
|
||||
#include "ICO.h"
|
||||
|
||||
#include <TranslatorWindow.h>
|
||||
#include <Application.h>
|
||||
/*
|
||||
#include <TranslatorRoster.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
*/
|
||||
|
||||
int
|
||||
main(int /*argc*/, char **/*argv*/)
|
||||
{
|
||||
BApplication app("application/x-vnd.haiku-ico-translator");
|
||||
|
||||
status_t result;
|
||||
result = LaunchTranslatorWindow(new ICOTranslator, "ICO Settings", BRect(0, 0, 225, 175));
|
||||
if (result != B_OK)
|
||||
return 1;
|
||||
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user