Skip to content

Commit

Permalink
Merge branch 'master' into bp/removeRunSerial
Browse files Browse the repository at this point in the history
  • Loading branch information
JimBobSquarePants authored Dec 12, 2021
2 parents 9473582 + ca8e984 commit edf7014
Show file tree
Hide file tree
Showing 60 changed files with 2,553 additions and 121 deletions.
5 changes: 5 additions & 0 deletions src/ImageSharp/Advanced/AotCompilerTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Tiff;
Expand Down Expand Up @@ -200,6 +201,7 @@ private static void AotCompileImageEncoderInternals<TPixel>()
default(BmpEncoderCore).Encode<TPixel>(default, default, default);
default(GifEncoderCore).Encode<TPixel>(default, default, default);
default(JpegEncoderCore).Encode<TPixel>(default, default, default);
default(PbmEncoderCore).Encode<TPixel>(default, default, default);
default(PngEncoderCore).Encode<TPixel>(default, default, default);
default(TgaEncoderCore).Encode<TPixel>(default, default, default);
default(TiffEncoderCore).Encode<TPixel>(default, default, default);
Expand All @@ -217,6 +219,7 @@ private static void AotCompileImageDecoderInternals<TPixel>()
default(BmpDecoderCore).Decode<TPixel>(default, default, default);
default(GifDecoderCore).Decode<TPixel>(default, default, default);
default(JpegDecoderCore).Decode<TPixel>(default, default, default);
default(PbmDecoderCore).Decode<TPixel>(default, default, default);
default(PngDecoderCore).Decode<TPixel>(default, default, default);
default(TgaDecoderCore).Decode<TPixel>(default, default, default);
default(TiffDecoderCore).Decode<TPixel>(default, default, default);
Expand All @@ -234,6 +237,7 @@ private static void AotCompileImageEncoders<TPixel>()
AotCompileImageEncoder<TPixel, BmpEncoder>();
AotCompileImageEncoder<TPixel, GifEncoder>();
AotCompileImageEncoder<TPixel, JpegEncoder>();
AotCompileImageEncoder<TPixel, PbmEncoder>();
AotCompileImageEncoder<TPixel, PngEncoder>();
AotCompileImageEncoder<TPixel, TgaEncoder>();
AotCompileImageEncoder<TPixel, TiffEncoder>();
Expand All @@ -251,6 +255,7 @@ private static void AotCompileImageDecoders<TPixel>()
AotCompileImageDecoder<TPixel, BmpDecoder>();
AotCompileImageDecoder<TPixel, GifDecoder>();
AotCompileImageDecoder<TPixel, JpegDecoder>();
AotCompileImageDecoder<TPixel, PbmDecoder>();
AotCompileImageDecoder<TPixel, PngDecoder>();
AotCompileImageDecoder<TPixel, TgaDecoder>();
AotCompileImageDecoder<TPixel, TiffDecoder>();
Expand Down
3 changes: 3 additions & 0 deletions src/ImageSharp/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Tiff;
Expand Down Expand Up @@ -209,6 +210,7 @@ public void Configure(IConfigurationModule configuration)
/// <see cref="JpegConfigurationModule"/>
/// <see cref="GifConfigurationModule"/>
/// <see cref="BmpConfigurationModule"/>.
/// <see cref="PbmConfigurationModule"/>.
/// <see cref="TgaConfigurationModule"/>.
/// <see cref="TiffConfigurationModule"/>.
/// <see cref="WebpConfigurationModule"/>.
Expand All @@ -219,6 +221,7 @@ public void Configure(IConfigurationModule configuration)
new JpegConfigurationModule(),
new GifConfigurationModule(),
new BmpConfigurationModule(),
new PbmConfigurationModule(),
new TgaConfigurationModule(),
new TiffConfigurationModule(),
new WebpConfigurationModule());
Expand Down
104 changes: 104 additions & 0 deletions src/ImageSharp/Formats/ImageExtensions.Save.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Webp;
Expand Down Expand Up @@ -331,6 +332,109 @@ public static Task SaveAsJpegAsync(this Image source, Stream stream, JpegEncoder
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance),
cancellationToken);

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="path">The file path to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
public static void SaveAsPbm(this Image source, string path) => SaveAsPbm(source, path, null);

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="path">The file path to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsPbmAsync(this Image source, string path) => SaveAsPbmAsync(source, path, null);

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="path">The file path to save the image to.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsPbmAsync(this Image source, string path, CancellationToken cancellationToken)
=> SaveAsPbmAsync(source, path, null, cancellationToken);

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="path">The file path to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
public static void SaveAsPbm(this Image source, string path, PbmEncoder encoder) =>
source.Save(
path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance));

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="path">The file path to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsPbmAsync(this Image source, string path, PbmEncoder encoder, CancellationToken cancellationToken = default) =>
source.SaveAsync(
path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance),
cancellationToken);

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsPbm(this Image source, Stream stream)
=> SaveAsPbm(source, stream, null);

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsPbmAsync(this Image source, Stream stream, CancellationToken cancellationToken = default)
=> SaveAsPbmAsync(source, stream, null, cancellationToken);

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder)
=> source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance));

