Browse Source

Fix build errors

pull/3096/head
Brian Popow 4 years ago
parent
commit
ea1aaa79c4
  1. 10
      src/ImageSharp/Formats/OpenExr/Compression/Compressors/NoneExrCompression.cs
  2. 10
      src/ImageSharp/Formats/OpenExr/Compression/Compressors/RunLengthCompression.cs
  3. 12
      src/ImageSharp/Formats/OpenExr/Compression/Compressors/ZipExrCompression.cs
  4. 10
      src/ImageSharp/Formats/OpenExr/Compression/ExrBaseCompression.cs
  5. 10
      src/ImageSharp/Formats/OpenExr/Compression/ExrBaseDecompressor.cs
  6. 9
      src/ImageSharp/Formats/OpenExr/Compression/ExrCompressionType.cs
  7. 9
      src/ImageSharp/Formats/OpenExr/Compression/ExrDecompressorFactory.cs
  8. 12
      src/ImageSharp/Formats/OpenExr/ExrAttribute.cs
  9. 11
      src/ImageSharp/Formats/OpenExr/ExrBox2i.cs
  10. 13
      src/ImageSharp/Formats/OpenExr/ExrChannelInfo.cs
  11. 15
      src/ImageSharp/Formats/OpenExr/ExrConfigurationModule.cs
  12. 15
      src/ImageSharp/Formats/OpenExr/ExrConstants.cs
  13. 63
      src/ImageSharp/Formats/OpenExr/ExrDecoder.cs
  14. 36
      src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs
  15. 13
      src/ImageSharp/Formats/OpenExr/ExrDecoderOptions.cs
  16. 22
      src/ImageSharp/Formats/OpenExr/ExrEncoder.cs
  17. 19
      src/ImageSharp/Formats/OpenExr/ExrEncoderCore.cs
  18. 16
      src/ImageSharp/Formats/OpenExr/ExrFormat.cs
  19. 10
      src/ImageSharp/Formats/OpenExr/ExrHeaderAttributes.cs
  20. 9
      src/ImageSharp/Formats/OpenExr/ExrImageDataType.cs
  21. 16
      src/ImageSharp/Formats/OpenExr/ExrImageFormatDetector.cs
  22. 9
      src/ImageSharp/Formats/OpenExr/ExrImageType.cs
  23. 9
      src/ImageSharp/Formats/OpenExr/ExrLineOrder.cs
  24. 15
      src/ImageSharp/Formats/OpenExr/ExrMetadata.cs
  25. 15
      src/ImageSharp/Formats/OpenExr/ExrPixelType.cs
  26. 16
      src/ImageSharp/Formats/OpenExr/ExrThrowHelper.cs
  27. 12
      src/ImageSharp/Formats/OpenExr/IExrDecoderOptions.cs
  28. 15
      src/ImageSharp/Formats/OpenExr/IExrEncoderOptions.cs
  29. 15
      src/ImageSharp/Formats/OpenExr/MetadataExtensions.cs
  30. 26
      src/ImageSharp/IO/BufferedReadStream.cs
  31. 101
      tests/ImageSharp.Tests/Formats/Exr/ImageExtensionsTest.cs
  32. 5
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

10
src/ImageSharp/Formats/OpenExr/Compression/Compressors/NoneExrCompression.cs

@ -1,14 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors;
internal class NoneExrCompression : ExrBaseDecompressor
{ {
internal class NoneExrCompression : ExrBaseDecompressor
{
public NoneExrCompression(MemoryAllocator allocator, uint uncompressedBytes) public NoneExrCompression(MemoryAllocator allocator, uint uncompressedBytes)
: base(allocator, uncompressedBytes) : base(allocator, uncompressedBytes)
{ {
@ -20,5 +19,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
} }
}
} }

10
src/ImageSharp/Formats/OpenExr/Compression/Compressors/RunLengthCompression.cs

