Code to convert to jpeg using libjpeg (RGB for now)

1,362 views
Skip to first unread message

Christopher Layne

unread,
May 11, 2008, 12:26:38 AM5/11/08
to OpenJPEG
The following is code to convert an openjpeg opj_image_t to jpeg using
libjpeg (jpeg-6b). Currently it supports RGB and compression only but
augmenting that should be fairly straightforward.

The jpeg error interface has been overridden so as not to issue an
immediate exit() on error - as has the destination manager (it writes
to memory rather than a stdio stream as libjpeg offers by default).
This is why all the callbacks are present.

Just pass a char **, size_t *, and opj_image_t * to imagetojpeg()
which will allocate space for jpeg output and set the passed buf
and sz to the allocated space and size thereof respectively. Caller
is responsible for free()ing.

-cl

--
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <openjpeg.h>
#include <jpeglib.h>

/* Override my own error checking functions */
#define ec_malloc malloc
#define ec_calloc calloc
#define ec_realloc realloc

struct imagetojpeg_err {
struct jpeg_error_mgr jerr;
int ret;
};

static void imagetojpeg_err_exit(j_common_ptr cinfo)
{
struct imagetojpeg_err *err = (void *)cinfo->err;

err->ret = -1;

return;
}

static void imagetojpeg_err_output(j_common_ptr cinfo)
{
(void) cinfo;
return;
}

static void imagetojpeg_err_emit(j_common_ptr cinfo, int level)
{
(void) cinfo, (void) level;
return;
}

static void imagetojpeg_err_format(j_common_ptr cinfo, char *buf)
{
(void) cinfo, (void) buf;
return;
}

static void imagetojpeg_err_reset(j_common_ptr cinfo)
{
(void) cinfo;
return;
}

static void imagetojpeg_err_set(j_compress_ptr cinfo, struct
imagetojpeg_err *err)
{
memset(err, 0, sizeof *err);
err->jerr.error_exit = imagetojpeg_err_exit;
err->jerr.emit_message = imagetojpeg_err_emit;
err->jerr.output_message = imagetojpeg_err_output;
err->jerr.format_message = imagetojpeg_err_format;
err->jerr.reset_error_mgr = imagetojpeg_err_reset;
cinfo->err = (void *)err;

return;
}

struct imagetojpeg_dst {
struct jpeg_destination_mgr jdst;
JOCTET *buf;
JOCTET *off;
size_t sz;
size_t used;
};

static void imagetojpeg_dst_init(j_compress_ptr cinfo)
{
struct imagetojpeg_dst *dst = (void *)cinfo->dest;

dst->used = 0;
dst->sz = cinfo->image_width
* cinfo->image_height
* cinfo->input_components / 8; /* 1/8th of raw size
*/
dst->buf = ec_malloc(dst->sz * sizeof *dst->buf);
dst->off = dst->buf;
dst->jdst.next_output_byte = dst->off;
dst->jdst.free_in_buffer = dst->sz;

return;
}

static boolean imagetojpeg_dst_empty(j_compress_ptr cinfo)
{
struct imagetojpeg_dst *dst = (void *)cinfo->dest;

dst->sz *= 2;
dst->used = dst->off - dst->buf;
dst->buf = ec_realloc(dst->buf, dst->sz * sizeof *dst->buf);
dst->off = dst->buf + dst->used;
dst->jdst.next_output_byte = dst->off;
dst->jdst.free_in_buffer = dst->sz - dst->used;

return TRUE;
}

static void imagetojpeg_dst_term(j_compress_ptr cinfo)
{
struct imagetojpeg_dst *dst = (void *)cinfo->dest;

dst->used += dst->sz - dst->jdst.free_in_buffer;
dst->off = dst->buf + dst->used;

return;
}

static void imagetojpeg_dst_set(j_compress_ptr cinfo, struct
imagetojpeg_dst *dst)
{
dst->jdst.init_destination = imagetojpeg_dst_init;
dst->jdst.empty_output_buffer = imagetojpeg_dst_empty;
dst->jdst.term_destination = imagetojpeg_dst_term;
cinfo->dest = (void *)dst;

return;
}

static int imagetojpeg(char **buf, size_t *szo, opj_image_t *img)
{
size_t w = img->x1 - img->x0;
size_t h = img->y1 - img->y0;
size_t i, c, nc = img->numcomps;
uint8_t *rgbt, *rgbp;
struct jpeg_compress_struct cinfo;
struct imagetojpeg_err err;
struct imagetojpeg_dst dst;
JSAMPROW *rows;

/* this order should not be changed */
imagetojpeg_err_set(&cinfo, &err);
jpeg_create_compress(&cinfo);
if (err.ret != 0)
return -1;
imagetojpeg_dst_set(&cinfo, &dst);
cinfo.image_width = w;
cinfo.image_height = h;
cinfo.input_components = nc;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, TRUE);
if (err.ret != 0) {
jpeg_destroy_compress(&cinfo);
return -1;
}

/*
* src:
* component 0: rrr ...
* component 1: ggg ...
* component 2: bbb ...
*
* dst:
* rgbp = rgbrgbrgbrgb ...
*/

rgbt = rgbp = ec_malloc(w * h * nc);
for (i = 0; i < w * h; i++) {
for (c = 0; c < nc; c++)
*rgbp++ = img->comps[c].data[i];
}
rows = ec_malloc(h * sizeof *rows);
for (i = 0; i < h; i++)
rows[i] = &rgbt[i * w * nc];

if (jpeg_write_scanlines(&cinfo, rows, h) == h && err.ret ==
0)
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
free(rows);
free(rgbt);

*buf = (char *)dst.buf;
*szo = dst.used;

return err.ret;
}
Reply all
Reply to author
Forward
0 new messages