diff --git a/Graphics/HsExif.hs b/Graphics/HsExif.hs
--- a/Graphics/HsExif.hs
+++ b/Graphics/HsExif.hs
@@ -1,39 +1,115 @@
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 -- | Ability to work with the EXIF data contained in JPEG files.
-module Graphics.HsExif (ExifTag(..), parseFileExif, parseExif, getDateTimeOriginal) where
+module Graphics.HsExif (
+	ExifTag(..),
+	TagLocation(..),
+	ExifValue(..),
+	parseFileExif,
+	parseExif,
+	getDateTimeOriginal,
+	getOrientation,
+	ImageOrientation(..),
+	RotationDirection(..),
 
+	-- now all known exif tags
+	exposureTime,
+	fnumber,
+	exposureProgram,
+	isoSpeedRatings,
+	exifVersion,
+	dateTimeOriginal,
+	dateTimeDigitized,
+	componentConfiguration,
+	compressedBitsPerPixel,
+	shutterSpeedValue,
+	apertureValue,
+	brightnessValue,
+	exposureBiasValue,
+	maxApertureValue,
+	subjectDistance,
+	meteringMode,
+	lightSource,
+	flash,
+	focalLength,
+	makerNote,
+	userComment,
+	colorSpace,
+	exifImageWidth,
+	exifImageHeight,
+	relatedSoundFile,
+	focalPlaneXResolution,
+	focalPlaneYResolution,
+	focalPlaneResolutionUnit,
+	sensingMethod,
+	fileSource,
+	sceneType,
+	orientation,
+	make,
+	model,
+	software,
+	copyright,
+) where
+
 import Data.Binary.Get
 import qualified Data.ByteString.Lazy as B
 import Control.Monad (liftM, unless)
 import qualified Data.ByteString.Char8 as Char8
 import Data.Word
-import Data.Int
+import Data.Int (Int32)
 import Data.List
 import Data.Maybe (fromMaybe)
 import qualified Data.Map as Map
 import Data.Map (Map)
 import Data.Time.LocalTime
 import Data.Time.Calendar
+import Numeric (showHex)
 
+-- | An exif value. Exif values can also be float,
+-- but this library doesn't support it yet. If you
+-- have JPG files containing float exif values,
+-- please send it!
+--
+-- If you want a string describing the contents
+-- of the value, simply use 'show'.
+data ExifValue = ExifNumber Int
+	-- ^ An exif number. Could be short, int, signed or not.
+	| ExifText String
+	-- ^ ASCII text.
+	| ExifRational Int Int
+	-- ^ A rational number (numerator, denominator).
+	-- Sometimes we're used to it as rational (exposition time: 1/160),
+	-- sometimes as float (exposition compensation, we rather think -0.75)
+	-- 'show' will display it as 1/160.
+	| ExifUnknown Word16 Int -- type then value
+	-- ^ Unknown exif tag. Not a rarity, we don't support all existing tags.
+	deriving Eq
+
+instance Show ExifValue where
+	show (ExifNumber v) = show v
+	show (ExifText v) = v
+	show (ExifRational n d) = show n ++ "/" ++ show d
+	show (ExifUnknown t v) = show "Unknown exif type. Type: " ++ show t ++ " value: " ++ show v
+
 -- see http://www.media.mit.edu/pia/Research/deepview/exif.html
 
 -- | Read EXIF data from the file you give. It's a key-value map.
-parseFileExif :: FilePath -> IO (Either String (Map ExifTag String))
+parseFileExif :: FilePath -> IO (Either String (Map ExifTag ExifValue))
 parseFileExif filename = liftM parseExif $ B.readFile filename
 
 -- | Read EXIF data from a lazy bytestring.
-parseExif :: B.ByteString -> Either String (Map ExifTag String)
+parseExif :: B.ByteString -> Either String (Map ExifTag ExifValue)
 parseExif contents = case runGetOrFail getExif contents of
 		Left (_,_,errorMsg) -> Left errorMsg
 		Right (_,_,result) -> Right result
 
-getExif :: Get (Map ExifTag String)
+getExif :: Get (Map ExifTag ExifValue)
 getExif = do
 	header <- getWord16be
 	unless (header == 0xffd8)
 		$ fail "Not a JPEG file"
 	findAndParseExifBlock
 
-findAndParseExifBlock :: Get (Map ExifTag String)
+findAndParseExifBlock :: Get (Map ExifTag ExifValue)
 findAndParseExifBlock = do
 	markerNumber <- getWord16be
 	dataSize <- liftM (fromIntegral . toInteger) getWord16be
@@ -54,7 +130,7 @@
 getWord32 Intel = getWord32le
 getWord32 Motorola = getWord32be
 
-parseExifBlock :: Get (Map ExifTag String)
+parseExifBlock :: Get (Map ExifTag ExifValue)
 parseExifBlock = do
 	header <- getByteString 4
 	nul <- liftM toInteger getWord16be
@@ -62,11 +138,13 @@
 		$ fail "invalid EXIF header"
 	tiffHeaderStart <- liftM fromIntegral bytesRead
 	byteAlign <- parseTiffHeader
-	exifSubIfdOffset <- liftM (fromIntegral . toInteger) (parseIfd byteAlign)
+	(exifSubIfdOffsetW, ifdEntries) <- parseIfd byteAlign tiffHeaderStart
+	let exifSubIfdOffset = fromIntegral $ toInteger exifSubIfdOffsetW
 	-- skip to the exif offset
 	bytesReadNow <- liftM fromIntegral bytesRead
 	skip $ (exifSubIfdOffset + tiffHeaderStart) - bytesReadNow
-	parseExifSubIfd byteAlign tiffHeaderStart
+	exifSubEntries <- parseExifSubIfd byteAlign tiffHeaderStart
+	return $ Map.fromList $ ifdEntries ++ exifSubEntries
 
 parseTiffHeader :: Get ByteAlign
 parseTiffHeader = do
@@ -82,21 +160,21 @@
 	skip $ ifdOffset - 8
 	return byteAlign
 
-parseIfd :: ByteAlign -> Get Word32
-parseIfd byteAlign = do
+parseIfd :: ByteAlign -> Int -> Get (Word32, [(ExifTag, ExifValue)])
+parseIfd byteAlign tiffHeaderStart = do
 	dirEntriesCount <- liftM toInteger (getWord16 byteAlign)
 	ifdEntries <- mapM (\_ -> parseIfEntry byteAlign) [1..dirEntriesCount]
 	let exifOffsetEntry = fromMaybe (error "Can't find the exif offset in the IFD")
 		(find (\ e -> entryTag e == 0x8769) ifdEntries)
 	let exifOffset = entryContents exifOffsetEntry
-	return exifOffset
+	entries <- mapM (decodeEntry byteAlign tiffHeaderStart IFD0) ifdEntries
+	return (exifOffset, entries)
 
-parseExifSubIfd :: ByteAlign -> Int -> Get (Map ExifTag String)
+parseExifSubIfd :: ByteAlign -> Int -> Get [(ExifTag, ExifValue)]
 parseExifSubIfd byteAlign tiffHeaderStart = do
 	dirEntriesCount <- liftM toInteger (getWord16 byteAlign)
 	ifdEntries <- mapM (\_ -> parseIfEntry byteAlign) [1..dirEntriesCount]
-	list <- mapM (decodeEntry byteAlign tiffHeaderStart) ifdEntries
-	return $ Map.fromList list
+	mapM (decodeEntry byteAlign tiffHeaderStart ExifSubIFD) ifdEntries
 
 data IfEntry = IfEntry
 	{
@@ -120,126 +198,168 @@
 			entryContents = value
 		}
 
