diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py index 94d49f705..6b1a36f3f 100644 --- a/PIL/Jpeg2KImagePlugin.py +++ b/PIL/Jpeg2KImagePlugin.py @@ -156,9 +156,13 @@ class Jpeg2KImageFile(ImageFile.ImageFile): self.reduce = 0 self.layers = 0 + fd = -1 + if hasattr(self.fp, "fileno"): + fd = self.fp.fileno() + self.tile = [('jpeg2k', (0, 0) + self.size, 0, - (self.codec, self.reduce, self.layers))] + (self.codec, self.reduce, self.layers, fd))] def load(self): if self.reduce: @@ -181,6 +185,38 @@ def _save(im, fp, filename): kind = 'j2k' else: kind = 'jp2' + + # Get the keyword arguments + info = im.encoderinfo + + offset = info.get('offset', None) + tile_offset = info.get('tile_offset', None) + tile_size = info.get('tile_size', None) + quality_mode = info.get('quality_mode', 'rates') + quality_layers = info.get('quality_layers', None) + num_resolutions = info.get('num_resolutions', 0) + cblk_size = info.get('codeblock_size', None) + irreversible = info.get('irreversible', False) + progression = info.get('progression', 'LRCP') + cinema_mode = info.get('cinema_mode', 'no') + fd = -1 + + if hasattr(fp, "fileno"): + fd = fp.fileno() + + im.encoderconfig = ( + offset, + tile_offset, + tile_size, + quality_mode, + quality_layers, + num_resolutions, + cblk_size, + irreversible, + progression, + cinema_mode, + fd + ) ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)]) diff --git a/decode.c b/decode.c index 0bc64ec77..f3eaa9a50 100644 --- a/decode.c +++ b/decode.c @@ -796,8 +796,9 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args) OPJ_CODEC_FORMAT codec_format; int reduce = 0; int layers = 0; - if (!PyArg_ParseTuple(args, "ss|ii", &mode, &format, - &reduce, &layers)) + int fd = -1; + if (!PyArg_ParseTuple(args, "ss|iii", &mode, &format, + &reduce, &layers, &fd)) return NULL; if (strcmp(format, "j2k") == 0) @@ -819,6 +820,7 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args) context = (JPEG2KDECODESTATE *)decoder->state.context; + context->fd = fd; context->format = codec_format; context->reduce = reduce; context->layers = layers; diff --git a/encode.c b/encode.c index 979742a84..52777cc0c 100644 --- a/encode.c +++ b/encode.c @@ -837,16 +837,18 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) PyObject *quality_layers = NULL; int num_resolutions = 0; PyObject *cblk_size = NULL; - int irreversible = 0; + PyObject *irreversible = NULL; char *progression = "LRCP"; OPJ_PROG_ORDER prog_order; char *cinema_mode = "no"; OPJ_CINEMA_MODE cine_mode; + int fd = -1; - if (!PyArg_ParseTuple(args, "ss|OOOsOiOpss", &mode, &format, + if (!PyArg_ParseTuple(args, "ss|OOOsOIOOssi", &mode, &format, &offset, &tile_offset, &tile_size, &quality_mode, &quality_layers, &num_resolutions, - &cblk_size, &irreversible, &progression, &cinema_mode)) + &cblk_size, &irreversible, &progression, &cinema_mode, + &fd)) return NULL; if (strcmp (format, "j2k") == 0) @@ -891,6 +893,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) context = (JPEG2KENCODESTATE *)encoder->state.context; + context->fd = fd; context->format = codec_format; context->offset_x = context->offset_y = 0; @@ -905,6 +908,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) if (quality_layers && PySequence_Check(quality_layers)) { context->quality_is_in_db = strcmp (quality_mode, "dB") == 0; context->quality_layers = quality_layers; + Py_INCREF(quality_layers); } context->num_resolutions = num_resolutions; @@ -913,7 +917,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) &context->cblk_width, &context->cblk_height); - context->irreversible = irreversible; + context->irreversible = PyObject_IsTrue(irreversible); context->progression = prog_order; context->cinema_mode = cine_mode; diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 1602622a2..26207d121 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -512,12 +512,23 @@ typedef int (*ImagingIncrementalCodecEntry)(Imaging im, ImagingCodecState state, ImagingIncrementalCodec codec); -extern ImagingIncrementalCodec ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, Imaging im, ImagingCodecState state); +enum { + INCREMENTAL_CODEC_READ = 1, + INCREMENTAL_CODEC_WRITE = 2 +}; + +enum { + INCREMENTAL_CODEC_NOT_SEEKABLE = 0, + INCREMENTAL_CODEC_SEEKABLE = 1 +}; + +extern ImagingIncrementalCodec ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, Imaging im, ImagingCodecState state, int read_or_write, int seekable, int fd); 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 ssize_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 ssize_t ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, const void *buffer, size_t bytes); +extern off_t ImagingIncrementalCodecSeek(ImagingIncrementalCodec codec, off_t bytes); extern size_t ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec); /* Errcodes */ diff --git a/libImaging/Incremental.c b/libImaging/Incremental.c index 45f064570..bc6a36b3e 100644 --- a/libImaging/Incremental.c +++ b/libImaging/Incremental.c @@ -35,6 +35,11 @@ thinking that the image is truncated, whereas generally you want it to pass the EOF condition (0 bytes to read) through to your code. */ +/* Additional complication: *Some* codecs need to seek; this is fine if + there is a file descriptor, but if we're buffering data it becomes + awkward. The incremental adaptor now contains code to handle these + two cases. */ + #ifdef _WIN32 #include #include @@ -64,18 +69,24 @@ struct ImagingIncrementalCodecStruct { pthread_cond_t data_cond; pthread_t thread; #endif - ImagingIncrementalCodecEntry entry; - Imaging im; - ImagingCodecState state; + ImagingIncrementalCodecEntry entry; + Imaging im; + ImagingCodecState state; struct { - UINT8 *buffer; - UINT8 *ptr; - UINT8 *end; + int fd; + UINT8 *buffer; /* Base of buffer */ + UINT8 *ptr; /* Current pointer in buffer */ + UINT8 *top; /* Highest point in buffer we've used */ + UINT8 *end; /* End of buffer */ } stream; - int started; - int result; + int read_or_write; + int seekable; + int started; + int result; }; +static void flush_stream(ImagingIncrementalCodec codec); + #if _WIN32 static void __stdcall codec_thread(void *ptr) @@ -84,6 +95,8 @@ codec_thread(void *ptr) codec->result = codec->entry(codec->im, codec->state, codec); + flush_stream(codec); + SetEvent(codec->hCodecEvent); } #else @@ -94,18 +107,54 @@ codec_thread(void *ptr) codec->result = codec->entry(codec->im, codec->state, codec); + flush_stream(codec); + + pthread_mutex_lock(&codec->codec_mutex); pthread_cond_signal(&codec->codec_cond); + pthread_mutex_unlock(&codec->codec_mutex); return NULL; } #endif +static void +flush_stream(ImagingIncrementalCodec codec) +{ + /* This is to flush data from the write buffer for a seekable write + codec. */ + if (codec->read_or_write != INCREMENTAL_CODEC_WRITE + || codec->state->errcode != IMAGING_CODEC_END + || !codec->seekable + || codec->stream.fd >= 0) + return; + + DEBUG("flushing data\n"); + + UINT8 *buffer = codec->stream.buffer; + size_t bytes = codec->stream.ptr - codec->stream.buffer; + + codec->state->errcode = 0; + codec->seekable = INCREMENTAL_CODEC_NOT_SEEKABLE; + codec->stream.buffer = codec->stream.ptr = codec->stream.end + = codec->stream.top = NULL; + + ImagingIncrementalCodecWrite(codec, buffer, bytes); + + codec->state->errcode = IMAGING_CODEC_END; + codec->result = (int)ImagingIncrementalCodecBytesInBuffer(codec); + + free(buffer); +} + /** * Create a new incremental codec */ ImagingIncrementalCodec ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, Imaging im, - ImagingCodecState state) + ImagingCodecState state, + int read_or_write, + int seekable, + int fd) { ImagingIncrementalCodec codec = (ImagingIncrementalCodec)malloc(sizeof(struct ImagingIncrementalCodecStruct)); @@ -113,8 +162,15 @@ ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, codec->im = im; codec->state = state; codec->result = 0; - codec->stream.buffer = codec->stream.ptr = codec->stream.end = NULL; + codec->stream.fd = fd; + codec->stream.buffer = codec->stream.ptr = codec->stream.end + = codec->stream.top = NULL; codec->started = 0; + codec->seekable = seekable; + codec->read_or_write = read_or_write; + + if (fd >= 0) + lseek(fd, 0, SEEK_SET); /* System specific set-up */ #if _WIN32 @@ -223,7 +279,11 @@ ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec) pthread_mutex_lock(&codec->data_mutex); #endif - codec->stream.buffer = codec->stream.ptr = codec->stream.end = NULL; + if (codec->seekable && codec->stream.fd < 0) + free (codec->stream.buffer); + + codec->stream.buffer = codec->stream.ptr = codec->stream.end + = codec->stream.top = NULL; #ifdef _WIN32 SetEvent(codec->hDataEvent); @@ -264,6 +324,22 @@ ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec, pthread_cond_signal(&codec->start_cond); #endif codec->started = 1; + + /* Wait for the thread to ask for data */ +#ifdef _WIN32 + WaitForSingleObject(codec->hCodecEvent); +#else + pthread_mutex_lock(&codec->codec_mutex); + pthread_cond_wait(&codec->codec_cond, &codec->codec_mutex); + pthread_mutex_unlock(&codec->codec_mutex); +#endif + } + + /* Codecs using an fd don't need data, so when we get here, we're done */ + if (codec->stream.fd >= 0) { + DEBUG("got result %d\n", codec->result); + + return codec->result; } DEBUG("providing %p, %d\n", buf, bytes); @@ -272,8 +348,30 @@ ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec, pthread_mutex_lock(&codec->data_mutex); #endif - codec->stream.buffer = codec->stream.ptr = buf; - codec->stream.end = buf + bytes; + if (codec->read_or_write == INCREMENTAL_CODEC_READ + && codec->seekable && codec->stream.fd < 0) { + /* In this specific case, we append to a buffer we allocate ourselves */ + size_t old_size = codec->stream.end - codec->stream.buffer; + size_t new_size = codec->stream.end - codec->stream.buffer + bytes; + UINT8 *new = (UINT8 *)realloc (codec->stream.buffer, new_size); + + if (!new) { + codec->state->errcode = IMAGING_CODEC_MEMORY; +#ifndef _WIN32 + pthread_mutex_unlock(&codec->data_mutex); +#endif + return -1; + } + + codec->stream.ptr = codec->stream.ptr - codec->stream.buffer + new; + codec->stream.end = new + new_size; + codec->stream.buffer = new; + + memcpy(new + old_size, buf, bytes); + } else { + codec->stream.buffer = codec->stream.ptr = buf; + codec->stream.end = buf + bytes; + } #ifdef _WIN32 SetEvent(codec->hDataEvent); @@ -298,15 +396,27 @@ ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec) return codec->stream.ptr - codec->stream.buffer; } -size_t +ssize_t ImagingIncrementalCodecRead(ImagingIncrementalCodec codec, void *buffer, size_t bytes) { UINT8 *ptr = (UINT8 *)buffer; size_t done = 0; + if (codec->read_or_write == INCREMENTAL_CODEC_WRITE) { + DEBUG("attempt to read from write codec\n"); + return -1; + } + DEBUG("reading (want %llu bytes)\n", (unsigned long long)bytes); + if (codec->stream.fd >= 0) { + off_t offset = lseek(codec->stream.fd, 0, SEEK_CUR); + ssize_t ret = read(codec->stream.fd, buffer, bytes); + DEBUG("read %lld bytes from fd at %lld\n", (long long)ret, (long long)offset); + return ret; + } + #ifndef _WIN32 pthread_mutex_lock(&codec->data_mutex); #endif @@ -331,9 +441,11 @@ ImagingIncrementalCodecRead(ImagingIncrementalCodec codec, #endif remaining = codec->stream.end - codec->stream.ptr; + codec->stream.top = codec->stream.end; DEBUG("got %llu bytes\n", (unsigned long long)remaining); } + if (todo > remaining) todo = remaining; @@ -357,12 +469,30 @@ ImagingIncrementalCodecRead(ImagingIncrementalCodec codec, off_t ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec, - off_t bytes) + off_t bytes) { off_t done = 0; DEBUG("skipping (want %llu bytes)\n", (unsigned long long)bytes); + /* In write mode, explicitly fill with zeroes */ + if (codec->read_or_write == INCREMENTAL_CODEC_WRITE) { + static const UINT8 zeroes[256] = { 0 }; + off_t done = 0; + while (bytes) { + size_t todo = bytes > 256 ? 256 : bytes; + ssize_t written = ImagingIncrementalCodecWrite(codec, zeroes, todo); + if (written <= 0) + break; + done += written; + bytes -= written; + } + return done; + } + + if (codec->stream.fd >= 0) + return lseek(codec->stream.fd, bytes, SEEK_CUR); + #ifndef _WIN32 pthread_mutex_lock(&codec->data_mutex); #endif @@ -388,6 +518,7 @@ ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec, remaining = codec->stream.end - codec->stream.ptr; } + if (todo > remaining) todo = remaining; @@ -407,15 +538,23 @@ ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec, return done; } -size_t +ssize_t ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, const void *buffer, size_t bytes) { const UINT8 *ptr = (const UINT8 *)buffer; size_t done = 0; + if (codec->read_or_write == INCREMENTAL_CODEC_READ) { + DEBUG("attempt to write from read codec\n"); + return -1; + } + DEBUG("write (have %llu bytes)\n", (unsigned long long)bytes); + if (codec->stream.fd >= 0) + return write(codec->stream.fd, buffer, bytes); + #ifndef _WIN32 pthread_mutex_lock(&codec->data_mutex); #endif @@ -424,20 +563,40 @@ ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, size_t remaining = codec->stream.end - codec->stream.ptr; if (!remaining) { - DEBUG("waiting for space\n"); + if (codec->seekable && codec->stream.fd < 0) { + /* In this case, we maintain the stream buffer ourselves */ + size_t old_size = codec->stream.top - codec->stream.buffer; + size_t new_size = (old_size + bytes + 65535) & ~65535; + UINT8 *new = (UINT8 *)realloc(codec->stream.buffer, new_size); + + if (!new) { + codec->state->errcode = IMAGING_CODEC_MEMORY; +#ifndef _WIN32 + pthread_mutex_unlock(&codec->data_mutex); +#endif + return done == 0 ? -1 : done; + } + + codec->stream.ptr = codec->stream.ptr - codec->stream.buffer + new; + codec->stream.buffer = new; + codec->stream.end = new + new_size; + codec->stream.top = new + old_size; + } else { + DEBUG("waiting for space\n"); #ifndef _WIN32 - pthread_mutex_lock(&codec->codec_mutex); + pthread_mutex_lock(&codec->codec_mutex); #endif - codec->result = (int)(codec->stream.ptr - codec->stream.buffer); + codec->result = (int)(codec->stream.ptr - codec->stream.buffer); #if _WIN32 - SetEvent(codec->hCodecEvent); - WaitForSingleObject(codec->hDataEvent); + 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); + 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; @@ -455,6 +614,10 @@ ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, done += todo; ptr += todo; } + + if (codec->stream.ptr > codec->stream.top) + codec->stream.top = codec->stream.ptr; + #ifndef _WIN32 pthread_mutex_unlock(&codec->data_mutex); #endif @@ -463,3 +626,33 @@ ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, return done; } + +off_t +ImagingIncrementalCodecSeek(ImagingIncrementalCodec codec, + off_t bytes) +{ + DEBUG("seeking (going to %llu bytes)\n", (unsigned long long)bytes); + + if (codec->stream.fd >= 0) + return lseek(codec->stream.fd, bytes, SEEK_SET); + + if (!codec->seekable) { + DEBUG("attempt to seek non-seekable stream\n"); + return -1; + } + + if (bytes < 0) { + DEBUG("attempt to seek before stream start\n"); + return -1; + } + + off_t buffered = codec->stream.top - codec->stream.buffer; + + if (bytes <= buffered) { + DEBUG("seek within buffer\n"); + codec->stream.ptr = codec->stream.buffer + bytes; + return bytes; + } + + return buffered + ImagingIncrementalCodecSkip(codec, bytes - buffered); +} diff --git a/libImaging/Jpeg2K.h b/libImaging/Jpeg2K.h index 128302f19..ba4b53a7f 100644 --- a/libImaging/Jpeg2K.h +++ b/libImaging/Jpeg2K.h @@ -17,6 +17,9 @@ typedef struct { /* CONFIGURATION */ + /* File descriptor, if available; otherwise, -1 */ + int fd; + /* Specify the desired format */ OPJ_CODEC_FORMAT format; @@ -39,6 +42,9 @@ typedef struct { typedef struct { /* CONFIGURATION */ + /* File descriptor, if available; otherwise, -1 */ + int fd; + /* Specify the desired format */ OPJ_CODEC_FORMAT format; diff --git a/libImaging/Jpeg2KDecode.c b/libImaging/Jpeg2KDecode.c index c3254d889..9c4e16b1f 100644 --- a/libImaging/Jpeg2KDecode.c +++ b/libImaging/Jpeg2KDecode.c @@ -53,15 +53,6 @@ j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) return len ? len : (OPJ_SIZE_T)-1; } -static OPJ_SIZE_T -j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) -{ - /* This should never happen */ - fprintf(stderr, "OpenJPEG has written to our read stream(!)"); - abort(); - return (OPJ_SIZE_T)-1; -} - static OPJ_OFF_T j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) { @@ -71,15 +62,6 @@ j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) 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 read stream(!)"); - abort(); - return OPJ_FALSE; -} - /* -------------------------------------------------------------------- */ /* Unpackers */ /* -------------------------------------------------------------------- */ @@ -476,9 +458,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state, } 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->decoder); @@ -623,6 +603,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state, } state->state = J2K_STATE_DONE; + state->errcode = IMAGING_CODEC_END; quick_exit: if (codec) @@ -645,7 +626,10 @@ ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) if (state->state == J2K_STATE_START) { context->decoder = ImagingIncrementalCodecCreate(j2k_decode_entry, - im, state); + im, state, + INCREMENTAL_CODEC_READ, + INCREMENTAL_CODEC_NOT_SEEKABLE, + context->fd); if (!context->decoder) { state->errcode = IMAGING_CODEC_BROKEN; diff --git a/libImaging/Jpeg2KEncode.c b/libImaging/Jpeg2KEncode.c index 75f40d58f..f5feaf72e 100644 --- a/libImaging/Jpeg2KEncode.c +++ b/libImaging/Jpeg2KEncode.c @@ -40,15 +40,6 @@ j2k_error(const char *msg, void *client_data) /* 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) { @@ -61,8 +52,8 @@ j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) 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); + ImagingIncrementalCodec encoder = (ImagingIncrementalCodec)p_user_data; + off_t pos = ImagingIncrementalCodecSkip(encoder, p_nb_bytes); return pos ? pos : (OPJ_OFF_T)-1; } @@ -70,10 +61,10 @@ j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) 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; + ImagingIncrementalCodec encoder = (ImagingIncrementalCodec)p_user_data; + off_t pos = ImagingIncrementalCodecSeek(encoder, p_nb_bytes); + + return pos == p_nb_bytes; } /* -------------------------------------------------------------------- */ @@ -259,7 +250,6 @@ j2k_encode_entry(Imaging im, ImagingCodecState state, 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); @@ -499,12 +489,19 @@ 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) + if (state->state == J2K_STATE_FAILED) return -1; if (state->state == J2K_STATE_START) { + int seekable = (context->format != OPJ_CODEC_J2K + ? INCREMENTAL_CODEC_SEEKABLE + : INCREMENTAL_CODEC_NOT_SEEKABLE); + context->encoder = ImagingIncrementalCodecCreate(j2k_encode_entry, - im, state); + im, state, + INCREMENTAL_CODEC_WRITE, + seekable, + context->fd); if (!context->encoder) { state->errcode = IMAGING_CODEC_BROKEN;