mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-25 05:01:26 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			631 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			631 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * The Python Imaging Library.
 | |
|  * $Id$
 | |
|  *
 | |
|  * decoder for JPEG2000 image data.
 | |
|  *
 | |
|  * history:
 | |
|  * 2014-03-12 ajh  Created
 | |
|  *
 | |
|  * Copyright (c) 2014 Coriolis Systems Limited
 | |
|  * Copyright (c) 2014 Alastair Houghton
 | |
|  *
 | |
|  * See the README file for details on usage and redistribution.
 | |
|  */
 | |
| 
 | |
| #include "Imaging.h"
 | |
| 
 | |
| #ifdef HAVE_OPENJPEG
 | |
| 
 | |
| #include "Jpeg2K.h"
 | |
| 
 | |
| #define CINEMA_24_CS_LENGTH   1302083
 | |
| #define CINEMA_48_CS_LENGTH    651041
 | |
| #define COMP_24_CS_MAX_LENGTH 1041666
 | |
| #define COMP_48_CS_MAX_LENGTH  520833
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /* Error handler                                                        */
 | |
| /* -------------------------------------------------------------------- */
 | |
| 
 | |
| static void
 | |
| j2k_error(const char *msg, void *client_data)
 | |
| {
 | |
|     JPEG2KENCODESTATE *state = (JPEG2KENCODESTATE *) client_data;
 | |
|     free((void *)state->error_msg);
 | |
|     state->error_msg = strdup(msg);
 | |
| }
 | |
| 
 | |
| static void
 | |
| j2k_warn(const char *msg, void *client_data)
 | |
| {
 | |
|     // Null handler
 | |
| }
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /* Buffer output stream                                                 */
 | |
| /* -------------------------------------------------------------------- */
 | |
| 
 | |
| static OPJ_SIZE_T
 | |
| j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
 | |
| {
 | |
|     ImagingCodecState state = (ImagingCodecState)p_user_data;
 | |
|     int result;
 | |
| 
 | |
|     result = _imaging_write_pyFd(state->fd, p_buffer, p_nb_bytes);
 | |
| 
 | |
|     return result ? result : (OPJ_SIZE_T)-1;
 | |
| }
 | |
| 
 | |
| 
 | |
| static OPJ_OFF_T
 | |
| j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
 | |
| {
 | |
|     ImagingCodecState state = (ImagingCodecState)p_user_data;
 | |
|     char *buffer;
 | |
|     int result;
 | |
| 
 | |
|     /* Explicitly write zeros */
 | |
|     buffer = calloc(p_nb_bytes,1);
 | |
|     if (!buffer) {
 | |
|         return (OPJ_OFF_T)-1;
 | |
|     }
 | |
| 
 | |
|     result = _imaging_write_pyFd(state->fd, buffer, p_nb_bytes);
 | |
| 
 | |
|     free(buffer);
 | |
| 
 | |
|     return result ? result : p_nb_bytes;
 | |
| }
 | |
| 
 | |
| static OPJ_BOOL
 | |
| j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data)
 | |
| {
 | |
|     ImagingCodecState state = (ImagingCodecState)p_user_data;
 | |
|     off_t pos = 0;
 | |
| 
 | |
|     _imaging_seek_pyFd(state->fd, p_nb_bytes, SEEK_SET);
 | |
|     pos = _imaging_tell_pyFd(state->fd);
 | |
| 
 | |
|     return pos == p_nb_bytes;
 | |
| }
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /* Encoder                                                              */
 | |
| /* -------------------------------------------------------------------- */
 | |
| 
 | |
| typedef void (*j2k_pack_tile_t)(Imaging im, UINT8 *buf,
 | |
|                                 unsigned x0, unsigned y0,
 | |
|                                 unsigned w, unsigned h);
 | |
| 
 | |
| static void
 | |
