mirror of https://github.com/SixLabors/ImageSharp
26 changed files with 746 additions and 36 deletions
@ -0,0 +1,26 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System.Diagnostics; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
[DebuggerDisplay("Name: {Name}, Type: {Type}, Length: {Length}")] |
||||
|
internal class ExrAttribute |
||||
|
{ |
||||
|
public static readonly ExrAttribute EmptyAttribute = new(string.Empty, string.Empty, 0); |
||||
|
|
||||
|
public ExrAttribute(string name, string type, int length) |
||||
|
{ |
||||
|
this.Name = name; |
||||
|
this.Type = type; |
||||
|
this.Length = length; |
||||
|
} |
||||
|
|
||||
|
public string Name { get; } |
||||
|
|
||||
|
public string Type { get; } |
||||
|
|
||||
|
public int Length { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
internal struct ExrBox2i |
||||
|
{ |
||||
|
public ExrBox2i(int xMin, int yMin, int xMax, int yMax) |
||||
|
{ |
||||
|
this.xMin = xMin; |
||||
|
this.yMin = yMin; |
||||
|
this.xMax = xMax; |
||||
|
this.yMax = yMax; |
||||
|
} |
||||
|
|
||||
|
public int xMin { get; } |
||||
|
|
||||
|
public int yMin { get; } |
||||
|
|
||||
|
public int xMax { get; } |
||||
|
|
||||
|
public int yMax { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)] |
||||
|
internal readonly struct ExrChannelInfo |
||||
|
{ |
||||
|
public ExrChannelInfo(string channelName, ExrPixelType pixelType, byte pLinear, int xSampling, int ySampling) |
||||
|
{ |
||||
|
this.ChannelName = channelName; |
||||
|
this.PixelType = pixelType; |
||||
|
this.PLinear = pLinear; |
||||
|
this.XSampling = xSampling; |
||||
|
this.YSampling = ySampling; |
||||
|
} |
||||
|
|
||||
|
public string ChannelName { get; } |
||||
|
|
||||
|
public ExrPixelType PixelType { get; } |
||||
|
|
||||
|
public byte PLinear { get; } |
||||
|
|
||||
|
public int XSampling { get; } |
||||
|
|
||||
|
public int YSampling { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
internal enum ExrCompression : int |
||||
|
{ |
||||
|
None = 0 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Registers the image encoders, decoders and mime type detectors for the OpenExr format.
|
||||
|
/// </summary>
|
||||
|
public sealed class ExrConfigurationModule : IConfigurationModule |
||||
|
{ |
||||
|
/// <inheritdoc/>
|
||||
|
public void Configure(Configuration configuration) |
||||
|
{ |
||||
|
configuration.ImageFormatsManager.SetDecoder(ExrFormat.Instance, new ExrDecoder()); |
||||
|
configuration.ImageFormatsManager.AddImageFormatDetector(new ExrImageFormatDetector()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Defines constants relating to OpenExr images.
|
||||
|
/// </summary>
|
||||
|
internal static class ExrConstants |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The list of mimetypes that equate to a OpenExr image.
|
||||
|
/// </summary>
|
||||
|
public static readonly IEnumerable<string> MimeTypes = new[] { "image/x-exr" }; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The list of file extensions that equate to a OpenExr image.
|
||||
|
/// </summary>
|
||||
|
public static readonly IEnumerable<string> FileExtensions = new[] { "exr" }; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The magick bytes identifying an OpenExr image.
|
||||
|
/// </summary>
|
||||
|
public static readonly int MagickBytes = 20000630; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,61 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System.IO; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Image decoder for generating an image out of a OpenExr stream.
|
||||
|
/// </summary>
|
||||
|
public sealed class ExrDecoder : IImageDecoder, IExrDecoderOptions, IImageInfoDetector |
||||
|
{ |
||||
|
/// <inheritdoc/>
|
||||
|
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) |
||||
|
where TPixel : unmanaged, IPixel<TPixel> |
||||
|
{ |
||||
|
Guard.NotNull(stream, nameof(stream)); |
||||
|
|
||||
|
var decoder = new ExrDecoderCore(configuration, this); |
||||
|
return decoder.Decode<TPixel>(configuration, stream); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Image Decode(Configuration configuration, Stream stream) |
||||
|
=> this.Decode<Rgba32>(configuration, stream); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken) |
||||
|
where TPixel : unmanaged, IPixel<TPixel> |
||||
|
{ |
||||
|
Guard.NotNull(stream, nameof(stream)); |
||||
|
|
||||
|
var decoder = new ExrDecoderCore(configuration, this); |
||||
|
return decoder.DecodeAsync<TPixel>(configuration, stream, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) |
||||
|
=> await this.DecodeAsync<Rgba32>(configuration, stream, cancellationToken) |
||||
|
.ConfigureAwait(false); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public IImageInfo Identify(Configuration configuration, Stream stream) |
||||
|
{ |
||||
|
Guard.NotNull(stream, nameof(stream)); |
||||
|
|
||||
|
return new ExrDecoderCore(configuration, this).Identify(configuration, stream); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) |
||||
|
{ |
||||
|
Guard.NotNull(stream, nameof(stream)); |
||||
|
|
||||
|
return new ExrDecoderCore(configuration, this).IdentifyAsync(configuration, stream, cancellationToken); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,256 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Buffers.Binary; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using SixLabors.ImageSharp.Formats.Pbm; |
||||
|
using SixLabors.ImageSharp.IO; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
using SixLabors.ImageSharp.Metadata; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Performs the OpenExr decoding operation.
|
||||
|
/// </summary>
|
||||
|
internal sealed class ExrDecoderCore : IImageDecoderInternals |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Reusable buffer.
|
||||
|
/// </summary>
|
||||
|
private readonly byte[] buffer = new byte[4]; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Used for allocating memory during processing operations.
|
||||
|
/// </summary>
|
||||
|
private readonly MemoryAllocator memoryAllocator; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The bitmap decoder options.
|
||||
|
/// </summary>
|
||||
|
private readonly IExrDecoderOptions options; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="ExrDecoderCore"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration">The configuration.</param>
|
||||
|
/// <param name="options">The options.</param>
|
||||
|
public ExrDecoderCore(Configuration configuration, IExrDecoderOptions options) |
||||
|
{ |
||||
|
this.Configuration = configuration; |
||||
|
this.memoryAllocator = configuration.MemoryAllocator; |
||||
|
this.options = options; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Configuration Configuration { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the dimensions of the image.
|
||||
|
/// </summary>
|
||||
|
public Size Dimensions => new(this.Width, this.Height); |
||||
|
|
||||
|
private int Width { get; set; } |
||||
|
|
||||
|
private int Height { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken) |
||||
|
where TPixel : unmanaged, IPixel<TPixel> => throw new NotImplementedException(); |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) |
||||
|
{ |
||||
|
// Skip over the magick bytes.
|
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
|
||||
|
// Read version number.
|
||||
|
byte version = (byte)stream.ReadByte(); |
||||
|
if (version != 2) |
||||
|
{ |
||||
|
ExrThrowHelper.ThrowNotSupportedVersion(); |
||||
|
} |
||||
|
|
||||
|
// Next three bytes contain info's about the image.
|
||||
|
// We ignore those for now.
|
||||
|
stream.Read(this.buffer, 0, 3); |
||||
|
|
||||
|
ExrHeader header = this.ParseHeader(stream); |
||||
|
|
||||
|
if (!header.IsValid()) |
||||
|
{ |
||||
|
ExrThrowHelper.ThrowInvalidImageHeader(); |
||||
|
} |
||||
|
|
||||
|
if (header.Channels.Count != 3) |
||||
|
{ |
||||
|
ExrThrowHelper.ThrowNotSupported("Only 3 channels are supported!"); |
||||
|
} |
||||
|
|
||||
|
this.Width = header.DataWindow.Value.xMax - header.DataWindow.Value.xMin + 1; |
||||
|
this.Height = header.DataWindow.Value.yMax - header.DataWindow.Value.yMin + 1; |
||||
|
|
||||
|
// TODO: calculate bits per pixel.
|
||||
|
int bitsPerPixel = 48; |
||||
|
|
||||
|
return new ImageInfo(new PixelTypeInfo(bitsPerPixel), this.Width, this.Height, new ImageMetadata()); |
||||
|
} |
||||
|
|
||||
|
private ExrHeader ParseHeader(BufferedReadStream stream) |
||||
|
{ |
||||
|
ExrAttribute attribute = this.ReadAttribute(stream); |
||||
|
var header = new ExrHeader(); |
||||
|
|
||||
|
while (!attribute.Equals(ExrAttribute.EmptyAttribute)) |
||||
|
{ |
||||
|
switch (attribute.Name) |
||||
|
{ |
||||
|
case "channels": |
||||
|
IList<ExrChannelInfo> channels = this.ParseChannelList(stream, attribute.Length); |
||||
|
header.Channels = channels; |
||||
|
break; |
||||
|
case "compression": |
||||
|
var compression = (ExrCompression)stream.ReadByte(); |
||||
|
header.Compression = compression; |
||||
|
break; |
||||
|
case "dataWindow": |
||||
|
ExrBox2i dataWindow = this.ReadBox2i(stream); |
||||
|
header.DataWindow = dataWindow; |
||||
|
break; |
||||
|
case "displayWindow": |
||||
|
ExrBox2i displayWindow = this.ReadBox2i(stream); |
||||
|
header.DisplayWindow = displayWindow; |
||||
|
break; |
||||
|
case "lineOrder": |
||||
|
var lineOrder = (ExrLineOrder)stream.ReadByte(); |
||||
|
header.LineOrder = lineOrder; |
||||
|
break; |
||||
|
case "pixelAspectRatio": |
||||
|
float aspectRatio = stream.ReadSingle(this.buffer); |
||||
|
header.AspectRatio = aspectRatio; |
||||
|
break; |
||||
|
case "screenWindowCenter": |
||||
|
float screenWindowCenterX = stream.ReadSingle(this.buffer); |
||||
|
float screenWindowCenterY = stream.ReadSingle(this.buffer); |
||||
|
header.ScreenWindowCenter = new PointF(screenWindowCenterX, screenWindowCenterY); |
||||
|
break; |
||||
|
case "screenWindowWidth": |
||||
|
float screenWindowWidth = stream.ReadSingle(this.buffer); |
||||
|
header.ScreenWindowWidth = screenWindowWidth; |
||||
|
break; |
||||
|
default: |
||||
|
// Skip unknown attribute bytes.
|
||||
|
stream.Skip(attribute.Length); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
attribute = this.ReadAttribute(stream); |
||||
|
} |
||||
|
|
||||
|
return header; |
||||
|
} |
||||
|
|
||||
|
private ExrAttribute ReadAttribute(BufferedReadStream stream) |
||||
|
{ |
||||
|
string attributeName = ReadString(stream); |
||||
|
if (attributeName.Equals(string.Empty)) |
||||
|
{ |
||||
|
return ExrAttribute.EmptyAttribute; |
||||
|
} |
||||
|
|
||||
|
string attributeType = ReadString(stream); |
||||
|
|
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
int attributeSize = BinaryPrimitives.ReadInt32LittleEndian(this.buffer); |
||||
|
|
||||
|
return new ExrAttribute(attributeName, attributeType, attributeSize); |
||||
|
} |
||||
|
|
||||
|
private ExrBox2i ReadBox2i(BufferedReadStream stream) |
||||
|
{ |
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
int xMin = BinaryPrimitives.ReadInt32LittleEndian(this.buffer); |
||||
|
|
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
int yMin = BinaryPrimitives.ReadInt32LittleEndian(this.buffer); |
||||
|
|
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
int xMax = BinaryPrimitives.ReadInt32LittleEndian(this.buffer); |
||||
|
|
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
int yMax = BinaryPrimitives.ReadInt32LittleEndian(this.buffer); |
||||
|
|
||||
|
return new ExrBox2i(xMin, yMin, xMax, yMax); |
||||
|
} |
||||
|
|
||||
|
private List<ExrChannelInfo> ParseChannelList(BufferedReadStream stream, int attributeSize) |
||||
|
{ |
||||
|
var channels = new List<ExrChannelInfo>(); |
||||
|
while (attributeSize > 1) |
||||
|
{ |
||||
|
ExrChannelInfo channelInfo = this.ReadChannelInfo(stream, out int bytesRead); |
||||
|
channels.Add(channelInfo); |
||||
|
attributeSize -= bytesRead; |
||||
|
} |
||||
|
|
||||
|
// Last byte should be a null byte.
|
||||
|
int byteRead = stream.ReadByte(); |
||||
|
|
||||
|
return channels; |
||||
|
} |
||||
|
|
||||
|
private ExrChannelInfo ReadChannelInfo(BufferedReadStream stream, out int bytesRead) |
||||
|
{ |
||||
|
string channelName = ReadString(stream); |
||||
|
bytesRead = channelName.Length + 1; |
||||
|
|
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
bytesRead += 4; |
||||
|
var pixelType = (ExrPixelType)BinaryPrimitives.ReadInt32LittleEndian(this.buffer); |
||||
|
|
||||
|
byte pLinear = (byte)stream.ReadByte(); |
||||
|
byte reserved0 = (byte)stream.ReadByte(); |
||||
|
byte reserved1 = (byte)stream.ReadByte(); |
||||
|
byte reserved2 = (byte)stream.ReadByte(); |
||||
|
bytesRead += 4; |
||||
|
|
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
bytesRead += 4; |
||||
|
int xSampling = BinaryPrimitives.ReadInt32LittleEndian(this.buffer); |
||||
|
|
||||
|
stream.Read(this.buffer, 0, 4); |
||||
|
bytesRead += 4; |
||||
|
int ySampling = BinaryPrimitives.ReadInt32LittleEndian(this.buffer); |
||||
|
|
||||
|
return new ExrChannelInfo(channelName, pixelType, pLinear, xSampling, ySampling); |
||||
|
} |
||||
|
|
||||
|
private static string ReadString(BufferedReadStream stream) |
||||
|
{ |
||||
|
var str = new StringBuilder(); |
||||
|
int character = stream.ReadByte(); |
||||
|
if (character == 0) |
||||
|
{ |
||||
|
// End of file header reached.
|
||||
|
return string.Empty; |
||||
|
} |
||||
|
|
||||
|
while (character != 0) |
||||
|
{ |
||||
|
if (character == -1) |
||||
|
{ |
||||
|
ExrThrowHelper.ThrowInvalidImageHeader(); |
||||
|
} |
||||
|
|
||||
|
str.Append((char)character); |
||||
|
character = stream.ReadByte(); |
||||
|
} |
||||
|
|
||||
|
return str.ToString(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using SixLabors.ImageSharp.Formats.Bmp; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Registers the image encoders, decoders and mime type detectors for the OpenExr format.
|
||||
|
/// </summary>
|
||||
|
public sealed class ExrFormat : IImageFormat<ExrMetadata> |
||||
|
{ |
||||
|
private ExrFormat() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the current instance.
|
||||
|
/// </summary>
|
||||
|
public static ExrFormat Instance { get; } = new(); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public string Name => "EXR"; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public string DefaultMimeType => "image/x-exr"; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public IEnumerable<string> MimeTypes => ExrConstants.MimeTypes; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public IEnumerable<string> FileExtensions => ExrConstants.FileExtensions; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public ExrMetadata CreateDefaultFormatMetadata() => new(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,71 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
internal class ExrHeader |
||||
|
{ |
||||
|
public IList<ExrChannelInfo> Channels { get; set; } |
||||
|
|
||||
|
public ExrCompression? Compression { get; set; } |
||||
|
|
||||
|
public ExrBox2i? DataWindow { get; set; } |
||||
|
|
||||
|
public ExrBox2i? DisplayWindow { get; set; } |
||||
|
|
||||
|
public ExrLineOrder? LineOrder { get; set; } |
||||
|
|
||||
|
public float? AspectRatio { get; set; } |
||||
|
|
||||
|
public float? ScreenWindowWidth { get; set; } |
||||
|
|
||||
|
public PointF? ScreenWindowCenter { get; set; } |
||||
|
|
||||
|
public bool IsValid() |
||||
|
{ |
||||
|
if (!this.Compression.HasValue) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!this.DataWindow.HasValue) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!this.DisplayWindow.HasValue) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!this.LineOrder.HasValue) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!this.AspectRatio.HasValue) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!this.ScreenWindowWidth.HasValue) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!this.ScreenWindowCenter.HasValue) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (this.Channels is null) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Buffers.Binary; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Detects OpenExr file headers.
|
||||
|
/// </summary>
|
||||
|
public sealed class ExrImageFormatDetector : IImageFormatDetector |
||||
|
{ |
||||
|
/// <inheritdoc/>
|
||||
|
public int HeaderSize => 4; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public IImageFormat DetectFormat(ReadOnlySpan<byte> header) => this.IsSupportedFileFormat(header) ? ExrFormat.Instance : null; |
||||
|
|
||||
|
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header) |
||||
|
{ |
||||
|
if (header.Length >= this.HeaderSize) |
||||
|
{ |
||||
|
int fileTypeMarker = BinaryPrimitives.ReadInt32LittleEndian(header); |
||||
|
return fileTypeMarker == ExrConstants.MagickBytes; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
internal enum ExrLineOrder : byte |
||||
|
{ |
||||
|
IncreasingY = 0, |
||||
|
|
||||
|
DecreasingY = 1, |
||||
|
|
||||
|
RandomY = 2 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Provides OpenExr specific metadata information for the image.
|
||||
|
/// </summary>
|
||||
|
public class ExrMetadata : IDeepCloneable |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="ExrMetadata"/> class.
|
||||
|
/// </summary>
|
||||
|
public ExrMetadata() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="ExrMetadata"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="other">The metadata to create an instance from.</param>
|
||||
|
private ExrMetadata(ExrMetadata other) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public IDeepCloneable DeepClone() => new ExrMetadata(this); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
internal enum ExrPixelType : int |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// unsigned int (32 bit).
|
||||
|
/// </summary>
|
||||
|
Uint = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// half (16 bit floating point).
|
||||
|
/// </summary>
|
||||
|
Half = 1, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// float (32 bit floating point).
|
||||
|
/// </summary>
|
||||
|
Float = 2 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Cold path optimizations for throwing exr format based exceptions.
|
||||
|
/// </summary>
|
||||
|
internal static class ExrThrowHelper |
||||
|
{ |
||||
|
[MethodImpl(InliningOptions.ColdPath)] |
||||
|
public static void ThrowNotSupportedVersion() => throw new NotSupportedException("Unsupported EXR version"); |
||||
|
|
||||
|
[MethodImpl(InliningOptions.ColdPath)] |
||||
|
public static void ThrowNotSupported(string msg) => throw new NotSupportedException(msg); |
||||
|
|
||||
|
[MethodImpl(InliningOptions.ColdPath)] |
||||
|
public static void ThrowInvalidImageHeader() => throw new InvalidImageContentException("Invalid EXR image header"); |
||||
|
|
||||
|
[MethodImpl(InliningOptions.ColdPath)] |
||||
|
public static void ThrowInvalidImageHeader(string msg) => throw new InvalidImageContentException(msg); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.OpenExr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Image decoder options for decoding OpenExr streams.
|
||||
|
/// </summary>
|
||||
|
internal interface IExrDecoderOptions |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
### Some useful links for documentation about the OpenEXR format: |
||||
|
|
||||
|
- [Technical Introduction](https://openexr.readthedocs.io/en/latest/TechnicalIntroduction.html) |
||||
|
- [OpenExr file layout](https://openexr.readthedocs.io/en/latest/OpenEXRFileLayout.html) |
||||
Loading…
Reference in new issue