public PngChunk([NotNull] PngChunkType chunkType, [NotNull] byte[] bytes) { ChunkType = chunkType; Bytes = bytes; }
public PngDirectory([NotNull] PngChunkType pngChunkType) { _pngChunkType = pngChunkType; SetDescriptor(new PngDescriptor(this)); }
public IEnumerable <PngChunk> Extract([NotNull] SequentialReader reader, [CanBeNull] ICollection <PngChunkType> desiredChunkTypes) { // // PNG DATA STREAM // // Starts with a PNG SIGNATURE, followed by a sequence of CHUNKS. // // PNG SIGNATURE // // Always composed of these bytes: 89 50 4E 47 0D 0A 1A 0A // // CHUNK // // 4 - length of the data field (unsigned, but always within 31 bytes), may be zero // 4 - chunk type, restricted to [65,90] and [97,122] (A-Za-z) // * - data field // 4 - CRC calculated from chunk type and chunk data, but not length // // CHUNK TYPES // // Critical Chunk Types: // // IHDR - image header, always the first chunk in the data stream // PLTE - palette table, associated with indexed PNG images // IDAT - image data chunk, of which there may be many // IEND - image trailer, always the last chunk in the data stream // // Ancillary Chunk Types: // // Transparency information: tRNS // Colour space information: cHRM, gAMA, iCCP, sBIT, sRGB // Textual information: iTXt, tEXt, zTXt // Miscellaneous information: bKGD, hIST, pHYs, sPLT // Time information: tIME // // network byte order reader = reader.WithByteOrder(isMotorolaByteOrder: true); if (!_pngSignatureBytes.SequenceEqual(reader.GetBytes(_pngSignatureBytes.Length))) { throw new PngProcessingException("PNG signature mismatch"); } var seenImageHeader = false; var seenImageTrailer = false; var chunks = new List <PngChunk>(); var seenChunkTypes = new HashSet <PngChunkType>(); while (!seenImageTrailer) { // Process the next chunk. var chunkDataLength = reader.GetInt32(); if (chunkDataLength < 0) { throw new PngProcessingException("PNG chunk length exceeds maximum"); } var chunkType = new PngChunkType(reader.GetBytes(4)); var willStoreChunk = desiredChunkTypes == null || desiredChunkTypes.Contains(chunkType); var chunkData = reader.GetBytes(chunkDataLength); // Skip the CRC bytes at the end of the chunk // TODO consider verifying the CRC value to determine if we're processing bad data reader.Skip(4); if (willStoreChunk && seenChunkTypes.Contains(chunkType) && !chunkType.AreMultipleAllowed) { throw new PngProcessingException($"Observed multiple instances of PNG chunk '{chunkType}', for which multiples are not allowed"); } if (chunkType.Equals(PngChunkType.IHDR)) { seenImageHeader = true; } else if (!seenImageHeader) { throw new PngProcessingException($"First chunk should be '{PngChunkType.IHDR}', but '{chunkType}' was observed"); } if (chunkType.Equals(PngChunkType.IEND)) { seenImageTrailer = true; } if (willStoreChunk) { chunks.Add(new PngChunk(chunkType, chunkData)); } seenChunkTypes.Add(chunkType); } return(chunks); }
private bool Equals([NotNull] PngChunkType other) => _bytes.SequenceEqual(other._bytes);
private bool Equals(PngChunkType other) => _bytes.SequenceEqual(other._bytes);
static PngDirectory ReadTextDirectory(string keyword, byte[] textBytes, PngChunkType pngChunkType) { var textPairs = new[] { new KeyValuePair(keyword, new StringValue(textBytes, _latin1Encoding)) }; var directory = new PngDirectory(pngChunkType); directory.Set(PngDirectory.TagTextualData, textPairs); return(directory); }
/// <exception cref="PngProcessingException"/> /// <exception cref="System.IO.IOException"/> public IEnumerable<PngChunk> Extract([NotNull] SequentialReader reader, [CanBeNull] ICollection<PngChunkType> desiredChunkTypes) { // // PNG DATA STREAM // // Starts with a PNG SIGNATURE, followed by a sequence of CHUNKS. // // PNG SIGNATURE // // Always composed of these bytes: 89 50 4E 47 0D 0A 1A 0A // // CHUNK // // 4 - length of the data field (unsigned, but always within 31 bytes), may be zero // 4 - chunk type, restricted to [65,90] and [97,122] (A-Za-z) // * - data field // 4 - CRC calculated from chunk type and chunk data, but not length // // CHUNK TYPES // // Critical Chunk Types: // // IHDR - image header, always the first chunk in the data stream // PLTE - palette table, associated with indexed PNG images // IDAT - image data chunk, of which there may be many // IEND - image trailer, always the last chunk in the data stream // // Ancillary Chunk Types: // // Transparency information: tRNS // Colour space information: cHRM, gAMA, iCCP, sBIT, sRGB // Textual information: iTXt, tEXt, zTXt // Miscellaneous information: bKGD, hIST, pHYs, sPLT // Time information: tIME // // network byte order reader.IsMotorolaByteOrder = true; if (!_pngSignatureBytes.SequenceEqual(reader.GetBytes(_pngSignatureBytes.Length))) throw new PngProcessingException("PNG signature mismatch"); var seenImageHeader = false; var seenImageTrailer = false; var chunks = new List<PngChunk>(); var seenChunkTypes = new HashSet<PngChunkType>(); while (!seenImageTrailer) { // Process the next chunk. var chunkDataLength = reader.GetInt32(); var chunkType = new PngChunkType(reader.GetBytes(4)); var willStoreChunk = desiredChunkTypes == null || desiredChunkTypes.Contains(chunkType); var chunkData = reader.GetBytes(chunkDataLength); // Skip the CRC bytes at the end of the chunk // TODO consider verifying the CRC value to determine if we're processing bad data reader.Skip(4); if (willStoreChunk && seenChunkTypes.Contains(chunkType) && !chunkType.AreMultipleAllowed) throw new PngProcessingException($"Observed multiple instances of PNG chunk '{chunkType}', for which multiples are not allowed"); if (chunkType.Equals(PngChunkType.IHDR)) seenImageHeader = true; else if (!seenImageHeader) throw new PngProcessingException($"First chunk should be '{PngChunkType.IHDR}', but '{chunkType}' was observed"); if (chunkType.Equals(PngChunkType.IEND)) seenImageTrailer = true; if (willStoreChunk) chunks.Add(new PngChunk(chunkType, chunkData)); seenChunkTypes.Add(chunkType); } return chunks; }
public PngDirectory(PngChunkType pngChunkType) { _pngChunkType = pngChunkType; SetDescriptor(new PngDescriptor(this)); }