Click here to Skip to main content
Click here to Skip to main content

EXIFextractor library to extract EXIF information

, 7 Sep 2005
Rate this:
Please Sign up or sign in to vote.
EXIFextractor library to extract EXIF information.

Introduction

OK, here is the problem, you have an image and you either want to set some EXIF tag in it or read some EXIF tag embedded in it. Solution...? well part of it has already being implemented by MS in .NET but that is just the tag number and raw data associated with it. Clearly this does not help us in any way when a user just wants to read the image comments. First you must know the tag number, then using .NET you extract that tag and then convert it. Well on the first hand it doesn't sound that bad (which if you take my word is really not bad if you are concerned with just ASCII strings) but say you want to extract ISO speed which ironically is in rational number format or other data types that require conversions, then you will agree that not only it's bad it can be sometimes stupid. If you are a person like me you will scratch your head first and think why are they trying to trick us by embedding the data like that? They could have easily done that in other simpler formats, but guess what? It's already done and you are the lucky one who is going to do all the decoding. What you have read in the previous lines were part of my emotions, when I set out to make an EXIF control for this website.

I will continue to update this control on my website so in case you are looking at this article in 2006 (and provided humans don't start WW3) there are some good chances that you will find the latest version there.

Background

Basic match knowledge, along with basic C# knowledge and idea about the Bitmap class. Oh yes 1 Brain (but it's optional).

Using the code

EXIFextractor is a very lightweight class, which you can just pass in your Bitmap as a reference and this class will use it. The bitmap won't be modified unless you call the setTag function to change a specific tag. It will be your job to store/save the bitmap once you have added/modified a tag.

Here is a sample code that shows you how to dump all the tags on a console.

System.Drawing.Bitmap bmp = 
             new System.Drawing.Bitmap("F:\\DSCI0006.JPG");

// create a new instance of Extractor 
// class. Here "\n" is the newline 
// that is used to seprate output of two tags. 
// You can replace it with "," if you want
Goheer.EXIF.EXIFextractor er = 
             new Goheer.EXIF.EXIFextractor(ref bmp,"\n");

// now dump all the tags on console
Console.Write(er); 

// to set a tag you have to specify the tag id
// code 0x13B is for artist name
// since this number has ascii string with 
// it pass the string you want to set
er.setTag(0x13B,"http://www.goheer.com");

// dispose the image here or do whatever you want.
//

If you want to get individual items such as artist name. Please keep in mind that this can return null for EXIF properties that are not present in the system, so it's a right thing to check for null values before doing any operation.

Console.Write(er["Equip Make"]);

You can also use enumerator like foreach and get all the properties one by one. Here a point worth mentioning is that the data is returned in the form of System.Web.UI.Pair object.

Goheer.EXIF.EXIFextractor er = 
              new Goheer.EXIF.EXIFextractor(ref bmp,"");
foreach(System.Web.UI.Pair s in er )
{
    // Remember the data is returned 
    // in a Key,Value Pair object
    Console.Write(s.First+"  " + s.Second +"\n");
}

Here is the list of properties that you can get using this method, all the values returned in this case will be converted to string values.

/// <SUMMARY>
/// Get the individual property value by supplying property name
/// These are the valid property names :
/// 
/// "Exif IFD"
/// "Gps IFD"
/// "New Subfile Type"
/// "Subfile Type"
/// "Image Width"
/// "Image Height"
/// "Bits Per Sample"
/// "Compression"
/// "Photometric Interp"
/// "Thresh Holding"
/// "Cell Width"
/// "Cell Height"
/// "Fill Order"
/// "Document Name"
/// "Image Description"
/// "Equip Make"
/// "Equip Model"
/// "Strip Offsets"
/// "Orientation"
/// "Samples PerPixel"
/// "Rows Per Strip"
/// "Strip Bytes Count"
/// "Min Sample Value"
/// "Max Sample Value"
/// "X Resolution"
/// "Y Resolution"
/// "Planar Config"
/// "Page Name"
/// "X Position"
/// "Y Position"
/// "Free Offset"
/// "Free Byte Counts"
/// "Gray Response Unit"
/// "Gray Response Curve"
/// "T4 Option"
/// "T6 Option"
/// "Resolution Unit"
/// "Page Number"
/// "Transfer Funcition"
/// "Software Used"
/// "Date Time"
/// "Artist"
/// "Host Computer"
/// "Predictor"
/// "White Point"
/// "Primary Chromaticities"
/// "ColorMap"
/// "Halftone Hints"
/// "Tile Width"
/// "Tile Length"
/// "Tile Offset"
/// "Tile ByteCounts"
/// "InkSet"
/// "Ink Names"
/// "Number Of Inks"
/// "Dot Range"
/// "Target Printer"
/// "Extra Samples"
/// "Sample Format"
/// "S Min Sample Value"
/// "S Max Sample Value"
/// "Transfer Range"
/// "JPEG Proc"
/// "JPEG InterFormat"
/// "JPEG InterLength"
/// "JPEG RestartInterval"
/// "JPEG LosslessPredictors"
/// "JPEG PointTransforms"
/// "JPEG QTables"
/// "JPEG DCTables"
/// "JPEG ACTables"
/// "YCbCr Coefficients"
/// "YCbCr Subsampling"
/// "YCbCr Positioning"
/// "REF Black White"
/// "ICC Profile"
/// "Gamma"
/// "ICC Profile Descriptor"
/// "SRGB RenderingIntent"
/// "Image Title"
/// "Copyright"
/// "Resolution X Unit"
/// "Resolution Y Unit"
/// "Resolution X LengthUnit"
/// "Resolution Y LengthUnit"
/// "Print Flags"
/// "Print Flags Version"
/// "Print Flags Crop"
/// "Print Flags Bleed Width"
/// "Print Flags Bleed Width Scale"
/// "Halftone LPI"
/// "Halftone LPIUnit"
/// "Halftone Degree"
/// "Halftone Shape"
/// "Halftone Misc"
/// "Halftone Screen"
/// "JPEG Quality"
/// "Grid Size"
/// "Thumbnail Format"
/// "Thumbnail Width"
/// "Thumbnail Height"
/// "Thumbnail ColorDepth"
/// "Thumbnail Planes"
/// "Thumbnail RawBytes"
/// "Thumbnail Size"
/// "Thumbnail CompressedSize"
/// "Color Transfer Function"
/// "Thumbnail Data"
/// "Thumbnail ImageWidth"
/// "Thumbnail ImageHeight"
/// "Thumbnail BitsPerSample"
/// "Thumbnail Compression"
/// "Thumbnail PhotometricInterp"
/// "Thumbnail ImageDescription"
/// "Thumbnail EquipMake"
/// "Thumbnail EquipModel"
/// "Thumbnail StripOffsets"
/// "Thumbnail Orientation"
/// "Thumbnail SamplesPerPixel"
/// "Thumbnail RowsPerStrip"
/// "Thumbnail StripBytesCount"
/// "Thumbnail ResolutionX"
/// "Thumbnail ResolutionY"
/// "Thumbnail PlanarConfig"
/// "Thumbnail ResolutionUnit"
/// "Thumbnail TransferFunction"
/// "Thumbnail SoftwareUsed"
/// "Thumbnail DateTime"
/// "Thumbnail Artist"
/// "Thumbnail WhitePoint"
/// "Thumbnail PrimaryChromaticities"
/// "Thumbnail YCbCrCoefficients"
/// "Thumbnail YCbCrSubsampling"
/// "Thumbnail YCbCrPositioning"
/// "Thumbnail RefBlackWhite"
/// "Thumbnail CopyRight"
/// "Luminance Table"
/// "Chrominance Table"
/// "Frame Delay"
/// "Loop Count"
/// "Pixel Unit"
/// "Pixel PerUnit X"
/// "Pixel PerUnit Y"
/// "Palette Histogram"
/// "Exposure Time"
/// "F-Number"
/// "Exposure Prog"
/// "Spectral Sense"
/// "ISO Speed"
/// "OECF"
/// "Ver"
/// "DTOrig"
/// "DTDigitized"
/// "CompConfig"
/// "CompBPP"
/// "Shutter Speed"
/// "Aperture"
/// "Brightness"
/// "Exposure Bias"
/// "MaxAperture"
/// "SubjectDist"
/// "Metering Mode"
/// "LightSource"
/// "Flash"
/// "FocalLength"
/// "Maker Note"
/// "User Comment"
/// "DTSubsec"
/// "DTOrigSS"
/// "DTDigSS"
/// "FPXVer"
/// "ColorSpace"
/// "PixXDim"
/// "PixYDim"
/// "RelatedWav"
/// "Interop"
/// "FlashEnergy"
/// "SpatialFR"
/// "FocalXRes"
/// "FocalYRes"
/// "FocalResUnit"
/// "Subject Loc"
/// "Exposure Index"
/// "Sensing Method"
/// "FileSource"
/// "SceneType"
</SUMMARY>

Here is how the class works. We take the PropertyItem array provided by .NET and then convert it to human readable form according to the EXIF standards. I am chopping off the extra details here you can see them in the code provided. Basically there are 6 types of data types that are normally embedded in an image. We take each one and treat them differently. Sometimes in a specific data type we have to do extra conversion for a specific tag (i.e. iso), we have to perform specific calculations on the data after which we will get the human readable form. There are many such conversions done in this loop which again I have removed on purpose.

System.Drawing.Imaging.PropertyItem [] y = 
                                 bmp.PropertyItems;
//
foreach(System.Drawing.Imaging.PropertyItem p in y)
{
    //1 = BYTE An 8-bit unsigned integer.,
    if( p.Type == 0x1 )
    {
        //byte
    }
        //2 = ASCII An 8-bit byte 
        //containing one 7-bit ASCII 
        //code. The final byte 
        //is terminated with NULL.,
    else if( p.Type == 0x2 )
    {
        // string                    

    }
        //3 = SHORT A 16-bit (2 -byte) 
        //unsigned integer,
    else if( p.Type == 0x3 )
    {
        // short int
    }
        //4 = LONG A 32-bit (4 -byte) 
        //unsigned integer,
    else if( p.Type == 0x4 )
    {
        // unsigned int

    }
        //5 = RATIONAL Two LONGs. The 
        //first LONG is the numerator 
        //and the second LONG expresses 
        //the denominator.,
    else if( p.Type == 0x5 )
    {
        // rational
        
    }
        //7 = UNDEFINED An 8-bit 
        //byte that can take 
        //any value depending on 
        //the field definition,
    else if( p.Type == 0x7 )
    {
        // depends upon the tag what form the 
        // data can take. no universal rule
    }
}

As you can see the basic concept is straight but the things you have to do for data conversion kills you.

Last thing to remember is that this code is provided as it is, if it fortunately destroys all of your precious image collection then no one is to be blamed except you Wink | ;) .

