int GP_ReadJP2Ex(GP_IO *io, GP_Context **rimg, GP_DataStorage *storage, GP_ProgressCallback *callback) { opj_dparameters_t params; opj_codec_t *codec; opj_stream_t *stream; opj_image_t *img; GP_PixelType pixel_type; GP_Context *res = NULL; unsigned int i, x, y; int err = 0, ret = 1; opj_set_default_decoder_parameters(¶ms); codec = opj_create_decompress(OPJ_CODEC_JP2); if (!codec) { GP_DEBUG(1, "opj_create_decompress failed"); err = ENOMEM; goto err0; } opj_set_error_handler(codec, jp2_err_callback, NULL); opj_set_warning_handler(codec, jp2_warn_callback, NULL); opj_set_info_handler(codec, jp2_info_callback, callback); if (!opj_setup_decoder(codec, ¶ms)) { GP_DEBUG(1, "opj_setup_decoder failed"); err = ENOMEM; goto err1; } stream = opj_stream_default_create(OPJ_TRUE); if (!stream) { GP_DEBUG(1, "opj_stream_create_default_file_stream faled"); err = ENOMEM; goto err1; } //TODO: Do we need seek and skip? opj_stream_set_read_function(stream, jp2_io_read); opj_stream_set_user_data(stream, io); if (!opj_read_header(stream, codec, &img)) { GP_DEBUG(1, "opj_read_header failed"); err = EINVAL; goto err2; } if (storage) fill_metadata(img, storage); GP_DEBUG(1, "Have image %ux%u-%ux%u colorspace=%s numcomps=%u", img->x0, img->y0, img->x1, img->y1, color_space_name(img->color_space), img->numcomps); if (!rimg) return 0; /* * Try to match the image information into pixel type. * * Unfortunately the images I had have color_space set * to unspecified yet they were RGB888. */ for (i = 0; i < img->numcomps; i++) { opj_image_comp_t *comp = &img->comps[i]; GP_DEBUG(2, "Component %u %ux%u bpp=%u", i, comp->w, comp->h, comp->prec); if (comp->w != img->comps[0].w || comp->h != img->comps[0].h) { GP_DEBUG(1, "Component %u has different size", 1); err = ENOSYS; goto err3; } if (comp->prec != 8) { GP_DEBUG(1, "Component %u has different bpp", 1); err = ENOSYS; goto err3; } } switch (img->color_space) { case OPJ_CLRSPC_UNSPECIFIED: if (img->numcomps != 3) { GP_DEBUG(1, "Unexpected number of components"); err = ENOSYS; goto err3; } pixel_type = GP_PIXEL_RGB888; break; default: GP_DEBUG(1, "Unsupported colorspace"); err = ENOSYS; goto err3; } GP_ProgressCallbackReport(callback, 0, 100, 100); if (!opj_decode(codec, stream, img)) { GP_DEBUG(1, "opj_decode failed"); err = EINVAL; goto err3; } res = GP_ContextAlloc(img->comps[0].w, img->comps[0].h, pixel_type); if (!res) { GP_DEBUG(1, "Malloc failed :("); err = ENOMEM; goto err3; } for (y = 0; y < res->h; y++) { for (x = 0; x < res->w; x++) { i = y * res->w + x; GP_Pixel p = img->comps[0].data[i] << 16| img->comps[1].data[i] << 8 | img->comps[2].data[i]; GP_PutPixel_Raw_24BPP(res, x, y, p); } } GP_ProgressCallbackDone(callback); *rimg = res; ret = 0; err3: opj_image_destroy(img); err2: opj_stream_destroy(stream); err1: opj_destroy_codec(codec); err0: if (err) errno = err; return ret; }
bool ossim::opj_decode( std::ifstream* in, const ossimIrect& rect, ossim_uint32 resLevel, ossim_int32 format, // OPJ_CODEC_FORMAT std::streamoff fileOffset, ossimImageData* tile) { static const char MODULE[] = "ossimOpjDecoder::decode"; bool status = false; if ( traceDebug() ) { ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << "entered...\nrect: " << rect << "\nresLevel: " << resLevel << std::endl; } // Need to check for NAN in rect if ( in && tile && !rect.hasNans()) { in->seekg( fileOffset, std::ios_base::beg ); opj_dparameters_t param; opj_codec_t* codec = 0; opj_image_t* image = 0;; opj_stream_t* stream = 0; opj_user_istream* userStream = new opj_user_istream(); userStream->m_str = in; userStream->m_offset = fileOffset; /* Set the length to avoid an assert */ in->seekg(0, std::ios_base::end); // Fix: length must be passed in for nift blocks. userStream->m_length = in->tellg(); // Set back to front: in->clear(); in->seekg(fileOffset, std::ios_base::beg); stream = opj_stream_default_create(OPJ_TRUE); if (!stream) { opj_stream_destroy(stream); std::string errMsg = MODULE; errMsg += " ERROR: opj_setup_decoder failed!"; throw ossimException(errMsg); } opj_stream_set_read_function(stream, ossim_opj_istream_read); opj_stream_set_skip_function(stream, ossim_opj_istream_skip); opj_stream_set_seek_function(stream, ossim_opj_istream_seek); // Fix: length must be passed in for nift blocks. opj_stream_set_user_data_length(stream, userStream->m_length); opj_stream_set_user_data(stream, userStream, ossim_opj_free_user_istream_data); opj_stream_set_user_data_length(stream, userStream->m_length); /* Set the default decoding parameters */ opj_set_default_decoder_parameters(¶m); param.decod_format = format; /** you may here add custom decoding parameters */ /* do not use layer decoding limitations */ param.cp_layer = 0; /* do not use resolutions reductions */ param.cp_reduce = resLevel; codec = opj_create_decompress( (CODEC_FORMAT)format ); // catch events using our callbacks and give a local context //opj_set_info_handler (codec, ossim::opj_info_callback, 00); opj_set_info_handler (codec, NULL, 00); opj_set_warning_handler(codec, ossim::opj_warning_callback,00); opj_set_error_handler (codec, ossim::opj_error_callback, 00); // Setup the decoder decoding parameters using user parameters if ( opj_setup_decoder(codec, ¶m) == false ) { opj_stream_destroy(stream); opj_destroy_codec(codec); std::string errMsg = MODULE; errMsg += " ERROR: opj_setup_decoder failed!"; throw ossimException(errMsg); } // Read the main header of the codestream and if necessary the JP2 boxes. if ( opj_read_header(stream, codec, &image) == false ) { opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(image); std::string errMsg = MODULE; errMsg += " ERROR: opj_read_header failed!"; throw ossimException(errMsg); } // tmp drb: // opj_stream_destroy(stream); // return; if ( opj_set_decoded_resolution_factor(codec, resLevel) == false) { opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(image); std::string errMsg = MODULE; errMsg += " ERROR: opj_set_decoded_resolution_factor failed!"; throw ossimException(errMsg); } //ossim_float32 res = resLevel; ossimIrect resRect = rect * (1 << resLevel); //std::cout << "resRect.ul(): " << resRect.ul() // << "\nresRect.lr(): " << resRect.lr() // << std::endl; // if ( opj_set_decode_area(codec, image, rect.ul().x, rect.ul().y, // rect.lr().x+1, rect.lr().y+1) == false ) if ( opj_set_decode_area(codec, image, resRect.ul().x, resRect.ul().y, resRect.lr().x+1, resRect.lr().y+1) == false ) { opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(image); std::string errMsg = MODULE; errMsg += " ERROR: opj_set_decode_area failed!"; throw ossimException(errMsg); } // Get the decoded image: if ( opj_decode(codec, stream, image) == false ) { opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(image); std::string errMsg = MODULE; errMsg += " ERROR: opj_decode failed!"; throw ossimException(errMsg); } // ossim::print(std::cout, *image); if(image->icc_profile_buf) { #if defined(OPJ_HAVE_LIBLCMS1) || defined(OPJ_HAVE_LIBLCMS2) color_apply_icc_profile(image); /* FIXME */ #endif free(image->icc_profile_buf); image->icc_profile_buf = NULL; image->icc_profile_len = 0; } status = ossim::copyOpjImage(image, tile); #if 0 ossim_uint32 tile_index = 0; ossim_uint32 data_size = 0; ossim_int32 current_tile_x0 = 0; ossim_int32 current_tile_y0 = 0; ossim_int32 current_tile_x1 = 0; ossim_int32 current_tile_y1 = 0; ossim_uint32 nb_comps = 0; OPJ_BOOL go_on = 1; if ( opj_read_tile_header( codec, stream, &tile_index, &data_size, ¤t_tile_x0, ¤t_tile_y0, ¤t_tile_x1, ¤t_tile_y1, &nb_comps, &go_on) == false ) { opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(image); std::string errMsg = MODULE; errMsg += " ERROR: opj_read_tile_header failed!"; throw ossimException(errMsg); } #endif #if 0 std::cout << "tile_index: " << tile_index << "\ndata_size: " << data_size << "\ncurrent_tile_x0: " << current_tile_x0 << "\ncurrent_tile_y0: " << current_tile_y0 << "\ncurrent_tile_x1: " << current_tile_x1 << "\ncurrent_tile_y1: " << current_tile_y1 << "\nnb_comps: " << nb_comps << std::endl; #endif #if 0 if ( opj_decode_tile_data(codec, tile_index,l_data,l_data_size,l_stream) == false) { opj_stream_destroy(l_stream); opj_destroy_codec(l_codec); opj_image_destroy(l_image); std::string errMsg = MODULE; errMsg += " ERROR: opj_read_tile_header failed!"; throw ossimException(errMsg); } #endif #if 0 if (opj_end_decompress(codec,stream) == false ) { opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(image); std::string errMsg = MODULE; errMsg += " ERROR: opj_end_decompress failed!"; throw ossimException(errMsg); } #endif /* Free memory */ opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(image); // Tmp drb: if ( in->eof() ) { in->clear(); } in->seekg(fileOffset, std::ios_base::beg ); } // Matches: if ( in && tile ) return status; } // End: ossim::opj_decode( ... )
static int j2k_encode_entry(Imaging im, ImagingCodecState state, ImagingIncrementalCodec encoder) { 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, num_tiles; unsigned x, y, tile_ndx; unsigned n; j2k_pack_tile_t pack; int ret = -1; stream = opj_stream_default_create(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); opj_stream_set_user_data(stream, encoder); /* 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, "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 = 8; image_params[n].bpp = 8; image_params[n].sgnd = 0; } image = opj_image_create(components, image_params, color_space); /* 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_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; num_tiles = tiles_x * tiles_y; state->buffer = malloc (tile_width * tile_height * components); 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; 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 = (int)ImagingIncrementalCodecBytesInBuffer(encoder); quick_exit: if (codec) opj_destroy_codec(codec); if (image) opj_image_destroy(image); if (stream) opj_stream_destroy(stream); return ret; }
fz_pixmap * fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *defcs, int indexed) { fz_pixmap *img; fz_colorspace *origcs; opj_dparameters_t params; opj_codec_t *codec; opj_image_t *jpx; opj_stream_t *stream; fz_colorspace *colorspace; unsigned char *p; OPJ_CODEC_FORMAT format; int a, n, w, h, depth, sgnd; int x, y, k, v; stream_block sb; if (size < 2) fz_throw(ctx, FZ_ERROR_GENERIC, "not enough data to determine image format"); /* Check for SOC marker -- if found we have a bare J2K stream */ if (data[0] == 0xFF && data[1] == 0x4F) format = OPJ_CODEC_J2K; else format = OPJ_CODEC_JP2; opj_set_default_decoder_parameters(¶ms); if (indexed) params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; codec = opj_create_decompress(format); opj_set_info_handler(codec, fz_opj_info_callback, ctx); opj_set_warning_handler(codec, fz_opj_warning_callback, ctx); opj_set_error_handler(codec, fz_opj_error_callback, ctx); if (!opj_setup_decoder(codec, ¶ms)) { fz_throw(ctx, FZ_ERROR_GENERIC, "j2k decode failed"); } stream = opj_stream_default_create(OPJ_TRUE); sb.data = data; sb.pos = 0; sb.size = size; opj_stream_set_read_function(stream, fz_opj_stream_read); opj_stream_set_skip_function(stream, fz_opj_stream_skip); opj_stream_set_seek_function(stream, fz_opj_stream_seek); opj_stream_set_user_data(stream, &sb); /* Set the length to avoid an assert */ opj_stream_set_user_data_length(stream, size); if (!opj_read_header(stream, codec, &jpx)) { opj_stream_destroy(stream); opj_destroy_codec(codec); fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to read JPX header"); } if (!opj_decode(codec, stream, jpx)) { opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to decode JPX image"); } opj_stream_destroy(stream); opj_destroy_codec(codec); /* jpx should never be NULL here, but check anyway */ if (!jpx) fz_throw(ctx, FZ_ERROR_GENERIC, "opj_decode failed"); for (k = 1; k < (int)jpx->numcomps; k++) { if (!jpx->comps[k].data) { opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "image components are missing data"); } if (jpx->comps[k].w != jpx->comps[0].w) { opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different width"); } if (jpx->comps[k].h != jpx->comps[0].h) { opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different height"); } if (jpx->comps[k].prec != jpx->comps[0].prec) { opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different precision"); } } n = jpx->numcomps; w = jpx->comps[0].w; h = jpx->comps[0].h; depth = jpx->comps[0].prec; sgnd = jpx->comps[0].sgnd; if (jpx->color_space == OPJ_CLRSPC_SRGB && n == 4) { n = 3; a = 1; } else if (jpx->color_space == OPJ_CLRSPC_SYCC && n == 4) { n = 3; a = 1; } else if (n == 2) { n = 1; a = 1; } else if (n > 4) { n = 4; a = 1; } else { a = 0; } origcs = defcs; if (defcs) { if (defcs->n == n) { colorspace = defcs; } else { fz_warn(ctx, "jpx file and dict colorspaces do not match"); defcs = NULL; } } if (!defcs) { switch (n) { case 1: colorspace = fz_device_gray(ctx); break; case 3: colorspace = fz_device_rgb(ctx); break; case 4: colorspace = fz_device_cmyk(ctx); break; } } fz_try(ctx) { img = fz_new_pixmap(ctx, colorspace, w, h); } fz_catch(ctx) { opj_image_destroy(jpx); fz_rethrow_message(ctx, "out of memory loading jpx"); } p = img->samples; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { for (k = 0; k < n + a; k++) { v = jpx->comps[k].data[y * w + x]; if (sgnd) v = v + (1 << (depth - 1)); if (depth > 8) v = v >> (depth - 8); *p++ = v; } if (!a) *p++ = 255; } } opj_image_destroy(jpx); if (a) { if (n == 4) { fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb(ctx), w, h); fz_convert_pixmap(ctx, tmp, img); fz_drop_pixmap(ctx, img); img = tmp; } fz_premultiply_pixmap(ctx, img); } if (origcs != defcs) { fz_pixmap *tmp = fz_new_pixmap(ctx, origcs, w, h); fz_convert_pixmap(ctx, tmp, img); fz_drop_pixmap(ctx, img); img = tmp; } return img; }