Skip to content

Commit

Permalink
Added a JPEG 2000 encoder.
Browse files Browse the repository at this point in the history
  • Loading branch information
al45tair committed Mar 13, 2014
1 parent aea0ec5 commit 61fb89e
Show file tree
Hide file tree
Showing 10 changed files with 1,004 additions and 208 deletions.
30 changes: 21 additions & 9 deletions PIL/Jpeg2KImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,17 +173,29 @@ def _accept(prefix):
return (prefix[:4] == b'\xff\x4f\xff\x51'
or prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a')

# ------------------------------------------------------------
# Save support

def _save(im, fp, filename):
if filename.endswith('.j2k'):
kind = 'j2k'
else:
kind = 'jp2'

ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)])

# ------------------------------------------------------------
# Registry stuff

Image.register_open("JPEG2000", Jpeg2KImageFile, _accept)
Image.register_open('JPEG2000', Jpeg2KImageFile, _accept)
Image.register_save('JPEG2000', _save)

Image.register_extension("JPEG2000", ".jp2")
Image.register_extension("JPEG2000", ".j2k")
Image.register_extension("JPEG2000", ".jpc")
Image.register_extension("JPEG2000", ".jpf")
Image.register_extension("JPEG2000", ".jpx")
Image.register_extension("JPEG2000", ".j2c")
Image.register_extension('JPEG2000', '.jp2')
Image.register_extension('JPEG2000', '.j2k')
Image.register_extension('JPEG2000', '.jpc')
Image.register_extension('JPEG2000', '.jpf')
Image.register_extension('JPEG2000', '.jpx')
Image.register_extension('JPEG2000', '.j2c')

Image.register_mime("JPEG2000", "image/jp2")
Image.register_mime("JPEG2000", "image/jpx")
Image.register_mime('JPEG2000', 'image/jp2')
Image.register_mime('JPEG2000', 'image/jpx')
2 changes: 2 additions & 0 deletions _imaging.c
Original file line number Diff line number Diff line change
Expand Up @@ -3300,6 +3300,7 @@ extern PyObject* PyImaging_ZipDecoderNew(PyObject* self, PyObject* args);
extern PyObject* PyImaging_EpsEncoderNew(PyObject* self, PyObject* args);
extern PyObject* PyImaging_GifEncoderNew(PyObject* self, PyObject* args);
extern PyObject* PyImaging_JpegEncoderNew(PyObject* self, PyObject* args);
extern PyObject* PyImaging_Jpeg2KEncoderNew(PyObject* self, PyObject* args);
extern PyObject* PyImaging_PcxEncoderNew(PyObject* self, PyObject* args);
extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args);
extern PyObject* PyImaging_XbmEncoderNew(PyObject* self, PyObject* args);
Expand Down Expand Up @@ -3355,6 +3356,7 @@ static PyMethodDef functions[] = {
#endif
#ifdef HAVE_OPENJPEG
{"jpeg2k_decoder", (PyCFunction)PyImaging_Jpeg2KDecoderNew, 1},
{"jpeg2k_encoder", (PyCFunction)PyImaging_Jpeg2KEncoderNew, 1},
#endif
{"tiff_lzw_decoder", (PyCFunction)PyImaging_TiffLzwDecoderNew, 1},
#ifdef HAVE_LIBTIFF
Expand Down
24 changes: 7 additions & 17 deletions decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,27 +778,18 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args)
#endif

/* -------------------------------------------------------------------- */
/* JPEG2000 */
/* JPEG 2000 */
/* -------------------------------------------------------------------- */

#ifdef HAVE_OPENJPEG

/* We better define this decoder last in this file, so the following
undef's won't mess things up for the Imaging library proper. */
#undef UINT8
#undef UINT16
#undef UINT32
#undef INT8
#undef INT16
#undef INT32

#include "Jpeg2K.h"

PyObject*
PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
{
ImagingDecoderObject* decoder;
JPEG2KSTATE *context;
JPEG2KDECODESTATE *context;

char* mode;
char* format;
Expand All @@ -809,26 +800,25 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
&reduce, &layers))
return NULL;

