Category: Programming

  • Working Around a Flaw

    I have been fighting with a problem in code for several weeks now relating to the writing of a negative exposure bias value to exif information using the .NET framework’s metadata class. The class has a set of properties and a table of what is allowed to be written to each of those properties. Unfortunately for my project, there was an oversight in that system. A variety of properties, such as System.Photo.ExposureBiasNumerator, do not accept negative values, even though they are supposed to hold signed integers. This has caused me to need to cast an absolute value on all of my exposure bias values, making them all positive. I have attempted to inquire through the MSDN forums and other sources for a reason for this, waiting for someone to point out that I’m wrong, but so far, no one has, so I must assume that there is a flaw. All other values are easy enough to write correctly with no special cases.

    Tonight I have reinstated the ability to write negative values to exposure bias. Effective in ExIf 35 build 20100410 that functionality will be again functional.

    I knew that there had to be a way to make it work, since those values are present in other applications and applications using the .NET Framework can read those values. I pulled some images into my diagnostic form and began reading /app1/ifd/exif/{ushort=37380} (thats ExIf 0x9204) from each of them. I found that there was an 11 digit number recorded in the space for all of them, both with positive and negative values. This got me curious, since a 32 bit integer is only 10 digits. I double checked with Visual Studio and it turns out that my two signed integers were being stored as one giant unsigned 64 bit integer. I began by trying to determine what those numbers could represent, trying to find any and all relationships between those 64 bit integers and the 2 part signed shorts I was working with (relationship between 30064771068 and –2/3 for example). Finally I gave up and decided to read the bytes.  30064771068 is 251, 255, 255, 255,6,0,0,0. I know they are supposed to be 32 bit numbers, so that takes us to 251, 255, 255, 255 and 6,0,0,0. 251 –255 = –4, and 6 = 6, making a rational of –4/6, reducing to my expected –2/3. Now it all makes sense, but I ask myself, why must I generate a 64-bit integer manually to make this work when Microsoft has created perfectly understandable way to write this crap to a file. I guess sometimes being able to do things the old way has its benefits.

    So, now I present, my code:

    //Assume exp.ExposureBias is a string such as -2/3
    if (exp.ExposureBias.Contains("/")) //check for rational
    {
    double tmp = Convert.ToDouble(exp.ExposureBias.Split('/')[0]);
    tmp = tmp / Convert.ToDouble(exp.ExposureBias.Split('/')[1]);
    tmp = Math.Round(tmp, 1);
    exp.ExposureBias = tmp.ToString();
    }
    //convert to a valid integer value
    int exposureBias = Convert.ToInt16(Math.Floor(Convert.ToDouble(exp.ExposureBias) * 10));
    //create the array to hold the 64 bits
    Byte[] exposureBiasByte = new Byte[8];
    if (exposureBias < 0)
    {
    exposureBias = 256 + exposureBias;
    exposureBiasByte[1] = 255;
    exposureBiasByte[2] = 255;
    exposureBiasByte[3] = 255;
    }
    else
    {
    exposureBiasByte[1] = 0;
    exposureBiasByte[2] = 0;
    exposureBiasByte[3] = 0;
    }
    exposureBiasByte[0] = Convert.ToByte(exposureBias);
    exposureBiasByte[4] = 10;
    exposureBiasByte[5] = 0;
    exposureBiasByte[6] = 0;
    exposureBiasByte[7] = 0;
    Int64 exposureBiasLong = BitConverter.ToInt64(exposureBiasByte, 0);
  • Changing of ExIf Tools

    As of Monday, ExIf 35 had its first major release. With the release of “Milestone 1”, daily build number 20100405, I decided that the application was feature complete and stable. The entire build package contained the released executable for the Windows version of the application, as well as two different mobile platforms (PocketPC 2003, Windows Mobile 5). The application works quite well for what its designed for, which is nothing more than tagging scanned negatives or prints with proper information that was recorded when the image was taken. This comes with several major problems, the least of which is that every film photographer in the world except me runs a Mac. The worst of the problems is that the majority of film photographers are not in it for the art of it, or any nostalgic purpose, they are just lazy and un-adaptive, which means that they are avoiding the digital side of things for convenience and in general do not record exposure details. In my opinion, there is as much science as art in photography, especially in film (we can say for certain that there is chemistry), and as scientists of light and optics it is our responsibility to record details about each “experiment” we capture.

    Now, off of my film soapbox, I am finding that the level of precision and care I take to tagging and keeping orderly my film information I wish to apply at least partially to my digital work. Of course the exif portion is already handled for me (thank the great maker for that), but I will be working on ExIfDSC to further manage this information. This will allow for manual adjustment of orientation, adding of tags, titles and descriptions. I plan to make the application function in two ways, first, just an image-by-image view that will let the user easily make adjustments without being distracted by 36 thumbnails on screen. Next there is to be a gallery view that will allow multiple image manipulation, mass rotations and such. ExIf35 works from its XML files, so will ExIfDSC, but it won’t be limited by them. ExIfDSC will support a majority of its processes by way of interacting directly with the image files. On the other hand, the gallery view will support forming gallery files, which will be images selected by the user that are important, have significance or are display-worthy. Sort of a more polished way of viewing images, eliminating much of the clutter that is associated with digital photography.

    I am not abandoning ExIf35 and intend to actively support and promote it (as well as poke at it frequently for minor tweaks), but I need to change my focus to ExIfDSC so that all of the processes can be streamlined and my photographic world can be a happier place (but my happy place is a topic for another blog entry).

  • What to call it?

    I am at the moment rewriting one of the key features of ExIf 35, its ExIf writing tool. I am switching from the .NET Image class’s PropertyItem stuff to .NET’s Bitmap Metadata class. I am making this change because of a recent compression issue that has come up with using the Image class. It is also believed that the metadata class is more useful since it will work with all of my metadata that I am fighting with (all my enemies in one basket).

    Now, the conversion isn’t really the issue, but having to relive some of the stupidity that has been left in ExIf, or its implementation, on the other hand, is a concern for me. In ExIf there lives two properties, ImageTitle (0x010D) and ImageDescription (0x010E). These two were designed as a pair, and were supposed to be implemented as such. In the present day of metadata reading though, it would seem that everything uses “ImageDescription”, and nothing cares for “ImageTitle”, even when the field that the utility claims to show is “title”. It is also interesting to note that once ExIf evolved, it was decided that there should be a title space, so “DocumentTitle” was born, several properties down the list. Now, ExIf has 2 titles and a description. It doesn’t really matter though, because nothing much uses either title space, everything wants to read and write description. Microsoft complicates this by throwing their own XMP field into the mix, “Comment”.

    I remember now why I was glad that this portion of the code was finished, so I wouldn’t have to face the back end of ExIf again.

  • Problems with Images in C#

    I am encountering a not-so-happy issue with programming in .NET for something that works with images. Because I write metadata and I don’t just read it, I am encountering issues regarding image quality and compression. If I let the happy little framework do things its way, I end up with files of reduced size. If I change the quality setting to be 100% (which I interpreted as “don’t fuck with it”), I get files that are much larger. I am intending to work only with metadata, not the images themselves, so I am at a loss as to what is going on here. I would really like to be able to directly copy the data from one file to the new file (since .NET requires a new file for each time a modification is done). I am so pissed off right now, since I have been releasing software for the past few weeks that will reduce image quality if allowed to overwrite the originals, and because I wasn’t using real files until now (just my sample images, which are simple geometric forms, under 10KB), I had no clue it was doing it. I knew a long time ago that my first pass (ExIf) was doing it, but I had no clue it was going on with the 2nd pass (XMP).

  • Image Rotation in ExIf

    ExIf rotation makes no rational or logical sense. Below is code that rotates an image based on its present position in increments of one quarter turn (90 degrees) at a time.


    private
    int rotateImg(int currentOrientation, int rotate)

    {


    int next = 0;


    int prev = 0;


    switch (currentOrientation)

    {


    //1,6,3,8


    case 0: next = 6; prev = 8; break;


    case 1: next = 6; prev = 8; break;


    case 6: next = 3; prev = 1; break;


    case 3: next = 8; prev = 6; break;


    case 8: next = 1; prev = 3; break;

    }


    if (rotate == 1)

    {


    return next;

    }


    else
    if (rotate == -1)

    {


    return prev;

    }


    else

    {


    return next;

    }

    }

  • Last Few Tweaks

    I believe that the majority of ExIf 35’s major goals have been implemented now. I just spent the last hour working in support for tagging/adding keywords to images. It’s a little feature that I didn’t really give much thought to at first because it’s not something I do with my digital photos. I have added it as a possibly useful feature at some later point when usefulness maters. I have tested the mechanism’s output with both ACDSee and Flickr, both of them accept the way that I have done it, which works for me as a test of success (since those are the primary things I would care about tags in). I have also refined the handling of the 0XA300 (File Source) ExIf tag, as well as its related fields in other specs (“DigitalSourceType” in Iptc4xmpExt, and a duplicate for the expected output of ExIf in /xmp/ExIf35 as “FileSource”). The application is almost finished being written for its original goals. Before I begin working on any new goals I will have to get another developer to help me go through, clean up some code and then perhaps get that developer (yeah, if he reads this, he will know who he is) to use his wonderfully talented aesthetic eye to help me plan a few ideas for menus or other UI elements to allow the expanding of functionality of the application.

    I guess once I finish with the next build all I have to do for the next little bit is try to work on the webpage for the app, which at the moment is very much too bare: http://exif35.pcfire.net.

  • First Steps Toward ExIf35 on Mac

    My first attempt to convert ExIf35 from .NET to Mono to run on Mac has not gone very well…

    Unhandled Exception: System.Reflection.TargetInvocationException:
    Exception has been thrown by the target of an invocation. —>
    System.OverflowException: Number overflow.
     at (wrapper managed-to-native)
    object:__icall_wrapper_mono_array_new_specific (intptr,int)
     at System.Drawing.Icon.InitFromStreamWithSize (System.IO.Stream
    stream, Int32 width, Int32 height) [0x00000]
     at System.Drawing.Icon..ctor
    (System.Runtime.Serialization.SerializationInfo info, StreamingContext
    context) [0x00000]
     at (wrapper managed-to-native)
    System.Reflection.MonoCMethod:InternalInvoke
    (object,object[],System.Exception&)
     at System.Reflection.MonoCMethod.Invoke (System.Object obj,
    BindingFlags invokeAttr, System.Reflection.Binder binder,
    System.Object[] parameters, System.Globalization.CultureInfo culture)
    [0x00000]
     — End of inner exception stack trace —
     at System.Reflection.MonoCMethod.Invoke (System.Object obj,
    BindingFlags invokeAttr, System.Reflection.Binder binder,
    System.Object[] parameters, System.Globalization.CultureInfo culture)
    [0x00000]
     at System.Reflection.MethodBase.Invoke (System.Object obj,
    System.Object[] parameters) [0x00000]
     at System.Runtime.Serialization.ObjectRecord.LoadData
    (System.Runtime.Serialization.ObjectManager manager,
    ISurrogateSelector selector, StreamingContext context) [0x00000]
     at System.Runtime.Serialization.ObjectManager.DoFixups () [0x00000]
     at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject
    (System.IO.BinaryReader reader) [0x00000]
     at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph
    (System.IO.BinaryReader reader, Boolean readHeaders, System.Object&
    result, System.Runtime.Remoting.Messaging.Header[]& headers) [0x00000]
     at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize
    (System.IO.Stream serializationStream,
    System.Runtime.Remoting.Messaging.HeaderHandler handler) [0x00000]
     at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize
    (System.IO.Stream serializationStream) [0x00000]
     at System.Resources.ResourceReader.ReadNonPredefinedValue
    (System.Type exp_type) [0x00000]
     at System.Resources.ResourceReader.ReadValueVer2 (Int32 type_index) [0x00000]
     at System.Resources.ResourceReader.LoadResourceValues
    (.ResourceCacheItem[] store) [0x00000]
     at System.Resources.ResourceReader+ResourceEnumerator.FillCache () [0x00000]
     at System.Resources.ResourceReader+ResourceEnumerator..ctor
    (System.Resources.ResourceReader readerToEnumerate) [0x00000]
     at System.Resources.ResourceReader.GetEnumerator () [0x00000]
     at System.Resources.ResourceSet.ReadResources () [0x00000]
     at System.Resources.ResourceSet.GetObjectInternal (System.String
    name, Boolean ignoreCase) [0x00000]
     at System.Resources.ResourceSet.GetObject (System.String name,
    Boolean ignoreCase) [0x00000]
     at System.Resources.RuntimeResourceSet.GetObject (System.String
    name, Boolean ignoreCase) [0x00000]
     at System.Resources.ResourceManager.GetObject (System.String name,
    System.Globalization.CultureInfo culture) [0x00000]
     at System.Resources.ResourceManager.GetObject (System.String name) [0x00000]
     at ExIF35.Form2.InitializeComponent () [0x00d04] in
    /home/curtis/Development/ExIF35/ExIF35/Form2.Designer.cs:334
     at ExIF35.Form2..ctor () [0x0002a] in
    /home/curtis/Development/ExIF35/ExIF35/Form2.cs:21
     at (wrapper remoting-invoke-with-check) ExIF35.Form2:.ctor ()
     at ExIF35.Program.Main () [0x0000b] in
    /home/curtis/Development/ExIF35/ExIF35/Program.cs:18

  • ExIf 35

    With all that has been going on with ExIf 35 and the amount I have blogged about it, it has occurred to me that I haven’t really introduced the app on my blog at all, outside of the problems I have been having with getting things working exactly the way that I want.

    First, a screenshot:

    The application is designed for film photographers (me) to store information about each exposure on a roll. The original intent of the application was to simply store the information into an XML file, but after that portion of the application was finished being written I added the ability for the application to write the information in the image file for the scanned negative or print. At some point I also decided that I wanted to keep up with lens information, which of course required me to learn a new skill of putting information into the files using XMP, what a joyful experience that was. Now the application is on the path to fully utilizing XMP, including contact information (I still have to put that feature in). I am also working on utilizing some custom fields in XMP that will store the information that is specific to the film process, such as the film type, developing chemicals used and the date the roll was developed. I intend to in the future (when the application has a web presence) to post the specifications for the custom fields that I utilize. In the future I may also add functionality for managing the rolls and not just the images on the rolls.

    This is the form used to add or edit images on a roll.

    This form is used to manage the lenses available to the exposures.

    Finally, this form will be used to write the information to the JPEG files. As you can see, it also allows the inclusion or not of other information.

     

    SourceForge Project: https://sourceforge.net/projects/exif35/

    Download From: https://sourceforge.net/projects/exif35/files/ (latest has Windows icon beside it)

  • Lens Information Stored

    Finally, I have managed to store lens information in my JPEG files! It isn’t using ExIf though, because honestly, it’s way too hard and would require me learning way too much information about how the Makernote segment of ExIf works. As an alternative, I am using XMP. XMP is an Adobe developed standard based on XML that is embedded into JPG files (or as a standalone beside RAW). I am so far using two fields of XMP that come from Microsoft’s standards used for Windows Vista/7’s image management tools, those are /xmp/MicrosoftPhoto:LensManufacturer and /xmp/MicrosoftPhoto:LensModel as well as /xmp/xmp:lens and /xmp/aux:Lens. I’ve gone from having 0 places for lens information to having 3 places for lens information. At this point I am just happy it’s in there, but now that I am using XMP, I have more places to put information which means I can allow for the option of storing more information in the files. I now have intentions on letting ExIf 35 store contact information in the files when the option is selected. Additional things I would like to store is things like the chemicals used in developing and a better way to do the film information, other than just a user comment area that states “Shot on ____ film”. Because things are moving more digital, I am likely to have to write my own schema addition to XMP and store the information. It’s likely that the only thing that will read those fields is ExIf 35 itself, but I’m hopeful that if it has to be done, I might be able to convince Flickr to adopt my schema addition as well, since it is quite likely it would be the only one anywhere near supporting film information. All of this information is relevant to the image, and it would be great to get it all in.

  • ExIf Lens Information

    I think I have managed to accomplish all that I wanted with ExIf except for one thing. I still want to store lens information in the ExIf info. Unfortunately, the only place to do that is MakerNotes, and I don’t know how to work with them. It is my understanding that I would have to pick a specific set of makernotes to use for this, but I’m not even sure how to go about that. Because of the nature of my project I am not tied down to one particular set of notes, but that also means that I don’t need all of the tags included in a full set. I can’t make heads or tails out of how makernotes function. Do I have to somehow specify what the notes are? Are there internal references between the notes that tell photo viewers what each tag is? I don’t have a clue and its starting to get to me. Is it possible to create my own maker notes? My guess on that is no, since everyone seems to be desperate to track down makernotes for every major camera ever created. I feel like I am Googling in circles at the moment trying to make things work.