750 lines
20 KiB
C
750 lines
20 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* 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
|
|
* of the License, 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Contributor(s): Campbell Barton
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/imbuf/intern/jp2.c
|
|
* \ingroup imbuf
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_math.h"
|
|
|
|
#include "imbuf.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
#include "IMB_imbuf.h"
|
|
#include "IMB_allocimbuf.h"
|
|
#include "IMB_filetype.h"
|
|
|
|
#include "openjpeg.h"
|
|
|
|
#define JP2_FILEHEADER_SIZE 14
|
|
|
|
static char JP2_HEAD[]= {0x0, 0x0, 0x0, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A};
|
|
|
|
/* We only need this because of how the presets are set */
|
|
typedef struct img_folder{
|
|
/** The directory path of the folder containing input images*/
|
|
char *imgdirpath;
|
|
/** Output format*/
|
|
char *out_format;
|
|
/** Enable option*/
|
|
char set_imgdir;
|
|
/** Enable Cod Format for output*/
|
|
char set_out_format;
|
|
/** User specified rate stored in case of cinema option*/
|
|
float *rates;
|
|
}img_fol_t;
|
|
|
|
static int check_jp2(unsigned char *mem) /* J2K_CFMT */
|
|
{
|
|
return memcmp(JP2_HEAD, mem, 12) ? 0 : 1;
|
|
}
|
|
|
|
int imb_is_a_jp2(unsigned char *buf)
|
|
{
|
|
return check_jp2(buf);
|
|
}
|
|
|
|
|
|
/**
|
|
sample error callback expecting a FILE* client object
|
|
*/
|
|
static void error_callback(const char *msg, void *client_data) {
|
|
FILE *stream = (FILE*)client_data;
|
|
fprintf(stream, "[ERROR] %s", msg);
|
|
}
|
|
/**
|
|
sample warning callback expecting a FILE* client object
|
|
*/
|
|
static void warning_callback(const char *msg, void *client_data) {
|
|
FILE *stream = (FILE*)client_data;
|
|
fprintf(stream, "[WARNING] %s", msg);
|
|
}
|
|
/**
|
|
sample debug callback expecting no client object
|
|
*/
|
|
static void info_callback(const char *msg, void *client_data) {
|
|
(void)client_data;
|
|
fprintf(stdout, "[INFO] %s", msg);
|
|
}
|
|
|
|
|
|
|
|
struct ImBuf *imb_jp2_decode(unsigned char *mem, size_t size, int flags)
|
|
{
|
|
struct ImBuf *ibuf = NULL;
|
|
int use_float = 0; /* for precision higher then 8 use float */
|
|
|
|
long signed_offsets[4]= {0, 0, 0, 0};
|
|
int float_divs[4]= {1, 1, 1, 1};
|
|
|
|
int index;
|
|
|
|
int w, h, depth;
|
|
|
|
opj_dparameters_t parameters; /* decompression parameters */
|
|
|
|
opj_event_mgr_t event_mgr; /* event manager */
|
|
opj_image_t *image = NULL;
|
|
|
|
int i;
|
|
|
|
opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */
|
|
opj_cio_t *cio = NULL;
|
|
|
|
if (check_jp2(mem) == 0) return(NULL);
|
|
|
|
/* configure the event callbacks (not required) */
|
|
memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
|
|
event_mgr.error_handler = error_callback;
|
|
event_mgr.warning_handler = warning_callback;
|
|
event_mgr.info_handler = info_callback;
|
|
|
|
|
|
/* set decoding parameters to default values */
|
|
opj_set_default_decoder_parameters(¶meters);
|
|
|
|
|
|
/* JPEG 2000 compressed image data */
|
|
|
|
/* get a decoder handle */
|
|
dinfo = opj_create_decompress(CODEC_JP2);
|
|
|
|
/* catch events using our callbacks and give a local context */
|
|
opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
|
|
|
|
/* setup the decoder decoding parameters using the current image and user parameters */
|
|
opj_setup_decoder(dinfo, ¶meters);
|
|
|
|
/* open a byte stream */
|
|
cio = opj_cio_open((opj_common_ptr)dinfo, mem, size);
|
|
|
|
/* decode the stream and fill the image structure */
|
|
image = opj_decode(dinfo, cio);
|
|
|
|
if(!image) {
|
|
fprintf(stderr, "ERROR -> j2k_to_image: failed to decode image!\n");
|
|
opj_destroy_decompress(dinfo);
|
|
opj_cio_close(cio);
|
|
return NULL;
|
|
}
|
|
|
|
/* close the byte stream */
|
|
opj_cio_close(cio);
|
|
|
|
|
|
if((image->numcomps * image->x1 * image->y1) == 0)
|
|
{
|
|
fprintf(stderr,"\nError: invalid raw image parameters\n");
|
|
return NULL;
|
|
}
|
|
|
|
w = image->comps[0].w;
|
|
h = image->comps[0].h;
|
|
|
|
switch (image->numcomps) {
|
|
case 1: /* Greyscale */
|
|
case 3: /* Color */
|
|
depth= 24;
|
|
break;
|
|
default: /* 2 or 4 - Greyscale or Color + alpha */
|
|
depth= 32; /* greyscale + alpha */
|
|
break;
|
|
}
|
|
|
|
|
|
i = image->numcomps;
|
|
if (i>4) i= 4;
|
|
|
|
while (i) {
|
|
i--;
|
|
|
|
if (image->comps[i].prec > 8)
|
|
use_float = 1;
|
|
|
|
if (image->comps[i].sgnd)
|
|
signed_offsets[i]= 1 << (image->comps[i].prec - 1);
|
|
|
|
/* only needed for float images but dosnt hurt to calc this */
|
|
float_divs[i]= (1<<image->comps[i].prec)-1;
|
|
}
|
|
|
|
ibuf= IMB_allocImBuf(w, h, depth, use_float ? IB_rectfloat : IB_rect);
|
|
|
|
if (ibuf==NULL) {
|
|
if(dinfo)
|
|
opj_destroy_decompress(dinfo);
|
|
return NULL;
|
|
}
|
|
|
|
ibuf->ftype = JP2;
|
|
|
|
if (use_float) {
|
|
float *rect_float= ibuf->rect_float;
|
|
|
|
if (image->numcomps < 3) {
|
|
/* greyscale 12bits+ */
|
|
for (i = 0; i < w * h; i++, rect_float+=4) {
|
|
index = w * h - ((i) / (w) + 1) * w + (i) % (w);
|
|
|
|
rect_float[0]= rect_float[1]= rect_float[2]= (float)(image->comps[0].data[index] + signed_offsets[0]) / float_divs[0];
|
|
|
|
if (image->numcomps == 2)
|
|
rect_float[3]= (image->comps[1].data[index] + signed_offsets[1]) / float_divs[1];
|
|
else
|
|
rect_float[3]= 1.0f;
|
|
}
|
|
} else {
|
|
/* rgb or rgba 12bits+ */
|
|
for (i = 0; i < w * h; i++, rect_float+=4) {
|
|
index = w * h - ((i) / (w) + 1) * w + (i) % (w);
|
|
|
|
rect_float[0]= (float)(image->comps[0].data[index] + signed_offsets[0]) / float_divs[0];
|
|
rect_float[1]= (float)(image->comps[1].data[index] + signed_offsets[1]) / float_divs[1];
|
|
rect_float[2]= (float)(image->comps[2].data[index] + signed_offsets[2]) / float_divs[2];
|
|
|
|
if (image->numcomps >= 4)
|
|
rect_float[3]= (float)(image->comps[3].data[index] + signed_offsets[3]) / float_divs[3];
|
|
else
|
|
rect_float[3]= 1.0f;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
unsigned char *rect= (unsigned char *)ibuf->rect;
|
|
|
|
if (image->numcomps < 3) {
|
|
/* greyscale */
|
|
for (i = 0; i < w * h; i++, rect+=4) {
|
|
index = w * h - ((i) / (w) + 1) * w + (i) % (w);
|
|
|
|
rect[0]= rect[1]= rect[2]= (image->comps[0].data[index] + signed_offsets[0]);
|
|
|
|
if (image->numcomps == 2)
|
|
rect[3]= image->comps[1].data[index] + signed_offsets[1];
|
|
else
|
|
rect[3]= 255;
|
|
}
|
|
} else {
|
|
/* 8bit rgb or rgba */
|
|
for (i = 0; i < w * h; i++, rect+=4) {
|
|
int index = w * h - ((i) / (w) + 1) * w + (i) % (w);
|
|
|
|
rect[0]= image->comps[0].data[index] + signed_offsets[0];
|
|
rect[1]= image->comps[1].data[index] + signed_offsets[1];
|
|
rect[2]= image->comps[2].data[index] + signed_offsets[2];
|
|
|
|
if (image->numcomps >= 4)
|
|
rect[3]= image->comps[3].data[index] + signed_offsets[3];
|
|
else
|
|
rect[3]= 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* free remaining structures */
|
|
if(dinfo) {
|
|
opj_destroy_decompress(dinfo);
|
|
}
|
|
|
|
/* free image data structure */
|
|
opj_image_destroy(image);
|
|
|
|
if (flags & IB_rect) {
|
|
IMB_rect_from_float(ibuf);
|
|
}
|
|
|
|
return(ibuf);
|
|
}
|
|
|
|
//static opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw_cparameters_t *raw_cp) {
|
|
/* prec can be 8, 12, 16 */
|
|
|
|
#define UPSAMPLE_8_TO_12(_val) ((_val<<4) | (_val & ((1<<4)-1)))
|
|
#define UPSAMPLE_8_TO_16(_val) ((_val<<8)+_val)
|
|
|
|
#define DOWNSAMPLE_FLOAT_TO_8BIT(_val) (_val)<=0.0f?0: ((_val)>=1.0f?255: (int)(255.0f*(_val)))
|
|
#define DOWNSAMPLE_FLOAT_TO_12BIT(_val) (_val)<=0.0f?0: ((_val)>=1.0f?4095: (int)(4095.0f*(_val)))
|
|
#define DOWNSAMPLE_FLOAT_TO_16BIT(_val) (_val)<=0.0f?0: ((_val)>=1.0f?65535: (int)(65535.0f*(_val)))
|
|
|
|
|
|
/*
|
|
2048x1080 (2K) at 24 fps or 48 fps, or 4096x2160 (4K) at 24 fps; 3x12 bits per pixel, XYZ color space
|
|
|
|
* In 2K, for Scope (2.39:1) presentation 2048x858 pixels of the imager is used
|
|
* In 2K, for Flat (1.85:1) presentation 1998x1080 pixels of the imager is used
|
|
*/
|
|
|
|
/* ****************************** COPIED FROM image_to_j2k.c */
|
|
|
|
/* ----------------------------------------------------------------------- */
|
|
#define CINEMA_24_CS 1302083 /*Codestream length for 24fps*/
|
|
#define CINEMA_48_CS 651041 /*Codestream length for 48fps*/
|
|
#define COMP_24_CS 1041666 /*Maximum size per color component for 2K & 4K @ 24fps*/
|
|
#define COMP_48_CS 520833 /*Maximum size per color component for 2K @ 48fps*/
|
|
|
|
|
|
static int initialise_4K_poc(opj_poc_t *POC, int numres){
|
|
POC[0].tile = 1;
|
|
POC[0].resno0 = 0;
|
|
POC[0].compno0 = 0;
|
|
POC[0].layno1 = 1;
|
|
POC[0].resno1 = numres-1;
|
|
POC[0].compno1 = 3;
|
|
POC[0].prg1 = CPRL;
|
|
POC[1].tile = 1;
|
|
POC[1].resno0 = numres-1;
|
|
POC[1].compno0 = 0;
|
|
POC[1].layno1 = 1;
|
|
POC[1].resno1 = numres;
|
|
POC[1].compno1 = 3;
|
|
POC[1].prg1 = CPRL;
|
|
return 2;
|
|
}
|
|
|
|
static void cinema_parameters(opj_cparameters_t *parameters){
|
|
parameters->tile_size_on = false;
|
|
parameters->cp_tdx=1;
|
|
parameters->cp_tdy=1;
|
|
|
|
/*Tile part*/
|
|
parameters->tp_flag = 'C';
|
|
parameters->tp_on = 1;
|
|
|
|
/*Tile and Image shall be at (0,0)*/
|
|
parameters->cp_tx0 = 0;
|
|
parameters->cp_ty0 = 0;
|
|
parameters->image_offset_x0 = 0;
|
|
parameters->image_offset_y0 = 0;
|
|
|
|
/*Codeblock size= 32*32*/
|
|
parameters->cblockw_init = 32;
|
|
parameters->cblockh_init = 32;
|
|
parameters->csty |= 0x01;
|
|
|
|
/*The progression order shall be CPRL*/
|
|
parameters->prog_order = CPRL;
|
|
|
|
/* No ROI */
|
|
parameters->roi_compno = -1;
|
|
|
|
parameters->subsampling_dx = 1; parameters->subsampling_dy = 1;
|
|
|
|
/* 9-7 transform */
|
|
parameters->irreversible = 1;
|
|
|
|
}
|
|
|
|
static void cinema_setup_encoder(opj_cparameters_t *parameters,opj_image_t *image, img_fol_t *img_fol){
|
|
int i;
|
|
float temp_rate;
|
|
|
|
switch (parameters->cp_cinema){
|
|
case CINEMA2K_24:
|
|
case CINEMA2K_48:
|
|
if(parameters->numresolution > 6){
|
|
parameters->numresolution = 6;
|
|
}
|
|
if (!((image->comps[0].w == 2048) || (image->comps[0].h == 1080))){
|
|
fprintf(stdout,"Image coordinates %d x %d is not 2K compliant.\nJPEG Digital Cinema Profile-3 "
|
|
"(2K profile) compliance requires that at least one of coordinates match 2048 x 1080\n",
|
|
image->comps[0].w,image->comps[0].h);
|
|
parameters->cp_rsiz = STD_RSIZ;
|
|
}
|
|
break;
|
|
|
|
case CINEMA4K_24:
|
|
if(parameters->numresolution < 1){
|
|
parameters->numresolution = 1;
|
|
}else if(parameters->numresolution > 7){
|
|
parameters->numresolution = 7;
|
|
}
|
|
if (!((image->comps[0].w == 4096) || (image->comps[0].h == 2160))){
|
|
fprintf(stdout,"Image coordinates %d x %d is not 4K compliant.\nJPEG Digital Cinema Profile-4"
|
|
"(4K profile) compliance requires that at least one of coordinates match 4096 x 2160\n",
|
|
image->comps[0].w,image->comps[0].h);
|
|
parameters->cp_rsiz = STD_RSIZ;
|
|
}
|
|
parameters->numpocs = initialise_4K_poc(parameters->POC,parameters->numresolution);
|
|
break;
|
|
case OFF:
|
|
/* do nothing */
|
|
break;
|
|
}
|
|
|
|
switch (parameters->cp_cinema){
|
|
case CINEMA2K_24:
|
|
case CINEMA4K_24:
|
|
for(i=0 ; i<parameters->tcp_numlayers ; i++){
|
|
temp_rate = 0 ;
|
|
if (img_fol->rates[i]== 0){
|
|
parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
|
|
(CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy);
|
|
}else{
|
|
temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
|
|
(img_fol->rates[i] * 8 * image->comps[0].dx * image->comps[0].dy);
|
|
if (temp_rate > CINEMA_24_CS ){
|
|
parameters->tcp_rates[i]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
|
|
(CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy);
|
|
}else{
|
|
parameters->tcp_rates[i]= img_fol->rates[i];
|
|
}
|
|
}
|
|
}
|
|
parameters->max_comp_size = COMP_24_CS;
|
|
break;
|
|
|
|
case CINEMA2K_48:
|
|
for(i=0 ; i<parameters->tcp_numlayers ; i++){
|
|
temp_rate = 0 ;
|
|
if (img_fol->rates[i]== 0){
|
|
parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
|
|
(CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy);
|
|
}else{
|
|
temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
|
|
(img_fol->rates[i] * 8 * image->comps[0].dx * image->comps[0].dy);
|
|
if (temp_rate > CINEMA_48_CS ){
|
|
parameters->tcp_rates[0]= ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
|
|
(CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy);
|
|
}else{
|
|
parameters->tcp_rates[i]= img_fol->rates[i];
|
|
}
|
|
}
|
|
}
|
|
parameters->max_comp_size = COMP_48_CS;
|
|
break;
|
|
case OFF:
|
|
/* do nothing */
|
|
break;
|
|
}
|
|
parameters->cp_disto_alloc = 1;
|
|
}
|
|
|
|
|
|
static opj_image_t* ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters) {
|
|
|
|
unsigned char *rect;
|
|
float *rect_float;
|
|
|
|
int subsampling_dx = parameters->subsampling_dx;
|
|
int subsampling_dy = parameters->subsampling_dy;
|
|
|
|
|
|
int i, numcomps, w, h, prec;
|
|
int x,y, y_row;
|
|
OPJ_COLOR_SPACE color_space;
|
|
opj_image_cmptparm_t cmptparm[4]; /* maximum of 4 components */
|
|
opj_image_t * image = NULL;
|
|
|
|
img_fol_t img_fol; /* only needed for cinema presets */
|
|
memset(&img_fol,0,sizeof(img_fol_t));
|
|
|
|
if (ibuf->ftype & JP2_CINE) {
|
|
|
|
if (ibuf->x==4096 || ibuf->y==2160)
|
|
parameters->cp_cinema= CINEMA4K_24;
|
|
else {
|
|
if (ibuf->ftype & JP2_CINE_48FPS) {
|
|
parameters->cp_cinema= CINEMA2K_48;
|
|
}
|
|
else {
|
|
parameters->cp_cinema= CINEMA2K_24;
|
|
}
|
|
}
|
|
if (parameters->cp_cinema){
|
|
img_fol.rates = (float*)MEM_mallocN(parameters->tcp_numlayers * sizeof(float), "jp2_rates");
|
|
for(i=0; i< parameters->tcp_numlayers; i++){
|
|
img_fol.rates[i] = parameters->tcp_rates[i];
|
|
}
|
|
cinema_parameters(parameters);
|
|
}
|
|
|
|
color_space= CLRSPC_SYCC;
|
|
prec= 12;
|
|
numcomps= 3;
|
|
}
|
|
else {
|
|
/* Get settings from the imbuf */
|
|
color_space = (ibuf->ftype & JP2_YCC) ? CLRSPC_SYCC : CLRSPC_SRGB;
|
|
|
|
if (ibuf->ftype & JP2_16BIT) prec= 16;
|
|
else if (ibuf->ftype & JP2_12BIT) prec= 12;
|
|
else prec= 8;
|
|
|
|
/* 32bit images == alpha channel */
|
|
/* grayscale not supported yet */
|
|
numcomps= (ibuf->depth==32) ? 4 : 3;
|
|
}
|
|
|
|
w= ibuf->x;
|
|
h= ibuf->y;
|
|
|
|
|
|
/* initialize image components */
|
|
memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
|
|
for(i = 0; i < numcomps; i++) {
|
|
cmptparm[i].prec = prec;
|
|
cmptparm[i].bpp = prec;
|
|
cmptparm[i].sgnd = 0;
|
|
cmptparm[i].dx = subsampling_dx;
|
|
cmptparm[i].dy = subsampling_dy;
|
|
cmptparm[i].w = w;
|
|
cmptparm[i].h = h;
|
|
}
|
|
/* create the image */
|
|
image = opj_image_create(numcomps, &cmptparm[0], color_space);
|
|
if(!image) {
|
|
printf("Error: opj_image_create() failed\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* set image offset and reference grid */
|
|
image->x0 = parameters->image_offset_x0;
|
|
image->y0 = parameters->image_offset_y0;
|
|
image->x1 = parameters->image_offset_x0 + (w - 1) * subsampling_dx + 1;
|
|
image->y1 = parameters->image_offset_y0 + (h - 1) * subsampling_dy + 1;
|
|
|
|
/* set image data */
|
|
rect = (unsigned char*) ibuf->rect;
|
|
rect_float= ibuf->rect_float;
|
|
|
|
if (rect_float && rect && prec==8) {
|
|
/* No need to use the floating point buffer, just write the 8 bits from the char buffer */
|
|
rect_float= NULL;
|
|
}
|
|
|
|
|
|
if (rect_float) {
|
|
float rgb[3];
|
|
|
|
switch (prec) {
|
|
case 8: /* Convert blenders float color channels to 8,12 or 16bit ints */
|
|
for(y=h-1; y>=0; y--) {
|
|
y_row = y*w;
|
|
for(x=0; x<w; x++, rect_float+=4) {
|
|
i = y_row + x;
|
|
|
|
if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
|
|
linearrgb_to_srgb_v3_v3(rgb, rect_float);
|
|
else
|
|
copy_v3_v3(rgb, rect_float);
|
|
|
|
image->comps[0].data[i] = DOWNSAMPLE_FLOAT_TO_8BIT(rgb[0]);
|
|
image->comps[1].data[i] = DOWNSAMPLE_FLOAT_TO_8BIT(rgb[1]);
|
|
image->comps[2].data[i] = DOWNSAMPLE_FLOAT_TO_8BIT(rgb[2]);
|
|
if (numcomps>3)
|
|
image->comps[3].data[i] = DOWNSAMPLE_FLOAT_TO_8BIT(rect_float[3]);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 12:
|
|
for(y=h-1; y>=0; y--) {
|
|
y_row = y*w;
|
|
for(x=0; x<w; x++, rect_float+=4) {
|
|
i = y_row + x;
|
|
|
|
if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
|
|
linearrgb_to_srgb_v3_v3(rgb, rect_float);
|
|
else
|
|
copy_v3_v3(rgb, rect_float);
|
|
|
|
image->comps[0].data[i] = DOWNSAMPLE_FLOAT_TO_12BIT(rgb[0]);
|
|
image->comps[1].data[i] = DOWNSAMPLE_FLOAT_TO_12BIT(rgb[1]);
|
|
image->comps[2].data[i] = DOWNSAMPLE_FLOAT_TO_12BIT(rgb[2]);
|
|
if (numcomps>3)
|
|
image->comps[3].data[i] = DOWNSAMPLE_FLOAT_TO_12BIT(rect_float[3]);
|
|
}
|
|
}
|
|
break;
|
|
case 16:
|
|
for(y=h-1; y>=0; y--) {
|
|
y_row = y*w;
|
|
for(x=0; x<w; x++, rect_float+=4) {
|
|
i = y_row + x;
|
|
|
|
if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
|
|
linearrgb_to_srgb_v3_v3(rgb, rect_float);
|
|
else
|
|
copy_v3_v3(rgb, rect_float);
|
|
|
|
image->comps[0].data[i] = DOWNSAMPLE_FLOAT_TO_16BIT(rgb[0]);
|
|
image->comps[1].data[i] = DOWNSAMPLE_FLOAT_TO_16BIT(rgb[1]);
|
|
image->comps[2].data[i] = DOWNSAMPLE_FLOAT_TO_16BIT(rgb[2]);
|
|
if (numcomps>3)
|
|
image->comps[3].data[i] = DOWNSAMPLE_FLOAT_TO_16BIT(rect_float[3]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
/* just use rect*/
|
|
switch (prec) {
|
|
case 8:
|
|
for(y=h-1; y>=0; y--) {
|
|
y_row = y*w;
|
|
for(x=0; x<w; x++, rect+=4) {
|
|
i = y_row + x;
|
|
|
|
image->comps[0].data[i] = rect[0];
|
|
image->comps[1].data[i] = rect[1];
|
|
image->comps[2].data[i] = rect[2];
|
|
if (numcomps>3)
|
|
image->comps[3].data[i] = rect[3];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 12: /* Up Sampling, a bit pointless but best write the bit depth requested */
|
|
for(y=h-1; y>=0; y--) {
|
|
y_row = y*w;
|
|
for(x=0; x<w; x++, rect+=4) {
|
|
i = y_row + x;
|
|
|
|
image->comps[0].data[i]= UPSAMPLE_8_TO_12(rect[0]);
|
|
image->comps[1].data[i]= UPSAMPLE_8_TO_12(rect[1]);
|
|
image->comps[2].data[i]= UPSAMPLE_8_TO_12(rect[2]);
|
|
if (numcomps>3)
|
|
image->comps[3].data[i]= UPSAMPLE_8_TO_12(rect[3]);
|
|
}
|
|
}
|
|
break;
|
|
case 16:
|
|
for(y=h-1; y>=0; y--) {
|
|
y_row = y*w;
|
|
for(x=0; x<w; x++, rect+=4) {
|
|
i = y_row + x;
|
|
|
|
image->comps[0].data[i]= UPSAMPLE_8_TO_16(rect[0]);
|
|
image->comps[1].data[i]= UPSAMPLE_8_TO_16(rect[1]);
|
|
image->comps[2].data[i]= UPSAMPLE_8_TO_16(rect[2]);
|
|
if (numcomps>3)
|
|
image->comps[3].data[i]= UPSAMPLE_8_TO_16(rect[3]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Decide if MCT should be used */
|
|
parameters->tcp_mct = image->numcomps == 3 ? 1 : 0;
|
|
|
|
if(parameters->cp_cinema){
|
|
cinema_setup_encoder(parameters,image,&img_fol);
|
|
}
|
|
|
|
if (img_fol.rates)
|
|
MEM_freeN(img_fol.rates);
|
|
|
|
return image;
|
|
}
|
|
|
|
|
|
/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
|
|
int imb_savejp2(struct ImBuf *ibuf, const char *name, int flags) {
|
|
|
|
int quality = ibuf->ftype & 0xff;
|
|
|
|
int bSuccess;
|
|
opj_cparameters_t parameters; /* compression parameters */
|
|
opj_event_mgr_t event_mgr; /* event manager */
|
|
opj_image_t *image = NULL;
|
|
|
|
(void)flags; /* unused */
|
|
|
|
/*
|
|
configure the event callbacks (not required)
|
|
setting of each callback is optionnal
|
|
*/
|
|
memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
|
|
event_mgr.error_handler = error_callback;
|
|
event_mgr.warning_handler = warning_callback;
|
|
event_mgr.info_handler = info_callback;
|
|
|
|
/* set encoding parameters to default values */
|
|
opj_set_default_encoder_parameters(¶meters);
|
|
|
|
/* compression ratio */
|
|
/* invert range, from 10-100, 100-1
|
|
* where jpeg see's 1 and highest quality (lossless) and 100 is very low quality*/
|
|
parameters.tcp_rates[0]= ((100-quality)/90.0f*99.0f) + 1;
|
|
|
|
|
|
parameters.tcp_numlayers = 1; // only one resolution
|
|
parameters.cp_disto_alloc = 1;
|
|
|
|
image= ibuftoimage(ibuf, ¶meters);
|
|
|
|
|
|
{ /* JP2 format output */
|
|
int codestream_length;
|
|
opj_cio_t *cio = NULL;
|
|
FILE *f = NULL;
|
|
|
|
/* get a JP2 compressor handle */
|
|
opj_cinfo_t* cinfo = opj_create_compress(CODEC_JP2);
|
|
|
|
/* catch events using our callbacks and give a local context */
|
|
opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
|
|
|
|
/* setup the encoder parameters using the current image and using user parameters */
|
|
opj_setup_encoder(cinfo, ¶meters, image);
|
|
|
|
/* open a byte stream for writing */
|
|
/* allocate memory for all tiles */
|
|
cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
|
|
|
|
/* encode the image */
|
|
bSuccess = opj_encode(cinfo, cio, image, NULL); /* last arg used to be parameters.index but this deprecated */
|
|
|
|
if (!bSuccess) {
|
|
opj_cio_close(cio);
|
|
fprintf(stderr, "failed to encode image\n");
|
|
return 0;
|
|
}
|
|
codestream_length = cio_tell(cio);
|
|
|
|
/* write the buffer to disk */
|
|
f = fopen(name, "wb");
|
|
|
|
if (!f) {
|
|
fprintf(stderr, "failed to open %s for writing\n", name);
|
|
return 1;
|
|
}
|
|
fwrite(cio->buffer, 1, codestream_length, f);
|
|
fclose(f);
|
|
fprintf(stderr,"Generated outfile %s\n",name);
|
|
/* close and free the byte stream */
|
|
opj_cio_close(cio);
|
|
|
|
/* free remaining compression structures */
|
|
opj_destroy_compress(cinfo);
|
|
}
|
|
|
|
/* free image data */
|
|
opj_image_destroy(image);
|
|
|
|
return 1;
|
|
}
|