Skip to content

Commit

Permalink
PngImage, saving works better.
Browse files Browse the repository at this point in the history
  • Loading branch information
juliusfriedman committed Oct 22, 2024
1 parent 7792917 commit 641e07a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 12 deletions.
6 changes: 4 additions & 2 deletions Codecs/Image/Png/Codec.Png/Chunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ namespace Media.Codec.Png;

public class Chunk : MemorySegment
{
public const int ChecksumLength = Binary.BytesPerInteger;

public Chunk(ChunkHeader header)
: base(new MemorySegment(ChunkHeader.ChunkHeaderLength + Binary.BytesPerInteger + header.Length))
{
Expand Down Expand Up @@ -44,7 +46,7 @@ public ChunkHeader Header
/// <summary>
/// Number of bytes contained including the <see cref="Crc"/>
/// </summary>
public int TotalLength => (int)(Header.Length + Binary.BytesPerInteger);
public int TotalLength => (int)(Header.Length + ChecksumLength);

/// <summary>
/// The number of bytes contained in the <see cref="Data"/> segment.
Expand Down Expand Up @@ -88,7 +90,7 @@ public int Crc

public int CrcDataOffset => Offset + ChunkHeader.ChunkHeaderLength + ChunkSize;

public MemorySegment CrcData => new(Array, CrcDataOffset, Binary.BytesPerInteger);
public MemorySegment CrcData => new(Array, CrcDataOffset, ChecksumLength);

internal static Chunk ReadChunk(Stream inputStream)
{
Expand Down
68 changes: 58 additions & 10 deletions Codecs/Image/Png/Codec.Png/PngImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Media.Codecs.Image;
using Media.Common;
using Media.Common.Collections.Generic;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace Media.Codec.Png;

Expand Down Expand Up @@ -90,25 +91,47 @@ public static PngImage FromStream(Stream stream)
//ToDo, Crc is in data segment, so we need to read it and validate it.
continue;
case ChunkName.Data:
//ToDo, Crc is in data segment, so we need to read it and validate it.
dataSegment = chunk.Data.Slice(0);

//TODO
//We should have a MeorySegmentStream and append to it because there can be multiple data chunks.
using(var ms = new MemoryStream(chunk.Array, chunk.DataOffset + 2, chunk.Count - chunk.DataOffset - 2))
{
using (MemoryStream decompressedStream = new MemoryStream())
{
using (DeflateStream deflateStream = new DeflateStream(ms, CompressionMode.Decompress))
{
try
{
deflateStream.CopyTo(decompressedStream);
dataSegment = new(decompressedStream.ToArray());
}
catch(InvalidDataException)
{
dataSegment = chunk.Data;
}
}
}
}

continue;
case ChunkName.End:
continue;
goto LoadImage;
default:
chunks.Add(chunkName, chunk);
continue;
}
}

LoadImage:

if(imageFormat == null || dataSegment == null)
throw new InvalidDataException("The provided stream does not contain valid PNG image data.");

// Create and return the PngImage
return new PngImage(imageFormat, width, height, dataSegment, colorType, chunks);
}

public void Save(Stream stream)
public void Save(Stream stream, CompressionLevel compressionLevel = CompressionLevel.Optimal)
{
// Write the PNG signature
stream.Write(Binary.GetBytes(PNGSignature, BitConverter.IsLittleEndian));
Expand All @@ -120,7 +143,7 @@ public void Save(Stream stream)
WriteIHDRChunk(stream);

// Write the IDAT chunk
WriteIDATChunk(stream);
WriteIDATChunk(stream, compressionLevel);

if (Chunks != null)
{
Expand Down Expand Up @@ -156,11 +179,36 @@ private void WriteIDATChunk(Stream stream, CompressionLevel compressionLevel = C
using (DeflateStream deflateStream = new DeflateStream(ms, compressionLevel, true))
{
deflateStream.Write(Data.Array, Data.Offset, Data.Count);
}
ms.Seek(0, SeekOrigin.Begin);
ms.TryGetBuffer(out var buffer);
idat = new Chunk(ChunkName.Data, buffer.Count);
buffer.CopyTo(idat.Array, idat.DataOffset);

deflateStream.Close();

ms.Seek(0, SeekOrigin.Begin);

const byte HeaderLength = 2;
const byte Deflate32KbWindow = 120;
const byte ChecksumBits = 1;

// Write the ZLib header
var result = new byte[HeaderLength + ms.Length + Chunk.ChecksumLength];

// Write the ZLib header.
result[0] = Deflate32KbWindow;
result[1] = ChecksumBits;

// Write the compressed data.
int streamValue;
var i = 0;
while ((streamValue = ms.ReadByte()) != -1)
{
result[HeaderLength + i] = (byte)streamValue;
i++;
}

//Todo calculate the CRC and write to result.

idat = new Chunk(ChunkName.Data, result.Length - Chunk.ChecksumLength);
result.CopyTo(idat.Array, idat.DataOffset);
}
}
stream.Write(idat.Array, idat.Offset, idat.Count);
idat.Dispose();
Expand Down

0 comments on commit 641e07a

Please sign in to comment.