Click here to Skip to main content
Email Password   helpLost your password?

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 ;).

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.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralStream locked again
Laurent.iss
8:50 29 Nov '09  
Cry I was using the binary DLL which locks the file..
Wink I now use the source version of the DLL which is corrected.
Roll eyes Could you update the binary version ?
Thanks!
GeneralStream locked
Laurent.iss
8:06 29 Nov '09  
Laugh This article is great but..
Frown Is seems form this forum that you cannot move, delete or rename a file after ExifExtrator.
OMG Where is the modified Dll version ?
Thanks.
GeneralBrilliant!!
binjafar
3:23 24 May '09  
Excellent work man!
was working hard for such a class of my own for my software... but u got it right!! great help!Thumbs Up
GeneralCan't get Exposure time
taenketank
4:32 11 Mar '09  
When Im trying to get the exposure time it returns zero, I expected it to return 1/180 sec or something like that. I have uploaded a test picture, and it can be found here: http://qaz.dk/nydraabe.jpg
I also tried to get shutter speed but i returns null.
GeneralSystem.ArgumentException was unhandled when try setTag
pa_duch
14:14 3 Jan '09  
I uncomented example code and set path to my own jpg.
When THIS LINE
 er.setTag(0x320, "http://www.beautifulpakistan.com");
was calling, exception System.ArgumentException was thrown in this function.

private static PropertyItem CreatePropertyItem(short type, int tag, int len, byte[] value)
{
PropertyItem item;

// Loads a PropertyItem from a Jpeg image stored in the assembly as a resource.
Assembly assembly = Assembly.GetExecutingAssembly();
Stream emptyBitmapStream = assembly.GetManifestResourceStream("EXIFextractor.decoy.jpg");
System.Drawing.Image empty = System.Drawing.Image.FromStream(emptyBitmapStream);

item = empty.PropertyItems[0];

// Copies the data to the property item.
item.Type = type;
item.Len = len;
item.Id = tag;
item.Value = new byte[value.Length];
value.CopyTo(item.Value, 0);

return item;
}

emptyBitmapStream was null.

What is wrong?
GeneralShutter Speed Issue
Hardy Wang
4:08 29 Dec '08  
If a picture has 1/125 shutter speed, your code wil return 1/125.37 instead.


GeneralAnybody knows how to convert this class to Compact Framework?
staryon
14:06 29 Apr '08  
I cannot find the way of doing that because image.PropertyItems doesn't exist in CF.

