#include "jpeg.hpp"
template <class T> void JpegErrorMgr<T>::error_exit(j_common_ptr cinfo) {
ctx_t* ctx = (ctx_t*)cinfo->err;
static char msg[JMSG_LENGTH_MAX];
(*(cinfo->err->format_message))(cinfo, msg);
LOG("%s", msg);
longjmp(ctx->setjmp_buffer, 1);
}
template <class T> bool JpegErrorMgr<T>::handle(handler_t handler, void* handler_ctx) {
ctx_t ctx;
T cinfo;
cinfo.err = jpeg_std_error(&ctx.pub);
ctx.pub.error_exit = &error_exit;
bool rv;
if (setjmp(ctx.setjmp_buffer) == 0) {
jpeg_create(&cinfo);
rv = handler(cinfo, handler_ctx) && !ctx.pub.num_warnings;
jpeg_destroy(&cinfo);
} else {
jpeg_destroy(&cinfo);
rv = false;
}
return rv;
}
bool JpegImage::jpeg_read(jpeg_decompress_struct& cinfo, void* _args) {
args_t* args = (args_t*)_args;
if (!args->fp) return false;
jpeg_stdio_src(&cinfo, args->fp);
(void)jpeg_read_header(&cinfo, TRUE);
(void)jpeg_start_decompress(&cinfo);
if (cinfo.output_components != 3) {
return false;
}
args->im.in = new Image(cinfo.output_width, cinfo.output_height);
while (cinfo.output_scanline < cinfo.output_height) {
JSAMPROW buffer = args->im.in->buf.at(cinfo.output_scanline);
(void)jpeg_read_scanlines(&cinfo, &buffer, 1);
}
(void)jpeg_finish_decompress(&cinfo);
return true;
}
bool JpegImage::jpeg_write(jpeg_compress_struct& cinfo, void* _args) {
args_t* args = (args_t*)_args;
if (!args->fp) return false;
jpeg_stdio_dest(&cinfo, args->fp);
cinfo.image_width = args->im.out->buf.w;
cinfo.image_height = args->im.out->buf.h;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 100, TRUE);
jpeg_start_compress(&cinfo, TRUE);
JSAMPROW row_pointer[1];
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = (unsigned char*)args->im.out->buf.at(cinfo.next_scanline); // const cast
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
return true;
}
Image* JpegImage::in(const char* fn) {
args_t args;
args.im.in = NULL;
args.fp = fopen(fn, "rb");
if (!args.fp) {
LOG("Cannot open '%s'", fn);
return NULL;
}
if (!JpegErrorMgr<jpeg_decompress_struct>::handle(&jpeg_read, &args)) {
LOG("Cannot read '%s'", fn);
if (args.im.in) {
delete args.im.in;
args.im.in = NULL;
}
} else {
LOG("Loaded '%s'", fn);
}
fclose(args.fp);
return args.im.in;
}
bool JpegImage::out(const char* fn, const Image* im) {
args_t args;
args.im.out = im;
args.fp = fopen(fn, "wb");
if (!args.fp) {
LOG("Cannot open '%s'", fn);
return false;
}
if (!JpegErrorMgr<jpeg_compress_struct>::handle(&jpeg_write, &args)) {
LOG("Cannot write '%s'", fn);
fclose(args.fp);
return false;
} else {
LOG("Wrote '%s'", fn);
fclose(args.fp);
return true;
}
}