mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-01 00:17:27 +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: | ||||||
|  | @ -182,6 +186,38 @@ def _save(im, fp, filename): | ||||||
|     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> | ||||||
|  | @ -68,14 +73,20 @@ struct ImagingIncrementalCodecStruct { | ||||||
|   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                           read_or_write; | ||||||
|  |   int                           seekable; | ||||||
|   int                           started; |   int                           started; | ||||||
|   int                           result; |   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 | ||||||
| 
 | 
 | ||||||
|  |   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.buffer = codec->stream.ptr = buf; | ||||||
|     codec->stream.end = buf + bytes; |     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; | ||||||
| 
 | 
 | ||||||
|  | @ -363,6 +475,24 @@ ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec, | ||||||
| 
 | 
 | ||||||
|   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,6 +563,25 @@ 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) { | ||||||
|  |       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"); |         DEBUG("waiting for space\n"); | ||||||
| 
 | 
 | ||||||
| #ifndef _WIN32 | #ifndef _WIN32 | ||||||
|  | @ -438,6 +596,7 @@ ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, | ||||||
|         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