-data ExifTag = ExposureTime
-	| FNumber
-	| ExposureProgram
-	| ISOSpeedRatings
-	| ExifVersion
-	| DateTimeOriginal
-	| DateTimeDigitized
-	| ComponentConfiguration
-	| CompressedBitsPerPixel
-	| ShutterSpeedValue
-	| ApertureValue
-	| BrightnessValue
-	| ExposureBiasValue
-	| MaxApertureValue
-	| SubjectDistance
-	| MeteringMode
-	| LightSource
-	| Flash
-	| FocalLength
-	| MakerNote
-	| UserComment
-	| FlashPixVersion
-	| ColorSpace
-	| ExifImageWidth
-	| ExifImageHeight
-	| RelatedSoundFile
-	| ExifInteroperabilityOffset
-	| FocalPlaneXResolution
-	| FocalPlaneYResolution
-	| FocalPlaneResolutionUnit
-	| SensingMethod
-	| FileSource
-	| SceneType
-	| Unknown Word16
-	deriving (Eq, Ord, Show)
+-- | Location of the tag in the JPG file structure.
+-- Normally you don't need to fiddle with this,
+-- except maybe if the library doesn't know the particular
+-- exif tag you're interested in.
+-- Rather check the list of supported exif tags, like
+-- 'exposureTime' and so on.
+data TagLocation = ExifSubIFD | IFD0
+	deriving (Show, Eq, Ord)
 
-getExifTag :: Word16 -> ExifTag
-getExifTag entryTagV = case entryTagV of
-	0x829a -> ExposureTime
-	0x829d -> FNumber
-	0x8822 -> ExposureProgram
-	0x8827 -> ISOSpeedRatings
-	0x9000 -> ExifVersion
-	0x9003 -> DateTimeOriginal
-	0x9004 -> DateTimeDigitized
-	0x9101 -> ComponentConfiguration
-	0x9102 -> CompressedBitsPerPixel
-	0x9201 -> ShutterSpeedValue
-	0x9202 -> ApertureValue
-	0x9203 -> BrightnessValue
-	0x9204 -> ExposureBiasValue
-	0x9205 -> MaxApertureValue
-	0x9206 -> SubjectDistance
-	0x9207 -> MeteringMode
-	0x9208 -> LightSource
-	0x9209 -> Flash
-	0x920a -> FocalLength
-	0x927c -> MakerNote
-	0x9286 -> UserComment
-	0xa000 -> FlashPixVersion
-	0xa001 -> ColorSpace
-	0xa002 -> ExifImageWidth
-	0xa003 -> ExifImageHeight
-	0xa004 -> RelatedSoundFile
-	0xa005 -> ExifInteroperabilityOffset
-	0xa20e -> FocalPlaneXResolution
-	0xa20f -> FocalPlaneYResolution
-	0xa210 -> FocalPlaneResolutionUnit
-	0xa217 -> SensingMethod
-	0xa300 -> FileSource
-	0xa301 -> SceneType
-	_ -> Unknown entryTagV
+-- | An exif tag. Normally you don't need to fiddle with this,
+-- except maybe if the library doesn't know the particular
+-- exif tag you're interested in.
+-- Rather check the list of supported exif tags, like
+-- 'exposureTime' and so on.
+data ExifTag = ExifTag
+	{
+		tagLocation :: TagLocation,
+		-- ^ In which part of the JPEG file the exif tag was found
+		tagDesc :: Maybe String,
+		-- ^ Description of the exif tag (exposureTime, fnumber...) or if unknown, Nothing.
+		-- This should be purely for debugging purposes, to compare tags use == on ExifTag
+		-- or compare the tagKey.
+		tagKey :: Word16
+		-- ^ Exif tag key, the number uniquely identifying this tag.
+	}
+	deriving (Eq, Ord)
 
