|
|
|
@ -20,6 +20,7 @@
|
|
|
|
|
#include <openjpeg.h>
|
|
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
#include <tdeglobal.h>
|
|
|
|
|
#include <tdetempfile.h>
|
|
|
|
|
#include <tqcolor.h>
|
|
|
|
|
#include <tqcstring.h>
|
|
|
|
@ -36,10 +37,6 @@
|
|
|
|
|
* - Doesn't support OPJ_CODEC_J2K.
|
|
|
|
|
* - Doesn't support subsampling.
|
|
|
|
|
* - Doesn't read ICC profiles.
|
|
|
|
|
* - Doesn't write images.
|
|
|
|
|
*
|
|
|
|
|
* Improvements:
|
|
|
|
|
* - kimgio_jp2_read_srgba/kimgio_jp2_read_grayscale could be merged.
|
|
|
|
|
*
|
|
|
|
|
* The API documentation is rather poor, so good references on how to use OpenJPEG
|
|
|
|
|
* are the tools provided by OpenJPEG, such as 'opj_decompress':
|
|
|
|
@ -91,7 +88,7 @@ static void kimgio_jp2_warn_handler(const char *message, void *data)
|
|
|
|
|
kdWarning(kCategory) << "Warning decoding JP2 image: " << message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void kimgio_jp2_read_srgba(TQImage &image, const KIMGJP2Wrapper &jp2)
|
|
|
|
|
static void kimgio_jp2_read_image(TQImage &image, const KIMGJP2Wrapper &jp2)
|
|
|
|
|
{
|
|
|
|
|
const int height = image.height();
|
|
|
|
|
const int width = image.width();
|
|
|
|
@ -103,61 +100,63 @@ static void kimgio_jp2_read_srgba(TQImage &image, const KIMGJP2Wrapper &jp2)
|
|
|
|
|
for (int col = 0; col < width; col++)
|
|
|
|
|
{
|
|
|
|
|
const int offset = row * width + col;
|
|
|
|
|
OPJ_INT32 r, g, b, a = 0xFF;
|
|
|
|
|
|
|
|
|
|
// Convert to unsigned
|
|
|
|
|
r = jp2.image->comps[0].data[offset];
|
|
|
|
|
r += (jp2.image->comps[0].sgnd ? 1 << (jp2.image->comps[0].prec - 1) : 0);
|
|
|
|
|
|
|
|
|
|
g = jp2.image->comps[1].data[offset];
|
|
|
|
|
g += (jp2.image->comps[0].sgnd ? 1 << (jp2.image->comps[1].prec - 1) : 0);
|
|
|
|
|
uint8_t rgba[4] = { 0x00, 0x00, 0x00, 0xFF };
|
|
|
|
|
|
|
|
|
|
b = jp2.image->comps[2].data[offset];
|
|
|
|
|
b += (jp2.image->comps[2].sgnd ? 1 << (jp2.image->comps[2].prec - 1) : 0);
|
|
|
|
|
for (int comp = 0; comp < jp2.image->numcomps; comp++)
|
|
|
|
|
{
|
|
|
|
|
OPJ_INT32 value = jp2.image->comps[comp].data[offset];
|
|
|
|
|
value += (jp2.image->comps[comp].sgnd ? (1 << jp2.image->comps[comp].prec - 1) : 0);
|
|
|
|
|
value = kClamp(value, 0, 255);
|
|
|
|
|
|
|
|
|
|
if (jp2.image->numcomps > 3 && jp2.image->comps[3].alpha)
|
|
|
|
|
switch (comp)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
{
|
|
|
|
|
a = jp2.image->comps[3].data[offset];
|
|
|
|
|
a += (jp2.image->comps[3].sgnd ? 1 << (jp2.image->comps[3].prec - 1) : 0);
|
|
|
|
|
// Red or Grayscale
|
|
|
|
|
rgba[0] = value;
|
|
|
|
|
rgba[1] = value;
|
|
|
|
|
rgba[2] = value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
image.setPixel(col, row, tqRgba(r, g, b, a));
|
|
|
|
|
alphaMask |= (255 - a);
|
|
|
|
|
case 1:
|
|
|
|
|
{
|
|
|
|
|
if ((jp2.image->color_space == OPJ_CLRSPC_GRAY) &&
|
|
|
|
|
(jp2.image->comps[comp].alpha != 0))
|
|
|
|
|
{
|
|
|
|
|
// Grayscale with Alpha
|
|
|
|
|
rgba[3] = value;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Green
|
|
|
|
|
rgba[1] = value;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (alphaMask != 0x0)
|
|
|
|
|
case 2:
|
|
|
|
|
{
|
|
|
|
|
image.setAlphaBuffer(true);
|
|
|
|
|
// Blue
|
|
|
|
|
rgba[2] = value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void kimgio_jp2_read_grayscale(TQImage &image, const KIMGJP2Wrapper &jp2)
|
|
|
|
|
{
|
|
|
|
|
const int height = image.height();
|
|
|
|
|
const int width = image.width();
|
|
|
|
|
|
|
|
|
|
unsigned char alphaMask = 0x0;
|
|
|
|
|
|
|
|
|
|
for (int row = 0; row < height; row++)
|
|
|
|
|
case 3:
|
|
|
|
|
{
|
|
|
|
|
for (int col = 0; col < width; col++)
|
|
|
|
|
// Alpha?
|
|
|
|
|
if (jp2.image->comps[comp].alpha != 0)
|
|
|
|
|
{
|
|
|
|
|
const int offset = row * width + col;
|
|
|
|
|
OPJ_INT32 g, a = 0xFF;
|
|
|
|
|
|
|
|
|
|
// Convert to unsigned
|
|
|
|
|
g = jp2.image->comps[0].data[offset];
|
|
|
|
|
g += (jp2.image->comps[0].sgnd ? (1 << jp2.image->comps[0].prec - 1) : 0);
|
|
|
|
|
|
|
|
|
|
if (jp2.image->numcomps > 1 && jp2.image->comps[1].alpha)
|
|
|
|
|
rgba[3] = value;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
a = jp2.image->comps[1].data[offset];
|
|
|
|
|
a = (jp2.image->comps[1].sgnd ? (1 << jp2.image->comps[1].prec - 1) : 0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
image.setPixel(col, row, tqRgba(g, g, g, a));
|
|
|
|
|
alphaMask |= (255 - a);
|
|
|
|
|
image.setPixel(col, row, tqRgba(rgba[0], rgba[1], rgba[2], rgba[3]));
|
|
|
|
|
alphaMask |= (255 - rgba[3]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -297,13 +296,9 @@ TDE_EXPORT void kimgio_jp2_read(TQImageIO* io)
|
|
|
|
|
switch (jp2.image->color_space)
|
|
|
|
|
{
|
|
|
|
|
case OPJ_CLRSPC_SRGB:
|
|
|
|
|
{
|
|
|
|
|
kimgio_jp2_read_srgba(image, jp2);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OPJ_CLRSPC_GRAY:
|
|
|
|
|
{
|
|
|
|
|
kimgio_jp2_read_grayscale(image, jp2);
|
|
|
|
|
kimgio_jp2_read_image(image, jp2);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|