using System; using System.Text; using System.Collections; using System.IO; using com.drew.metadata; using com.drew.imaging.jpg; /// /// This class was first written by Drew Noakes in Java. /// /// This is public domain software - that is, you can do whatever you want /// with it, and include it software that is licensed under the GNU or the /// BSD license, or whatever other licence you choose, including proprietary /// closed source licenses. I do ask that you leave this header in tact. /// /// If you make modifications to this code that you think would benefit the /// wider community, please send me a copy and I'll post it on my site. /// /// If you make use of this code, Drew Noakes will appreciate hearing /// about it: drew@drewnoakes.com /// /// Latest Java version of this software kept at /// http://drewnoakes.com/ /// /// The C# class was made by Ferret Renaud: /// renaud91@free.fr /// If you find a bug in the C# code, feel free to mail me. /// namespace com.drew.metadata.jpeg { /// /// The JPEG reader class /// public class JpegReader : MetadataReader { /// /// The SOF0 data segment. /// private byte[] _data; /// /// Creates a new IptcReader for the specified Jpeg jpegFile. /// /// where to read public JpegReader(FileInfo jpegFile) : this( new JpegSegmentReader(jpegFile).ReadSegment( JpegSegmentReader.SEGMENT_SOF0)) { } /// /// Constructor of the object /// /// the data to read public JpegReader(byte[] data) { _data = data; } /// /// Performs the Exif data extraction, returning a new instance of Metadata. /// /// a new instance of Metadata public Metadata Extract() { return Extract(new Metadata()); } /// /// Extracts metadata /// /// where to add metadata /// the metadata found public Metadata Extract(Metadata metadata) { if (_data == null) { return metadata; } JpegDirectory directory = (JpegDirectory) metadata.GetDirectory(Type.GetType("com.drew.metadata.jpeg.JpegDirectory")); try { // data precision int dataPrecision = Get16Bits(JpegDirectory.TAG_JPEG_DATA_PRECISION); directory.SetObject( JpegDirectory.TAG_JPEG_DATA_PRECISION, dataPrecision); // process height int height = Get32Bits(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT); directory.SetObject(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, height); // process width int width = Get32Bits(JpegDirectory.TAG_JPEG_IMAGE_WIDTH); directory.SetObject(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, width); // number of components int numberOfComponents = Get16Bits(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS); directory.SetObject( JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS, numberOfComponents); // for each component, there are three bytes of data: // 1 - Component ID: 1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q // 2 - Sampling factors: bit 0-3 vertical, 4-7 horizontal // 3 - Quantization table number int offset = 6; for (int i = 0; i < numberOfComponents; i++) { int componentId = Get16Bits(offset++); int samplingFactorByte = Get16Bits(offset++); int quantizationTableNumber = Get16Bits(offset++); JpegComponent component = new JpegComponent( componentId, samplingFactorByte, quantizationTableNumber); directory.SetObject( JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + i, component); } } catch (MetadataException me) { directory.AddError("MetadataException: " + me); } return metadata; } /// /// Returns an int calculated from two bytes of data at the specified offset (MSB, LSB). /// /// position within the data buffer to read first byte /// the 32 bit int value, between 0x0000 and 0xFFFF private int Get32Bits(int offset) { if (offset + 1 >= _data.Length) { throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer"); } return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255); } /// /// Returns an int calculated from one byte of data at the specified offset. /// /// position within the data buffer to read byte /// the 16 bit int value, between 0x00 and 0xFF private int Get16Bits(int offset) { if (offset >= _data.Length) { throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer"); } return (_data[offset] & 255); } } }