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 InvalidBytes_TestData() { // IconTests.Ctor_InvalidBytesInStream_TestData an array of 2 objects, but this test only uses the diff --git a/src/libraries/System.Drawing.Common/tests/Imaging/PropertyItemTests.cs b/src/libraries/System.Drawing.Common/tests/Imaging/PropertyItemTests.cs index 185a26be954f0..5dccc82bdfb70 100644 --- a/src/libraries/System.Drawing.Common/tests/Imaging/PropertyItemTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Imaging/PropertyItemTests.cs @@ -1,27 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// -// Copyright (C) 2005-2006 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.Collections.Generic; using Xunit; @@ -30,7 +8,64 @@ namespace System.Drawing.Imaging.Tests { public class PropertyItemTests { - private const string PngFile = "16x16_nonindexed_24bit.png"; + private const int PropertyTagLuminanceTable = 0x5090; + + [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] + [ConditionalTheory(Helpers.IsDrawingSupported)] + [InlineData(1)] + [InlineData(0)] + [InlineData(-1)] + public void Id_Set_GetReturnsExpected(int value) + { + using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg")); + PropertyItem item = bitmap.GetPropertyItem(PropertyTagLuminanceTable); + item.Id = value; + Assert.Equal(value, item.Id); + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] + [ConditionalTheory(Helpers.IsDrawingSupported)] + [InlineData(1)] + [InlineData(0)] + [InlineData(-1)] + public void Len_Set_GetReturnsExpected(int value) + { + using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg")); + PropertyItem item = bitmap.GetPropertyItem(PropertyTagLuminanceTable); + item.Len = value; + Assert.Equal(value, item.Len); + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] + [ConditionalTheory(Helpers.IsDrawingSupported)] + [InlineData(1)] + [InlineData(0)] + [InlineData(-1)] + public void Type_Set_GetReturnsExpected(short value) + { + using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg")); + PropertyItem item = bitmap.GetPropertyItem(PropertyTagLuminanceTable); + item.Type = value; + Assert.Equal(value, item.Type); + } + + public static IEnumerable Value_Set_TestData() + { + yield return new object[] { null }; + yield return new object[] { Array.Empty() }; + yield return new object[] { new byte[] { 1, 2, 3 } }; + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] + [ConditionalTheory(Helpers.IsDrawingSupported)] + [MemberData(nameof(Value_Set_TestData))] + public void Value_Set_GetReturnsExpected(byte[] value) + { + using var bitmap = new Bitmap(Helpers.GetTestBitmapPath("nature24bits.jpg")); + PropertyItem item = bitmap.GetPropertyItem(PropertyTagLuminanceTable); + item.Value = value; + Assert.Same(value, item.Value); + } public static IEnumerable Properties_TestData() { @@ -40,31 +75,29 @@ public static IEnumerable Properties_TestData() } [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/34592", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [ConditionalTheory(Helpers.IsDrawingSupported)] [MemberData(nameof(Properties_TestData))] public void Properties_SetValues_ReturnsExpected(int id, int len, short type, byte[] value) { - using (Image image = new Bitmap(Helpers.GetTestBitmapPath(PngFile))) - using (Image clone = (Image)image.Clone()) - { - PropertyItem[] propItems = clone.PropertyItems; - PropertyItem propItem = propItems[0]; - Assert.Equal(771, propItem.Id); - Assert.Equal(1, propItem.Len); - Assert.Equal(1, propItem.Type); - Assert.Equal(new byte[1] { 0 }, propItem.Value); + using var image = new Bitmap(Helpers.GetTestBitmapPath("16x16_nonindexed_24bit.png")); + using Image clone = (Image)image.Clone(); + + PropertyItem[] propItems = clone.PropertyItems; + PropertyItem propItem = propItems[0]; + Assert.Equal(771, propItem.Id); + Assert.Equal(1, propItem.Len); + Assert.Equal(1, propItem.Type); + Assert.Equal(new byte[1] { 0 }, propItem.Value); - propItem.Id = id; - propItem.Len = len; - propItem.Type = type; - propItem.Value = value; + propItem.Id = id; + propItem.Len = len; + propItem.Type = type; + propItem.Value = value; - Assert.Equal(id, propItem.Id); - Assert.Equal(len, propItem.Len); - Assert.Equal(type, propItem.Type); - Assert.Equal(value, propItem.Value); - } + Assert.Equal(id, propItem.Id); + Assert.Equal(len, propItem.Len); + Assert.Equal(type, propItem.Type); + Assert.Equal(value, propItem.Value); } } }