Index: gdk-pixbuf/io-tiff.c
===================================================================
--- gdk-pixbuf/io-tiff.c	(revision 17792)
+++ gdk-pixbuf/io-tiff.c	(working copy)
@@ -141,27 +141,14 @@
 	g_free (pixels);
 }
 
-#if TIFFLIB_VERSION >= 20031226
-static gboolean tifflibversion (int *major, int *minor, int *revision)
-{
-        if (sscanf (TIFFGetVersion(), 
-                    "LIBTIFF, Version %d.%d.%d", 
-                    major, minor, revision) < 3)
-                return FALSE;
-
-        return TRUE;
-}
-#endif
-
 static GdkPixbuf *
 tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
 {
 	guchar *pixels = NULL;
 	gint width, height, rowstride, bytes;
 	GdkPixbuf *pixbuf;
-#if TIFFLIB_VERSION >= 20031226
-        gint major, minor, revision;
-#endif
+	uint16 orientation = 0;
+	uint16 transform = 0;
 
         /* We're called with the lock held. */
         
@@ -238,95 +225,73 @@
                 return NULL;
         }
 
+	/* Set the "orientation" key associated with this image. libtiff 
+	   orientation handling is odd, so further processing is required
+	   by higher-level functions based on this tag. If the embedded
+	   orientation tag is 1-4, libtiff flips/mirrors the image as
+	   required, and no client processing is required - so we report 
+	   no orientation. Orientations 5-8 require rotations which would 
+	   swap the width and height of the image. libtiff does not do this. 
+	   Instead it interprets orientations 5-8 the same as 1-4. 
+	   See http://bugzilla.remotesensing.org/show_bug.cgi?id=1548.
+	   To correct for this, the client must apply the transform normally
+	   used for orientation 5 to both orientations 5 and 7, and apply
+	   the transform normally used for orientation 7 for both
+	   orientations 6 and 8. Then everythings works out OK! */
+	
+	TIFFGetField (tiff, TIFFTAG_ORIENTATION, &orientation);
+
+	switch (orientation) {
+		case 5:
+		case 7:
+			transform = 5;
+			break;
+		case 6:
+		case 8:
+			transform = 7;
+			break;
+		default:
+			transform = 0;
+			break;
+	}
+
+	if (transform > 0 ) {
+		gchar str[5];
+		snprintf(str, sizeof(str), "%d", transform);
+		gdk_pixbuf_set_option(pixbuf, "orientation", str);
+	}
+
 	if (context && context->prepare_func)
 		(* context->prepare_func) (pixbuf, NULL, context->user_data);
 
-#if TIFFLIB_VERSION >= 20031226
-        if (tifflibversion(&major, &minor, &revision) && major == 3 &&
-            (minor > 6 || (minor == 6 && revision > 0))) {                
-                if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1) || global_error) 
-                {
-                        tiff_set_error (error,
-                                        GDK_PIXBUF_ERROR_FAILED,
-                                        _("Failed to load RGB data from TIFF file"));
-                        g_object_unref (pixbuf);
-                        return NULL;
-                }
+	if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1) || global_error) {
+		tiff_set_error (error,
+                                GDK_PIXBUF_ERROR_FAILED,
+                                _("Failed to load RGB data from TIFF file"));
+		g_object_unref (pixbuf);
+		return NULL;
+	}
 
 #if G_BYTE_ORDER == G_BIG_ENDIAN
-                /* Turns out that the packing used by TIFFRGBAImage depends on 
-                 * the host byte order... 
-                 */ 
-                while (pixels < pixbuf->pixels + bytes) {
-                        uint32 pixel = *(uint32 *)pixels;
-                        int r = TIFFGetR(pixel);
-                        int g = TIFFGetG(pixel);
-                        int b = TIFFGetB(pixel);
-                        int a = TIFFGetA(pixel);
-                        *pixels++ = r;
-                        *pixels++ = g;
-                        *pixels++ = b;
-                        *pixels++ = a;
-                }
+	/* Turns out that the packing used by TIFFRGBAImage depends on 
+         * the host byte order... 
+         */ 
+	while (pixels < pixbuf->pixels + bytes) {
+		uint32 pixel = *(uint32 *)pixels;
+		int r = TIFFGetR(pixel);
+		int g = TIFFGetG(pixel);
+		int b = TIFFGetB(pixel);
+		int a = TIFFGetA(pixel);
+		*pixels++ = r;
+		*pixels++ = g;
+		*pixels++ = b;
+		*pixels++ = a;
+	}
 #endif
-        }
-        else 
-#endif
-              {
-                uint32 *rast, *tmp_rast;
-                gint x, y;
-                guchar *tmppix;
 
-                /* Yes, it needs to be _TIFFMalloc... */
-                rast = (uint32 *) _TIFFmalloc (width * height * sizeof (uint32));
-                if (!rast) {
-                        g_set_error (error,
-                                     GDK_PIXBUF_ERROR,
-                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
-                                     _("Insufficient memory to open TIFF file"));
-                        g_object_unref (pixbuf);
-                        
-                        return NULL;
-                }
-                if (!TIFFReadRGBAImage (tiff, width, height, rast, 1) || global_error) {
-                        tiff_set_error (error,
-                                        GDK_PIXBUF_ERROR_FAILED,
-                                        _("Failed to load RGB data from TIFF file"));
-                        g_object_unref (pixbuf);
-                        _TIFFfree (rast);
-                        
-                        return NULL;
-                }
-                
-                pixels = gdk_pixbuf_get_pixels (pixbuf);
-                
-                g_assert (pixels);
-                
-                tmppix = pixels;
-                
-                for (y = 0; y < height; y++) {
-                        /* Unexplainable...are tiffs backwards? */
-                        /* Also looking at the GIMP plugin, this
-                         * whole reading thing can be a bit more
-                         * robust.
-                         */
-                        tmp_rast = rast + ((height - y - 1) * width);
-                        for (x = 0; x < width; x++) {
-                                tmppix[0] = TIFFGetR (*tmp_rast);
-                                tmppix[1] = TIFFGetG (*tmp_rast);
-                                tmppix[2] = TIFFGetB (*tmp_rast);
-                                tmppix[3] = TIFFGetA (*tmp_rast);
-                                tmp_rast++;
-                                tmppix += 4;
-                        }
-                }
-                
-                _TIFFfree (rast);
-             }
-
 	if (context && context->update_func)
 		(* context->update_func) (pixbuf, 0, 0, width, height, context->user_data);
-        
+
         return pixbuf;
 }
 
Index: gdk-pixbuf/gdk-pixbuf-loader.c
===================================================================
--- gdk-pixbuf/gdk-pixbuf-loader.c	(revision 17792)
+++ gdk-pixbuf/gdk-pixbuf-loader.c	(working copy)
@@ -65,6 +65,7 @@
         gint height;
         gboolean size_fixed;
         gboolean needs_scale;
+	GHashTable *pixbuf_options;
 } GdkPixbufLoaderPrivate;
 
 G_DEFINE_TYPE (GdkPixbufLoader, gdk_pixbuf_loader, G_TYPE_OBJECT)
@@ -173,6 +174,7 @@
         priv = g_new0 (GdkPixbufLoaderPrivate, 1);
         priv->width = -1;
         priv->height = -1;
+	priv->pixbuf_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
         loader->priv = priv;
 }
@@ -194,7 +196,10 @@
         }
         if (priv->animation)
                 g_object_unref (priv->animation);
-  
+ 
+        if (priv->pixbuf_options)
+		g_hash_table_destroy (priv->pixbuf_options);
+
         g_free (priv);
   
         G_OBJECT_CLASS (gdk_pixbuf_loader_parent_class)->finalize (object);
@@ -256,6 +261,8 @@
 			   gpointer            loader)
 {
         GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
+	const char *orientation_str;
+
         g_return_if_fail (pixbuf != NULL);
 
         if (!priv->size_fixed) 
@@ -275,8 +282,17 @@
 
         if (anim)
                 g_object_ref (anim);
-        else
+        else {
                 anim = gdk_pixbuf_non_anim_new (pixbuf);
+
+		/* Preserve important options that may be stored in the pixbuf.
+		   Currently, only the orientation value is kept. */
+		orientation_str = gdk_pixbuf_get_option (pixbuf, "orientation");
+		if (orientation_str != NULL)
+			g_hash_table_insert (priv->pixbuf_options, 
+				             g_strdup ("orientation"), 
+					     g_strdup (orientation_str));
+	}
   
 	if (priv->needs_scale) {
 		priv->animation  = _gdk_pixbuf_scaled_anim_new (anim, 	
@@ -632,15 +648,24 @@
 gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
 {
         GdkPixbufLoaderPrivate *priv;
+	GdkPixbuf *pixbuf;
+	const char *orientation;
   
         g_return_val_if_fail (loader != NULL, NULL);
         g_return_val_if_fail (GDK_IS_PIXBUF_LOADER (loader), NULL);
   
         priv = loader->priv;
 
-        if (priv->animation)
-                return gdk_pixbuf_animation_get_static_image (priv->animation);
-        else
+        if (priv->animation) {
+                pixbuf = gdk_pixbuf_animation_get_static_image (priv->animation);
+
+		/* Attach pixbuf options. Currently, this is only done for the
+		   orientation option. */
+		orientation = g_hash_table_lookup (priv->pixbuf_options, "orientation");
+		if (orientation != NULL)
+			gdk_pixbuf_set_option (pixbuf, "orientation", orientation);
+		return pixbuf;
+	} else
                 return NULL;
 }
 
Index: gdk-pixbuf/io-jpeg.c
===================================================================
--- gdk-pixbuf/io-jpeg.c	(revision 17792)
+++ gdk-pixbuf/io-jpeg.c	(working copy)
@@ -277,11 +277,161 @@
 	}
 }
 
+
+const char leth[]  = {0x49, 0x49, 0x2a, 0x00};	// Little endian TIFF header
+const char beth[]  = {0x4d, 0x4d, 0x00, 0x2a};	// Big endian TIFF header
+const char types[] = {0x00, 0x01, 0x01, 0x02, 0x04, 0x08, 0x00, 
+		      0x08, 0x00, 0x04, 0x08}; 	// size in bytes for EXIF types
+ 
+#define DE_ENDIAN16(val) endian == G_BIG_ENDIAN ? GUINT16_FROM_BE(val) : GUINT16_FROM_LE(val)
+#define DE_ENDIAN32(val) endian == G_BIG_ENDIAN ? GUINT32_FROM_BE(val) : GUINT32_FROM_LE(val)
+ 
+#define ENDIAN16_IT(val) endian == G_BIG_ENDIAN ? GUINT16_TO_BE(val) : GUINT16_TO_LE(val)
+#define ENDIAN32_IT(val) endian == G_BIG_ENDIAN ? GUINT32_TO_BE(val) : GUINT32_TO_LE(val)
+ 
+#define EXIF_JPEG_MARKER   JPEG_APP0+1
+#define EXIF_IDENT_STRING  "Exif\000\000"
+
+static gint 
+get_orientation (j_decompress_ptr cinfo)
+{
+	/* This function looks through the meta data in the libjpeg decompress structure to
+	   determine if an EXIF Orientation tag is present and if so return its value (1-8). 
+	   If no EXIF Orientation tag is found 0 (zero) is returned. */
+
+ 	guint   i;              /* index into working buffer */
+ 	guint   orient_tag_id;  /* endianed version of orientation tag ID */
+	guint   ret;            /* Return value */
+ 	guint   offset;        	/* de-endianed offset in various situations */
+ 	guint   tags;           /* number of tags in current ifd */
+ 	guint   type;           /* de-endianed type of tag used as index into types[] */
+ 	guint   count;          /* de-endianed count of elements in a tag */
+        guint   tiff = 0;   	/* offset to active tiff header */
+        guint   endian = 0;   	/* detected endian of data */
+
+	jpeg_saved_marker_ptr exif_marker;  /* Location of the Exif APP1 marker */
+	jpeg_saved_marker_ptr cmarker;	    /* Location to check for Exif APP1 marker */
+
+	/* check for Exif marker (also called the APP1 marker) */
+	exif_marker = NULL;
+	cmarker = cinfo->marker_list;
+	while (cmarker) {
+		if (cmarker->marker == EXIF_JPEG_MARKER) {
+			/* The Exif APP1 marker should contain a unique
+			   identification string ("Exif\0\0"). Check for it. */
+			if (!memcmp (cmarker->data, EXIF_IDENT_STRING, 6)) {
+				exif_marker = cmarker;
+				}
+			}
+		cmarker = cmarker->next;
+	}
+	  
+	/* Did we find the Exif APP1 marker? */
+	if (exif_marker == NULL)
+		return 0;
+
+	/* Do we have enough data? */
+	if (exif_marker->data_length < 32)
+		return 0;
+
+        /* Check for TIFF header and catch endianess */
+ 	i = 0;
+
+	/* Just skip data until TIFF header - it should be within 16 bytes from marker start.
+	   Normal structure relative to APP1 marker -
+		0x0000: APP1 marker entry = 2 bytes
+	   	0x0002: APP1 length entry = 2 bytes
+		0x0004: Exif Identifier entry = 6 bytes
+		0x000A: Start of TIFF header (Byte order entry) - 4 bytes  
+		    	- This is what we look for, to determine endianess.
+		0x000E: 0th IFD offset pointer - 4 bytes
+
+		exif_marker->data points to the first data after the APP1 marker
+		and length entries, which is the exif identification string.
+		The TIFF header should thus normally be found at i=6, below,
+		and the pointer to IFD0 will be at 6+4 = 10.
+ 	*/
+		    
+ 	while (i < 16) {
+ 
+ 		/* Little endian TIFF header */
+ 		if (memcmp (&exif_marker->data[i], leth, 4) == 0){ 
+ 			endian = G_LITTLE_ENDIAN;
+                }
+ 
+ 		/* Big endian TIFF header */
+ 		else if (memcmp (&exif_marker->data[i], beth, 4) == 0){ 
+ 			endian = G_BIG_ENDIAN;
+                }
+ 
+ 		/* Keep looking through buffer */
+ 		else {
+ 			i++;
+ 			continue;
+ 		}
+ 		/* We have found either big or little endian TIFF header */
+ 		tiff = i;
+ 		break;
+        }
+
+ 	/* So did we find a TIFF header or did we just hit end of buffer? */
+ 	if (tiff == 0) 
+		return 0;
+ 
+        /* Endian the orientation tag ID, to locate it more easily */
+        orient_tag_id = ENDIAN16_IT(0x112);
+ 
+        /* Read out the offset pointer to IFD0 */
+        offset  = DE_ENDIAN32(*((unsigned long*) (&exif_marker->data[i] + 4)));
+ 	i       = i + offset;
+
+	/* Check that we still are within the buffer and can read the tag count */
+	if ((i + 2) > exif_marker->data_length)
+		return 0;
+
+	/* Find out how many tags we have in IFD0. As per the TIFF spec, the first
+	   two bytes of the IFD contain a count of the number of tags. */
+	tags    = DE_ENDIAN16(*((unsigned short*) (&exif_marker->data[i])));
+	i       = i + 2;
+
+	/* Check that we still have enough data for all tags to check. The tags
+	   are listed in consecutive 12-byte blocks. The tag ID, type, size, and
+	   a pointer to the actual value, are packed into these 12 byte entries. */
+	if ((i + tags * 12) > exif_marker->data_length)
+		return 0;
+
+	/* Check through IFD0 for tags of interest */
+	while (tags--){
+		type   = DE_ENDIAN16(*((unsigned short*)(&exif_marker->data[i + 2])));
+		count  = DE_ENDIAN32(*((unsigned long*) (&exif_marker->data[i + 4])));
+
+		/* Is this the orientation tag? */
+		if (memcmp (&exif_marker->data[i], (char *) &orient_tag_id, 2) == 0){ 
+ 
+			/* Check that type and count fields are OK. The orientation field 
+			   will consist of a single (count=1) 2-byte integer (type=3). */
+			if (type != 3 || count != 1) return 0;
+
+			/* Return the orientation value. Within the 12-byte block, the
+			   pointer to the actual data is at offset 8. */
+			ret = DE_ENDIAN16(*((unsigned short*) (&exif_marker->data[i + 8])));
+			return ret <= 8 ? ret : 0;
+		}
+		/* move the pointer to the next 12-byte tag field. */
+		i = i + 12;
+	}
+
+	return 0; /* No EXIF Orientation tag found */
+}
+
+
 /* Shared library entry point */
 static GdkPixbuf *
 gdk_pixbuf__jpeg_image_load (FILE *f, GError **error)
 {
-	gint i;
+	gint   i;
+	int     is_otag;
+	char   otag_str[5];
 	GdkPixbuf * volatile pixbuf = NULL;
 	guchar *dptr;
 	guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height, 
@@ -332,7 +482,12 @@
 	src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
 	src->pub.next_input_byte = NULL; /* until buffer loaded */
 
+	jpeg_save_markers (&cinfo, EXIF_JPEG_MARKER, 0xffff);
 	jpeg_read_header (&cinfo, TRUE);
+
+	/* check for orientation tag */
+	is_otag = get_orientation (&cinfo);
+	
 	jpeg_start_decompress (&cinfo);
 	cinfo.do_fancy_upsampling = FALSE;
 	cinfo.do_block_smoothing = FALSE;
@@ -357,6 +512,13 @@
 		return NULL;
 	}
 
+	/* if orientation tag was found set an option to remember its value */
+	if (is_otag) {
+		snprintf(otag_str, sizeof(otag_str), "%d", is_otag);
+		gdk_pixbuf_set_option(pixbuf, "orientation", otag_str);
+	}
+
+
 	dptr = pixbuf->pixels;
 
 	/* decompress all the lines, a few at a time */
@@ -626,14 +788,16 @@
                                        GError **error)
 {
 	JpegProgContext *context = (JpegProgContext *)data;
-	struct jpeg_decompress_struct *cinfo;
-	my_src_ptr  src;
-	guint       num_left, num_copy;
-	guint       last_bytes_left;
-	guint       spinguard;
-	gboolean    first;
-	const guchar *bufhd;
-	gint        width, height;
+	struct           jpeg_decompress_struct *cinfo;
+	my_src_ptr       src;
+	guint            num_left, num_copy;
+	guint            last_bytes_left;
+	guint            spinguard;
+	gboolean         first;
+	const guchar    *bufhd;
+	gint             width, height;
+        int              is_otag;
+	char             otag_str[5];
 
 	g_return_val_if_fail (context != NULL, FALSE);
 	g_return_val_if_fail (buf != NULL, FALSE);
@@ -707,7 +871,8 @@
 		/* try to load jpeg header */
 		if (!context->got_header) {
 			int rc;
-			
+		
+			jpeg_save_markers (cinfo, EXIF_JPEG_MARKER, 0xffff);
 			rc = jpeg_read_header (cinfo, TRUE);
 			context->src_initialized = TRUE;
 			
@@ -715,7 +880,10 @@
 				continue;
 			
 			context->got_header = TRUE;
-			
+
+			/* check for orientation tag */
+			is_otag = get_orientation (cinfo);
+		
 			width = cinfo->image_width;
 			height = cinfo->image_height;
 			if (context->size_func) {
@@ -751,7 +919,13 @@
                                              _("Couldn't allocate memory for loading JPEG file"));
                                 return FALSE;
 			}
-			
+		
+		        /* if orientation tag was found set an option to remember its value */
+		        if (is_otag) {
+                		snprintf(otag_str, sizeof(otag_str), "%d", is_otag);
+		                gdk_pixbuf_set_option (context->pixbuf, "orientation", otag_str);
+		        }
+
 			/* Use pixbuf buffer to store decompressed data */
 			context->dptr = context->pixbuf->pixels;
 			
Index: README.in
===================================================================
--- README.in	(revision 17792)
+++ README.in	(working copy)
@@ -30,6 +30,8 @@
 Release notes for 2.10
 ======================
 
+* The tiff loader now requires libtiff 3.6.0 or later.
+
 * The hexadecimal Unicode input feature has been reworked. It no longer
   blocks the use of the sixteen Ctrl-Shift-<hex digit> key sequences. Now
   it only uses Ctrl-Shift-u.
Index: INSTALL
===================================================================
--- INSTALL	(revision 17792)
+++ INSTALL	(working copy)
@@ -15,6 +15,8 @@
     http://www.libpng.org/
     http://www.ijg.org/
 
+    libtiff must be version 3.6.0 or higher.
+
 Simple install procedure
 ========================
 
Index: INSTALL.in
===================================================================
--- INSTALL.in	(revision 17792)
+++ INSTALL.in	(working copy)
@@ -15,6 +15,8 @@
     http://www.libpng.org/
     http://www.ijg.org/
 
+    libtiff must be version 3.6.0 or higher.
+
 Simple install procedure
 ========================
 
Index: configure.in
===================================================================
--- configure.in	(revision 17792)
+++ configure.in	(working copy)
@@ -736,7 +736,7 @@
 
 dnl Test for libtiff
   if test x$with_libtiff != xno && test -z "$LIBTIFF"; then
-    AC_CHECK_LIB(tiff, TIFFReadScanline,
+    AC_CHECK_LIB(tiff, TIFFReadRGBAImageOriented,
       [AC_CHECK_HEADER(tiffio.h,
         TIFF='tiff'; LIBTIFF='-ltiff',
         AC_MSG_WARN(*** TIFF loader will not be built (TIFF header files not found) ***))],
