Added seek support to make writing jp2 files work. Also added support for directly using an fd rather than relying on the Python loop, if we have a real fd.

This commit is contained in:
Alastair Houghton 2014-03-14 11:21:08 +00:00
parent 61fb89ec54
commit cb1f990a92
8 changed files with 306 additions and 73 deletions

View File

@ -156,9 +156,13 @@ class Jpeg2KImageFile(ImageFile.ImageFile):
self.reduce = 0 self.reduce = 0
self.layers = 0 self.layers = 0
fd = -1
if hasattr(self.fp, "fileno"):
fd = self.fp.fileno()
self.tile = [('jpeg2k', (0, 0) + self.size, 0, self.tile = [('jpeg2k', (0, 0) + self.size, 0,
(self.codec, self.reduce, self.layers))] (self.codec, self.reduce, self.layers, fd))]
def load(self): def load(self):
if self.reduce: if self.reduce:
@ -181,6 +185,38 @@ def _save(im, fp, filename):
kind = 'j2k' kind = 'j2k'
else: else:
kind = 'jp2' 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)]) ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)])

View File

@ -796,8 +796,9 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
OPJ_CODEC_FORMAT codec_format; OPJ_CODEC_FORMAT codec_format;
int reduce = 0; int reduce = 0;
int layers = 0; int layers = 0;
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &format, int fd = -1;
&reduce, &layers)) if (!PyArg_ParseTuple(args, "ss|iii", &mode, &format,
&reduce, &layers, &fd))
return NULL; return NULL;
if (strcmp(format, "j2k") == 0) if (strcmp(format, "j2k") == 0)
@ -819,6 +820,7 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
context = (JPEG2KDECODESTATE *)decoder->state.context; context = (JPEG2KDECODESTATE *)decoder->state.context;
context->fd = fd;
context->format = codec_format; context->format = codec_format;
context->reduce = reduce; context->reduce = reduce;
context->layers = layers; context->layers = layers;

View File

@ -837,16 +837,18 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
PyObject *quality_layers = NULL; PyObject *quality_layers = NULL;
int num_resolutions = 0; int num_resolutions = 0;
PyObject *cblk_size = NULL; PyObject *cblk_size = NULL;
int irreversible = 0; PyObject *irreversible = NULL;
char *progression = "LRCP"; char *progression = "LRCP";
OPJ_PROG_ORDER prog_order; OPJ_PROG_ORDER prog_order;
char *cinema_mode = "no"; char *cinema_mode = "no";
OPJ_CINEMA_MODE cine_mode; 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, &offset, &tile_offset, &tile_size,
&quality_mode, &quality_layers, &num_resolutions, &quality_mode, &quality_layers, &num_resolutions,
&cblk_size, &irreversible, &progression, &cinema_mode)) &cblk_size, &irreversible, &progression, &cinema_mode,
&fd))
return NULL; return NULL;
if (strcmp (format, "j2k") == 0) if (strcmp (format, "j2k") == 0)
@ -891,6 +893,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
context = (JPEG2KENCODESTATE *)encoder->state.context; context = (JPEG2KENCODESTATE *)encoder->state.context;
context->fd = fd;
context->format = codec_format; context->format = codec_format;
context->offset_x = context->offset_y = 0; context->offset_x = context->offset_y = 0;
@ -905,6 +908,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
if (quality_layers && PySequence_Check(quality_layers)) { if (quality_layers && PySequence_Check(quality_layers)) {
context->quality_is_in_db = strcmp (quality_mode, "dB") == 0; context->quality_is_in_db = strcmp (quality_mode, "dB") == 0;
context->quality_layers = quality_layers; context->quality_layers = quality_layers;
Py_INCREF(quality_layers);
} }
context->num_resolutions = num_resolutions; context->num_resolutions = num_resolutions;
@ -913,7 +917,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
&context->cblk_width, &context->cblk_width,
&context->cblk_height); &context->cblk_height);
context->irreversible = irreversible; context->irreversible = PyObject_IsTrue(irreversible);
context->progression = prog_order; context->progression = prog_order;
context->cinema_mode = cine_mode; context->cinema_mode = cine_mode;

View File

@ -512,12 +512,23 @@ typedef int (*ImagingIncrementalCodecEntry)(Imaging im,
ImagingCodecState state, ImagingCodecState state,
ImagingIncrementalCodec codec); 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 void ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec);
extern int ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec, UINT8 *buf, int bytes); 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 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); extern size_t ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec);
/* Errcodes */ /* Errcodes */

View File

@ -35,6 +35,11 @@
thinking that the image is truncated, whereas generally you want it to thinking that the image is truncated, whereas generally you want it to
pass the EOF condition (0 bytes to read) through to your code. */ 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 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <process.h> #include <process.h>
@ -64,18 +69,24 @@ struct ImagingIncrementalCodecStruct {
pthread_cond_t data_cond; pthread_cond_t data_cond;
pthread_t thread; pthread_t thread;
#endif #endif
ImagingIncrementalCodecEntry entry; ImagingIncrementalCodecEntry entry;
Imaging im; Imaging im;
ImagingCodecState state; ImagingCodecState state;
struct { struct {
UINT8 *buffer; int fd;
UINT8 *ptr; UINT8 *buffer; /* Base of buffer */
UINT8 *end; UINT8 *ptr; /* Current pointer in buffer */
UINT8 *top; /* Highest point in buffer we've used */
UINT8 *end; /* End of buffer */
} stream; } stream;
int started; int read_or_write;
int result; int seekable;
int started;
int result;
}; };
static void flush_stream(ImagingIncrementalCodec codec);
#if _WIN32 #if _WIN32
static void __stdcall static void __stdcall
codec_thread(void *ptr) codec_thread(void *ptr)
@ -84,6 +95,8 @@ codec_thread(void *ptr)
codec->result = codec->entry(codec->im, codec->state, codec); codec->result = codec->entry(codec->im, codec->state, codec);
flush_stream(codec);
SetEvent(codec->hCodecEvent); SetEvent(codec->hCodecEvent);
} }
#else #else
@ -94,18 +107,54 @@ codec_thread(void *ptr)
codec->result = codec->entry(codec->im, codec->state, codec); 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_cond_signal(&codec->codec_cond);
pthread_mutex_unlock(&codec->codec_mutex);
return NULL; return NULL;
} }
#endif #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 */ * Create a new incremental codec */
ImagingIncrementalCodec ImagingIncrementalCodec
ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry,
Imaging im, Imaging im,
ImagingCodecState state) ImagingCodecState state,
int read_or_write,
int seekable,
int fd)
{ {
ImagingIncrementalCodec codec = (ImagingIncrementalCodec)malloc(sizeof(struct ImagingIncrementalCodecStruct)); ImagingIncrementalCodec codec = (ImagingIncrementalCodec)malloc(sizeof(struct ImagingIncrementalCodecStruct));
@ -113,8 +162,15 @@ ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry,
codec->im = im; codec->im = im;
codec->state = state; codec->state = state;
codec->result = 0; 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->started = 0;
codec->seekable = seekable;
codec->read_or_write = read_or_write;
if (fd >= 0)
lseek(fd, 0, SEEK_SET);
/* System specific set-up */ /* System specific set-up */
#if _WIN32 #if _WIN32
@ -223,7 +279,11 @@ ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec)
pthread_mutex_lock(&codec->data_mutex); pthread_mutex_lock(&codec->data_mutex);
#endif #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 #ifdef _WIN32
SetEvent(codec->hDataEvent); SetEvent(codec->hDataEvent);
@ -264,6 +324,22 @@ ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec,
pthread_cond_signal(&codec->start_cond); pthread_cond_signal(&codec->start_cond);
#endif #endif
codec->started = 1; 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); DEBUG("providing %p, %d\n", buf, bytes);
@ -272,8 +348,30 @@ ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec,
pthread_mutex_lock(&codec->data_mutex); pthread_mutex_lock(&codec->data_mutex);
#endif #endif
codec->stream.buffer = codec->stream.ptr = buf; if (codec->read_or_write == INCREMENTAL_CODEC_READ
codec->stream.end = buf + bytes; && 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 #ifdef _WIN32
SetEvent(codec->hDataEvent); SetEvent(codec->hDataEvent);
@ -298,15 +396,27 @@ ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec)
return codec->stream.ptr - codec->stream.buffer; return codec->stream.ptr - codec->stream.buffer;
} }
size_t ssize_t
ImagingIncrementalCodecRead(ImagingIncrementalCodec codec, ImagingIncrementalCodecRead(ImagingIncrementalCodec codec,
void *buffer, size_t bytes) void *buffer, size_t bytes)
{ {
UINT8 *ptr = (UINT8 *)buffer; UINT8 *ptr = (UINT8 *)buffer;
size_t done = 0; 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); 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 #ifndef _WIN32
pthread_mutex_lock(&codec->data_mutex); pthread_mutex_lock(&codec->data_mutex);
#endif #endif
@ -331,9 +441,11 @@ ImagingIncrementalCodecRead(ImagingIncrementalCodec codec,
#endif #endif
remaining = codec->stream.end - codec->stream.ptr; remaining = codec->stream.end - codec->stream.ptr;
codec->stream.top = codec->stream.end;
DEBUG("got %llu bytes\n", (unsigned long long)remaining); DEBUG("got %llu bytes\n", (unsigned long long)remaining);
} }
if (todo > remaining) if (todo > remaining)
todo = remaining; todo = remaining;
@ -357,12 +469,30 @@ ImagingIncrementalCodecRead(ImagingIncrementalCodec codec,
off_t off_t
ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec, ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec,
off_t bytes) off_t bytes)
{ {
off_t done = 0; off_t done = 0;
DEBUG("skipping (want %llu bytes)\n", (unsigned long long)bytes); 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 #ifndef _WIN32
pthread_mutex_lock(&codec->data_mutex); pthread_mutex_lock(&codec->data_mutex);
#endif #endif
@ -388,6 +518,7 @@ ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec,
remaining = codec->stream.end - codec->stream.ptr; remaining = codec->stream.end - codec->stream.ptr;
} }
if (todo > remaining) if (todo > remaining)
todo = remaining; todo = remaining;
@ -407,15 +538,23 @@ ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec,
return done; return done;
} }
size_t ssize_t
ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec,
const void *buffer, size_t bytes) const void *buffer, size_t bytes)
{ {
const UINT8 *ptr = (const UINT8 *)buffer; const UINT8 *ptr = (const UINT8 *)buffer;
size_t done = 0; 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); DEBUG("write (have %llu bytes)\n", (unsigned long long)bytes);
if (codec->stream.fd >= 0)
return write(codec->stream.fd, buffer, bytes);
#ifndef _WIN32 #ifndef _WIN32
pthread_mutex_lock(&codec->data_mutex); pthread_mutex_lock(&codec->data_mutex);
#endif #endif
@ -424,20 +563,40 @@ ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec,
size_t remaining = codec->stream.end - codec->stream.ptr; size_t remaining = codec->stream.end - codec->stream.ptr;
if (!remaining) { 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 #ifndef _WIN32
pthread_mutex_lock(&codec->codec_mutex); pthread_mutex_lock(&codec->codec_mutex);
#endif #endif
codec->result = (int)(codec->stream.ptr - codec->stream.buffer); codec->result = (int)(codec->stream.ptr - codec->stream.buffer);
#if _WIN32 #if _WIN32
SetEvent(codec->hCodecEvent); SetEvent(codec->hCodecEvent);
WaitForSingleObject(codec->hDataEvent); WaitForSingleObject(codec->hDataEvent);
#else #else
pthread_cond_signal(&codec->codec_cond); pthread_cond_signal(&codec->codec_cond);
pthread_mutex_unlock(&codec->codec_mutex); pthread_mutex_unlock(&codec->codec_mutex);
pthread_cond_wait(&codec->data_cond, &codec->data_mutex); pthread_cond_wait(&codec->data_cond, &codec->data_mutex);
#endif #endif
}
remaining = codec->stream.end - codec->stream.ptr; remaining = codec->stream.end - codec->stream.ptr;
@ -455,6 +614,10 @@ ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec,
done += todo; done += todo;
ptr += todo; ptr += todo;
} }
if (codec->stream.ptr > codec->stream.top)
codec->stream.top = codec->stream.ptr;
#ifndef _WIN32 #ifndef _WIN32
pthread_mutex_unlock(&codec->data_mutex); pthread_mutex_unlock(&codec->data_mutex);
#endif #endif
@ -463,3 +626,33 @@ ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec,
return done; 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);
}