| j2k_pack_l(Imaging im, UINT8 *buf,
 | |
|            unsigned x0, unsigned y0, unsigned w, unsigned h)
 | |
| {
 | |
|     UINT8 *ptr = buf;
 | |
|     unsigned x,y;
 | |
|     for (y = 0; y < h; ++y) {
 | |
|         UINT8 *data = (UINT8 *)(im->image[y + y0] + x0);
 | |
|         for (x = 0; x < w; ++x)
 | |
|             *ptr++ = *data++;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| j2k_pack_i16(Imaging im, UINT8 *buf,
 | |
|              unsigned x0, unsigned y0, unsigned w, unsigned h)
 | |
| {
 | |
|     UINT8 *ptr = buf;
 | |
|     unsigned x,y;
 | |
|     for (y = 0; y < h; ++y) {
 | |
|         UINT8 *data = (UINT8 *)(im->image[y + y0] + x0);
 | |
|         for (x = 0; x < w; ++x) {
 | |
|             *ptr++ = *data++;
 | |
|             *ptr++ = *data++;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| j2k_pack_la(Imaging im, UINT8 *buf,
 | |
|             unsigned x0, unsigned y0, unsigned w, unsigned h)
 | |
| {
 | |
|     UINT8 *ptr = buf;
 | |
|     UINT8 *ptra = buf + w * h;
 | |
|     unsigned x,y;
 | |
|     for (y = 0; y < h; ++y) {
 | |
|         UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
 | |
|         for (x = 0; x < w; ++x) {
 | |
|             *ptr++ = data[0];
 | |
|             *ptra++ = data[3];
 | |
|             data += 4;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| j2k_pack_rgb(Imaging im, UINT8 *buf,
 | |
|              unsigned x0, unsigned y0, unsigned w, unsigned h)
 | |
| {
 | |
|     UINT8 *pr = buf;
 | |
|     UINT8 *pg = pr + w * h;
 | |
|     UINT8 *pb = pg + w * h;
 | |
|     unsigned x,y;
 | |
|     for (y = 0; y < h; ++y) {
 | |
|         UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
 | |
|         for (x = 0; x < w; ++x) {
 | |
|             *pr++ = data[0];
 | |
|             *pg++ = data[1];
 | |
|             *pb++ = data[2];
 | |
|             data += 4;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| j2k_pack_rgba(Imaging im, UINT8 *buf,
 | |
|               unsigned x0, unsigned y0, unsigned w, unsigned h)
 | |
| {
 | |
|     UINT8 *pr = buf;
 | |
|     UINT8 *pg = pr + w * h;
 | |
|     UINT8 *pb = pg + w * h;
 | |
|     UINT8 *pa = pb + w * h;
 | |
|     unsigned x,y;
 | |
|     for (y = 0; y < h; ++y) {
 | |
|         UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
 | |
|         for (x = 0; x < w; ++x) {
 | |
|             *pr++ = *data++;
 | |
|             *pg++ = *data++;
 | |
|             *pb++ = *data++;
 | |
|             *pa++ = *data++;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| enum {
 | |
|     J2K_STATE_START = 0,
 | |
|     J2K_STATE_ENCODING = 1,
 | |
|     J2K_STATE_DONE = 2,
 | |
|     J2K_STATE_FAILED = 3,
 | |
| };
 | |
| 
 | |
| static void
 | |
| j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params)
 | |
| {
 | |
|     float rate;
 | |
|     unsigned n;
 | |
| 
 | |
|     /* These settings have been copied from opj_compress in the OpenJPEG
 | |
|        sources. */
 | |
| 
 | |
|     params->tile_size_on = OPJ_FALSE;
 | |
|     params->cp_tdx = params->cp_tdy = 1;
 | |
|     params->tp_flag = 'C';
 | |
|     params->tp_on = 1;
 | |
|     params->cp_tx0 = params->cp_ty0 = 0;
 | |
|     params->image_offset_x0 = params->image_offset_y0 = 0;
 | |
|     params->cblockw_init = 32;
 | |
|     params->cblockh_init = 32;
 | |
|     params->csty |= 0x01;
 | |
|     params->prog_order = OPJ_CPRL;
 | |
|     params->roi_compno = -1;
 | |
|     params->subsampling_dx = params->subsampling_dy = 1;
 | |
|     params->irreversible = 1;
 | |
| 
 | |
|     if (params->cp_cinema == OPJ_CINEMA4K_24) {
 | |
|         float max_rate = ((float)(components * im->xsize * im->ysize * 8)
 | |
|                           / (CINEMA_24_CS_LENGTH * 8));
 | |
| 
 | |
|         params->POC[0].tile = 1;
 | |
|         params->POC[0].resno0 = 0;
 | |
|         params->POC[0].compno0 = 0;
 | |
|         params->POC[0].layno1 = 1;
 | |
|         params->POC[0].resno1 = params->numresolution - 1;
 | |
|         params->POC[0].compno1 = 3;
 | |
|         params->POC[0].prg1 = OPJ_CPRL;
 | |
|         params->POC[1].tile = 1;
 | |
|         params->POC[1].resno0 = 0;
 | |
|         params->POC[1].compno0 = 0;
 | |
|         params->POC[1].layno1 = 1;
 | |
|         params->POC[1].resno1 = params->numresolution - 1;
 | |
|         params->POC[1].compno1 = 3;
 | |
|         params->POC[1].prg1 = OPJ_CPRL;
 | |
|         params->numpocs = 2;
 | |
| 
 | |
|         for (n = 0; n < params->tcp_numlayers; ++n) {
 | |
|             rate = 0;
 | |
|             if (params->tcp_rates[0] == 0) {
 | |
|                 params->tcp_rates[n] = max_rate;
 | |
|             } else {
 | |
|                 rate = ((float)(components * im->xsize * im->ysize * 8)
 | |
|                         / (params->tcp_rates[n] * 8));
 | |
|                 if (rate > CINEMA_24_CS_LENGTH)
 | |
|                     params->tcp_rates[n] = max_rate;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         params->max_comp_size = COMP_24_CS_MAX_LENGTH;
 | |
|     } else {
 | |
|         float max_rate = ((float)(components * im->xsize * im->ysize * 8)
 | |
|                           / (CINEMA_48_CS_LENGTH * 8));
 | |
| 
 | |
|         for (n = 0; n < params->tcp_numlayers; ++n) {
 | |
|             rate = 0;
 | |
|             if (params->tcp_rates[0] == 0) {
 | |
|                 params->tcp_rates[n] = max_rate;
 | |
|             } else {
 | |
|                 rate = ((float)(components * im->xsize * im->ysize * 8)
 | |
|                         / (params->tcp_rates[n] * 8));
 | |
|                 if (rate > CINEMA_48_CS_LENGTH)
 | |
|                     params->tcp_rates[n] = max_rate;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         params->max_comp_size = COMP_48_CS_MAX_LENGTH;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int
 | |
| j2k_encode_entry(Imaging im, ImagingCodecState state)
 | |
| {
 | |
|     JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
 | |
|     opj_stream_t *stream = NULL;
 | |
|     opj_image_t *image = NULL;
 | |
|     opj_codec_t *codec = NULL;
 | |
|     opj_cparameters_t params;
 | |
|     unsigned components;
 | |
|     OPJ_COLOR_SPACE color_space;
 | |
|     opj_image_cmptparm_t image_params[4];
 | |
|     unsigned xsiz, ysiz;
 | |
|     unsigned tile_width, tile_height;
 | |
|     unsigned tiles_x, tiles_y;
 | |
|     unsigned x, y, tile_ndx;
 | |
|     unsigned n;
 | |
|     j2k_pack_tile_t pack;
 | |
|     int ret = -1;
 | |
| 
 | |
|     unsigned prec = 8;
 | |
|     unsigned bpp = 8;
 | |
|     unsigned _overflow_scale_factor;
 | |
| 
 | |
|     stream = opj_stream_create(BUFFER_SIZE, OPJ_FALSE);
 | |
| 
 | |
|     if (!stream) {
 | |
|         state->errcode = IMAGING_CODEC_BROKEN;
 | |
|         state->state = J2K_STATE_FAILED;
 | |
|         goto quick_exit;
 | |
|     }
 | |
| 
 | |
|     opj_stream_set_write_function(stream, j2k_write);
 | |
|     opj_stream_set_skip_function(stream, j2k_skip);
 | |
|     opj_stream_set_seek_function(stream, j2k_seek);
 | |
| 
 | |
|     /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
 | |
| #ifndef OPJ_VERSION_MAJOR
 | |
|     opj_stream_set_user_data(stream, state);
 | |
| #else
 | |
|     opj_stream_set_user_data(stream, state, NULL);
 | |
| #endif
 | |
| 
 | |
|     /* Setup an opj_image */
 | |
|     if (strcmp (im->mode, "L") == 0) {
 | |
|         components = 1;
 | |
|         color_space = OPJ_CLRSPC_GRAY;
 | |
|         pack = j2k_pack_l;
 | |
|     } else if (strcmp (im->mode, "I;16") == 0){
 | |
|         components = 1;
 | |
|         color_space = OPJ_CLRSPC_GRAY;
 | |
|         pack = j2k_pack_i16;
 | |
|         prec = 16;
 | |
|         bpp = 12;
 | |
|     } else if (strcmp (im->mode, "I;16B") == 0){
 | |
|         components = 1;
 | |
|         color_space = OPJ_CLRSPC_GRAY;
 | |
|         pack = j2k_pack_i16;
 | |
|         prec = 16;
 | |
|         bpp = 12;
 | |
|     } else if (strcmp (im->mode, "LA") == 0) {
 | |
|         components = 2;
 | |
|         color_space = OPJ_CLRSPC_GRAY;
 | |
|         pack = j2k_pack_la;
 | |
|     } else if (strcmp (im->mode, "RGB") == 0) {
 | |
|         components = 3;
 | |
|         color_space = OPJ_CLRSPC_SRGB;
 | |
|         pack = j2k_pack_rgb;
 | |
|     } else if (strcmp (im->mode, "YCbCr") == 0) {
 | |
|         components = 3;
 | |
|         color_space = OPJ_CLRSPC_SYCC;
 | |
|         pack = j2k_pack_rgb;
 | |
|     } else if (strcmp (im->mode, "RGBA") == 0) {
 | |
|         components = 4;
 | |
|         color_space = OPJ_CLRSPC_SRGB;
 | |
|         pack = j2k_pack_rgba;
 | |
|     } else {
 | |
|         state->errcode = IMAGING_CODEC_BROKEN;
 | |
|         state->state = J2K_STATE_FAILED;
 | |
|         goto quick_exit;
 | |
|     }
 | |
| 
 | |
|     for (n = 0; n < components; ++n) {
 | |
|         image_params[n].dx = image_params[n].dy = 1;
 | |
|         image_params[n].w = im->xsize;
 | |
|         image_params[n].h = im->ysize;
 | |
|         image_params[n].x0 = image_params[n].y0 = 0;
 | |
|         image_params[n].prec = prec;
 | |
|         image_params[n].bpp = bpp;
 | |
|         image_params[n].sgnd = 0;
 | |
|     }
 | |
| 
 | |
|     image = opj_image_create(components, image_params, color_space);
 | |
|     if (!image) {
 | |
|         state->errcode = IMAGING_CODEC_BROKEN;
 | |
|         state->state = J2K_STATE_FAILED;
 | |
|         goto quick_exit;
 | |
|     }
 | |
| 
 | |
|     /* Setup compression context */
 | |
|     context->error_msg = NULL;
 | |
| 
 | |
|     opj_set_default_encoder_parameters(¶ms);
 | |
| 
 | |
|     params.image_offset_x0 = context->offset_x;
 | |
|     params.image_offset_y0 = context->offset_y;
 | |
| 
 | |
|     if (context->tile_size_x && context->tile_size_y) {
 | |
|         params.tile_size_on = OPJ_TRUE;
 | |
|         params.cp_tx0 = context->tile_offset_x;
 | |
|         params.cp_ty0 = context->tile_offset_y;
 | |
|         params.cp_tdx = context->tile_size_x;
 | |
|         params.cp_tdy = context->tile_size_y;
 | |
| 
 | |
|         tile_width = params.cp_tdx;
 | |
|         tile_height = params.cp_tdy;
 | |
|     } else {
 | |
|         params.cp_tx0 = 0;
 | |
|         params.cp_ty0 = 0;
 | |
|         params.cp_tdx = 1;
 | |
|         params.cp_tdy = 1;
 | |
| 
 | |
|         tile_width = im->xsize;
 | |
|         tile_height = im->ysize;
 | |
|     }
 | |
| 
 | |
|     if (context->quality_layers && PySequence_Check(context->quality_layers)) {
 | |
|         Py_ssize_t len = PySequence_Length(context->quality_layers);
 | |
|         Py_ssize_t n;
 | |
|         float *pq;
 | |
| 
 | |
|         if (len) {
 | |
|             if (len > sizeof(params.tcp_rates) / sizeof(params.tcp_rates[0]))
 | |
|                 len = sizeof(params.tcp_rates)/sizeof(params.tcp_rates[0]);
 | |
| 
 | |
|             params.tcp_numlayers = (int)len;
 | |
| 
 | |
|             if (context->quality_is_in_db) {
 | |
|                 params.cp_disto_alloc = params.cp_fixed_alloc = 0;
 | |
|                 params.cp_fixed_quality = 1;
 | |
|                 pq = params.tcp_distoratio;
 | |
|             } else {
 | |
|                 params.cp_disto_alloc = 1;
 | |
|                 params.cp_fixed_alloc = params.cp_fixed_quality = 0;
 | |
|                 pq = params.tcp_rates;
 | |
|             }
 | |
| 
 | |
|             for (n = 0; n < len; ++n) {
 | |
|                 PyObject *obj = PySequence_ITEM(context->quality_layers, n);
 | |
|                 pq[n] = PyFloat_AsDouble(obj);
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         params.tcp_numlayers = 1;
 | |
|         params.tcp_rates[0] = 0;
 | |
|         params.cp_disto_alloc = 1;
 | |
|     }
 | |
| 
 | |
|     if (context->num_resolutions)
 | |
|         params.numresolution = context->num_resolutions;
 | |
| 
 | |
|     if (context->cblk_width >= 4 && context->cblk_width <= 1024
 | |
|         && context->cblk_height >= 4 && context->cblk_height <= 1024
 | |
|         && context->cblk_width * context->cblk_height <= 4096) {
 | |
|         params.cblockw_init = context->cblk_width;
 | |
|         params.cblockh_init = context->cblk_height;
 | |
|     }
 | |
| 
 | |
|     if (context->precinct_width >= 4 && context->precinct_height >= 4
 | |
|         && context->precinct_width >= context->cblk_width
 | |
|         && context->precinct_height > context->cblk_height) {
 | |
|         params.prcw_init[0] = context->precinct_width;
 | |
|         params.prch_init[0] = context->precinct_height;
 | |
|         params.res_spec = 1;
 | |
|         params.csty |= 0x01;
 | |
|     }
 | |
| 
 | |
|     params.irreversible = context->irreversible;
 | |
| 
 | |
|     params.prog_order = context->progression;
 | |
| 
 | |
|     params.cp_cinema = context->cinema_mode;
 | |
| 
 | |
|     switch (params.cp_cinema) {
 | |
|     case OPJ_OFF:
 | |
|         params.cp_rsiz = OPJ_STD_RSIZ;
 | |
|         break;
 | |
|     case OPJ_CINEMA2K_24:
 | |
|     case OPJ_CINEMA2K_48:
 | |
|         params.cp_rsiz = OPJ_CINEMA2K;
 | |
|         if (params.numresolution > 6)
 | |
|             params.numresolution = 6;
 | |
|         break;
 | |
|     case OPJ_CINEMA4K_24:
 | |
|         params.cp_rsiz = OPJ_CINEMA4K;
 | |
|         if (params.numresolution > 7)
 | |
|             params.numresolution = 7;
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     if (context->cinema_mode != OPJ_OFF)
 | |
|         j2k_set_cinema_params(im, components, ¶ms);
 | |
| 
 | |
|     /* Set up the reference grid in the image */
 | |
|     image->x0 = params.image_offset_x0;
 | |
|     image->y0 = params.image_offset_y0;
 | |
|     image->x1 = xsiz = im->xsize + params.image_offset_x0;
 | |
|     image->y1 = ysiz = im->ysize + params.image_offset_y0;
 | |
| 
 | |
|     /* Create the compressor */
 | |
|     codec = opj_create_compress(context->format);
 | |
| 
 | |
|     if (!codec) {
 | |
|         state->errcode = IMAGING_CODEC_BROKEN;
 | |
|         state->state = J2K_STATE_FAILED;
 | |
|         goto quick_exit;
 | |
|     }
 | |
| 
 | |
|     opj_set_error_handler(codec, j2k_error, context);
 | |
|     opj_set_info_handler(codec, j2k_warn, context);
 | |
|     opj_set_warning_handler(codec, j2k_warn, context);
 | |
|     opj_setup_encoder(codec, ¶ms, image);
 | |
| 
 | |
|     /* Start encoding */
 | |
|     if (!opj_start_compress(codec, image, stream)) {
 | |
|         state->errcode = IMAGING_CODEC_BROKEN;
 | |
|         state->state = J2K_STATE_FAILED;
 | |
|         goto quick_exit;
 | |
|     }
 | |
| 
 | |
|     /* Write each tile */
 | |
|     tiles_x = (im->xsize + (params.image_offset_x0 - params.cp_tx0)
 | |
|                + tile_width - 1) / tile_width;
 | |
|     tiles_y = (im->ysize + (params.image_offset_y0 - params.cp_ty0)
 | |
|                + tile_height - 1) / tile_height;
 | |
| 
 | |
|     /* check for integer overflow for the malloc line, checking any expression
 | |
|        that may multiply either tile_width or tile_height */
 | |
|     _overflow_scale_factor = components * prec;
 | |
|     if (( tile_width > UINT_MAX / _overflow_scale_factor ) ||
 | |
|         ( tile_height > UINT_MAX / _overflow_scale_factor ) ||
 | |
|         ( tile_width > UINT_MAX / (tile_height * _overflow_scale_factor )) ||
 | |
|         ( tile_height > UINT_MAX / (tile_width * _overflow_scale_factor ))) {
 | |
|         state->errcode = IMAGING_CODEC_BROKEN;
 | |
|         state->state = J2K_STATE_FAILED;
 | |
|         goto quick_exit;
 | |
|     }
 | |
|     /* malloc check ok, checked for overflow above */
 | |
|     state->buffer = malloc (tile_width * tile_height * components * prec / 8);
 | |
|     if (!state->buffer) {
 | |
|         state->errcode = IMAGING_CODEC_BROKEN;
 | |
|         state->state = J2K_STATE_FAILED;
 | |
|         goto quick_exit;
 | |
|     }
 | |
| 
 | |
|     tile_ndx = 0;
 | |
|     for (y = 0; y < tiles_y; ++y) {
 | |
|         unsigned ty0 = params.cp_ty0 + y * tile_height;
 | |
|         unsigned ty1 = ty0 + tile_height;
 | |
|         unsigned pixy, pixh;
 | |
| 
 | |
|         if (ty0 < params.image_offset_y0)
 | |
|             ty0 = params.image_offset_y0;
 | |
|         if (ty1 > ysiz)
 | |
|             ty1 = ysiz;
 | |
| 
 | |
|         pixy = ty0 - params.image_offset_y0;
 | |
|         pixh = ty1 - ty0;
 | |
| 
 | |
|         for (x = 0; x < tiles_x; ++x) {
 | |
|             unsigned tx0 = params.cp_tx0 + x * tile_width;
 | |
|             unsigned tx1 = tx0 + tile_width;
 | |
|             unsigned pixx, pixw;
 | |
|             unsigned data_size;
 | |
| 
 | |
|             if (tx0 < params.image_offset_x0)
 | |
|                 tx0 = params.image_offset_x0;
 | |
|             if (tx1 > xsiz)
 | |
|                 tx1 = xsiz;
 | |
| 
 | |
|             pixx = tx0 - params.image_offset_x0;
 | |
|             pixw = tx1 - tx0;
 | |
| 
 | |
|             pack(im, state->buffer, pixx, pixy, pixw, pixh);
 | |
| 
 | |
|             data_size = pixw * pixh * components * prec / 8;
 | |
| 
 | |
|             if (!opj_write_tile(codec, tile_ndx++, state->buffer,
 | |
|                                 data_size, stream)) {
 | |
|                 state->errcode = IMAGING_CODEC_BROKEN;
 | |
|                 state->state = J2K_STATE_FAILED;
 | |
|                 goto quick_exit;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!opj_end_compress(codec, stream)) {
 | |
|         state->errcode = IMAGING_CODEC_BROKEN;
 | |
|         state->state = J2K_STATE_FAILED;
 | |
|         goto quick_exit;
 | |
|     }
 | |
| 
 | |
|     state->errcode = IMAGING_CODEC_END;
 | |
|     state->state = J2K_STATE_DONE;
 | |
|     ret = -1;
 | |
| 
 | |
|  quick_exit:
 | |
|     if (codec)
 | |
|         opj_destroy_codec(codec);
 | |
|     if (image)
 | |
|         opj_image_destroy(image);
 | |
|     if (stream)
 | |
|         opj_stream_destroy(stream);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int
 | |
| ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes)
 | |
| {
 | |
|     if (state->state == J2K_STATE_FAILED)
 | |
|         return -1;
 | |
| 
 | |
|     if (state->state == J2K_STATE_START) {
 | |
| 
 | |
|         state->state = J2K_STATE_ENCODING;
 | |
| 
 | |
|         return j2k_encode_entry(im, state);
 | |
|     }
 | |
| 
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| /* -------------------------------------------------------------------- */
 | |
| /* Cleanup                                                              */
 | |
| /* -------------------------------------------------------------------- */
 | |
| 
 | |
| int
 | |
| ImagingJpeg2KEncodeCleanup(ImagingCodecState state) {
 | |
|     JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
 | |
| 
 | |
|     if (context->quality_layers) {
 | |
|         Py_XDECREF(context->quality_layers);
 | |
|         context->quality_layers = NULL;
 | |
|     }
 | |
| 
 | |
|     if (context->error_msg)
 | |
|         free ((void *)context->error_msg);
 | |
| 
 | |
|     context->error_msg = NULL;
 | |
| 
 | |
| 
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| #endif /* HAVE_OPENJPEG */
 | |
| 
 | |
| /*
 | |
|  * Local Variables:
 | |
|  * c-basic-offset: 4
 | |
|  * End:
 | |
|  *
 | |
|  */
 |