Skip to content

Commit 437144d

Browse files
committed
(Vp8L) Write total size after writing. Separate the writes of each block
1 parent 95d36af commit 437144d

5 files changed

Lines changed: 97 additions & 153 deletions

File tree

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

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,82 @@ protected static void OverwriteFileSize(Stream stream)
137137
stream.Position = position;
138138
}
139139

140+
/// <summary>
141+
/// Write the trunks before data trunk.
142+
/// </summary>
143+
/// <remarks>Think of it as a static method — none of the other members are called except for <see cref="BitWriterBase.scratchBuffer"/></remarks>
144+
/// <param name="stream">The stream to write to.</param>
145+
/// <param name="width">The width of the image.</param>
146+
/// <param name="height">The height of the image.</param>
147+
/// <param name="exifProfile">The exif profile.</param>
148+
/// <param name="xmpProfile">The XMP profile.</param>
149+
/// <param name="iccProfile">The color profile.</param>
150+
/// <param name="hasAlpha">Flag indicating, if a alpha channel is present.</param>
151+
/// <param name="alphaData">The alpha channel data.</param>
152+
/// <param name="alphaDataIsCompressed">Indicates, if the alpha data is compressed.</param>
153+
public void WriteTrunksBeforeData(
154+
Stream stream,
155+
uint width,
156+
uint height,
157+
ExifProfile? exifProfile,
158+
XmpProfile? xmpProfile,
159+
IccProfile? iccProfile,
160+
bool hasAlpha,
161+
Span<byte> alphaData,
162+
bool alphaDataIsCompressed)
163+
{
164+
// Write file size later
165+
this.WriteRiffHeader(stream, 0);
166+
167+
// Write VP8X, header if necessary.
168+
bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha;
169+
if (isVp8X)
170+
{
171+
this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha);
172+
173+
if (iccProfile != null)
174+
{
175+
this.WriteColorProfile(stream, iccProfile.ToByteArray());
176+
}
177+
178+
if (hasAlpha)
179+
{
180+
this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed);
181+
}
182+
}
183+
}
184+
185+
/// <summary>
186+
/// Writes the encoded image to the stream.
187+
/// </summary>
188+
/// <param name="stream">The stream to write to.</param>
189+
public abstract void WriteEncodedImageToStream(Stream stream);
190+
191+
/// <summary>
192+
/// Write the trunks after data trunk.
193+
/// </summary>
194+
/// <remarks>Think of it as a static method — none of the other members are called except for <see cref="BitWriterBase.scratchBuffer"/></remarks>
195+
/// <param name="stream">The stream to write to.</param>
196+
/// <param name="exifProfile">The exif profile.</param>
197+
/// <param name="xmpProfile">The XMP profile.</param>
198+
public void WriteTrunksAfterData(
199+
Stream stream,
200+
ExifProfile? exifProfile,
201+
XmpProfile? xmpProfile)
202+
{
203+
if (exifProfile != null)
204+
{
205+
this.WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif);
206+
}
207+
208+
if (xmpProfile != null)
209+
{
210+
this.WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp);
211+
}
212+
213+
OverwriteFileSize(stream);
214+
}
215+
140216
/// <summary>
141217
/// Writes a metadata profile (EXIF or XMP) to the stream.
142218
/// </summary>

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

Lines changed: 2 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33

44
using System.Buffers.Binary;
55
using SixLabors.ImageSharp.Formats.Webp.Lossy;
6-
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
7-
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
8-
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
96

107
namespace SixLabors.ImageSharp.Formats.Webp.BitWriter;
118

@@ -394,56 +391,8 @@ private void Flush()
394391
}
395392
}
396393

