mirror of https://github.com/SixLabors/ImageSharp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
7.3 KiB
251 lines
7.3 KiB
// Copyright (c) Six Labors and contributors.
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
|
|
{
|
|
/// <summary>
|
|
/// Provides methods to write ICC data types
|
|
/// </summary>
|
|
internal sealed partial class IccDataWriter : IDisposable
|
|
{
|
|
private static readonly bool IsLittleEndian = BitConverter.IsLittleEndian;
|
|
private static readonly Encoding AsciiEncoding = Encoding.ASCII;
|
|
|
|
/// <summary>
|
|
/// The underlying stream where the data is written to
|
|
/// </summary>
|
|
private readonly MemoryStream dataStream;
|
|
|
|
/// <summary>
|
|
/// To detect redundant calls
|
|
/// </summary>
|
|
private bool isDisposed;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="IccDataWriter"/> class.
|
|
/// </summary>
|
|
public IccDataWriter()
|
|
{
|
|
this.dataStream = new MemoryStream();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the currently written length in bytes
|
|
/// </summary>
|
|
public uint Length => (uint)this.dataStream.Length;
|
|
|
|
/// <summary>
|
|
/// Gets the written data bytes
|
|
/// </summary>
|
|
/// <returns>The written data</returns>
|
|
public byte[] GetData()
|
|
{
|
|
return this.dataStream.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the writing position to the given value
|
|
/// </summary>
|
|
/// <param name="index">The new index position</param>
|
|
public void SetIndex(int index)
|
|
{
|
|
this.dataStream.Position = index;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a byte array
|
|
/// </summary>
|
|
/// <param name="data">The array to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
public int WriteArray(byte[] data)
|
|
{
|
|
this.dataStream.Write(data, 0, data.Length);
|
|
return data.Length;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a ushort array
|
|
/// </summary>
|
|
/// <param name="data">The array to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
public int WriteArray(ushort[] data)
|
|
{
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
this.WriteUInt16(data[i]);
|
|
}
|
|
|
|
return data.Length * 2;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a short array
|
|
/// </summary>
|
|
/// <param name="data">The array to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
public int WriteArray(short[] data)
|
|
{
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
this.WriteInt16(data[i]);
|
|
}
|
|
|
|
return data.Length * 2;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a uint array
|
|
/// </summary>
|
|
/// <param name="data">The array to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
public int WriteArray(uint[] data)
|
|
{
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
this.WriteUInt32(data[i]);
|
|
}
|
|
|
|
return data.Length * 4;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes an int array
|
|
/// </summary>
|
|
/// <param name="data">The array to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
public int WriteArray(int[] data)
|
|
{
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
this.WriteInt32(data[i]);
|
|
}
|
|
|
|
return data.Length * 4;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a ulong array
|
|
/// </summary>
|
|
/// <param name="data">The array to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
public int WriteArray(ulong[] data)
|
|
{
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
this.WriteUInt64(data[i]);
|
|
}
|
|
|
|
return data.Length * 8;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write a number of empty bytes
|
|
/// </summary>
|
|
/// <param name="length">The number of bytes to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
public int WriteEmpty(int length)
|
|
{
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
this.dataStream.WriteByte(0);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes empty bytes to a 4-byte margin
|
|
/// </summary>
|
|
/// <returns>The number of bytes written</returns>
|
|
public int WritePadding()
|
|
{
|
|
int p = 4 - ((int)this.dataStream.Position % 4);
|
|
return this.WriteEmpty(p >= 4 ? 0 : p);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public void Dispose()
|
|
{
|
|
this.Dispose(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes given bytes from pointer
|
|
/// </summary>
|
|
/// <param name="data">Pointer to the bytes to write</param>
|
|
/// <param name="length">The number of bytes to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
private unsafe int WriteBytes(byte* data, int length)
|
|
{
|
|
if (IsLittleEndian)
|
|
{
|
|
for (int i = length - 1; i >= 0; i--)
|
|
{
|
|
this.dataStream.WriteByte(data[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.WriteBytesDirect(data, length);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes given bytes from pointer ignoring endianness
|
|
/// </summary>
|
|
/// <param name="data">Pointer to the bytes to write</param>
|
|
/// <param name="length">The number of bytes to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
private unsafe int WriteBytesDirect(byte* data, int length)
|
|
{
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
this.dataStream.WriteByte(data[i]);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes curve data
|
|
/// </summary>
|
|
/// <param name="curves">The curves to write</param>
|
|
/// <returns>The number of bytes written</returns>
|
|
private int WriteCurves(IccTagDataEntry[] curves)
|
|
{
|
|
int count = 0;
|
|
foreach (IccTagDataEntry curve in curves)
|
|
{
|
|
if (curve.Signature != IccTypeSignature.Curve && curve.Signature != IccTypeSignature.ParametricCurve)
|
|
{
|
|
throw new InvalidIccProfileException($"Curve has to be either \"{nameof(IccTypeSignature)}.{nameof(IccTypeSignature.Curve)}\" or" +
|
|
$" \"{nameof(IccTypeSignature)}.{nameof(IccTypeSignature.ParametricCurve)}\" for LutAToB- and LutBToA-TagDataEntries");
|
|
}
|
|
|
|
count += this.WriteTagDataEntry(curve);
|
|
count += this.WritePadding();
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
private void Dispose(bool disposing)
|
|
{
|
|
if (!this.isDisposed)
|
|
{
|
|
if (disposing)
|
|
{
|
|
this.dataStream?.Dispose();
|
|
}
|
|
|
|
this.isDisposed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|