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; }
int GP_ReadJPGEx(GP_IO *io, GP_Context **img, GP_DataStorage *storage, GP_ProgressCallback *callback) { struct jpeg_decompress_struct cinfo; struct my_source_mgr src; struct my_jpg_err my_err; GP_Context *ret = NULL; uint8_t buf[1024]; int err; cinfo.err = jpeg_std_error(&my_err.error_mgr); my_err.error_mgr.error_exit = my_error_exit; if (setjmp(my_err.setjmp_buf)) { err = EIO; goto err2; } jpeg_create_decompress(&cinfo); init_source_mgr(&src, io, buf, sizeof(buf)); cinfo.src = (void*)&src; if (storage) save_jpg_markers(&cinfo); jpeg_read_header(&cinfo, TRUE); GP_DEBUG(1, "Have %s JPEG size %ux%u %i channels", get_colorspace(cinfo.jpeg_color_space), cinfo.image_width, cinfo.image_height, cinfo.num_components); //TODO: Propagate failure? if (storage) read_jpg_metadata(&cinfo, storage); if (!img) goto exit; GP_Pixel pixel_type; switch (cinfo.out_color_space) { case JCS_GRAYSCALE: pixel_type = GP_PIXEL_G8; break; case JCS_RGB: pixel_type = GP_PIXEL_BGR888; break; case JCS_CMYK: pixel_type = GP_PIXEL_CMYK8888; break; default: pixel_type = GP_PIXEL_UNKNOWN; } if (pixel_type == GP_PIXEL_UNKNOWN) { GP_DEBUG(1, "Can't handle %s JPEG output format", get_colorspace(cinfo.out_color_space)); err = ENOSYS; goto err1; } ret = GP_ContextAlloc(cinfo.image_width, cinfo.image_height, pixel_type); if (ret == NULL) { GP_DEBUG(1, "Malloc failed :("); err = ENOMEM; goto err1; } jpeg_start_decompress(&cinfo); switch (pixel_type) { case GP_PIXEL_BGR888: case GP_PIXEL_G8: err = load(&cinfo, ret, callback); break; case GP_PIXEL_CMYK8888: err = load_cmyk(&cinfo, ret, callback); break; default: err = EINVAL; } if (err) goto err2; jpeg_finish_decompress(&cinfo); exit: jpeg_destroy_decompress(&cinfo); GP_ProgressCallbackDone(callback); if (img) *img = ret; return 0; err2: GP_ContextFree(ret); err1: jpeg_destroy_decompress(&cinfo); errno = err; return 1; }
int GP_WriteJPG(const GP_Context *src, GP_IO *io, GP_ProgressCallback *callback) { struct jpeg_compress_struct cinfo; GP_PixelType out_pix; struct my_jpg_err my_err; struct my_dest_mgr dst; uint8_t buf[1024]; int err; GP_DEBUG(1, "Writing JPG Image to I/O (%p)", io); out_pix = GP_LineConvertible(src->pixel_type, out_pixel_types); if (out_pix == GP_PIXEL_UNKNOWN) { GP_DEBUG(1, "Unsupported pixel type %s", GP_PixelTypeName(src->pixel_type)); errno = ENOSYS; return 1; } if (setjmp(my_err.setjmp_buf)) { errno = EIO; return 1; } cinfo.err = jpeg_std_error(&my_err.error_mgr); my_err.error_mgr.error_exit = my_error_exit; jpeg_create_compress(&cinfo); init_dest_mgr(&dst, io, buf, sizeof(buf)); cinfo.dest = (void*)&dst; cinfo.image_width = src->w; cinfo.image_height = src->h; switch (out_pix) { case GP_PIXEL_BGR888: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; break; case GP_PIXEL_G8: cinfo.input_components = 1; cinfo.in_color_space = JCS_GRAYSCALE; break; default: GP_BUG("Don't know how to set color_space and compoments"); } jpeg_set_defaults(&cinfo); jpeg_start_compress(&cinfo, TRUE); if (out_pix != src->pixel_type) err = save_convert(&cinfo, src, out_pix, callback); else err = save(&cinfo, src, callback); if (err) { jpeg_destroy_compress(&cinfo); errno = err; return 1; } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); GP_ProgressCallbackDone(callback); return 0; }
int GP_FilterGaussianBlur_Raw(const GP_Context *src, GP_Coord x_src, GP_Coord y_src, GP_Size w_src, GP_Size h_src, GP_Context *dst, GP_Coord x_dst, GP_Coord y_dst, float sigma_x, float sigma_y, GP_ProgressCallback *callback) { unsigned int size_x = gaussian_kernel_size(sigma_x); unsigned int size_y = gaussian_kernel_size(sigma_y); GP_DEBUG(1, "Gaussian blur sigma_x=%2.3f sigma_y=%2.3f kernel %ix%i image %ux%u", sigma_x, sigma_y, size_x, size_y, w_src, h_src); GP_ProgressCallback *new_callback = NULL; GP_ProgressCallback gaussian_callback = { .callback = gaussian_callback_horiz, .priv = callback }; if (callback != NULL) new_callback = &gaussian_callback; /* compute kernel and apply in horizontal direction */ if (sigma_x > 0) { float kernel_x[size_x]; float sum = gaussian_kernel_init(sigma_x, kernel_x); GP_ConvolutionParams params = { .src = src, .x_src = x_src, .y_src = y_src, .w_src = w_src, .h_src = h_src, .dst = dst, .x_dst = x_dst, .y_dst = y_dst, .kernel = kernel_x, .kw = size_x, .kh = 1, .kern_div = sum, .callback = new_callback, }; if (GP_FilterHConvolutionMP_Raw(¶ms)) return 1; } if (new_callback != NULL) new_callback->callback = gaussian_callback_vert; /* compute kernel and apply in vertical direction */ if (sigma_y > 0) { float kernel_y[size_y]; float sum = gaussian_kernel_init(sigma_y, kernel_y); GP_ConvolutionParams params = { .src = src, .x_src = x_src, .y_src = y_src, .w_src = w_src, .h_src = h_src, .dst = dst, .x_dst = x_dst, .y_dst = y_dst, .kernel = kernel_y, .kw = 1, .kh = size_y, .kern_div = sum, .callback = new_callback, }; if (GP_FilterVConvolutionMP_Raw(¶ms)) return 1; } GP_ProgressCallbackDone(callback); return 0; }