Thanks
AnswerHow to get valid GPS coordinates [modified]
blackmanticore
5:54 21 Apr '08  
For those of you who require the GPS info. In the EXIFextractor.cs after
//5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses the//denominator.,
else if( p.Type == 0x5 )
{

I inserted this:


else if( p.Type == 0x5 )
{
//My code starts here
if (p.Id == 0x0004)
{
//lat
// rational
byte[] deg = new byte[4];
byte[] degdiv = new byte[4];
byte[] min = new byte[4];
byte[] mindiv = new byte[4];
byte[] sec = new byte[4];
byte[] secdiv = new byte[4];
Array.Copy(p.Value, 0, deg, 0, 4);
Array.Copy(p.Value, 4, degdiv, 0, 4);
Array.Copy(p.Value, 8, min, 0, 4);
Array.Copy(p.Value, 12, mindiv, 0, 4);
Array.Copy(p.Value, 16, sec, 0, 4);
Array.Copy(p.Value, 20, secdiv, 0, 4);
double a = convertToInt32U(deg);
double b = convertToInt32U(degdiv);
double c = convertToInt32U(min);
double d = convertToInt32U(mindiv);
double e = convertToInt32U(sec);
double f = convertToInt32U(secdiv);
double o =((a/b) + ((c/b)/60) + ((e/f)/3600));
v = o.ToString();
// Rational r = new Rational(a, b);
}
else if (p.Id == 0x0002)
{
//long
byte[] deg = new byte[4];
byte[] degdiv = new byte[4];
byte[] min = new byte[4];
byte[] mindiv = new byte[4];
byte[] sec = new byte[4];
byte[] secdiv = new byte[4];
Array.Copy(p.Value, 0, deg, 0, 4);
Array.Copy(p.Value, 4, degdiv, 0, 4);
Array.Copy(p.Value, 8, min, 0, 4);
Array.Copy(p.Value, 12, mindiv, 0, 4);
Array.Copy(p.Value, 16, sec, 0, 4);
Array.Copy(p.Value, 20, secdiv, 0, 4);
double a = convertToInt32U(deg);
double b = convertToInt32U(degdiv);
double c = convertToInt32U(min);
double d = convertToInt32U(mindiv);
double e = convertToInt32U(sec);
double f = convertToInt32U(secdiv);
double o = ((a / b) + ((c / b) / 60) + ((e / f) / 3600));
v = o.ToString();
}
//My Code ends here
else {
// rational
byte[] n = new byte[p.Len / 2];

Not perfect but it returns valid coordinates

Some Info on how this works:
The GPS coordinates come in as rational byte arrays
d d d d x x x x m m m m x x x x s s s s x x x x
55 0 0 0 1 0 0 0 37 22 0 0 100 0 0 0 0 0 0 0 1 0 0 0

55.94483 is...
55 0 0 0 = 55 / 1 = 55 Degrees
1 0 0 0
37 22 0 0 = 5669 / 100 = 56.69 Minutes (56.69 Minutes / 60 = 0.94483 Degrees)
100 0 0 0
0 0 0 0 = 0 / 1 = 0.0 Seconds (0 Seconds / 3600 = 0 Degrees)
1 0 0 0

modified on Thursday, April 24, 2008 7:11 AM

GeneralRe: How to get valid GPS coordinates
staryon
14:04 29 Apr '08  
Thanks a lot!! It works great
GeneralRe: How to get valid GPS coordinates
rrrrrrrrrrrd
1:10 2 May '08  
This is great, many thanks. I added the code you posted for GPS data, but it doesnt seem to recognise the sign, ie. -117 degrees or +117 degrees? Will look at this, but any ideas appreciated.

Rob
GeneralRe: How to get valid GPS coordinates
rrrrrrrrrrrd
0:12 14 May '08  
Ok, you can figure out if it is + or minus by reading the Gps LongitudeRef or Gps LatitudeRef.
GeneralRe: How to get valid GPS coordinates
Bangassou
1:29 8 Jul '08  
For all Germans who need a conversion from WGS84 to Gauss Krueger I post my solution which works great:

public Int16 Transform_WGS84_2_GK ( double rLatDec, double rLonDec, double rH, ref double rLongitude, ref double rLatitude)
{
double rWGS_a = 6378137.000;
double rWGS_b = 6356752.314;

double Bessel_a = 6377397.155;
double Bessel_b = 6356078.962;

double TPdx = 598.1;
double TPdy = 73.7;
double TPdz = 418.2;
double TPex = -0.202;
double TPey = -0.045;
double TPez = 2.455;
double TPm = 6.7;

double rWGS_E2, rWGS_N;
double rVecX, rVecY, rVecZ;
double F2, F3, F4, F5, F6, F7, F8;
double rotVec1,rotVec2, rotVec3;
double trans1, trans2, trans3;
double s5;
double T5;
double B5;
double L5;
double N5;
double h5,B,L,h;
double Bessel_e2;
double n6, alpha, beta, gamma, delta, epsilon;
int L0;
double l6, B6, N6_, nano, t6;
double Bogenlaenge;
double h1,h2,r1,r2;

rWGS_E2 = ( Sqr(rWGS_a) - Sqr(rWGS_b))/ (Sqr(rWGS_a));

rWGS_N = (rWGS_a)/(Math.Sqrt( 1 - rWGS_E2*Sqr(Math.Sin( rLatDec/180*Math.PI))));

rVecX = (rWGS_N + rH) * Math.Cos(rLatDec / 180 * Math.PI) * Math.Cos(rLonDec / 180 * Math.PI);
rVecY = (rWGS_N + rH) * Math.Cos(rLatDec / 180 * Math.PI) * Math.Sin(rLonDec / 180 * Math.PI);
rVecZ = ( rWGS_N * Sqr(rWGS_b)/Sqr( rWGS_a) + rH) * Math.Sin( rLatDec / 180 * Math.PI);


F5 = -TPex * Math.PI / 180 / 3600;
F6 = -TPey * Math.PI / 180 / 3600;
F7 = -TPez * Math.PI / 180 / 3600;
F8 = 1 - TPm/1000000;

F2 = -( TPdx + F7*TPdy - F6*TPdz);
F3 = -(-F7*TPdx + TPdy + F5*TPdz);
F4 = -( F6*TPdx - F5*TPdy + TPdz);


rotVec1 = ( rVecX + F7*rVecY - F6*rVecZ) * F8;
rotVec2 = (-F7*rVecX + rVecY + F5*rVecZ) * F8;
rotVec3 = ( F6*rVecX - F5*rVecY + rVecZ) * F8;

trans1 = rotVec1 + F2;
trans2 = rotVec2 + F3;
trans3 = rotVec3 + F4;

s5 = Math.Sqrt(Sqr(trans1) + Sqr(trans2));
Bessel_e2 = (Sqr(Bessel_a)-Sqr(Bessel_b))/Sqr(Bessel_a);
T5 = Math.Atan( trans3 * Bessel_a / (s5 * Bessel_b));
B5 = Math.Atan((trans3 + Bessel_e2 * Sqr(Bessel_a) / Bessel_b * Math.Pow(Math.Sin(T5), 3)) / (s5 - Bessel_e2 * Bessel_a * Math.Pow(Math.Cos(T5), 3)));
L5 = Math.Atan( trans2 / trans1);
N5 = Bessel_a/Math.Sqrt(1-Bessel_e2 * Sqr(Math.Sin(B5)));
h5 = (s5 / Math.Cos(B5)) - N5;

B = B5 * 180 / Math.PI;
L = L5 * 180 / Math.PI;
h = h5;

n6 = (Bessel_a - Bessel_b)/(Bessel_a + Bessel_b);
alpha = ((Bessel_a + Bessel_b)/2) * ( 1 + 0.25*Sqr(n6) + 1/64*Math.Pow(n6,4));
beta = -1.5*n6 + 9/16*Math.Pow(n6,3) - 3/32*Math.Pow(n6,5);
gamma = 15/16 * Sqr(n6) - 15/32*Math.Pow(n6,4);
delta = -35/48*Math.Pow(n6,3) + 105/256*Math.Pow(n6,5);
epsilon = 315/512*Math.Pow(n6,4);

if( Math.Abs(L-6) < 1.5)
L0 = 6;
else if (Math.Abs(L - 9) < 1.5)
L0 = 9;
else if (Math.Abs(L - 12) < 1.5)
L0 = 12;
else if (Math.Abs(L - 15) < 1.5)
L0 = 15;
else
{
MessageBox.Show( "Länge nicht unterstützt! Koordinatentransformation nur für Deutschland!");
L0 = -1;
}
if (L0 > 0)
{
l6 = (L - L0) * Math.PI / 180;
B6 = B * Math.PI / 180;
N6_ = Bessel_a / Math.Sqrt(1 - Bessel_e2 * Sqr(Math.Sin(B6)));
nano = Math.Sqrt(Sqr(Bessel_a) / Sqr(Bessel_b) * Bessel_e2 * Sqr(Math.Cos(B6)));
t6 = Math.Tan(B6);

Bogenlaenge = alpha * (B6 + beta * Math.Sin(2 * B6) + gamma * Math.Sin(4 * B6) + delta * Math.Sin(6 * B6) + epsilon * Math.Sin(8 * B6));
h1 = t6 / 2 * N6_ * Sqr(Math.Cos(B6)) * Sqr(l6);
h2 = t6 / 24 * N6_ * Math.Pow(Math.Cos(B6), 4) * (5 - Sqr(t6) + 9 * Sqr(nano) + 4 * Math.Pow(nano, 4)) * Math.Pow(l6, 4);
// h3 := t6/720*N6_*Power(Cos(B6),6)*(61 - 58*Sqr(t6) + 270*Sqr(nano) - 330*Sqr(t6)*Sqr(nano))*Power(l6,6);
// h4 := t6/40320*N6_*Power(Cos(B6),8)*(1385-3111*Sqr(t6) + 543*Power(t6,4) - Power(t6,6))*Power(l6,8);

rLatitude = Bogenlaenge + h1 + h2;

r1 = N6_ * Math.Cos(B6) * l6;
r2 = N6_ / 6 * Math.Pow(Math.Cos(B6), 3) * (1 - Sqr(t6) + Sqr(nano)) * Math.Pow(l6, 3);

rLongitude = r1 + r2 + 500000 + L0 / 3 * 1000000;
}

return 0;
}
private double Sqr(double r)
{
return ( Math.Pow( r, 2.0));
}
GeneralRe: How to get valid GPS coordinates
Mario Campo
1:40 16 Jul '08  
Hi, Exist a little bug in:

double o = ((a / b) + ((c / b) / 60) + ((e / f) / 3600));
it would to be

double o = ((a / b) + ((c / d) / 60) + ((e / f) / 3600));
Best Regards,
Mario
GeneralRe: How to get valid GPS coordinates
cookie_biscuit
19:31 27 Mar '09  
hi,thank you for ur gps code n for the author coding,i manage to add it into
another program

but there is a problem --> [b]Field '.myHash' is never assigned to,and will
always have its default value null[/b]

how should i set it?
Generaljpg file gets locked after using this library
rav
8:22 6 Apr '08  
I experienced problem calculating md5 of image immediately after using this library for read EXIF. After analyzing the problem I think there is a bug in this library. The following method must be modified to correct it (FileStream is being closed explicitly):

public static PropertyItem[] GetExifProperties(string fileName)
{
FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
System.Drawing.Image image = System.Drawing.Image.FromStream(stream,
/* useEmbeddedColorManagement = */ true,
/* validateImageData = */ false);
PropertyItem[] pi = image.PropertyItems;
stream.Close();
return pi;
}
GeneralRe: jpg file gets locked after using this library
Greg Cadmes
6:28 10 May '08  
Here is the fix for your file locked issue:

public static PropertyItem[] GetExifProperties(string fileName, out long size)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
size = stream.Length;

using (System.Drawing.Image image = System.Drawing.Image.FromStream(stream, true, false))
{
return image.PropertyItems;
}
}
// return null;
}


I too found this problem and after modifying the code above, it works fine now.

cheers,
QuestionRAW Image data
mvanschie
22:54 3 Jan '08  
I have a general question related to RAW image data that i run into when i try to read the EXIF data from an image.


I started out with a free library that uses an System.Drawing.Image as an input and besides the fact that is didn't perform so great with JPG it gave me an "out of memory" exception on the following line:

Image imgImage = Image.FromFile(filePath);
I started using the EXIFExtractor class and get a System.ArgumentException exception on the following line:

Bitmap bmp = new Bitmap(filePath);
I did install the (in my case) CANON RAW codec so i can view them using windows image galary. I thought that the .NET framework would use this codec to open the RAW image, but that was not the case Hmmm .

Does anybody know how to read/DECODE a RAW image to a .NET Image of Bitmap object?.
Generalabout GPS photo
SILENCE226
7:57 16 Sep '07  
I can provide a photo with GPS information:
http://farm2.static.flickr.com/1049/1358747187_496d7bb0df_o.jpg
Generalclosing FileStream and some updated buildDB cases
davidhart
9:54 12 Jul '07  
I was trying to get the exif data out and then move the image to a different location but it was crashing because this class wasn't closing the filestream. Here's what i changed it to and it worked.

public static PropertyItem[] GetExifProperties(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
System.Drawing.Image image = System.Drawing.Image.FromStream(stream,
/* useEmbeddedColorManagement = */ true,
/* validateImageData = */ false);
return image.PropertyItems;
}
}


-----------------------------------------
Also, I needed a few extra cases in the buildDB so I thought I would put them in here in case anyone else wanted them. They belong inside the "else if( p.Type == 0x3 )" statement.


case 0xA001: // Color Space
switch (convertToInt16U(p.Value))
{
case 1: v = "sRGB"; break;
//case -1: v = "Uncalibrated"; break;
default: v = " reserved"; break;
}
break;
case 0x500B:// Halftone LPIUnit
switch (convertToInt16U(p.Value))
{
case 1: v = "lines per inch"; break;
case 2: v = "lines per centimeter"; break;
}
break;
case 0x500D: // Halftone Shape - shape of the halftone dots
switch (convertToInt16U(p.Value))
{
case 0: v = "round"; break;
case 1: v = "ellipse"; break;
case 2: v = "line"; break;
case 3: v = "square"; break;
case 4: v = "cross"; break;
case 6: v = "diamond"; break;
}
break;

--------------------------------------
And i added some of the other elements to the flash case.

case 0x9209: // Flash
switch(convertToInt16U(p.Value) )
{
case 0: v = "Flash did not fire"; break;
case 1: v = "Flash fired"; break;
case 5: v = "Strobe return light not detected"; break;
case 7: v = "Strobe return light detected"; break;
case 9: v = "Flash fired, compulsory flash mode"; break;
case 13: v = "Flash fired, compulsory flash mode, return light not detected"; break;
case 15: v = "Flash fired, compulsory flash mode, return light detected"; break;
case 16: v = "Flash did not fire, compulsory flash mode"; break;
case 24: v = "Flash did not fire, auto mode"; break;
case 25: v = "Flash fired, auto mode"; break;
case 29: v = "Flash fired, auto mode, return light not detected"; break;
case 31: v = "Flash fired, auto mode, return light detected"; break;
case 32: v = "No flash function"; break;
case 65: v = "Flash fired, red-eye reduction mode"; break;
case 69: v = "Flash fired, red-eye reduction mode, return light not detected"; break;
case 71: v = "Flash fired, red-eye reduction mode, return light detected"; break;
case 73: v = "Flash fired, compulsory flash mode, red-eye reduction mode"; break;
case 77: v = "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected"; break;
case 79: v = "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected"; break;
case 89: v = "Flash fired, auto mode, red-eye reduction mode"; break;
case 93: v = "Flash fired, auto mode, return light not detected, red-eye reduction mode"; break;
case 95: v = "Flash fired, auto mode, return light detected, red-eye reduction mode"; break;
default: v = "Unknown flash status"; break;
}
break;

