internal void read(BigEndianBinaryReader reader) { width = reader.ReadInt32(); height = reader.ReadInt32(); bitdepth = reader.ReadByte(); colortype = (ColorType)reader.ReadByte(); method = reader.ReadByte(); filter = reader.ReadByte(); interlace = reader.ReadByte(); }
void readImagedata(BigEndianBinaryReader reader, int length) { int width = ihdr.width; int height = ihdr.height; int bitDepth = ihdr.bitdepth; int samples = ihdr.getSamples(); bool interlaced = ihdr.isInterlaced(); SubInputStream sis = new SubInputStream(reader.BaseStream, length); InflaterInputStream iis = new InflaterInputStream(sis); Defilterer d = new Defilterer(iis, bitDepth, samples, width); //todo: interlacing imageOutput.start(this); d.defilter(0, 0, 1, 1, width, height, imageOutput); imageOutput.finish(); }
void readPLTE(BigEndianBinaryReader reader, int length) { if(length == 0) throw new BadImageFormatException("PLTE chunk cannot be empty"); if(length % 3 != 0) throw new BadImageFormatException("PLTE chunk length indivisible by 3: " + length); int size = length / 3; if(size > 256) throw new BadImageFormatException("Too many palette entries: " + size); switch (ihdr.colortype) { case ColorType.PALETTE: if (size > (1 << ihdr.bitdepth)) throw new BadImageFormatException("Too many palette entries: " + size); palette = new byte[length]; reader.Read(palette, 0, length); break; default: throw new BadImageFormatException("PLTE chunk found in non-palette colorformat image"); } }
public void read(Stream stream, IPngImageOutput imageOutput) { this.imageOutput = imageOutput; CRCInputStream crcstream = new CRCInputStream(stream); BigEndianBinaryReader reader = new BigEndianBinaryReader(crcstream); //check signature if(!IsPng(stream)) throw new BadImageFormatException("signature invalid"); //sort of an inefficient way to do it, but at 3:30am itll do fine MemoryStream msIDAT = new MemoryStream(); int state = 0; for(; ; ) { bool skipChunk = false; int chunkLen = reader.ReadInt32(); crcstream.resetCrc(); int chunkType = reader.ReadInt32(); //expect an IHDR if(state == 0) { if(chunkType != type_IHDR) throw new BadImageFormatException("did not encounter initial IHDR"); ihdr.read(reader); //validate ihdr: do we support interlaced images for now? state = 1; } else if(state == 1) { switch(chunkType) { case type_IEND: //actually do the imagedata read now msIDAT.Position = 0; readImagedata(new BigEndianBinaryReader(msIDAT), (int)msIDAT.Length); state = 2; break; case type_IHDR: throw new BadImageFormatException("encountered supernumerary IHDR"); case type_IDAT: byte[] buf = new byte[chunkLen]; reader.BaseStream.Read(buf, 0, chunkLen); msIDAT.Write(buf, 0, chunkLen); break; case type_PLTE: readPLTE(reader, chunkLen); break; default: { skipChunk = true; byte[] bytes = System.BitConverter.GetBytes(chunkType); //debug: which chunk was skipped? //Console.WriteLine("{0}{1}{2}{3}", (char)bytes[3], (char)bytes[2], (char)bytes[1], (char)bytes[0]); } break; } } //if we skipped the chunk, skip the bytes. if(skipChunk) { reader.BaseStream.Position += chunkLen + 4; //+4 for the crc } else { //if we didnt skip it, do the crc validation if(!skipChunk) { int actualCrc = (int)crcstream.Value; int targetCrc = reader.ReadInt32(); if(actualCrc != targetCrc) throw new BadImageFormatException("Crc failure"); } } if(state == 2) break; } }