Points of interest

If you want to see the scalability of this control then you should definitely visit this site. On this site when a user uploads a picture all the data is automatically extracted from the image, along with that the image is checked for duplicates if someone else has uploaded that same image or not. Then in the next stage thumbnail images are created, so basically you can say that this site works on its own.

History

I wrote my first article on how to display screensaver on both screens of a dual monitor. If any of you guys have free time then do check it out and give me suggestions/comments about that too. It's called GxTS.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Asim Goheer

United States United States
No Biography provided

Comments and Discussions

 
QuestionIs this in the public domain? Pinmemberfocs11-Jun-14 21:02 
QuestionCall EXIFextractor from simple .aspx page PinmemberPapermouse30-Oct-13 23:09 
GeneralMy vote of 5 Pinmemberfrankfpp11-Feb-13 7:24 
Questiona litle fix to GetExifProperties PinmemberJayson Ragasa22-Nov-12 17:02 
I am using your code for a little personal tool and I was trying to rename the image file after taking the ExIf information. The problem is, the file always locked and I looked at your code it looks like you're not handling the stream pretty well which costs the file to lock the entire runtime so here's a little fix of your code.
 
Instead of leaving the stream open, copy the stream on a new stream (MemoryStream) and use that MemoryStream on the Image.
 
public static PropertyItem[] GetExifProperties(string fileName) 
{
	MemoryStream ms = new MemoryStream();
 
	using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
	{
		stream.CopyTo(ms);
	}
 
	System.Drawing.Image image = System.Drawing.Image.FromStream(ms, 
					 /* useEmbeddedColorManagement = */ true,
					 /* validateImageData = */ false);
	
	return image.PropertyItems;
}
Software Developer
Jayzon Ragasa
Baguio City, Philippines