if (strcmp (format, "j2k") == 0)
if (strcmp(format, "j2k") == 0)
codec_format = OPJ_CODEC_J2K;
else if (strcmp (format, "jpt") == 0)
else if (strcmp(format, "jpt") == 0)
codec_format = OPJ_CODEC_JPT;
else if (strcmp (format, "jp2") == 0)
else if (strcmp(format, "jp2") == 0)
codec_format = OPJ_CODEC_JP2;
else
return NULL;

decoder = PyImaging_DecoderNew(sizeof(JPEG2KSTATE));
decoder = PyImaging_DecoderNew(sizeof(JPEG2KDECODESTATE));
if (decoder == NULL)
return NULL;

decoder->handles_eof = 1;
decoder->decode = ImagingJpeg2KDecode;
decoder->cleanup = ImagingJpeg2KDecodeCleanup;

context = (JPEG2KSTATE *)decoder->state.context;
context = (JPEG2KDECODESTATE *)decoder->state.context;

strncpy(context->mode, mode, 8);
context->format = codec_format;
context->reduce = reduce;
context->layers = layers;
Expand Down
135 changes: 135 additions & 0 deletions encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ typedef struct {
PyObject_HEAD
int (*encode)(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes);
int (*cleanup)(ImagingCodecState state);
struct ImagingCodecStateInstance state;
Imaging im;
PyObject* lock;
Expand Down Expand Up @@ -77,6 +78,9 @@ PyImaging_EncoderNew(int contextsize)
/* Initialize encoder context */
encoder->state.context = context;

/* Most encoders don't need this */
encoder->cleanup = NULL;

/* Target image */
encoder->lock = NULL;
encoder->im = NULL;
Expand All @@ -87,6 +91,8 @@ PyImaging_EncoderNew(int contextsize)
static void
_dealloc(ImagingEncoderObject* encoder)
{
if (encoder->cleanup)
encoder->cleanup(&encoder->state);
free(encoder->state.buffer);
free(encoder->state.context);
Py_XDECREF(encoder->lock);
Expand Down Expand Up @@ -793,3 +799,132 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)

#endif

/* -------------------------------------------------------------------- */
/* JPEG 2000 */
/* -------------------------------------------------------------------- */

#ifdef HAVE_OPENJPEG

#include "Jpeg2K.h"

static void
j2k_decode_coord_tuple(PyObject *tuple, int *x, int *y)
{
*x = *y = 0;

if (tuple && PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2) {
*x = (int)PyInt_AsLong(PyTuple_GET_ITEM(tuple, 0));
*y = (int)PyInt_AsLong(PyTuple_GET_ITEM(tuple, 1));

if (*x < 0)
*x = 0;
if (*y < 0)
*y = 0;
}
}

PyObject*
PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
{
ImagingEncoderObject *encoder;
JPEG2KENCODESTATE *context;

char *mode;
char *format;
OPJ_CODEC_FORMAT codec_format;
PyObject *offset = NULL, *tile_offset = NULL, *tile_size = NULL;
char *quality_mode = "rates";
PyObject *quality_layers = NULL;
int num_resolutions = 0;
PyObject *cblk_size = NULL;
int irreversible = 0;
char *progression = "LRCP";
OPJ_PROG_ORDER prog_order;
char *cinema_mode = "no";
OPJ_CINEMA_MODE cine_mode;

if (!PyArg_ParseTuple(args, "ss|OOOsOiOpss", &mode, &format,
&offset, &tile_offset, &tile_size,
&quality_mode, &quality_layers, &num_resolutions,
&cblk_size, &irreversible, &progression, &cinema_mode))
return NULL;

if (strcmp (format, "j2k") == 0)
codec_format = OPJ_CODEC_J2K;
else if (strcmp (format, "jpt") == 0)
codec_format = OPJ_CODEC_JPT;
else if (strcmp (format, "jp2") == 0)
codec_format = OPJ_CODEC_JP2;
else
return NULL;

if (strcmp(progression, "LRCP") == 0)
prog_order = OPJ_LRCP;
else if (strcmp(progression, "RLCP") == 0)
prog_order = OPJ_RLCP;
else if (strcmp(progression, "RPCL") == 0)
prog_order = OPJ_RPCL;
else if (strcmp(progression, "PCRL") == 0)
prog_order = OPJ_PCRL;
else if (strcmp(progression, "CPRL") == 0)
prog_order = OPJ_CPRL;
else
return NULL;

if (strcmp(cinema_mode, "no") == 0)
cine_mode = OPJ_OFF;
else if (strcmp(cinema_mode, "cinema2k-24") == 0)
cine_mode = OPJ_CINEMA2K_24;
else if (strcmp(cinema_mode, "cinema2k-48") == 0)
cine_mode = OPJ_CINEMA2K_48;
else if (strcmp(cinema_mode, "cinema4k-24") == 0)
cine_mode = OPJ_CINEMA4K_24;
else
return NULL;

encoder = PyImaging_EncoderNew(sizeof(JPEG2KENCODESTATE));
if (!encoder)
return NULL;

encoder->encode = ImagingJpeg2KEncode;
encoder->cleanup = ImagingJpeg2KEncodeCleanup;

context = (JPEG2KENCODESTATE *)encoder->state.context;

context->format = codec_format;
context->offset_x = context->offset_y = 0;

j2k_decode_coord_tuple(offset, &context->offset_x, &context->offset_y);
j2k_decode_coord_tuple(tile_offset,
&context->tile_offset_x,
&context->tile_offset_y);
j2k_decode_coord_tuple(tile_size,
&context->tile_size_x,
&context->tile_size_y);

if (quality_layers && PySequence_Check(quality_layers)) {
context->quality_is_in_db = strcmp (quality_mode, "dB") == 0;
context->quality_layers = quality_layers;
}

context->num_resolutions = num_resolutions;

j2k_decode_coord_tuple(cblk_size,
&context->cblk_width,
&context->cblk_height);

context->irreversible = irreversible;
context->progression = prog_order;
context->cinema_mode = cine_mode;

return (PyObject *)encoder;
}

#endif

/*
* Local Variables:
* c-basic-offset: 4
* End:
*
*/
25 changes: 15 additions & 10 deletions libImaging/Imaging.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@ extern int ImagingJpegEncode(Imaging im, ImagingCodecState state,
extern int ImagingJpeg2KDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes);
extern int ImagingJpeg2KDecodeCleanup(ImagingCodecState state);
extern int ImagingJpeg2KEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes);
extern int ImagingJpeg2KEncodeCleanup(ImagingCodecState state);
#endif
extern int ImagingLzwDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes);
Expand Down Expand Up @@ -502,18 +505,20 @@ struct ImagingCodecStateInstance {
void *context;
};

