Job Runner ImageUsage Tracker Image
TransparentPadder

Share On FacebookShare On Facebook
 
Ben's Blog (57)Ben's Blog (57)
Development (13)Development (13)
Lisa's Blog (4)Lisa's Blog (4)
 
Show All (75)Show All (75)
 
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 (75)Show All (75)
 
RSS & Atom FeedsRSS & Atom Feeds




TransparentPadder
Home  |  Shopping Cart (0)Blog  |  Highlights  |  Albums  |  Search  |  Contact  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  |  2 Comments
Category: Development
Tags: Windows Imaging Component, XMP, Exif, GeoTagging, FotoFly

 

 
TransparentPadderTransparentPadderTransparentPadder
TransparentPadder

Facebook Status  Ben Email decimated, unfortunately more like the Roman definition than the modern one.

(Updated: Wed, 3 Feb 2010, 00:22:01)
TransparentPadder
Alcatraz . American Express . Australia . Bing . Blue Angels . bmi . Breathe Magazine . British Food . Camping . Canada . Christmas . Christmas Tree . Cleaner Shrimp . CodePlex . Cooking . Coral Sea . Cycling . Diving . DragonLance . Engagement . Exif . Expedia . Facebook . Fire Shrimp . Firemen . Fish Tank . Fleet Week . Flying . Foie Gras . Food . FotoFly . GeoTagging . Giving Campaign . Golden Gate National Recreation Area . Google . Goose Fat . Gordon Ramsay . Hollywood . Hotmail . IPTC . Michelin Star . Microsoft . Monterey Bay Aquarium . Mountain Biking . Photography . San Francisco . Search Engine Optimzation . SEO . Silverlight . Tassography.com . TransRockies . United . Usage . Windows 7 . Windows Imaging Component . Windows Live . Windows Live Calendar . Windows Live Photo Gallery . Wineries . XMP

Sunday, January 24, 2010
- 2010-01-23 Lisa's Birthday

Sunday, January 17, 2010
- 2010-01-18 Things We Collect
- 2010-01-17 Weekend in Half Moon Bay

Saturday, January 16, 2010
- 2009-12-31 Holiday in Beaver Creek

Sunday, October 18, 2009
- 2009-10-10 San Francisco Fleet Week 2009

Sunday, October 04, 2009
- 2009-10-04 Biking Around The Bay

Sunday, August 30, 2009
- 2009-08-26 Caltrain
- 2009-08-22 Biking And Fracturing a Rib in Mammoth Lakes

Tuesday, August 11, 2009
- 2009-08-09 Biking on Pine Mountain

Wednesday, August 05, 2009
- 2009-08-01 Lisa's Mum and Sister Visit