|
|
@ -217,19 +217,18 @@ namespace SixLabors.ImageSharp.Formats.Png |
|
|
{ |
|
|
{ |
|
|
using (var deframeStream = new ZlibInflateStream(this.currentStream)) |
|
|
using (var deframeStream = new ZlibInflateStream(this.currentStream)) |
|
|
{ |
|
|
{ |
|
|
PngChunk currentChunk; |
|
|
while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) |
|
|
while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null) |
|
|
|
|
|
{ |
|
|
{ |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
switch (currentChunk.Type) |
|
|
switch (chunk.Type) |
|
|
{ |
|
|
{ |
|
|
case PngChunkTypes.Header: |
|
|
case PngChunkTypes.Header: |
|
|
this.ReadHeaderChunk(currentChunk.Data.Array); |
|
|
this.ReadHeaderChunk(chunk.Data.Array); |
|
|
this.ValidateHeader(); |
|
|
this.ValidateHeader(); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.Physical: |
|
|
case PngChunkTypes.Physical: |
|
|
this.ReadPhysicalChunk(metadata, currentChunk.Data.Array); |
|
|
this.ReadPhysicalChunk(metadata, chunk.Data.Array); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.Data: |
|
|
case PngChunkTypes.Data: |
|
|
if (image == null) |
|
|
if (image == null) |
|
|
@ -237,23 +236,23 @@ namespace SixLabors.ImageSharp.Formats.Png |
|
|
this.InitializeImage(metadata, out image); |
|
|
this.InitializeImage(metadata, out image); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
deframeStream.AllocateNewBytes(currentChunk.Length); |
|
|
deframeStream.AllocateNewBytes(chunk.Length); |
|
|
this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); |
|
|
this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); |
|
|
this.currentStream.Read(this.crcBuffer, 0, 4); |
|
|
this.currentStream.Read(this.crcBuffer, 0, 4); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.Palette: |
|
|
case PngChunkTypes.Palette: |
|
|
byte[] pal = new byte[currentChunk.Length]; |
|
|
byte[] pal = new byte[chunk.Length]; |
|
|
Buffer.BlockCopy(currentChunk.Data.Array, 0, pal, 0, currentChunk.Length); |
|
|
Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); |
|
|
this.palette = pal; |
|
|
this.palette = pal; |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.PaletteAlpha: |
|
|
case PngChunkTypes.PaletteAlpha: |
|
|
byte[] alpha = new byte[currentChunk.Length]; |
|
|
byte[] alpha = new byte[chunk.Length]; |
|
|
Buffer.BlockCopy(currentChunk.Data.Array, 0, alpha, 0, currentChunk.Length); |
|
|
Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); |
|
|
this.paletteAlpha = alpha; |
|
|
this.paletteAlpha = alpha; |
|
|
this.AssignTransparentMarkers(alpha); |
|
|
this.AssignTransparentMarkers(alpha); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.Text: |
|
|
case PngChunkTypes.Text: |
|
|
this.ReadTextChunk(metadata, currentChunk.Data.Array, currentChunk.Length); |
|
|
this.ReadTextChunk(metadata, chunk.Data.Array, chunk.Length); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.End: |
|
|
case PngChunkTypes.End: |
|
|
this.isEndChunkReached = true; |
|
|
this.isEndChunkReached = true; |
|
|
@ -263,10 +262,10 @@ namespace SixLabors.ImageSharp.Formats.Png |
|
|
finally |
|
|
finally |
|
|
{ |
|
|
{ |
|
|
// Data is rented in ReadChunkData()
|
|
|
// Data is rented in ReadChunkData()
|
|
|
if (currentChunk.Data != null) |
|
|
if (chunk.Data != null) |
|
|
{ |
|
|
{ |
|
|
currentChunk.Data.Dispose(); |
|
|
chunk.Data.Dispose(); |
|
|
currentChunk.Data = null; |
|
|
chunk.Data = null; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -297,25 +296,24 @@ namespace SixLabors.ImageSharp.Formats.Png |
|
|
this.currentStream.Skip(8); |
|
|
this.currentStream.Skip(8); |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
PngChunk currentChunk; |
|
|
while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) |
|
|
while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null) |
|
|
|
|
|
{ |
|
|
{ |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
switch (currentChunk.Type) |
|
|
switch (chunk.Type) |
|
|
{ |
|
|
{ |
|
|
case PngChunkTypes.Header: |
|
|
case PngChunkTypes.Header: |
|
|
this.ReadHeaderChunk(currentChunk.Data.Array); |
|
|
this.ReadHeaderChunk(chunk.Data.Array); |
|
|
this.ValidateHeader(); |
|
|
this.ValidateHeader(); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.Physical: |
|
|
case PngChunkTypes.Physical: |
|
|
this.ReadPhysicalChunk(metadata, currentChunk.Data.Array); |
|
|
this.ReadPhysicalChunk(metadata, chunk.Data.Array); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.Data: |
|
|
case PngChunkTypes.Data: |
|
|
this.SkipChunkDataAndCrc(currentChunk); |
|
|
this.SkipChunkDataAndCrc(chunk); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.Text: |
|
|
case PngChunkTypes.Text: |
|
|
this.ReadTextChunk(metadata, currentChunk.Data.Array, currentChunk.Length); |
|
|
this.ReadTextChunk(metadata, chunk.Data.Array, chunk.Length); |
|
|
break; |
|
|
break; |
|
|
case PngChunkTypes.End: |
|
|
case PngChunkTypes.End: |
|
|
this.isEndChunkReached = true; |
|
|
this.isEndChunkReached = true; |
|
|
@ -325,9 +323,9 @@ namespace SixLabors.ImageSharp.Formats.Png |
|
|
finally |
|
|
finally |
|
|
{ |
|
|
{ |
|
|
// Data is rented in ReadChunkData()
|
|
|
// Data is rented in ReadChunkData()
|
|
|
if (currentChunk.Data != null) |
|
|
if (chunk.Data != null) |
|
|
{ |
|
|
{ |
|
|
ArrayPool<byte>.Shared.Return(currentChunk.Data.Array); |
|
|
ArrayPool<byte>.Shared.Return(chunk.Data.Array); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -1208,36 +1206,40 @@ namespace SixLabors.ImageSharp.Formats.Png |
|
|
/// <returns>
|
|
|
/// <returns>
|
|
|
/// The <see cref="PngChunk"/>.
|
|
|
/// The <see cref="PngChunk"/>.
|
|
|
/// </returns>
|
|
|
/// </returns>
|
|
|
private PngChunk ReadChunk() |
|
|
private bool TryReadChunk(out PngChunk chunk) |
|
|
{ |
|
|
{ |
|
|
var chunk = new PngChunk(); |
|
|
int length = this.ReadChunkLength(); |
|
|
this.ReadChunkLength(chunk); |
|
|
|
|
|
|
|
|
|
|
|
if (chunk.Length == -1) |
|
|
if (length == -1) |
|
|
{ |
|
|
{ |
|
|
|
|
|
chunk = default; |
|
|
|
|
|
|
|
|
// IEND
|
|
|
// IEND
|
|
|
return null; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
chunk = new PngChunk(length); |
|
|
|
|
|
|
|
|
if (chunk.Length < 0 || chunk.Length > this.currentStream.Length - this.currentStream.Position) |
|
|
if (chunk.Length < 0 || chunk.Length > this.currentStream.Length - this.currentStream.Position) |
|
|
{ |
|
|
{ |
|
|
// Not a valid chunk so we skip back all but one of the four bytes we have just read.
|
|
|
// Not a valid chunk so we skip back all but one of the four bytes we have just read.
|
|
|
// That lets us read one byte at a time until we reach a known chunk.
|
|
|
// That lets us read one byte at a time until we reach a known chunk.
|
|
|
this.currentStream.Position -= 3; |
|
|
this.currentStream.Position -= 3; |
|
|
return chunk; |
|
|
|
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.ReadChunkType(chunk); |
|
|
this.ReadChunkType(chunk); |
|
|
|
|
|
|
|
|
if (chunk.Type == PngChunkTypes.Data) |
|
|
if (chunk.Type == PngChunkTypes.Data) |
|
|
{ |
|
|
{ |
|
|
return chunk; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.ReadChunkData(chunk); |
|
|
this.ReadChunkData(chunk); |
|
|
this.ReadChunkCrc(chunk); |
|
|
this.ReadChunkCrc(chunk); |
|
|
|
|
|
|
|
|
return chunk; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
@ -1314,21 +1316,19 @@ namespace SixLabors.ImageSharp.Formats.Png |
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Calculates the length of the given chunk.
|
|
|
/// Calculates the length of the given chunk.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
/// <param name="chunk">The chunk.</param>
|
|
|
|
|
|
/// <exception cref="ImageFormatException">
|
|
|
/// <exception cref="ImageFormatException">
|
|
|
/// Thrown if the input stream is not valid.
|
|
|
/// Thrown if the input stream is not valid.
|
|
|
/// </exception>
|
|
|
/// </exception>
|
|
|
private void ReadChunkLength(PngChunk chunk) |
|
|
private int ReadChunkLength() |
|
|
{ |
|
|
{ |
|
|
int numBytes = this.currentStream.Read(this.chunkLengthBuffer, 0, 4); |
|
|
int numBytes = this.currentStream.Read(this.chunkLengthBuffer, 0, 4); |
|
|
|
|
|
|
|
|
if (numBytes < 4) |
|
|
if (numBytes < 4) |
|
|
{ |
|
|
{ |
|
|
chunk.Length = -1; |
|
|
return -1; |
|
|
return; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
chunk.Length = BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer); |
|
|
return BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
|