397-
/// <summary>
398-
/// Write the trunks before data trunk.
399-
/// </summary>
400-
/// <remarks>Think of it as a static method — none of the other members are called except for <see cref="BitWriterBase.scratchBuffer"/></remarks>
401-
/// <param name="stream">The stream to write to.</param>
402-
/// <param name="width">The width of the image.</param>
403-
/// <param name="height">The height of the image.</param>
404-
/// <param name="exifProfile">The exif profile.</param>
405-
/// <param name="xmpProfile">The XMP profile.</param>
406-
/// <param name="iccProfile">The color profile.</param>
407-
/// <param name="hasAlpha">Flag indicating, if a alpha channel is present.</param>
408-
/// <param name="alphaData">The alpha channel data.</param>
409-
/// <param name="alphaDataIsCompressed">Indicates, if the alpha data is compressed.</param>
410-
public void WriteTrunksBeforeData(
411-
Stream stream,
412-
uint width,
413-
uint height,
414-
ExifProfile? exifProfile,
415-
XmpProfile? xmpProfile,
416-
IccProfile? iccProfile,
417-
bool hasAlpha,
418-
Span<byte> alphaData,
419-
bool alphaDataIsCompressed)
420-
{
421-
// Write file size later
422-
this.WriteRiffHeader(stream, 0);
423-
424-
// Write VP8X, header if necessary.
425-
bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha;
426-
if (isVp8X)
427-
{
428-
this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha);
429-
430-
if (iccProfile != null)
431-
{
432-
this.WriteColorProfile(stream, iccProfile.ToByteArray());
433-
}
434-
435-
if (hasAlpha)
436-
{
437-
this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed);
438-
}
439-
}
440-
}
441-
442-
/// <summary>
443-
/// Writes the encoded image to the stream.
444-
/// </summary>
445-
/// <param name="stream">The stream to write to.</param>
446-
public void WriteEncodedImageToStream(Stream stream)
394+
/// <inheritdoc />
395+
public override void WriteEncodedImageToStream(Stream stream)
447396
{
448397
uint numBytes = (uint)this.NumBytes;
449398

@@ -474,31 +423,6 @@ public void WriteEncodedImageToStream(Stream stream)
474423
}
475424
}
476425

477-
/// <summary>
478-
/// Write the trunks after data trunk.
479-
/// </summary>
480-
/// <remarks>Think of it as a static method — none of the other members are called except for <see cref="BitWriterBase.scratchBuffer"/></remarks>
481-
/// <param name="stream">The stream to write to.</param>
482-
/// <param name="exifProfile">The exif profile.</param>
483-
/// <param name="xmpProfile">The XMP profile.</param>
484-
public void WriteTrunksAfterData(
485-
Stream stream,
486-
ExifProfile? exifProfile,
487-
XmpProfile? xmpProfile)
488-
{
489-
if (exifProfile != null)
490-
{
491-
this.WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif);
492-
}
493-
494-
if (xmpProfile != null)
495-
{
496-
this.WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp);
497-
}
498-
499-
OverwriteFileSize(stream);
500-
}
501-
502426
private uint GeneratePartition0()
503427
{
504428
this.PutBitUniform(0); // colorspace

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

Lines changed: 3 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33

44
using System.Buffers.Binary;
55
using SixLabors.ImageSharp.Formats.Webp.Lossless;
6-
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
7-
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
8-
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
96

107
namespace SixLabors.ImageSharp.Formats.Webp.BitWriter;
118

@@ -122,68 +119,11 @@ public override void Finish()
122119
this.used = 0;
123120
}
124121