@ -1,15 +1,14 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using System.Buffers; using System.Buffers;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors;
internal class RunLengthCompression : ExrBaseDecompressor
{ {
internal class RunLengthCompression : ExrBaseDecompressor
{
private readonly IMemoryOwner<byte> tmpBuffer; private readonly IMemoryOwner<byte> tmpBuffer;
public RunLengthCompression(MemoryAllocator allocator, uint uncompressedBytes) public RunLengthCompression(MemoryAllocator allocator, uint uncompressedBytes)
@ -90,5 +89,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors
} }
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose();
}
} }

12
src/ImageSharp/Formats/OpenExr/Compression/Compressors/ZipExrCompression.cs

@ -1,17 +1,16 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using System.Buffers; using System.Buffers;
using System.IO.Compression; using System.IO.Compression;
using SixLabors.ImageSharp.Compression.Zlib; using SixLabors.ImageSharp.Compression.Zlib;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors;
internal class ZipExrCompression : ExrBaseDecompressor
{ {
internal class ZipExrCompression : ExrBaseDecompressor
{
private readonly IMemoryOwner<byte> tmpBuffer; private readonly IMemoryOwner<byte> tmpBuffer;
public ZipExrCompression(MemoryAllocator allocator, uint uncompressedBytes) public ZipExrCompression(MemoryAllocator allocator, uint uncompressedBytes)
@ -22,7 +21,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors
Span<byte> uncompressed = this.tmpBuffer.GetSpan(); Span<byte> uncompressed = this.tmpBuffer.GetSpan();
long pos = stream.Position; long pos = stream.Position;
using var deframeStream = new ZlibInflateStream( using ZlibInflateStream deframeStream = new(
stream, stream,
() => () =>
{ {
@ -54,5 +53,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors
} }
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose();
}
} }

10
src/ImageSharp/Formats/OpenExr/Compression/ExrBaseCompression.cs

@ -1,13 +1,12 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression namespace SixLabors.ImageSharp.Formats.OpenExr.Compression;
internal abstract class ExrBaseCompression : IDisposable
{ {
internal abstract class ExrBaseCompression : IDisposable
{
private bool isDisposed; private bool isDisposed;
protected ExrBaseCompression(MemoryAllocator allocator, uint bytePerRow) protected ExrBaseCompression(MemoryAllocator allocator, uint bytePerRow)
@ -39,5 +38,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr.Compression
} }
protected abstract void Dispose(bool disposing); protected abstract void Dispose(bool disposing);
}
} }

10
src/ImageSharp/Formats/OpenExr/Compression/ExrBaseDecompressor.cs

@ -1,14 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression namespace SixLabors.ImageSharp.Formats.OpenExr.Compression;
internal abstract class ExrBaseDecompressor : ExrBaseCompression
{ {
internal abstract class ExrBaseDecompressor : ExrBaseCompression
{
protected ExrBaseDecompressor(MemoryAllocator allocator, uint bytePerRow) protected ExrBaseDecompressor(MemoryAllocator allocator, uint bytePerRow)
: base(allocator, bytePerRow) : base(allocator, bytePerRow)
{ {
@ -38,5 +37,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr.Compression
output[sourceOffset++] = source[offset1++]; output[sourceOffset++] = source[offset1++];
} }
} }
}
} }

9
src/ImageSharp/Formats/OpenExr/Compression/ExrCompressionType.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression namespace SixLabors.ImageSharp.Formats.OpenExr.Compression;
internal enum ExrCompressionType
{ {
internal enum ExrCompressionType
{
/// <summary> /// <summary>
/// Pixel data is not compressed. /// Pixel data is not compressed.
/// </summary> /// </summary>
@ -57,5 +57,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr.Compression
/// Compression is lossy. /// Compression is lossy.
/// </summary> /// </summary>
B44A = 7 B44A = 7
}
} }

9
src/ImageSharp/Formats/OpenExr/Compression/ExrDecompressorFactory.cs

@ -1,13 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors; using SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression namespace SixLabors.ImageSharp.Formats.OpenExr.Compression;
internal static class ExrDecompressorFactory
{ {
internal static class ExrDecompressorFactory
{
public static ExrBaseDecompressor Create(ExrCompressionType method, MemoryAllocator memoryAllocator, uint uncompressedBytes) public static ExrBaseDecompressor Create(ExrCompressionType method, MemoryAllocator memoryAllocator, uint uncompressedBytes)
{ {
switch (method) switch (method)
@ -24,5 +24,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr.Compression
throw ExrThrowHelper.NotSupportedDecompressor(nameof(method)); throw ExrThrowHelper.NotSupportedDecompressor(nameof(method));
} }
} }
}
} }

12
src/ImageSharp/Formats/OpenExr/ExrAttribute.cs

@ -1,13 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License..
using System.Diagnostics; using System.Diagnostics;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
[DebuggerDisplay("Name: {Name}, Type: {Type}, Length: {Length}")]
internal class ExrAttribute
{ {
[DebuggerDisplay("Name: {Name}, Type: {Type}, Length: {Length}")]
internal class ExrAttribute
{
public static readonly ExrAttribute EmptyAttribute = new(string.Empty, string.Empty, 0); public static readonly ExrAttribute EmptyAttribute = new(string.Empty, string.Empty, 0);
public ExrAttribute(string name, string type, int length) public ExrAttribute(string name, string type, int length)
@ -22,5 +22,5 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
public string Type { get; } public string Type { get; }
public int Length { get; } public int Length { get; }
}
} }

11
src/ImageSharp/Formats/OpenExr/ExrBox2i.cs

