You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
716 lines
23 KiB
716 lines
23 KiB
/* ============================================================
|
|
*
|
|
* This file is a part of digiKam project
|
|
* http://www.digikam.org
|
|
*
|
|
* Date : 2006-06-14
|
|
* Description : A JPEG2000 IO file for DImg framework
|
|
*
|
|
* Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
|
|
*
|
|
* This implementation use Jasper API
|
|
* library : http://www.ece.uvic.ca/~mdadams/jasper
|
|
* Other JPEG2000 encoder-decoder : http://www.openjpeg.org
|
|
*
|
|
* Others Linux JPEG2000 Loader implementation using Jasper:
|
|
* http://cvs.graphicsmagick.org/cgi-bin/cvsweb.cgi/GraphicsMagick/coders/jp2.c
|
|
* https://subversion.imagemagick.org/subversion/ImageMagick/trunk/coders/jp2.c
|
|
* http://svn.ghostscript.com:8080/jasper/trunk/src/appl/jasper.c
|
|
* http://websvn.kde.org/trunk/KDE/tdelibs/kimgio/jp2.cpp
|
|
*
|
|
* This program is free software; you can redistribute it
|
|
* and/or modify it under the terms of the GNU General
|
|
* Public License as published by the Free Software Foundation;
|
|
* either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* ============================================================ */
|
|
|
|
// This line must be commented to prevent any latency time
|
|
// when we use threaded image loader interface for each image
|
|
// files io. Uncomment this line only for debugging.
|
|
//#define ENABLE_DEBUG_MESSAGES
|
|
|
|
// C ANSI includes.
|
|
|
|
extern "C"
|
|
{
|
|
#if !defined(__STDC_LIMIT_MACROS)
|
|
#define __STDC_LIMIT_MACROS
|
|
#endif
|
|
#include <stdint.h>
|
|
}
|
|
|
|
// TQt includes.
|
|
|
|
#include <tqfile.h>
|
|
#include <tqcstring.h>
|
|
|
|
// Local includes.
|
|
|
|
#include "ddebug.h"
|
|
#include "dimg.h"
|
|
#include "dimgloaderobserver.h"
|
|
#include "jp2kloader.h"
|
|
|
|
namespace Digikam
|
|
{
|
|
|
|
JP2KLoader::JP2KLoader(DImg* image)
|
|
: DImgLoader(image)
|
|
{
|
|
m_hasAlpha = false;
|
|
m_sixteenBit = false;
|
|
}
|
|
|
|
bool JP2KLoader::load(const TQString& filePath, DImgLoaderObserver *observer)
|
|
{
|
|
readMetadata(filePath, DImg::JPEG);
|
|
|
|
FILE *file = fopen(TQFile::encodeName(filePath), "rb");
|
|
if (!file)
|
|
return false;
|
|
|
|
unsigned char header[9];
|
|
|
|
if (fread(&header, 9, 1, file) != 1)
|
|
{
|
|
fclose(file);
|
|
return false;
|
|
}
|
|
|
|
unsigned char jp2ID[5] = { 0x6A, 0x50, 0x20, 0x20, 0x0D, };
|
|
unsigned char jpcID[2] = { 0xFF, 0x4F };
|
|
|
|
if (memcmp(&header[4], &jp2ID, 5) != 0 &&
|
|
memcmp(&header, &jpcID, 2) != 0)
|
|
{
|
|
// not a jpeg2000 file
|
|
fclose(file);
|
|
return false;
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
// -------------------------------------------------------------------
|
|
// Initialize JPEG 2000 API.
|
|
|
|
long i, x, y;
|
|
int components[4];
|
|
unsigned int maximum_component_depth, scale[4], x_step[4], y_step[4];
|
|
unsigned long number_components;
|
|
|
|
jas_image_t *jp2_image = 0;
|
|
jas_stream_t *jp2_stream = 0;
|
|
jas_matrix_t *pixels[4];
|
|
|
|
int init = jas_init();
|
|
if (init != 0)
|
|
{
|
|
DDebug() << "Unable to init JPEG2000 decoder" << endl;
|
|
return false;
|
|
}
|
|
|
|
jp2_stream = jas_stream_fopen(TQFile::encodeName(filePath), "rb");
|
|
if (jp2_stream == 0)
|
|
{
|
|
DDebug() << "Unable to open JPEG2000 stream" << endl;
|
|
return false;
|
|
}
|
|
|
|
jp2_image = jas_image_decode(jp2_stream, -1, 0);
|
|
if (jp2_image == 0)
|
|
{
|
|
jas_stream_close(jp2_stream);
|
|
DDebug() << "Unable to decode JPEG2000 image" << endl;
|
|
return false;
|
|
}
|
|
|
|
jas_stream_close(jp2_stream);
|
|
|
|
// some pseudo-progress
|
|
if (observer)
|
|
observer->progressInfo(m_image, 0.1);
|
|
|
|
// -------------------------------------------------------------------
|
|
// Check color space.
|
|
|
|
switch (jas_clrspc_fam(jas_image_clrspc(jp2_image)))
|
|
{
|
|
case JAS_CLRSPC_FAM_RGB:
|
|
{
|
|
components[0] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_RGB_R);
|
|
components[1] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_RGB_G);
|
|
components[2] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_RGB_B);
|
|
if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
|
|
{
|
|
jas_image_destroy(jp2_image);
|
|
DDebug() << "Error parsing JPEG2000 image : Missing Image Channel" << endl;
|
|
return false;
|
|
}
|
|
|
|
number_components = 3;
|
|
components[3] = jas_image_getcmptbytype(jp2_image, 3);
|
|
if (components[3] > 0)
|
|
{
|
|
m_hasAlpha = true;
|
|
number_components++;
|
|
}
|
|
break;
|
|
}
|
|
case JAS_CLRSPC_FAM_GRAY:
|
|
{
|
|
components[0] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_GRAY_Y);
|
|
if (components[0] < 0)
|
|
{
|
|
jas_image_destroy(jp2_image);
|
|
DDebug() << "Error parsing JP2000 image : Missing Image Channel" << endl;
|
|
return false;
|
|
}
|
|
number_components=1;
|
|
break;
|
|
}
|
|
case JAS_CLRSPC_FAM_YCBCR:
|
|
{
|
|
components[0] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_YCBCR_Y);
|
|
components[1] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_YCBCR_CB);
|
|
components[2] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_YCBCR_CR);
|
|
if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
|
|
{
|
|
jas_image_destroy(jp2_image);
|
|
DDebug() << "Error parsing JP2000 image : Missing Image Channel" << endl;
|
|
return false;
|
|
}
|
|
number_components = 3;
|
|
components[3] = jas_image_getcmptbytype(jp2_image, JAS_IMAGE_CT_UNKNOWN);
|
|
if (components[3] > 0)
|
|
{
|
|
m_hasAlpha = true;
|
|
number_components++;
|
|
}
|
|
// FIXME : image->colorspace=YCbCrColorspace;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
jas_image_destroy(jp2_image);
|
|
DDebug() << "Error parsing JP2000 image : Colorspace Model Is Not Supported" << endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// Check image geometry.
|
|
|
|
imageWidth() = jas_image_width(jp2_image);
|
|
imageHeight() = jas_image_height(jp2_image);
|
|
|
|
for (i = 0; i < (long)number_components; i++)
|
|
{
|
|
if ((((jas_image_cmptwidth(jp2_image, components[i])*
|
|
jas_image_cmpthstep(jp2_image, components[i])) != (long)imageWidth())) ||
|
|
(((jas_image_cmptheight(jp2_image, components[i])*
|
|
jas_image_cmptvstep(jp2_image, components[i])) != (long)imageHeight())) ||
|
|
(jas_image_cmpttlx(jp2_image, components[i]) != 0) ||
|
|
(jas_image_cmpttly(jp2_image, components[i]) != 0) ||
|
|
(jas_image_cmptsgnd(jp2_image, components[i]) != false))
|
|
{
|
|
jas_image_destroy(jp2_image);
|
|
DDebug() << "Error parsing JPEG2000 image : Irregular Channel Geometry Not Supported" << endl;
|
|
return false;
|
|
}
|
|
x_step[i] = jas_image_cmpthstep(jp2_image, components[i]);
|
|
y_step[i] = jas_image_cmptvstep(jp2_image, components[i]);
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// Convert image data.
|
|
|
|
m_hasAlpha = number_components > 3;
|
|
maximum_component_depth = 0;
|
|
|
|
for (i = 0; i < (long)number_components; i++)
|
|
{
|
|
maximum_component_depth = TQMAX(jas_image_cmptprec(jp2_image,components[i]),
|
|
(long)maximum_component_depth);
|
|
pixels[i] = jas_matrix_create(1, ((unsigned int)imageWidth())/x_step[i]);
|
|
if (!pixels[i])
|
|
{
|
|
jas_image_destroy(jp2_image);
|
|
DDebug() << "Error decoding JPEG2000 image data : Memory Allocation Failed" << endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (maximum_component_depth > 8)
|
|
m_sixteenBit = true;
|
|
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
{
|
|
scale[i] = 1;
|
|
int prec = jas_image_cmptprec(jp2_image, components[i]);
|
|
if (m_sixteenBit && prec < 16)
|
|
scale[i] = (1 << (16 - jas_image_cmptprec(jp2_image, components[i])));
|
|
}
|
|
|
|
uchar* data = 0;
|
|
if (m_sixteenBit) // 16 bits image.
|
|
data = new uchar[imageWidth()*imageHeight()*8];
|
|
else
|
|
data = new uchar[imageWidth()*imageHeight()*4];
|
|
|
|
if (!data)
|
|
{
|
|
DDebug() << "Error decoding JPEG2000 image data : Memory Allocation Failed" << endl;
|
|
jas_image_destroy(jp2_image);
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
jas_matrix_destroy(pixels[i]);
|
|
|
|
jas_cleanup();
|
|
return false;
|
|
}
|
|
|
|
uint checkPoint = 0;
|
|
uchar *dst = data;
|
|
unsigned short *dst16 = (unsigned short *)data;
|
|
|
|
for (y = 0 ; y < (long)imageHeight() ; y++)
|
|
{
|
|
for (i = 0 ; i < (long)number_components; i++)
|
|
{
|
|
int ret = jas_image_readcmpt(jp2_image, (short)components[i], 0,
|
|
((unsigned int) y) / y_step[i],
|
|
((unsigned int) imageWidth()) / x_step[i],
|
|
1, pixels[i]);
|
|
if (ret != 0)
|
|
{
|
|
DDebug() << "Error decoding JPEG2000 image data" << endl;
|
|
delete [] data;
|
|
jas_image_destroy(jp2_image);
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
jas_matrix_destroy(pixels[i]);
|
|
|
|
jas_cleanup();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
switch (number_components)
|
|
{
|
|
case 1: // Grayscale.
|
|
{
|
|
for (x = 0 ; x < (long)imageWidth() ; x++)
|
|
{
|
|
dst[0] = (uchar)(scale[0]*jas_matrix_getv(pixels[0], x/x_step[0]));
|
|
dst[1] = dst[0];
|
|
dst[2] = dst[0];
|
|
dst[3] = 0xFF;
|
|
|
|
dst += 4;
|
|
}
|
|
break;
|
|
}
|
|
case 3: // RGB.
|
|
{
|
|
if (!m_sixteenBit) // 8 bits image.
|
|
{
|
|
for (x = 0 ; x < (long)imageWidth() ; x++)
|
|
{
|
|
// Blue
|
|
dst[0] = (uchar)(scale[2]*jas_matrix_getv(pixels[2], x/x_step[2]));
|
|
// Green
|
|
dst[1] = (uchar)(scale[1]*jas_matrix_getv(pixels[1], x/x_step[1]));
|
|
// Red
|
|
dst[2] = (uchar)(scale[0]*jas_matrix_getv(pixels[0], x/x_step[0]));
|
|
// Alpha
|
|
dst[3] = 0xFF;
|
|
|
|
dst += 4;
|
|
}
|
|
}
|
|
else // 16 bits image.
|
|
{
|
|
for (x = 0 ; x < (long)imageWidth() ; x++)
|
|
{
|
|
// Blue
|
|
dst16[0] = (unsigned short)(scale[2]*jas_matrix_getv(pixels[2], x/x_step[2]));
|
|
// Green
|
|
dst16[1] = (unsigned short)(scale[1]*jas_matrix_getv(pixels[1], x/x_step[1]));
|
|
// Red
|
|
dst16[2] = (unsigned short)(scale[0]*jas_matrix_getv(pixels[0], x/x_step[0]));
|
|
// Alpha
|
|
dst16[3] = 0xFFFF;
|
|
|
|
dst16 += 4;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 4: // RGBA.
|
|
{
|
|
if (!m_sixteenBit) // 8 bits image.
|
|
{
|
|
for (x = 0 ; x < (long)imageWidth() ; x++)
|
|
{
|
|
// Blue
|
|
dst[0] = (uchar)(scale[2] * jas_matrix_getv(pixels[2], x/x_step[2]));
|
|
// Green
|
|
dst[1] = (uchar)(scale[1] * jas_matrix_getv(pixels[1], x/x_step[1]));
|
|
// Red
|
|
dst[2] = (uchar)(scale[0] * jas_matrix_getv(pixels[0], x/x_step[0]));
|
|
// Alpha
|
|
dst[3] = (uchar)(scale[3] * jas_matrix_getv(pixels[3], x/x_step[3]));
|
|
|
|
dst += 4;
|
|
}
|
|
}
|
|
else // 16 bits image.
|
|
{
|
|
for (x = 0 ; x < (long)imageWidth() ; x++)
|
|
{
|
|
// Blue
|
|
dst16[0] = (unsigned short)(scale[2]*jas_matrix_getv(pixels[2], x/x_step[2]));
|
|
// Green
|
|
dst16[1] = (unsigned short)(scale[1]*jas_matrix_getv(pixels[1], x/x_step[1]));
|
|
// Red
|
|
dst16[2] = (unsigned short)(scale[0]*jas_matrix_getv(pixels[0], x/x_step[0]));
|
|
// Alpha
|
|
dst16[3] = (unsigned short)(scale[3]*jas_matrix_getv(pixels[3], x/x_step[3]));
|
|
|
|
dst16 += 4;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// use 0-10% and 90-100% for pseudo-progress
|
|
if (observer && y >= (long)checkPoint)
|
|
{
|
|
checkPoint += granularity(observer, y, 0.8);
|
|
if (!observer->continueQuery(m_image))
|
|
{
|
|
delete [] data;
|
|
jas_image_destroy(jp2_image);
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
jas_matrix_destroy(pixels[i]);
|
|
|
|
jas_cleanup();
|
|
|
|
return false;
|
|
}
|
|
observer->progressInfo(m_image, 0.1 + (0.8 * ( ((float)y)/((float)imageHeight()) )));
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// Get ICC color profile.
|
|
|
|
jas_iccprof_t *icc_profile = 0;
|
|
jas_stream_t *icc_stream = 0;
|
|
jas_cmprof_t *cm_profile = 0;
|
|
|
|
cm_profile = jas_image_cmprof(jp2_image);
|
|
if (cm_profile != 0)
|
|
icc_profile = jas_iccprof_createfromcmprof(cm_profile);
|
|
|
|
if (icc_profile != 0)
|
|
{
|
|
icc_stream = jas_stream_memopen(NULL, 0);
|
|
|
|
if (icc_stream != 0)
|
|
{
|
|
if (jas_iccprof_save(icc_profile, icc_stream) == 0)
|
|
{
|
|
if (jas_stream_flush(icc_stream) == 0)
|
|
{
|
|
TQMap<int, TQByteArray>& metaData = imageMetaData();
|
|
jas_stream_memobj_t *blob = (jas_stream_memobj_t *) icc_stream->obj_;
|
|
TQByteArray profile_rawdata(blob->len_);
|
|
memcpy(profile_rawdata.data(), blob->buf_, blob->len_);
|
|
metaData.insert(DImg::ICC, profile_rawdata);
|
|
jas_stream_close(icc_stream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (observer)
|
|
observer->progressInfo(m_image, 1.0);
|
|
|
|
imageSetAttribute("format", "JP2K");
|
|
imageData() = data;
|
|
|
|
jas_image_destroy(jp2_image);
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
jas_matrix_destroy(pixels[i]);
|
|
|
|
jas_cleanup();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool JP2KLoader::save(const TQString& filePath, DImgLoaderObserver *observer)
|
|
{
|
|
FILE *file = fopen(TQFile::encodeName(filePath), "wb");
|
|
if (!file)
|
|
return false;
|
|
|
|
fclose(file);
|
|
|
|
// -------------------------------------------------------------------
|
|
// Initialize JPEG 2000 API.
|
|
|
|
long i, x, y;
|
|
unsigned long number_components;
|
|
|
|
jas_image_t *jp2_image = 0;
|
|
jas_stream_t *jp2_stream = 0;
|
|
jas_matrix_t *pixels[4];
|
|
jas_image_cmptparm_t component_info[4];
|
|
|
|
int init = jas_init();
|
|
if (init != 0)
|
|
{
|
|
DDebug() << "Unable to init JPEG2000 decoder" << endl;
|
|
return false;
|
|
}
|
|
|
|
jp2_stream = jas_stream_fopen(TQFile::encodeName(filePath), "wb");
|
|
if (jp2_stream == 0)
|
|
{
|
|
DDebug() << "Unable to open JPEG2000 stream" << endl;
|
|
return false;
|
|
}
|
|
|
|
number_components = imageHasAlpha() ? 4 : 3;
|
|
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
{
|
|
component_info[i].tlx = 0;
|
|
component_info[i].tly = 0;
|
|
component_info[i].hstep = 1;
|
|
component_info[i].vstep = 1;
|
|
component_info[i].width = imageWidth();
|
|
component_info[i].height = imageHeight();
|
|
component_info[i].prec = imageBitsDepth();
|
|
component_info[i].sgnd = false;
|
|
}
|
|
|
|
jp2_image = jas_image_create(number_components, component_info, JAS_CLRSPC_UNKNOWN);
|
|
if (jp2_image == 0)
|
|
{
|
|
jas_stream_close(jp2_stream);
|
|
DDebug() << "Unable to create JPEG2000 image" << endl;
|
|
return false;
|
|
}
|
|
|
|
if (observer)
|
|
observer->progressInfo(m_image, 0.1);
|
|
|
|
// -------------------------------------------------------------------
|
|
// Check color space.
|
|
|
|
if (number_components >= 3 ) // RGB & RGBA
|
|
{
|
|
// Alpha Channel
|
|
if (number_components == 4 )
|
|
jas_image_setcmpttype(jp2_image, 3, JAS_IMAGE_CT_OPACITY);
|
|
|
|
jas_image_setclrspc(jp2_image, JAS_CLRSPC_SRGB);
|
|
jas_image_setcmpttype(jp2_image, 0, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
|
|
jas_image_setcmpttype(jp2_image, 1, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
|
|
jas_image_setcmpttype(jp2_image, 2, JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// Set ICC color profile.
|
|
|
|
// FIXME : doesn't work yet!
|
|
|
|
jas_cmprof_t *cm_profile = 0;
|
|
jas_iccprof_t *icc_profile = 0;
|
|
|
|
TQByteArray profile_rawdata = m_image->getICCProfil();
|
|
|
|
icc_profile = jas_iccprof_createfrombuf((uchar*)profile_rawdata.data(), profile_rawdata.size());
|
|
if (icc_profile != 0)
|
|
{
|
|
cm_profile = jas_cmprof_createfromiccprof(icc_profile);
|
|
if (cm_profile != 0)
|
|
{
|
|
jas_image_setcmprof(jp2_image, cm_profile);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// Convert to JPEG 2000 pixels.
|
|
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
{
|
|
pixels[i] = jas_matrix_create(1, (unsigned int)imageWidth());
|
|
if (pixels[i] == 0)
|
|
{
|
|
for (x = 0 ; x < i ; x++)
|
|
jas_matrix_destroy(pixels[x]);
|
|
|
|
jas_image_destroy(jp2_image);
|
|
DDebug() << "Error encoding JPEG2000 image data : Memory Allocation Failed" << endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
unsigned char* data = imageData();
|
|
unsigned char* pixel;
|
|
unsigned short r, g, b, a=0;
|
|
uint checkpoint = 0;
|
|
|
|
for (y = 0 ; y < (long)imageHeight() ; y++)
|
|
{
|
|
if (observer && y == (long)checkpoint)
|
|
{
|
|
checkpoint += granularity(observer, imageHeight(), 0.8);
|
|
if (!observer->continueQuery(m_image))
|
|
{
|
|
jas_image_destroy(jp2_image);
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
jas_matrix_destroy(pixels[i]);
|
|
|
|
jas_cleanup();
|
|
|
|
return false;
|
|
}
|
|
observer->progressInfo(m_image, 0.1 + (0.8 * ( ((float)y)/((float)imageHeight()) )));
|
|
}
|
|
|
|
for (x = 0 ; x < (long)imageWidth() ; x++)
|
|
{
|
|
pixel = &data[((y * imageWidth()) + x) * imageBytesDepth()];
|
|
|
|
if ( imageSixteenBit() ) // 16 bits image.
|
|
{
|
|
b = (unsigned short)(pixel[0]+256*pixel[1]);
|
|
g = (unsigned short)(pixel[2]+256*pixel[3]);
|
|
r = (unsigned short)(pixel[4]+256*pixel[5]);
|
|
|
|
if (imageHasAlpha())
|
|
a = (unsigned short)(pixel[6]+256*pixel[7]);
|
|
}
|
|
else // 8 bits image.
|
|
{
|
|
b = (unsigned short)pixel[0];
|
|
g = (unsigned short)pixel[1];
|
|
r = (unsigned short)pixel[2];
|
|
|
|
if (imageHasAlpha())
|
|
a = (unsigned short)(pixel[3]);
|
|
}
|
|
|
|
jas_matrix_setv(pixels[0], x, r);
|
|
jas_matrix_setv(pixels[1], x, g);
|
|
jas_matrix_setv(pixels[2], x, b);
|
|
|
|
if (number_components > 3)
|
|
jas_matrix_setv(pixels[3], x, a);
|
|
}
|
|
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
{
|
|
int ret = jas_image_writecmpt(jp2_image, (short) i, 0, (unsigned int)y,
|
|
(unsigned int)imageWidth(), 1, pixels[i]);
|
|
if (ret != 0)
|
|
{
|
|
DDebug() << "Error encoding JPEG2000 image data" << endl;
|
|
|
|
jas_image_destroy(jp2_image);
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
jas_matrix_destroy(pixels[i]);
|
|
|
|
jas_cleanup();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
TQVariant qualityAttr = imageGetAttribute("quality");
|
|
int quality = qualityAttr.isValid() ? qualityAttr.toInt() : 90;
|
|
|
|
if (quality < 0)
|
|
quality = 90;
|
|
if (quality > 100)
|
|
quality = 100;
|
|
|
|
TQString rate;
|
|
TQTextStream ts( &rate, IO_WriteOnly );
|
|
|
|
// NOTE: to have a lossless compression use quality=100.
|
|
// jp2_encode()::optstr:
|
|
// - rate=#B => the resulting file size is about # bytes
|
|
// - rate=0.0 .. 1.0 => the resulting file size is about the factor times
|
|
// the uncompressed size
|
|
ts << "rate=" << ( quality / 100.0F );
|
|
|
|
DDebug() << "JPEG2000 quality: " << quality << endl;
|
|
DDebug() << "JPEG2000 " << rate << endl;
|
|
|
|
# if defined(JAS_VERSION_MAJOR) && (JAS_VERSION_MAJOR >= 3)
|
|
const jas_image_fmtinfo_t *jp2_fmtinfo = jas_image_lookupfmtbyname("jp2");
|
|
int ret = -1;
|
|
if (jp2_fmtinfo)
|
|
{
|
|
ret = jas_image_encode(jp2_image, jp2_stream, jp2_fmtinfo->id, rate.utf8().data());
|
|
}
|
|
# else
|
|
int ret = jp2_encode(jp2_image, jp2_stream, rate.utf8().data());
|
|
# endif
|
|
|
|
if (ret != 0)
|
|
{
|
|
DDebug() << "Unable to encode JPEG2000 image" << endl;
|
|
|
|
jas_image_destroy(jp2_image);
|
|
jas_stream_close(jp2_stream);
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
jas_matrix_destroy(pixels[i]);
|
|
|
|
jas_cleanup();
|
|
|
|
return false;
|
|
}
|
|
|
|
if (observer)
|
|
observer->progressInfo(m_image, 1.0);
|
|
|
|
imageSetAttribute("savedformat", "JP2K");
|
|
|
|
saveMetadata(filePath);
|
|
|
|
jas_image_destroy(jp2_image);
|
|
jas_stream_close(jp2_stream);
|
|
for (i = 0 ; i < (long)number_components ; i++)
|
|
jas_matrix_destroy(pixels[i]);
|
|
|
|
jas_cleanup();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool JP2KLoader::hasAlpha() const
|
|
{
|
|
return m_hasAlpha;
|
|
}
|
|
|
|
bool JP2KLoader::sixteenBit() const
|
|
{
|
|
return m_sixteenBit;
|
|
}
|
|
|
|
} // NameSpace Digikam
|