dotnet / dotnet/winforms

Add custom image metadata to System.Drawing

Open
#8,836 1 comment 0 reactions 1 assignee Claimed by @JeremyKuhne View on GitHub
api-suggestion area-System.Drawing
Dominant language
C#
Stars
4.9k
Forks
1.1k
Avg merge
20h 23m
Merged PRs (30d)
103

Description

### Background

GDI+ 1.1 added support for custom image metadata. JPEG, PNG, and GIF images can have multiple `ImageItemData` objects serialized inside of them, each of which consist of a fixed-size description and any amount of arbitrary data. This functionality is accessed by adding the data to standard `EncodingParameter`s, which are configured with the new `ImageItems` encoder.

This proposal is one of many to add missing GDI+ 1.1 functionality to `System.Drawing`.

### Usage Example

Writing metadata:
```cs
Image image = Image.FromFile("river.jpg");
ImageCodecInfo codec = ImageCodecInfo.GetImageEncoders().Single(e => e.FormatID == ImageFormat.Jpeg.Guid);

var data = new ImageItemData(ItemDataPosition.AfterHeader,
new byte[] { 0xE4 },
Encoding.ASCII.GetBytes("Byte sequence of your choice"));

var parameters = new EncoderParameters
{
Param =
{
[0] = new EncoderParameter(Encoder.ImageItems, data)
}
};

image.Save("river2.jpg", codec, parameters);
```

Reading metadata:
```cs
Image image = Image.FromFile("river2.jpg");

foreach (ImageItemData item in image.EnumerateImageItems())
{
Console.WriteLine(Convert.ToHexString(item.Data));
}
```

### API Proposal

See the documentation for:
- [ImageItemData](https://docs.microsoft.com/en-us/windows/win32/api/gdiplusimaging/nl-gdiplusimaging-imageitemdata)
- [ItemDataPosition](https://docs.microsoft.com/en-us/windows/win32/api/gdiplusimaging/ne-gdiplusimaging-itemdataposition)
- [Image::GetItemData](https://docs.microsoft.com/en-us/windows/win32/api/gdiplusheaders/nf-gdiplusheaders-image-getitemdata)
- [Image::FindFirstItem](https://docs.microsoft.com/en-us/windows/win32/api/gdiplusheaders/nf-gdiplusheaders-image-findfirstitem)
- [Image::FindNextItem](https://docs.microsoft.com/en-us/windows/win32/api/gdiplusheaders/nf-gdiplusheaders-image-findnextitem)

```diff
namespace System.Drawing.Imaging
{
+ public sealed class ImageItemData
+ {
+ public ImageItemData(ItemDataPosition position, byte[] description, byte[] data);
+
+ public ItemDataPosition Position { get; set; }
+ public byte[] Description { get; set; }
+ public byte[] Data { get; set; }
+ }

+ public enum ItemDataPosition
+ {
+ AfterHeader,
+ AfterPalette,
+ AfterBits
+ }

public sealed class EncoderParameter : IDisposable
{
+ public EncoderParameter(Encoder encoder, ImageItemData value);
}
}

namespace System.Drawing
{
public abstract class Image : MarshalByRefObject, ICloneable, IDisposable, ISerializable
{
+ public IEnumerable EnumerateImageItems();
}
}
```

The native API exposes an enumerator to read this custom metadata. Firstly, `FindFirstItem` is called to initialize the enumerator. After calling this method, calling `FindNextItem` advances the iterator. Both of these methods populate data in a structure which is passed to `GetItemData`, which ultimately returns the complete metadata. I projected this into an IEnumerable for the managed definitions, as it seems to fit naturally.

This requires changes to libgdiplus in order to support it on non-Windows platforms.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.