Jump to content

FileType plugins and Exif data


Recommended Posts

I'm trying to write a file type plugin basically another raw to paint.net plugin but this one using WIC. I got the part of opening the image just working fine but i'm having issued getting the metadata to pass with the image since the Document.Metadata takes Property items has parameters and that object has no public constructor.

This is the info i got for the exif data

Title - /ifd/{ushort=270}

Subject - /ifd/{ushort=270}

Camera Maker - /ifd/{ushort=271}

Camera Model -/ifd/{ushort=272}

F-Stop - /ifd/{ushort=34665}/{ushort=34850}

Exposure time - /ifd/{ushort=34665}/{ushort=33434}

Exposure program - /ifd/{ushort=34665}/{ushort=34850}

Exposure bias - /ifd/{ushort=34665}/{ushort=37380}

Focal Lenght - /ifd/{ushort=34665}/{ushort=37386}

Flash mode - /ifd/{ushort=34665}/{ushort=37385}

Date Taken - /ifd/{ushort=306}

Program Name - /ifd/{ushort=305}

Width - /ifd/{ushort=256}

Height - /ifd/{ushort=257}

Resolution unit - /ifd/{ushort=296}

iso - /ifd/{ushort=34665}/{ushort=34855}

Link to comment
Share on other sites

The way that Paint.NET has to do this internally is to store a small image resource in its DLL which has an EXIF tag in it. Then, any time there is a need to construct a custom PropertyItem, we load the image, yank out a PropertyItem (any PropertyItem), then set the values to what's needed.

So, you simply have to do the same thing yourself. (Do NOT use the methods in SystemLayer -- they are not for plugins. They do change, and your plugin will break.)

I hadn't looked at this code in a loooooong time (the Metadata class). It's clearly showing its age.

        // System.Drawing.Imaging.PropertyItem does not have a public constructor
       // So, as per the documentation, we have to "steal" one.
       // Quite ridiculous.
       // This depends on PropertyItem.png being an embedded resource in this assembly.
       private static Image propertyItemImage;

       private static PropertyItem GetPropertyItem()
           if (propertyItemImage == null)
               Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("PaintDotNet.SystemLayer.PropertyItem.png");
               propertyItemImage = Image.FromStream(stream);

           PropertyItem pi = propertyItemImage.PropertyItems[0]; // this works because the PropertyItems property returns a copy
           pi.Id = 0;
           pi.Len = 0;
           pi.Type = 0;
           pi.Value = ArrayUtil.Empty();

           return pi;

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html


Link to comment
Share on other sites

I've seen this hack (sorry to call it that but is weird tactic) before i'm going to see if there are any other options and will let you knwo what i ended up doing in my plugin. Btw the wrapper for WIC in .net seems rather incomplete which kind of disapointed me a bit.

Alright an update on the current progress in case anyone is interested I can now insert string of any types and it works with the current metadata system.

Retrieving the Property Item.

     ConstructorInfo[] constructor = typeof(PropertyItem).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
           object[] objects = new object[0];
           PropertyItem item = (PropertyItem)constructor[0].Invoke(objects);

Passing the data for a string goes something like this

string title = (string)metaData.GetQuery(@"/ifd/{ushort=270}");
               //18 + (2 * number of characters) string lenght
               ASCIIEncoding encoding = new ASCIIEncoding();
               itemList.Add(new ExifValue(270, encoding.GetByteCount(title), 2, encoding.GetBytes(title)));

And then finally into document metadata

Document currentDoc = Document.FromImage(;
                   List items = new List();
                   foreach (ExifValue e in properties)
                       ConstructorInfo[] constructor = typeof(PropertyItem).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
                       object[] objects = new object[0];

                       PropertyItem item = (PropertyItem)constructor[0].Invoke(objects);
                       item.Id = e.id;
                       item.Len = e.len;
                       item.Type = e.type;
                       item.Value = e.value;

I will keep going and see if i can pass all the data i'm interested on hopefully put a beta of this out tonight. Thanks for the help.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...