-decodeEntry :: ByteAlign -> Int -> IfEntry -> Get (ExifTag, String)
-decodeEntry byteAlign tiffHeaderStart entry = do
-	let tagKey = getExifTag $ entryTag entry
+instance Show ExifTag where
+	show (ExifTag _ (Just d) _) = d
+	show (ExifTag l _ v) = "Unknown tag, location: " ++ show l
+		++ ", value: 0x" ++ showHex v ""
+
+exifSubIfdTag :: String -> Word16 -> ExifTag
+exifSubIfdTag d = ExifTag ExifSubIFD (Just d)
+
+exifIfd0Tag :: String -> Word16 -> ExifTag
+exifIfd0Tag d = ExifTag IFD0 (Just d)
+
+exposureTime		= exifSubIfdTag "exposureTime" 0x829a
+fnumber			= exifSubIfdTag "fnumber" 0x829d
+exposureProgram		= exifSubIfdTag "exposureProgram" 0x8822
+isoSpeedRatings		= exifSubIfdTag "isoSpeedRatings" 0x8827 
+exifVersion		= exifSubIfdTag "exifVersion" 0x9000 
+dateTimeOriginal	= exifSubIfdTag "dateTimeOriginal" 0x9003 
+dateTimeDigitized	= exifSubIfdTag "dateTimeDigitized" 0x9004 
+componentConfiguration	= exifSubIfdTag "componentConfiguration" 0x9101 
+compressedBitsPerPixel	= exifSubIfdTag "compressedBitsPerPixel" 0x9102 
+shutterSpeedValue	= exifSubIfdTag "shutterSpeedValue" 0x9201 
+apertureValue		= exifSubIfdTag "apertureValue" 0x9202 
+brightnessValue		= exifSubIfdTag "brightnessValue" 0x9203 
+exposureBiasValue	= exifSubIfdTag "exposureBiasValue" 0x9204 
+maxApertureValue	= exifSubIfdTag "maxApertureValue" 0x9205 
+subjectDistance		= exifSubIfdTag "subjectDistance" 0x9206 
+meteringMode		= exifSubIfdTag "meteringMode" 0x9207 
+lightSource		= exifSubIfdTag "lightSource" 0x9208 
+flash			= exifSubIfdTag "flash" 0x9209 
+focalLength		= exifSubIfdTag "focalLength" 0x920a 
+makerNote		= exifSubIfdTag "makerNote" 0x927c 
+userComment		= exifSubIfdTag "userComment" 0x9286 
+colorSpace		= exifSubIfdTag "colorSpace" 0xa001 
+exifImageWidth		= exifSubIfdTag "exifImageWidth" 0xa002 
+exifImageHeight		= exifSubIfdTag "exifImageHeight" 0xa003 
+relatedSoundFile	= exifSubIfdTag "relatedSoundFile" 0xa004 
+focalPlaneXResolution	= exifSubIfdTag "focalPlaneXResolution" 0xa20e 
+focalPlaneYResolution	= exifSubIfdTag "focalPlaneYResolution" 0xa20f 
+focalPlaneResolutionUnit= exifSubIfdTag "focalPlaneResolutionUnit" 0xa210 
+sensingMethod		= exifSubIfdTag "sensingMethod" 0xa217 
+fileSource		= exifSubIfdTag "fileSource" 0xa300 
+sceneType		= exifSubIfdTag "sceneType" 0xa301 
+orientation		= exifIfd0Tag "orientation" 0x0112 
+make			= exifIfd0Tag "make" 0x010f 
+model			= exifIfd0Tag "model" 0x0110 
+software		= exifIfd0Tag "software" 0x0131 
+copyright		= exifIfd0Tag "copyright" 0x8298 
+
+allExifTags :: [ExifTag]
+allExifTags = [exposureTime, fnumber, exposureProgram, isoSpeedRatings,
+	exifVersion, dateTimeOriginal, dateTimeDigitized, componentConfiguration,
+	compressedBitsPerPixel, shutterSpeedValue, apertureValue, brightnessValue,
+	exposureBiasValue, maxApertureValue, subjectDistance, meteringMode,
+	lightSource, flash, focalLength, makerNote, userComment, colorSpace,
+	exifImageWidth, exifImageHeight, relatedSoundFile, focalPlaneXResolution,
+	focalPlaneYResolution, focalPlaneResolutionUnit, sensingMethod, fileSource,
+	sceneType, orientation, make, model, software, copyright]
+
+getExifTag :: TagLocation -> Word16 -> ExifTag
+getExifTag l v = fromMaybe (ExifTag l Nothing v) $ find (isSameTag l v) allExifTags
+	where isSameTag l1 v1 (ExifTag l2 _ v2) = l1 == l2 && v1 == v2
+
+decodeEntry :: ByteAlign -> Int -> TagLocation -> IfEntry -> Get (ExifTag, ExifValue)
+decodeEntry byteAlign tiffHeaderStart location entry = do
+	let exifTag = getExifTag location $ entryTag entry
 	let contentsInt = fromIntegral $ toInteger $ entryContents entry
 	let componentsInt = fromIntegral $ toInteger $ entryNoComponents entry
 	-- because I only know how to skip ahead, I hope the entries
 	-- are always sorted in order of the offsets to their values...
 	-- (maybe lookAhead could help here?)
 	tagValue <- case entryFormat entry of
