mirror of https://github.com/SixLabors/ImageSharp
7 changed files with 95 additions and 2 deletions
@ -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…
Reference in new issue