Skip to content

Commit 61fb89e

Browse files
committed
Added a JPEG 2000 encoder.
1 parent aea0ec5 commit 61fb89e

10 files changed

+1004
-208
lines changed

PIL/Jpeg2KImagePlugin.py

+21-9
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,29 @@ def _accept(prefix):
173173
return (prefix[:4] == b'\xff\x4f\xff\x51'
174174
or prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a')
175175

176+
# ------------------------------------------------------------
177+
# Save support
178+
179+
def _save(im, fp, filename):
180+
if filename.endswith('.j2k'):
181+
kind = 'j2k'
182+
else:
183+
kind = 'jp2'
184+
185+
ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)])
186+
176187
# ------------------------------------------------------------
177188
# Registry stuff
178189

179-
Image.register_open("JPEG2000", Jpeg2KImageFile, _accept)
190+
Image.register_open('JPEG2000', Jpeg2KImageFile, _accept)
191+
Image.register_save('JPEG2000', _save)
180192

181-
Image.register_extension("JPEG2000", ".jp2")
182-
Image.register_extension("JPEG2000", ".j2k")
183-
Image.register_extension("JPEG2000", ".jpc")
184-
Image.register_extension("JPEG2000", ".jpf")
185-
Image.register_extension("JPEG2000", ".jpx")
186-
Image.register_extension("JPEG2000", ".j2c")
193+
Image.register_extension('JPEG2000', '.jp2')
194+
Image.register_extension('JPEG2000', '.j2k')
195+
Image.register_extension('JPEG2000', '.jpc')
196+
Image.register_extension('JPEG2000', '.jpf')
197+
Image.register_extension('JPEG2000', '.jpx')
198+
Image.register_extension('JPEG2000', '.j2c')
187199

188-
Image.register_mime("JPEG2000", "image/jp2")
189-
Image.register_mime("JPEG2000", "image/jpx")
200+
Image.register_mime('JPEG2000', 'image/jp2')
201+
Image.register_mime('JPEG2000', 'image/jpx')

_imaging.c

+2
Original file line numberDiff line numberDiff line change
@@ -3300,6 +3300,7 @@ extern PyObject* PyImaging_ZipDecoderNew(PyObject* self, PyObject* args);
33003300
extern PyObject* PyImaging_EpsEncoderNew(PyObject* self, PyObject* args);
33013301
extern PyObject* PyImaging_GifEncoderNew(PyObject* self, PyObject* args);
33023302
extern PyObject* PyImaging_JpegEncoderNew(PyObject* self, PyObject* args);
3303+
extern PyObject* PyImaging_Jpeg2KEncoderNew(PyObject* self, PyObject* args);
33033304
extern PyObject* PyImaging_PcxEncoderNew(PyObject* self, PyObject* args);
33043305
extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args);
33053306
extern PyObject* PyImaging_XbmEncoderNew(PyObject* self, PyObject* args);
@@ -3355,6 +3356,7 @@ static PyMethodDef functions[] = {
33553356
#endif
33563357
#ifdef HAVE_OPENJPEG
33573358
{"jpeg2k_decoder", (PyCFunction)PyImaging_Jpeg2KDecoderNew, 1},
3359+
{"jpeg2k_encoder", (PyCFunction)PyImaging_Jpeg2KEncoderNew, 1},
33583360
#endif
33593361
{"tiff_lzw_decoder", (PyCFunction)PyImaging_TiffLzwDecoderNew, 1},
33603362
#ifdef HAVE_LIBTIFF

decode.c

+7-17
Original file line numberDiff line numberDiff line change
@@ -778,27 +778,18 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args)
778778
#endif
779779

780780
/* -------------------------------------------------------------------- */
781-
/* JPEG2000 */
781+
/* JPEG 2000 */
782782
/* -------------------------------------------------------------------- */
783783

784784
#ifdef HAVE_OPENJPEG
785785

786-
/* We better define this decoder last in this file, so the following
787-
undef's won't mess things up for the Imaging library proper. */
788-
#undef UINT8
789-
#undef UINT16
790-
#undef UINT32
791-
#undef INT8
792-
#undef INT16
793-
#undef INT32
794-
795786
#include "Jpeg2K.h"
796787

797788
PyObject*
798789
PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
799790
{
800791
ImagingDecoderObject* decoder;
801-
JPEG2KSTATE *context;
792+
JPEG2KDECODESTATE *context;
802793

803794
char* mode;
804795
char* format;
@@ -809,26 +800,25 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
809800
&reduce, &layers))
810801
return NULL;
811802

812-
if (strcmp (format, "j2k") == 0)
803+
if (strcmp(format, "j2k") == 0)
813804
codec_format = OPJ_CODEC_J2K;
814-
else if (strcmp (format, "jpt") == 0)
805+
else if (strcmp(format, "jpt") == 0)
815806
codec_format = OPJ_CODEC_JPT;
816-
else if (strcmp (format, "jp2") == 0)
807+
else if (strcmp(format, "jp2") == 0)
817808
codec_format = OPJ_CODEC_JP2;
818809
else
819810
return NULL;
820811

