Browse Source

Write bytes from the bitwriter to the stream

pull/1552/head
Brian Popow 6 years ago
parent
commit
fe8193a982
  1. 39
      src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs
  2. 47
      src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
  3. 31
      src/ImageSharp/Formats/WebP/WebPConstants.cs

39
src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs

@ -3,6 +3,7 @@
using System;
using System.Buffers.Binary;
using System.IO;
using SixLabors.ImageSharp.Formats.WebP.Lossless;
namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
@ -21,8 +22,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
private const int WriterBits = 32;
private const int WriterMaxBits = 64;
/// <summary>
/// Bit accumulator.
/// </summary>
@ -45,15 +44,20 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
private int end;
/// <summary>
/// Initializes a new instance of the <see cref="Vp8LBitWriter"/> class.
/// </summary>
/// <param name="expectedSize">The expected size in bytes.</param>
public Vp8LBitWriter(int expectedSize)
{
// TODO: maybe use memory allocator here.
this.buffer = new byte[expectedSize];
this.end = this.buffer.Length;
}
/// <summary>
/// Initializes a new instance of the <see cref="Vp8LBitWriter"/> class.
/// Used internally for cloning
/// Used internally for cloning.
/// </summary>
private Vp8LBitWriter(byte[] buffer, ulong bits, int used, int cur)
{
@ -107,6 +111,31 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
return new Vp8LBitWriter(clonedBuffer, this.bits, this.used, this.cur);
}
/// <summary>
/// Writes the encoded bytes of the image to the stream. Call BitWriterFinish() before this.
/// </summary>
/// <param name="stream">The stream to write to.</param>
public void WriteToStream(Stream stream)
{
stream.Write(this.buffer.AsSpan(0, this.NumBytes()));
}
/// <summary>
/// Flush leftover bits.
/// </summary>
public void BitWriterFinish()
{
this.BitWriterResize((this.used + 7) >> 3);
while (this.used > 0)
{
this.buffer[this.cur++] = (byte)this.bits;
this.bits >>= 8;
this.used -= 8;
}
this.used = 0;
}
/// <summary>
/// Internal function for PutBits flushing 32 bits from the written state.
/// </summary>
@ -125,6 +154,10 @@ namespace SixLabors.ImageSharp.Formats.WebP.BitWriter
this.used -= WriterBits;
}
/// <summary>
/// Resizes the buffer to write to.
/// </summary>
/// <param name="extraSize">The extra size in bytes needed.</param>
private void BitWriterResize(int extraSize)
{
int maxBytes = this.end + this.buffer.Length;

47
src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs

@ -3,8 +3,10 @@
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.WebP.BitWriter;
using SixLabors.ImageSharp.Memory;
@ -147,6 +149,12 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
/// </summary>
public Vp8LHashChain HashChain { get; }
/// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TPixel}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
@ -162,11 +170,18 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// Encode the main image stream.
this.EncodeStream(image);
// TODO: write bytes from the bitwriter to the stream.
// Write bytes from the bitwriter buffer to the stream.
this.bitWriter.BitWriterFinish();
var numBytes = this.bitWriter.NumBytes();
var vp8LSize = 1 + numBytes; // One byte extra for the VP8L signature.
var pad = vp8LSize & 1;
var riffSize = WebPConstants.TagSize + WebPConstants.ChunkHeaderSize + vp8LSize + pad;
this.WriteRiffHeader(riffSize, vp8LSize, stream);
this.bitWriter.WriteToStream(stream);
}
/// <summary>
/// Writes the image size to the stream.
/// Writes the image size to the bitwriter buffer.
/// </summary>
/// <param name="inputImgWidth">The input image width.</param>
/// <param name="inputImgHeight">The input image height.</param>
@ -182,12 +197,36 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
this.bitWriter.PutBits(height, WebPConstants.Vp8LImageSizeBits);
}
/// <summary>
/// Writes a flag indicating if alpha channel is used and the VP8L version to the bitwriter buffer.
/// </summary>
/// <param name="hasAlpha">Indicates if a alpha channel is present.</param>
private void WriteAlphaAndVersion(bool hasAlpha)
{
this.bitWriter.PutBits(hasAlpha ? 1U : 0, 1);
this.bitWriter.PutBits(WebPConstants.Vp8LVersion, WebPConstants.Vp8LVersionBits);
}
/// <summary>
/// Writes the RIFF header to the stream.
/// </summary>
/// <param name="riffSize">The block length.</param>
/// <param name="vp8LSize">The size in bytes of the compressed image.</param>
/// <param name="stream">The stream to write to.</param>
private void WriteRiffHeader(int riffSize, int vp8LSize, Stream stream)
{
Span<byte> buffer = stackalloc byte[4];
stream.Write(WebPConstants.RiffFourCc);
BinaryPrimitives.WriteUInt32LittleEndian(buffer, (uint)riffSize);
stream.Write(buffer);
stream.Write(WebPConstants.WebPHeader);
stream.Write(WebPConstants.Vp8LTag);
BinaryPrimitives.WriteUInt32LittleEndian(buffer, (uint)vp8LSize);
stream.Write(buffer);
stream.WriteByte(WebPConstants.Vp8LMagicByte);
}
/// <summary>
/// Encodes the image stream using lossless webp format.
/// </summary>
@ -323,6 +362,10 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
{
bitWriterBest = this.bitWriter.Clone();
}
else
{
bitWriterBest = this.bitWriter;
}
for (int lz77sIdx = 0; lz77sIdx < lz77sTypesToTrySize; lz77sIdx++)
{

31
src/ImageSharp/Formats/WebP/WebPConstants.cs

@ -30,6 +30,22 @@ namespace SixLabors.ImageSharp.Formats.WebP
0x2A
};
/// <summary>
/// Signature byte which identifies a VP8L header.
/// </summary>
public const byte Vp8LMagicByte = 0x2F;
/// <summary>
/// Header bytes identifying a lossless image.
/// </summary>
public static readonly byte[] Vp8LTag =
{
0x56, // V
0x50, // P
0x38, // 8
0x4C // L
};
/// <summary>
/// The header bytes identifying RIFF file.
/// </summary>
@ -52,11 +68,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
0x50 // P
};
/// <summary>
/// Signature byte which identifies a VP8L header.
/// </summary>
public const byte Vp8LMagicByte = 0x2F;
/// <summary>
/// 3 bits reserved for version.
/// </summary>
@ -67,6 +78,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public const int Vp8LImageSizeBits = 14;
/// <summary>
/// Size of a chunk header.
/// </summary>
public const int ChunkHeaderSize = 8;
/// <summary>
/// Size of a chunk tag (e.g. "VP8L").
/// </summary>
public const int TagSize = 4;
/// <summary>
/// The Vp8L version 0.
/// </summary>

Loading…
Cancel
Save