125-
/// <summary>
126-
/// Writes the encoded image to the stream.
127-
/// </summary>
128-
/// <param name="stream">The stream to write to.</param>
129-
/// <param name="exifProfile">The exif profile.</param>
130-
/// <param name="xmpProfile">The XMP profile.</param>
131-
/// <param name="iccProfile">The color profile.</param>
132-
/// <param name="width">The width of the image.</param>
133-
/// <param name="height">The height of the image.</param>
134-
/// <param name="hasAlpha">Flag indicating, if a alpha channel is present.</param>
135-
public void WriteEncodedImageToStream(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha)
122+
/// <inheritdoc />
123+
public override void WriteEncodedImageToStream(Stream stream)
136124
{
137-
bool isVp8X = false;
138-
byte[]? exifBytes = null;
139-
byte[]? xmpBytes = null;
140-
byte[]? iccBytes = null;
141-
uint riffSize = 0;
142-
if (exifProfile != null)
143-
{
144-
isVp8X = true;
145-
exifBytes = exifProfile.ToByteArray();
146-
riffSize += MetadataChunkSize(exifBytes!);
147-
}
148-
149-
if (xmpProfile != null)
150-
{
151-
isVp8X = true;
152-
xmpBytes = xmpProfile.Data;
153-
riffSize += MetadataChunkSize(xmpBytes!);
154-
}
155-
156-
if (iccProfile != null)
157-
{
158-
isVp8X = true;
159-
iccBytes = iccProfile.ToByteArray();
160-
riffSize += MetadataChunkSize(iccBytes);
161-
}
162-
163-
if (isVp8X)
164-
{
165-
riffSize += ExtendedFileChunkSize;
166-
}
167-
168-
this.Finish();
169-
uint size = (uint)this.NumBytes;
170-
size++; // One byte extra for the VP8L signature.
171-
172-
// Write RIFF header.
125+
uint size = (uint)this.NumBytes + 1; // One byte extra for the VP8L signature
173126
uint pad = size & 1;
174-
riffSize += WebpConstants.TagSize + WebpConstants.ChunkHeaderSize + size + pad;
175-
this.WriteRiffHeader(stream, riffSize);
176-
177-
// Write VP8X, header if necessary.
178-
if (isVp8X)
179-
{
180-
this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha);
181-
182-
if (iccBytes != null)
183-
{
184-
this.WriteColorProfile(stream, iccBytes);
185-
}
186-
}
187127

188128
// Write magic bytes indicating its a lossless webp.
189129
Span<byte> scratchBuffer = stackalloc byte[WebpConstants.TagSize];
@@ -201,16 +141,6 @@ public void WriteEncodedImageToStream(Stream stream, ExifProfile? exifProfile, X
201141
{
202142
stream.WriteByte(0);
203143
}
204-
205-
if (exifProfile != null)
206-
{
207-
this.WriteMetadataProfile(stream, exifBytes, WebpChunkType.Exif);
208-
}
209-
210-
if (xmpProfile != null)
211-
{
212-
this.WriteMetadataProfile(stream, xmpBytes, WebpChunkType.Xmp);
213-
}
214144
}
215145

216146
/// <summary>

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using SixLabors.ImageSharp.Memory;
1111
using SixLabors.ImageSharp.Metadata;
1212
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
13+
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
1314
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
1415
using SixLabors.ImageSharp.PixelFormats;
1516

@@ -265,8 +266,22 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
265266
// Encode the main image stream.
266267
this.EncodeStream(image.Frames.RootFrame);
267268

269+
this.bitWriter.Finish();
270+
this.bitWriter.WriteTrunksBeforeData(
271+
stream,
272+
(uint)width,
273+
(uint)height,
274+
exifProfile,
275+
xmpProfile,
276+
metadata.IccProfile,
277+
false /*hasAlpha*/,
278+
Span<byte>.Empty,
279+
false);
280+
268281
// Write bytes from the bitwriter buffer to the stream.
269-
this.bitWriter.WriteEncodedImageToStream(stream, exifProfile, xmpProfile, metadata.IccProfile, (uint)width, (uint)height, hasAlpha);
282+
this.bitWriter.WriteEncodedImageToStream(stream);
283+
284+
this.bitWriter.WriteTrunksAfterData(stream, exifProfile, xmpProfile);
270285
}
271286

272287
/// <summary>

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using SixLabors.ImageSharp.Memory;
99
using SixLabors.ImageSharp.Metadata;
1010
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
11-
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
1211
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
1312
using SixLabors.ImageSharp.PixelFormats;
1413

0 commit comments

Comments
 (0)