#include "JPEG2000Translator.h"
#include "TranslatorWindow.h"
#include <syslog.h>
#include <LayoutBuilder.h>
#include <TabView.h>
#include <TextView.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "JPEG2000Translator"
#define JP2_ACRONYM "JP2"
#define JP2_FORMAT 'JP2 '
#define JP2_MIME_STRING "image/jp2"
#define JP2_DESCRIPTION "JPEG2000 image"
#define B_TRANSLATOR_BITMAP_MIME_STRING "image/x-be-bitmap"
#define B_TRANSLATOR_BITMAP_DESCRIPTION "Be Bitmap Format (JPEG2000Translator)"
static int32 sTranslatorVersion = B_TRANSLATION_MAKE_VERSION(1, 0, 0);
static const char* sTranslatorName = B_TRANSLATE("JPEG2000 images");
static const char* sTranslatorInfo = B_TRANSLATE("©2002-2003, Shard\n"
"©2005-2006, Haiku\n"
"\n"
"Based on JasPer library:\n"
"© 1999-2000, Image Power, Inc. and\n"
"the University of British Columbia, Canada.\n"
"© 2001-2003 Michael David Adams.\n"
"\thttp://www.ece.uvic.ca/~mdadams/jasper/\n"
"\n"
"ImageMagick's jp2 codec was used as \"tutorial\".\n"
"\thttp://www.imagemagick.org/\n");
static const translation_format sInputFormats[] = {
{ JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
JP2_MIME_STRING, JP2_DESCRIPTION },
{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
};
static const translation_format sOutputFormats[] = {
{ JP2_FORMAT, B_TRANSLATOR_BITMAP, 0.5, 0.5,
JP2_MIME_STRING, JP2_DESCRIPTION },
{ B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.5, 0.5,
B_TRANSLATOR_BITMAP_MIME_STRING, B_TRANSLATOR_BITMAP_DESCRIPTION },
};
static const TranSetting sDefaultSettings[] = {
{JP2_SET_QUALITY, TRAN_SETTING_INT32, 25},
{JP2_SET_JPC, TRAN_SETTING_BOOL, false},
{JP2_SET_GRAY1_AS_B_RGB24, TRAN_SETTING_BOOL, false},
{JP2_SET_GRAY8_AS_B_RGB32, TRAN_SETTING_BOOL, true}
};
const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);
#define JP2_BOX_JP 0x6a502020
#define JPC_MS_SOC 0xff4f
namespace conversion{
inline void
read_rgb24_to_rgb32(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 index = 0;
int32 x = 0;
while (x < width) {
scanline[index++] = (uchar)jas_matrix_getv(pixels[2], x);
scanline[index++] = (uchar)jas_matrix_getv(pixels[1], x);
scanline[index++] = (uchar)jas_matrix_getv(pixels[0], x);
scanline[index++] = 255;
x++;
}
}
inline void
read_gray_to_rgb32(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 index = 0;
int32 x = 0;
uchar color = 0;
while (x < width) {
color = (uchar)jas_matrix_getv(pixels[0], x++);
scanline[index++] = color;
scanline[index++] = color;
scanline[index++] = color;
scanline[index++] = 255;
}
}
inline void
read_rgba32(jas_matrix_t** pixels, uchar *scanline, int width)
{
int32 index = 0;
int32 x = 0;
while (x < width) {
scanline[index++] = (uchar)jas_matrix_getv(pixels[2], x);
scanline[index++] = (uchar)jas_matrix_getv(pixels[1], x);
scanline[index++] = (uchar)jas_matrix_getv(pixels[0], x);
scanline[index++] = (uchar)jas_matrix_getv(pixels[3], x);
x++;
}
}
inline void
read_gray(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 x = 0;
while (x < width) {
scanline[x] = (uchar)jas_matrix_getv(pixels[0], x);
x++;
}
}
inline void
write_gray1_to_gray(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 x = 0;
int32 index = 0;
while (x < (width/8)) {
unsigned char c = scanline[x++];
for (int b = 128; b; b = b >> 1) {
if (c & b)
jas_matrix_setv(pixels[0], index++, 0);
else
jas_matrix_setv(pixels[0], index++, 255);
}
}
}
inline void
write_gray1_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 x = 0;
int32 index = 0;
while (x < (width / 8)) {
unsigned char c = scanline[x++];
for (int b = 128; b; b = b >> 1) {
if (c & b) {
jas_matrix_setv(pixels[0], index, 0);
jas_matrix_setv(pixels[1], index, 0);
jas_matrix_setv(pixels[2], index, 0);
} else {
jas_matrix_setv(pixels[0], index, 255);
jas_matrix_setv(pixels[1], index, 255);
jas_matrix_setv(pixels[2], index, 255);
}
index++;
}
}
}
inline void
write_cmap8_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
const color_map* map = system_colors();
int32 x = 0;
while (x < width) {
rgb_color color = map->color_list[scanline[x]];
jas_matrix_setv(pixels[0], x, color.red);
jas_matrix_setv(pixels[1], x, color.green);
jas_matrix_setv(pixels[2], x, color.blue);
x++;
}
}
inline void
write_gray(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 x = 0;
while (x < width) {
jas_matrix_setv(pixels[0], x, scanline[x]);
x++;
}
}
inline void
write_rgb15_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 x = 0;
int32 index = 0;
int16 in_pixel;
while (x < width) {
in_pixel = scanline[index] | (scanline[index+1] << 8);
index += 2;
jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7)
| (((in_pixel & 0x7c00)) >> 12));
jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2)
| (((in_pixel & 0x3e0)) >> 7));
jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3)
| (((in_pixel & 0x1f)) >> 2));
x++;
}
}
inline void
write_rgb15b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 x = 0;
int32 index = 0;
int16 in_pixel;
while (x < width) {
in_pixel = scanline[index + 1] | (scanline[index] << 8);
index += 2;
jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0x7c00)) >> 7)
| (((in_pixel & 0x7c00)) >> 12));
jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x3e0)) >> 2)
| (((in_pixel & 0x3e0)) >> 7));
jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3)
| (((in_pixel & 0x1f)) >> 2));
x++;
}
}
inline void
write_rgb16_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 x = 0;
int32 index = 0;
int16 in_pixel;
while (x < width) {
in_pixel = scanline[index] | (scanline[index+1] << 8);
index += 2;
jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8)
| (((in_pixel & 0x7c00)) >> 12));
jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3)
| (((in_pixel & 0x7e0)) >> 9));
jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3)
| (((in_pixel & 0x1f)) >> 2));
x++;
}
}
inline void
write_rgb16b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 x = 0;
int32 index = 0;
int16 in_pixel;
while (x < width) {
in_pixel = scanline[index + 1] | (scanline[index] << 8);
index += 2;
jas_matrix_setv(pixels[0], x, (char)(((in_pixel & 0xf800)) >> 8)
| (((in_pixel & 0xf800)) >> 13));
jas_matrix_setv(pixels[1], x, (char)(((in_pixel & 0x7e0)) >> 3)
| (((in_pixel & 0x7e0)) >> 9));
jas_matrix_setv(pixels[2], x, (char)(((in_pixel & 0x1f)) << 3)
| (((in_pixel & 0x1f)) >> 2));
x++;
}
}
inline void
write_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 index = 0;
int32 x = 0;
while (x < width) {
jas_matrix_setv(pixels[2], x, scanline[index++]);
jas_matrix_setv(pixels[1], x, scanline[index++]);
jas_matrix_setv(pixels[0], x, scanline[index++]);
x++;
}
}
inline void
write_rgb24b(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 index = 0;
int32 x = 0;
while (x < width) {
jas_matrix_setv(pixels[0], x, scanline[index++]);
jas_matrix_setv(pixels[1], x, scanline[index++]);
jas_matrix_setv(pixels[2], x, scanline[index++]);
x++;
}
}
inline void
write_rgb32_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 index = 0;
int32 x = 0;
while (x < width) {
jas_matrix_setv(pixels[2], x, scanline[index++]);
jas_matrix_setv(pixels[1], x, scanline[index++]);
jas_matrix_setv(pixels[0], x, scanline[index++]);
index++;
x++;
}
}
inline void
write_rgb32b_to_rgb24(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 index = 0;
int32 x = 0;
while (x < width) {
index++;
jas_matrix_setv(pixels[0], x, scanline[index++]);
jas_matrix_setv(pixels[1], x, scanline[index++]);
jas_matrix_setv(pixels[2], x, scanline[index++]);
x++;
}
}
inline void
write_rgba32(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 index = 0;
int32 x = 0;
while (x < width) {
jas_matrix_setv(pixels[3], x, scanline[index++]);
jas_matrix_setv(pixels[2], x, scanline[index++]);
jas_matrix_setv(pixels[1], x, scanline[index++]);
jas_matrix_setv(pixels[0], x, scanline[index++]);
x++;
}
}
inline void
write_rgba32b(jas_matrix_t** pixels, uchar* scanline, int width)
{
int32 index = 0;
int32 x = 0;
while (x < width) {
jas_matrix_setv(pixels[0], x, scanline[index++]);
jas_matrix_setv(pixels[1], x, scanline[index++]);
jas_matrix_setv(pixels[2], x, scanline[index++]);
jas_matrix_setv(pixels[3], x, scanline[index++]);
x++;
}
}
}
#if __GNUC__ == 2
typedef int jasper_length_t;
#else
typedef unsigned int jasper_length_t;
#endif
static int
Read(jas_stream_obj_t* object, char* buffer, const jasper_length_t length)
{
return (*(BPositionIO**)object)->Read(buffer, length);
}
static int
Write(jas_stream_obj_t* object, const char* buffer, const jasper_length_t length)
{
return (*(BPositionIO**)object)->Write(buffer, length);
}
static long
Seek(jas_stream_obj_t* object, long offset, int origin)
{
return (*(BPositionIO**)object)->Seek(offset, origin);
}
static int
Close(jas_stream_obj_t* object)
{
return 0;
}
static jas_stream_ops_t positionIOops = {
Read,
Write,
Seek,
Close
};
static jas_stream_t*
jas_stream_positionIOopen(BPositionIO *positionIO)
{
jas_stream_t* stream;
stream = (jas_stream_t *)malloc(sizeof(jas_stream_t));
if (stream == (jas_stream_t *)NULL)
return (jas_stream_t *)NULL;
memset(stream, 0, sizeof(jas_stream_t));
stream->rwlimit_ = -1;
stream->obj_=(jas_stream_obj_t *)malloc(sizeof(BPositionIO*));
if (stream->obj_ == (jas_stream_obj_t *)NULL) {
free(stream);
return (jas_stream_t *)NULL;
}
*((BPositionIO**)stream->obj_) = positionIO;
stream->ops_ = (&positionIOops);
stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
stream->bufbase_ = stream->tinybuf_;
stream->bufsize_ = 1;
stream->bufstart_ = (&stream->bufbase_[JAS_STREAM_MAXPUTBACK]);
stream->ptr_ = stream->bufstart_;
stream->bufmode_ |= JAS_STREAM_UNBUF & JAS_STREAM_BUFMODEMASK;
return stream;
}
SSlider::SSlider(const char* name, const char* label,
BMessage* message, int32 minValue, int32 maxValue, orientation posture,
thumb_style thumbType, uint32 flags)
:
BSlider(name, label, message, minValue, maxValue,
posture, thumbType, flags)
{
}
const char*
SSlider::UpdateText() const
{
snprintf(fStatusLabel, sizeof(fStatusLabel), "%" B_PRId32, Value());
return fStatusLabel;
}
TranslatorReadView::TranslatorReadView(const char* name,
TranslatorSettings* settings)
:
BView(name, 0, new BGroupLayout(B_VERTICAL)),
fSettings(settings)
{
fGrayAsRGB32 = new BCheckBox("grayasrgb32",
B_TRANSLATE("Read greyscale images as RGB32"),
new BMessage(VIEW_MSG_SET_GRAYASRGB32));
if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32))
fGrayAsRGB32->SetValue(B_CONTROL_ON);
float padding = 10.0f;
BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(padding)
.Add(fGrayAsRGB32)
.AddGlue();
}
TranslatorReadView::~TranslatorReadView()
{
fSettings->Release();
}
void
TranslatorReadView::AttachedToWindow()
{
fGrayAsRGB32->SetTarget(this);
}
void
TranslatorReadView::MessageReceived(BMessage* message)
{
switch (message->what) {
case VIEW_MSG_SET_GRAYASRGB32:
{
int32 value;
if (message->FindInt32("be:value", &value) == B_OK) {
bool boolValue = value;
fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32, &boolValue);
fSettings->SaveSettings();
}
break;
}
default:
BView::MessageReceived(message);
break;
}
}
TranslatorWriteView::TranslatorWriteView(const char* name,
TranslatorSettings* settings)
:
BView(name, 0, new BGroupLayout(B_VERTICAL)),
fSettings(settings)
{
fQualitySlider = new SSlider("quality", B_TRANSLATE("Output quality"),
new BMessage(VIEW_MSG_SET_QUALITY), 0, 100, B_HORIZONTAL, B_TRIANGLE_THUMB);
fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
fQualitySlider->SetHashMarkCount(10);
fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High"));
fQualitySlider->SetValue(fSettings->SetGetInt32(JP2_SET_QUALITY));
fGrayAsRGB24 = new BCheckBox("gray1asrgb24",
B_TRANSLATE("Write black-and-white images as RGB24"),
new BMessage(VIEW_MSG_SET_GRAY1ASRGB24));
if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24))
fGrayAsRGB24->SetValue(B_CONTROL_ON);
fCodeStreamOnly = new BCheckBox("codestreamonly",
B_TRANSLATE("Output only codestream (.jpc)"),
new BMessage(VIEW_MSG_SET_JPC));
if (fSettings->SetGetBool(JP2_SET_JPC))
fCodeStreamOnly->SetValue(B_CONTROL_ON);
BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(B_USE_DEFAULT_SPACING)
.Add(fQualitySlider)
.Add(fGrayAsRGB24)
.Add(fCodeStreamOnly)
.AddGlue();
}
TranslatorWriteView::~TranslatorWriteView()
{
fSettings->Release();
}
void
TranslatorWriteView::AttachedToWindow()
{
fQualitySlider->SetTarget(this);
fGrayAsRGB24->SetTarget(this);
fCodeStreamOnly->SetTarget(this);
}
void
TranslatorWriteView::MessageReceived(BMessage* message)
{
switch (message->what) {
case VIEW_MSG_SET_QUALITY:
{
int32 value;
if (message->FindInt32("be:value", &value) == B_OK) {
fSettings->SetGetInt32(JP2_SET_QUALITY, &value);
fSettings->SaveSettings();
}
break;
}
case VIEW_MSG_SET_GRAY1ASRGB24:
{
int32 value;
if (message->FindInt32("be:value", &value) == B_OK) {
bool boolValue = value;
fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24, &boolValue);
fSettings->SaveSettings();
}
break;
}
case VIEW_MSG_SET_JPC:
{
int32 value;
if (message->FindInt32("be:value", &value) == B_OK) {
bool boolValue = value;
fSettings->SetGetBool(JP2_SET_JPC, &boolValue);
fSettings->SaveSettings();
}
break;
}
default:
BView::MessageReceived(message);
break;
}
}
TranslatorAboutView::TranslatorAboutView(const char* name)
:
BView(name, 0, new BGroupLayout(B_VERTICAL))
{
BAlignment labelAlignment = BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP);
BStringView* title = new BStringView("Title", sTranslatorName);
title->SetFont(be_bold_font);
title->SetExplicitAlignment(labelAlignment);
char versionString[100];
snprintf(versionString, sizeof(versionString),
B_TRANSLATE("Version %d.%d.%d"),
static_cast<int>(sTranslatorVersion >> 8),
static_cast<int>((sTranslatorVersion >> 4) & 0xf),
static_cast<int>(sTranslatorVersion & 0xf));
BStringView* version = new BStringView("Version", versionString);
version->SetExplicitAlignment(labelAlignment);
BTextView* infoView = new BTextView("info");
infoView->SetText(sTranslatorInfo);
infoView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
infoView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
infoView->MakeEditable(false);
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(B_USE_DEFAULT_SPACING)
.Add(title)
.Add(version)
.Add(infoView);
}
TranslatorView::TranslatorView(const char* name, TranslatorSettings* settings)
:
BTabView(name, B_WIDTH_FROM_LABEL)
{
SetBorder(B_NO_BORDER);
AddTab(new TranslatorWriteView(B_TRANSLATE("Write"),
settings->Acquire()));
AddTab(new TranslatorReadView(B_TRANSLATE("Read"),
settings->Acquire()));
AddTab(new TranslatorAboutView(B_TRANSLATE("About")));
settings->Release();
}
BView*
JP2Translator::NewConfigView(TranslatorSettings* settings)
{
BView* outView = new TranslatorView("TranslatorView", settings);
return outView;
}
JP2Translator::JP2Translator()
: BaseTranslator(sTranslatorName, sTranslatorInfo, sTranslatorVersion,
sInputFormats, kNumInputFormats,
sOutputFormats, kNumOutputFormats,
JP2_SETTINGS_FILE,
sDefaultSettings, kNumDefaultSettings,
B_TRANSLATOR_BITMAP, JP2_FORMAT)
{
}
status_t
JP2Translator::DerivedIdentify(BPositionIO* inSource,
const translation_format* inFormat, BMessage* ioExtension,
translator_info* outInfo, uint32 outType)
{
if ((outType != 0) && (outType != B_TRANSLATOR_BITMAP)
&& outType != JP2_FORMAT)
return B_NO_TRANSLATOR;
off_t position = inSource->Position();
uint8 header[sizeof(TranslatorBitmap)];
status_t err = inSource->Read(header, sizeof(TranslatorBitmap));
inSource->Seek(position, SEEK_SET);
if (err < B_OK)
return err;
if (B_BENDIAN_TO_HOST_INT32(((TranslatorBitmap *)header)->magic)
== B_TRANSLATOR_BITMAP) {
if (PopulateInfoFromFormat(outInfo, B_TRANSLATOR_BITMAP) != B_OK)
return B_NO_TRANSLATOR;
} else {
if ((((header[4] << 24) | (header[5] << 16) | (header[6] << 8)
| header[7]) == JP2_BOX_JP)
|| (header[0] == (JPC_MS_SOC >> 8) && header[1]
== (JPC_MS_SOC & 0xff)))
{
if (PopulateInfoFromFormat(outInfo, JP2_FORMAT) != B_OK)
return B_NO_TRANSLATOR;
} else
return B_NO_TRANSLATOR;
}
return B_OK;
}
status_t
JP2Translator::DerivedTranslate(BPositionIO* inSource,
const translator_info* inInfo, BMessage* ioExtension, uint32 outType,
BPositionIO* outDestination, int32 baseType)
{
if (outType == 0)
outType = B_TRANSLATOR_BITMAP;
if (outType == inInfo->type)
return Copy(inSource, outDestination);
if (inInfo->type == B_TRANSLATOR_BITMAP && outType == JP2_FORMAT)
return Compress(inSource, outDestination);
if (inInfo->type == JP2_FORMAT && outType == B_TRANSLATOR_BITMAP)
return Decompress(inSource, outDestination);
return B_NO_TRANSLATOR;
}
status_t
JP2Translator::Copy(BPositionIO* in, BPositionIO* out)
{
int block_size = 65536;
void* buffer = malloc(block_size);
char temp[1024];
if (buffer == NULL) {
buffer = temp;
block_size = 1024;
}
status_t err = B_OK;
while (1) {
ssize_t to_read = block_size;
err = in->Read(buffer, to_read);
if (err == -1) {
if (buffer != temp)
free(buffer);
return B_OK;
}
if (err <= B_OK) break;
to_read = err;
err = out->Write(buffer, to_read);
if (err != to_read) if (err >= 0) err = B_DEVICE_FULL;
if (err < B_OK) break;
}
if (buffer != temp)
free(buffer);
return (err >= 0) ? B_OK : err;
}
status_t
JP2Translator::Compress(BPositionIO* in, BPositionIO* out)
{
using namespace conversion;
TranslatorBitmap header;
status_t err = in->Read(&header, sizeof(TranslatorBitmap));
if (err < B_OK)
return err;
if (err < (int)sizeof(TranslatorBitmap))
return B_ERROR;
BRect bounds;
bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left);
bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top);
bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right);
bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
int32 in_row_bytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
int width = bounds.IntegerWidth() + 1;
int height = bounds.IntegerHeight() + 1;
void (*converter)(jas_matrix_t** pixels, uchar* inscanline,
int width) = write_rgba32;
int out_color_space = JAS_CLRSPC_SRGB;
int out_color_components = 3;
switch ((color_space)B_BENDIAN_TO_HOST_INT32(header.colors)) {
case B_GRAY1:
if (fSettings->SetGetBool(JP2_SET_GRAY1_AS_B_RGB24)) {
converter = write_gray1_to_rgb24;
} else {
out_color_components = 1;
out_color_space = JAS_CLRSPC_SGRAY;
converter = write_gray1_to_gray;
}
break;
case B_CMAP8:
converter = write_cmap8_to_rgb24;
break;
case B_GRAY8:
out_color_components = 1;
out_color_space = JAS_CLRSPC_SGRAY;
converter = write_gray;
break;
case B_RGB15:
case B_RGBA15:
converter = write_rgb15_to_rgb24;
break;
case B_RGB15_BIG:
case B_RGBA15_BIG:
converter = write_rgb15b_to_rgb24;
break;
case B_RGB16:
converter = write_rgb16_to_rgb24;
break;
case B_RGB16_BIG:
converter = write_rgb16b_to_rgb24;
break;
case B_RGB24:
converter = write_rgb24;
break;
case B_RGB24_BIG:
converter = write_rgb24b;
break;
case B_RGB32:
converter = write_rgb32_to_rgb24;
break;
case B_RGB32_BIG:
converter = write_rgb32b_to_rgb24;
break;
case B_RGBA32:
converter = write_rgb32_to_rgb24;
break;
case B_RGBA32_BIG:
converter = write_rgb32b_to_rgb24;
break;
default:
syslog(LOG_ERR, "Unknown color space.\n");
return B_ERROR;
}
jas_image_t* image;
jas_stream_t* outs;
jas_matrix_t* pixels[4];
jas_image_cmptparm_t component_info[4];
if (jas_init())
return B_ERROR;
if (!(outs = jas_stream_positionIOopen(out)))
return B_ERROR;
int32 i = 0;
for (i = 0; i < (long)out_color_components; i++) {
(void) memset(component_info + i, 0, sizeof(jas_image_cmptparm_t));
component_info[i].hstep = 1;
component_info[i].vstep = 1;
component_info[i].width = (unsigned int)width;
component_info[i].height = (unsigned int)height;
component_info[i].prec = (unsigned int)8;
}
image = jas_image_create((short)out_color_components, component_info,
out_color_space);
if (image == (jas_image_t *)NULL)
return Error(outs, NULL, NULL, 0, NULL, B_ERROR);
uchar *in_scanline = (uchar*) malloc(in_row_bytes);
if (in_scanline == NULL)
return Error(outs, image, NULL, 0, NULL, B_ERROR);
for (i = 0; i < (long)out_color_components; i++) {
pixels[i] = jas_matrix_create(1, (unsigned int)width);
if (pixels[i] == (jas_matrix_t *)NULL)
return Error(outs, image, pixels, i+1, in_scanline, B_ERROR);
}
int32 y = 0;
for (y = 0; y < (long)height; y++) {
err = in->Read(in_scanline, in_row_bytes);
if (err < in_row_bytes) {
return (err < B_OK) ? Error(outs, image, pixels,
out_color_components, in_scanline, err)
: Error(outs, image, pixels, out_color_components, in_scanline,
B_ERROR);
}
converter(pixels, in_scanline, width);
for (i = 0; i < (long)out_color_components; i++) {
(void)jas_image_writecmpt(image, (short)i, 0, (unsigned int)y,
(unsigned int)width, 1, pixels[i]);
}
}
char opts[16];
sprintf(opts, "rate=%1f",
(float)fSettings->SetGetInt32(JP2_SET_QUALITY) / 100.0);
if (jas_image_encode(image, outs, jas_image_strtofmt(
fSettings->SetGetBool(JP2_SET_JPC) ?
(char*)"jpc" : (char*)"jp2"), opts)) {
return Error(outs, image, pixels,
out_color_components, in_scanline, err);
}
free(in_scanline);
for (i = 0; i < (long)out_color_components; i++)
jas_matrix_destroy(pixels[i]);
jas_stream_close(outs);
jas_image_destroy(image);
jas_image_clearfmts();
return B_OK;
}
status_t
JP2Translator::Decompress(BPositionIO* in, BPositionIO* out)
{
using namespace conversion;
jas_image_t* image;
jas_stream_t* ins;
jas_matrix_t* pixels[4];
if (jas_init())
return B_ERROR;
if (!(ins = jas_stream_positionIOopen(in)))
return B_ERROR;
if (!(image = jas_image_decode(ins, -1, 0)))
return Error(ins, NULL, NULL, 0, NULL, B_ERROR);
color_space out_color_space;
int out_color_components;
int in_color_components = jas_image_numcmpts(image);
void (*converter)(jas_matrix_t** pixels, uchar* outscanline,
int width) = NULL;
switch (jas_clrspc_fam(jas_image_clrspc(image))) {
case JAS_CLRSPC_FAM_RGB:
out_color_components = 4;
if (in_color_components == 3) {
out_color_space = B_RGB32;
converter = read_rgb24_to_rgb32;
} else if (in_color_components == 4) {
out_color_space = B_RGBA32;
converter = read_rgba32;
} else {
syslog(LOG_ERR, "Other than RGB with 3 or 4 color "
"components not implemented.\n");
return Error(ins, image, NULL, 0, NULL, B_ERROR);
}
break;
case JAS_CLRSPC_FAM_GRAY:
if (fSettings->SetGetBool(JP2_SET_GRAY8_AS_B_RGB32)) {
out_color_space = B_RGB32;
out_color_components = 4;
converter = read_gray_to_rgb32;
} else {
out_color_space = B_GRAY8;
out_color_components = 1;
converter = read_gray;
}
break;
case JAS_CLRSPC_FAM_YCBCR:
syslog(LOG_ERR, "Color space YCBCR not implemented yet.\n");
return Error(ins, image, NULL, 0, NULL, B_ERROR);
break;
case JAS_CLRSPC_UNKNOWN:
default:
syslog(LOG_ERR, "Color space unknown. \n");
return Error(ins, image, NULL, 0, NULL, B_ERROR);
break;
}
float width = (float)jas_image_width(image);
float height = (float)jas_image_height(image);
int64 out_row_bytes = (int32)width * out_color_components;
BRect bounds(0, 0, width - 1, height - 1);
TranslatorBitmap header;
header.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP);
header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(bounds.left);
header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(bounds.top);
header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(bounds.right);
header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(bounds.bottom);
header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_color_space);
header.rowBytes = B_HOST_TO_BENDIAN_INT32(out_row_bytes);
header.dataSize = B_HOST_TO_BENDIAN_INT32((int32)(out_row_bytes * height));
status_t err = out->Write(&header, sizeof(TranslatorBitmap));
if (err < B_OK)
return Error(ins, image, NULL, 0, NULL, err);
if (err < (int)sizeof(TranslatorBitmap))
return Error(ins, image, NULL, 0, NULL, B_ERROR);
uchar *out_scanline = (uchar*) malloc(out_row_bytes);
if (out_scanline == NULL)
return Error(ins, image, NULL, 0, NULL, B_ERROR);
int32 i = 0;
for (i = 0; i < (long)in_color_components; i++) {
pixels[i] = jas_matrix_create(1, (unsigned int)width);
if (pixels[i] == (jas_matrix_t *)NULL)
return Error(ins, image, pixels, i + 1, out_scanline, B_ERROR);
}
int32 y = 0;
for (y = 0; y < (long)height; y++) {
for (i = 0; i < (long)in_color_components; i++) {
(void)jas_image_readcmpt(image, (short)i, 0, (unsigned int)y,
(unsigned int)width, 1, pixels[i]);
}
converter(pixels, out_scanline, (int32)width);
err = out->Write(out_scanline, out_row_bytes);
if (err < out_row_bytes) {
return (err < B_OK) ? Error(ins, image, pixels, in_color_components,
out_scanline, err)
: Error(ins, image, pixels, in_color_components, out_scanline,
B_ERROR);
}
}
free(out_scanline);
for (i = 0; i < (long)in_color_components; i++)
jas_matrix_destroy(pixels[i]);
jas_stream_close(ins);
jas_image_destroy(image);
jas_image_clearfmts();
return B_OK;
}
status_t
JP2Translator::PopulateInfoFromFormat(translator_info* info,
uint32 formatType, translator_id id)
{
int32 formatCount;
const translation_format* formats = OutputFormats(&formatCount);
for (int i = 0; i <= 1; formats = InputFormats(&formatCount), i++) {
if (PopulateInfoFromFormat(info, formatType,
formats, formatCount) == B_OK) {
info->translator = id;
return B_OK;
}
}
return B_ERROR;
}
status_t
JP2Translator::PopulateInfoFromFormat(translator_info* info,
uint32 formatType, const translation_format* formats, int32 formatCount)
{
for (int i = 0; i < formatCount; i++) {
if (formats[i].type == formatType) {
info->type = formatType;
info->group = formats[i].group;
info->quality = formats[i].quality;
info->capability = formats[i].capability;
if (strcmp(formats[i].name, B_TRANSLATOR_BITMAP_DESCRIPTION)
== 0) {
strlcpy(info->name,
B_TRANSLATE(B_TRANSLATOR_BITMAP_DESCRIPTION),
sizeof(info->name));
} else {
strlcpy(info->name, formats[i].name, sizeof(info->name));
}
strlcpy(info->MIME, formats[i].MIME, sizeof(info->MIME));
return B_OK;
}
}
return B_ERROR;
}
status_t
Error(jas_stream_t* stream, jas_image_t* image, jas_matrix_t** pixels,
int32 pixels_count, uchar* scanline, status_t error)
{
if (pixels) {
int32 i;
for (i = 0; i < (long)pixels_count; i++) {
if (pixels[i] != NULL)
jas_matrix_destroy(pixels[i]);
}
}
if (stream)
jas_stream_close(stream);
if (image)
jas_image_destroy(image);
jas_image_clearfmts();
free(scanline);
return error;
}
BTranslator*
make_nth_translator(int32 n, image_id you, uint32 flags, ...)
{
if (!n)
return new JP2Translator();
return NULL;
}
int
main()
{
BApplication app("application/x-vnd.Haiku-JPEG2000Translator");
JP2Translator* translator = new JP2Translator();
if (LaunchTranslatorWindow(translator, sTranslatorName) == B_OK)
app.Run();
return 0;
}