@ -1,13 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System.Diagnostics; using System.Diagnostics;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
[DebuggerDisplay("xMin: {XMin}, yMin: {YMin}, xMax: {XMax}, yMax: {YMax}")]
internal struct ExrBox2i
{ {
[DebuggerDisplay("xMin: {XMin}, yMin: {YMin}, xMax: {XMax}, yMax: {YMax}")]
internal struct ExrBox2i
{
public ExrBox2i(int xMin, int yMin, int xMax, int yMax) public ExrBox2i(int xMin, int yMin, int xMax, int yMax)
{ {
this.XMin = xMin; this.XMin = xMin;
@ -23,5 +23,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
public int XMax { get; } public int XMax { get; }
public int YMax { get; } public int YMax { get; }
}
} }

13
src/ImageSharp/Formats/OpenExr/ExrChannelInfo.cs

@ -1,15 +1,15 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
[DebuggerDisplay("Name: {ChannelName}, PixelType: {PixelType}")]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct ExrChannelInfo
{ {
[DebuggerDisplay("Name: {ChannelName}, PixelType: {PixelType}")]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct ExrChannelInfo
{
public ExrChannelInfo(string channelName, ExrPixelType pixelType, byte pLinear, int xSampling, int ySampling) public ExrChannelInfo(string channelName, ExrPixelType pixelType, byte pLinear, int xSampling, int ySampling)
{ {
this.ChannelName = channelName; this.ChannelName = channelName;
@ -28,5 +28,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
public int XSampling { get; } public int XSampling { get; }
public int YSampling { get; } public int YSampling { get; }
}
} }

15
src/ImageSharp/Formats/OpenExr/ExrConfigurationModule.cs

@ -1,13 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr 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
{ {
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the OpenExr format.
/// </summary>
public sealed class ExrConfigurationModule : IConfigurationModule
{
/// <inheritdoc/> /// <inheritdoc/>
public void Configure(Configuration configuration) public void Configure(Configuration configuration)
{ {
@ -15,5 +15,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
configuration.ImageFormatsManager.SetDecoder(ExrFormat.Instance, new ExrDecoder()); configuration.ImageFormatsManager.SetDecoder(ExrFormat.Instance, new ExrDecoder());
configuration.ImageFormatsManager.AddImageFormatDetector(new ExrImageFormatDetector()); configuration.ImageFormatsManager.AddImageFormatDetector(new ExrImageFormatDetector());
} }
}
} }

15
src/ImageSharp/Formats/OpenExr/ExrConstants.cs

@ -1,15 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System.Collections.Generic; namespace SixLabors.ImageSharp.Formats.OpenExr;
namespace SixLabors.ImageSharp.Formats.OpenExr /// <summary>
/// Defines constants relating to OpenExr images.
/// </summary>
internal static class ExrConstants
{ {
/// <summary>
/// Defines constants relating to OpenExr images.
/// </summary>
internal static class ExrConstants
{
/// <summary> /// <summary>
/// The list of mimetypes that equate to a OpenExr image. /// The list of mimetypes that equate to a OpenExr image.
/// </summary> /// </summary>
@ -81,5 +79,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
public const string Luminance = "Y"; public const string Luminance = "Y";
} }
}
} }

63
src/ImageSharp/Formats/OpenExr/ExrDecoder.cs

@ -1,61 +1,46 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Image decoder for generating an image out of a OpenExr stream.
/// </summary>
public class ExrDecoder : IImageDecoderSpecialized<ExrDecoderOptions>
{ {
/// <summary>
/// Image decoder for generating an image out of a OpenExr stream.
/// </summary>
public sealed class ExrDecoder : IImageDecoder, IExrDecoderOptions, IImageInfoDetector
{
/// <inheritdoc/> /// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) IImageInfo IImageInfoDetector.Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{ {
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
var decoder = new ExrDecoderCore(configuration, this); return new ExrDecoderCore(new() { GeneralOptions = options }).Identify(options.Configuration, stream, cancellationToken);
return decoder.Decode<TPixel>(configuration, stream);
} }
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream)
=> this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc/> /// <inheritdoc/>
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken) Image<TPixel> IImageDecoder.Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> => ((IImageDecoderSpecialized<ExrDecoderOptions>)this).Decode<TPixel>(new() { GeneralOptions = options }, stream, cancellationToken);
{
Guard.NotNull(stream, nameof(stream));
var decoder = new ExrDecoderCore(configuration, this);
return decoder.DecodeAsync<TPixel>(configuration, stream, cancellationToken);
}
/// <inheritdoc /> /// <inheritdoc/>
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) Image IImageDecoder.Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> await this.DecodeAsync<Rgba32>(configuration, stream, cancellationToken) => ((IImageDecoderSpecialized<ExrDecoderOptions>)this).Decode(new() { GeneralOptions = options }, stream, cancellationToken);
.ConfigureAwait(false);
/// <inheritdoc/> /// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream) Image<TPixel> IImageDecoderSpecialized<ExrDecoderOptions>.Decode<TPixel>(ExrDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{ {
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
return new ExrDecoderCore(configuration, this).Identify(configuration, stream); Image<TPixel> image = new ExrDecoderCore(options).Decode<TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken);
}
/// <inheritdoc/> ImageDecoderUtilities.Resize(options.GeneralOptions, image);
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(stream, nameof(stream));
return new ExrDecoderCore(configuration, this).IdentifyAsync(configuration, stream, cancellationToken); return image;
}
} }
/// <inheritdoc/>
Image IImageDecoderSpecialized<ExrDecoderOptions>.Decode(ExrDecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> ((IImageDecoderSpecialized<ExrDecoderOptions>)this).Decode<Rgba32>(options, stream, cancellationToken);
} }

36
src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs

@ -1,27 +1,23 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using System.Buffers; using System.Buffers;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading;
using SixLabors.ImageSharp.Formats.OpenExr.Compression; using SixLabors.ImageSharp.Formats.OpenExr.Compression;
using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Performs the OpenExr decoding operation.
/// </summary>
internal sealed class ExrDecoderCore : IImageDecoderInternals
{ {
/// <summary>
/// Performs the OpenExr decoding operation.
/// </summary>
internal sealed class ExrDecoderCore : IImageDecoderInternals
{
/// <summary> /// <summary>
/// Reusable buffer. /// Reusable buffer.
/// </summary> /// </summary>
@ -33,9 +29,9 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
private readonly MemoryAllocator memoryAllocator; private readonly MemoryAllocator memoryAllocator;
/// <summary> /// <summary>
/// The bitmap decoder options. /// The global configuration.
/// </summary> /// </summary>
private readonly IExrDecoderOptions options; private readonly Configuration configuration;
/// <summary> /// <summary>
/// The metadata. /// The metadata.
@ -45,17 +41,16 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExrDecoderCore"/> class. /// Initializes a new instance of the <see cref="ExrDecoderCore"/> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
public ExrDecoderCore(Configuration configuration, IExrDecoderOptions options) public ExrDecoderCore(ExrDecoderOptions options)
{ {
this.Configuration = configuration; this.Options = options.GeneralOptions;
this.memoryAllocator = configuration.MemoryAllocator; this.configuration = options.GeneralOptions.Configuration;
this.options = options; this.memoryAllocator = this.configuration.MemoryAllocator;
} }
/// <inheritdoc /> /// <inheritdoc />
public Configuration Configuration { get; } public DecoderOptions Options { get; }
/// <summary> /// <summary>
/// Gets the dimensions of the image. /// Gets the dimensions of the image.
@ -85,7 +80,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
ExrPixelType pixelType = this.ValidateChannels(); ExrPixelType pixelType = this.ValidateChannels();
this.ReadImageDataType(); this.ReadImageDataType();
var image = new Image<TPixel>(this.Configuration, this.Width, this.Height, this.metadata); Image<TPixel> image = new Image<TPixel>(this.configuration, this.Width, this.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer(); Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
switch (pixelType) switch (pixelType)
@ -761,5 +756,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
return BinaryPrimitives.ReadInt32LittleEndian(this.buffer); return BinaryPrimitives.ReadInt32LittleEndian(this.buffer);
} }
}
} }

13
src/ImageSharp/Formats/OpenExr/ExrDecoderOptions.cs

@ -0,0 +1,13 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Image decoder options for decoding OpenExr streams.
/// </summary>
public sealed class ExrDecoderOptions : ISpecializedDecoderOptions
{
/// <inheritdoc/>
public DecoderOptions GeneralOptions { get; set; } = new();
}

22
src/ImageSharp/Formats/OpenExr/ExrEncoder.cs

@ -1,19 +1,16 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Image encoder for writing an image to a stream in the OpenExr Format.
/// </summary>
public sealed class ExrEncoder : IImageEncoder, IExrEncoderOptions
{ {
/// <summary>
/// Image encoder for writing an image to a stream in the OpenExr Format.
/// </summary>
public sealed class ExrEncoder : IImageEncoder, IExrEncoderOptions
{
/// <summary> /// <summary>
/// Gets or sets the pixel type of the image. /// Gets or sets the pixel type of the image.
/// </summary> /// </summary>
@ -23,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
public void Encode<TPixel>(Image<TPixel> image, Stream stream) public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
var encoder = new ExrEncoderCore(this, image.GetMemoryAllocator()); ExrEncoderCore encoder = new(this, image.GetMemoryAllocator());
encoder.Encode(image, stream); encoder.Encode(image, stream);
} }
@ -31,8 +28,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
var encoder = new ExrEncoderCore(this, image.GetMemoryAllocator()); ExrEncoderCore encoder = new(this, image.GetMemoryAllocator());
return encoder.EncodeAsync(image, stream, cancellationToken); return encoder.EncodeAsync(image, stream, cancellationToken);
} }
}
} }

19
src/ImageSharp/Formats/OpenExr/ExrEncoderCore.cs

@ -1,25 +1,21 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using System.Buffers; using System.Buffers;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading;
using SixLabors.ImageSharp.Formats.OpenExr.Compression; using SixLabors.ImageSharp.Formats.OpenExr.Compression;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Image encoder for writing an image to a stream in the OpenExr format.
/// </summary>
internal sealed class ExrEncoderCore : IImageEncoderInternals
{ {
/// <summary>
/// Image encoder for writing an image to a stream in the OpenExr format.
/// </summary>
internal sealed class ExrEncoderCore : IImageEncoderInternals
{
/// <summary> /// <summary>
/// Reusable buffer. /// Reusable buffer.
/// </summary> /// </summary>
@ -418,5 +414,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value); BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value);
stream.Write(this.buffer.AsSpan(0, 4)); stream.Write(this.buffer.AsSpan(0, 4));
} }
}
} }

16
src/ImageSharp/Formats/OpenExr/ExrFormat.cs

@ -1,16 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System.Collections.Generic; namespace SixLabors.ImageSharp.Formats.OpenExr;
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>
{ {
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the OpenExr format.
/// </summary>
public sealed class ExrFormat : IImageFormat<ExrMetadata>
{
private ExrFormat() private ExrFormat()
{ {
} }
@ -34,5 +31,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
/// <inheritdoc/> /// <inheritdoc/>
public ExrMetadata CreateDefaultFormatMetadata() => new(); public ExrMetadata CreateDefaultFormatMetadata() => new();
}
} }

10
src/ImageSharp/Formats/OpenExr/ExrHeaderAttributes.cs

@ -1,13 +1,12 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.OpenExr.Compression; using SixLabors.ImageSharp.Formats.OpenExr.Compression;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
internal class ExrHeaderAttributes
{ {
internal class ExrHeaderAttributes
{
public IList<ExrChannelInfo> Channels { get; set; } public IList<ExrChannelInfo> Channels { get; set; }
public ExrCompressionType? Compression { get; set; } public ExrCompressionType? Compression { get; set; }
@ -74,5 +73,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
return true; return true;
} }
}
} }

9
src/ImageSharp/Formats/OpenExr/ExrImageDataType.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
internal enum ExrImageDataType
{ {
internal enum ExrImageDataType
{
Unknown = 0, Unknown = 0,
Rgb = 1, Rgb = 1,
@ -12,5 +12,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
Rgba = 2, Rgba = 2,
Gray = 3, Gray = 3,
}
} }

16
src/ImageSharp/Formats/OpenExr/ExrImageFormatDetector.cs

@ -1,16 +1,15 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using System.Buffers.Binary; using System.Buffers.Binary;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Detects OpenExr file headers.
/// </summary>
public sealed class ExrImageFormatDetector : IImageFormatDetector
{ {
/// <summary>
/// Detects OpenExr file headers.
/// </summary>
public sealed class ExrImageFormatDetector : IImageFormatDetector
{
/// <inheritdoc/> /// <inheritdoc/>
public int HeaderSize => 4; public int HeaderSize => 4;
@ -27,5 +26,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
return false; return false;
} }
}
} }

9
src/ImageSharp/Formats/OpenExr/ExrImageType.cs

@ -1,12 +1,11 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
internal enum ExrImageType
{ {
internal enum ExrImageType
{
ScanLine = 0, ScanLine = 0,
Tiled = 1 Tiled = 1
}
} }

9
src/ImageSharp/Formats/OpenExr/ExrLineOrder.cs

@ -1,14 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
internal enum ExrLineOrder : byte
{ {
internal enum ExrLineOrder : byte
{
IncreasingY = 0, IncreasingY = 0,
DecreasingY = 1, DecreasingY = 1,
RandomY = 2 RandomY = 2
}
} }

15
src/ImageSharp/Formats/OpenExr/ExrMetadata.cs

@ -1,13 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Provides OpenExr specific metadata information for the image.
/// </summary>
public class ExrMetadata : IDeepCloneable
{ {
/// <summary>
/// Provides OpenExr specific metadata information for the image.
/// </summary>
public class ExrMetadata : IDeepCloneable
{
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExrMetadata"/> class. /// Initializes a new instance of the <see cref="ExrMetadata"/> class.
/// </summary> /// </summary>
@ -28,5 +28,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
/// <inheritdoc/> /// <inheritdoc/>
public IDeepCloneable DeepClone() => new ExrMetadata(this); public IDeepCloneable DeepClone() => new ExrMetadata(this);
}
} }

15
src/ImageSharp/Formats/OpenExr/ExrPixelType.cs

@ -1,13 +1,13 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// The different pixel formats for a OpenEXR image.
/// </summary>
public enum ExrPixelType
{ {
/// <summary>
/// The different pixel formats for a OpenEXR image.
/// </summary>
public enum ExrPixelType
{
/// <summary> /// <summary>
/// unsigned int (32 bit). /// unsigned int (32 bit).
/// </summary> /// </summary>
@ -22,5 +22,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
/// float (32 bit floating point). /// float (32 bit floating point).
/// </summary> /// </summary>
Float = 2 Float = 2
}
} }

16
src/ImageSharp/Formats/OpenExr/ExrThrowHelper.cs

@ -1,16 +1,15 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Cold path optimizations for throwing exr format based exceptions.
/// </summary>
internal static class ExrThrowHelper
{ {
/// <summary>
/// Cold path optimizations for throwing exr format based exceptions.
/// </summary>
internal static class ExrThrowHelper
{
[MethodImpl(InliningOptions.ColdPath)] [MethodImpl(InliningOptions.ColdPath)]
public static Exception NotSupportedDecompressor(string compressionType) => throw new NotSupportedException($"Not supported decoder compression method: {compressionType}"); public static Exception NotSupportedDecompressor(string compressionType) => throw new NotSupportedException($"Not supported decoder compression method: {compressionType}");
@ -28,5 +27,4 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
[MethodImpl(InliningOptions.ColdPath)] [MethodImpl(InliningOptions.ColdPath)]
public static void ThrowInvalidImageHeader(string msg) => throw new InvalidImageContentException(msg); public static void ThrowInvalidImageHeader(string msg) => throw new InvalidImageContentException(msg);
}
} }

12
src/ImageSharp/Formats/OpenExr/IExrDecoderOptions.cs

@ -1,12 +0,0 @@
// 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
{
}
}

15
src/ImageSharp/Formats/OpenExr/IExrEncoderOptions.cs

@ -1,16 +1,15 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.OpenExr namespace SixLabors.ImageSharp.Formats.OpenExr;
/// <summary>
/// Configuration options for use during OpenExr encoding.
/// </summary>
internal interface IExrEncoderOptions
{ {
/// <summary>
/// Configuration options for use during OpenExr encoding.
/// </summary>
internal interface IExrEncoderOptions
{
/// <summary> /// <summary>
/// Gets the pixel type of the image. /// Gets the pixel type of the image.
/// </summary> /// </summary>
ExrPixelType? PixelType { get; } ExrPixelType? PixelType { get; }
}
} }

15
src/ImageSharp/Formats/OpenExr/MetadataExtensions.cs

@ -1,21 +1,20 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.OpenExr; using SixLabors.ImageSharp.Formats.OpenExr;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp;
/// <summary>
/// Extension methods for the <see cref="ImageMetadata"/> type.
/// </summary>
public static partial class MetadataExtensions
{ {
/// <summary>
/// Extension methods for the <see cref="ImageMetadata"/> type.
/// </summary>
public static partial class MetadataExtensions
{
/// <summary> /// <summary>
/// Gets the open exr format specific metadata for the image. /// Gets the open exr format specific metadata for the image.
/// </summary> /// </summary>
/// <param name="metadata">The metadata this method extends.</param> /// <param name="metadata">The metadata this method extends.</param>
/// <returns>The <see cref="ExrMetadata"/>.</returns> /// <returns>The <see cref="ExrMetadata"/>.</returns>
public static ExrMetadata GetExrMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(ExrFormat.Instance); public static ExrMetadata GetExrMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(ExrFormat.Instance);
}
} }