821-
decoder = PyImaging_DecoderNew(sizeof(JPEG2KSTATE));
812+
decoder = PyImaging_DecoderNew(sizeof(JPEG2KDECODESTATE));
822813
if (decoder == NULL)
823814
return NULL;
824815

825816
decoder->handles_eof = 1;
826817
decoder->decode = ImagingJpeg2KDecode;
827818
decoder->cleanup = ImagingJpeg2KDecodeCleanup;
828819

829-
context = (JPEG2KSTATE *)decoder->state.context;
820+
context = (JPEG2KDECODESTATE *)decoder->state.context;
830821

831-
strncpy(context->mode, mode, 8);
832822
context->format = codec_format;
833823
context->reduce = reduce;
834824
context->layers = layers;

encode.c

+135
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ typedef struct {
4040
PyObject_HEAD
4141
int (*encode)(Imaging im, ImagingCodecState state,
4242
UINT8* buffer, int bytes);
43+
int (*cleanup)(ImagingCodecState state);
4344
struct ImagingCodecStateInstance state;
4445
Imaging im;
4546
PyObject* lock;
@@ -77,6 +78,9 @@ PyImaging_EncoderNew(int contextsize)
7778
/* Initialize encoder context */
7879
encoder->state.context = context;
7980

81+
/* Most encoders don't need this */
82+
encoder->cleanup = NULL;
83+
8084
/* Target image */
8185
encoder->lock = NULL;
8286
encoder->im = NULL;
@@ -87,6 +91,8 @@ PyImaging_EncoderNew(int contextsize)
8791
static void
8892
_dealloc(ImagingEncoderObject* encoder)
8993
{
94+
if (encoder->cleanup)
95+
encoder->cleanup(&encoder->state);
9096
free(encoder->state.buffer);
9197
free(encoder->state.context);
9298
Py_XDECREF(encoder->lock);
@@ -793,3 +799,132 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
793799

794800
#endif
795801

802+
/* -------------------------------------------------------------------- */
803+
/* JPEG 2000 */
804+
/* -------------------------------------------------------------------- */
805+
806+
#ifdef HAVE_OPENJPEG
807+
808+
#include "Jpeg2K.h"
809+
810+
static void
811+
j2k_decode_coord_tuple(PyObject *tuple, int *x, int *y)
812+
{
813+
*x = *y = 0;
814+
815+
if (tuple && PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2) {
816+
*x = (int)PyInt_AsLong(PyTuple_GET_ITEM(tuple, 0));
817+
*y = (int)PyInt_AsLong(PyTuple_GET_ITEM(tuple, 1));
818+
819+
if (*x < 0)
820+
*x = 0;
821+
if (*y < 0)
822+
*y = 0;
823+
}
824+
}
825+
826+
PyObject*
827+
PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
828+
{
829+
ImagingEncoderObject *encoder;
830+
JPEG2KENCODESTATE *context;
831+
832+
char *mode;
833+
char *format;
834+
OPJ_CODEC_FORMAT codec_format;
835+
PyObject *offset = NULL, *tile_offset = NULL, *tile_size = NULL;
836+
char *quality_mode = "rates";
837+
PyObject *quality_layers = NULL;
838+
int num_resolutions = 0;
839+
PyObject *cblk_size = NULL;
840+
int irreversible = 0;
841+
char *progression = "LRCP";
842+
OPJ_PROG_ORDER prog_order;
843+
char *cinema_mode = "no";
844+
OPJ_CINEMA_MODE cine_mode;
845+
846+
if (!PyArg_ParseTuple(args, "ss|OOOsOiOpss", &mode, &format,
847+
&offset, &tile_offset, &tile_size,
848+
&quality_mode, &quality_layers, &num_resolutions,
849+
&cblk_size, &irreversible, &progression, &cinema_mode))
850+
return NULL;
851+
852+
if (strcmp (format, "j2k") == 0)
853+
codec_format = OPJ_CODEC_J2K;
854+
else if (strcmp (format, "jpt") == 0)
855+
codec_format = OPJ_CODEC_JPT;
856+
else if (strcmp (format, "jp2") == 0)
857+
codec_format = OPJ_CODEC_JP2;
858+
else
859+
return NULL;
860+
861+
if (strcmp(progression, "LRCP") == 0)
862+
prog_order = OPJ_LRCP;
863+
else if (strcmp(progression, "RLCP") == 0)
864+
prog_order = OPJ_RLCP;
865+
else if (strcmp(progression, "RPCL") == 0)
866+
prog_order = OPJ_RPCL;
867+
else if (strcmp(progression, "PCRL") == 0)
868+
prog_order = OPJ_PCRL;
869+
else if (strcmp(progression, "CPRL") == 0)
870+
prog_order = OPJ_CPRL;
871+
else
872+
return NULL;
873+
874+
if (strcmp(cinema_mode, "no") == 0)
875+
cine_mode = OPJ_OFF;
876+
else if (strcmp(cinema_mode, "cinema2k-24") == 0)
877+
cine_mode = OPJ_CINEMA2K_24;
878+
else if (strcmp(cinema_mode, "cinema2k-48") == 0)
879+
cine_mode = OPJ_CINEMA2K_48;
880+
else if (strcmp(cinema_mode, "cinema4k-24") == 0)
881+
cine_mode = OPJ_CINEMA4K_24;
882+
else
883+
return NULL;
884+
885+
encoder = PyImaging_EncoderNew(sizeof(JPEG2KENCODESTATE));
886+
if (!encoder)
887+
return NULL;
888+
889+
encoder->encode = ImagingJpeg2KEncode;
890+
encoder->cleanup = ImagingJpeg2KEncodeCleanup;
891+
892+
context = (JPEG2KENCODESTATE *)encoder->state.context;
893+
894+
context->format = codec_format;
895+
context->offset_x = context->offset_y = 0;
896+
897+
j2k_decode_coord_tuple(offset, &context->offset_x, &context->offset_y);
898+
j2k_decode_coord_tuple(tile_offset,
899+
&context->tile_offset_x,
900+
&context->tile_offset_y);
901+
j2k_decode_coord_tuple(tile_size,
902+
&context->tile_size_x,
903+
&context->tile_size_y);
904+
905+
if (quality_layers && PySequence_Check(quality_layers)) {
906+
context->quality_is_in_db = strcmp (quality_mode, "dB") == 0;
907+
context->quality_layers = quality_layers;
908+
}
909+
910+
context->num_resolutions = num_resolutions;
911+
912+
j2k_decode_coord_tuple(cblk_size,
913+
&context->cblk_width,
914+
&context->cblk_height);
915+
916+
context->irreversible = irreversible;
917+
context->progression = prog_order;
918+
context->cinema_mode = cine_mode;
919+
920+
return (PyObject *)encoder;
921+
}
922+
923+
#endif
924+
925+
/*
926+
* Local Variables:
927+
* c-basic-offset: 4
928+
* End:
929+
*
930+
*/

libImaging/Imaging.h

+15-10
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,9 @@ extern int ImagingJpegEncode(Imaging im, ImagingCodecState state,
428428
extern int ImagingJpeg2KDecode(Imaging im, ImagingCodecState state,
429429
UINT8* buffer, int bytes);
430430
extern int ImagingJpeg2KDecodeCleanup(ImagingCodecState state);
431+
extern int ImagingJpeg2KEncode(Imaging im, ImagingCodecState state,
432+
UINT8* buffer, int bytes);
433+
extern int ImagingJpeg2KEncodeCleanup(ImagingCodecState state);
431434
#endif
432435
extern int ImagingLzwDecode(Imaging im, ImagingCodecState state,
433436
UINT8* buffer, int bytes);
@@ -502,18 +505,20 @@ struct ImagingCodecStateInstance {
502505
void *context;
503506
};
504507

505-
/* Incremental decoding support */
506-
typedef struct ImagingIncrementalDecoderStruct *ImagingIncrementalDecoder;
508+
/* Incremental encoding/decoding support */
509+
typedef struct ImagingIncrementalCodecStruct *ImagingIncrementalCodec;
507510

508-
typedef int (*ImagingIncrementalDecoderEntry)(Imaging im,
509-
ImagingCodecState state,
510-
ImagingIncrementalDecoder decoder);
511+
typedef int (*ImagingIncrementalCodecEntry)(Imaging im,
512+
ImagingCodecState state,
513+
ImagingIncrementalCodec codec);
511514

512-
extern ImagingIncrementalDecoder ImagingIncrementalDecoderCreate(ImagingIncrementalDecoderEntry decoder_entry, Imaging im, ImagingCodecState state);
513-
extern void ImagingIncrementalDecoderDestroy(ImagingIncrementalDecoder decoder);
514-
extern int ImagingIncrementalDecodeData(ImagingIncrementalDecoder decoder, UINT8 *buf, int bytes);
515-
size_t ImagingIncrementalDecoderRead(ImagingIncrementalDecoder decoder, void *buffer, size_t bytes);
516-
off_t ImagingIncrementalDecoderSkip(ImagingIncrementalDecoder decoder, off_t bytes);
515+
extern ImagingIncrementalCodec ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, Imaging im, ImagingCodecState state);
516+
extern void ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec);
517+
extern int ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec, UINT8 *buf, int bytes);
518+
extern size_t ImagingIncrementalCodecRead(ImagingIncrementalCodec codec, void *buffer, size_t bytes);
519+
extern off_t ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec, off_t bytes);
520+
extern size_t ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, const void *buffer, size_t bytes);
521+
extern size_t ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec);
517522

518523
/* Errcodes */
519524
#define IMAGING_CODEC_END 1

0 commit comments

Comments
 (0)