📷 A modern, cross-platform, 2D Graphics library for .NET
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.
 
 

171 lines
6.0 KiB

// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Metadata.Profiles.Icc
{
/// <summary>
/// Provides methods to read ICC data types
/// </summary>
internal sealed partial class IccDataReader
{
/// <summary>
/// Reads an 8bit lookup table
/// </summary>
/// <returns>The read LUT</returns>
public IccLut ReadLut8()
{
return new IccLut(this.ReadBytes(256));
}
/// <summary>
/// Reads a 16bit lookup table
/// </summary>
/// <param name="count">The number of entries</param>
/// <returns>The read LUT</returns>
public IccLut ReadLut16(int count)
{
var values = new ushort[count];
for (int i = 0; i < count; i++)
{
values[i] = this.ReadUInt16();
}
return new IccLut(values);
}
/// <summary>
/// Reads a CLUT depending on type
/// </summary>
/// <param name="inChannelCount">Input channel count</param>
/// <param name="outChannelCount">Output channel count</param>
/// <param name="isFloat">If true, it's read as CLUTf32,
/// else read as either CLUT8 or CLUT16 depending on embedded information</param>
/// <returns>The read CLUT</returns>
public IccClut ReadClut(int inChannelCount, int outChannelCount, bool isFloat)
{
// Grid-points are always 16 bytes long but only 0-inChCount are used
var gridPointCount = new byte[inChannelCount];
Buffer.BlockCopy(this.data, this.AddIndex(16), gridPointCount, 0, inChannelCount);
if (!isFloat)
{
byte size = this.data[this.AddIndex(4)]; // First byte is info, last 3 bytes are reserved
if (size == 1)
{
return this.ReadClut8(inChannelCount, outChannelCount, gridPointCount);
}
if (size == 2)
{
return this.ReadClut16(inChannelCount, outChannelCount, gridPointCount);
}
throw new InvalidIccProfileException($"Invalid CLUT size of {size}");
}
return this.ReadClutF32(inChannelCount, outChannelCount, gridPointCount);
}
/// <summary>
/// Reads an 8 bit CLUT
/// </summary>
/// <param name="inChannelCount">Input channel count</param>
/// <param name="outChannelCount">Output channel count</param>
/// <param name="gridPointCount">Grid point count for each CLUT channel</param>
/// <returns>The read CLUT8</returns>
public IccClut ReadClut8(int inChannelCount, int outChannelCount, byte[] gridPointCount)
{
int start = this.currentIndex;
int length = 0;
for (int i = 0; i < inChannelCount; i++)
{
length += (int)Math.Pow(gridPointCount[i], inChannelCount);
}
length /= inChannelCount;
const float Max = byte.MaxValue;
var values = new float[length][];
for (int i = 0; i < length; i++)
{
values[i] = new float[outChannelCount];
for (int j = 0; j < outChannelCount; j++)
{
values[i][j] = this.data[this.currentIndex++] / Max;
}
}
this.currentIndex = start + (length * outChannelCount);
return new IccClut(values, gridPointCount, IccClutDataType.UInt8);
}
/// <summary>
/// Reads a 16 bit CLUT
/// </summary>
/// <param name="inChannelCount">Input channel count</param>
/// <param name="outChannelCount">Output channel count</param>
/// <param name="gridPointCount">Grid point count for each CLUT channel</param>
/// <returns>The read CLUT16</returns>
public IccClut ReadClut16(int inChannelCount, int outChannelCount, byte[] gridPointCount)
{
int start = this.currentIndex;
int length = 0;
for (int i = 0; i < inChannelCount; i++)
{
length += (int)Math.Pow(gridPointCount[i], inChannelCount);
}
length /= inChannelCount;
const float Max = ushort.MaxValue;
var values = new float[length][];
for (int i = 0; i < length; i++)
{
values[i] = new float[outChannelCount];
for (int j = 0; j < outChannelCount; j++)
{
values[i][j] = this.ReadUInt16() / Max;
}
}
this.currentIndex = start + (length * outChannelCount * 2);
return new IccClut(values, gridPointCount, IccClutDataType.UInt16);
}
/// <summary>
/// Reads a 32bit floating point CLUT
/// </summary>
/// <param name="inChCount">Input channel count</param>
/// <param name="outChCount">Output channel count</param>
/// <param name="gridPointCount">Grid point count for each CLUT channel</param>
/// <returns>The read CLUTf32</returns>
public IccClut ReadClutF32(int inChCount, int outChCount, byte[] gridPointCount)
{
int start = this.currentIndex;
int length = 0;
for (int i = 0; i < inChCount; i++)
{
length += (int)Math.Pow(gridPointCount[i], inChCount);
}
length /= inChCount;
var values = new float[length][];
for (int i = 0; i < length; i++)
{
values[i] = new float[outChCount];
for (int j = 0; j < outChCount; j++)
{
values[i][j] = this.ReadSingle();
}
}
this.currentIndex = start + (length * outChCount * 4);
return new IccClut(values, gridPointCount, IccClutDataType.Float);
}
}
}