/* Incremental decoding support */
typedef struct ImagingIncrementalDecoderStruct *ImagingIncrementalDecoder;
/* Incremental encoding/decoding support */
typedef struct ImagingIncrementalCodecStruct *ImagingIncrementalCodec;

typedef int (*ImagingIncrementalDecoderEntry)(Imaging im,
ImagingCodecState state,
ImagingIncrementalDecoder decoder);
typedef int (*ImagingIncrementalCodecEntry)(Imaging im,
ImagingCodecState state,
ImagingIncrementalCodec codec);

extern ImagingIncrementalDecoder ImagingIncrementalDecoderCreate(ImagingIncrementalDecoderEntry decoder_entry, Imaging im, ImagingCodecState state);
extern void ImagingIncrementalDecoderDestroy(ImagingIncrementalDecoder decoder);
extern int ImagingIncrementalDecodeData(ImagingIncrementalDecoder decoder, UINT8 *buf, int bytes);
size_t ImagingIncrementalDecoderRead(ImagingIncrementalDecoder decoder, void *buffer, size_t bytes);
off_t ImagingIncrementalDecoderSkip(ImagingIncrementalDecoder decoder, off_t bytes);
extern ImagingIncrementalCodec ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, Imaging im, ImagingCodecState state);
extern void ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec);
extern int ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec, UINT8 *buf, int bytes);
extern size_t ImagingIncrementalCodecRead(ImagingIncrementalCodec codec, void *buffer, size_t bytes);
extern off_t ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec, off_t bytes);
extern size_t ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, const void *buffer, size_t bytes);
extern size_t ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec);

/* Errcodes */
#define IMAGING_CODEC_END 1
Expand Down
Loading

0 comments on commit 61fb89e

Please sign in to comment.