Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
0c45f37
Merge pull request #1 from SixLabors/master
ynse01 Apr 1, 2021
319beee
Merge branch 'SixLabors:master' into master
ynse01 Nov 17, 2021
065cb1c
Fix vanilla build on VS2019
ynse01 Nov 17, 2021
251e802
Revert of: Fix vanilla build on VS2019
ynse01 Nov 18, 2021
49d9266
Merge branch 'master' of https://github.com/ynse01/ImageSharp
ynse01 Nov 18, 2021
100e788
Merge branch 'SixLabors:master' into master
ynse01 Nov 18, 2021
a13eae6
Merge branch 'SixLabors:master' into master
ynse01 Nov 24, 2021
7510250
Support Pbm, Pgm and Ppm images
ynse01 Nov 24, 2021
b87362d
Fix style warning in BinaryDecoder
ynse01 Nov 25, 2021
5939bf8
Restore LangVersion
ynse01 Nov 25, 2021
0c8c892
Process first round of review comments
ynse01 Nov 27, 2021
0e984cf
Remove non existing LFS objects
ynse01 Nov 28, 2021
e21d2c3
Put back missing LFS objects
ynse01 Nov 28, 2021
7d1c3b5
Remove test images, so they can be moved to LFS
ynse01 Nov 29, 2021
c600274
Merge branch 'SixLabors:master' into pgm-support
ynse01 Nov 29, 2021
593c84c
Merge branch 'pgm-support' of https://github.com/ynse01/ImageSharp in…
ynse01 Nov 29, 2021
2b00a22
Put the test images back into LFS
ynse01 Nov 29, 2021
9599efe
Update .gitattributes file
ynse01 Nov 29, 2021
58a1dd8
Merge branch 'master' into pgm-support
JimBobSquarePants Nov 30, 2021
cf8e184
Revert stack allocation in Plain Encoder
ynse01 Nov 30, 2021
87ce4e5
Various review comments
ynse01 Dec 1, 2021
a5e1723
Dispose of images after use, in Pbm Round Trip Test
ynse01 Dec 1, 2021
e17ebe6
Merge branch 'master' into pgm-support
JimBobSquarePants Dec 1, 2021
26b3e66
Fix bug in black and white plain decoding
ynse01 Dec 3, 2021
5587770
Merge branch 'pgm-support' of https://github.com/ynse01/ImageSharp in…
ynse01 Dec 3, 2021
c4cf012
Scale pixel value up to full allocation range
ynse01 Dec 3, 2021
a5af74e
Merge branch 'master' into pgm-support
antonfirsov Dec 4, 2021
284772c
Push input images to LFS again
ynse01 Dec 4, 2021
20b0349
NeedsUpscaling code improvements
ynse01 Dec 4, 2021
3a0a044
Improve exception messages
ynse01 Dec 4, 2021
61cfa66
Make variables as const if possible
ynse01 Dec 4, 2021
5e27397
Merge branch 'master' into pgm-support
brianpopow Dec 4, 2021
dd49f9a
Single image compare utils for multiple Formats
ynse01 Dec 5, 2021
1aa27bd
Add Magick compatible input image
ynse01 Dec 5, 2021
093e1ae
Add missing using
brianpopow Dec 5, 2021
f09641c
Cleanup
brianpopow Dec 5, 2021
a581ab6
Merge branch 'master' into pgm-support
brianpopow Dec 6, 2021
f6301d4
Refactor Pbm option enums
ynse01 Dec 8, 2021
7494525
Write EOF indicated for plain encoding
ynse01 Dec 10, 2021
b2bc25c
No need to await async PbmDecoder methods
ynse01 Dec 10, 2021
efece70
Partial revert of b2bc25c
ynse01 Dec 10, 2021
6619809
Merge remote-tracking branch 'upstream/master' into pgm-support
ynse01 Dec 10, 2021
3730a02
Fix build after merge
ynse01 Dec 10, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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