public override void Init(Stream stream) { using (var bh = new ByteHelper(stream)) { bh.IsLsbf = false; bh.Seek(0, SeekOrigin.Begin); // http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html var signature = bh.ReadBytes(8); IsValid = signature[0] == 137 && signature[1] == 80 && signature[2] == 78 && signature[3] == 71 && signature[4] == 13 && signature[5] == 10 && signature[6] == 26 && signature[7] == 10; if (!IsValid) { return; } DpiH = DpiV = 96; while (stream.Position < stream.Length) { var chunkDataLength = bh.ReadUint(); var chunkType = bh.ReadAscii(4); switch (chunkType) { case "IHDR": Width = (int)bh.ReadUint(); Height = (int)bh.ReadUint(); bh.Seek(5); break; case "pHYs": var pixelsPerUnitX = (int)bh.ReadUint(); var pixelsPerUnitY = (int)bh.ReadUint(); var unit = bh.ReadByte(); if (unit == 1) { // Unit is the meter. DpiH = PixelsPerMeterToPixelsPerInch(pixelsPerUnitX); DpiV = PixelsPerMeterToPixelsPerInch(pixelsPerUnitY); } return; default: bh.Seek(chunkDataLength, SeekOrigin.Current); break; } // Skip CRC. bh.Seek(4, SeekOrigin.Current); } } }
public override void Init(Stream stream) { using (var bh = new ByteHelper(stream)) { bh.Seek(0, SeekOrigin.Begin); bh.IsLsbf = false; // Start of Image (SOI) marker. var marker = bh.ReadBytes(2); if (marker[0] != 0xFF && marker[1] != 0xD8) { return; } DpiH = DpiV = 96; int length; while (stream.Position < stream.Length) { marker = bh.ReadBytes(2); if (marker[0] != 0xFF) { throw new Exception("Invalid JPEG file."); } switch (marker[1]) { case 0xE0: // APP0 (JFIF) marker. length = bh.ReadUshort(); bh.Seek(7); var densityUnits = bh.ReadByte(); var xdensity = bh.ReadUshort(); var ydensity = bh.ReadUshort(); if (densityUnits == 1) { DpiH = xdensity; DpiV = ydensity; } else if (densityUnits == 2) { // Pixels per centimeter DpiH = PixelsPerMeterToPixelsPerInch(xdensity * 100); DpiV = PixelsPerMeterToPixelsPerInch(ydensity * 100); } bh.Seek(length - 14); break; //case 0xE1: // APP1-marker. This could be an Exif marker. // TODO: read x/y-resolution from Exif APP1 case 0xFF: // Filler byte. bh.Seek(-1, SeekOrigin.Current); break; case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: case 0xD8: case 0xD9: // RSTn are used for resync, may be ignored. break; case 0xDA: // SOS (Start of Scan) marker, followed by image data. IsValid = true; return; case 0xC0: case 0xC1: case 0xC2: case 0xC3: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCD: case 0xCE: case 0xCF: // SOFn (Start Of Frame) markers. length = bh.ReadUshort(); bh.Seek(1); Height = bh.ReadUshort(); Width = bh.ReadUshort(); bh.Seek(length - 7); break; default: // Irrelevant variable-length packets. length = bh.ReadUshort(); bh.Seek(length - 2); break; } } } }