diff --git a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj
index 70519aab76611..153bbc77f97fc 100644
--- a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj
+++ b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj
@@ -339,7 +339,6 @@
-
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Unix.cs
index 37bd0481c5067..f2f0594472a67 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Unix.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Unix.cs
@@ -121,30 +121,9 @@ private static void PlatformInitialize()
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipSetImagePalette(IntPtr image, IntPtr palette);
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertyCount(IntPtr image, out uint propNumbers);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertyIdList(IntPtr image, uint propNumbers, [Out] int[] list);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertySize(IntPtr image, out int bufferSize, out int propNumbers);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetAllPropertyItems(IntPtr image, int bufferSize, int propNumbers, IntPtr items);
-
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipGetImageBounds(IntPtr image, out RectangleF source, ref GraphicsUnit unit);
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertyItemSize(IntPtr image, int propertyID, out int propertySize);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertyItem(IntPtr image, int propertyID, int propertySize, IntPtr buffer);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipSetPropertyItem(IntPtr image, GdipPropertyItem* propertyItem);
-
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipGetImageThumbnail(IntPtr image, uint width, uint height, out IntPtr thumbImage, IntPtr callback, IntPtr callBackData);
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.cs
index 234eed272a771..47aeb4f9397c3 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.cs
@@ -248,27 +248,6 @@ private static void PlatformInitialize()
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipGetImagePaletteSize(HandleRef image, out int size);
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertyCount(HandleRef image, out int count);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertyIdList(HandleRef image, int count, int[] list);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertyItemSize(HandleRef image, int propid, out int size);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertyItem(HandleRef image, int propid, int size, IntPtr buffer);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetPropertySize(HandleRef image, out int totalSize, ref int count);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetAllPropertyItems(HandleRef image, int totalSize, int count, IntPtr buffer);
-
- [DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipSetPropertyItem(HandleRef image, PropertyItemInternal propitem);
-
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipImageForceValidation(IntPtr image);
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs
index 4071574574e10..18619993c0d1d 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs
@@ -1060,9 +1060,30 @@ internal static unsafe partial class Gdip
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipImageRotateFlip(HandleRef image, int rotateFlipType);
+ [DllImport(LibraryName, ExactSpelling = true)]
+ internal static extern int GdipGetAllPropertyItems(HandleRef image, uint totalBufferSize, uint numProperties, PropertyItemInternal* allItems);
+
+ [DllImport(LibraryName, ExactSpelling = true)]
+ internal static extern int GdipGetPropertyCount(HandleRef image, out uint numOfProperty);
+
+ [DllImport(LibraryName, ExactSpelling = true)]
+ internal static extern int GdipGetPropertyIdList(HandleRef image, uint numOfProperty, int* list);
+
+ [DllImport(LibraryName, ExactSpelling = true)]
+ internal static extern int GdipGetPropertyItem(HandleRef image, int propid, uint propSize, PropertyItemInternal* buffer);
+
+ [DllImport(LibraryName, ExactSpelling = true)]
+ internal static extern int GdipGetPropertyItemSize(HandleRef image, int propid, out uint size);
+
+ [DllImport(LibraryName, ExactSpelling = true)]
+ internal static extern int GdipGetPropertySize(HandleRef image, out uint totalBufferSize, out uint numProperties);
+
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipRemovePropertyItem(HandleRef image, int propid);
+ [DllImport(LibraryName, ExactSpelling = true)]
+ internal static extern int GdipSetPropertyItem(HandleRef image, PropertyItemInternal* item);
+
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipGetImageType(HandleRef image, out int type);
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Unix.cs
index 0385b18eb5ece..45504c00830ef 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Unix.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Unix.cs
@@ -98,35 +98,6 @@ public RectangleF GetBounds(ref GraphicsUnit pageUnit)
return source;
}
- public PropertyItem GetPropertyItem(int propid)
- {
- int propSize;
- IntPtr property;
- PropertyItem item = new PropertyItem();
- GdipPropertyItem gdipProperty = default;
- int status;
-
- status = Gdip.GdipGetPropertyItemSize(nativeImage, propid,
- out propSize);
- Gdip.CheckStatus(status);
-
- /* Get PropertyItem */
- property = Marshal.AllocHGlobal(propSize);
- try
- {
- status = Gdip.GdipGetPropertyItem(nativeImage, propid, propSize, property);
- Gdip.CheckStatus(status);
- gdipProperty = (GdipPropertyItem)Marshal.PtrToStructure(property,
- typeof(GdipPropertyItem))!;
- GdipPropertyItem.MarshalTo(gdipProperty, item);
- }
- finally
- {
- Marshal.FreeHGlobal(property);
- }
- return item;
- }
-
public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort? callback, IntPtr callbackData)
{
if ((thumbWidth <= 0) || (thumbHeight <= 0))
@@ -285,37 +256,6 @@ public void SaveAdd(Image image, EncoderParameters encoderParams)
Gdip.CheckStatus(st);
}
- public void SetPropertyItem(PropertyItem propitem)
- {
- if (propitem == null)
- throw new ArgumentNullException(nameof(propitem));
-
- int nItemSize = Marshal.SizeOf(propitem.Value![0]);
- int size = nItemSize * propitem.Value.Length;
- IntPtr dest = Marshal.AllocHGlobal(size);
- try
- {
- GdipPropertyItem pi = default;
- pi.id = propitem.Id;
- pi.len = propitem.Len;
- pi.type = propitem.Type;
-
- Marshal.Copy(propitem.Value, 0, dest, size);
- pi.value = dest;
-
- unsafe
- {
- int status = Gdip.GdipSetPropertyItem(nativeImage, &pi);
-
- Gdip.CheckStatus(status);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(dest);
- }
- }
-
[Browsable(false)]
public ColorPalette Palette
{
@@ -375,72 +315,6 @@ internal void storeGDIPalette(ColorPalette palette)
}
}
- [Browsable(false)]
- public int[] PropertyIdList
- {
- get
- {
- uint propNumbers;
-
- int status = Gdip.GdipGetPropertyCount(nativeImage,
- out propNumbers);
- Gdip.CheckStatus(status);
-
- int[] idList = new int[propNumbers];
- status = Gdip.GdipGetPropertyIdList(nativeImage,
- propNumbers, idList);
- Gdip.CheckStatus(status);
-
- return idList;
- }
- }
-
- [Browsable(false)]
- public PropertyItem[] PropertyItems
- {
- get
- {
- int propNums, propsSize, propSize;
- IntPtr properties, propPtr;
- PropertyItem[] items;
- GdipPropertyItem gdipProperty = default;
- int status;
-
- status = Gdip.GdipGetPropertySize(nativeImage, out propsSize, out propNums);
- Gdip.CheckStatus(status);
-
- items = new PropertyItem[propNums];
-
- if (propNums == 0)
- return items;
-
- /* Get PropertyItem list*/
- properties = Marshal.AllocHGlobal(propsSize * propNums);
- try
- {
- status = Gdip.GdipGetAllPropertyItems(nativeImage, propsSize,
- propNums, properties);
- Gdip.CheckStatus(status);
-
- propSize = Marshal.SizeOf(gdipProperty);
- propPtr = properties;
-
- for (int i = 0; i < propNums; i++, propPtr = new IntPtr(propPtr.ToInt64() + propSize))
- {
- gdipProperty = (GdipPropertyItem)Marshal.PtrToStructure
- (propPtr, typeof(GdipPropertyItem))!;
- items[i] = new PropertyItem();
- GdipPropertyItem.MarshalTo(gdipProperty, items[i]);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(properties);
- }
- return items;
- }
- }
-
protected virtual void Dispose(bool disposing)
{
if (nativeImage != IntPtr.Zero)
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
index 545e85f9f649b..a6dd53744a974 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
@@ -390,91 +390,6 @@ public Image GetThumbnailImage(int thumbWidth, int thumbHeight, GetThumbnailImag
return CreateImageObject(thumbImage);
}
- ///
- /// Gets an array of the property IDs stored in this .
- ///
- [Browsable(false)]
- public int[] PropertyIdList
- {
- get
- {
- Gdip.CheckStatus(Gdip.GdipGetPropertyCount(new HandleRef(this, nativeImage), out int count));
-
- int[] propid = new int[count];
-
- //if we have a 0 count, just return our empty array
- if (count == 0)
- return propid;
-
- Gdip.CheckStatus(Gdip.GdipGetPropertyIdList(new HandleRef(this, nativeImage), count, propid));
-
- return propid;
- }
- }
-
- ///
- /// Gets the specified property item from this .
- ///
- public PropertyItem? GetPropertyItem(int propid)
- {
- Gdip.CheckStatus(Gdip.GdipGetPropertyItemSize(new HandleRef(this, nativeImage), propid, out int size));
-
- if (size == 0)
- return null;
-
- IntPtr propdata = Marshal.AllocHGlobal(size);
-
- try
- {
- Gdip.CheckStatus(Gdip.GdipGetPropertyItem(new HandleRef(this, nativeImage), propid, size, propdata));
- return PropertyItemInternal.ConvertFromMemory(propdata, 1)[0];
- }
- finally
- {
- Marshal.FreeHGlobal(propdata);
- }
- }
-
- ///
- /// Sets the specified property item to the specified value.
- ///
- public void SetPropertyItem(PropertyItem propitem)
- {
- PropertyItemInternal propItemInternal = PropertyItemInternal.ConvertFromPropertyItem(propitem);
-
- using (propItemInternal)
- {
- Gdip.CheckStatus(Gdip.GdipSetPropertyItem(new HandleRef(this, nativeImage), propItemInternal));
- }
- }
-
- ///
- /// Gets an array of objects that describe this .
- ///
- [Browsable(false)]
- public PropertyItem[] PropertyItems
- {
- get
- {
- Gdip.CheckStatus(Gdip.GdipGetPropertyCount(new HandleRef(this, nativeImage), out int count));
- Gdip.CheckStatus(Gdip.GdipGetPropertySize(new HandleRef(this, nativeImage), out int size, ref count));
-
- if (size == 0 || count == 0)
- return Array.Empty();
-
- IntPtr propdata = Marshal.AllocHGlobal(size);
- try
- {
- Gdip.CheckStatus(Gdip.GdipGetAllPropertyItems(new HandleRef(this, nativeImage), size, count, propdata));
- return PropertyItemInternal.ConvertFromMemory(propdata, count);
- }
- finally
- {
- Marshal.FreeHGlobal(propdata);
- }
- }
- }
-
internal static void ValidateImage(IntPtr image)
{
try
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.cs
index 4321b50a8140e..24977ec94a51f 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Buffers;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Imaging;
@@ -298,6 +299,65 @@ public PixelFormat PixelFormat
}
}
+ ///
+ /// Gets an array of the property IDs stored in this .
+ ///
+ [Browsable(false)]
+ public unsafe int[] PropertyIdList
+ {
+ get
+ {
+ Gdip.CheckStatus(Gdip.GdipGetPropertyCount(new HandleRef(this, nativeImage), out uint count));
+ if (count == 0)
+ return Array.Empty();
+
+ var propid = new int[count];
+ fixed (int* pPropid = propid)
+ {
+ Gdip.CheckStatus(Gdip.GdipGetPropertyIdList(new HandleRef(this, nativeImage), count, pPropid));
+ }
+
+ return propid;
+ }
+ }
+
+ ///
+ /// Gets an array of objects that describe this .
+ ///
+ [Browsable(false)]
+ public unsafe PropertyItem[] PropertyItems
+ {
+ get
+ {
+ Gdip.CheckStatus(Gdip.GdipGetPropertySize(new HandleRef(this, nativeImage), out uint size, out uint count));
+
+ if (size == 0 || count == 0)
+ return Array.Empty();
+
+ var result = new PropertyItem[(int)count];
+ byte[] buffer = ArrayPool.Shared.Rent((int)size);
+ fixed (byte *pBuffer = buffer)
+ {
+ PropertyItemInternal* pPropData = (PropertyItemInternal*)pBuffer;
+ Gdip.CheckStatus(Gdip.GdipGetAllPropertyItems(new HandleRef(this, nativeImage), size, count, pPropData));
+
+ for (int i = 0; i < count; i++)
+ {
+ result[i] = new PropertyItem
+ {
+ Id = pPropData[i].id,
+ Len = pPropData[i].len,
+ Type = pPropData[i].type,
+ Value = pPropData[i].Value.ToArray()
+ };
+ }
+ }
+
+ ArrayPool.Shared.Return(buffer);
+ return result;
+ }
+ }
+
///
/// Returns the number of frames of the given dimension.
///
@@ -308,6 +368,36 @@ public int GetFrameCount(FrameDimension dimension)
return count;
}
+ ///
+ /// Gets the specified property item from this .
+ ///
+ public unsafe PropertyItem? GetPropertyItem(int propid)
+ {
+ Gdip.CheckStatus(Gdip.GdipGetPropertyItemSize(new HandleRef(this, nativeImage), propid, out uint size));
+
+ if (size == 0)
+ return null;
+
+ PropertyItem result;
+ byte[] buffer = ArrayPool.Shared.Rent((int)size);
+ fixed (byte *pBuffer = buffer)
+ {
+ PropertyItemInternal* pPropData = (PropertyItemInternal*)pBuffer;
+ Gdip.CheckStatus(Gdip.GdipGetPropertyItem(new HandleRef(this, nativeImage), propid, size, pPropData));
+
+ result = new PropertyItem
+ {
+ Id = pPropData->id,
+ Len = pPropData->len,
+ Type = pPropData->type,
+ Value = pPropData->Value.ToArray()
+ };
+ }
+
+ ArrayPool.Shared.Return(buffer);
+ return result;
+ }
+
///
/// Selects the frame specified by the given dimension and index.
///
@@ -318,6 +408,24 @@ public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
return 0;
}
+ ///
+ /// Sets the specified property item to the specified value.
+ ///
+ public unsafe void SetPropertyItem(PropertyItem propitem)
+ {
+ fixed (byte *propItemValue = propitem.Value)
+ {
+ var propItemInternal = new PropertyItemInternal
+ {
+ id = propitem.Id,
+ len = propitem.Len,
+ type = propitem.Type,
+ value = propItemValue
+ };
+ Gdip.CheckStatus(Gdip.GdipSetPropertyItem(new HandleRef(this, nativeImage), &propItemInternal));
+ }
+ }
+
public void RotateFlip(RotateFlipType rotateFlipType)
{
int status = Gdip.GdipImageRotateFlip(new HandleRef(this, nativeImage), unchecked((int)rotateFlipType));
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/ImageAnimator.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/ImageAnimator.Unix.cs
index 0da66c044b546..a8a03c47fa444 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/ImageAnimator.Unix.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/ImageAnimator.Unix.cs
@@ -88,7 +88,7 @@ public static void Animate(Image image, EventHandler onFrameChangedHandler)
if (ht.ContainsKey(image))
return;
- PropertyItem item = image.GetPropertyItem(0x5100); // FrameDelay in libgdiplus
+ PropertyItem item = image.GetPropertyItem(0x5100)!; // FrameDelay in libgdiplus
byte[] value = item.Value!;
int[] delay = new int[(value.Length >> 2)];
for (int i = 0, n = 0; i < value.Length; i += 4, n++)
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/PropertyItem.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/PropertyItem.cs
index 4f28e7a933247..cc7974280e30a 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/PropertyItem.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/PropertyItem.cs
@@ -9,11 +9,6 @@ namespace System.Drawing.Imaging
///
public sealed class PropertyItem
{
- private int _id;
- private int _len;
- private short _type;
- private byte[]? _value;
-
internal PropertyItem()
{
}
@@ -21,34 +16,21 @@ internal PropertyItem()
///
/// Represents the ID of the property.
///
- public int Id
- {
- get { return _id; }
- set { _id = value; }
- }
+ public int Id { get; set; }
+
///
/// Represents the length of the property.
///
- public int Len
- {
- get { return _len; }
- set { _len = value; }
- }
+ public int Len { get; set; }
+
///
/// Represents the type of the property.
///
- public short Type
- {
- get { return _type; }
- set { _type = value; }
- }
+ public short Type { get; set; }
+
///
/// Contains the property value.
///
- public byte[]? Value
- {
- get { return _value; }
- set { _value = value; }
- }
+ public byte[]? Value { get; set; }
}
}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/LibX11Functions.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/LibX11Functions.cs
index 0d3ae0aa061a8..daafc9a7f6806 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/LibX11Functions.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/LibX11Functions.cs
@@ -46,4 +46,19 @@ internal static class LibX11Functions
[DllImport("libX11", EntryPoint = "XFree")]
internal static extern void XFree(IntPtr data);
}
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct XVisualInfo
+ {
+ internal IntPtr visual;
+ internal IntPtr visualid;
+ internal int screen;
+ internal uint depth;
+ internal int klass;
+ internal IntPtr red_mask;
+ internal IntPtr green_mask;
+ internal IntPtr blue_mask;
+ internal int colormap_size;
+ internal int bits_per_rgb;
+ }
}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/NativeStructs.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/NativeStructs.Unix.cs
deleted file mode 100644
index 0b1822199e0ee..0000000000000
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/NativeStructs.Unix.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-//
-// System.Drawing.NativeStructs.cs
-//
-// Author:
-// Alexandre Pigolkine (pigolkine@gmx.de)
-// Jordi Mas (jordi@ximian.com)
-//
-// Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System.Drawing.Imaging;
-using System.Runtime.InteropServices;
-
-namespace System.Drawing
-{
- [StructLayout(LayoutKind.Sequential)]
- internal struct GdipImageCodecInfo
- {
- internal Guid Clsid;
- internal Guid FormatID;
- internal IntPtr CodecName;
- internal IntPtr DllName;
- internal IntPtr FormatDescription;
- internal IntPtr FilenameExtension;
- internal IntPtr MimeType;
- internal ImageCodecFlags Flags;
- internal int Version;
- internal int SigCount;
- internal int SigSize;
- private IntPtr SigPattern;
- private IntPtr SigMask;
-
- internal static void MarshalTo(GdipImageCodecInfo gdipcodec, ImageCodecInfo codec)
- {
- codec.CodecName = Marshal.PtrToStringUni(gdipcodec.CodecName);
- codec.DllName = Marshal.PtrToStringUni(gdipcodec.DllName);
- codec.FormatDescription = Marshal.PtrToStringUni(gdipcodec.FormatDescription);
- codec.FilenameExtension = Marshal.PtrToStringUni(gdipcodec.FilenameExtension);
- codec.MimeType = Marshal.PtrToStringUni(gdipcodec.MimeType);
- codec.Clsid = gdipcodec.Clsid;
- codec.FormatID = gdipcodec.FormatID;
- codec.Flags = gdipcodec.Flags;
- codec.Version = gdipcodec.Version;
- codec.SignatureMasks = new byte[gdipcodec.SigCount][];
- codec.SignaturePatterns = new byte[gdipcodec.SigCount][];
- IntPtr p = gdipcodec.SigPattern;
- IntPtr m = gdipcodec.SigMask;
- for (int i = 0; i < gdipcodec.SigCount; i++)
- {
- codec.SignatureMasks[i] = new byte[gdipcodec.SigSize];
- Marshal.Copy(m, codec.SignatureMasks[i], 0, gdipcodec.SigSize);
- m = new IntPtr(m.ToInt64() + gdipcodec.SigSize);
- codec.SignaturePatterns[i] = new byte[gdipcodec.SigSize];
- Marshal.Copy(p, codec.SignaturePatterns[i], 0, gdipcodec.SigSize);
- p = new IntPtr(p.ToInt64() + gdipcodec.SigSize);
- }
- }
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct GdipPropertyItem
- {
- internal int id;
- internal int len;
- internal short type;
- internal IntPtr value;
-
- internal static void MarshalTo(GdipPropertyItem gdipProp, PropertyItem prop)
- {
- prop.Id = gdipProp.id;
- prop.Len = gdipProp.len;
- prop.Type = gdipProp.type;
- prop.Value = new byte[gdipProp.len];
- Marshal.Copy(gdipProp.value, prop.Value, 0, gdipProp.len);
- }
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct IconInfo
- {
- private int fIcon;
- public int xHotspot;
- public int yHotspot;
- public IntPtr hbmMask;
- public IntPtr hbmColor;
-
- public bool IsIcon
- {
- get { return (fIcon == 1); }
- set { fIcon = (value) ? 1 : 0; }
- }
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct XVisualInfo
- {
- internal IntPtr visual;
- internal IntPtr visualid;
- internal int screen;
- internal uint depth;
- internal int klass;
- internal IntPtr red_mask;
- internal IntPtr green_mask;
- internal IntPtr blue_mask;
- internal int colormap_size;
- internal int bits_per_rgb;
- }
-}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/PropertyItemInternal.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/PropertyItemInternal.cs
index c811ea17672ee..e64c042c6d90e 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/PropertyItemInternal.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/PropertyItemInternal.cs
@@ -1,119 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Runtime.InteropServices;
+
namespace System.Drawing.Imaging
{
- using System.Runtime.InteropServices;
-
- // sdkinc\imaging.h
- [StructLayout(LayoutKind.Sequential)]
- internal sealed class PropertyItemInternal : IDisposable
+ internal unsafe struct PropertyItemInternal
{
public int id;
public int len;
public short type;
- public IntPtr value = IntPtr.Zero;
-
- internal PropertyItemInternal()
- {
- }
-
- ~PropertyItemInternal()
- {
- Dispose(false);
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- private void Dispose(bool disposing)
- {
- if (value != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(value);
- value = IntPtr.Zero;
- }
-
- if (disposing)
- {
- GC.SuppressFinalize(this);
- }
- }
-
- internal static PropertyItemInternal ConvertFromPropertyItem(PropertyItem propItem)
- {
- PropertyItemInternal propItemInternal = new PropertyItemInternal();
- propItemInternal.id = propItem.Id;
- propItemInternal.len = 0;
- propItemInternal.type = propItem.Type;
-
- byte[]? propItemValue = propItem.Value;
- if (propItemValue != null)
- {
- int length = propItemValue.Length;
- propItemInternal.len = length;
- propItemInternal.value = Marshal.AllocHGlobal(length);
- Marshal.Copy(propItemValue, 0, propItemInternal.value, length);
- }
-
- return propItemInternal;
- }
-
- internal static PropertyItem[] ConvertFromMemory(IntPtr propdata, int count)
- {
- PropertyItem[] props = new PropertyItem[count];
-
- for (int i = 0; i < count; i++)
- {
- PropertyItemInternal? propcopy = null;
- try
- {
- propcopy = (PropertyItemInternal)Marshal.PtrToStructure(propdata,
- typeof(PropertyItemInternal))!;
-
- props[i] = new PropertyItem();
- props[i].Id = propcopy.id;
- props[i].Len = propcopy.len;
- props[i].Type = propcopy.type;
-
- // this calls Marshal.Copy and creates a copy of the original memory into a byte array.
- props[i].Value = propcopy.Value;
-
- propcopy.value = IntPtr.Zero; // we dont actually own this memory so dont free it.
- }
- finally
- {
- if (propcopy != null)
- {
- propcopy.Dispose();
- }
- }
-
- propdata = (IntPtr)((long)propdata + (int)Marshal.SizeOf(typeof(PropertyItemInternal)));
- }
-
- return props;
- }
-
- public byte[]? Value
- {
- get
- {
- if (len == 0)
- {
- return null;
- }
-
- byte[] bytes = new byte[len];
+ public byte* value;
- Marshal.Copy(value,
- bytes,
- 0,
- (int)len);
- return bytes;
- }
- }
+ public Span Value => new Span(value, len);
}
}
diff --git a/src/libraries/System.Drawing.Common/tests/ImageTests.cs b/src/libraries/System.Drawing.Common/tests/ImageTests.cs
index 04a361394609b..08cce1156a2e8 100644
--- a/src/libraries/System.Drawing.Common/tests/ImageTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/ImageTests.cs
@@ -5,13 +5,498 @@
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
using Microsoft.DotNet.XUnitExtensions;
using Xunit;
+using Encoder = System.Drawing.Imaging.Encoder;
namespace System.Drawing.Tests
{
public class ImageTests
{
+ private const int PropertyTagLuminanceTable = 0x5090;
+ private const int PropertyTagChrominanceTable = 0x5091;
+ private const int PropertyTagExifUserComment = 0x9286;
+ private const int PropertyTagTypeASCII = 2;
+ private const int PropertyTagTypeShort = 3;
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ public void PropertyIdList_GetBitmapJpg_Success()
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ Assert.Equal(new int[] { PropertyTagExifUserComment, PropertyTagChrominanceTable, PropertyTagLuminanceTable }, bitmap.PropertyIdList);
+ Assert.NotSame(bitmap.PropertyIdList, bitmap.PropertyIdList);
+ }
+
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Returns new int[0] in .NET Framework.")]
+ public void PropertyIdList_GetEmptyMemoryBitmap_ReturnsExpected()
+ {
+ using var bitmap = new Bitmap(1, 1);
+ Assert.Empty(bitmap.PropertyIdList);
+ Assert.Same(bitmap.PropertyIdList, bitmap.PropertyIdList);
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ public void PropertyItems_GetBitmapJpg_Success()
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ PropertyItem[] items = bitmap.PropertyItems;
+ Assert.Equal(3, items.Length);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(29, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("LEAD Technologies Inc. V1.01\0", Encoding.ASCII.GetString(items[0].Value));
+ Assert.Equal(PropertyTagChrominanceTable, items[1].Id);
+ Assert.Equal(128, items[1].Len);
+ Assert.Equal(PropertyTagTypeShort, items[1].Type);
+ Assert.Equal(new byte[]
+ {
+ 0x16, 0x00, 0x17, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x17,
+ 0x00, 0x1B, 0x00, 0x22, 0x00, 0x57, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x1F,
+ 0x00, 0x22, 0x00, 0x49, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x3E,
+ 0x00, 0x57, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00
+ }, items[1].Value);
+ Assert.Equal(PropertyTagLuminanceTable, items[2].Id);
+ Assert.Equal(128, items[2].Len);
+ Assert.Equal(PropertyTagTypeShort, items[2].Type);
+ Assert.Equal(new byte[]
+ {
+ 0x15, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x34, 0x00, 0x43, 0x00, 0x50, 0x00, 0x0F,
+ 0x00, 0x0F, 0x00, 0x12, 0x00, 0x19, 0x00, 0x22, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x48, 0x00, 0x12,
+ 0x00, 0x11, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x34, 0x00, 0x4B, 0x00, 0x5B, 0x00, 0x49, 0x00, 0x12,
+ 0x00, 0x16, 0x00, 0x1D, 0x00, 0x26, 0x00, 0x43, 0x00, 0x72, 0x00, 0x69, 0x00, 0x51, 0x00, 0x17,
+ 0x00, 0x1D, 0x00, 0x30, 0x00, 0x49, 0x00, 0x59, 0x00, 0x8F, 0x00, 0x87, 0x00, 0x65, 0x00, 0x1F,
+ 0x00, 0x2E, 0x00, 0x48, 0x00, 0x54, 0x00, 0x6A, 0x00, 0x89, 0x00, 0x95, 0x00, 0x79, 0x00, 0x40,
+ 0x00, 0x54, 0x00, 0x66, 0x00, 0x72, 0x00, 0x87, 0x00, 0x9F, 0x00, 0x9E, 0x00, 0x85, 0x00, 0x5F,
+ 0x00, 0x79, 0x00, 0x7D, 0x00, 0x81, 0x00, 0x93, 0x00, 0x84, 0x00, 0x87, 0x00, 0x82, 0x00,
+ }, items[2].Value);
+
+ Assert.NotSame(items, bitmap.PropertyItems);
+ }
+
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Returns new PropertyItem[0] in .NET Framework.")]
+ public void PropertyItems_GetEmptyBitmapBmp_Success()
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("almogaver1bit.bmp"));
+ Assert.Empty(bitmap.PropertyItems);
+ Assert.Same(bitmap.PropertyItems, bitmap.PropertyItems);
+ }
+
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Returns new PropertyItem[0] in .NET Framework.")]
+ public void PropertyItems_GetEmptyMemoryBitmap_ReturnsExpected()
+ {
+ using var bitmap = new Bitmap(1, 1);
+ Assert.Empty(bitmap.PropertyItems);
+ Assert.Same(bitmap.PropertyItems, bitmap.PropertyItems);
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ public void GetPropertyItem_InvokeExistsBitmapBmp_Success()
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ PropertyItem item = bitmap.GetPropertyItem(PropertyTagExifUserComment);
+ Assert.Equal(PropertyTagExifUserComment, item.Id);
+ Assert.Equal(29, item.Len);
+ Assert.Equal(PropertyTagTypeASCII, item.Type);
+ Assert.Equal("LEAD Technologies Inc. V1.01\0", Encoding.ASCII.GetString(item.Value));
+ }
+
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void GetPropertyItem_NoSuchPropertyItemEmptyMemoryBitmap_ThrowsArgumentException(int propid)
+ {
+ using var bitmap = new Bitmap(1, 1);
+ Assert.Throws(null, () => bitmap.GetPropertyItem(propid));
+ }
+
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void GetPropertyItem_NoSuchPropertyItemEmptyImageBitmapBmp_ThrowsArgumentException(int propid)
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("almogaver1bit.bmp"));
+ Assert.Throws(null, () => bitmap.GetPropertyItem(propid));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ public void RemovePropertyItem_InvokeMemoryBitmap_Success()
+ {
+ using var source = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ PropertyItem item1 = source.GetPropertyItem(PropertyTagExifUserComment);
+ PropertyItem item2 = source.GetPropertyItem(PropertyTagChrominanceTable);
+ PropertyItem item3 = source.GetPropertyItem(PropertyTagLuminanceTable);
+ using var bitmap = new Bitmap(1, 1);
+ bitmap.SetPropertyItem(item1);
+ bitmap.SetPropertyItem(item2);
+ bitmap.SetPropertyItem(item3);
+
+ bitmap.RemovePropertyItem(PropertyTagExifUserComment);
+ Assert.Equal(new int[] { PropertyTagChrominanceTable, PropertyTagLuminanceTable }, bitmap.PropertyIdList);
+ Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagExifUserComment));
+ Assert.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagExifUserComment));
+
+ bitmap.RemovePropertyItem(PropertyTagLuminanceTable);
+ Assert.Equal(new int[] { PropertyTagChrominanceTable }, bitmap.PropertyIdList);
+ Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagLuminanceTable));
+ Assert.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagLuminanceTable));
+
+ bitmap.RemovePropertyItem(PropertyTagChrominanceTable);
+ Assert.Empty(bitmap.PropertyIdList);
+ Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagChrominanceTable));
+ Assert.Throws(() => bitmap.RemovePropertyItem(PropertyTagChrominanceTable));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalFact(Helpers.IsDrawingSupported)]
+ public void RemovePropertyItem_InvokeBitmapJpg_Success()
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ bitmap.RemovePropertyItem(PropertyTagExifUserComment);
+ Assert.Equal(new int[] { PropertyTagChrominanceTable, PropertyTagLuminanceTable }, bitmap.PropertyIdList);
+ Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagExifUserComment));
+ Assert.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagExifUserComment));
+
+ bitmap.RemovePropertyItem(PropertyTagLuminanceTable);
+ Assert.Equal(new int[] { PropertyTagChrominanceTable }, bitmap.PropertyIdList);
+ Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagLuminanceTable));
+ Assert.Throws(null, () => bitmap.RemovePropertyItem(PropertyTagLuminanceTable));
+
+ bitmap.RemovePropertyItem(PropertyTagChrominanceTable);
+ Assert.Empty(bitmap.PropertyIdList);
+ Assert.Throws(null, () => bitmap.GetPropertyItem(PropertyTagChrominanceTable));
+ Assert.Throws(() => bitmap.RemovePropertyItem(PropertyTagChrominanceTable));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void RemovePropertyItem_NoSuchPropertyItemEmptyMemoryBitmap_ThrowsExternalException(int propid)
+ {
+ using var bitmap = new Bitmap(1, 1);
+ Assert.Throws(() => bitmap.RemovePropertyItem(propid));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void RemovePropertyItem_NoSuchPropertyItemEmptyImageBitmapBmp_ThrowsExternalException(int propid)
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("almogaver1bit.bmp"));
+ Assert.Throws(() => bitmap.RemovePropertyItem(propid));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void RemovePropertyItem_NoSuchPropertyNotEmptyMemoryBitmap_ThrowsArgumentException(int propid)
+ {
+ using var source = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ PropertyItem item1 = source.GetPropertyItem(PropertyTagExifUserComment);
+ PropertyItem item2 = source.GetPropertyItem(PropertyTagChrominanceTable);
+ PropertyItem item3 = source.GetPropertyItem(PropertyTagLuminanceTable);
+ using var bitmap = new Bitmap(1, 1);
+ bitmap.SetPropertyItem(item1);
+ bitmap.SetPropertyItem(item2);
+ bitmap.SetPropertyItem(item3);
+
+ Assert.Throws(null, () => bitmap.RemovePropertyItem(propid));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void RemovePropertyItem_NoSuchPropertyNotEmptyBitmapJpg_ThrowsArgumentException(int propid)
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ Assert.Throws(null, () => bitmap.RemovePropertyItem(propid));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void SetPropertyItem_InvokeMemoryBitmap_Success(int propid)
+ {
+ using var source = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ using var bitmap = new Bitmap(1, 1);
+
+ // Change data.
+ PropertyItem item = source.GetPropertyItem(PropertyTagExifUserComment);
+ item.Value = Encoding.ASCII.GetBytes("Hello World\0");
+ item.Len = item.Value.Length;
+
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment }, bitmap.PropertyIdList);
+ PropertyItem[] items = bitmap.PropertyItems;
+ Assert.Single(items);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+
+ // New data.
+ item.Id = propid;
+ item.Value = Encoding.ASCII.GetBytes("New Value\0");
+ item.Len = item.Value.Length;
+
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment, propid }, bitmap.PropertyIdList);
+ items = bitmap.PropertyItems;
+ Assert.Equal(2, items.Length);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+ Assert.Equal(propid, items[1].Id);
+ Assert.Equal(10, items[1].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[1].Type);
+ Assert.Equal("New Value\0", Encoding.ASCII.GetString(items[1].Value));
+
+ // Set same.
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment, propid }, bitmap.PropertyIdList);
+ items = bitmap.PropertyItems;
+ Assert.Equal(2, items.Length);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+ Assert.Equal(propid, items[1].Id);
+ Assert.Equal(10, items[1].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[1].Type);
+ Assert.Equal("New Value\0", Encoding.ASCII.GetString(items[1].Value));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void SetPropertyItem_InvokeBitmapJpg_Success(int propid)
+ {
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+
+ // Change data.
+ PropertyItem item = bitmap.GetPropertyItem(PropertyTagExifUserComment);
+ item.Value = Encoding.ASCII.GetBytes("Hello World\0");
+ item.Len = item.Value.Length;
+
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment, PropertyTagChrominanceTable, PropertyTagLuminanceTable }, bitmap.PropertyIdList);
+ PropertyItem[] items = bitmap.PropertyItems;
+ Assert.Equal(3, items.Length);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+ Assert.Equal(PropertyTagChrominanceTable, items[1].Id);
+ Assert.Equal(128, items[1].Len);
+ Assert.Equal(PropertyTagTypeShort, items[1].Type);
+ Assert.Equal(new byte[]
+ {
+ 0x16, 0x00, 0x17, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x17,
+ 0x00, 0x1B, 0x00, 0x22, 0x00, 0x57, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x1F,
+ 0x00, 0x22, 0x00, 0x49, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x3E,
+ 0x00, 0x57, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00
+ }, items[1].Value);
+ Assert.Equal(PropertyTagLuminanceTable, items[2].Id);
+ Assert.Equal(128, items[2].Len);
+ Assert.Equal(PropertyTagTypeShort, items[2].Type);
+ Assert.Equal(new byte[]
+ {
+ 0x15, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x34, 0x00, 0x43, 0x00, 0x50, 0x00, 0x0F,
+ 0x00, 0x0F, 0x00, 0x12, 0x00, 0x19, 0x00, 0x22, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x48, 0x00, 0x12,
+ 0x00, 0x11, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x34, 0x00, 0x4B, 0x00, 0x5B, 0x00, 0x49, 0x00, 0x12,
+ 0x00, 0x16, 0x00, 0x1D, 0x00, 0x26, 0x00, 0x43, 0x00, 0x72, 0x00, 0x69, 0x00, 0x51, 0x00, 0x17,
+ 0x00, 0x1D, 0x00, 0x30, 0x00, 0x49, 0x00, 0x59, 0x00, 0x8F, 0x00, 0x87, 0x00, 0x65, 0x00, 0x1F,
+ 0x00, 0x2E, 0x00, 0x48, 0x00, 0x54, 0x00, 0x6A, 0x00, 0x89, 0x00, 0x95, 0x00, 0x79, 0x00, 0x40,
+ 0x00, 0x54, 0x00, 0x66, 0x00, 0x72, 0x00, 0x87, 0x00, 0x9F, 0x00, 0x9E, 0x00, 0x85, 0x00, 0x5F,
+ 0x00, 0x79, 0x00, 0x7D, 0x00, 0x81, 0x00, 0x93, 0x00, 0x84, 0x00, 0x87, 0x00, 0x82, 0x00,
+ }, items[2].Value);
+
+ // New data.
+ item.Id = propid;
+ item.Value = Encoding.ASCII.GetBytes("New Value\0");
+ item.Len = item.Value.Length;
+
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment, PropertyTagChrominanceTable, PropertyTagLuminanceTable, propid }, bitmap.PropertyIdList);
+ items = bitmap.PropertyItems;
+ Assert.Equal(4, items.Length);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+ Assert.Equal(PropertyTagChrominanceTable, items[1].Id);
+ Assert.Equal(128, items[1].Len);
+ Assert.Equal(PropertyTagTypeShort, items[1].Type);
+ Assert.Equal(new byte[]
+ {
+ 0x16, 0x00, 0x17, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x17,
+ 0x00, 0x1B, 0x00, 0x22, 0x00, 0x57, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x1F,
+ 0x00, 0x22, 0x00, 0x49, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x3E,
+ 0x00, 0x57, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00
+ }, items[1].Value);
+ Assert.Equal(PropertyTagLuminanceTable, items[2].Id);
+ Assert.Equal(128, items[2].Len);
+ Assert.Equal(PropertyTagTypeShort, items[2].Type);
+ Assert.Equal(new byte[]
+ {
+ 0x15, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x34, 0x00, 0x43, 0x00, 0x50, 0x00, 0x0F,
+ 0x00, 0x0F, 0x00, 0x12, 0x00, 0x19, 0x00, 0x22, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x48, 0x00, 0x12,
+ 0x00, 0x11, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x34, 0x00, 0x4B, 0x00, 0x5B, 0x00, 0x49, 0x00, 0x12,
+ 0x00, 0x16, 0x00, 0x1D, 0x00, 0x26, 0x00, 0x43, 0x00, 0x72, 0x00, 0x69, 0x00, 0x51, 0x00, 0x17,
+ 0x00, 0x1D, 0x00, 0x30, 0x00, 0x49, 0x00, 0x59, 0x00, 0x8F, 0x00, 0x87, 0x00, 0x65, 0x00, 0x1F,
+ 0x00, 0x2E, 0x00, 0x48, 0x00, 0x54, 0x00, 0x6A, 0x00, 0x89, 0x00, 0x95, 0x00, 0x79, 0x00, 0x40,
+ 0x00, 0x54, 0x00, 0x66, 0x00, 0x72, 0x00, 0x87, 0x00, 0x9F, 0x00, 0x9E, 0x00, 0x85, 0x00, 0x5F,
+ 0x00, 0x79, 0x00, 0x7D, 0x00, 0x81, 0x00, 0x93, 0x00, 0x84, 0x00, 0x87, 0x00, 0x82, 0x00,
+ }, items[2].Value);
+ Assert.Equal(propid, items[3].Id);
+ Assert.Equal(10, items[3].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[3].Type);
+ Assert.Equal("New Value\0", Encoding.ASCII.GetString(items[3].Value));
+
+ // Set same.
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment, PropertyTagChrominanceTable, PropertyTagLuminanceTable, propid }, bitmap.PropertyIdList);
+ items = bitmap.PropertyItems;
+ Assert.Equal(4, items.Length);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+ Assert.Equal(PropertyTagChrominanceTable, items[1].Id);
+ Assert.Equal(128, items[1].Len);
+ Assert.Equal(PropertyTagTypeShort, items[1].Type);
+ Assert.Equal(new byte[]
+ {
+ 0x16, 0x00, 0x17, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x17,
+ 0x00, 0x1B, 0x00, 0x22, 0x00, 0x57, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x1F,
+ 0x00, 0x22, 0x00, 0x49, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x3E,
+ 0x00, 0x57, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82,
+ 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00
+ }, items[1].Value);
+ Assert.Equal(PropertyTagLuminanceTable, items[2].Id);
+ Assert.Equal(128, items[2].Len);
+ Assert.Equal(PropertyTagTypeShort, items[2].Type);
+ Assert.Equal(new byte[]
+ {
+ 0x15, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x34, 0x00, 0x43, 0x00, 0x50, 0x00, 0x0F,
+ 0x00, 0x0F, 0x00, 0x12, 0x00, 0x19, 0x00, 0x22, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x48, 0x00, 0x12,
+ 0x00, 0x11, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x34, 0x00, 0x4B, 0x00, 0x5B, 0x00, 0x49, 0x00, 0x12,
+ 0x00, 0x16, 0x00, 0x1D, 0x00, 0x26, 0x00, 0x43, 0x00, 0x72, 0x00, 0x69, 0x00, 0x51, 0x00, 0x17,
+ 0x00, 0x1D, 0x00, 0x30, 0x00, 0x49, 0x00, 0x59, 0x00, 0x8F, 0x00, 0x87, 0x00, 0x65, 0x00, 0x1F,
+ 0x00, 0x2E, 0x00, 0x48, 0x00, 0x54, 0x00, 0x6A, 0x00, 0x89, 0x00, 0x95, 0x00, 0x79, 0x00, 0x40,
+ 0x00, 0x54, 0x00, 0x66, 0x00, 0x72, 0x00, 0x87, 0x00, 0x9F, 0x00, 0x9E, 0x00, 0x85, 0x00, 0x5F,
+ 0x00, 0x79, 0x00, 0x7D, 0x00, 0x81, 0x00, 0x93, 0x00, 0x84, 0x00, 0x87, 0x00, 0x82, 0x00,
+ }, items[2].Value);
+ Assert.Equal(propid, items[3].Id);
+ Assert.Equal(10, items[3].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[3].Type);
+ Assert.Equal("New Value\0", Encoding.ASCII.GetString(items[3].Value));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)]
+ [ConditionalTheory(Helpers.IsDrawingSupported)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(-1)]
+ public void SetPropertyItem_InvokeBitmapBmp_Success(int propid)
+ {
+ using var source = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg"));
+ using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("almogaver1bit.bmp"));
+
+ // Change data.
+ PropertyItem item = source.GetPropertyItem(PropertyTagExifUserComment);
+ item.Value = Encoding.ASCII.GetBytes("Hello World\0");
+ item.Len = item.Value.Length;
+
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment }, bitmap.PropertyIdList);
+ PropertyItem[] items = bitmap.PropertyItems;
+ Assert.Single(items);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+
+ // New data.
+ item.Id = propid;
+ item.Value = Encoding.ASCII.GetBytes("New Value\0");
+ item.Len = item.Value.Length;
+
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment, propid }, bitmap.PropertyIdList);
+ items = bitmap.PropertyItems;
+ Assert.Equal(2, items.Length);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+ Assert.Equal(propid, items[1].Id);
+ Assert.Equal(10, items[1].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[1].Type);
+ Assert.Equal("New Value\0", Encoding.ASCII.GetString(items[1].Value));
+
+ // Set same.
+ bitmap.SetPropertyItem(item);
+
+ Assert.Equal(new int[] { PropertyTagExifUserComment, propid }, bitmap.PropertyIdList);
+ items = bitmap.PropertyItems;
+ Assert.Equal(2, items.Length);
+ Assert.Equal(PropertyTagExifUserComment, items[0].Id);
+ Assert.Equal(12, items[0].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[0].Type);
+ Assert.Equal("Hello World\0", Encoding.ASCII.GetString(items[0].Value));
+ Assert.Equal(propid, items[1].Id);
+ Assert.Equal(10, items[1].Len);
+ Assert.Equal(PropertyTagTypeASCII, items[1].Type);
+ Assert.Equal("New Value\0", Encoding.ASCII.GetString(items[1].Value));
+ }
+
public static IEnumerable