Index: libs/vips/patches/002-im_bufjpeg2vips.patch
===================================================================
--- libs/vips/patches/002-im_bufjpeg2vips.patch	(revision 0)
+++ libs/vips/patches/002-im_bufjpeg2vips.patch	(revision 0)
@@ -0,0 +1,288 @@
+diff -u --recursive vips-7.24.5-vanilla/libvips/format/im_jpeg2vips.c vips-7.24.5/libvips/format/im_jpeg2vips.c
+--- vips-7.24.5-vanilla/libvips/format/im_jpeg2vips.c	2011-07-04 09:23:04.437730278 -0500
++++ vips-7.24.5/libvips/format/im_jpeg2vips.c	2011-07-04 09:27:46.972274128 -0500
+@@ -30,6 +30,8 @@
+  * 	- gtkdoc
+  * 4/12/10
+  * 	- attach the jpeg thumbnail and multiscan fields (thanks Mike)
++ * 20/4/2011
++ *     - added im_bufjpeg2vips()
+  */
+ 
+ /*
+@@ -683,7 +685,7 @@
+ 			fail_on_warn = TRUE;
+ 	}
+ 
+-	/* Make jpeg compression object.
++	/* Make jpeg dcompression object.
+  	 */
+         cinfo.err = jpeg_std_error( &eman.pub );
+ 	eman.pub.error_exit = new_error_exit;
+@@ -737,6 +739,227 @@
+ 	return( result );
+ }
+ 
++/* Just like the above, but we read from a memory buffer.
++ */
++typedef struct {
++	/* Public jpeg fields.
++	 */
++	struct jpeg_source_mgr pub;
++
++	/* Private stuff during read.
++	 */
++	gboolean start_of_file;	/* have we gotten any data yet? */
++	JOCTET *buf;
++	size_t len;
++} InputBuffer;
++
++/*
++ * Initialize source --- called by jpeg_read_header
++ * before any data is actually read.
++ */
++
++static void
++init_source (j_decompress_ptr cinfo)
++{
++  InputBuffer *src = (InputBuffer *) 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 = TRUE;
++}
++
++/*
++ * Fill the input buffer --- called whenever buffer is emptied.
++ *
++ * In typical applications, this should read fresh data into the buffer
++ * (ignoring the current state of next_input_byte & bytes_in_buffer),
++ * reset the pointer & count to the start of the buffer, and return TRUE
++ * indicating that the buffer has been reloaded.  It is not necessary to
++ * fill the buffer entirely, only to obtain at least one more byte.
++ *
++ * There is no such thing as an EOF return.  If the end of the file has been
++ * reached, the routine has a choice of ERREXIT() or inserting fake data into
++ * the buffer.  In most cases, generating a warning message and inserting a
++ * fake EOI marker is the best course of action --- this will allow the
++ * decompressor to output however much of the image is there.  However,
++ * the resulting error message is misleading if the real problem is an empty
++ * input file, so we handle that case specially.
++ *
++ * In applications that need to be able to suspend compression due to input
++ * not being available yet, a FALSE return indicates that no more data can be
++ * obtained right now, but more may be forthcoming later.  In this situation,
++ * the decompressor will return to its caller (with an indication of the
++ * number of scanlines it has read, if any).  The application should resume
++ * decompression after it has loaded more data into the input buffer.  Note
++ * that there are substantial restrictions on the use of suspension --- see
++ * the documentation.
++ *
++ * When suspending, the decompressor will back up to a convenient restart point
++ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
++ * indicate where the restart point will be if the current call returns FALSE.
++ * Data beyond this point must be rescanned after resumption, so move it to
++ * the front of the buffer rather than discarding it.
++ */
++
++static boolean
++fill_input_buffer (j_decompress_ptr cinfo)
++{
++  InputBuffer *src = (InputBuffer *) cinfo->src;
++  size_t nbytes;
++
++  if (src->start_of_file) {
++    nbytes = src->len;
++  }
++  else {
++    WARNMS(cinfo, JWRN_JPEG_EOF);
++    /* Insert a fake EOI marker */
++    src->buf[0] = (JOCTET) 0xFF;
++    src->buf[1] = (JOCTET) JPEG_EOI;
++    nbytes = 2;
++  }
++
++  src->pub.next_input_byte = src->buf;
++  src->pub.bytes_in_buffer = nbytes;
++  src->start_of_file = FALSE;
++
++  return TRUE;
++}
++
++/*
++ * Skip data --- used to skip over a potentially large amount of
++ * uninteresting data (such as an APPn marker).
++ *
++ * Writers of suspendable-input applications must note that skip_input_data
++ * is not granted the right to give a suspension return.  If the skip extends
++ * beyond the data currently in the buffer, the buffer can be marked empty so
++ * that the next read will cause a fill_input_buffer call that can suspend.
++ * Arranging for additional bytes to be discarded before reloading the input
++ * buffer is the application writer's problem.
++ */
++
++static void
++skip_input_data (j_decompress_ptr cinfo, long num_bytes)
++{
++  InputBuffer *src = (InputBuffer *) cinfo->src;
++
++  /* Just skip fwd.
++   */
++  if (num_bytes > 0) {
++    src->pub.next_input_byte += (size_t) num_bytes;
++    src->pub.bytes_in_buffer -= (size_t) num_bytes;
++  }
++}
++
++/*
++ * An additional method that can be provided by data source modules is the
++ * resync_to_restart method for error recovery in the presence of RST markers.
++ * For the moment, this source module just uses the default resync method
++ * provided by the JPEG library.  That method assumes that no backtracking
++ * is possible.
++ */
++
++/*
++ * Terminate source --- called by jpeg_finish_decompress
++ * after all data has been read.  Often a no-op.
++ *
++ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
++ * application must deal with any cleanup that should happen even
++ * for error exit.
++ */
++
++static void
++term_source (j_decompress_ptr cinfo)
++{
++  /* no work necessary here */
++}
++
++/*
++ * Prepare for input from a memory buffer. The caller needs to free the
++ * buffer after decompress is done, we don't take ownership.
++ */
++
++static void
++buf_source (j_decompress_ptr cinfo, void *buf, size_t len)
++{
++  InputBuffer *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(InputBuffer));
++    src = (InputBuffer *) cinfo->src;
++    src->buf = buf;
++    src->len = len;
++  }
++
++  src = (InputBuffer *) cinfo->src;
++  src->pub.init_source = init_source;
++  src->pub.fill_input_buffer = fill_input_buffer;
++  src->pub.skip_input_data = skip_input_data;
++  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
++  src->pub.term_source = term_source;
++  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
++  src->pub.next_input_byte = NULL; /* until buffer loaded */
++}
++
++/* Read a JPEG memory buffer into a VIPS image.
++ */
++static int
++bufjpeg2vips( void *buf, size_t len, IMAGE *out )
++{
++	char *p, *q;
++	struct jpeg_decompress_struct cinfo;
++        ErrorManager eman;
++	int result;
++	gboolean invert_pels;
++	gboolean header_only = FALSE;
++
++	/* Make jpeg dcompression object.
++ 	 */
++        cinfo.err = jpeg_std_error( &eman.pub );
++	eman.pub.error_exit = new_error_exit;
++	eman.pub.output_message = new_output_message;
++	eman.fp = NULL;
++	if( setjmp( eman.jmp ) ) {
++		/* Here for longjmp() from new_error_exit().
++		 */
++		jpeg_destroy_decompress( &cinfo );
++
++		return( -1 );
++	}
++        jpeg_create_decompress( &cinfo );
++
++	/* Make input.
++	 */
++	buf_source( &cinfo, buf, len );
++
++	/* Need to read in APP1 (EXIF metadata) and APP2 (ICC profile).
++	 */
++	jpeg_save_markers( &cinfo, JPEG_APP0 + 1, 0xffff );
++	jpeg_save_markers( &cinfo, JPEG_APP0 + 2, 0xffff );
++
++	/* Convert!
++	 */
++	result = read_jpeg_header( &cinfo, out, &invert_pels, 1 );
++	if( !header_only && !result )
++		result = read_jpeg_image( &cinfo, out, invert_pels );
++
++	/* Close and tidy.
++	 */
++	jpeg_destroy_decompress( &cinfo );
++
++	return( result );
++}
++
+ /**
+  * im_jpeg2vips:
+  * @filename: file to load
+@@ -803,6 +1026,27 @@
+ 	return( jpeg2vips( filename, out, FALSE ) );
+ }
+ 
++/**
++ * im_bufjpeg2vips:
++ * @buf: memory area to load
++ * @len: size of memory area
++ * @out: image to write
++ *
++ * Read a JPEG-formatted memory block into a VIPS image. It can read most 
++ * 8-bit JPEG images, including CMYK and YCbCr.
++ *
++ * This function is handy for processing JPEG image thumbnails.
++ *
++ * See also: #VipsFormat, im_jpeg2vips().
++ *
++ * Returns: 0 on success, -1 on error.
++ */
++int
++im_bufjpeg2vips( void *buf, size_t len, IMAGE *out )
++{
++	return( bufjpeg2vips( buf, len, out ) );
++}
++
+ static int
+ isjpeg( const char *filename )
+ {
+diff -u --recursive vips-7.24.5-vanilla/libvips/include/vips/format.h vips-7.24.5/libvips/include/vips/format.h
+--- vips-7.24.5-vanilla/libvips/include/vips/format.h	2011-07-04 09:23:04.643721945 -0500
++++ vips-7.24.5/libvips/include/vips/format.h	2011-07-04 09:26:21.870724494 -0500
+@@ -122,6 +122,7 @@
+ /* Low-level read/write operations.
+  */
+ int im_jpeg2vips( const char *filename, IMAGE *out );
++int im_bufjpeg2vips( void *buf, size_t len, IMAGE *out );
+ int im_vips2jpeg( IMAGE *in, const char *filename );
+ int im_vips2mimejpeg( IMAGE *in, int qfac );
+ int im_vips2bufjpeg( IMAGE *in, IMAGE *out, int qfac, char **obuf, int *olen );