Reputation: 4945
I can't seem to get the tag I'm adding to an image to stick once I save the image to a memory stream. Any idea how I can get that tag to end up in the imageCache byte array after I try and copy it to another memory stream without the Image.Save method adding/removing random properties?
byte[] imageCache = File.ReadAllBytes(@"c:\test\test.tif");
using (MemoryStream msOut = new MemoryStream())
{
using (MemoryStream ms = new MemoryStream(imageCache))
{
using (Image image = Image.FromStream(ms))
{
/*
Total tags on page 1 of 3: 20 tags
Image does not show the tag I want to add. This is expected.
*/
// Select the correct page (1 of 3)
image.SelectActiveFrame(FrameDimension.Page, 0);
// Add a tag to the image's page 1
PropertyItem property = CreateBasePropertyItem();
property.Id = 38888;
property.Type = 2;
property.Value = Encoding.ASCII.GetBytes("This is a test tag.");
property.Len = property.Value.Length;
// Save the tag on the image's page 1
image.SetPropertyItem(property);
/*
Total tags on page 1 of 3: 21 tags
Image does show the tag I just added. This is expected.
*/
// Save the image to a new memory stream
image.Save(msOut, image.RawFormat);
}
}
// Convert the new image to a byte array to replace the cached byte array
imageCache = msOut.ToArray();
}
using (MemoryStream ms = new MemoryStream(imageCache))
{
using (Image image = Image.FromStream(ms))
{
/*
Total tags on page 1 of 3: 13 tags
Image does not show the new tag I added above. This is not expected.
*/
}
}
Just so no one needs to ask, including this too even though it's irrelevant for the purpose of my question. Just to elaborate on this, the reason I'm using reflection to create a new PropertyItem is because there is not a way to create one with normal means. Microsoft recommends that you just clone an existing one, change it's values and then add it to the collection. Below is a function I created based off of suggestions from this answer.
Note: I have updated this function since posting the original question. The following function will cause errors, use the new one below it.
private PropertyItem CreateBasePropertyItem()
{
BindingFlags flags = (BindingFlags)(-20);
PropertyItem pi = (PropertyItem)typeof(PropertyItem)
.Assembly
.CreateInstance("System.Drawing.Imaging.PropertyItem", false, flags, null, null, null, null);
return pi;
}
Here is the new version of the function. This one below works.
private PropertyItem CreateBasePropertyItem()
{
return (PropertyItem)FormatterServices
.GetUninitializedObject(typeof(PropertyItem));
}
Now that I have managed to get it to work (saving the new property after saving the image to a memory stream), I noticed something else that was concerning as well. If I use this method for example (suggested by Microsoft) instead it does seem to save the new property in the memory stream.
byte[] imageCache = File.ReadAllBytes(@"c:\test\test.tif");
using (MemoryStream msOut = new MemoryStream())
{
using (MemoryStream ms = new MemoryStream(imageCache))
{
using (Image image = Image.FromStream(ms))
{
/*
Total tags on page: 23 tags
Image does not show the tag I want to add. This is expected.
*/
// Select the correct page (1 of 3)
image.SelectActiveFrame(FrameDimension.Page, 0);
// Add a tag to the image's page 1
PropertyItem property = image.PropertyItems[0];
foreach (var p in image.PropertyItems)
Debug.WriteLine($"BEFORE - ID:{p.Id} Type:{p.Type} Len:{p.Len}");
property.Id = 38888;
property.Type = 2;
property.Value = System.Text.Encoding.ASCII.GetBytes("This is a test tag.");
property.Len = property.Value.Length;
// Save the tag on the image's page 1
image.SetPropertyItem(property);
/*
Total tags on page: 24 tags
Image does show the tag I just added. This is expected.
*/
// Save the image to a new memory stream
image.Save(msOut, image.RawFormat);
}
}
// Convert the new image to a byte array to replace the cached byte array
imageCache = msOut.ToArray();
}
using (MemoryStream ms = new MemoryStream(imageCache))
{
using (Image image = Image.FromStream(ms))
{
foreach (var p in image.PropertyItems)
Debug.WriteLine($"AFTER - ID:{p.Id} Type:{p.Type} Len:{p.Len}");
/*
Total tags on page: 22 tags
Image does show the new tag I added above but other tags are added and some
others are missing. This is not expected.
*/
}
}
However, I loose other properties in the process. I'm not sure which way is the correct way of going about creating a new PropertyItem.
Upvotes: 0
Views: 34