Skip to content

Commit

Permalink
v1.0.6 add support for loading bgra32 format and fix save bug for alpha
Browse files Browse the repository at this point in the history
there was a bug when the image could use a palette but also had an
alpha channel which meant the output image was invalid.
  • Loading branch information
EliotJones committed May 1, 2021
1 parent 86e579b commit a1fad87
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/BigGustave/BigGustave.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PackageIcon>uglytoad.png</PackageIcon>
<PackageLicenseExpression>Unlicense</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/EliotJones/BigGustave</PackageProjectUrl>
<Version>1.0.5</Version>
<Version>1.0.6</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
63 changes: 62 additions & 1 deletion src/BigGustave/PngBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,67 @@ public static PngBuilder FromPngBytes(byte[] png)
return FromPng(pngActual);
}

/// <summary>
/// Create a builder from the bytes in the BGRA32 pixel format.
/// https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.pixelformats.bgra32
/// </summary>
/// <param name="data">The pixels in BGRA32 format.</param>
/// <param name="width">The width in pixels.</param>
/// <param name="height">The height in pixels.</param>
/// <param name="useAlphaChannel">Whether to include an alpha channel in the output.</param>
public static PngBuilder FromBgra32Pixels(byte[] data, int width, int height, bool useAlphaChannel = true)
{
using (var memoryStream = new MemoryStream(data))
{
var builder = FromBgra32Pixels(memoryStream, width, height, useAlphaChannel);

return builder;
}
}

/// <summary>
/// Create a builder from the bytes in the BGRA32 pixel format.
/// https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.pixelformats.bgra32
/// </summary>
/// <param name="data">The pixels in BGRA32 format.</param>
/// <param name="width">The width in pixels.</param>
/// <param name="height">The height in pixels.</param>
/// <param name="useAlphaChannel">Whether to include an alpha channel in the output.</param>
public static PngBuilder FromBgra32Pixels(Stream data, int width, int height, bool useAlphaChannel = true)
{
var bpp = useAlphaChannel ? 4 : 3;

var length = (height * width * bpp) + height;

var builder = new PngBuilder(new byte[length], useAlphaChannel, width, height, bpp);

var buffer = new byte[4];

for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
{
var read = data.Read(buffer, 0, buffer.Length);

if (read != 4)
{
throw new InvalidOperationException($"Unexpected end of stream, expected to read 4 bytes at offset {data.Position - read} for (x: {x}, y: {y}), instead got {read}.");
}

if (useAlphaChannel)
{
builder.SetPixel(new Pixel(buffer[0], buffer[1], buffer[2], buffer[3], false), x, y);
}
else
{
builder.SetPixel(buffer[0], buffer[1], buffer[2], x, y);
}
}
}

return builder;
}

private PngBuilder(byte[] rawData, bool hasAlphaChannel, int width, int height, int bytesPerPixel)
{
this.rawData = rawData;
Expand Down Expand Up @@ -223,7 +284,7 @@ public void Save(Stream outputStream, SaveOptions options = null)
var dataLength = rawData.Length;
var bitDepth = 8;

if (!hasTooManyColorsForPalette)
if (!hasTooManyColorsForPalette && !hasAlphaChannel)
{
var paletteColors = colorCounts.OrderByDescending(x => x.Value).Select(x => x.Key).ToList();
bitDepth = paletteColors.Count >= 128 ? 8 : 4;
Expand Down

0 comments on commit a1fad87

Please sign in to comment.