mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 01:46:18 +03:00
Added a JPEG 2000 encoder.
This commit is contained in:
parent
aea0ec56b2
commit
61fb89ec54
|
@ -173,17 +173,29 @@ def _accept(prefix):
|
||||||
return (prefix[:4] == b'\xff\x4f\xff\x51'
|
return (prefix[:4] == b'\xff\x4f\xff\x51'
|
||||||
or prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a')
|
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
|
# 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', '.jp2')
|
||||||
Image.register_extension("JPEG2000", ".j2k")
|
Image.register_extension('JPEG2000', '.j2k')
|
||||||
Image.register_extension("JPEG2000", ".jpc")
|
Image.register_extension('JPEG2000', '.jpc')
|
||||||
Image.register_extension("JPEG2000", ".jpf")
|
Image.register_extension('JPEG2000', '.jpf')
|
||||||
Image.register_extension("JPEG2000", ".jpx")
|
Image.register_extension('JPEG2000', '.jpx')
|
||||||
Image.register_extension("JPEG2000", ".j2c")
|
Image.register_extension('JPEG2000', '.j2c')
|
||||||
|
|
||||||
Image.register_mime("JPEG2000", "image/jp2")
|
Image.register_mime('JPEG2000', 'image/jp2')
|
||||||
Image.register_mime("JPEG2000", "image/jpx")
|
Image.register_mime('JPEG2000', 'image/jpx')
|
||||||
|
|
|
@ -3300,6 +3300,7 @@ extern PyObject* PyImaging_ZipDecoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_EpsEncoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_EpsEncoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_GifEncoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_GifEncoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_JpegEncoderNew(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_PcxEncoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_XbmEncoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_XbmEncoderNew(PyObject* self, PyObject* args);
|
||||||
|
@ -3355,6 +3356,7 @@ static PyMethodDef functions[] = {
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_OPENJPEG
|
#ifdef HAVE_OPENJPEG
|
||||||
{"jpeg2k_decoder", (PyCFunction)PyImaging_Jpeg2KDecoderNew, 1},
|
{"jpeg2k_decoder", (PyCFunction)PyImaging_Jpeg2KDecoderNew, 1},
|
||||||
|
{"jpeg2k_encoder", (PyCFunction)PyImaging_Jpeg2KEncoderNew, 1},
|
||||||
#endif
|
#endif
|
||||||
{"tiff_lzw_decoder", (PyCFunction)PyImaging_TiffLzwDecoderNew, 1},
|
{"tiff_lzw_decoder", (PyCFunction)PyImaging_TiffLzwDecoderNew, 1},
|
||||||
#ifdef HAVE_LIBTIFF
|
#ifdef HAVE_LIBTIFF
|
||||||
|
|
24
decode.c
24
decode.c
|
@ -778,27 +778,18 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* JPEG2000 */
|
/* JPEG 2000 */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
#ifdef HAVE_OPENJPEG
|
#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"
|
#include "Jpeg2K.h"
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
|
PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
ImagingDecoderObject* decoder;
|
ImagingDecoderObject* decoder;
|
||||||
JPEG2KSTATE *context;
|
JPEG2KDECODESTATE *context;
|
||||||
|
|
||||||
char* mode;
|
char* mode;
|
||||||
char* format;
|
char* format;
|
||||||
|
@ -809,16 +800,16 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
|
||||||
&reduce, &layers))
|
&reduce, &layers))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (strcmp (format, "j2k") == 0)
|
if (strcmp(format, "j2k") == 0)
|
||||||
codec_format = OPJ_CODEC_J2K;
|
codec_format = OPJ_CODEC_J2K;
|
||||||
else if (strcmp (format, "jpt") == 0)
|
else if (strcmp(format, "jpt") == 0)
|
||||||
codec_format = OPJ_CODEC_JPT;
|
codec_format = OPJ_CODEC_JPT;
|
||||||
else if (strcmp (format, "jp2") == 0)
|
else if (strcmp(format, "jp2") == 0)
|
||||||
codec_format = OPJ_CODEC_JP2;
|
codec_format = OPJ_CODEC_JP2;
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
decoder = PyImaging_DecoderNew(sizeof(JPEG2KSTATE));
|
decoder = PyImaging_DecoderNew(sizeof(JPEG2KDECODESTATE));
|
||||||
if (decoder == NULL)
|
if (decoder == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -826,9 +817,8 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
|
||||||
decoder->decode = ImagingJpeg2KDecode;
|
decoder->decode = ImagingJpeg2KDecode;
|
||||||
decoder->cleanup = ImagingJpeg2KDecodeCleanup;
|
decoder->cleanup = ImagingJpeg2KDecodeCleanup;
|
||||||
|
|
||||||
context = (JPEG2KSTATE *)decoder->state.context;
|
context = (JPEG2KDECODESTATE *)decoder->state.context;
|
||||||
|
|
||||||
strncpy(context->mode, mode, 8);
|
|
||||||
context->format = codec_format;
|
context->format = codec_format;
|
||||||
context->reduce = reduce;
|
context->reduce = reduce;
|
||||||
context->layers = layers;
|
context->layers = layers;
|
||||||
|
|
135
encode.c
135
encode.c
|
@ -40,6 +40,7 @@ typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
int (*encode)(Imaging im, ImagingCodecState state,
|
int (*encode)(Imaging im, ImagingCodecState state,
|
||||||
UINT8* buffer, int bytes);
|
UINT8* buffer, int bytes);
|
||||||
|
int (*cleanup)(ImagingCodecState state);
|
||||||
struct ImagingCodecStateInstance state;
|
struct ImagingCodecStateInstance state;
|
||||||
Imaging im;
|
Imaging im;
|
||||||
PyObject* lock;
|
PyObject* lock;
|
||||||
|
@ -77,6 +78,9 @@ PyImaging_EncoderNew(int contextsize)
|
||||||
/* Initialize encoder context */
|
/* Initialize encoder context */
|
||||||
encoder->state.context = context;
|
encoder->state.context = context;
|
||||||
|
|
||||||
|
/* Most encoders don't need this */
|
||||||
|
encoder->cleanup = NULL;
|
||||||
|
|
||||||
/* Target image */
|
/* Target image */
|
||||||
encoder->lock = NULL;
|
encoder->lock = NULL;
|
||||||
encoder->im = NULL;
|
encoder->im = NULL;
|
||||||
|
@ -87,6 +91,8 @@ PyImaging_EncoderNew(int contextsize)
|
||||||
static void
|
static void
|
||||||
_dealloc(ImagingEncoderObject* encoder)
|
_dealloc(ImagingEncoderObject* encoder)
|
||||||
{
|
{
|
||||||
|
if (encoder->cleanup)
|
||||||
|
encoder->cleanup(&encoder->state);
|
||||||
free(encoder->state.buffer);
|
free(encoder->state.buffer);
|
||||||
free(encoder->state.context);
|
free(encoder->state.context);
|
||||||
Py_XDECREF(encoder->lock);
|
Py_XDECREF(encoder->lock);
|
||||||
|
@ -793,3 +799,132 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
||||||
|
|
||||||
#endif
|
#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:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
|
@ -428,6 +428,9 @@ extern int ImagingJpegEncode(Imaging im, ImagingCodecState state,
|
||||||
extern int ImagingJpeg2KDecode(Imaging im, ImagingCodecState state,
|
extern int ImagingJpeg2KDecode(Imaging im, ImagingCodecState state,
|
||||||
UINT8* buffer, int bytes);
|
UINT8* buffer, int bytes);
|
||||||
extern int ImagingJpeg2KDecodeCleanup(ImagingCodecState state);
|
extern int ImagingJpeg2KDecodeCleanup(ImagingCodecState state);
|
||||||
|
extern int ImagingJpeg2KEncode(Imaging im, ImagingCodecState state,
|
||||||
|
UINT8* buffer, int bytes);
|
||||||
|
extern int ImagingJpeg2KEncodeCleanup(ImagingCodecState state);
|
||||||
#endif
|
#endif
|
||||||
extern int ImagingLzwDecode(Imaging im, ImagingCodecState state,
|
extern int ImagingLzwDecode(Imaging im, ImagingCodecState state,
|
||||||
UINT8* buffer, int bytes);
|
UINT8* buffer, int bytes);
|
||||||
|
@ -502,18 +505,20 @@ struct ImagingCodecStateInstance {
|
||||||
void *context;
|
void *context;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Incremental decoding support */
|
/* Incremental encoding/decoding support */
|
||||||
typedef struct ImagingIncrementalDecoderStruct *ImagingIncrementalDecoder;
|
typedef struct ImagingIncrementalCodecStruct *ImagingIncrementalCodec;
|
||||||
|
|
||||||
typedef int (*ImagingIncrementalDecoderEntry)(Imaging im,
|
typedef int (*ImagingIncrementalCodecEntry)(Imaging im,
|
||||||
ImagingCodecState state,
|
ImagingCodecState state,
|
||||||
ImagingIncrementalDecoder decoder);
|
ImagingIncrementalCodec codec);
|
||||||
|
|
||||||
extern ImagingIncrementalDecoder ImagingIncrementalDecoderCreate(ImagingIncrementalDecoderEntry decoder_entry, Imaging im, ImagingCodecState state);
|
extern ImagingIncrementalCodec ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, Imaging im, ImagingCodecState state);
|
||||||
extern void ImagingIncrementalDecoderDestroy(ImagingIncrementalDecoder decoder);
|
extern void ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec);
|
||||||
extern int ImagingIncrementalDecodeData(ImagingIncrementalDecoder decoder, UINT8 *buf, int bytes);
|
extern int ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec, UINT8 *buf, int bytes);
|
||||||
size_t ImagingIncrementalDecoderRead(ImagingIncrementalDecoder decoder, void *buffer, size_t bytes);
|
extern size_t ImagingIncrementalCodecRead(ImagingIncrementalCodec codec, void *buffer, size_t bytes);
|
||||||
off_t ImagingIncrementalDecoderSkip(ImagingIncrementalDecoder decoder, off_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 */
|
/* Errcodes */
|
||||||
#define IMAGING_CODEC_END 1
|
#define IMAGING_CODEC_END 1
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
|
|
||||||
/* The idea behind this interface is simple: the actual decoding proceeds in
|
/* The idea behind this interface is simple: the actual decoding proceeds in
|
||||||
a thread, which is run in lock step with the main thread. Whenever the
|
a thread, which is run in lock step with the main thread. Whenever the
|
||||||
ImagingIncrementalDecoderRead() call runs short on data, it suspends the
|
ImagingIncrementalCodecRead() call runs short on data, it suspends the
|
||||||
decoding thread and wakes the main thread. Conversely, the
|
decoding thread and wakes the main thread. Conversely, the
|
||||||
ImagingIncrementalDecodeData() call suspends the main thread and wakes
|
ImagingIncrementalCodecPushBuffer() call suspends the main thread and wakes
|
||||||
the decoding thread, providing a buffer of data.
|
the decoding thread, providing a buffer of data.
|
||||||
|
|
||||||
The two threads are never running simultaneously, so there is no need for
|
The two threads are never running simultaneously, so there is no need for
|
||||||
|
@ -50,27 +50,21 @@
|
||||||
#define DEBUG(...)
|
#define DEBUG(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ImagingIncrementalStreamStruct {
|
struct ImagingIncrementalCodecStruct {
|
||||||
UINT8 *buffer;
|
|
||||||
UINT8 *ptr;
|
|
||||||
UINT8 *end;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ImagingIncrementalDecoderStruct {
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hDecodeEvent;
|
HANDLE hCodecEvent;
|
||||||
HANDLE hDataEvent;
|
HANDLE hDataEvent;
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
#else
|
#else
|
||||||
pthread_mutex_t start_mutex;
|
pthread_mutex_t start_mutex;
|
||||||
pthread_cond_t start_cond;
|
pthread_cond_t start_cond;
|
||||||
pthread_mutex_t decode_mutex;
|
pthread_mutex_t codec_mutex;
|
||||||
pthread_cond_t decode_cond;
|
pthread_cond_t codec_cond;
|
||||||
pthread_mutex_t data_mutex;
|
pthread_mutex_t data_mutex;
|
||||||
pthread_cond_t data_cond;
|
pthread_cond_t data_cond;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
#endif
|
#endif
|
||||||
ImagingIncrementalDecoderEntry entry;
|
ImagingIncrementalCodecEntry entry;
|
||||||
Imaging im;
|
Imaging im;
|
||||||
ImagingCodecState state;
|
ImagingCodecState state;
|
||||||
struct {
|
struct {
|
||||||
|
@ -84,222 +78,228 @@ struct ImagingIncrementalDecoderStruct {
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
static void __stdcall
|
static void __stdcall
|
||||||
incremental_thread(void *ptr)
|
codec_thread(void *ptr)
|
||||||
{
|
{
|
||||||
ImagingIncrementalDecoder decoder = (ImagingIncrementalDecoder)ptr;
|
ImagingIncrementalCodec codec = (ImagingIncrementalCodec)ptr;
|
||||||
|
|
||||||
decoder->result = decoder->entry(decoder->im, decoder->state, decoder);
|
codec->result = codec->entry(codec->im, codec->state, codec);
|
||||||
|
|
||||||
SetEvent(decoder->hDecodeEvent);
|
SetEvent(codec->hCodecEvent);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void *
|
static void *
|
||||||
incremental_thread(void *ptr)
|
codec_thread(void *ptr)
|
||||||
{
|
{
|
||||||
ImagingIncrementalDecoder decoder = (ImagingIncrementalDecoder)ptr;
|
ImagingIncrementalCodec codec = (ImagingIncrementalCodec)ptr;
|
||||||
|
|
||||||
decoder->result = decoder->entry(decoder->im, decoder->state, decoder);
|
codec->result = codec->entry(codec->im, codec->state, codec);
|
||||||
|
|
||||||
pthread_cond_signal(&decoder->decode_cond);
|
pthread_cond_signal(&codec->codec_cond);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new incremental decoder */
|
* Create a new incremental codec */
|
||||||
ImagingIncrementalDecoder
|
ImagingIncrementalCodec
|
||||||
ImagingIncrementalDecoderCreate(ImagingIncrementalDecoderEntry decoder_entry,
|
ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry,
|
||||||
Imaging im,
|
Imaging im,
|
||||||
ImagingCodecState state)
|
ImagingCodecState state)
|
||||||
{
|
{
|
||||||
ImagingIncrementalDecoder decoder = (ImagingIncrementalDecoder)malloc(sizeof(struct ImagingIncrementalDecoderStruct));
|
ImagingIncrementalCodec codec = (ImagingIncrementalCodec)malloc(sizeof(struct ImagingIncrementalCodecStruct));
|
||||||
|
|
||||||
decoder->entry = decoder_entry;
|
codec->entry = codec_entry;
|
||||||
decoder->im = im;
|
codec->im = im;
|
||||||
decoder->state = state;
|
codec->state = state;
|
||||||
decoder->result = 0;
|
codec->result = 0;
|
||||||
decoder->stream.buffer = decoder->stream.ptr = decoder->stream.end = NULL;
|
codec->stream.buffer = codec->stream.ptr = codec->stream.end = NULL;
|
||||||
decoder->started = 0;
|
codec->started = 0;
|
||||||
|
|
||||||
/* System specific set-up */
|
/* System specific set-up */
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
decoder->hDecodeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
codec->hCodecEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
if (!decoder->hDecodeEvent) {
|
if (!codec->hCodecEvent) {
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder->hDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
codec->hDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
if (!decoder->hDataEvent) {
|
if (!codec->hDataEvent) {
|
||||||
CloseHandle(decoder->hDecodeEvent);
|
CloseHandle(codec->hCodecEvent);
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder->hThread = _beginthreadex(NULL, 0, incremental_thread, decoder,
|
codec->hThread = _beginthreadex(NULL, 0, codec_thread, codec,
|
||||||
CREATE_SUSPENDED, NULL);
|
CREATE_SUSPENDED, NULL);
|
||||||
|
|
||||||
if (!decoder->hThread) {
|
if (!codec->hThread) {
|
||||||
CloseHandle(decoder->hDecodeEvent);
|
CloseHandle(codec->hCodecEvent);
|
||||||
CloseHandle(decoder->hDataEvent);
|
CloseHandle(codec->hDataEvent);
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (pthread_mutex_init(&decoder->start_mutex, NULL)) {
|
if (pthread_mutex_init(&codec->start_mutex, NULL)) {
|
||||||
free (decoder);
|
free (codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_mutex_init(&decoder->decode_mutex, NULL)) {
|
if (pthread_mutex_init(&codec->codec_mutex, NULL)) {
|
||||||
pthread_mutex_destroy(&decoder->start_mutex);
|
pthread_mutex_destroy(&codec->start_mutex);
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_mutex_init(&decoder->data_mutex, NULL)) {
|
if (pthread_mutex_init(&codec->data_mutex, NULL)) {
|
||||||
pthread_mutex_destroy(&decoder->start_mutex);
|
pthread_mutex_destroy(&codec->start_mutex);
|
||||||
pthread_mutex_destroy(&decoder->decode_mutex);
|
pthread_mutex_destroy(&codec->codec_mutex);
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_cond_init(&decoder->start_cond, NULL)) {
|
if (pthread_cond_init(&codec->start_cond, NULL)) {
|
||||||
pthread_mutex_destroy(&decoder->start_mutex);
|
pthread_mutex_destroy(&codec->start_mutex);
|
||||||
pthread_mutex_destroy(&decoder->decode_mutex);
|
pthread_mutex_destroy(&codec->codec_mutex);
|
||||||
pthread_mutex_destroy(&decoder->data_mutex);
|
pthread_mutex_destroy(&codec->data_mutex);
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_cond_init(&decoder->decode_cond, NULL)) {
|
if (pthread_cond_init(&codec->codec_cond, NULL)) {
|
||||||
pthread_mutex_destroy(&decoder->start_mutex);
|
pthread_mutex_destroy(&codec->start_mutex);
|
||||||
pthread_mutex_destroy(&decoder->decode_mutex);
|
pthread_mutex_destroy(&codec->codec_mutex);
|
||||||
pthread_mutex_destroy(&decoder->data_mutex);
|
pthread_mutex_destroy(&codec->data_mutex);
|
||||||
pthread_cond_destroy(&decoder->start_cond);
|
pthread_cond_destroy(&codec->start_cond);
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_cond_init(&decoder->data_cond, NULL)) {
|
if (pthread_cond_init(&codec->data_cond, NULL)) {
|
||||||
pthread_mutex_destroy(&decoder->start_mutex);
|
pthread_mutex_destroy(&codec->start_mutex);
|
||||||
pthread_mutex_destroy(&decoder->decode_mutex);
|
pthread_mutex_destroy(&codec->codec_mutex);
|
||||||
pthread_mutex_destroy(&decoder->data_mutex);
|
pthread_mutex_destroy(&codec->data_mutex);
|
||||||
pthread_cond_destroy(&decoder->start_cond);
|
pthread_cond_destroy(&codec->start_cond);
|
||||||
pthread_cond_destroy(&decoder->decode_cond);
|
pthread_cond_destroy(&codec->codec_cond);
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_create(&decoder->thread, NULL, incremental_thread, decoder)) {
|
if (pthread_create(&codec->thread, NULL, codec_thread, codec)) {
|
||||||
pthread_mutex_destroy(&decoder->start_mutex);
|
pthread_mutex_destroy(&codec->start_mutex);
|
||||||
pthread_mutex_destroy(&decoder->decode_mutex);
|
pthread_mutex_destroy(&codec->codec_mutex);
|
||||||
pthread_mutex_destroy(&decoder->data_mutex);
|
pthread_mutex_destroy(&codec->data_mutex);
|
||||||
pthread_cond_destroy(&decoder->start_cond);
|
pthread_cond_destroy(&codec->start_cond);
|
||||||
pthread_cond_destroy(&decoder->decode_cond);
|
pthread_cond_destroy(&codec->codec_cond);
|
||||||
pthread_cond_destroy(&decoder->data_cond);
|
pthread_cond_destroy(&codec->data_cond);
|
||||||
free(decoder);
|
free(codec);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return decoder;
|
return codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy an incremental decoder */
|
* Destroy an incremental codec */
|
||||||
void
|
void
|
||||||
ImagingIncrementalDecoderDestroy(ImagingIncrementalDecoder decoder)
|
ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec)
|
||||||
{
|
{
|
||||||
DEBUG("destroying\n");
|
DEBUG("destroying\n");
|
||||||
|
|
||||||
if (!decoder->started) {
|
if (!codec->started) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ResumeThread(decoder->hThread);
|
ResumeThread(codec->hThread);
|
||||||
#else
|
#else
|
||||||
pthread_cond_signal(&decoder->start_cond);
|
pthread_cond_signal(&codec->start_cond);
|
||||||
#endif
|
#endif
|
||||||
decoder->started = 1;
|
codec->started = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_lock(&decoder->data_mutex);
|
pthread_mutex_lock(&codec->data_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
decoder->stream.buffer = decoder->stream.ptr = decoder->stream.end = NULL;
|
codec->stream.buffer = codec->stream.ptr = codec->stream.end = NULL;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetEvent(decoder->hDataEvent);
|
SetEvent(codec->hDataEvent);
|
||||||
|
|
||||||
WaitForSingleObject(decoder->hThread, INFINITE);
|
WaitForSingleObject(codec->hThread, INFINITE);
|
||||||
|
|
||||||
CloseHandle(decoder->hThread);
|
CloseHandle(codec->hThread);
|
||||||
CloseHandle(decoder->hDecodeEvent);
|
CloseHandle(codec->hCodecEvent);
|
||||||
CloseHandle(decoder->hDataEvent);
|
CloseHandle(codec->hDataEvent);
|
||||||
#else
|
#else
|
||||||
pthread_cond_signal(&decoder->data_cond);
|
pthread_cond_signal(&codec->data_cond);
|
||||||
pthread_mutex_unlock(&decoder->data_mutex);
|
pthread_mutex_unlock(&codec->data_mutex);
|
||||||
|
|
||||||
pthread_join(decoder->thread, NULL);
|
pthread_join(codec->thread, NULL);
|
||||||
|
|
||||||
pthread_mutex_destroy(&decoder->start_mutex);
|
pthread_mutex_destroy(&codec->start_mutex);
|
||||||
pthread_mutex_destroy(&decoder->decode_mutex);
|
pthread_mutex_destroy(&codec->codec_mutex);
|
||||||
pthread_mutex_destroy(&decoder->data_mutex);
|
pthread_mutex_destroy(&codec->data_mutex);
|
||||||
pthread_cond_destroy(&decoder->start_cond);
|
pthread_cond_destroy(&codec->start_cond);
|
||||||
pthread_cond_destroy(&decoder->decode_cond);
|
pthread_cond_destroy(&codec->codec_cond);
|
||||||
pthread_cond_destroy(&decoder->data_cond);
|
pthread_cond_destroy(&codec->data_cond);
|
||||||
#endif
|
#endif
|
||||||
free (decoder);
|
free (codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode data using an incremental decoder */
|
* Push a data buffer for an incremental codec */
|
||||||
int
|
int
|
||||||
ImagingIncrementalDecodeData(ImagingIncrementalDecoder decoder,
|
ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec,
|
||||||
UINT8 *buf, int bytes)
|
UINT8 *buf, int bytes)
|
||||||
{
|
{
|
||||||
if (!decoder->started) {
|
if (!codec->started) {
|
||||||
DEBUG("starting\n");
|
DEBUG("starting\n");
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ResumeThread(decoder->hThread);
|
ResumeThread(codec->hThread);
|
||||||
#else
|
#else
|
||||||
pthread_cond_signal(&decoder->start_cond);
|
pthread_cond_signal(&codec->start_cond);
|
||||||
#endif
|
#endif
|
||||||
decoder->started = 1;
|
codec->started = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("providing %p, %d\n", buf, bytes);
|
DEBUG("providing %p, %d\n", buf, bytes);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_lock(&decoder->data_mutex);
|
pthread_mutex_lock(&codec->data_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
decoder->stream.buffer = decoder->stream.ptr = buf;
|
codec->stream.buffer = codec->stream.ptr = buf;
|
||||||
decoder->stream.end = buf + bytes;
|
codec->stream.end = buf + bytes;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetEvent(decoder->hDataEvent);
|
SetEvent(codec->hDataEvent);
|
||||||
WaitForSingleObject(decoder->hDecodeEvent);
|
WaitForSingleObject(codec->hCodecEvent);
|
||||||
#else
|
#else
|
||||||
pthread_cond_signal(&decoder->data_cond);
|
pthread_cond_signal(&codec->data_cond);
|
||||||
pthread_mutex_unlock(&decoder->data_mutex);
|
pthread_mutex_unlock(&codec->data_mutex);
|
||||||
|
|
||||||
pthread_mutex_lock(&decoder->decode_mutex);
|
pthread_mutex_lock(&codec->codec_mutex);
|
||||||
pthread_cond_wait(&decoder->decode_cond, &decoder->decode_mutex);
|
pthread_cond_wait(&codec->codec_cond, &codec->codec_mutex);
|
||||||
pthread_mutex_unlock(&decoder->decode_mutex);
|
pthread_mutex_unlock(&codec->codec_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG("got result %d\n", decoder->result);
|
DEBUG("got result %d\n", codec->result);
|
||||||
|
|
||||||
return decoder->result;
|
return codec->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ImagingIncrementalDecoderRead(ImagingIncrementalDecoder decoder,
|
ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec)
|
||||||
|
{
|
||||||
|
return codec->stream.ptr - codec->stream.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ImagingIncrementalCodecRead(ImagingIncrementalCodec codec,
|
||||||
void *buffer, size_t bytes)
|
void *buffer, size_t bytes)
|
||||||
{
|
{
|
||||||
UINT8 *ptr = (UINT8 *)buffer;
|
UINT8 *ptr = (UINT8 *)buffer;
|
||||||
|
@ -308,29 +308,29 @@ ImagingIncrementalDecoderRead(ImagingIncrementalDecoder decoder,
|
||||||
DEBUG("reading (want %llu bytes)\n", (unsigned long long)bytes);
|
DEBUG("reading (want %llu bytes)\n", (unsigned long long)bytes);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_lock(&decoder->data_mutex);
|
pthread_mutex_lock(&codec->data_mutex);
|
||||||
#endif
|
#endif
|
||||||
while (bytes) {
|
while (bytes) {
|
||||||
size_t todo = bytes;
|
size_t todo = bytes;
|
||||||
size_t remaining = decoder->stream.end - decoder->stream.ptr;
|
size_t remaining = codec->stream.end - codec->stream.ptr;
|
||||||
|
|
||||||
if (!remaining) {
|
if (!remaining) {
|
||||||
DEBUG("waiting for data\n");
|
DEBUG("waiting for data\n");
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_lock(&decoder->decode_mutex);
|
pthread_mutex_lock(&codec->codec_mutex);
|
||||||
#endif
|
#endif
|
||||||
decoder->result = (int)(decoder->stream.ptr - decoder->stream.buffer);
|
codec->result = (int)(codec->stream.ptr - codec->stream.buffer);
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
SetEvent(decoder->hDecodeEvent);
|
SetEvent(codec->hCodecEvent);
|
||||||
WaitForSingleObject(decoder->hDataEvent);
|
WaitForSingleObject(codec->hDataEvent);
|
||||||
#else
|
#else
|
||||||
pthread_cond_signal(&decoder->decode_cond);
|
pthread_cond_signal(&codec->codec_cond);
|
||||||
pthread_mutex_unlock(&decoder->decode_mutex);
|
pthread_mutex_unlock(&codec->codec_mutex);
|
||||||
pthread_cond_wait(&decoder->data_cond, &decoder->data_mutex);
|
pthread_cond_wait(&codec->data_cond, &codec->data_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
remaining = decoder->stream.end - decoder->stream.ptr;
|
remaining = codec->stream.end - codec->stream.ptr;
|
||||||
|
|
||||||
DEBUG("got %llu bytes\n", (unsigned long long)remaining);
|
DEBUG("got %llu bytes\n", (unsigned long long)remaining);
|
||||||
}
|
}
|
||||||
|
@ -340,14 +340,14 @@ ImagingIncrementalDecoderRead(ImagingIncrementalDecoder decoder,
|
||||||
if (!todo)
|
if (!todo)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
memcpy (ptr, decoder->stream.ptr, todo);
|
memcpy (ptr, codec->stream.ptr, todo);
|
||||||
decoder->stream.ptr += todo;
|
codec->stream.ptr += todo;
|
||||||
bytes -= todo;
|
bytes -= todo;
|
||||||
done += todo;
|
done += todo;
|
||||||
ptr += todo;
|
ptr += todo;
|
||||||
}
|
}
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_unlock(&decoder->data_mutex);
|
pthread_mutex_unlock(&codec->data_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG("read total %llu bytes\n", (unsigned long long)done);
|
DEBUG("read total %llu bytes\n", (unsigned long long)done);
|
||||||
|
@ -356,7 +356,7 @@ ImagingIncrementalDecoderRead(ImagingIncrementalDecoder decoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t
|
off_t
|
||||||
ImagingIncrementalDecoderSkip(ImagingIncrementalDecoder decoder,
|
ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec,
|
||||||
off_t bytes)
|
off_t bytes)
|
||||||
{
|
{
|
||||||
off_t done = 0;
|
off_t done = 0;
|
||||||
|
@ -364,29 +364,29 @@ ImagingIncrementalDecoderSkip(ImagingIncrementalDecoder decoder,
|
||||||
DEBUG("skipping (want %llu bytes)\n", (unsigned long long)bytes);
|
DEBUG("skipping (want %llu bytes)\n", (unsigned long long)bytes);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_lock(&decoder->data_mutex);
|
pthread_mutex_lock(&codec->data_mutex);
|
||||||
#endif
|
#endif
|
||||||
while (bytes) {
|
while (bytes) {
|
||||||
off_t todo = bytes;
|
off_t todo = bytes;
|
||||||
off_t remaining = decoder->stream.end - decoder->stream.ptr;
|
off_t remaining = codec->stream.end - codec->stream.ptr;
|
||||||
|
|
||||||
if (!remaining) {
|
if (!remaining) {
|
||||||
DEBUG("waiting for data\n");
|
DEBUG("waiting for data\n");
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_lock(&decoder->decode_mutex);
|
pthread_mutex_lock(&codec->codec_mutex);
|
||||||
#endif
|
#endif
|
||||||
decoder->result = (int)(decoder->stream.ptr - decoder->stream.buffer);
|
codec->result = (int)(codec->stream.ptr - codec->stream.buffer);
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
SetEvent(decoder->hDecodeEvent);
|
SetEvent(codec->hCodecEvent);
|
||||||
WaitForSingleObject(decoder->hDataEvent);
|
WaitForSingleObject(codec->hDataEvent);
|
||||||
#else
|
#else
|
||||||
pthread_cond_signal(&decoder->decode_cond);
|
pthread_cond_signal(&codec->codec_cond);
|
||||||
pthread_mutex_unlock(&decoder->decode_mutex);
|
pthread_mutex_unlock(&codec->codec_mutex);
|
||||||
pthread_cond_wait(&decoder->data_cond, &decoder->data_mutex);
|
pthread_cond_wait(&codec->data_cond, &codec->data_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
remaining = decoder->stream.end - decoder->stream.ptr;
|
remaining = codec->stream.end - codec->stream.ptr;
|
||||||
}
|
}
|
||||||
if (todo > remaining)
|
if (todo > remaining)
|
||||||
todo = remaining;
|
todo = remaining;
|
||||||
|
@ -394,12 +394,12 @@ ImagingIncrementalDecoderSkip(ImagingIncrementalDecoder decoder,
|
||||||
if (!todo)
|
if (!todo)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
decoder->stream.ptr += todo;
|
codec->stream.ptr += todo;
|
||||||
bytes -= todo;
|
bytes -= todo;
|
||||||
done += todo;
|
done += todo;
|
||||||
}
|
}
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
pthread_mutex_unlock(&decoder->data_mutex);
|
pthread_mutex_unlock(&codec->data_mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG("skipped total %llu bytes\n", (unsigned long long)done);
|
DEBUG("skipped total %llu bytes\n", (unsigned long long)done);
|
||||||
|
@ -407,3 +407,59 @@ ImagingIncrementalDecoderSkip(ImagingIncrementalDecoder decoder,
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec,
|
||||||
|
const void *buffer, size_t bytes)
|
||||||
|
{
|
||||||
|
const UINT8 *ptr = (const UINT8 *)buffer;
|
||||||
|
size_t done = 0;
|
||||||
|
|
||||||
|
DEBUG("write (have %llu bytes)\n", (unsigned long long)bytes);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
pthread_mutex_lock(&codec->data_mutex);
|
||||||
|
#endif
|
||||||
|
while (bytes) {
|
||||||
|
size_t todo = bytes;
|
||||||
|
size_t remaining = codec->stream.end - codec->stream.ptr;
|
||||||
|
|
||||||
|
if (!remaining) {
|
||||||
|
DEBUG("waiting for space\n");
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
pthread_mutex_lock(&codec->codec_mutex);
|
||||||
|
#endif
|
||||||
|
codec->result = (int)(codec->stream.ptr - codec->stream.buffer);
|
||||||
|
#if _WIN32
|
||||||
|
SetEvent(codec->hCodecEvent);
|
||||||
|
WaitForSingleObject(codec->hDataEvent);
|
||||||
|
#else
|
||||||
|
pthread_cond_signal(&codec->codec_cond);
|
||||||
|
pthread_mutex_unlock(&codec->codec_mutex);
|
||||||
|
pthread_cond_wait(&codec->data_cond, &codec->data_mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
remaining = codec->stream.end - codec->stream.ptr;
|
||||||
|
|
||||||
|
DEBUG("got %llu bytes\n", (unsigned long long)remaining);
|
||||||
|
}
|
||||||
|
if (todo > remaining)
|
||||||
|
todo = remaining;
|
||||||
|
|
||||||
|
if (!todo)
|
||||||
|
break;
|
||||||
|
|
||||||
|
memcpy (codec->stream.ptr, ptr, todo);
|
||||||
|
codec->stream.ptr += todo;
|
||||||
|
bytes -= todo;
|
||||||
|
done += todo;
|
||||||
|
ptr += todo;
|
||||||
|
}
|
||||||
|
#ifndef _WIN32
|
||||||
|
pthread_mutex_unlock(&codec->data_mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEBUG("wrote total %llu bytes\n", (unsigned long long)done);
|
||||||
|
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
|
@ -12,13 +12,11 @@
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Decoder */
|
/* Decoder */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* CONFIGURATION */
|
/* CONFIGURATION */
|
||||||
|
|
||||||
/* Output mode */
|
|
||||||
char mode[8];
|
|
||||||
|
|
||||||
/* Specify the desired format */
|
/* Specify the desired format */
|
||||||
OPJ_CODEC_FORMAT format;
|
OPJ_CODEC_FORMAT format;
|
||||||
|
|
||||||
|
@ -31,10 +29,50 @@ typedef struct {
|
||||||
/* PRIVATE CONTEXT (set by decoder) */
|
/* PRIVATE CONTEXT (set by decoder) */
|
||||||
const char *error_msg;
|
const char *error_msg;
|
||||||
|
|
||||||
ImagingIncrementalDecoder decoder;
|
ImagingIncrementalCodec decoder;
|
||||||
|
} JPEG2KDECODESTATE;
|
||||||
|
|
||||||
opj_stream_t *stream;
|
/* -------------------------------------------------------------------- */
|
||||||
} JPEG2KSTATE;
|
/* Encoder */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* CONFIGURATION */
|
||||||
|
|
||||||
|
/* Specify the desired format */
|
||||||
|
OPJ_CODEC_FORMAT format;
|
||||||
|
|
||||||
|
/* Image offset */
|
||||||
|
int offset_x, offset_y;
|
||||||
|
|
||||||
|
/* Tile information */
|
||||||
|
int tile_offset_x, tile_offset_y;
|
||||||
|
int tile_size_x, tile_size_y;
|
||||||
|
|
||||||
|
/* Quality layers (a sequence of numbers giving *either* rates or dB) */
|
||||||
|
int quality_is_in_db;
|
||||||
|
PyObject *quality_layers;
|
||||||
|
|
||||||
|
/* Number of resolutions (DWT decompositions + 1 */
|
||||||
|
int num_resolutions;
|
||||||
|
|
||||||
|
/* Code block size */
|
||||||
|
int cblk_width, cblk_height;
|
||||||
|
|
||||||
|
/* Compression style */
|
||||||
|
int irreversible;
|
||||||
|
|
||||||
|
/* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */
|
||||||
|
OPJ_PROG_ORDER progression;
|
||||||
|
|
||||||
|
/* Cinema mode */
|
||||||
|
OPJ_CINEMA_MODE cinema_mode;
|
||||||
|
|
||||||
|
/* PRIVATE CONTEXT (set by decoder) */
|
||||||
|
const char *error_msg;
|
||||||
|
|
||||||
|
ImagingIncrementalCodec encoder;
|
||||||
|
} JPEG2KENCODESTATE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
|
|
|
@ -34,7 +34,7 @@ typedef struct {
|
||||||
static void
|
static void
|
||||||
j2k_error(const char *msg, void *client_data)
|
j2k_error(const char *msg, void *client_data)
|
||||||
{
|
{
|
||||||
JPEG2KSTATE *state = (JPEG2KSTATE *) client_data;
|
JPEG2KDECODESTATE *state = (JPEG2KDECODESTATE *) client_data;
|
||||||
free((void *)state->error_msg);
|
free((void *)state->error_msg);
|
||||||
state->error_msg = strdup(msg);
|
state->error_msg = strdup(msg);
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,9 @@ j2k_error(const char *msg, void *client_data)
|
||||||
static OPJ_SIZE_T
|
static OPJ_SIZE_T
|
||||||
j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
|
j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
|
||||||
{
|
{
|
||||||
ImagingIncrementalDecoder decoder = (ImagingIncrementalDecoder)p_user_data;
|
ImagingIncrementalCodec decoder = (ImagingIncrementalCodec)p_user_data;
|
||||||
|
|
||||||
size_t len = ImagingIncrementalDecoderRead(decoder, p_buffer, p_nb_bytes);
|
size_t len = ImagingIncrementalCodecRead(decoder, p_buffer, p_nb_bytes);
|
||||||
|
|
||||||
return len ? len : (OPJ_SIZE_T)-1;
|
return len ? len : (OPJ_SIZE_T)-1;
|
||||||
}
|
}
|
||||||
|
@ -65,8 +65,8 @@ j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
|
||||||
static OPJ_OFF_T
|
static OPJ_OFF_T
|
||||||
j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
|
j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
|
||||||
{
|
{
|
||||||
ImagingIncrementalDecoder decoder = (ImagingIncrementalDecoder)p_user_data;
|
ImagingIncrementalCodec decoder = (ImagingIncrementalCodec)p_user_data;
|
||||||
off_t pos = ImagingIncrementalDecoderSkip(decoder, p_nb_bytes);
|
off_t pos = ImagingIncrementalCodecSkip(decoder, p_nb_bytes);
|
||||||
|
|
||||||
return pos ? pos : (OPJ_OFF_T)-1;
|
return pos ? pos : (OPJ_OFF_T)-1;
|
||||||
}
|
}
|
||||||
|
@ -455,9 +455,9 @@ enum {
|
||||||
|
|
||||||
static int
|
static int
|
||||||
j2k_decode_entry(Imaging im, ImagingCodecState state,
|
j2k_decode_entry(Imaging im, ImagingCodecState state,
|
||||||
ImagingIncrementalDecoder decoder)
|
ImagingIncrementalCodec decoder)
|
||||||
{
|
{
|
||||||
JPEG2KSTATE *context = (JPEG2KSTATE *) state->context;
|
JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context;
|
||||||
opj_stream_t *stream = NULL;
|
opj_stream_t *stream = NULL;
|
||||||
opj_image_t *image = NULL;
|
opj_image_t *image = NULL;
|
||||||
opj_codec_t *codec = NULL;
|
opj_codec_t *codec = NULL;
|
||||||
|
@ -482,7 +482,6 @@ j2k_decode_entry(Imaging im, ImagingCodecState state,
|
||||||
|
|
||||||
opj_stream_set_user_data(stream, context->decoder);
|
opj_stream_set_user_data(stream, context->decoder);
|
||||||
|
|
||||||
|
|
||||||
/* Setup decompression context */
|
/* Setup decompression context */
|
||||||
context->error_msg = NULL;
|
context->error_msg = NULL;
|
||||||
|
|
||||||
|
@ -559,7 +558,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state,
|
||||||
for (n = 0; n < sizeof(j2k_unpackers) / sizeof (j2k_unpackers[0]); ++n) {
|
for (n = 0; n < sizeof(j2k_unpackers) / sizeof (j2k_unpackers[0]); ++n) {
|
||||||
if (color_space == j2k_unpackers[n].color_space
|
if (color_space == j2k_unpackers[n].color_space
|
||||||
&& image->numcomps == j2k_unpackers[n].components
|
&& image->numcomps == j2k_unpackers[n].components
|
||||||
&& strcmp (context->mode, j2k_unpackers[n].mode) == 0) {
|
&& strcmp (im->mode, j2k_unpackers[n].mode) == 0) {
|
||||||
unpack = j2k_unpackers[n].unpacker;
|
unpack = j2k_unpackers[n].unpacker;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -617,6 +616,14 @@ j2k_decode_entry(Imaging im, ImagingCodecState state,
|
||||||
unpack(image, &tile_info, state->buffer, im);
|
unpack(image, &tile_info, state->buffer, im);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!opj_end_decompress(codec, stream)) {
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
state->state = J2K_STATE_FAILED;
|
||||||
|
goto quick_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->state = J2K_STATE_DONE;
|
||||||
|
|
||||||
quick_exit:
|
quick_exit:
|
||||||
if (codec)
|
if (codec)
|
||||||
opj_destroy_codec(codec);
|
opj_destroy_codec(codec);
|
||||||
|
@ -631,14 +638,14 @@ j2k_decode_entry(Imaging im, ImagingCodecState state,
|
||||||
int
|
int
|
||||||
ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
{
|
{
|
||||||
JPEG2KSTATE *context = (JPEG2KSTATE *) state->context;
|
JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context;
|
||||||
|
|
||||||
if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED)
|
if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (state->state == J2K_STATE_START) {
|
if (state->state == J2K_STATE_START) {
|
||||||
context->decoder = ImagingIncrementalDecoderCreate(j2k_decode_entry,
|
context->decoder = ImagingIncrementalCodecCreate(j2k_decode_entry,
|
||||||
im, state);
|
im, state);
|
||||||
|
|
||||||
if (!context->decoder) {
|
if (!context->decoder) {
|
||||||
state->errcode = IMAGING_CODEC_BROKEN;
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
@ -649,7 +656,7 @@ ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
state->state = J2K_STATE_DECODING;
|
state->state = J2K_STATE_DECODING;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImagingIncrementalDecodeData(context->decoder, buf, bytes);
|
return ImagingIncrementalCodecPushBuffer(context->decoder, buf, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -658,10 +665,13 @@ ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
|
|
||||||
int
|
int
|
||||||
ImagingJpeg2KDecodeCleanup(ImagingCodecState state) {
|
ImagingJpeg2KDecodeCleanup(ImagingCodecState state) {
|
||||||
JPEG2KSTATE *context = (JPEG2KSTATE *)state->context;
|
JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *)state->context;
|
||||||
|
|
||||||
|
if (context->error_msg)
|
||||||
|
free ((void *)context->error_msg);
|
||||||
|
|
||||||
if (context->decoder)
|
if (context->decoder)
|
||||||
ImagingIncrementalDecoderDestroy(context->decoder);
|
ImagingIncrementalCodecDestroy(context->decoder);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
548
libImaging/Jpeg2KEncode.c
Normal file
548
libImaging/Jpeg2KEncode.c
Normal file
|
@ -0,0 +1,548 @@
|
||||||
|
/*
|
||||||
|
* The Python Imaging Library.
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* decoder for JPEG2000 image data.
|
||||||
|
*
|
||||||
|
* history:
|
||||||
|
* 2014-03-12 ajh Created
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Coriolis Systems Limited
|
||||||
|
* Copyright (c) 2014 Alastair Houghton
|
||||||
|
*
|
||||||
|
* See the README file for details on usage and redistribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Imaging.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENJPEG
|
||||||
|
|
||||||
|
#include "Jpeg2K.h"
|
||||||
|
|
||||||
|
#define CINEMA_24_CS_LENGTH 1302083
|
||||||
|
#define CINEMA_48_CS_LENGTH 651041
|
||||||
|
#define COMP_24_CS_MAX_LENGTH 1041666
|
||||||
|
#define COMP_48_CS_MAX_LENGTH 520833
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* Error handler */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void
|
||||||
|
j2k_error(const char *msg, void *client_data)
|
||||||
|
{
|
||||||
|
JPEG2KENCODESTATE *state = (JPEG2KENCODESTATE *) client_data;
|
||||||
|
free((void *)state->error_msg);
|
||||||
|
state->error_msg = strdup(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* Buffer output stream */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static OPJ_SIZE_T
|
||||||
|
j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
|
||||||
|
{
|
||||||
|
/* This should never happen */
|
||||||
|
fprintf (stderr, "OpenJPEG has read from our write stream(!)");
|
||||||
|
abort();
|
||||||
|
return (OPJ_SIZE_T)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OPJ_SIZE_T
|
||||||
|
j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
|
||||||
|
{
|
||||||
|
ImagingIncrementalCodec encoder = (ImagingIncrementalCodec)p_user_data;
|
||||||
|
size_t len = ImagingIncrementalCodecWrite(encoder, p_buffer, p_nb_bytes);
|
||||||
|
|
||||||
|
return len ? len : (OPJ_SIZE_T)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OPJ_OFF_T
|
||||||
|
j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
|
||||||
|
{
|
||||||
|
ImagingIncrementalCodec decoder = (ImagingIncrementalCodec)p_user_data;
|
||||||
|
off_t pos = ImagingIncrementalCodecSkip(decoder, p_nb_bytes);
|
||||||
|
|
||||||
|
return pos ? pos : (OPJ_OFF_T)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OPJ_BOOL
|
||||||
|
j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data)
|
||||||
|
{
|
||||||
|
/* This should never happen */
|
||||||
|
fprintf(stderr, "OpenJPEG tried to seek our write stream(!)");
|
||||||
|
abort();
|
||||||
|
return OPJ_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* Encoder */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef void (*j2k_pack_tile_t)(Imaging im, UINT8 *buf,
|
||||||
|
unsigned x0, unsigned y0,
|
||||||
|
unsigned w, unsigned h);
|
||||||
|
|
||||||
|
static void
|
||||||
|
j2k_pack_l(Imaging im, UINT8 *buf,
|
||||||
|
unsigned x0, unsigned y0, unsigned w, unsigned h)
|
||||||
|
{
|
||||||
|
UINT8 *ptr = buf;
|
||||||
|
for (unsigned y = 0; y < h; ++y) {
|
||||||
|
UINT8 *data = (UINT8 *)(im->image[y + y0] + x0);
|
||||||
|
for (unsigned x = 0; x < w; ++x)
|
||||||
|
*ptr++ = *data++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
j2k_pack_la(Imaging im, UINT8 *buf,
|
||||||
|
unsigned x0, unsigned y0, unsigned w, unsigned h)
|
||||||
|
{
|
||||||
|
UINT8 *ptr = buf;
|
||||||
|
UINT8 *ptra = buf + w * h;
|
||||||
|
for (unsigned y = 0; y < h; ++y) {
|
||||||
|
UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
|
||||||
|
for (unsigned x = 0; x < w; ++x) {
|
||||||
|
*ptr++ = data[0];
|
||||||
|
*ptra++ = data[3];
|
||||||
|
data += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
j2k_pack_rgb(Imaging im, UINT8 *buf,
|
||||||
|
unsigned x0, unsigned y0, unsigned w, unsigned h)
|
||||||
|
{
|
||||||
|
UINT8 *pr = buf;
|
||||||
|
UINT8 *pg = pr + w * h;
|
||||||
|
UINT8 *pb = pg + w * h;
|
||||||
|
for (unsigned y = 0; y < h; ++y) {
|
||||||
|
UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
|
||||||
|
for (unsigned x = 0; x < w; ++x) {
|
||||||
|
*pr++ = data[0];
|
||||||
|
*pg++ = data[1];
|
||||||
|
*pb++ = data[2];
|
||||||
|
data += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
j2k_pack_rgba(Imaging im, UINT8 *buf,
|
||||||
|
unsigned x0, unsigned y0, unsigned w, unsigned h)
|
||||||
|
{
|
||||||
|
UINT8 *pr = buf;
|
||||||
|
UINT8 *pg = pr + w * h;
|
||||||
|
UINT8 *pb = pg + w * h;
|
||||||
|
UINT8 *pa = pb + w * h;
|
||||||
|
for (unsigned y = 0; y < h; ++y) {
|
||||||
|
UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
|
||||||
|
for (unsigned x = 0; x < w; ++x) {
|
||||||
|
*pr++ = *data++;
|
||||||
|
*pg++ = *data++;
|
||||||
|
*pb++ = *data++;
|
||||||
|
*pa++ = *data++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
J2K_STATE_START = 0,
|
||||||
|
J2K_STATE_ENCODING = 1,
|
||||||
|
J2K_STATE_DONE = 2,
|
||||||
|
J2K_STATE_FAILED = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params)
|
||||||
|
{
|
||||||
|
float rate;
|
||||||
|
unsigned n;
|
||||||
|
|
||||||
|
/* These settings have been copied from opj_compress in the OpenJPEG
|
||||||
|
sources. */
|
||||||
|
|
||||||
|
params->tile_size_on = OPJ_FALSE;
|
||||||
|
params->cp_tdx = params->cp_tdy = 1;
|
||||||
|
params->tp_flag = 'C';
|
||||||
|
params->tp_on = 1;
|
||||||
|
params->cp_tx0 = params->cp_ty0 = 0;
|
||||||
|
params->image_offset_x0 = params->image_offset_y0 = 0;
|
||||||
|
params->cblockw_init = 32;
|
||||||
|
params->cblockh_init = 32;
|
||||||
|
params->csty |= 0x01;
|
||||||
|
params->prog_order = OPJ_CPRL;
|
||||||
|
params->roi_compno = -1;
|
||||||
|
params->subsampling_dx = params->subsampling_dy = 1;
|
||||||
|
params->irreversible = 1;
|
||||||
|
|
||||||
|
if (params->cp_cinema == OPJ_CINEMA4K_24) {
|
||||||
|
float max_rate = ((float)(components * im->xsize * im->ysize * 8)
|
||||||
|
/ (CINEMA_24_CS_LENGTH * 8));
|
||||||
|
|
||||||
|
params->POC[0].tile = 1;
|
||||||
|
params->POC[0].resno0 = 0;
|
||||||
|
params->POC[0].compno0 = 0;
|
||||||
|
params->POC[0].layno1 = 1;
|
||||||
|
params->POC[0].resno1 = params->numresolution - 1;
|
||||||
|
params->POC[0].compno1 = 3;
|
||||||
|
params->POC[0].prg1 = OPJ_CPRL;
|
||||||
|
params->POC[1].tile = 1;
|
||||||
|
params->POC[1].resno0 = 0;
|
||||||
|
params->POC[1].compno0 = 0;
|
||||||
|
params->POC[1].layno1 = 1;
|
||||||
|
params->POC[1].resno1 = params->numresolution - 1;
|
||||||
|
params->POC[1].compno1 = 3;
|
||||||
|
params->POC[1].prg1 = OPJ_CPRL;
|
||||||
|
params->numpocs = 2;
|
||||||
|
|
||||||
|
for (n = 0; n < params->tcp_numlayers; ++n) {
|
||||||
|
rate = 0;
|
||||||
|
if (params->tcp_rates[0] == 0) {
|
||||||
|
params->tcp_rates[n] = max_rate;
|
||||||
|
} else {
|
||||||
|
rate = ((float)(components * im->xsize * im->ysize * 8)
|
||||||
|
/ (params->tcp_rates[n] * 8));
|
||||||
|
if (rate > CINEMA_24_CS_LENGTH)
|
||||||
|
params->tcp_rates[n] = max_rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params->max_comp_size = COMP_24_CS_MAX_LENGTH;
|
||||||
|
} else {
|
||||||
|
float max_rate = ((float)(components * im->xsize * im->ysize * 8)
|
||||||
|
/ (CINEMA_48_CS_LENGTH * 8));
|
||||||
|
|
||||||
|
for (n = 0; n < params->tcp_numlayers; ++n) {
|
||||||
|
rate = 0;
|
||||||
|
if (params->tcp_rates[0] == 0) {
|
||||||
|
params->tcp_rates[n] = max_rate;
|
||||||
|
} else {
|
||||||
|
rate = ((float)(components * im->xsize * im->ysize * 8)
|
||||||
|
/ (params->tcp_rates[n] * 8));
|
||||||
|
if (rate > CINEMA_48_CS_LENGTH)
|
||||||
|
params->tcp_rates[n] = max_rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params->max_comp_size = COMP_48_CS_MAX_LENGTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
j2k_encode_entry(Imaging im, ImagingCodecState state,
|
||||||
|
ImagingIncrementalCodec encoder)
|
||||||
|
{
|
||||||
|
JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
|
||||||
|
opj_stream_t *stream = NULL;
|
||||||
|
opj_image_t *image = NULL;
|
||||||
|
opj_codec_t *codec = NULL;
|
||||||
|
opj_cparameters_t params;
|
||||||
|
unsigned components;
|
||||||
|
OPJ_COLOR_SPACE color_space;
|
||||||
|
opj_image_cmptparm_t image_params[4];
|
||||||
|
unsigned xsiz, ysiz;
|
||||||
|
unsigned tile_width, tile_height;
|
||||||
|
unsigned tiles_x, tiles_y, num_tiles;
|
||||||
|
unsigned x, y, tile_ndx;
|
||||||
|
j2k_pack_tile_t pack;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
stream = opj_stream_default_create(OPJ_FALSE);
|
||||||
|
|
||||||
|
if (!stream) {
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
state->state = J2K_STATE_FAILED;
|
||||||
|
goto quick_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
opj_stream_set_read_function(stream, j2k_read);
|
||||||
|
opj_stream_set_write_function(stream, j2k_write);
|
||||||
|
opj_stream_set_skip_function(stream, j2k_skip);
|
||||||
|
opj_stream_set_seek_function(stream, j2k_seek);
|
||||||
|
|
||||||
|
opj_stream_set_user_data(stream, context->encoder);
|
||||||
|
|
||||||
|
/* Setup an opj_image */
|
||||||
|
if (strcmp (im->mode, "L") == 0) {
|
||||||
|
components = 1;
|
||||||
|
color_space = OPJ_CLRSPC_GRAY;
|
||||||
|
pack = j2k_pack_l;
|
||||||
|
} else if (strcmp (im->mode, "LA") == 0) {
|
||||||
|
components = 2;
|
||||||
|
color_space = OPJ_CLRSPC_GRAY;
|
||||||
|
pack = j2k_pack_la;
|
||||||
|
} else if (strcmp (im->mode, "RGB") == 0) {
|
||||||
|
components = 3;
|
||||||
|
color_space = OPJ_CLRSPC_SRGB;
|
||||||
|
pack = j2k_pack_rgb;
|
||||||
|
} else if (strcmp (im->mode, "YCbCr") == 0) {
|
||||||
|
components = 3;
|
||||||
|
color_space = OPJ_CLRSPC_SYCC;
|
||||||
|
pack = j2k_pack_rgb;
|
||||||
|
} else if (strcmp (im->mode, "RGBA") == 0) {
|
||||||
|
components = 4;
|
||||||
|
color_space = OPJ_CLRSPC_SRGB;
|
||||||
|
pack = j2k_pack_rgba;
|
||||||
|
} else {
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
state->state = J2K_STATE_FAILED;
|
||||||
|
goto quick_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned n = 0; n < components; ++n) {
|
||||||
|
image_params[n].dx = image_params[n].dy = 1;
|
||||||
|
image_params[n].w = im->xsize;
|
||||||
|
image_params[n].h = im->ysize;
|
||||||
|
image_params[n].x0 = image_params[n].y0 = 0;
|
||||||
|
image_params[n].prec = 8;
|
||||||
|
image_params[n].bpp = 8;
|
||||||
|
image_params[n].sgnd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = opj_image_create(components, image_params, color_space);
|
||||||
|
|
||||||
|
/* Setup compression context */
|
||||||
|
context->error_msg = NULL;
|
||||||
|
|
||||||
|
opj_set_default_encoder_parameters(¶ms);
|
||||||
|
|
||||||
|
params.image_offset_x0 = context->offset_x;
|
||||||
|
params.image_offset_y0 = context->offset_y;
|
||||||
|
|
||||||
|
if (context->tile_size_x && context->tile_size_y) {
|
||||||
|
params.tile_size_on = OPJ_TRUE;
|
||||||
|
params.cp_tx0 = context->tile_offset_x;
|
||||||
|
params.cp_ty0 = context->tile_offset_y;
|
||||||
|
params.cp_tdx = context->tile_size_x;
|
||||||
|
params.cp_tdy = context->tile_size_y;
|
||||||
|
|
||||||
|
tile_width = params.cp_tdx;
|
||||||
|
tile_height = params.cp_tdy;
|
||||||
|
} else {
|
||||||
|
params.cp_tx0 = 0;
|
||||||
|
params.cp_ty0 = 0;
|
||||||
|
params.cp_tdx = 1;
|
||||||
|
params.cp_tdy = 1;
|
||||||
|
|
||||||
|
tile_width = im->xsize;
|
||||||
|
tile_height = im->ysize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PySequence_Check(context->quality_layers)) {
|
||||||
|
Py_ssize_t len = PySequence_Length(context->quality_layers);
|
||||||
|
Py_ssize_t n;
|
||||||
|
float *pq;
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
if (len > sizeof(params.tcp_rates) / sizeof(params.tcp_rates[0]))
|
||||||
|
len = sizeof(params.tcp_rates)/sizeof(params.tcp_rates[0]);
|
||||||
|
|
||||||
|
params.tcp_numlayers = (int)len;
|
||||||
|
|
||||||
|
if (context->quality_is_in_db) {
|
||||||
|
params.cp_disto_alloc = params.cp_fixed_alloc = 0;
|
||||||
|
params.cp_fixed_quality = 1;
|
||||||
|
pq = params.tcp_distoratio;
|
||||||
|
} else {
|
||||||
|
params.cp_disto_alloc = 1;
|
||||||
|
params.cp_fixed_alloc = params.cp_fixed_quality = 0;
|
||||||
|
pq = params.tcp_rates;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0; n < len; ++n) {
|
||||||
|
PyObject *obj = PySequence_ITEM(context->quality_layers, n);
|
||||||
|
pq[n] = PyFloat_AsDouble(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params.tcp_numlayers = 1;
|
||||||
|
params.tcp_rates[0] = 0;
|
||||||
|
params.cp_disto_alloc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->num_resolutions)
|
||||||
|
params.numresolution = context->num_resolutions;
|
||||||
|
|
||||||
|
if (context->cblk_width >= 4 && context->cblk_width <= 1024
|
||||||
|
&& context->cblk_height >= 4 && context->cblk_height <= 1024
|
||||||
|
&& context->cblk_width * context->cblk_height <= 4096) {
|
||||||
|
params.cblockw_init = context->cblk_width;
|
||||||
|
params.cblockh_init = context->cblk_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.irreversible = context->irreversible;
|
||||||
|
|
||||||
|
params.prog_order = context->progression;
|
||||||
|
|
||||||
|
params.cp_cinema = context->cinema_mode;
|
||||||
|
|
||||||
|
switch (params.cp_cinema) {
|
||||||
|
case OPJ_OFF:
|
||||||
|
params.cp_rsiz = OPJ_STD_RSIZ;
|
||||||
|
break;
|
||||||
|
case OPJ_CINEMA2K_24:
|
||||||
|
case OPJ_CINEMA2K_48:
|
||||||
|
params.cp_rsiz = OPJ_CINEMA2K;
|
||||||
|
if (params.numresolution > 6)
|
||||||
|
params.numresolution = 6;
|
||||||
|
break;
|
||||||
|
case OPJ_CINEMA4K_24:
|
||||||
|
params.cp_rsiz = OPJ_CINEMA4K;
|
||||||
|
if (params.numresolution > 7)
|
||||||
|
params.numresolution = 7;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->cinema_mode != OPJ_OFF)
|
||||||
|
j2k_set_cinema_params(im, components, ¶ms);
|
||||||
|
|
||||||
|
/* Set up the reference grid in the image */
|
||||||
|
image->x0 = params.image_offset_x0;
|
||||||
|
image->y0 = params.image_offset_y0;
|
||||||
|
image->x1 = xsiz = im->xsize + params.image_offset_x0;
|
||||||
|
image->y1 = ysiz = im->ysize + params.image_offset_y0;
|
||||||
|
|
||||||
|
/* Create the compressor */
|
||||||
|
codec = opj_create_compress(context->format);
|
||||||
|
|
||||||
|
if (!codec) {
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
state->state = J2K_STATE_FAILED;
|
||||||
|
goto quick_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
opj_set_error_handler(codec, j2k_error, context);
|
||||||
|
opj_setup_encoder(codec, ¶ms, image);
|
||||||
|
|
||||||
|
/* Start encoding */
|
||||||
|
if (!opj_start_compress(codec, image, stream)) {
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
state->state = J2K_STATE_FAILED;
|
||||||
|
goto quick_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write each tile */
|
||||||
|
tiles_x = (im->xsize + tile_width - 1) / tile_width;
|
||||||
|
tiles_y = (im->ysize + tile_height - 1) / tile_height;
|
||||||
|
num_tiles = tiles_x * tiles_y;
|
||||||
|
|
||||||
|
state->buffer = malloc (tile_width * tile_height * components);
|
||||||
|
|
||||||
|
tile_ndx = 0;
|
||||||
|
for (y = 0; y < tiles_y; ++y) {
|
||||||
|
unsigned ty0 = params.cp_ty0 + y * tile_height;
|
||||||
|
unsigned ty1 = ty0 + tile_height;
|
||||||
|
unsigned pixy, pixh;
|
||||||
|
|
||||||
|
if (ty0 < params.image_offset_y0)
|
||||||
|
ty0 = params.image_offset_y0;
|
||||||
|
if (ty1 > ysiz)
|
||||||
|
ty1 = ysiz;
|
||||||
|
|
||||||
|
pixy = ty0 - params.image_offset_y0;
|
||||||
|
pixh = ty1 - ty0;
|
||||||
|
|
||||||
|
for (x = 0; x < tiles_x; ++x) {
|
||||||
|
unsigned tx0 = params.cp_tx0 + x * tile_width;
|
||||||
|
unsigned tx1 = tx0 + tile_width;
|
||||||
|
unsigned pixx, pixw;
|
||||||
|
unsigned data_size;
|
||||||
|
|
||||||
|
if (tx0 < params.image_offset_x0)
|
||||||
|
tx0 = params.image_offset_x0;
|
||||||
|
if (tx1 > xsiz)
|
||||||
|
tx1 = xsiz;
|
||||||
|
|
||||||
|
pixx = tx0 - params.image_offset_x0;
|
||||||
|
pixw = tx1 - tx0;
|
||||||
|
|
||||||
|
pack(im, state->buffer, pixx, pixy, pixw, pixh);
|
||||||
|
|
||||||
|
data_size = pixw * pixh * components;
|
||||||
|
|
||||||
|
if (!opj_write_tile(codec, tile_ndx++, state->buffer,
|
||||||
|
data_size, stream)) {
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
state->state = J2K_STATE_FAILED;
|
||||||
|
goto quick_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opj_end_compress(codec, stream)) {
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
state->state = J2K_STATE_FAILED;
|
||||||
|
goto quick_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->errcode = IMAGING_CODEC_END;
|
||||||
|
state->state = J2K_STATE_DONE;
|
||||||
|
ret = (int)ImagingIncrementalCodecBytesInBuffer(encoder);
|
||||||
|
|
||||||
|
quick_exit:
|
||||||
|
if (codec)
|
||||||
|
opj_destroy_codec(codec);
|
||||||
|
if (image)
|
||||||
|
opj_image_destroy(image);
|
||||||
|
if (stream)
|
||||||
|
opj_stream_destroy(stream);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes)
|
||||||
|
{
|
||||||
|
JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
|
||||||
|
|
||||||
|
if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (state->state == J2K_STATE_START) {
|
||||||
|
context->encoder = ImagingIncrementalCodecCreate(j2k_encode_entry,
|
||||||
|
im, state);
|
||||||
|
|
||||||
|
if (!context->encoder) {
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
state->state = J2K_STATE_FAILED;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->state = J2K_STATE_ENCODING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ImagingIncrementalCodecPushBuffer(context->encoder, buf, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* Cleanup */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
int
|
||||||
|
ImagingJpeg2KEncodeCleanup(ImagingCodecState state) {
|
||||||
|
JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
|
||||||
|
|
||||||
|
if (context->quality_layers)
|
||||||
|
Py_DECREF(context->quality_layers);
|
||||||
|
|
||||||
|
if (context->error_msg)
|
||||||
|
free ((void *)context->error_msg);
|
||||||
|
|
||||||
|
if (context->encoder)
|
||||||
|
ImagingIncrementalCodecDestroy(context->encoder);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_OPENJPEG */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* End:
|
||||||
|
*
|
||||||
|
*/
|
2
setup.py
2
setup.py
|
@ -34,7 +34,7 @@ _LIB_IMAGING = (
|
||||||
"RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
|
"RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
|
||||||
"TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
|
"TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
|
||||||
"XbmEncode", "ZipDecode", "ZipEncode", "TiffDecode", "Incremental",
|
"XbmEncode", "ZipDecode", "ZipEncode", "TiffDecode", "Incremental",
|
||||||
"Jpeg2KDecode")
|
"Jpeg2KDecode", "Jpeg2KEncode")
|
||||||
|
|
||||||
|
|
||||||
def _add_directory(path, dir, where=None):
|
def _add_directory(path, dir, where=None):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user