/// <summary>
/// Saves the image to the given stream with the Pbm format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsPbmAsync(this Image source, Stream stream, PbmEncoder encoder, CancellationToken cancellationToken = default) =>
source.SaveAsync(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance),
cancellationToken);

/// <summary>
/// Saves the image to the given stream with the Png format.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/ImageSharp/Formats/ImageExtensions.Save.tt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ using SixLabors.ImageSharp.Advanced;
"Bmp",
"Gif",
"Jpeg",
"Pbm",
"Png",
"Tga",
"Webp",
Expand Down
194 changes: 194 additions & 0 deletions src/ImageSharp/Formats/Pbm/BinaryDecoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Buffers;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;

namespace SixLabors.ImageSharp.Formats.Pbm
{
/// <summary>
/// Pixel decoding methods for the PBM binary encoding.
/// </summary>
internal class BinaryDecoder
{
private static L8 white = new(255);
private static L8 black = new(0);

/// <summary>
/// Decode the specified pixels.
/// </summary>
/// <typeparam name="TPixel">The type of pixel to encode to.</typeparam>
/// <param name="configuration">The configuration.</param>
/// <param name="pixels">The pixel array to encode into.</param>
/// <param name="stream">The stream to read the data from.</param>
/// <param name="colorType">The ColorType to decode.</param>
/// <param name="componentType">Data type of the pixles components.</param>
/// <exception cref="InvalidImageContentException">
/// Thrown if an invalid combination of setting is requested.
/// </exception>
public static void Process<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream, PbmColorType colorType, PbmComponentType componentType)
where TPixel : unmanaged, IPixel<TPixel>
{
if (colorType == PbmColorType.Grayscale)
{
if (componentType == PbmComponentType.Byte)
{
ProcessGrayscale(configuration, pixels, stream);
}
else
{
ProcessWideGrayscale(configuration, pixels, stream);
}
}
else if (colorType == PbmColorType.Rgb)
{
if (componentType == PbmComponentType.Byte)
{
ProcessRgb(configuration, pixels, stream);
}
else
{
ProcessWideRgb(configuration, pixels, stream);
}
}
else
{
ProcessBlackAndWhite(configuration, pixels, stream);
}
}

private static void ProcessGrayscale<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
const int bytesPerPixel = 1;
int width = pixels.Width;
int height = pixels.Height;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner<byte> row = allocator.Allocate<byte>(width * bytesPerPixel);
Span<byte> rowSpan = row.GetSpan();

for (int y = 0; y < height; y++)
{
stream.Read(rowSpan);
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.FromL8Bytes(
configuration,
rowSpan,
pixelSpan,
width);
}
}

private static void ProcessWideGrayscale<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
const int bytesPerPixel = 2;
int width = pixels.Width;
int height = pixels.Height;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner<byte> row = allocator.Allocate<byte>(width * bytesPerPixel);
Span<byte> rowSpan = row.GetSpan();

for (int y = 0; y < height; y++)
{
stream.Read(rowSpan);
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.FromL16Bytes(
configuration,
rowSpan,
pixelSpan,
width);
}
}

private static void ProcessRgb<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
const int bytesPerPixel = 3;
int width = pixels.Width;
int height = pixels.Height;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner<byte> row = allocator.Allocate<byte>(width * bytesPerPixel);
Span<byte> rowSpan = row.GetSpan();

for (int y = 0; y < height; y++)
{
stream.Read(rowSpan);
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.FromRgb24Bytes(
configuration,
rowSpan,
pixelSpan,
width);
}
}

private static void ProcessWideRgb<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
const int bytesPerPixel = 6;
int width = pixels.Width;
int height = pixels.Height;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner<byte> row = allocator.Allocate<byte>(width * bytesPerPixel);
Span<byte> rowSpan = row.GetSpan();

for (int y = 0; y < height; y++)
{
stream.Read(rowSpan);
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.FromRgb48Bytes(
configuration,
rowSpan,
pixelSpan,
width);
}
}

private static void ProcessBlackAndWhite<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
int width = pixels.Width;
int height = pixels.Height;
int startBit = 0;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner<L8> row = allocator.Allocate<L8>(width);
Span<L8> rowSpan = row.GetSpan();

for (int y = 0; y < height; y++)
{
for (int x = 0; x < width;)
{
int raw = stream.ReadByte();
int bit = startBit;
startBit = 0;
for (; bit < 8; bit++)
{
bool bitValue = (raw & (0x80 >> bit)) != 0;
rowSpan[x] = bitValue ? black : white;
x++;
if (x == width)
{
startBit = (bit + 1) & 7; // Round off to below 8.
if (startBit != 0)
{
stream.Seek(-1, System.IO.SeekOrigin.Current);
}

break;
}
}
}

Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.FromL8(
configuration,
rowSpan,
pixelSpan);
}
}
}
}
Loading

0 comments on commit edf7014

Please sign in to comment.