Browse Source

(Vp8L) Write total size after writing. Separate the writes of each block

pull/2569/head
Poker 3 years ago
parent
commit
437144dab5
No known key found for this signature in database GPG Key ID: C65A6AD457D5C8F8
  1. 76
      src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs
  2. 80
      src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs
  3. 76
      src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs
  4. 17
      src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
  5. 1
      src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs

76
src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs

@ -137,6 +137,82 @@ internal abstract class BitWriterBase
stream.Position = position;
}
/// <summary>
/// Write the trunks before data trunk.
/// </summary>
/// <remarks>Think of it as a static method — none of the other members are called except for <see cref="BitWriterBase.scratchBuffer"/></remarks>
/// <param name="stream">The stream to write to.</param>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="exifProfile">The exif profile.</param>
/// <param name="xmpProfile">The XMP profile.</param>
/// <param name="iccProfile">The color profile.</param>
/// <param name="hasAlpha">Flag indicating, if a alpha channel is present.</param>
/// <param name="alphaData">The alpha channel data.</param>
/// <param name="alphaDataIsCompressed">Indicates, if the alpha data is compressed.</param>
public void WriteTrunksBeforeData(
Stream stream,
uint width,
uint height,
ExifProfile? exifProfile,
XmpProfile? xmpProfile,
IccProfile? iccProfile,
bool hasAlpha,
Span<byte> alphaData,
bool alphaDataIsCompressed)
{
// Write file size later
this.WriteRiffHeader(stream, 0);
// Write VP8X, header if necessary.
bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha;
if (isVp8X)
{
this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha);
if (iccProfile != null)
{
this.WriteColorProfile(stream, iccProfile.ToByteArray());
}
if (hasAlpha)
{
this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed);
}
}
}
/// <summary>
/// Writes the encoded image to the stream.
/// </summary>
/// <param name="stream">The stream to write to.</param>
public abstract void WriteEncodedImageToStream(Stream stream);
/// <summary>
/// Write the trunks after data trunk.
/// </summary>
/// <remarks>Think of it as a static method — none of the other members are called except for <see cref="BitWriterBase.scratchBuffer"/></remarks>
/// <param name="stream">The stream to write to.</param>
/// <param name="exifProfile">The exif profile.</param>
/// <param name="xmpProfile">The XMP profile.</param>
public void WriteTrunksAfterData(
Stream stream,
ExifProfile? exifProfile,
XmpProfile? xmpProfile)
{
if (exifProfile != null)
{
this.WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif);
}
if (xmpProfile != null)
{
this.WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp);
}
OverwriteFileSize(stream);
}
/// <summary>
/// Writes a metadata profile (EXIF or XMP) to the stream.
/// </summary>

80
src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs

@ -3,9 +3,6 @@
using System.Buffers.Binary;
using SixLabors.ImageSharp.Formats.Webp.Lossy;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
namespace SixLabors.ImageSharp.Formats.Webp.BitWriter;
@ -394,56 +391,8 @@ internal class Vp8BitWriter : BitWriterBase
}
}
/// <summary>
/// Write the trunks before data trunk.
/// </summary>
/// <remarks>Think of it as a static method — none of the other members are called except for <see cref="BitWriterBase.scratchBuffer"/></remarks>
/// <param name="stream">The stream to write to.</param>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="exifProfile">The exif profile.</param>
/// <param name="xmpProfile">The XMP profile.</param>
/// <param name="iccProfile">The color profile.</param>
/// <param name="hasAlpha">Flag indicating, if a alpha channel is present.</param>
/// <param name="alphaData">The alpha channel data.</param>
/// <param name="alphaDataIsCompressed">Indicates, if the alpha data is compressed.</param>
public void WriteTrunksBeforeData(
Stream stream,
uint width,
uint height,
ExifProfile? exifProfile,
XmpProfile? xmpProfile,
IccProfile? iccProfile,
bool hasAlpha,
Span<byte> alphaData,
bool alphaDataIsCompressed)
{
// Write file size later
this.WriteRiffHeader(stream, 0);
// Write VP8X, header if necessary.
bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha;
if (isVp8X)
{
this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha);
if (iccProfile != null)
{
this.WriteColorProfile(stream, iccProfile.ToByteArray());
}
if (hasAlpha)
{
this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed);
}
}
}
/// <summary>
/// Writes the encoded image to the stream.
/// </summary>
/// <param name="stream">The stream to write to.</param>
public void WriteEncodedImageToStream(Stream stream)
/// <inheritdoc />
public override void WriteEncodedImageToStream(Stream stream)
{
uint numBytes = (uint)this.NumBytes;
@ -474,31 +423,6 @@ internal class Vp8BitWriter : BitWriterBase
}
}
/// <summary>
/// Write the trunks after data trunk.
/// </summary>
/// <remarks>Think of it as a static method — none of the other members are called except for <see cref="BitWriterBase.scratchBuffer"/></remarks>
/// <param name="stream">The stream to write to.</param>
/// <param name="exifProfile">The exif profile.</param>
/// <param name="xmpProfile">The XMP profile.</param>
public void WriteTrunksAfterData(
Stream stream,
ExifProfile? exifProfile,
XmpProfile? xmpProfile)
{
if (exifProfile != null)
{
this.WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif);
}
if (xmpProfile != null)
{
this.WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp);
}
OverwriteFileSize(stream);
}
private uint GeneratePartition0()
{
this.PutBitUniform(0); // colorspace

76
src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs

@ -3,9 +3,6 @@
using System.Buffers.Binary;
using SixLabors.ImageSharp.Formats.Webp.Lossless;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
namespace SixLabors.ImageSharp.Formats.Webp.BitWriter;
@ -122,68 +119,11 @@ internal class Vp8LBitWriter : BitWriterBase
this.used = 0;
}
/// <summary>
/// Writes the encoded image to the stream.
/// </summary>
/// <param name="stream">The stream to write to.</param>
/// <param name="exifProfile">The exif profile.</param>
/// <param name="xmpProfile">The XMP profile.</param>
/// <param name="iccProfile">The color profile.</param>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="hasAlpha">Flag indicating, if a alpha channel is present.</param>
public void WriteEncodedImageToStream(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha)
/// <inheritdoc />
public override void WriteEncodedImageToStream(Stream stream)
{
bool isVp8X = false;
byte[]? exifBytes = null;
byte[]? xmpBytes = null;
byte[]? iccBytes = null;
uint riffSize = 0;
if (exifProfile != null)
{
isVp8X = true;
exifBytes = exifProfile.ToByteArray();
riffSize += MetadataChunkSize(exifBytes!);
}
if (xmpProfile != null)
{
isVp8X = true;
xmpBytes = xmpProfile.Data;
riffSize += MetadataChunkSize(xmpBytes!);
}
if (iccProfile != null)
{
isVp8X = true;
iccBytes = iccProfile.ToByteArray();
riffSize += MetadataChunkSize(iccBytes);
}
if (isVp8X)
{
riffSize += ExtendedFileChunkSize;
}
this.Finish();
uint size = (uint)this.NumBytes;
size++; // One byte extra for the VP8L signature.
// Write RIFF header.
uint size = (uint)this.NumBytes + 1; // One byte extra for the VP8L signature
uint pad = size & 1;
riffSize += WebpConstants.TagSize + WebpConstants.ChunkHeaderSize + size + pad;
this.WriteRiffHeader(stream, riffSize);
// Write VP8X, header if necessary.
if (isVp8X)
{
this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha);
if (iccBytes != null)
{
this.WriteColorProfile(stream, iccBytes);
}
}
// Write magic bytes indicating its a lossless webp.
Span<byte> scratchBuffer = stackalloc byte[WebpConstants.TagSize];
@ -201,16 +141,6 @@ internal class Vp8LBitWriter : BitWriterBase
{
stream.WriteByte(0);
}
if (exifProfile != null)
{
this.WriteMetadataProfile(stream, exifBytes, WebpChunkType.Exif);
}
if (xmpProfile != null)
{
this.WriteMetadataProfile(stream, xmpBytes, WebpChunkType.Xmp);
}
}
/// <summary>

17
src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs

@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Formats.Webp.BitWriter;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
using SixLabors.ImageSharp.PixelFormats;
@ -265,8 +266,22 @@ internal class Vp8LEncoder : IDisposable
// Encode the main image stream.
this.EncodeStream(image.Frames.RootFrame);
this.bitWriter.Finish();
this.bitWriter.WriteTrunksBeforeData(
stream,
(uint)width,
(uint)height,
exifProfile,
xmpProfile,
metadata.IccProfile,
false /*hasAlpha*/,
Span<byte>.Empty,
false);
// Write bytes from the bitwriter buffer to the stream.
this.bitWriter.WriteEncodedImageToStream(stream, exifProfile, xmpProfile, metadata.IccProfile, (uint)width, (uint)height, hasAlpha);
this.bitWriter.WriteEncodedImageToStream(stream);
this.bitWriter.WriteTrunksAfterData(stream, exifProfile, xmpProfile);
}
/// <summary>

1
src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs

@ -8,7 +8,6 @@ using SixLabors.ImageSharp.Formats.Webp.BitWriter;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
using SixLabors.ImageSharp.PixelFormats;

Loading…
Cancel
Save