mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-27 09:44:31 +03:00
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:
parent
61fb89ec54
commit
cb1f990a92
|
@ -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)])
|
||||||
|
|
||||||
|
|
6
decode.c
6
decode.c
|
@ -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;
|
||||||
|
|
12
encode.c
12
encode.c
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user