mirror of https://github.com/SixLabors/ImageSharp
22 changed files with 1034 additions and 139 deletions
@ -1,16 +1,183 @@ |
|||||
// Copyright (c) Six Labors.
|
// Copyright (c) Six Labors.
|
||||
// Licensed under the Six Labors Split License.
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.Formats.Bmp; |
||||
|
using SixLabors.ImageSharp.Formats.Icon; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.Cur; |
namespace SixLabors.ImageSharp.Formats.Cur; |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// Provides Ico specific metadata information for the image.
|
/// Provides Cur specific metadata information for the image.
|
||||
/// </summary>
|
/// </summary>
|
||||
public class CurMetadata : IDeepCloneable<CurMetadata>, IDeepCloneable |
public class CurMetadata : IFormatMetadata<CurMetadata> |
||||
{ |
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="CurMetadata"/> class.
|
||||
|
/// </summary>
|
||||
|
public CurMetadata() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
private CurMetadata(CurMetadata other) |
||||
|
{ |
||||
|
this.Compression = other.Compression; |
||||
|
this.HotspotX = other.HotspotX; |
||||
|
this.HotspotY = other.HotspotY; |
||||
|
this.EncodingWidth = other.EncodingWidth; |
||||
|
this.EncodingHeight = other.EncodingHeight; |
||||
|
this.BmpBitsPerPixel = other.BmpBitsPerPixel; |
||||
|
|
||||
|
if (other.ColorTable?.Length > 0) |
||||
|
{ |
||||
|
this.ColorTable = other.ColorTable.Value.ToArray(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the frame compressions format. Derived from the root frame.
|
||||
|
/// </summary>
|
||||
|
public IconFrameCompression Compression { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the horizontal coordinates of the hotspot in number of pixels from the left. Derived from the root frame.
|
||||
|
/// </summary>
|
||||
|
public ushort HotspotX { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the vertical coordinates of the hotspot in number of pixels from the top. Derived from the root frame.
|
||||
|
/// </summary>
|
||||
|
public ushort HotspotY { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the encoding width. <br />
|
||||
|
/// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame.
|
||||
|
/// </summary>
|
||||
|
public byte EncodingWidth { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the encoding height. <br />
|
||||
|
/// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame.
|
||||
|
/// </summary>
|
||||
|
public byte EncodingHeight { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the number of bits per pixel.<br/>
|
||||
|
/// Used when <see cref="Compression"/> is <see cref="IconFrameCompression.Bmp"/>
|
||||
|
/// </summary>
|
||||
|
public BmpBitsPerPixel BmpBitsPerPixel { get; set; } = BmpBitsPerPixel.Bit32; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the color table, if any. Derived from the root frame.<br/>
|
||||
|
/// The underlying pixel format is represented by <see cref="Bgr24"/>.
|
||||
|
/// </summary>
|
||||
|
public ReadOnlyMemory<Color>? ColorTable { get; set; } |
||||
|
|
||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||
public CurMetadata DeepClone() => new(); |
public static CurMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) |
||||
|
{ |
||||
|
int bpp = metadata.PixelTypeInfo.BitsPerPixel; |
||||
|
BmpBitsPerPixel bbpp = bpp switch |
||||
|
{ |
||||
|
1 => BmpBitsPerPixel.Bit1, |
||||
|
2 => BmpBitsPerPixel.Bit2, |
||||
|
<= 4 => BmpBitsPerPixel.Bit4, |
||||
|
<= 8 => BmpBitsPerPixel.Bit8, |
||||
|
<= 16 => BmpBitsPerPixel.Bit16, |
||||
|
<= 24 => BmpBitsPerPixel.Bit24, |
||||
|
_ => BmpBitsPerPixel.Bit32 |
||||
|
}; |
||||
|
|
||||
|
IconFrameCompression compression = IconFrameCompression.Bmp; |
||||
|
if (bbpp is BmpBitsPerPixel.Bit32) |
||||
|
{ |
||||
|
compression = IconFrameCompression.Png; |
||||
|
} |
||||
|
|
||||
|
return new CurMetadata |
||||
|
{ |
||||
|
BmpBitsPerPixel = bbpp, |
||||
|
Compression = compression, |
||||
|
ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public PixelTypeInfo GetPixelTypeInfo() |
||||
|
{ |
||||
|
int bpp = (int)this.BmpBitsPerPixel; |
||||
|
PixelComponentInfo info; |
||||
|
PixelColorType color; |
||||
|
PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; |
||||
|
|
||||
|
if (this.Compression is IconFrameCompression.Png) |
||||
|
{ |
||||
|
bpp = 32; |
||||
|
info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); |
||||
|
color = PixelColorType.RGB | PixelColorType.Alpha; |
||||
|
alpha = PixelAlphaRepresentation.Unassociated; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
switch (this.BmpBitsPerPixel) |
||||
|
{ |
||||
|
case BmpBitsPerPixel.Bit1: |
||||
|
info = PixelComponentInfo.Create(1, bpp, 1); |
||||
|
color = PixelColorType.Binary; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit2: |
||||
|
info = PixelComponentInfo.Create(1, bpp, 2); |
||||
|
color = PixelColorType.Indexed; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit4: |
||||
|
info = PixelComponentInfo.Create(1, bpp, 4); |
||||
|
color = PixelColorType.Indexed; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit8: |
||||
|
info = PixelComponentInfo.Create(1, bpp, 8); |
||||
|
color = PixelColorType.Indexed; |
||||
|
break; |
||||
|
|
||||
|
// Could be 555 with padding but 565 is more common in newer bitmaps and offers
|
||||
|
// greater accuracy due to extra green precision.
|
||||
|
case BmpBitsPerPixel.Bit16: |
||||
|
info = PixelComponentInfo.Create(3, bpp, 5, 6, 5); |
||||
|
color = PixelColorType.RGB; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit24: |
||||
|
info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); |
||||
|
color = PixelColorType.RGB; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit32 or _: |
||||
|
info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); |
||||
|
color = PixelColorType.RGB | PixelColorType.Alpha; |
||||
|
alpha = PixelAlphaRepresentation.Unassociated; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return new PixelTypeInfo(bpp) |
||||
|
{ |
||||
|
AlphaRepresentation = alpha, |
||||
|
ComponentInfo = info, |
||||
|
ColorType = color |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public FormatConnectingMetadata ToFormatConnectingMetadata() |
||||
|
=> new() |
||||
|
{ |
||||
|
EncodingType = this.Compression == IconFrameCompression.Bmp && this.BmpBitsPerPixel <= BmpBitsPerPixel.Bit8 |
||||
|
? EncodingType.Lossy |
||||
|
: EncodingType.Lossless, |
||||
|
PixelTypeInfo = this.GetPixelTypeInfo(), |
||||
|
ColorTable = this.ColorTable |
||||
|
}; |
||||
|
|
||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); |
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public CurMetadata DeepClone() => new(this); |
||||
} |
} |
||||
|
|||||
@ -1,45 +0,0 @@ |
|||||
// Copyright (c) Six Labors.
|
|
||||
// Licensed under the Six Labors Split License.
|
|
||||
|
|
||||
using System.Diagnostics.CodeAnalysis; |
|
||||
using SixLabors.ImageSharp.Formats.Cur; |
|
||||
using SixLabors.ImageSharp.Metadata; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="ImageMetadata"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class MetadataExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the Icon format specific metadata for the image.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The metadata this method extends.</param>
|
|
||||
/// <returns>The <see cref="CurMetadata"/>.</returns>
|
|
||||
public static CurMetadata GetCurMetadata(this ImageMetadata source) |
|
||||
=> source.GetFormatMetadata(CurFormat.Instance); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Icon format specific metadata for the image frame.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The metadata this method extends.</param>
|
|
||||
/// <returns>The <see cref="CurFrameMetadata"/>.</returns>
|
|
||||
public static CurFrameMetadata GetCurMetadata(this ImageFrameMetadata source) |
|
||||
=> source.GetFormatMetadata(CurFormat.Instance); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Icon format specific metadata for the image frame.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The metadata this method extends.</param>
|
|
||||
/// <param name="metadata">
|
|
||||
/// When this method returns, contains the metadata associated with the specified frame,
|
|
||||
/// if found; otherwise, the default value for the type of the metadata parameter.
|
|
||||
/// This parameter is passed uninitialized.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// <see langword="true"/> if the Icon frame metadata exists; otherwise, <see langword="false"/>.
|
|
||||
/// </returns>
|
|
||||
public static bool TryGetCurMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out CurFrameMetadata? metadata) |
|
||||
=> source.TryGetFormatMetadata(CurFormat.Instance, out metadata); |
|
||||
} |
|
||||
@ -1,16 +1,171 @@ |
|||||
// Copyright (c) Six Labors.
|
// Copyright (c) Six Labors.
|
||||
// Licensed under the Six Labors Split License.
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.Formats.Bmp; |
||||
|
using SixLabors.ImageSharp.Formats.Icon; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.Ico; |
namespace SixLabors.ImageSharp.Formats.Ico; |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// Provides Ico specific metadata information for the image.
|
/// Provides Ico specific metadata information for the image.
|
||||
/// </summary>
|
/// </summary>
|
||||
public class IcoMetadata : IDeepCloneable<IcoMetadata>, IDeepCloneable |
public class IcoMetadata : IFormatMetadata<IcoMetadata> |
||||
{ |
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="IcoMetadata"/> class.
|
||||
|
/// </summary>
|
||||
|
public IcoMetadata() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
private IcoMetadata(IcoMetadata other) |
||||
|
{ |
||||
|
this.Compression = other.Compression; |
||||
|
this.EncodingWidth = other.EncodingWidth; |
||||
|
this.EncodingHeight = other.EncodingHeight; |
||||
|
this.BmpBitsPerPixel = other.BmpBitsPerPixel; |
||||
|
|
||||
|
if (other.ColorTable?.Length > 0) |
||||
|
{ |
||||
|
this.ColorTable = other.ColorTable.Value.ToArray(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the frame compressions format. Derived from the root frame.
|
||||
|
/// </summary>
|
||||
|
public IconFrameCompression Compression { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the encoding width. <br />
|
||||
|
/// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame.
|
||||
|
/// </summary>
|
||||
|
public byte EncodingWidth { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the encoding height. <br />
|
||||
|
/// Can be any number between 0 and 255. Value 0 means a frame height of 256 pixels or greater. Derived from the root frame.
|
||||
|
/// </summary>
|
||||
|
public byte EncodingHeight { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the number of bits per pixel.<br/>
|
||||
|
/// Used when <see cref="Compression"/> is <see cref="IconFrameCompression.Bmp"/>
|
||||
|
/// </summary>
|
||||
|
public BmpBitsPerPixel BmpBitsPerPixel { get; set; } = BmpBitsPerPixel.Bit32; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the color table, if any. Derived from the root frame.<br/>
|
||||
|
/// The underlying pixel format is represented by <see cref="Bgr24"/>.
|
||||
|
/// </summary>
|
||||
|
public ReadOnlyMemory<Color>? ColorTable { get; set; } |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public static IcoMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata) |
||||
|
{ |
||||
|
int bpp = metadata.PixelTypeInfo.BitsPerPixel; |
||||
|
BmpBitsPerPixel bbpp = bpp switch |
||||
|
{ |
||||
|
1 => BmpBitsPerPixel.Bit1, |
||||
|
2 => BmpBitsPerPixel.Bit2, |
||||
|
<= 4 => BmpBitsPerPixel.Bit4, |
||||
|
<= 8 => BmpBitsPerPixel.Bit8, |
||||
|
<= 16 => BmpBitsPerPixel.Bit16, |
||||
|
<= 24 => BmpBitsPerPixel.Bit24, |
||||
|
_ => BmpBitsPerPixel.Bit32 |
||||
|
}; |
||||
|
|
||||
|
IconFrameCompression compression = IconFrameCompression.Bmp; |
||||
|
if (bbpp is BmpBitsPerPixel.Bit32) |
||||
|
{ |
||||
|
compression = IconFrameCompression.Png; |
||||
|
} |
||||
|
|
||||
|
return new IcoMetadata |
||||
|
{ |
||||
|
BmpBitsPerPixel = bbpp, |
||||
|
Compression = compression, |
||||
|
ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public PixelTypeInfo GetPixelTypeInfo() |
||||
|
{ |
||||
|
int bpp = (int)this.BmpBitsPerPixel; |
||||
|
PixelComponentInfo info; |
||||
|
PixelColorType color; |
||||
|
PixelAlphaRepresentation alpha = PixelAlphaRepresentation.None; |
||||
|
|
||||
|
if (this.Compression is IconFrameCompression.Png) |
||||
|
{ |
||||
|
bpp = 32; |
||||
|
info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); |
||||
|
color = PixelColorType.RGB | PixelColorType.Alpha; |
||||
|
alpha = PixelAlphaRepresentation.Unassociated; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
switch (this.BmpBitsPerPixel) |
||||
|
{ |
||||
|
case BmpBitsPerPixel.Bit1: |
||||
|
info = PixelComponentInfo.Create(1, bpp, 1); |
||||
|
color = PixelColorType.Binary; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit2: |
||||
|
info = PixelComponentInfo.Create(1, bpp, 2); |
||||
|
color = PixelColorType.Indexed; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit4: |
||||
|
info = PixelComponentInfo.Create(1, bpp, 4); |
||||
|
color = PixelColorType.Indexed; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit8: |
||||
|
info = PixelComponentInfo.Create(1, bpp, 8); |
||||
|
color = PixelColorType.Indexed; |
||||
|
break; |
||||
|
|
||||
|
// Could be 555 with padding but 565 is more common in newer bitmaps and offers
|
||||
|
// greater accuracy due to extra green precision.
|
||||
|
case BmpBitsPerPixel.Bit16: |
||||
|
info = PixelComponentInfo.Create(3, bpp, 5, 6, 5); |
||||
|
color = PixelColorType.RGB; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit24: |
||||
|
info = PixelComponentInfo.Create(3, bpp, 8, 8, 8); |
||||
|
color = PixelColorType.RGB; |
||||
|
break; |
||||
|
case BmpBitsPerPixel.Bit32 or _: |
||||
|
info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8); |
||||
|
color = PixelColorType.RGB | PixelColorType.Alpha; |
||||
|
alpha = PixelAlphaRepresentation.Unassociated; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return new PixelTypeInfo(bpp) |
||||
|
{ |
||||
|
AlphaRepresentation = alpha, |
||||
|
ComponentInfo = info, |
||||
|
ColorType = color |
||||
|
}; |
||||
|
} |
||||
|
|
||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||
public IcoMetadata DeepClone() => new(); |
public FormatConnectingMetadata ToFormatConnectingMetadata() |
||||
|
=> new() |
||||
|
{ |
||||
|
EncodingType = this.Compression == IconFrameCompression.Bmp && this.BmpBitsPerPixel <= BmpBitsPerPixel.Bit8 |
||||
|
? EncodingType.Lossy |
||||
|
: EncodingType.Lossless, |
||||
|
PixelTypeInfo = this.GetPixelTypeInfo(), |
||||
|
ColorTable = this.ColorTable |
||||
|
}; |
||||
|
|
||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); |
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public IcoMetadata DeepClone() => new(this); |
||||
} |
} |
||||
|
|||||
@ -1,45 +0,0 @@ |
|||||
// Copyright (c) Six Labors.
|
|
||||
// Licensed under the Six Labors Split License.
|
|
||||
|
|
||||
using System.Diagnostics.CodeAnalysis; |
|
||||
using SixLabors.ImageSharp.Formats.Ico; |
|
||||
using SixLabors.ImageSharp.Metadata; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Extension methods for the <see cref="ImageMetadata"/> type.
|
|
||||
/// </summary>
|
|
||||
public static partial class MetadataExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the Ico format specific metadata for the image.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The metadata this method extends.</param>
|
|
||||
/// <returns>The <see cref="IcoMetadata"/>.</returns>
|
|
||||
public static IcoMetadata GetIcoMetadata(this ImageMetadata source) |
|
||||
=> source.GetFormatMetadata(IcoFormat.Instance); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Ico format specific metadata for the image frame.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The metadata this method extends.</param>
|
|
||||
/// <returns>The <see cref="IcoFrameMetadata"/>.</returns>
|
|
||||
public static IcoFrameMetadata GetIcoMetadata(this ImageFrameMetadata source) |
|
||||
=> source.GetFormatMetadata(IcoFormat.Instance); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the Ico format specific metadata for the image frame.
|
|
||||
/// </summary>
|
|
||||
/// <param name="source">The metadata this method extends.</param>
|
|
||||
/// <param name="metadata">
|
|
||||
/// When this method returns, contains the metadata associated with the specified frame,
|
|
||||
/// if found; otherwise, the default value for the type of the metadata parameter.
|
|
||||
/// This parameter is passed uninitialized.
|
|
||||
/// </param>
|
|
||||
/// <returns>
|
|
||||
/// <see langword="true"/> if the Ico frame metadata exists; otherwise, <see langword="false"/>.
|
|
||||
/// </returns>
|
|
||||
public static bool TryGetIcoMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out IcoFrameMetadata? metadata) |
|
||||
=> source.TryGetFormatMetadata(IcoFormat.Instance, out metadata); |
|
||||
} |
|
||||
Loading…
Reference in new issue