-		1 -> return $ show contentsInt -- unsigned byte
+		1 -> return $ ExifNumber contentsInt -- unsigned byte
 		2 -> do -- ascii string
 			curPos <- liftM fromIntegral bytesRead
 			skip $ contentsInt + tiffHeaderStart - curPos
-			liftM Char8.unpack (getByteString (componentsInt-1))
-		3 -> return $ show contentsInt -- unsigned short
-		4 -> return $ show contentsInt -- unsigned long
+			liftM (ExifText . Char8.unpack) (getByteString (componentsInt-1))
+		3 -> return $ ExifNumber contentsInt -- unsigned short
+		4 -> return $ ExifNumber contentsInt -- unsigned long
 		5 -> do -- unsigned rational
 			curPos <- liftM fromIntegral bytesRead
 			skip $ contentsInt + tiffHeaderStart - curPos
-			numerator <- getWord32 byteAlign
-			denominator <- getWord32 byteAlign
-			return $ show numerator ++ "/" ++ show denominator
-		6 -> return $ show $ word32toint32 $ entryContents entry -- signed byte
-		7 -> return $ show contentsInt -- undefined
-		8 -> return $ show $ word32toint32 $ entryContents entry -- signed short
-		9 -> return $ show $ word32toint32 $ entryContents entry -- signed long
+			numerator <- liftM fromIntegral $ getWord32 byteAlign
+			denominator <- liftM fromIntegral $ getWord32 byteAlign
+			return $ ExifRational numerator denominator
+		6 -> return $ ExifNumber $ signedInt32ToInt $ entryContents entry -- signed byte
+		7 -> return $ ExifNumber contentsInt -- undefined
+		8 -> return $ ExifNumber $ signedInt32ToInt $ entryContents entry -- signed short
+		9 -> return $ ExifNumber $ signedInt32ToInt $ entryContents entry -- signed long
 		10 -> do -- signed rational
 			curPos <- liftM fromIntegral bytesRead
 			skip $ contentsInt + tiffHeaderStart - curPos
-			numerator <- liftM word32toint32 (getWord32 byteAlign)
-			denominator <- liftM word32toint32 (getWord32 byteAlign)
-			return $ show numerator ++ "/" ++ show denominator
+			numerator <- liftM signedInt32ToInt (getWord32 byteAlign)
+			denominator <- liftM signedInt32ToInt (getWord32 byteAlign)
+			return $ ExifRational numerator denominator
 		-- TODO decode float values, 11 single float and 12 double float but I'd like tests
-		_ -> return $ "type: " ++ show (entryFormat entry) ++ " -> " ++ show contentsInt
-	return (tagKey, tagValue)
+		_ -> return $ ExifUnknown (entryFormat entry) contentsInt
+	return (exifTag, tagValue)
 
-word32toint32 :: Word32 -> Int32
-word32toint32 word = fromIntegral word :: Int32
+signedInt32ToInt :: Word32 -> Int
+signedInt32ToInt w = fromIntegral (fromIntegral w :: Int32)
 
 -- | Extract the date and time when the picture was taken
 -- from the EXIF information.
-getDateTimeOriginal :: Map ExifTag String -> Maybe LocalTime
+getDateTimeOriginal :: Map ExifTag ExifValue -> Maybe LocalTime
 getDateTimeOriginal exifData = do 
-	dateStr <- Map.lookup DateTimeOriginal exifData
+	dateStr <- liftM show $ Map.lookup dateTimeOriginal exifData
 	-- i know more elegant ways to code this.. parsec, regex, text..
 	-- but i don't want to bring in too many dependencies to this library.
 	-- the date is like "YYYY:MM:DD HH:MM:SS"
 	return $ LocalTime
 		(fromGregorian (read $ take 4 dateStr) (read $ take 2 . drop 5 $ dateStr) (read $ take 2 . drop 8 $ dateStr))
 		(TimeOfDay (read $ take 2 . drop 11 $ dateStr) (read $ take 2 . drop 14 $ dateStr) (read $ take 2 . drop 17 $ dateStr))
