TASSOGRAPHY

Photography and More
by Ben Vincent
TransparentPadder

Share On FacebookShare On Facebook
 
Ben's Blog (71)Ben's Blog (71)
Development (16)Development (16)
Lisa's Blog (6)Lisa's Blog (6)
 
Show All (94)Show All (94)
 
Jun 2010 (4)Jun 2010 (4)
May 2010 (2)May 2010 (2)
Apr 2010 (7)Apr 2010 (7)
Mar 2010 (5)Mar 2010 (5)
Feb 2010 (1)Feb 2010 (1)
Jan 2010 (3)Jan 2010 (3)
Nov 2009 (8)Nov 2009 (8)
Oct 2009 (4)Oct 2009 (4)
Sep 2009 (4)Sep 2009 (4)
Jul 2009 (6)Jul 2009 (6)
Jun 2009 (5)Jun 2009 (5)
May 2009 (7)May 2009 (7)
Mar 2009 (1)Mar 2009 (1)
Feb 2009 (5)Feb 2009 (5)
Jan 2009 (7)Jan 2009 (7)
Dec 2008 (6)Dec 2008 (6)
Oct 2008 (3)Oct 2008 (3)
Sep 2008 (3)Sep 2008 (3)
Aug 2008 (9)Aug 2008 (9)
Jul 2008 (3)Jul 2008 (3)
Jun 2008 (1)Jun 2008 (1)
 
Show All (94)Show All (94)
 
RSS & Atom FeedsRSS & Atom Feeds




TransparentPadder
Home Job Runner Image Usage Tracker Image Blog   |   Highlights   |   Photography   |   Contact   |   About    Atom & RSS Feeds  

Reading and Creating Exif Rationals by Ben Vincent

Quite why Jeida who created Exif decided to use Rationals is beyond me but they did so you have to work with them if you’re playing with jpg metadata. In this blog post I’ll share my Rational class so you don’t have to go through all the pain I went through in creating it. It’s amusingly short now I look at it here but it took way too long to work it out.

The class has two constructors, one for the value you’ve retrieved from BitmapMetadata, the second when you’re creating your own rationals. Internally the value is stored as two ints (the numerator and denominator). Additionally, there are four methods for retrieving the value of the Rational as a uLong, Double, Int and String.

public class Rational
{
    private int numerator;
    private int denominator;

    /// <summary>
    /// Creates an Exif Rational
    /// </summary>
    /// <param name="numerator">The value you want to store in the Rational</param>
    /// <param name="accuracy">The number of decimal places of accuracy</param>

    public Rational(double numerator, int accuracy)
    {
        accuracy = (int)Math.Pow(10, accuracy);

        this.numerator = Convert.ToInt32(Math.Abs(numerator * accuracy));
        this.denominator = accuracy;
    }

    /// <summary>
    /// Creates an Exif Rational
    /// </summary>
    /// <param name="data">A ulong typically read from exif metadata</param>

    public Rational(ulong data)
    {
        this.numerator = (int)(data & 0xFFFFFFFFL);
        this.denominator = (int)((data & 0xFFFFFFFF00000000L) >> 32);
    }

    /// <summary>
    /// Returns the Rational as a Ulong, typically used to write back to exif metadata
    /// </summary>
    /// <returns>Ulong</returns>
    public ulong ToUlong()
    {
        return ((ulong)this.numerator) | (((ulong)this.denominator) << 32);
    }

    /// <summary>
    /// Returns the Rational as an Integer
    /// </summary>
    /// <returns>Int</returns>

    public int ToInt()
    {
        return Convert.ToInt32(Math.Round(Convert.ToDouble(this.numerator) / Convert.ToDouble(this.denominator)));
    }

    /// <summary>
    /// Returns the Rational as a Double
    /// </summary>
    /// <returns>Double</returns>

    public double ToDouble()
    {
        return this.ToDouble(0);
    }

    /// <summary>
    /// Returns the Rational as a Double
    /// </summary>
    /// <returns>Double, accurate to the specified number of decimal places</returns>

    /// <param name="decimalPlaces">The number of decimal places of accuracy</param>
    public double ToDouble(int decimalPlaces)
    {
        return Math.Round(Convert.ToDouble(this.numerator) / Convert.ToDouble(this.denominator), decimalPlaces);
    }

    /// <summary>
    /// Returns the Rational as a string
    /// </summary>
    /// <returns>A string in the format numerator/denominator</returns>

    public new string ToString()
    {
        return this.numerator.ToString() + "/" + this.denominator.ToString();
    }
}

Using Exposure Bias as an example, here’s how you use the class to read the value, and if desired write it back:

// Query for Exposure Bias
string exifExposureBias = "/app1/ifd/exif/subifd:{uint=37380}";

// Grab copy of BitmapMetadata
BitmapMetadata bitmapMetadata = StandaloneWpfReader.ReadMetadata("Test-Geotagging.jpg");

// Try parsing the value as a ulong
ulong numeric;

if (ulong.TryParse(bitmapMetadata.GetQuery(exifExposureBias).ToString(), out numeric))
{
    // Create Rational
    Rational rational = new Rational(numeric);

    // Write the ulong value back
    bitmapMetadata.SetQuery(exifExposureBias, rational.ToUlong());
}

Lets take an example where the Exposure Bias is 1. Here are the values you might see when debugging this code. Note how the numeric passed into the Rational (the numeric = 4294967297) is the same as the value rational.ToUlong() value.

Exposure Bias Debug Output

It’s worth noting that some Exif values, notably GPS data, are stored as an array of three rationals. So you’ll need to cast the output of GetQuery to a ulong array before you create three rationals (for hours, minutes and seconds).

    // Grab GpsLatitude as a ulong array
    ulong[] numerics = (ulong[])bitmapMetadata.GetQuery("/app1/ifd/Gps/subifd:{uint=2}");

I’ll go into more details on reading GPS data in another blog.


Posted: Fri, 6 Nov 2009, 05:51:43 GMT Updated: Fri, 6 Nov 2009, 09:05:23 GMT by Ben Vincent
Category: Development
Tags: Windows Imaging Component, XMP, Exif, Geotagging, Fotofly


TransparentPadder TransparentPadder TransparentPadder

Tweet  Ben - Cool! A nice end to the week, my mum was waiting for me in St Louis, she kept it a secret!

(Updated: Fri, 30 Jul 2010, 23:10:30)

Alcatraz . American Express . Amusing Photos . ASP.Net MVC . Australia . Bing . Blue Angels . BMi . Breathe Magazine . British Food . British Virgin Islands . California Highway Patrol . Camping . Canada . Christmas . Christmas Tree . Cleaner Shrimp . codeplex . Cooking . Coral Sea . Diving . Dragonlance . Engagement . Exif . Expedia . Facebook . Fish Tank . Flying . Food . Fotofly . Geotagging . Golden Gate National Recreation Area . Google . Gordon Ramsay . Hotmail . IPTC . Michelin Star . Microsoft . Microsoft Giving Campaign . Monterey Bay Aquarium . Mountain Biking . Nudibranch . San Francisco . Search Engine Optimzation (SEO) . Ship Wrecks . Silverlight . Starbucks . Tassography . The Sea Nettle Jelly . TransRockies . TV Commercial . United Airlines . Usage . Windows 7 . Windows Imaging Component . Windows Live . Windows Live Calendar . Windows Live Photo Gallery . Wineries . XMP


This website, all photography & other content is Copyright © Ben Vincent. Unauthorised use of images is strictly prohibited.
Catalog Last Updated: Mon, 19 Jul 2010, 22:48:43    |   Version v4.0.3861.38195
Powered by
Fotofly Logo