View File

@ -17,6 +17,9 @@
typedef struct { typedef struct {
/* CONFIGURATION */ /* CONFIGURATION */
/* File descriptor, if available; otherwise, -1 */
int fd;
/* Specify the desired format */ /* Specify the desired format */
OPJ_CODEC_FORMAT format; OPJ_CODEC_FORMAT format;
@ -39,6 +42,9 @@ typedef struct {
typedef struct { typedef struct {
/* CONFIGURATION */ /* CONFIGURATION */
/* File descriptor, if available; otherwise, -1 */
int fd;
/* Specify the desired format */ /* Specify the desired format */
OPJ_CODEC_FORMAT format; OPJ_CODEC_FORMAT format;

View File

@ -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; 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 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)
{ {
@ -71,15 +62,6 @@ j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
return pos ? pos : (OPJ_OFF_T)-1; 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 */ /* Unpackers */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@ -476,9 +458,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state,
} }
opj_stream_set_read_function(stream, j2k_read); 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_skip_function(stream, j2k_skip);
opj_stream_set_seek_function(stream, j2k_seek);
opj_stream_set_user_data(stream, context->decoder); 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->state = J2K_STATE_DONE;
state->errcode = IMAGING_CODEC_END;
quick_exit: quick_exit:
if (codec) if (codec)
@ -645,7 +626,10 @@ ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
if (state->state == J2K_STATE_START) { if (state->state == J2K_STATE_START) {
context->decoder = ImagingIncrementalCodecCreate(j2k_decode_entry, context->decoder = ImagingIncrementalCodecCreate(j2k_decode_entry,
im, state); im, state,
INCREMENTAL_CODEC_READ,
INCREMENTAL_CODEC_NOT_SEEKABLE,
context->fd);
if (!context->decoder) { if (!context->decoder) {
state->errcode = IMAGING_CODEC_BROKEN; state->errcode = IMAGING_CODEC_BROKEN;

View File

@ -40,15 +40,6 @@ j2k_error(const char *msg, void *client_data)
/* Buffer output stream */ /* 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 static OPJ_SIZE_T
j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) 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 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)
{ {
ImagingIncrementalCodec decoder = (ImagingIncrementalCodec)p_user_data; ImagingIncrementalCodec encoder = (ImagingIncrementalCodec)p_user_data;
off_t pos = ImagingIncrementalCodecSkip(decoder, p_nb_bytes); off_t pos = ImagingIncrementalCodecSkip(encoder, p_nb_bytes);
return pos ? pos : (OPJ_OFF_T)-1; 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 static OPJ_BOOL
j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data) j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data)
{ {
/* This should never happen */ ImagingIncrementalCodec encoder = (ImagingIncrementalCodec)p_user_data;
fprintf(stderr, "OpenJPEG tried to seek our write stream(!)"); off_t pos = ImagingIncrementalCodecSeek(encoder, p_nb_bytes);
abort();
return OPJ_FALSE; return pos == p_nb_bytes;
} }
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@ -259,7 +250,6 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
goto quick_exit; goto quick_exit;
} }
opj_stream_set_read_function(stream, j2k_read);
opj_stream_set_write_function(stream, j2k_write); opj_stream_set_write_function(stream, j2k_write);
opj_stream_set_skip_function(stream, j2k_skip); opj_stream_set_skip_function(stream, j2k_skip);
opj_stream_set_seek_function(stream, j2k_seek); 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; JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED) if (state->state == J2K_STATE_FAILED)
return -1; return -1;
if (state->state == J2K_STATE_START) { 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, context->encoder = ImagingIncrementalCodecCreate(j2k_encode_entry,
im, state); im, state,
INCREMENTAL_CODEC_WRITE,
seekable,
context->fd);
if (!context->encoder) { if (!context->encoder) {
state->errcode = IMAGING_CODEC_BROKEN; state->errcode = IMAGING_CODEC_BROKEN;