Browse Source

Add option to write bi-level tiff's

pull/1570/head
Brian Popow 5 years ago
parent
commit
11abaeff60
  1. 4
      src/ImageSharp/Formats/Tiff/README.md
  2. 9
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  3. 5
      src/ImageSharp/Formats/Tiff/TiffEncodingMode.cs
  4. 54
      src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs

4
src/ImageSharp/Formats/Tiff/README.md

@ -57,8 +57,8 @@
|---------------------------|:-----:|:-----:|--------------------------|
|WhiteIsZero | | Y | General + 1/4/8-bit optimised implementations |
|BlackIsZero | | Y | General + 1/4/8-bit optimised implementations |
|Rgb (Chunky) | | Y | General + Rgb888 optimised implementation |
|Rgb (Planar) | Y | Y | General implementation only |
|Rgb (Chunky) | Y | Y | General + Rgb888 optimised implementation |
|Rgb (Planar) | | Y | General implementation only |
|PaletteColor | Y | Y | General implementation only |
|TransparencyMask | | | |
|Separated (TIFF Extension) | | | |

9
src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs

@ -158,6 +158,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffEncodingMode.Gray:
imageDataBytes = writer.WriteGray(image, this.padding, this.CompressionType);
break;
case TiffEncodingMode.BiColor:
imageDataBytes = writer.WriteBiColor(image);
break;
default:
imageDataBytes = writer.WriteRgbImageData(image, this.padding, this.CompressionType);
break;
@ -337,6 +340,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffEncodingMode.ColorPalette:
this.PhotometricInterpretation = TiffPhotometricInterpretation.PaletteColor;
break;
case TiffEncodingMode.BiColor:
case TiffEncodingMode.Gray:
this.PhotometricInterpretation = TiffPhotometricInterpretation.BlackIsZero;
break;
@ -369,6 +373,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffPhotometricInterpretation.Rgb:
return new ushort[] { 8, 8, 8 };
case TiffPhotometricInterpretation.BlackIsZero:
if (this.Mode == TiffEncodingMode.BiColor)
{
return new ushort[] { 1 };
}
return new ushort[] { 8 };
default:
return new ushort[] { 8, 8, 8 };

5
src/ImageSharp/Formats/Tiff/TiffEncodingMode.cs

@ -27,5 +27,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// The image will be encoded as 8 bit gray.
/// </summary>
Gray = 3,
/// <summary>
/// The image will be written as a white and black image.
/// </summary>
BiColor = 4,
}
}

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

@ -12,6 +12,8 @@ using SixLabors.ImageSharp.Formats.Png.Zlib;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
namespace SixLabors.ImageSharp.Formats.Tiff
@ -199,6 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="image">The image to write to the stream.</param>
/// <param name="quantizer">The quantizer to use.</param>
/// <param name="padding">The padding bytes for each row.</param>
/// <param name="compression">The compression to use.</param>
/// <param name="colorMap">The color map.</param>
/// <returns>The number of bytes written.</returns>
public int WritePalettedRgb<TPixel>(Image<TPixel> image, IQuantizer quantizer, int padding, TiffEncoderCompression compression, out IExifValue colorMap)
@ -328,7 +331,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// Writes the image data as 8 bit gray with deflate compression to the stream.
/// </summary>
/// <param name="image">The image to write to the stream.</param>
/// <param name="rowSpan">A span of a pixel row.</param>
/// <param name="rowSpan">A span of a row of pixels.</param>
/// <returns>The number of bytes written.</returns>
private int WriteGrayDeflateCompressed<TPixel>(Image<TPixel> image, Span<byte> rowSpan)
where TPixel : unmanaged, IPixel<TPixel>
@ -337,8 +340,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
using var memoryStream = new MemoryStream();
// TODO: move zlib compression from png to a common place?
using var deflateStream =
new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable
for (int y = 0; y < image.Height; y++)
{
@ -355,6 +357,52 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return bytesWritten;
}
public int WriteBiColor<TPixel>(Image<TPixel> image)
where TPixel : unmanaged, IPixel<TPixel>
{
int padding = image.Width % 8 == 0 ? 0 : 1;
int bytesPerRow = (image.Width / 8) + padding;
using IMemoryOwner<Rgb24> rowRgb = this.memoryAllocator.Allocate<Rgb24>(image.Width);
using IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(bytesPerRow, AllocationOptions.Clean);
Span<byte> rowSpan = row.GetSpan();
Span<Rgb24> rowRgbSpan = rowRgb.GetSpan();
// Convert image to black and white.
using Image<TPixel> imageClone = image.Clone();
imageClone.Mutate(img => img.BinaryDither(default(ErrorDither)));
int bytesWritten = 0;
for (int y = 0; y < image.Height; y++)
{
int bitIndex = 0;
int byteIndex = 0;
Span<TPixel> pixelRow = imageClone.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToRgb24(this.configuration, pixelRow, rowRgbSpan);
for (int x = 0; x < pixelRow.Length; x++)
{
int shift = 7 - bitIndex;
if (rowRgbSpan[x].R == 255)
{
rowSpan[byteIndex] |= (byte)(1 << shift);
}
bitIndex++;
if (bitIndex == 8)
{
byteIndex++;
bitIndex = 0;
}
}
this.output.Write(row);
bytesWritten += row.Length();
row.Clear();
}
return bytesWritten;
}
private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel, int padding) => this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, padding);
/// <summary>

Loading…
Cancel
Save