QuestionNullReferenceException was unhandled
puyopuy
20:16 28 Jun '07  
He everyone,

I downloaded the latest version and try to set a Tag property, I got "NullReferenceException was unhandled" error. I trace into the source code and found it happen in this.bmp.SetPropertyItem( p ) inside the function setTag in EXIFextractor.cs.

I just put a line the following line

er2.setTag(0x9286, "My Comment");

before

Console.WriteLine(er2["Maker Note"]); //In Class1.cs

Any help is much appreciated.


Generalsystem.web.ui ?
coldkatz
6:03 2 Jun '07  
I am at a total loss here. When I paste your code and try to compile, I get an error claiming System.Web.UI ist missing, as well as the use of undefined function "translation"... which I guess is due to the missing namespace. I found absolutely no information on System.Web.UI on the internet... Any clue as to what I have to install to get this running?

I am using a fresh installation of Visual C# Express with SP1, .NET 3.0 (2.0 wouldn't work either, so I got the new one)
GeneralRe: system.web.ui ?
Asim Goheer
8:14 2 Jun '07  
I dont remember using anything like web.ui. I think its because of some other error. btw why are you copy pasting it? simply link to the dll and call the functions from your code.
GeneralRe: system.web.ui ?
david_k13
14:06 3 Jun '07  
Thx for the utility. Very handy.
I'm having the same problem, though. I need to enumerate all the key/value pairs and am having a hard time finding the right type of object to use. The watch window classifies the priperties array as a hashtable, but I'm a little lost as to what type the individual pairs are of.
GeneralRe: system.web.ui ?
david_k13
14:13 3 Jun '07  
Sorry, answered my own question.
Coldkatz - you need to add the System.Web reference to your project, and then add "using System.Web.UI".
After that, you'll be able to see the "Pair" type and use it to enumerate all the properties.
QuestionGPS Information
MarkRedman
22:38 30 May '07  
Does anyone know how to convert the data in the GPS Coordinates into Degrees, Minutes and seconds?


Last Updated 7 Sep 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010