Browse Source

Add bit writer

pull/3153/head
winscripter 4 weeks ago
parent
commit
836a0554e1
  1. 1
      src/ImageSharp/Formats/Jxl/Fields/JxlBitsCoder.cs
  2. 3
      src/ImageSharp/Formats/Jxl/Fields/JxlBundle.cs
  3. 2
      src/ImageSharp/Formats/Jxl/Fields/JxlCanEncodeVisitor.cs
  4. 1
      src/ImageSharp/Formats/Jxl/Fields/JxlF16Coder.cs
  5. 1
      src/ImageSharp/Formats/Jxl/Fields/JxlU32Coder.cs
  6. 1
      src/ImageSharp/Formats/Jxl/Fields/JxlU64Coder.cs
  7. 88
      src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlBitWriter.cs

1
src/ImageSharp/Formats/Jxl/Fields/JxlBitsCoder.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder;
namespace SixLabors.ImageSharp.Formats.Jxl.Fields; namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

3
src/ImageSharp/Formats/Jxl/Fields/JxlBundle.cs

@ -5,6 +5,7 @@ using SixLabors.ImageSharp.Formats.Jxl.IO.FrameHeader;
using SixLabors.ImageSharp.Formats.Jxl.IO.Metadata; using SixLabors.ImageSharp.Formats.Jxl.IO.Metadata;
using SixLabors.ImageSharp.Formats.Jxl.Processing; using SixLabors.ImageSharp.Formats.Jxl.Processing;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder.AuxiliaryOutput; using SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder.AuxiliaryOutput;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Quantization; using SixLabors.ImageSharp.Formats.Jxl.Processing.Quantization;
@ -118,7 +119,7 @@ internal static class JxlBundle
return false; return false;
} }
return writer.WithMaxBits(totalBits, layer, auxOutput, () => return writer.WithMaxBits(totalBits, () =>
{ {
JxlWriteVisitor visitor = new(extensionBits, writer); JxlWriteVisitor visitor = new(extensionBits, writer);

2
src/ImageSharp/Formats/Jxl/Fields/JxlCanEncodeVisitor.cs

@ -102,7 +102,7 @@ internal sealed class JxlCanEncodeVisitor : JxlVisitorBase
extensionBits = (int)this.encodedBits - (int)this.posAfterExt; extensionBits = (int)this.encodedBits - (int)this.posAfterExt;
int encodedBits = 0; int encodedBits = 0;
this.OK &= JxlU64Coder.CanEncode(extensionBits, ref encodedBits); this.OK &= JxlU64Coder.CanEncode((ulong)extensionBits, ref encodedBits);
totalBits += encodedBits; totalBits += encodedBits;
for (int i = 1; i < BitOperations.PopCount(this.extensions); i++) for (int i = 1; i < BitOperations.PopCount(this.extensions); i++)

1
src/ImageSharp/Formats/Jxl/Fields/JxlF16Coder.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder;
namespace SixLabors.ImageSharp.Formats.Jxl.Fields; namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

1
src/ImageSharp/Formats/Jxl/Fields/JxlU32Coder.cs

@ -3,6 +3,7 @@
using SixLabors.ImageSharp.Formats.Jxl.Processing; using SixLabors.ImageSharp.Formats.Jxl.Processing;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder;
namespace SixLabors.ImageSharp.Formats.Jxl.Fields; namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

1
src/ImageSharp/Formats/Jxl/Fields/JxlU64Coder.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder;
namespace SixLabors.ImageSharp.Formats.Jxl.Fields; namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

88
src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlBitWriter.cs

@ -0,0 +1,88 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder;
internal sealed class JxlBitWriter(Stream stream)
{
private const int BitsPerByte = 8;
private bool isLimited;
private ulong bitsLimit;
private byte currentByte;
private int bitsInCurrentByte;
public long BitsWritten { get; private set; }
public void Write(int nBits, int bits) => this.Write(nBits, (ulong)bits);
public void Write(int nBits, ulong bits)
{
DebugGuard.MustBeGreaterThanOrEqualTo(nBits, 0, nameof(nBits));
DebugGuard.MustBeLessThanOrEqualTo(nBits, 64, nameof(nBits));
if (this.isLimited)
{
if ((ulong)nBits > this.bitsLimit)
{
throw new InvalidOperationException("Too many bits were written");
}
this.bitsLimit -= (ulong)nBits;
}
while (nBits > 0)
{
int bitsAvailable = BitsPerByte - this.bitsInCurrentByte;
int count = Math.Min(nBits, bitsAvailable);
ulong mask = count == 64
? ulong.MaxValue
: (1UL << count) - 1;
this.currentByte |= (byte)((bits & mask) << this.bitsInCurrentByte);
bits >>= count;
nBits -= count;
this.bitsInCurrentByte += count;
this.BitsWritten += count;
if (this.bitsInCurrentByte == BitsPerByte)
{
stream.WriteByte(this.currentByte);
this.currentByte = 0;
this.bitsInCurrentByte = 0;
}
}
}
public bool WithMaxBits(ulong maxBits, Func<bool> func)
{
bool previousIsLimited = this.isLimited;
ulong previousLimit = this.bitsLimit;
this.isLimited = true;
this.bitsLimit = maxBits;
try
{
return func();
}
finally
{
this.isLimited = previousIsLimited;
this.bitsLimit = previousLimit;
}
}
public void Flush()
{
if (this.bitsInCurrentByte != 0)
{
stream.WriteByte(this.currentByte);
this.currentByte = 0;
this.bitsInCurrentByte = 0;
}
}
}
Loading…
Cancel
Save