+
+data RotationDirection = MinusNinety
+	| Ninety
+	| HundredAndEighty
+	deriving (Show, Eq)
+
+data ImageOrientation = Normal
+	| Mirror
+	| Rotation RotationDirection
+	| MirrorRotation RotationDirection
+	deriving (Show, Eq)
+
+-- | Extract the image orientation from the EXIF information.
+getOrientation :: Map ExifTag ExifValue -> Maybe ImageOrientation
+getOrientation exifData = do
+	rotationVal <- Map.lookup orientation exifData
+	case rotationVal of
+		ExifNumber 1 -> Just Normal
+		ExifNumber 2 -> Just Mirror
+		ExifNumber 3 -> Just $ Rotation HundredAndEighty
+		ExifNumber 4 -> Just $ MirrorRotation HundredAndEighty
+		ExifNumber 5 -> Just $ MirrorRotation MinusNinety
+		ExifNumber 6 -> Just $ Rotation MinusNinety
+		ExifNumber 7 -> Just $ MirrorRotation Ninety
+		ExifNumber 8 -> Just $ Rotation Ninety
+		_ -> error $ show rotationVal
diff --git a/hsexif.cabal b/hsexif.cabal
--- a/hsexif.cabal
+++ b/hsexif.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                hsexif
-version:             0.1.0.1
+version:             0.2.0.0
 synopsis:            EXIF handling library in pure Haskell
 description:         The hsexif library provides functions for working with EXIF data
                      contained in JPEG files. Currently it only supports reading the data.
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -4,19 +4,24 @@
 import Graphics.HsExif
 import qualified Data.ByteString.Lazy as B
 import qualified Data.Map as Map
+import Data.Map (Map)
 import Data.Time.LocalTime
 import Data.Time.Calendar
+import Data.Word
 
 main :: IO ()
 main = do
 	imageContents <- B.readFile "tests/test.jpg"
 	noExif <- B.readFile "tests/noexif.jpg"
 	png <- B.readFile "tests/test.png"
+	let parseExifCorrect = (\(Right x) -> x) . parseExif
+	let exifData = parseExifCorrect imageContents
 	hspec $ do
 		describe "not a JPG" $ testNotAJpeg png
 		describe "no EXIF" $ testNoExif noExif
 		describe "basic parsing" $ testBasic imageContents
-		describe "extract picture date" $ testDate imageContents
+		describe "extract picture date" $ testDate exifData
+		describe "image orientation" $ testOrientation exifData
 
 testNotAJpeg :: B.ByteString -> Spec
 testNotAJpeg imageContents = it "returns empty list if not a JPEG" $
@@ -28,9 +33,66 @@
 
 testBasic :: B.ByteString -> Spec
 testBasic imageContents = it "parses a simple JPEG" $
