/*****************************************************************************/
// SGITranslator
// Written by Stephan Aßmus
// based on TIFFTranslator written mostly by
// Michael Wilber
//
// SGITranslator.cpp
//
// This BTranslator based object is for opening and writing
// SGI images.
//
//
// Copyright (c) 2003-2009 Haiku, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
/*****************************************************************************/
//
// How this works:
//
// libtiff has a special version of SGIOpen() that gets passed custom
// functions for reading writing etc. and a handle. This handle in our case
// is a BPositionIO object, which libtiff passes on to the functions for reading
// writing etc. So when operations are performed on the SGI* handle that is
// returned by SGIOpen(), libtiff uses the special reading writing etc
// functions so that all stream io happens on the BPositionIO object.
#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"
// The input formats that this translator supports.
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"
}
};
// The output formats that this translator supports.
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"
}
};
// Default settings for the Translator
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}
// compression is set to RLE by default
};
const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
// ---------------------------------------------------------------
// make_nth_translator
//
// Creates a SGITranslator object to be used by BTranslatorRoster
//
// Preconditions:
//
// Parameters: n, The translator to return. Since
// SGITranslator only publishes one
// translator, it only returns a
// SGITranslator if n == 0
//
// you, The image_id of the add-on that
// contains code (not used).
//
// flags, Has no meaning yet, should be 0.
//
// Postconditions:
//
// Returns: NULL if n is not zero,
// a new SGITranslator if n is zero
// ---------------------------------------------------------------
BTranslator *
make_nth_translator(int32 n, image_id you, uint32 flags, ...)
{
if (!n)
return new SGITranslator();
else
return NULL;
}
// ---------------------------------------------------------------
// Constructor
//
// Sets up the version info and the name of the translator so that
// these values can be returned when they are requested.
//
// Preconditions:
//
// Parameters:
//
// Postconditions:
//
// Returns:
// ---------------------------------------------------------------
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)
{
}
// ---------------------------------------------------------------
// Destructor
//
// Does nothing
//
// Preconditions:
//
// Parameters:
//
// Postconditions:
//
// Returns:
// ---------------------------------------------------------------
SGITranslator::~SGITranslator()
{
}
status_t
identify_sgi_header(BPositionIO *inSource, translator_info *outInfo, uint32 outType,
SGIImage **poutSGIImage = NULL)
{
status_t status = B_NO_MEMORY;
// construct new SGIImage object and set it to the provided BPositionIO
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)
// close SGIImage if caller is not interested in SGIImage handle
delete sgiImage;
else
// leave SGIImage open (if it is) and return handle if caller needs it
*poutSGIImage = sgiImage;
return status;
}
// ---------------------------------------------------------------
// DerivedIdentify
//
// Examines the data from inSource and determines if it is in a
// format that this translator knows how to work with.
//
// Preconditions:
//
// Parameters: inSource, where the data to examine is
//
// inFormat, a hint about the data in inSource,
// it is ignored since it is only a hint
//
// ioExtension, configuration settings for the
// translator (not used)
//
// outInfo, information about what data is in
// inSource and how well this translator
// can handle that data is stored here
//
// outType, The format that the user wants
// the data in inSource to be
// converted to
//
// Postconditions:
//
// Returns: B_NO_TRANSLATOR, if this translator can't handle
// the data in inSource
//
// B_ERROR, if there was an error converting the data to the host
// format
//
// B_BAD_VALUE, if the settings in ioExtension are bad
//
// B_OK, if this translator understood the data and there were
// no errors found
//
// Other errors if BPositionIO::Read() returned an error value
// ---------------------------------------------------------------
status_t
SGITranslator::DerivedIdentify(BPositionIO *inSource,
const translation_format *inFormat, BMessage *ioExtension,
translator_info *outInfo, uint32 outType)
{
return identify_sgi_header(inSource, outInfo, outType);
}
// translate_from_bits
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;
// Translate B_TRANSLATOR_BITMAP to SGI_FORMAT
if (outType == SGI_FORMAT) {
// common fields which are independent of the bitmap 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;
}
// Set up SGI header
SGIImage* sgiImage = new SGIImage();
status_t ret = sgiImage->SetTo(outDestination, width, height,
channelCount, bytesPerChannel, compression);
if (ret >= B_OK) {
// read one row at a time,
// convert to the correct format
// and write out the results
// SGI Images store each channel separately
// a buffer is allocated big enough to hold all channels
// then the pointers are assigned with offsets into that buffer
uint8** rows = new(nothrow) uint8*[channelCount];
if (rows)
rows[0] = new(nothrow) uint8[width * channelCount * bytesPerChannel];
// rowBuffer is going to hold the converted data
uint8* rowBuffer = new(nothrow) uint8[bytesPerRow];
if (rows && rows[0] && rowBuffer) {
// assign the other pointers (channel offsets in row buffer)
for (uint32 i = 1; i < channelCount; i++)
rows[i] = rows[0] + i * width;
// loop through all lines of the image
for (int32 y = height - 1; y >= 0 && ret >= B_OK; y--) {
ret = inSource->Read(rowBuffer, bytesPerRow);
// see if an error happened while reading
if (ret < B_OK)
break;
// convert to native format (big endian)
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];
// ignore src[3]
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];
// ignore src[0]
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:
// cannot be here
break;
} // switch (format)
// for each channel, write a row buffer
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;
}
}
} // for (uint32 y = 0; y < height && ret >= B_OK; y++)
if (ret >= B_OK)
ret = B_OK;
} else // if (rows && rows[0] && rowBuffer)
ret = B_NO_MEMORY;
delete[] rows[0];
delete[] rows;
delete[] rowBuffer;
}
// done with the SGIImage object
delete sgiImage;
return ret;
}
return B_NO_TRANSLATOR;
}
// translate_from_sgi
status_t
SGITranslator::translate_from_sgi(BPositionIO *inSource, uint32 outType,
BPositionIO *outDestination)
{
status_t ret = B_NO_TRANSLATOR;
// if copying SGI_FORMAT to SGI_FORMAT
if (outType == SGI_FORMAT) {
translate_direct_copy(inSource, outDestination);
return B_OK;
}
// variables needing cleanup
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_GRAY8; // this format is not supported by most applications
// bytesPerRow = width;
format = B_RGB32;
bytesPerRow = width * 4;
} else if (channelCount == 2) {
// means gray (luminance) + alpha, we convert that to B_RGBA32
format = B_RGBA32;
bytesPerRow = width * 4;
} else if (channelCount == 3) {
format = B_RGB32; // should be B_RGB24, but let's not push it too hard...
bytesPerRow = width * 4;
} else if (channelCount == 4) {
format = B_RGBA32;
bytesPerRow = width * 4;
} else
ret = B_NO_TRANSLATOR; // we cannot handle this image
if (ret >= B_OK && !bdataonly) {
// Construct and write Be bitmap header
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) {
// read one row at a time,
// convert to the correct format
// and write out the results
// SGI Images store each channel separately
// a buffer is allocated big enough to hold all channels
// then the pointers are assigned with offsets into that buffer
uint8** rows = new(nothrow) uint8*[channelCount];
if (rows)
rows[0] = new(nothrow) uint8[width * channelCount * bytesPerChannel];
// rowBuffer is going to hold the converted data
uint8* rowBuffer = new(nothrow) uint8[bytesPerRow];
if (rows && rows[0] && rowBuffer) {
// assign the other pointers (channel offsets in row buffer)
for (uint32 i = 1; i < channelCount; i++)
rows[i] = rows[0] + i * width * bytesPerChannel;
// loop through all lines of the image
for (int32 y = height - 1; y >= 0 && ret >= B_OK; y--) {
// fill the row buffer with each channel
for (uint32 z = 0; z < channelCount; z++) {
ret = sgiImage->ReadRow(rows[z], y, z);
if (ret < B_OK)
break;
}
// see if an error happened while reading
if (ret < B_OK)
break;
// convert to native format (big endian)
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:
// cannot be here
break;
} // switch (format)
ret = outDestination->Write(rowBuffer, bytesPerRow);
} else {
// support for 16 bits per channel images
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:
// cannot be here
break;
} // switch (format)
ret = outDestination->Write(rowBuffer, bytesPerRow);
} // 16 bit version
} // for (uint32 y = 0; y < height && ret >= B_OK; y++)
if (ret >= B_OK)
ret = B_OK;
} else // if (rows && rows[0] && rowBuffer)
ret = B_NO_MEMORY;
delete[] rows[0];
delete[] rows;
delete[] rowBuffer;
} // if (ret >= B_OK && !bheaderonly)
} // if (ret >= B_OK)
delete sgiImage;
return ret;
}
// ---------------------------------------------------------------
// DerivedTranslate
//
// Translates the data in inSource to the type outType and stores
// the translated data in outDestination.
//
// Preconditions:
//
// Parameters: inSource, the data to be translated
//
// inInfo, hint about the data in inSource (not used)
//
// ioExtension, configuration options for the
// translator
//
// outType, the type to convert inSource to
//
// outDestination, where the translated data is
// put
//
// baseType, indicates whether inSource is in the
// bits format, not in the bits format or
// is unknown
//
// Postconditions:
//
// Returns: B_BAD_VALUE, if the options in ioExtension are bad
//
// B_NO_TRANSLATOR, if this translator doesn't understand the data
//
// B_ERROR, if there was an error allocating memory or converting
// data
//
// B_OK, if all went well
// ---------------------------------------------------------------
status_t
SGITranslator::DerivedTranslate(BPositionIO *inSource,
const translator_info *inInfo, BMessage *ioExtension,
uint32 outType, BPositionIO *outDestination, int32 baseType)
{
if (baseType == 1)
// if inSource is in bits format
return translate_from_bits(inSource, outType, outDestination);
else if (baseType == 0)
// if inSource is NOT in bits format
return translate_from_sgi(inSource, outType, outDestination);
else
// if BaseTranslator did not properly identify the data as
// bits or not bits
return B_NO_TRANSLATOR;
}
BView *
SGITranslator::NewConfigView(TranslatorSettings *settings)
{
return new SGIView(B_TRANSLATE("SGITranslator Settings"), B_WILL_DRAW,
settings);
}
↑ V576 Incorrect format. A different number of actual arguments is expected while calling 'syslog' function. Expected: 3. Present: 2.