#include <new>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <Catalog.h>
#include <OS.h>
#include "SGIImage.h"
#include "SGITranslator.h"
#include "SGIView.h"
using std::nothrow;
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SGITranslator"
static const translation_format sInputFormats[] = {
{
B_TRANSLATOR_BITMAP,
B_TRANSLATOR_BITMAP,
BBT_IN_QUALITY,
BBT_IN_CAPABILITY,
"image/x-be-bitmap",
"Be Bitmap Format (SGITranslator)"
},
{
SGI_FORMAT,
B_TRANSLATOR_BITMAP,
SGI_IN_QUALITY,
SGI_IN_CAPABILITY,
"image/sgi",
"SGI image"
}
};
static const translation_format sOutputFormats[] = {
{
B_TRANSLATOR_BITMAP,
B_TRANSLATOR_BITMAP,
BBT_OUT_QUALITY,
BBT_OUT_CAPABILITY,
"image/x-be-bitmap",
"Be Bitmap Format (SGITranslator)"
},
{
SGI_FORMAT,
B_TRANSLATOR_BITMAP,
SGI_OUT_QUALITY,
SGI_OUT_CAPABILITY,
"image/sgi",
"SGI image"
}
};
static const TranSetting sDefaultSettings[] = {
{B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
{B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false},
{SGI_SETTING_COMPRESSION, TRAN_SETTING_INT32, SGI_COMP_RLE}
};
const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
BTranslator *
make_nth_translator(int32 n, image_id you, uint32 flags, ...)
{
if (!n)
return new SGITranslator();
else
return NULL;
}
SGITranslator::SGITranslator()
:
BaseTranslator(B_TRANSLATE("SGI images"),
B_TRANSLATE("SGI image translator"),
SGI_TRANSLATOR_VERSION,
sInputFormats, kNumInputFormats,
sOutputFormats, kNumOutputFormats,
"SGITranslator_Settings",
sDefaultSettings, kNumDefaultSettings,
B_TRANSLATOR_BITMAP, SGI_FORMAT)
{
}
SGITranslator::~SGITranslator()
{
}
status_t
identify_sgi_header(BPositionIO *inSource, translator_info *outInfo, uint32 outType,
SGIImage **poutSGIImage = NULL)
{
status_t status = B_NO_MEMORY;
SGIImage* sgiImage = new(nothrow) SGIImage();
if (sgiImage)
status = sgiImage->SetTo(inSource);
if (status >= B_OK) {
if (outInfo) {
outInfo->type = SGI_FORMAT;
outInfo->group = B_TRANSLATOR_BITMAP;
outInfo->quality = SGI_IN_QUALITY;
outInfo->capability = SGI_IN_CAPABILITY;
strcpy(outInfo->MIME, "image/sgi");
strlcpy(outInfo->name, B_TRANSLATE("SGI image"),
sizeof(outInfo->name));
}
} else {
delete sgiImage;
sgiImage = NULL;
}
if (!poutSGIImage)
delete sgiImage;
else
*poutSGIImage = sgiImage;
return status;
}
status_t
SGITranslator::DerivedIdentify(BPositionIO *inSource,
const translation_format *inFormat, BMessage *ioExtension,
translator_info *outInfo, uint32 outType)
{
return identify_sgi_header(inSource, outInfo, outType);
}
status_t
SGITranslator::translate_from_bits(BPositionIO *inSource, uint32 outType,
BPositionIO *outDestination)
{
TranslatorBitmap bitsHeader;
uint32 compression = fSettings->SetGetInt32(SGI_SETTING_COMPRESSION);
status_t ret = identify_bits_header(inSource, NULL, &bitsHeader);
if (ret < B_OK)
return ret;
if (outType == SGI_FORMAT) {
uint32 width = bitsHeader.bounds.IntegerWidth() + 1;
uint32 height = bitsHeader.bounds.IntegerHeight() + 1;
uint32 bytesPerRow = bitsHeader.rowBytes;
uint32 bytesPerChannel = 1;
color_space format = bitsHeader.colors;
uint32 channelCount;
switch (format) {
case B_GRAY8:
channelCount = 1;
break;
case B_RGB32:
case B_RGB32_BIG:
case B_RGB24:
case B_RGB24_BIG:
channelCount = 3;
break;
case B_RGBA32:
case B_RGBA32_BIG:
channelCount = 4;
break;
default:
return B_NO_TRANSLATOR;
}
SGIImage* sgiImage = new SGIImage();
status_t ret = sgiImage->SetTo(outDestination, width, height,
channelCount, bytesPerChannel, compression);
if (ret >= B_OK) {
uint8** rows = new(nothrow) uint8*[channelCount];
if (rows)
rows[0] = new(nothrow) uint8[width * channelCount * bytesPerChannel];
uint8* rowBuffer = new(nothrow) uint8[bytesPerRow];
if (rows && rows[0] && rowBuffer) {
for (uint32 i = 1; i < channelCount; i++)
rows[i] = rows[0] + i * width;
for (int32 y = height - 1; y >= 0 && ret >= B_OK; y--) {
ret = inSource->Read(rowBuffer, bytesPerRow);
if (ret < B_OK)
break;
switch (format) {
case B_GRAY8: {
uint8* src = rowBuffer;
for (uint32 x = 0; x < width; x++) {
rows[0][x] = src[0];
src += 1;
}
break;
}
case B_RGB24: {
uint8* src = rowBuffer;
for (uint32 x = 0; x < width; x++) {
rows[0][x] = src[2];
rows[1][x] = src[1];
rows[2][x] = src[0];
src += 3;
}
break;
}
case B_RGB24_BIG: {
uint8* src = rowBuffer;
for (uint32 x = 0; x < width; x++) {
rows[0][x] = src[0];
rows[1][x] = src[1];
rows[2][x] = src[2];
src += 3;
}
break;
}
case B_RGB32: {
uint8* src = rowBuffer;
for (uint32 x = 0; x < width; x++) {
rows[0][x] = src[2];
rows[1][x] = src[1];
rows[2][x] = src[0];
src += 4;
}
break;
}
case B_RGB32_BIG: {
uint8* src = rowBuffer;
for (uint32 x = 0; x < width; x++) {
rows[0][x] = src[1];
rows[1][x] = src[2];
rows[2][x] = src[3];
src += 4;
}
break;
}
case B_RGBA32: {
uint8* src = rowBuffer;
for (uint32 x = 0; x < width; x++) {
rows[0][x] = src[2];
rows[1][x] = src[1];
rows[2][x] = src[0];
rows[3][x] = src[3];
src += 4;
}
break;
}
case B_RGBA32_BIG: {
uint8* src = rowBuffer;
for (uint32 x = 0; x < width; x++) {
rows[0][x] = src[1];
rows[1][x] = src[2];
rows[2][x] = src[3];
rows[3][x] = src[0];
src += 4;
}
break;
}
default:
break;
}
for (uint32 z = 0; z < channelCount; z++) {
ret = sgiImage->WriteRow(rows[z], y, z);
if (ret < B_OK) {
syslog(LOG_ERR,
"WriteRow() returned %s!\n", strerror(ret));
break;
}
}
}
if (ret >= B_OK)
ret = B_OK;
} else
ret = B_NO_MEMORY;
delete[] rows[0];
delete[] rows;
delete[] rowBuffer;
}
delete sgiImage;
return ret;
}
return B_NO_TRANSLATOR;
}
status_t
SGITranslator::translate_from_sgi(BPositionIO *inSource, uint32 outType,
BPositionIO *outDestination)
{
status_t ret = B_NO_TRANSLATOR;
if (outType == SGI_FORMAT) {
translate_direct_copy(inSource, outDestination);
return B_OK;
}
SGIImage* sgiImage = NULL;
ret = identify_sgi_header(inSource, NULL, outType, &sgiImage);
if (ret >= B_OK) {
bool bheaderonly = false, bdataonly = false;
uint32 width = sgiImage->Width();
uint32 height = sgiImage->Height();
uint32 channelCount = sgiImage->CountChannels();
color_space format = B_RGBA32;
uint32 bytesPerRow = 0;
uint32 bytesPerChannel = sgiImage->BytesPerChannel();
if (channelCount == 1) {
format = B_RGB32;
bytesPerRow = width * 4;
} else if (channelCount == 2) {
format = B_RGBA32;
bytesPerRow = width * 4;
} else if (channelCount == 3) {
format = B_RGB32;
bytesPerRow = width * 4;
} else if (channelCount == 4) {
format = B_RGBA32;
bytesPerRow = width * 4;
} else
ret = B_NO_TRANSLATOR;
if (ret >= B_OK && !bdataonly) {
TranslatorBitmap bitsHeader;
bitsHeader.magic = B_TRANSLATOR_BITMAP;
bitsHeader.bounds.left = 0;
bitsHeader.bounds.top = 0;
bitsHeader.bounds.right = width - 1;
bitsHeader.bounds.bottom = height - 1;
bitsHeader.rowBytes = bytesPerRow;
bitsHeader.colors = format;
bitsHeader.dataSize = bitsHeader.rowBytes * height;
if ((ret = swap_data(B_UINT32_TYPE, &bitsHeader,
sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN)) < B_OK) {
return ret;
} else
ret = outDestination->Write(&bitsHeader,
sizeof(TranslatorBitmap));
}
if (ret < B_OK)
syslog(LOG_ERR, "error writing bits header: %s\n", strerror(ret));
if (ret >= B_OK && !bheaderonly) {
uint8** rows = new(nothrow) uint8*[channelCount];
if (rows)
rows[0] = new(nothrow) uint8[width * channelCount * bytesPerChannel];
uint8* rowBuffer = new(nothrow) uint8[bytesPerRow];
if (rows && rows[0] && rowBuffer) {
for (uint32 i = 1; i < channelCount; i++)
rows[i] = rows[0] + i * width * bytesPerChannel;
for (int32 y = height - 1; y >= 0 && ret >= B_OK; y--) {
for (uint32 z = 0; z < channelCount; z++) {
ret = sgiImage->ReadRow(rows[z], y, z);
if (ret < B_OK)
break;
}
if (ret < B_OK)
break;
if (bytesPerChannel == 1) {
switch (format) {
case B_GRAY8: {
uint8* dst = rowBuffer;
for (uint32 x = 0; x < width; x++) {
dst[0] = rows[0][x];
dst += 1;
}
break;
}
case B_RGB24: {
uint8* dst = rowBuffer;
for (uint32 x = 0; x < width; x++) {
dst[0] = rows[2][x];
dst[1] = rows[1][x];
dst[2] = rows[0][x];
dst += 3;
}
break;
}
case B_RGB32: {
uint8* dst = rowBuffer;
if (channelCount == 1) {
for (uint32 x = 0; x < width; x++) {
dst[0] = rows[0][x];
dst[1] = rows[0][x];
dst[2] = rows[0][x];
dst[3] = 255;
dst += 4;
}
} else {
for (uint32 x = 0; x < width; x++) {
dst[0] = rows[2][x];
dst[1] = rows[1][x];
dst[2] = rows[0][x];
dst[3] = 255;
dst += 4;
}
}
break;
}
case B_RGBA32: {
uint8* dst = rowBuffer;
if (channelCount == 2) {
for (uint32 x = 0; x < width; x++) {
dst[0] = rows[0][x];
dst[1] = rows[0][x];
dst[2] = rows[0][x];
dst[3] = rows[1][x];
dst += 4;
}
} else {
for (uint32 x = 0; x < width; x++) {
dst[0] = rows[2][x];
dst[1] = rows[1][x];
dst[2] = rows[0][x];
dst[3] = rows[3][x];
dst += 4;
}
}
break;
}
default:
break;
}
ret = outDestination->Write(rowBuffer, bytesPerRow);
} else {
uint16** rows16 = (uint16**)rows;
switch (format) {
case B_GRAY8: {
uint8* dst = rowBuffer;
for (uint32 x = 0; x < width; x++) {
dst[0] = rows16[0][x] >> 8;
dst += 1;
}
break;
}
case B_RGB24: {
uint8* dst = rowBuffer;
for (uint32 x = 0; x < width; x++) {
dst[0] = rows16[2][x] >> 8;
dst[1] = rows16[1][x] >> 8;
dst[2] = rows16[0][x] >> 8;
dst += 3;
}
break;
}
case B_RGB32: {
uint8* dst = rowBuffer;
if (channelCount == 1) {
for (uint32 x = 0; x < width; x++) {
dst[0] = rows16[0][x] >> 8;
dst[1] = rows16[0][x] >> 8;
dst[2] = rows16[0][x] >> 8;
dst[3] = 255;
dst += 4;
}
} else {
for (uint32 x = 0; x < width; x++) {
dst[0] = rows16[2][x] >> 8;
dst[1] = rows16[1][x] >> 8;
dst[2] = rows16[0][x] >> 8;
dst[3] = 255;
dst += 4;
}
}
break;
}
case B_RGBA32: {
uint8* dst = rowBuffer;
if (channelCount == 2) {
for (uint32 x = 0; x < width; x++) {
dst[0] = rows16[0][x] >> 8;
dst[1] = rows16[0][x] >> 8;
dst[2] = rows16[0][x] >> 8;
dst[3] = rows16[1][x] >> 8;
dst += 4;
}
} else {
for (uint32 x = 0; x < width; x++) {
dst[0] = rows16[2][x] >> 8;
dst[1] = rows16[1][x] >> 8;
dst[2] = rows16[0][x] >> 8;
dst[3] = rows16[3][x] >> 8;
dst += 4;
}
}
break;
}
default:
break;
}
ret = outDestination->Write(rowBuffer, bytesPerRow);
}
}
if (ret >= B_OK)
ret = B_OK;
} else
ret = B_NO_MEMORY;
delete[] rows[0];
delete[] rows;
delete[] rowBuffer;
}
}
delete sgiImage;
return ret;
}
status_t
SGITranslator::DerivedTranslate(BPositionIO *inSource,
const translator_info *inInfo, BMessage *ioExtension,
uint32 outType, BPositionIO *outDestination, int32 baseType)
{
if (baseType == 1)
return translate_from_bits(inSource, outType, outDestination);
else if (baseType == 0)
return translate_from_sgi(inSource, outType, outDestination);
else
return B_NO_TRANSLATOR;
}
BView *
SGITranslator::NewConfigView(TranslatorSettings *settings)
{
return new SGIView(B_TRANSLATE("SGITranslator Settings"), B_WILL_DRAW,
settings);
}