-	assertEqual "doesn't match" (Right $ Map.fromList [(ExposureTime,"1/160"),(FNumber,"0/10"),(ExposureProgram,"2"),(ISOSpeedRatings,"1600"),(ExifVersion,"808661552"),(DateTimeOriginal,"2013:10:02 20:33:33"),(DateTimeDigitized,"2013:10:02 20:33:33"),(ComponentConfiguration,"197121"),(CompressedBitsPerPixel,"2/1"),(BrightnessValue,"-4226/2560"),(ExposureBiasValue,"0/10"),(MaxApertureValue,"0/10"),(MeteringMode,"5"),(LightSource,"0"),(Flash,"24"),(FocalLength,"0/10"),(MakerNote,"868"),(UserComment,"36568"),(FlashPixVersion,"808464688"),(ColorSpace,"1"),(ExifImageWidth,"1"),(ExifImageHeight,"1"),(ExifInteroperabilityOffset,"36640"),(FileSource,"3"),(SceneType,"1"),(Unknown 41985,"0"),(Unknown 41986,"0"),(Unknown 41987,"0"),(Unknown 41988,"16/16"),(Unknown 41989,"0"),(Unknown 41990,"0"),(Unknown 41992,"0"),(Unknown 41993,"0"),(Unknown 41994,"0")]) (parseExif imageContents)
+	assertEqual "doesn't match" (Right $ Map.fromList [
+		(exposureTime, ExifRational 1 160),
+		(fnumber, ExifRational 0 10),
+		(exposureProgram, ExifNumber 2),
+		(isoSpeedRatings, ExifNumber 1600),
+		(exifVersion, ExifNumber 808661552),
+		(dateTimeOriginal, ExifText "2013:10:02 20:33:33"),
+		(dateTimeDigitized, ExifText "2013:10:02 20:33:33"),
+		(componentConfiguration, ExifNumber 197121),
+		(compressedBitsPerPixel, ExifRational 2 1),
+		(brightnessValue, ExifRational (-4226) 2560),
+		(exposureBiasValue, ExifRational 0 10),
+		(maxApertureValue, ExifRational 0 10),
+		(meteringMode, ExifNumber 5),
+		(lightSource, ExifNumber 0),
+		(fileSource, ExifNumber 3),
+		(flash, ExifNumber 24),
+		(focalLength, ExifRational 0 10),
+		(makerNote, ExifNumber 868),
+		(userComment, ExifNumber 36568),
+		(unknownExifSubIfdTag 40960, ExifNumber 808464688),
+		(colorSpace, ExifNumber 1),
+		(sceneType, ExifNumber 1),
+		(exifImageWidth, ExifNumber 1),
+		(exifImageHeight, ExifNumber 1),
+		(unknownExifSubIfdTag 40965, ExifNumber 36640),
+		(unknownExifSubIfdTag 41985, ExifNumber 0),
+		(unknownExifSubIfdTag 41986, ExifNumber 0),
+		(unknownExifSubIfdTag 41987, ExifNumber 0),
+		(unknownExifSubIfdTag 41988, ExifRational 16 16),
+		(unknownExifSubIfdTag 41989, ExifNumber 0),
+		(unknownExifSubIfdTag 41990, ExifNumber 0),
+		(unknownExifSubIfdTag 41992, ExifNumber 0),
+		(unknownExifSubIfdTag 41993, ExifNumber 0),
+		(unknownExifSubIfdTag 41994, ExifNumber 0),
+		(make, ExifText "SONY"),
+		(model, ExifText "NEX-3N"),
+		(software, ExifText "GIMP 2.8.10"),
+		(orientation, ExifNumber 1),
+		(unknownExifIfd0Tag 0x10e, ExifText "                               "),
+		(unknownExifIfd0Tag 0x11a, ExifRational 350 1),
+		(unknownExifIfd0Tag 0x11b, ExifRational 350 1),
+		(unknownExifIfd0Tag 0x128, ExifNumber 2),
+		(unknownExifIfd0Tag 0x132, ExifText "2014:04:10 20:14:20"),
+		(unknownExifIfd0Tag 0x213, ExifNumber 2),
+		(unknownExifIfd0Tag 0x8769, ExifNumber 358),
+		(unknownExifIfd0Tag 0xc4a5, ExifNumber 252)
+	]) (parseExif imageContents)
 
-testDate :: B.ByteString -> Spec
-testDate imageContents = it "extracts the date correctly" $
+unknownExifSubIfdTag :: Word16 -> ExifTag
+unknownExifSubIfdTag = ExifTag ExifSubIFD Nothing
+
+unknownExifIfd0Tag :: Word16 -> ExifTag
+unknownExifIfd0Tag = ExifTag IFD0 Nothing
+
+testDate :: Map ExifTag ExifValue -> Spec
+testDate exifData = it "extracts the date correctly" $
 	assertEqual "doesn't match" (Just $ LocalTime (fromGregorian 2013 10 2) (TimeOfDay 20 33 33))
-		(getDateTimeOriginal $ (\(Right x) -> x) $ parseExif imageContents)
+		(getDateTimeOriginal exifData)
+
+testOrientation :: Map ExifTag ExifValue -> Spec
+testOrientation exifData = it "reads exif orientation" $
+	assertEqual "doesn't match" (Just Normal) $ getOrientation exifData
