Browse Source

Move apply horizontal prediction to appropriate class

pull/1467/head
Brian Popow 6 years ago
parent
commit
ad425f452f
  1. 36
      src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
  2. 45
      src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs

36
src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -31,6 +32,41 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
} }
} }
/// <summary>
/// Applies a horizontal predictor to the rgb row.
/// Make use of the fact that many continuous-tone images rarely vary much in pixel value from one pixel to the next.
/// In such images, if we replace the pixel values by differences between consecutive pixels, many of the differences should be 0, plus
/// or minus 1, and so on.This reduces the apparent information content and allows LZW to encode the data more compactly.
/// </summary>
/// <param name="rowSpan">The rgb pixel row.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ApplyHorizontalPrediction24Bit(Span<byte> rowSpan)
{
Span<Rgb24> rowRgb = MemoryMarshal.Cast<byte, Rgb24>(rowSpan);
for (int x = rowRgb.Length - 1; x >= 1; x--)
{
byte r = (byte)(rowRgb[x].R - rowRgb[x - 1].R);
byte g = (byte)(rowRgb[x].G - rowRgb[x - 1].G);
byte b = (byte)(rowRgb[x].B - rowRgb[x - 1].B);
var rgb = new Rgb24(r, g, b);
rowRgb[x].FromRgb24(rgb);
}
}
/// <summary>
/// Applies a horizontal predictor to a gray pixel row.
/// </summary>
/// <param name="rowSpan">The gray pixel row.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ApplyHorizontalPrediction8Bit(Span<byte> rowSpan)
{
for (int x = rowSpan.Length - 1; x >= 1; x--)
{
rowSpan[x] -= rowSpan[x - 1];
}
}
private static void Undo8Bit(Span<byte> pixelBytes, int width) private static void Undo8Bit(Span<byte> pixelBytes, int width)
{ {
var rowBytesCount = width; var rowBytesCount = width;

45
src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs

@ -7,9 +7,9 @@ using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Formats.Png.Zlib;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (useHorizontalPredictor) if (useHorizontalPredictor)
{ {
this.ApplyHorizontalPredictionRgb(rowSpan); HorizontalPredictor.ApplyHorizontalPrediction24Bit(rowSpan);
} }
deflateStream.Write(rowSpan); deflateStream.Write(rowSpan);
@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (useHorizontalPredictor) if (useHorizontalPredictor)
{ {
this.ApplyHorizontalPredictionRgb(rowSpan); HorizontalPredictor.ApplyHorizontalPrediction24Bit(rowSpan);
} }
rowSpan.CopyTo(pixels.Slice(y * image.Width * 3)); rowSpan.CopyTo(pixels.Slice(y * image.Width * 3));
@ -249,27 +249,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
return bytesWritten; return bytesWritten;
} }
/// <summary>
/// Applies a horizontal predictor to the rgb row.
/// Make use of the fact that many continuous-tone images rarely vary much in pixel value from one pixel to the next.
/// In such images, if we replace the pixel values by differences between consecutive pixels, many of the differences should be 0, plus
/// or minus 1, and so on.This reduces the apparent information content and allows LZW to encode the data more compactly.
/// </summary>
/// <param name="rowSpan">The rgb pixel row.</param>
private void ApplyHorizontalPredictionRgb(Span<byte> rowSpan)
{
Span<Rgb24> rowRgb = MemoryMarshal.Cast<byte, Rgb24>(rowSpan);
for (int x = rowRgb.Length - 1; x >= 1; x--)
{
byte r = (byte)(rowRgb[x].R - rowRgb[x - 1].R);
byte g = (byte)(rowRgb[x].G - rowRgb[x - 1].G);
byte b = (byte)(rowRgb[x].B - rowRgb[x - 1].B);
var rgb = new Rgb24(r, g, b);
rowRgb[x].FromRgb24(rgb);
}
}
/// <summary> /// <summary>
/// Writes the image data as RGB with packed bits compression to the stream. /// Writes the image data as RGB with packed bits compression to the stream.
/// </summary> /// </summary>
@ -281,7 +260,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
// Worst case is that the actual compressed data is larger then the input data. In this case we need 1 additional byte per 127 bytes. // Worst case is that the actual compressed data is larger then the input data. In this case we need 1 additional byte per 127 bytes.
int additionalBytes = (image.Width * 3 / 127) + 1; int additionalBytes = ((image.Width * 3) / 127) + 1;
using IManagedByteBuffer compressedRow = this.memoryAllocator.AllocateManagedByteBuffer((image.Width * 3) + additionalBytes, AllocationOptions.Clean); using IManagedByteBuffer compressedRow = this.memoryAllocator.AllocateManagedByteBuffer((image.Width * 3) + additionalBytes, AllocationOptions.Clean);
Span<byte> compressedRowSpan = compressedRow.GetSpan(); Span<byte> compressedRowSpan = compressedRow.GetSpan();
int bytesWritten = 0; int bytesWritten = 0;
@ -527,7 +506,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (useHorizontalPredictor) if (useHorizontalPredictor)
{ {
this.ApplyHorizontalPredictionGray(rowSpan); HorizontalPredictor.ApplyHorizontalPrediction8Bit(rowSpan);
} }
deflateStream.Write(rowSpan); deflateStream.Write(rowSpan);
@ -562,7 +541,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
PixelOperations<TPixel>.Instance.ToL8Bytes(this.configuration, pixelRow, rowSpan, pixelRow.Length); PixelOperations<TPixel>.Instance.ToL8Bytes(this.configuration, pixelRow, rowSpan, pixelRow.Length);
if (useHorizontalPredictor) if (useHorizontalPredictor)
{ {
this.ApplyHorizontalPredictionGray(rowSpan); HorizontalPredictor.ApplyHorizontalPrediction8Bit(rowSpan);
} }
rowSpan.CopyTo(pixels.Slice(y * image.Width)); rowSpan.CopyTo(pixels.Slice(y * image.Width));
@ -577,18 +556,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
return bytesWritten; return bytesWritten;
} }
/// <summary>
/// Applies a horizontal predictor to a gray pixel row.
/// </summary>
/// <param name="rowSpan">The gray pixel row.</param>
private void ApplyHorizontalPredictionGray(Span<byte> rowSpan)
{
for (int x = rowSpan.Length - 1; x >= 1; x--)
{
rowSpan[x] -= rowSpan[x - 1];
}
}
/// <summary> /// <summary>
/// Writes the image data as 8 bit gray to the stream. /// Writes the image data as 8 bit gray to the stream.
/// </summary> /// </summary>

Loading…
Cancel
Save