|
|
|
@ -178,7 +178,7 @@ namespace ImageSharp.Formats |
|
|
|
/// <exception cref="ImageFormatException">
|
|
|
|
/// Thrown if the stream does not contain and end chunk.
|
|
|
|
/// </exception>
|
|
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
|
|
/// <exception cref="ArgumentOutOfRangeException">
|
|
|
|
/// Thrown if the image is larger than the maximum allowable size.
|
|
|
|
/// </exception>
|
|
|
|
/// <returns>The decoded image</returns>
|
|
|
|
@ -189,7 +189,6 @@ namespace ImageSharp.Formats |
|
|
|
this.currentStream = stream; |
|
|
|
this.currentStream.Skip(8); |
|
|
|
Image<TPixel> image = null; |
|
|
|
PixelAccessor<TPixel> pixels = null; |
|
|
|
try |
|
|
|
{ |
|
|
|
using (var deframeStream = new ZlibInflateStream(this.currentStream)) |
|
|
|
@ -211,11 +210,11 @@ namespace ImageSharp.Formats |
|
|
|
case PngChunkTypes.Data: |
|
|
|
if (image == null) |
|
|
|
{ |
|
|
|
this.InitializeImage(metadata, out image, out pixels); |
|
|
|
this.InitializeImage(metadata, out image); |
|
|
|
} |
|
|
|
|
|
|
|
deframeStream.AllocateNewBytes(currentChunk.Length); |
|
|
|
this.ReadScanlines(deframeStream.CompressedStream, pixels); |
|
|
|
this.ReadScanlines(deframeStream.CompressedStream, image); |
|
|
|
stream.Read(this.crcBuffer, 0, 4); |
|
|
|
break; |
|
|
|
case PngChunkTypes.Palette: |
|
|
|
@ -252,7 +251,6 @@ namespace ImageSharp.Formats |
|
|
|
} |
|
|
|
finally |
|
|
|
{ |
|
|
|
pixels?.Dispose(); |
|
|
|
this.scanline?.Dispose(); |
|
|
|
this.previousScanline?.Dispose(); |
|
|
|
} |
|
|
|
@ -324,8 +322,7 @@ namespace ImageSharp.Formats |
|
|
|
/// <typeparam name="TPixel">The type the pixels will be</typeparam>
|
|
|
|
/// <param name="metadata">The metadata information for the image</param>
|
|
|
|
/// <param name="image">The image that we will populate</param>
|
|
|
|
/// <param name="pixels">The pixel accessor</param>
|
|
|
|
private void InitializeImage<TPixel>(ImageMetaData metadata, out Image<TPixel> image, out PixelAccessor<TPixel> pixels) |
|
|
|
private void InitializeImage<TPixel>(ImageMetaData metadata, out Image<TPixel> image) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
if (this.header.Width > Image<TPixel>.MaxWidth || this.header.Height > Image<TPixel>.MaxHeight) |
|
|
|
@ -334,7 +331,6 @@ namespace ImageSharp.Formats |
|
|
|
} |
|
|
|
|
|
|
|
image = new Image<TPixel>(this.configuration, this.header.Width, this.header.Height, metadata); |
|
|
|
pixels = image.Lock(); |
|
|
|
this.bytesPerPixel = this.CalculateBytesPerPixel(); |
|
|
|
this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1; |
|
|
|
this.bytesPerSample = 1; |
|
|
|
@ -398,17 +394,17 @@ namespace ImageSharp.Formats |
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
|
|
/// <param name="dataStream">The <see cref="MemoryStream"/> containing data.</param>
|
|
|
|
/// <param name="pixels"> The pixel data.</param>
|
|
|
|
private void ReadScanlines<TPixel>(Stream dataStream, PixelAccessor<TPixel> pixels) |
|
|
|
/// <param name="image"> The pixel data.</param>
|
|
|
|
private void ReadScanlines<TPixel>(Stream dataStream, Image<TPixel> image) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) |
|
|
|
{ |
|
|
|
this.DecodeInterlacedPixelData(dataStream, pixels); |
|
|
|
this.DecodeInterlacedPixelData(dataStream, image); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
this.DecodePixelData(dataStream, pixels); |
|
|
|
this.DecodePixelData(dataStream, image); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -417,8 +413,8 @@ namespace ImageSharp.Formats |
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
|
|
/// <param name="compressedStream">The compressed pixel data stream.</param>
|
|
|
|
/// <param name="pixels">The image pixel accessor.</param>
|
|
|
|
private void DecodePixelData<TPixel>(Stream compressedStream, PixelAccessor<TPixel> pixels) |
|
|
|
/// <param name="image">The image to decode to.</param>
|
|
|
|
private void DecodePixelData<TPixel>(Stream compressedStream, Image<TPixel> image) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
while (this.currentRow < this.header.Height) |
|
|
|
@ -462,7 +458,7 @@ namespace ImageSharp.Formats |
|
|
|
throw new ImageFormatException("Unknown filter type."); |
|
|
|
} |
|
|
|
|
|
|
|
this.ProcessDefilteredScanline(this.scanline.Array, pixels); |
|
|
|
this.ProcessDefilteredScanline(this.scanline.Array, image); |
|
|
|
|
|
|
|
Swap(ref this.scanline, ref this.previousScanline); |
|
|
|
this.currentRow++; |
|
|
|
@ -475,8 +471,8 @@ namespace ImageSharp.Formats |
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
|
|
/// <param name="compressedStream">The compressed pixel data stream.</param>
|
|
|
|
/// <param name="pixels">The image pixel accessor.</param>
|
|
|
|
private void DecodeInterlacedPixelData<TPixel>(Stream compressedStream, PixelAccessor<TPixel> pixels) |
|
|
|
/// <param name="image">The current image.</param>
|
|
|
|
private void DecodeInterlacedPixelData<TPixel>(Stream compressedStream, Image<TPixel> image) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
while (true) |
|
|
|
@ -537,7 +533,8 @@ namespace ImageSharp.Formats |
|
|
|
throw new ImageFormatException("Unknown filter type."); |
|
|
|
} |
|
|
|
|
|
|
|
this.ProcessInterlacedDefilteredScanline(this.scanline.Array, this.currentRow, pixels, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]); |
|
|
|
Span<TPixel> rowSpan = image.GetRowSpan(this.currentRow); |
|
|
|
this.ProcessInterlacedDefilteredScanline(this.scanline.Array, rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]); |
|
|
|
|
|
|
|
Swap(ref this.scanline, ref this.previousScanline); |
|
|
|
|
|
|
|
@ -561,12 +558,12 @@ namespace ImageSharp.Formats |
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
|
|
/// <param name="defilteredScanline">The de-filtered scanline</param>
|
|
|
|
/// <param name="pixels">The image pixels</param>
|
|
|
|
private void ProcessDefilteredScanline<TPixel>(byte[] defilteredScanline, PixelAccessor<TPixel> pixels) |
|
|
|
/// <param name="pixels">The image</param>
|
|
|
|
private void ProcessDefilteredScanline<TPixel>(byte[] defilteredScanline, Image<TPixel> pixels) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
var color = default(TPixel); |
|
|
|
Span<TPixel> pixelBuffer = pixels.GetRowSpan(this.currentRow); |
|
|
|
Span<TPixel> rowSpan = pixels.GetRowSpan(this.currentRow); |
|
|
|
var scanlineBuffer = new Span<byte>(defilteredScanline, 1); |
|
|
|
|
|
|
|
switch (this.PngColorType) |
|
|
|
@ -578,7 +575,7 @@ namespace ImageSharp.Formats |
|
|
|
{ |
|
|
|
byte intensity = (byte)(newScanline1[x] * factor); |
|
|
|
color.PackFromBytes(intensity, intensity, intensity, 255); |
|
|
|
pixels[x, this.currentRow] = color; |
|
|
|
rowSpan[x] = color; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
@ -593,26 +590,26 @@ namespace ImageSharp.Formats |
|
|
|
byte alpha = defilteredScanline[offset + this.bytesPerSample]; |
|
|
|
|
|
|
|
color.PackFromBytes(intensity, intensity, intensity, alpha); |
|
|
|
pixels[x, this.currentRow] = color; |
|
|
|
rowSpan[x] = color; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case PngColorType.Palette: |
|
|
|
|
|
|
|
this.ProcessScanlineFromPalette(defilteredScanline, pixels); |
|
|
|
this.ProcessScanlineFromPalette(defilteredScanline, rowSpan); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case PngColorType.Rgb: |
|
|
|
|
|
|
|
PixelOperations<TPixel>.Instance.PackFromXyzBytes(scanlineBuffer, pixelBuffer, this.header.Width); |
|
|
|
PixelOperations<TPixel>.Instance.PackFromXyzBytes(scanlineBuffer, rowSpan, this.header.Width); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case PngColorType.RgbWithAlpha: |
|
|
|
|
|
|
|
PixelOperations<TPixel>.Instance.PackFromXyzwBytes(scanlineBuffer, pixelBuffer, this.header.Width); |
|
|
|
PixelOperations<TPixel>.Instance.PackFromXyzwBytes(scanlineBuffer, rowSpan, this.header.Width); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
@ -623,8 +620,8 @@ namespace ImageSharp.Formats |
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TPixel">The type of pixel we are expanding to</typeparam>
|
|
|
|
/// <param name="defilteredScanline">The scanline</param>
|
|
|
|
/// <param name="pixels">The output pixels</param>
|
|
|
|
private void ProcessScanlineFromPalette<TPixel>(byte[] defilteredScanline, PixelAccessor<TPixel> pixels) |
|
|
|
/// <param name="row">Thecurrent output image row</param>
|
|
|
|
private void ProcessScanlineFromPalette<TPixel>(byte[] defilteredScanline, Span<TPixel> row) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); |
|
|
|
@ -654,7 +651,7 @@ namespace ImageSharp.Formats |
|
|
|
color.PackFromBytes(0, 0, 0, 0); |
|
|
|
} |
|
|
|
|
|
|
|
pixels[x, this.currentRow] = color; |
|
|
|
row[x] = color; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
@ -669,7 +666,7 @@ namespace ImageSharp.Formats |
|
|
|
byte b = palette[pixelOffset + 2]; |
|
|
|
|
|
|
|
color.PackFromBytes(r, g, b, 255); |
|
|
|
pixels[x, this.currentRow] = color; |
|
|
|
row[x] = color; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -679,11 +676,10 @@ namespace ImageSharp.Formats |
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
|
|
/// <param name="defilteredScanline">The de-filtered scanline</param>
|
|
|
|
/// <param name="row">The current image row.</param>
|
|
|
|
/// <param name="pixels">The image pixels</param>
|
|
|
|
/// <param name="rowSpan">The current image row.</param>
|
|
|
|
/// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</param>
|
|
|
|
/// <param name="increment">The column increment. Always 1 for none interlaced images.</param>
|
|
|
|
private void ProcessInterlacedDefilteredScanline<TPixel>(byte[] defilteredScanline, int row, PixelAccessor<TPixel> pixels, int pixelOffset = 0, int increment = 1) |
|
|
|
private void ProcessInterlacedDefilteredScanline<TPixel>(byte[] defilteredScanline, Span<TPixel> rowSpan, int pixelOffset = 0, int increment = 1) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
var color = default(TPixel); |
|
|
|
@ -697,7 +693,7 @@ namespace ImageSharp.Formats |
|
|
|
{ |
|
|
|
byte intensity = (byte)(newScanline1[o] * factor); |
|
|
|
color.PackFromBytes(intensity, intensity, intensity, 255); |
|
|
|
pixels[x, row] = color; |
|
|
|
rowSpan[x] = color; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
@ -710,7 +706,7 @@ namespace ImageSharp.Formats |
|
|
|
byte alpha = defilteredScanline[o + this.bytesPerSample]; |
|
|
|
|
|
|
|
color.PackFromBytes(intensity, intensity, intensity, alpha); |
|
|
|
pixels[x, row] = color; |
|
|
|
rowSpan[x] = color; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
@ -742,7 +738,7 @@ namespace ImageSharp.Formats |
|
|
|
color.PackFromBytes(0, 0, 0, 0); |
|
|
|
} |
|
|
|
|
|
|
|
pixels[x, row] = color; |
|
|
|
rowSpan[x] = color; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
@ -757,7 +753,7 @@ namespace ImageSharp.Formats |
|
|
|
byte b = this.palette[offset + 2]; |
|
|
|
|
|
|
|
color.PackFromBytes(r, g, b, 255); |
|
|
|
pixels[x, row] = color; |
|
|
|
rowSpan[x] = color; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -772,7 +768,7 @@ namespace ImageSharp.Formats |
|
|
|
byte b = defilteredScanline[o + (2 * this.bytesPerSample)]; |
|
|
|
|
|
|
|
color.PackFromBytes(r, g, b, 255); |
|
|
|
pixels[x, row] = color; |
|
|
|
rowSpan[x] = color; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
@ -787,7 +783,7 @@ namespace ImageSharp.Formats |
|
|
|
byte a = defilteredScanline[o + (3 * this.bytesPerSample)]; |
|
|
|
|
|
|
|
color.PackFromBytes(r, g, b, a); |
|
|
|
pixels[x, row] = color; |
|
|
|
rowSpan[x] = color; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|