mirror of https://github.com/SixLabors/ImageSharp
5 changed files with 311 additions and 35 deletions
@ -0,0 +1,276 @@ |
|||||
|
// <copyright file="PackedPixelConverterHelper.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Assists with the conversion of known packed pixel formats from one to another.
|
||||
|
/// </summary>
|
||||
|
internal static class PackedPixelConverterHelper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A non operative function. Simply returns the original vector.
|
||||
|
/// </summary>
|
||||
|
private static readonly Func<Vector4, Vector4> Noop = vector4 => vector4; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the correct scaling function for the given types The compute scale function.
|
||||
|
/// </summary>
|
||||
|
/// <param name="scaleFunc">The scale function.</param>
|
||||
|
/// <typeparam name="TColor">The source pixel format.</typeparam>
|
||||
|
/// <typeparam name="TColor2">The target pixel format.</typeparam>
|
||||
|
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
||||
|
public static Func<Vector4, Vector4> ComputeScaleFunction<TColor, TColor2>(Func<Vector4, Vector4> scaleFunc) |
||||
|
{ |
||||
|
// Custom type with a custom function.
|
||||
|
if (scaleFunc != null) |
||||
|
{ |
||||
|
return scaleFunc; |
||||
|
} |
||||
|
|
||||
|
Type source = typeof(TColor); |
||||
|
Type target = typeof(TColor2); |
||||
|
|
||||
|
// Standard to offset
|
||||
|
if (IsStandardNormalizedType(source)) |
||||
|
{ |
||||
|
if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target)) |
||||
|
{ |
||||
|
// Expand the range then offset the center down.
|
||||
|
return vector4 => (2F * vector4) - Vector4.One; |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetType(target) || IsOffsetTwoComponentType(target)) |
||||
|
{ |
||||
|
return v => (65534 * v) - new Vector4(32767); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Normalized offsets. All four components.
|
||||
|
if (IsOffsetNormalizedType(source)) |
||||
|
{ |
||||
|
return FromOffsetNormalizedType(target); |
||||
|
} |
||||
|
|
||||
|
// Offset. All four components.
|
||||
|
if (IsOffsetType(source)) |
||||
|
{ |
||||
|
return FromOffsetType(target); |
||||
|
} |
||||
|
|
||||
|
// Normalized offsets. First component pair only.
|
||||
|
if (IsOffsetTwoComponentNormalizedType(source)) |
||||
|
{ |
||||
|
return FromOffsetTwoComponentNormalizedType(target); |
||||
|
} |
||||
|
|
||||
|
// Offsets. First component pair only.
|
||||
|
if (IsOffsetTwoComponentType(source)) |
||||
|
{ |
||||
|
return FromOffsetTwoComponentType(target); |
||||
|
} |
||||
|
|
||||
|
return Noop; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the correct conversion function to convert from types having vector values representing all four components
|
||||
|
/// ranging from -1 to 1.
|
||||
|
/// </summary>
|
||||
|
/// <param name="target">The target type</param>
|
||||
|
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
||||
|
private static Func<Vector4, Vector4> FromOffsetNormalizedType(Type target) |
||||
|
{ |
||||
|
if (IsStandardNormalizedType(target)) |
||||
|
{ |
||||
|
// Compress the range then offset the center up.
|
||||
|
return vector4 => (vector4 / 2F) + new Vector4(.5F); |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetType(target) || IsOffsetTwoComponentType(target)) |
||||
|
{ |
||||
|
// Multiply out the range, two component won't read the last two values.
|
||||
|
return vector4 => (vector4 * 32767F); |
||||
|
} |
||||
|
|
||||
|
return Noop; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the correct conversion function to convert from types having vector values representing all four components
|
||||
|
/// ranging from -32767 to 32767.
|
||||
|
/// </summary>
|
||||
|
/// <param name="target">The target type</param>
|
||||
|
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
||||
|
private static Func<Vector4, Vector4> FromOffsetType(Type target) |
||||
|
{ |
||||
|
if (IsStandardNormalizedType(target)) |
||||
|
{ |
||||
|
// Compress the range then offset the center up.
|
||||
|
return vector4 => (vector4 / 65534) + new Vector4(.5F); |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target)) |
||||
|
{ |
||||
|
// Compress the range. Two component won't read the last two values.
|
||||
|
return vector4 => (vector4 / 32767); |
||||
|
} |
||||
|
|
||||
|
return Noop; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the correct conversion function to convert from types having vector with the first component pair ranging from -1 to 1.
|
||||
|
/// and the second component pair ranging from 0 to 1.
|
||||
|
/// </summary>
|
||||
|
/// <param name="target">The target type</param>
|
||||
|
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
||||
|
private static Func<Vector4, Vector4> FromOffsetTwoComponentNormalizedType(Type target) |
||||
|
{ |
||||
|
if (IsStandardNormalizedType(target)) |
||||
|
{ |
||||
|
return vector4 => |
||||
|
{ |
||||
|
// Compress the range then offset the center up for first pair.
|
||||
|
Vector4 v = (vector4 / 2F) + new Vector4(.5F); |
||||
|
return new Vector4(v.X, v.Y, 0, 1); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetNormalizedType(target)) |
||||
|
{ |
||||
|
// Copy the first two components and set second pair to 0 and 1 equivalent.
|
||||
|
return vector4 => new Vector4(vector4.X, vector4.Y, -1, 1); |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetTwoComponentType(target)) |
||||
|
{ |
||||
|
// Multiply. Two component won't read the last two values.
|
||||
|
return vector4 => (vector4 * 32767); |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetType(target)) |
||||
|
{ |
||||
|
return vector4 => |
||||
|
{ |
||||
|
// Multiply the first two components and set second pair to 0 and 1 equivalent.
|
||||
|
Vector4 v = vector4 * 32767; |
||||
|
return new Vector4(v.X, v.Y, -32767, 32767); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
return Noop; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the correct conversion function to convert from types having vector with the first component pair ranging from -32767 to 32767.
|
||||
|
/// and the second component pair ranging from 0 to 1.
|
||||
|
/// </summary>
|
||||
|
/// <param name="target">The target type</param>
|
||||
|
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
|
||||
|
private static Func<Vector4, Vector4> FromOffsetTwoComponentType(Type target) |
||||
|
{ |
||||
|
if (IsStandardNormalizedType(target)) |
||||
|
{ |
||||
|
return vector4 => |
||||
|
{ |
||||
|
Vector4 v = (vector4 / 65534) + new Vector4(.5F); |
||||
|
return new Vector4(v.X, v.Y, 0, 1); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetType(target)) |
||||
|
{ |
||||
|
// Copy the first two components and set second pair to 0 and 1 equivalent.
|
||||
|
return vector4 => new Vector4(vector4.X, vector4.Y, -32767, 32767); |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetNormalizedType(target)) |
||||
|
{ |
||||
|
return vector4 => |
||||
|
{ |
||||
|
// Divide the first two components and set second pair to 0 and 1 equivalent.
|
||||
|
Vector4 v = vector4 / 32767; |
||||
|
return new Vector4(v.X, v.Y, -1, 1); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
if (IsOffsetTwoComponentNormalizedType(target)) |
||||
|
{ |
||||
|
// Divide. Two component won't read the last two values.
|
||||
|
return vector4 => (vector4 / 32767); |
||||
|
} |
||||
|
|
||||
|
return Noop; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the type as having vector component values ranging from 0 to 1.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type to test.</param>
|
||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||
|
private static bool IsStandardNormalizedType(Type type) |
||||
|
{ |
||||
|
return type == typeof(Color) |
||||
|
|| type == typeof(Bgr565) |
||||
|
|| type == typeof(Bgra4444) |
||||
|
|| type == typeof(Bgra5551) |
||||
|
|| type == typeof(Byte4) |
||||
|
|| type == typeof(HalfSingle) |
||||
|
|| type == typeof(HalfVector2) |
||||
|
|| type == typeof(HalfVector4) |
||||
|
|| type == typeof(Rg32) |
||||
|
|| type == typeof(Rgba1010102) |
||||
|
|| type == typeof(Rgba64); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the type as having vector values representing the first component pair ranging from -1 to 1.
|
||||
|
/// and the second component pair ranging from 0 to 1.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type to test.</param>
|
||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||
|
private static bool IsOffsetTwoComponentNormalizedType(Type type) |
||||
|
{ |
||||
|
return type == typeof(NormalizedByte2) |
||||
|
|| type == typeof(NormalizedShort2); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the type as having vector values representing all four components ranging from -1 to 1.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type to test.</param>
|
||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||
|
private static bool IsOffsetNormalizedType(Type type) |
||||
|
{ |
||||
|
return type == typeof(NormalizedByte4) |
||||
|
|| type == typeof(NormalizedShort4); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the type as having vector values representing the first component pair ranging from -32767 to 32767.
|
||||
|
/// and the second component pair ranging from 0 to 1.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type to test.</param>
|
||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||
|
private static bool IsOffsetTwoComponentType(Type type) |
||||
|
{ |
||||
|
return type == typeof(Short2); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the type as having vector values representing all four components ranging from -32767 to 32767.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type to test.</param>
|
||||
|
/// <returns>The <see cref="bool"/></returns>
|
||||
|
private static bool IsOffsetType(Type type) |
||||
|
{ |
||||
|
return type == typeof(Short4); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue