mirror of https://github.com/SixLabors/ImageSharp
Browse Source
JxlBoxHeader contains a header for boxes in the JPEG XL container. JxlFileTypeBox represents the ftyp box. BinaryUtils contains helper methods to read/write primitives from/to Stream in custom endiannesspull/3153/head
4 changed files with 597 additions and 0 deletions
@ -0,0 +1,321 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Buffers.Binary; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.IO; |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads primitives from streams with correct endianness.
|
||||
|
/// </summary>
|
||||
|
// TODO: move this class into the IO or Common folder?
|
||||
|
internal static class BinaryUtils |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="Int16" />
|
||||
|
/// from the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int16" /> will be read from.</param>
|
||||
|
/// <returns><see cref="Int16" /></returns>
|
||||
|
public static Int16 ReadInt16LittleEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int16)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadInt16LittleEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="Int16" />
|
||||
|
/// from the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int16" /> will be read from.</param>
|
||||
|
/// <returns><see cref="Int16" /></returns>
|
||||
|
public static Int16 ReadInt16BigEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int16)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadInt16BigEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="Int16" />
|
||||
|
/// into the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int16" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteInt16LittleEndian(Stream stream, Int16 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int16)]; |
||||
|
BinaryPrimitives.WriteInt16LittleEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="Int16" />
|
||||
|
/// into the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int16" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteInt16BigEndian(Stream stream, Int16 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int16)]; |
||||
|
BinaryPrimitives.WriteInt16BigEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="UInt16" />
|
||||
|
/// from the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt16" /> will be read from.</param>
|
||||
|
/// <returns><see cref="UInt16" /></returns>
|
||||
|
public static UInt16 ReadUInt16LittleEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt16)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadUInt16LittleEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="UInt16" />
|
||||
|
/// from the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt16" /> will be read from.</param>
|
||||
|
/// <returns><see cref="UInt16" /></returns>
|
||||
|
public static UInt16 ReadUInt16BigEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt16)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadUInt16BigEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="UInt16" />
|
||||
|
/// into the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt16" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteUInt16LittleEndian(Stream stream, UInt16 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt16)]; |
||||
|
BinaryPrimitives.WriteUInt16LittleEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="UInt16" />
|
||||
|
/// into the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt16" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteUInt16BigEndian(Stream stream, UInt16 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt16)]; |
||||
|
BinaryPrimitives.WriteUInt16BigEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="Int32" />
|
||||
|
/// from the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int32" /> will be read from.</param>
|
||||
|
/// <returns><see cref="Int32" /></returns>
|
||||
|
public static Int32 ReadInt32LittleEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int32)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadInt32LittleEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="Int32" />
|
||||
|
/// from the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int32" /> will be read from.</param>
|
||||
|
/// <returns><see cref="Int32" /></returns>
|
||||
|
public static Int32 ReadInt32BigEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int32)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadInt32BigEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="Int32" />
|
||||
|
/// into the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int32" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteInt32LittleEndian(Stream stream, Int32 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int32)]; |
||||
|
BinaryPrimitives.WriteInt32LittleEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="Int32" />
|
||||
|
/// into the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int32" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteInt32BigEndian(Stream stream, Int32 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int32)]; |
||||
|
BinaryPrimitives.WriteInt32BigEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="UInt32" />
|
||||
|
/// from the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt32" /> will be read from.</param>
|
||||
|
/// <returns><see cref="UInt32" /></returns>
|
||||
|
public static UInt32 ReadUInt32LittleEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt32)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadUInt32LittleEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="UInt32" />
|
||||
|
/// from the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt32" /> will be read from.</param>
|
||||
|
/// <returns><see cref="UInt32" /></returns>
|
||||
|
public static UInt32 ReadUInt32BigEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt32)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadUInt32BigEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="UInt32" />
|
||||
|
/// into the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt32" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteUInt32LittleEndian(Stream stream, UInt32 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt32)]; |
||||
|
BinaryPrimitives.WriteUInt32LittleEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="UInt32" />
|
||||
|
/// into the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt32" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteUInt32BigEndian(Stream stream, UInt32 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt32)]; |
||||
|
BinaryPrimitives.WriteUInt32BigEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="Int64" />
|
||||
|
/// from the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int64" /> will be read from.</param>
|
||||
|
/// <returns><see cref="Int64" /></returns>
|
||||
|
public static Int64 ReadInt64LittleEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int64)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadInt64LittleEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="Int64" />
|
||||
|
/// from the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int64" /> will be read from.</param>
|
||||
|
/// <returns><see cref="Int64" /></returns>
|
||||
|
public static Int64 ReadInt64BigEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int64)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadInt64BigEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="Int64" />
|
||||
|
/// into the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int64" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteInt64LittleEndian(Stream stream, Int64 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int64)]; |
||||
|
BinaryPrimitives.WriteInt64LittleEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="Int64" />
|
||||
|
/// into the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="Int64" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteInt64BigEndian(Stream stream, Int64 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(Int64)]; |
||||
|
BinaryPrimitives.WriteInt64BigEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="UInt64" />
|
||||
|
/// from the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt64" /> will be read from.</param>
|
||||
|
/// <returns><see cref="UInt64" /></returns>
|
||||
|
public static UInt64 ReadUInt64LittleEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt64)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadUInt64LittleEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Reads a <see cref="UInt64" />
|
||||
|
/// from the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt64" /> will be read from.</param>
|
||||
|
/// <returns><see cref="UInt64" /></returns>
|
||||
|
public static UInt64 ReadUInt64BigEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt64)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.ReadUInt64BigEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="UInt64" />
|
||||
|
/// into the specified stream in little-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt64" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteUInt64LittleEndian(Stream stream, UInt64 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt64)]; |
||||
|
BinaryPrimitives.WriteUInt64LittleEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes a <see cref="UInt64" />
|
||||
|
/// into the specified stream in big-endian order.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The stream where the <see cref="UInt64" /> will be written to.</param>
|
||||
|
/// <param name="value">Value which will be written to the stream.</param>
|
||||
|
public static void WriteUInt64BigEndian(Stream stream, UInt64 value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(UInt64)]; |
||||
|
BinaryPrimitives.WriteUInt64BigEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
<#@ template language="C#" #> |
||||
|
<#@ import namespace="System" #> |
||||
|
<#@ import namespace="System.IO" #> |
||||
|
<#@ import namespace="System.Collections.Generic" #> |
||||
|
<#@ output extension=".Generated.cs" #> |
||||
|
// Copyright (c) Six Labors. |
||||
|
// Licensed under the Six Labors Split License. |
||||
|
|
||||
|
using System.Buffers.Binary; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.IO; |
||||
|
|
||||
|
<# |
||||
|
List<Type> types = [ |
||||
|
typeof(short), |
||||
|
typeof(ushort), |
||||
|
typeof(int), |
||||
|
typeof(uint), |
||||
|
typeof(long), |
||||
|
typeof(ulong) |
||||
|
]; |
||||
|
#> |
||||
|
|
||||
|
/// <summary> |
||||
|
/// Reads primitives from streams with correct endianness. |
||||
|
/// </summary> |
||||
|
// TODO: move this class into the IO or Common folder? |
||||
|
internal static class BinaryUtils |
||||
|
{ |
||||
|
<# |
||||
|
foreach (Type type in types) |
||||
|
{ |
||||
|
#> |
||||
|
/// <summary> |
||||
|
/// Reads a <see cref="<#= type.Name #>" /> |
||||
|
/// from the specified stream in little-endian order. |
||||
|
/// </summary> |
||||
|
/// <param name="stream">The stream where the <see cref="<#= type.Name #>" /> will be read from.</param> |
||||
|
/// <returns><see cref="<#= type.Name #>" /></returns> |
||||
|
public static <#= type.Name #> Read<#= type.Name#>LittleEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(<#= type.Name #>)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.Read<#= type.Name #>LittleEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary> |
||||
|
/// Reads a <see cref="<#= type.Name #>" /> |
||||
|
/// from the specified stream in big-endian order. |
||||
|
/// </summary> |
||||
|
/// <param name="stream">The stream where the <see cref="<#= type.Name #>" /> will be read from.</param> |
||||
|
/// <returns><see cref="<#= type.Name #>" /></returns> |
||||
|
public static <#= type.Name #> Read<#= type.Name#>BigEndian(Stream stream) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(<#= type.Name #>)]; |
||||
|
stream.ReadExactly(data); |
||||
|
return BinaryPrimitives.Read<#= type.Name #>BigEndian(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary> |
||||
|
/// Writes a <see cref="<#= type.Name #>" /> |
||||
|
/// into the specified stream in little-endian order. |
||||
|
/// </summary> |
||||
|
/// <param name="stream">The stream where the <see cref="<#= type.Name #>" /> will be written to.</param> |
||||
|
/// <param name="value">Value which will be written to the stream.</param> |
||||
|
public static void Write<#= type.Name #>LittleEndian(Stream stream, <#= type.Name #> value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(<#= type.Name #>)]; |
||||
|
BinaryPrimitives.Write<#= type.Name #>LittleEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
|
||||
|
/// <summary> |
||||
|
/// Writes a <see cref="<#= type.Name #>" /> |
||||
|
/// into the specified stream in big-endian order. |
||||
|
/// </summary> |
||||
|
/// <param name="stream">The stream where the <see cref="<#= type.Name #>" /> will be written to.</param> |
||||
|
/// <param name="value">Value which will be written to the stream.</param> |
||||
|
public static void Write<#= type.Name #>BigEndian(Stream stream, <#= type.Name #> value) |
||||
|
{ |
||||
|
Span<byte> data = stackalloc byte[sizeof(<#= type.Name #>)]; |
||||
|
BinaryPrimitives.Write<#= type.Name #>BigEndian(data, value); |
||||
|
stream.Write(data); |
||||
|
} |
||||
|
<# } #> |
||||
|
} |
||||
@ -0,0 +1,132 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Buffers.Binary; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.IO.Container; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Header for JPEG XL container format.
|
||||
|
/// </summary>
|
||||
|
[StructLayout(LayoutKind.Sequential, Size = 16)] |
||||
|
internal struct JxlBoxHeader |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Box size in bytes.
|
||||
|
/// </summary>
|
||||
|
public ulong Size; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Type of the box.
|
||||
|
/// </summary>
|
||||
|
public uint Type; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// True if the size field extends until the end of the file.
|
||||
|
/// </summary>
|
||||
|
public bool SizeExtendsTillEnd; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="JxlBoxHeader"/> struct.
|
||||
|
/// </summary>
|
||||
|
/// <param name="size">The size of the box.</param>
|
||||
|
/// <param name="type">The type of the box.</param>
|
||||
|
/// <param name="sizeExtendsTillEnd">Does the box size extend till the end of the file?</param>
|
||||
|
public JxlBoxHeader(ulong size, uint type, bool sizeExtendsTillEnd) |
||||
|
{ |
||||
|
this.Size = size; |
||||
|
this.Type = type; |
||||
|
this.SizeExtendsTillEnd = sizeExtendsTillEnd; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts a 4-character ASCII string (e.g. "jxlc") into a uint type code.
|
||||
|
/// </summary>
|
||||
|
/// <param name="typeString">Input type string to convert</param>
|
||||
|
/// <returns>Unsigned integer representation of the type string</returns>
|
||||
|
public static uint TypeFromString(string typeString) |
||||
|
{ |
||||
|
if (typeString.Length != 4) |
||||
|
{ |
||||
|
throw new ArgumentException("Box type must be exactly 4 characters", nameof(typeString)); |
||||
|
} |
||||
|
|
||||
|
Span<byte> buffer = stackalloc byte[4]; |
||||
|
_ = Encoding.ASCII.GetBytes(typeString, buffer); |
||||
|
|
||||
|
return BinaryPrimitives.ReadUInt32BigEndian(buffer); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts a uint type code back into a 4-character ASCII string.
|
||||
|
/// </summary>
|
||||
|
/// <param name="typeCode">Unsigned integer representation of the type string</param>
|
||||
|
/// <returns>The string representing the type code.</returns>
|
||||
|
public static string TypeToString(uint typeCode) |
||||
|
{ |
||||
|
Span<byte> buffer = stackalloc byte[4]; |
||||
|
BinaryPrimitives.WriteUInt32BigEndian(buffer, typeCode); |
||||
|
|
||||
|
return Encoding.ASCII.GetString(buffer); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Parses the JPEG XL box header.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">A stream to parse the header from.</param>
|
||||
|
/// <returns>The box header.</returns>
|
||||
|
/// <exception cref="InvalidOperationException">Thrown when the header is invalid.</exception>
|
||||
|
public static JxlBoxHeader ReadHeader(Stream stream) |
||||
|
{ |
||||
|
ulong size = BinaryUtils.ReadUInt32BigEndian(stream); |
||||
|
bool haveSize64 = false; |
||||
|
|
||||
|
if (size == 1) |
||||
|
{ |
||||
|
// When the size value is equal to 1, a new 64-bit
|
||||
|
// size field follows.
|
||||
|
haveSize64 = true; |
||||
|
size = BinaryUtils.ReadUInt64BigEndian(stream); |
||||
|
} |
||||
|
|
||||
|
// Read the 4-byte type field.
|
||||
|
uint type = BinaryUtils.ReadUInt32BigEndian(stream); |
||||
|
|
||||
|
if (haveSize64) |
||||
|
{ |
||||
|
// When the 64-bit largesize was read,
|
||||
|
// the size cannot proceed till the end of the file.
|
||||
|
if (size is 0 or 1) |
||||
|
{ |
||||
|
throw new InvalidOperationException("Large size cannot have another large size or extend till the end of the file"); |
||||
|
} |
||||
|
|
||||
|
return new JxlBoxHeader(size, type, sizeExtendsTillEnd: false); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return new JxlBoxHeader(size, type, sizeExtendsTillEnd: size == 0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Writes the box header to the specified stream.
|
||||
|
/// </summary>
|
||||
|
/// <param name="writer">The stream to write the box header to.</param>
|
||||
|
public readonly void WriteHeader(Stream writer) |
||||
|
{ |
||||
|
if (this.Size is > uint.MaxValue or 1) |
||||
|
{ |
||||
|
BinaryUtils.WriteUInt32BigEndian(writer, 1); // Indicates a large size is present
|
||||
|
BinaryUtils.WriteUInt64BigEndian(writer, this.Size); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
BinaryUtils.WriteUInt32BigEndian(writer, (uint)this.Size); |
||||
|
} |
||||
|
|
||||
|
BinaryUtils.WriteUInt32BigEndian(writer, this.Type); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.IO.Container; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A ftyp box payload.
|
||||
|
/// </summary>
|
||||
|
internal sealed class JxlFileTypeBox(string majorBrand, uint minorVersion) |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the primary format. Has to be "jxl " for JPEG XL.
|
||||
|
/// </summary>
|
||||
|
public string MajorBrand { get; set; } = majorBrand; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the revision of the major brand.
|
||||
|
/// </summary>
|
||||
|
public uint MinorVersion { get; set; } = minorVersion; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the list of other brands the file is compatible with.
|
||||
|
/// </summary>
|
||||
|
public List<string> CompatibleBrands { get; set; } = []; |
||||
|
|
||||
|
public int GetPayloadSize() => 8 + (this.CompatibleBrands.Count * 4); |
||||
|
|
||||
|
public static JxlFileTypeBox Parse(Stream stream, ulong boxSize) |
||||
|
{ |
||||
|
string majorBrand = JxlBoxHeader.TypeToString(BinaryUtils.ReadUInt32BigEndian(stream)); |
||||
|
uint minorVersion = BinaryUtils.ReadUInt32BigEndian(stream); |
||||
|
boxSize -= 8; |
||||
|
|
||||
|
List<string> compatibleBrands = []; |
||||
|
for (ulong i = 0; i < boxSize; i += 4) |
||||
|
{ |
||||
|
compatibleBrands.Add(JxlBoxHeader.TypeToString(BinaryUtils.ReadUInt32BigEndian(stream))); |
||||
|
} |
||||
|
|
||||
|
JxlFileTypeBox ftyp = new(majorBrand, minorVersion) |
||||
|
{ |
||||
|
CompatibleBrands = compatibleBrands |
||||
|
}; |
||||
|
|
||||
|
return ftyp; |
||||
|
} |
||||
|
|
||||
|
public void WritePayload(Stream stream) |
||||
|
{ |
||||
|
BinaryUtils.WriteUInt32BigEndian(stream, JxlBoxHeader.TypeFromString(this.MajorBrand)); |
||||
|
BinaryUtils.WriteUInt32BigEndian(stream, this.MinorVersion); |
||||
|
|
||||
|
foreach (string compatibleBrand in this.CompatibleBrands) |
||||
|
{ |
||||
|
BinaryUtils.WriteUInt32BigEndian(stream, JxlBoxHeader.TypeFromString(compatibleBrand)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue