diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
index 3cbe5a81dd..108b6ae6ed 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
@@ -31,6 +32,41 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
}
}
+ ///
+ /// 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.
+ ///
+ /// The rgb pixel row.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void ApplyHorizontalPrediction24Bit(Span rowSpan)
+ {
+ Span rowRgb = MemoryMarshal.Cast(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);
+ }
+ }
+
+ ///
+ /// Applies a horizontal predictor to a gray pixel row.
+ ///
+ /// The gray pixel row.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void ApplyHorizontalPrediction8Bit(Span rowSpan)
+ {
+ for (int x = rowSpan.Length - 1; x >= 1; x--)
+ {
+ rowSpan[x] -= rowSpan[x - 1];
+ }
+ }
+
private static void Undo8Bit(Span pixelBytes, int width)
{
var rowBytesCount = width;
diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
index 1ce03cf2eb..d427e9c668 100644
--- a/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
+++ b/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
@@ -7,9 +7,9 @@ using System.IO;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
-using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Png.Zlib;
+using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
@@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (useHorizontalPredictor)
{
- this.ApplyHorizontalPredictionRgb(rowSpan);
+ HorizontalPredictor.ApplyHorizontalPrediction24Bit(rowSpan);
}
deflateStream.Write(rowSpan);
@@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (useHorizontalPredictor)
{
- this.ApplyHorizontalPredictionRgb(rowSpan);
+ HorizontalPredictor.ApplyHorizontalPrediction24Bit(rowSpan);
}
rowSpan.CopyTo(pixels.Slice(y * image.Width * 3));
@@ -249,27 +249,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
return bytesWritten;
}
- ///
- /// 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.
- ///
- /// The rgb pixel row.
- private void ApplyHorizontalPredictionRgb(Span rowSpan)
- {
- Span rowRgb = MemoryMarshal.Cast(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);
- }
- }
-
///
/// Writes the image data as RGB with packed bits compression to the stream.
///
@@ -281,7 +260,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
where TPixel : unmanaged, IPixel
{
// 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);
Span compressedRowSpan = compressedRow.GetSpan();
int bytesWritten = 0;
@@ -527,7 +506,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (useHorizontalPredictor)
{
- this.ApplyHorizontalPredictionGray(rowSpan);
+ HorizontalPredictor.ApplyHorizontalPrediction8Bit(rowSpan);
}
deflateStream.Write(rowSpan);
@@ -562,7 +541,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
PixelOperations.Instance.ToL8Bytes(this.configuration, pixelRow, rowSpan, pixelRow.Length);
if (useHorizontalPredictor)
{
- this.ApplyHorizontalPredictionGray(rowSpan);
+ HorizontalPredictor.ApplyHorizontalPrediction8Bit(rowSpan);
}
rowSpan.CopyTo(pixels.Slice(y * image.Width));
@@ -577,18 +556,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
return bytesWritten;
}
- ///
- /// Applies a horizontal predictor to a gray pixel row.
- ///
- /// The gray pixel row.
- private void ApplyHorizontalPredictionGray(Span rowSpan)
- {
- for (int x = rowSpan.Length - 1; x >= 1; x--)
- {
- rowSpan[x] -= rowSpan[x - 1];
- }
- }
-
///
/// Writes the image data as 8 bit gray to the stream.
///