26
src/ImageSharp/IO/BufferedReadStream.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Buffers; using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.IO; namespace SixLabors.ImageSharp.IO;
@ -153,6 +154,31 @@ internal sealed class BufferedReadStream : Stream
} }
} }
/// <summary>
/// Reads a float value.
/// </summary>
/// <returns>The value.</returns>
public float ReadSingle(byte[] data)
{
int offset = 0;
int bytesToRead = 4;
while (bytesToRead > 0)
{
int bytesRead = this.Read(data, offset, bytesToRead);
if (bytesRead == 0)
{
throw new ImageFormatException("Not enough data to read a float value from the stream");
}
bytesToRead -= bytesRead;
offset += bytesRead;
}
int intValue = BinaryPrimitives.ReadInt32BigEndian(data);
return Unsafe.As<int, float>(ref intValue);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)

101
tests/ImageSharp.Tests/Formats/Exr/ImageExtensionsTest.cs

@ -1,86 +1,15 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.OpenExr; using SixLabors.ImageSharp.Formats.OpenExr;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Exr namespace SixLabors.ImageSharp.Tests.Formats.Exr;
{
[Trait("Format", "Exr")]
public class ImageExtensionsTest
{
[Fact]
public void SaveAsExr_Path()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsExr_Path.exr");
using (var image = new Image<Rgba32>(10, 10))
{
image.SaveAsOpenExr(file);
}
using (Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/x-exr", mime.DefaultMimeType);
}
}
[Fact]
public async Task SaveAsExrAsync_Path()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsExrAsync_Path.exr");
using (var image = new Image<Rgba32>(10, 10))
{
await image.SaveAsOpenExrAsync(file);
}
using (Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/x-exr", mime.DefaultMimeType);
}
}
[Fact]
public void SaveAsExr_Path_Encoder()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsExr_Path_Encoder.exr");
using (var image = new Image<Rgba32>(10, 10))
{
image.SaveAsOpenExr(file, new ExrEncoder());
}
using (Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/x-exr", mime.DefaultMimeType);
}
}
[Fact]
public async Task SaveAsExrAsync_Path_Encoder()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsExrAsync_Path_Encoder.tiff");
using (var image = new Image<Rgba32>(10, 10))
{
await image.SaveAsOpenExrAsync(file, new ExrEncoder());
}
using (Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/x-exr", mime.DefaultMimeType);
}
}
[Trait("Format", "Exr")]
public class ImageExtensionsTest
{
[Fact] [Fact]
public void SaveAsExr_Stream() public void SaveAsExr_Stream()
{ {
@ -88,25 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Exr
using (var image = new Image<Rgba32>(10, 10)) using (var image = new Image<Rgba32>(10, 10))
{ {
image.SaveAsOpenExr(memoryStream); image.SaveAsOpenExr(memoryStream, new ExrEncoder());
}
memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime))
{
Assert.Equal("image/x-exr", mime.DefaultMimeType);
}
}
[Fact]
public async Task SaveAsExrAsync_StreamAsync()
{
using var memoryStream = new MemoryStream();
using (var image = new Image<Rgba32>(10, 10))
{
await image.SaveAsOpenExrAsync(memoryStream);
} }
memoryStream.Position = 0; memoryStream.Position = 0;
@ -152,5 +63,5 @@ namespace SixLabors.ImageSharp.Tests.Formats.Exr
Assert.Equal("image/x-exr", mime.DefaultMimeType); Assert.Equal("image/x-exr", mime.DefaultMimeType);
} }
} }
}
} }

5
tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

@ -144,11 +144,6 @@ public class GeneralFormatTests
{ {
image.SaveAsTiff(output); image.SaveAsTiff(output);
} }
using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.exr")))
{
image.SaveAsOpenExr(output);
}
} }
} }

Loading…
Cancel
Save