[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Problem with library images on Windows (again)
From: |
Juanma Barranquero |
Subject: |
Re: Problem with library images on Windows (again) |
Date: |
Tue, 14 Jun 2005 04:02:28 +0200 |
> (I suppose I could get around the issue by writing read functions for
> libpng and jpeg and bypassing the standard code altogether;
And finally, that's what I've done.
The following patch gets rid of png_init_io() and jpeg_stdio_src(),
and instead define custom read functions to read image data from FILE
*. With it, image support finally works as expected on MSVC and MinGW
builds of Emacs on Windows.
Highlights of the patch:
- It has no ChangeLog entries :-) (I'll write them once the patch is accepted)
- Deletion of png_init_io() and jpeg_stdio_src() is not conditional
on HAVE_NTGUI; I've assumed it's best to have just one mechanism for
Windows, Unix, GNU/Linux and MacOS platforms. I can reinstate the
deleted functions and put the alternative into #ifdef's if deemed
necessary.
- I've changed a few names of the memory-reading data source
functions for JPEG so it's clearer the paralelism between from-memory
and from-file data source setups.
- Most jpeg code I've added is heavily based on jdatasrc.c, from the
JPEG library. I assume there's no legal trouble, as other jpeg code
comes also from JPEG library examples.
--
/L/e/k/t/u
Index: src/image.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/image.c,v
retrieving revision 1.27
diff -u -2 -r1.27 image.c
--- src/image.c 11 Jun 2005 16:24:36 -0000 1.27
+++ src/image.c 14 Jun 2005 01:46:10 -0000
@@ -5632,5 +5632,4 @@
DEF_IMGLIB_FN (png_destroy_read_struct);
DEF_IMGLIB_FN (png_set_read_fn);
-DEF_IMGLIB_FN (png_init_io);
DEF_IMGLIB_FN (png_set_sig_bytes);
DEF_IMGLIB_FN (png_read_info);
@@ -5664,5 +5663,4 @@
LOAD_IMGLIB_FN (library, png_destroy_read_struct);
LOAD_IMGLIB_FN (library, png_set_read_fn);
- LOAD_IMGLIB_FN (library, png_init_io);
LOAD_IMGLIB_FN (library, png_set_sig_bytes);
LOAD_IMGLIB_FN (library, png_read_info);
@@ -5690,5 +5688,4 @@
#define fn_png_destroy_read_struct png_destroy_read_struct
#define fn_png_set_read_fn png_set_read_fn
-#define fn_png_init_io png_init_io
#define fn_png_set_sig_bytes png_set_sig_bytes
#define fn_png_read_info png_read_info
@@ -5763,4 +5760,21 @@
+/* Function set as reader function when reading PNG image from a file.
+ PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
+ bytes from the input to DATA. */
+
+static void
+png_read_from_file (png_ptr, data, length)
+ png_structp png_ptr;
+ png_bytep data;
+ png_size_t length;
+{
+ FILE *fp = (FILE *) fn_png_get_io_ptr (png_ptr);
+
+ if (fread (data, 1, length, fp) < length)
+ fn_png_error (png_ptr, "Read error");
+}
+
+
/* Load PNG image IMG for use on frame F. Value is non-zero if
successful. */
@@ -5896,5 +5910,5 @@
fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
else
- fn_png_init_io (png_ptr, fp);
+ fn_png_set_read_fn (png_ptr, (void *) fp, png_read_from_file);
fn_png_set_sig_bytes (png_ptr, sizeof sig);
@@ -6295,5 +6309,4 @@
DEF_IMGLIB_FN (jpeg_read_header);
DEF_IMGLIB_FN (jpeg_read_scanlines);
-DEF_IMGLIB_FN (jpeg_stdio_src);
DEF_IMGLIB_FN (jpeg_std_error);
DEF_IMGLIB_FN (jpeg_resync_to_restart);
@@ -6311,5 +6324,4 @@
LOAD_IMGLIB_FN (library, jpeg_start_decompress);
LOAD_IMGLIB_FN (library, jpeg_read_header);
- LOAD_IMGLIB_FN (library, jpeg_stdio_src);
LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
@@ -6337,5 +6349,4 @@
#define fn_jpeg_read_header jpeg_read_header
#define fn_jpeg_read_scanlines jpeg_read_scanlines
-#define fn_jpeg_stdio_src jpeg_stdio_src
#define fn_jpeg_std_error jpeg_std_error
#define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
@@ -6359,4 +6370,15 @@
+/* Method to terminate data source. Called by
+ jpeg_finish_decompress() after all data has been processed.
+ Common to memory and file source managers. */
+
+static void
+our_common_term_source (cinfo)
+ j_decompress_ptr cinfo;
+{
+}
+
+
/* Init source method for JPEG data source manager. Called by
jpeg_read_header() before any data is actually read. See
@@ -6364,5 +6386,5 @@
static void
-our_init_source (cinfo)
+our_memory_init_source (cinfo)
j_decompress_ptr cinfo;
{
@@ -6375,5 +6397,5 @@
static boolean
-our_fill_input_buffer (cinfo)
+our_memory_fill_input_buffer (cinfo)
j_decompress_ptr cinfo;
{
@@ -6395,5 +6417,5 @@
static void
-our_skip_input_data (cinfo, num_bytes)
+our_memory_skip_input_data (cinfo, num_bytes)
j_decompress_ptr cinfo;
long num_bytes;
@@ -6412,14 +6434,4 @@
-/* Method to terminate data source. Called by
- jpeg_finish_decompress() after all data has been processed. */
-
-static void
-our_term_source (cinfo)
- j_decompress_ptr cinfo;
-{
-}
-
-
/* Set up the JPEG lib for reading an image from DATA which contains
LEN bytes. CINFO is the decompression info structure created for
@@ -6445,9 +6457,9 @@
src = (struct jpeg_source_mgr *) cinfo->src;
- src->init_source = our_init_source;
- src->fill_input_buffer = our_fill_input_buffer;
- src->skip_input_data = our_skip_input_data;
+ src->init_source = our_memory_init_source;
+ src->fill_input_buffer = our_memory_fill_input_buffer;
+ src->skip_input_data = our_memory_skip_input_data;
src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use
default method. */
- src->term_source = our_term_source;
+ src->term_source = our_common_term_source;
src->bytes_in_buffer = len;
src->next_input_byte = data;
@@ -6455,4 +6467,136 @@
+/* JPEG data source manager setup for JPEG images read from a file.
+ Heavily based on jdatasrc.c from the JPEG library. */
+
+struct my_jpeg_file_src {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ FILE *infile; /* source stream */
+ JOCTET *buffer; /* start of buffer */
+ boolean start_of_file; /* have we gotten any data yet? */
+};
+
+typedef struct my_jpeg_file_src *my_jpeg_file_ptr;
+
+#define JPEG_INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
+
+
+/* Init source method for JPEG data source manager.
+ Called by jpeg_read_header() before any data is actually read. */
+
+static void
+our_file_init_source (j_decompress_ptr cinfo)
+{
+ my_jpeg_file_ptr src = (my_jpeg_file_ptr) cinfo->src;
+
+ /* We reset the empty-input-file flag for each image,
+ * but we don't clear the input buffer.
+ * This is correct behavior for reading a series of images from one source.
+ */
+ src->start_of_file = 1;
+}
+
+
+/* Fill input buffer method for JPEG data source manager.
+ Called whenever more data is needed. */
+
+static boolean
+our_file_fill_input_buffer (j_decompress_ptr cinfo)
+{
+ my_jpeg_file_ptr src = (my_jpeg_file_ptr) cinfo->src;
+ size_t nbytes;
+
+ nbytes = fread (src->buffer, 1, JPEG_INPUT_BUF_SIZE, src->infile);
+
+ if (nbytes <= 0) {
+ if (src->start_of_file) /* Treat empty input file as fatal error */
+ ERREXIT (cinfo, JERR_INPUT_EMPTY);
+ WARNMS (cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_file = 0;
+
+ return 1;
+}
+
+
+/* Method to skip over NUM_BYTES bytes in the image data.
+ CINFO->src is the JPEG data source manager. */
+
+static void
+our_file_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ my_jpeg_file_ptr src = (my_jpeg_file_ptr) cinfo->src;
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0)
+ {
+ while (num_bytes > (long) src->pub.bytes_in_buffer)
+ {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ (void) our_file_fill_input_buffer (cinfo);
+ /* note we assume that fill_file_input_buffer will never
return FALSE,
+ * so suspension need not be handled.
+ */
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+
+/* Set up the JPEG lib for reading an image from a FILE * via
+ a customized function, thus avoiding FILE * conflicts between
+ different builds of the image library. CINFO is the
+ decompression info structure created for reading the image. */
+
+static void
+jpeg_file_src (cinfo, infile)
+ j_decompress_ptr cinfo;
+ FILE *infile;
+{
+ my_jpeg_file_ptr src;
+
+ /* The source object and input buffer are made permanent so that a series
+ * of JPEG images can be read from the same file by calling jpeg_stdio_src
+ * only before the first one. (If we discarded the buffer at the end
of
+ * one image, we'd likely lose the start of the next one.)
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL)
+ {
+ /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof (struct my_jpeg_file_src));
+ src = (my_jpeg_file_ptr) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ JPEG_INPUT_BUF_SIZE * sizeof (JOCTET));
+ }
+
+ src = (my_jpeg_file_ptr) cinfo->src;
+ src->pub.init_source = our_file_init_source;
+ src->pub.fill_input_buffer = our_file_fill_input_buffer;
+ src->pub.skip_input_data = our_file_skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart_wrapper; /*
use default method */
+ src->pub.term_source = our_common_term_source;
+ src->infile = infile;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
+
+
/* Load image IMG for use on frame F. Patterned after example.c
from the JPEG lib. */
@@ -6538,5 +6682,5 @@
if (NILP (specified_data))
- fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
+ jpeg_file_src (&cinfo, fp);
else
jpeg_memory_src (&cinfo, SDATA (specified_data),