QuestionFreaking awesome PinmemberGrant Carroll20-Aug-12 14:45 
QuestionFreaking awesome PinmemberGrant Carroll20-Aug-12 14:45 
Generalawesome 5 stars :) Pinmemberrasmus fjord4-Apr-12 4:15 
GeneralMy vote of 5 Pinmembermanoj kumar choubey13-Feb-12 0:34 
QuestionWell, very nice done Sr Asim Goheer!!! Pinmemberbozzo225-Nov-11 14:52 
QuestionMacintosh [modified] Pinmemberdejan19dejan1920-Sep-11 2:02 
QuestionChanging recording time PinmemberMember 817504620-Aug-11 2:50 
Generalflawless Pinmembercraude4-Sep-10 12:40 
GeneralMy vote of 5 Pinmembercraude4-Sep-10 12:37 
GeneralStream locked again PinmemberLaurent.iss29-Nov-09 8:50 
GeneralStream locked PinmemberLaurent.iss29-Nov-09 8:06 
AnswerRe: Stream locked PinmemberVladimir Emelyanov14-Oct-13 21:03 
GeneralBrilliant!! Pinmemberbinjafar24-May-09 3:23 
GeneralCan't get Exposure time Pinmembertaenketank11-Mar-09 4:32 
GeneralSystem.ArgumentException was unhandled when try setTag Pinmemberpa_duch3-Jan-09 14:14 
GeneralShutter Speed Issue PinmemberHardy Wang29-Dec-08 4:08 
QuestionAnybody knows how to convert this class to Compact Framework? Pinmemberstaryon29-Apr-08 14:06 
QuestionHow to get valid GPS coordinates [modified] Pinmemberblackmanticore21-Apr-08 5:54 
AnswerRe: How to get valid GPS coordinates Pinmemberstaryon29-Apr-08 14:04 
GeneralRe: How to get valid GPS coordinates Pinmemberrrrrrrrrrrrd2-May-08 1:10 
GeneralRe: How to get valid GPS coordinates Pinmemberrrrrrrrrrrrd14-May-08 0:12 
AnswerRe: How to get valid GPS coordinates PinmemberBangassou8-Jul-08 1:29 
AnswerRe: How to get valid GPS coordinates PinmemberMario Campo16-Jul-08 1:40 
AnswerRe: How to get valid GPS coordinates Pinmembercookie_biscuit27-Mar-09 19:31 
Generaljpg file gets locked after using this library Pinmemberrav6-Apr-08 8:22 
GeneralRe: jpg file gets locked after using this library PinmemberGreg Cadmes10-May-08 6:28 
QuestionRAW Image data Pinmembermvanschie3-Jan-08 22:54 
AnswerRe: RAW Image data Pinmemberglenneroo27-Nov-10 16:25 
Generalabout GPS photo PinmemberSILENCE22616-Sep-07 7:57 
Generalclosing FileStream and some updated buildDB cases Pinmemberdavidhart12-Jul-07 9:54 
GeneralRe: closing FileStream and some updated buildDB cases Pinmember3soft3-Sep-10 11:32 
QuestionNullReferenceException was unhandled Pinmemberpuyopuy28-Jun-07 20:16 
Questionsystem.web.ui ? Pinmembercoldkatz2-Jun-07 6:03 
AnswerRe: system.web.ui ? PinmemberAsim Goheer2-Jun-07 8:14 
GeneralRe: system.web.ui ? Pinmemberdavid_k133-Jun-07 14:06 
GeneralRe: system.web.ui ? Pinmemberdavid_k133-Jun-07 14:13 
QuestionGPS Information PinmemberMarkRedman30-May-07 22:38 
AnswerRe: GPS Information PinmemberAsim Goheer2-Jun-07 8:16 
GeneralRe: GPS Information PinmemberMarkRedman3-Jun-07 5:53 
GeneralRead ExIf data and Move File PinmemberJan.Seiffert30-May-07 5:36 
GeneralRe: Read ExIf data and Move File PinmemberAsim Goheer2-Jun-07 8:16 
GeneralGPS information Pinmembercruidi12-Apr-07 19:58 
GeneralRe: GPS information PinmemberAsim Goheer2-Jun-07 8:18 
QuestionUnexpected behavior in Windows Explorer Pinmemberthkoe0027-Sep-06 9:33 
AnswerRe: Unexpected behavior in Windows Explorer PinmemberAsim Goheer7-Sep-06 21:49 
QuestionCan't update tags for tiff files Pinmemberdevmicro9-Aug-06 23:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 7 Sep 2005
Article Copyright 2005 by Asim Goheer
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid