/// <summary> /// Reads the APP0 section containing JFIF metadata. /// </summary> private void ReadJFIFAPP0() { // Find the APP0 section containing JFIF metadata _jfifApp0 = Sections.Find(a => a.Marker == JPEGMarker.APP0 && a.Header.Length >= 5 && Encoding.ASCII.GetString(a.Header, 0, 5) == "JFIF\0"); // If there is no APP0 section, return. if (_jfifApp0 == null) { return; } var header = _jfifApp0.Header; BitConverterEx jfifConv = BitConverterEx.BigEndian; // Version var version = jfifConv.ToUInt16(header, 5); Properties.Add(new JFIFVersion(ExifTag.JFIFVersion, version)); // Units var unit = header[7]; Properties.Add(new ExifEnumProperty <JFIFDensityUnit>(ExifTag.JFIFUnits, (JFIFDensityUnit)unit)); // X and Y densities var xdensity = jfifConv.ToUInt16(header, 8); Properties.Add(new ExifUShort(ExifTag.XDensity, xdensity)); var ydensity = jfifConv.ToUInt16(header, 10); Properties.Add(new ExifUShort(ExifTag.YDensity, ydensity)); // Thumbnails pixel count var xthumbnail = header[12]; Properties.Add(new ExifByte(ExifTag.JFIFXThumbnail, xthumbnail)); var ythumbnail = header[13]; Properties.Add(new ExifByte(ExifTag.JFIFYThumbnail, ythumbnail)); // Read JFIF thumbnail var n = xthumbnail * ythumbnail; var jfifThumbnail = new byte[n]; Array.Copy(header, 14, jfifThumbnail, 0, n); Properties.Add(new JFIFThumbnailProperty(ExifTag.JFIFThumbnail, new JFIFThumbnail(JFIFThumbnail.ImageFormat.JPEG, jfifThumbnail))); }
/// <summary> /// Returns a <see cref="ImageFileDirectoryEntry" /> initialized from the given byte data. /// </summary> /// <param name="data">The data.</param> /// <param name="offset">The offset into <paramref name="data" />.</param> /// <param name="byteOrder">The byte order of <paramref name="data" />.</param> /// <returns>A <see cref="ImageFileDirectoryEntry" /> initialized from the given byte data.</returns> public static ImageFileDirectoryEntry FromBytes(byte[] data, uint offset, BitConverterEx.ByteOrder byteOrder) { // Tag ID var tag = BitConverterEx.ToUInt16(data, offset, byteOrder, BitConverterEx.SystemByteOrder); // Tag Type var type = BitConverterEx.ToUInt16(data, offset + 2, byteOrder, BitConverterEx.SystemByteOrder); // Count of Type var count = BitConverterEx.ToUInt32(data, offset + 4, byteOrder, BitConverterEx.SystemByteOrder); // Field value or offset to field data var value = new byte[4]; Array.Copy(data, offset + 8, value, 0, 4); // Calculate the bytes we need to read var baselength = GetBaseLength(type); var totallength = count * baselength; // If field value does not fit in 4 bytes // the value field is an offset to the actual // field value if (totallength > 4) { var dataoffset = BitConverterEx.ToUInt32(value, 0, byteOrder, BitConverterEx.SystemByteOrder); value = new byte[totallength]; Array.Copy(data, dataoffset, value, 0, totallength); } // Reverse array order if byte orders are different if (byteOrder != BitConverterEx.SystemByteOrder) { for (uint i = 0; i < count; i++) { var val = new byte[baselength]; Array.Copy(value, i * baselength, val, 0, baselength); Array.Reverse(val); Array.Copy(val, 0, value, i * baselength, baselength); } } return(new ImageFileDirectoryEntry(tag, type, count, value)); }
/// <summary> /// 读取包含的Exif元数据APP1部分 /// </summary> private void ReadAPP1() { // Find the APP1 section containing Exif metadata app1 = file.Sections.Find(a => (a.Marker == JPEGMarker.APP1) && (Encoding.ASCII.GetString(a.Header, 0, 6) == "Exif\0\0")); // If there is no APP1 section, add a new one after the last APP0 section (if any). if (app1 == null) { int insertionIndex = file.Sections.FindLastIndex(a => a.Marker == JPEGMarker.APP0); if (insertionIndex == -1) { insertionIndex = 0; } insertionIndex++; ByteOrder = BitConverterEx.ByteOrder.BigEndian; app1 = new JPEGSection(JPEGMarker.APP1); file.Sections.Insert(insertionIndex, app1); return; } byte[] header = app1.Header; SortedList <int, IFD> ifdqueue = new SortedList <int, IFD>(); makerNoteOffset = 0; // TIFF header int tiffoffset = 6; if (header[tiffoffset] == 0x49) { ByteOrder = BitConverterEx.ByteOrder.LittleEndian; } else { ByteOrder = BitConverterEx.ByteOrder.BigEndian; } BitConverterEx conv = new BitConverterEx(ByteOrder, BitConverterEx.ByteOrder.System); // Offset to 0th IFD int ifd0offset = (int)conv.ToUInt32(header, tiffoffset + 4); ifdqueue.Add(ifd0offset, IFD.Zeroth); int thumboffset = -1; int thumblength = 0; int thumbtype = -1; // Read IFDs while (ifdqueue.Count != 0) { int ifdoffset = tiffoffset + ifdqueue.Keys[0]; IFD currentifd = ifdqueue.Values[0]; ifdqueue.RemoveAt(0); // Field count ushort fieldcount = conv.ToUInt16(header, ifdoffset); for (short i = 0; i < fieldcount; i++) { // Read field info int fieldoffset = ifdoffset + 2 + 12 * i; ushort tag = conv.ToUInt16(header, fieldoffset); ushort type = conv.ToUInt16(header, fieldoffset + 2); uint count = conv.ToUInt32(header, fieldoffset + 4); byte[] value = new byte[4]; Array.Copy(header, fieldoffset + 8, value, 0, 4); // Fields containing offsets to other IFDs if (currentifd == IFD.Zeroth && tag == 0x8769) { int exififdpointer = (int)conv.ToUInt32(value, 0); ifdqueue.Add(exififdpointer, IFD.EXIF); } else if (currentifd == IFD.Zeroth && tag == 0x8825) { int gpsifdpointer = (int)conv.ToUInt32(value, 0); ifdqueue.Add(gpsifdpointer, IFD.GPS); } else if (currentifd == IFD.EXIF && tag == 0xa005) { int interopifdpointer = (int)conv.ToUInt32(value, 0); ifdqueue.Add(interopifdpointer, IFD.Interop); } // Save the offset to maker note data if (currentifd == IFD.EXIF && tag == 37500) { makerNoteOffset = conv.ToUInt32(value, 0); } // Calculate the bytes we need to read uint baselength = 0; if (type == 1 || type == 2 || type == 7) { baselength = 1; } else if (type == 3) { baselength = 2; } else if (type == 4 || type == 9) { baselength = 4; } else if (type == 5 || type == 10) { baselength = 8; } uint totallength = count * baselength; // If field value does not fit in 4 bytes // the value field is an offset to the actual // field value int fieldposition = 0; if (totallength > 4) { fieldposition = tiffoffset + (int)conv.ToUInt32(value, 0); value = new byte[totallength]; Array.Copy(header, fieldposition, value, 0, totallength); } // Compressed thumbnail data if (currentifd == IFD.First && tag == 0x201) { thumbtype = 0; thumboffset = (int)conv.ToUInt32(value, 0); } else if (currentifd == IFD.First && tag == 0x202) { thumblength = (int)conv.ToUInt32(value, 0); } // Uncompressed thumbnail data if (currentifd == IFD.First && tag == 0x111) { thumbtype = 1; // Offset to first strip if (type == 3) { thumboffset = (int)conv.ToUInt16(value, 0); } else { thumboffset = (int)conv.ToUInt32(value, 0); } } else if (currentifd == IFD.First && tag == 0x117) { thumblength = 0; for (int j = 0; j < count; j++) { if (type == 3) { thumblength += (int)conv.ToUInt16(value, 0); } else { thumblength += (int)conv.ToUInt32(value, 0); } } } // Create the exif property from the interop data ExifProperty prop = ExifPropertyFactory.Get(tag, type, count, value, ByteOrder, currentifd); Properties.Add(prop.Tag, prop); } // 1st IFD pointer int firstifdpointer = (int)conv.ToUInt32(header, ifdoffset + 2 + 12 * fieldcount); if (firstifdpointer != 0) { ifdqueue.Add(firstifdpointer, IFD.First); } // Read thumbnail if (thumboffset != -1 && thumblength != 0 && Thumbnail == null) { if (thumbtype == 0) { using (MemoryStream ts = new MemoryStream(header, tiffoffset + thumboffset, thumblength)) { Thumbnail = new JPEGFile(ts); } } } } }
/// <summary> /// Reads the APP1 section containing Exif metadata. /// </summary> private void ReadExifAPP1() { // Find the APP1 section containing Exif metadata _exifApp1 = Sections.Find(a => a.Marker == JPEGMarker.APP1 && a.Header.Length >= 6 && Encoding.ASCII.GetString(a.Header, 0, 6) == "Exif\0\0"); // If there is no APP1 section, add a new one after the last APP0 section (if any). if (_exifApp1 == null) { var insertionIndex = Sections.FindLastIndex(a => a.Marker == JPEGMarker.APP0); if (insertionIndex == -1) { insertionIndex = 0; } insertionIndex++; _exifApp1 = new JPEGSection(JPEGMarker.APP1); Sections.Insert(insertionIndex, _exifApp1); if (BitConverterEx.SystemByteOrder == BitConverterEx.ByteOrder.LittleEndian) { ByteOrder = BitConverterEx.ByteOrder.LittleEndian; } else { ByteOrder = BitConverterEx.ByteOrder.BigEndian; } return; } var header = _exifApp1.Header; var ifdqueue = new SortedList <int, IFD>(); _makerNoteOffset = 0; // TIFF header var tiffoffset = 6; if (header[tiffoffset] == 0x49 && header[tiffoffset + 1] == 0x49) { ByteOrder = BitConverterEx.ByteOrder.LittleEndian; } else if (header[tiffoffset] == 0x4D && header[tiffoffset + 1] == 0x4D) { ByteOrder = BitConverterEx.ByteOrder.BigEndian; } else { throw new NotValidExifFileException(); } // TIFF header may have a different byte order BitConverterEx.ByteOrder tiffByteOrder = ByteOrder; if (BitConverterEx.LittleEndian.ToUInt16(header, tiffoffset + 2) == 42) { tiffByteOrder = BitConverterEx.ByteOrder.LittleEndian; } else if (BitConverterEx.BigEndian.ToUInt16(header, tiffoffset + 2) == 42) { tiffByteOrder = BitConverterEx.ByteOrder.BigEndian; } else { throw new NotValidExifFileException(); } // Offset to 0th IFD var ifd0offset = (int)BitConverterEx.ToUInt32(header, tiffoffset + 4, tiffByteOrder, BitConverterEx.SystemByteOrder); ifdqueue.Add(ifd0offset, IFD.Zeroth); var conv = new BitConverterEx(ByteOrder, BitConverterEx.SystemByteOrder); var thumboffset = -1; var thumblength = 0; var thumbtype = -1; // Read IFDs while (ifdqueue.Count != 0) { var ifdoffset = tiffoffset + ifdqueue.Keys[0]; IFD currentifd = ifdqueue.Values[0]; ifdqueue.RemoveAt(0); // Field count var fieldcount = conv.ToUInt16(header, ifdoffset); for (short i = 0; i < fieldcount; i++) { // Read field info var fieldoffset = ifdoffset + 2 + (12 * i); var tag = conv.ToUInt16(header, fieldoffset); var type = conv.ToUInt16(header, fieldoffset + 2); var count = conv.ToUInt32(header, fieldoffset + 4); var value = new byte[4]; Array.Copy(header, fieldoffset + 8, value, 0, 4); // Fields containing offsets to other IFDs if (currentifd == IFD.Zeroth && tag == 0x8769) { var exififdpointer = (int)conv.ToUInt32(value, 0); ifdqueue.Add(exififdpointer, IFD.EXIF); } else if (currentifd == IFD.Zeroth && tag == 0x8825) { var gpsifdpointer = (int)conv.ToUInt32(value, 0); ifdqueue.Add(gpsifdpointer, IFD.GPS); } else if (currentifd == IFD.EXIF && tag == 0xa005) { var interopifdpointer = (int)conv.ToUInt32(value, 0); ifdqueue.Add(interopifdpointer, IFD.Interop); } // Save the offset to maker note data if (currentifd == IFD.EXIF && tag == 37500) { _makerNoteOffset = conv.ToUInt32(value, 0); } // Calculate the bytes we need to read uint baselength = 0; if (type == 1 || type == 2 || type == 7) { baselength = 1; } else if (type == 3) { baselength = 2; } else if (type == 4 || type == 9) { baselength = 4; } else if (type == 5 || type == 10) { baselength = 8; } var totallength = count * baselength; // If field value does not fit in 4 bytes // the value field is an offset to the actual // field value var fieldposition = 0; if (totallength > 4) { fieldposition = tiffoffset + (int)conv.ToUInt32(value, 0); value = new byte[totallength]; Array.Copy(header, fieldposition, value, 0, totallength); } // Compressed thumbnail data if (currentifd == IFD.First && tag == 0x201) { thumbtype = 0; thumboffset = (int)conv.ToUInt32(value, 0); } else if (currentifd == IFD.First && tag == 0x202) { thumblength = (int)conv.ToUInt32(value, 0); } // Uncompressed thumbnail data if (currentifd == IFD.First && tag == 0x111) { thumbtype = 1; // Offset to first strip if (type == 3) { thumboffset = conv.ToUInt16(value, 0); } else { thumboffset = (int)conv.ToUInt32(value, 0); } } else if (currentifd == IFD.First && tag == 0x117) { thumblength = 0; for (var j = 0; j < count; j++) { if (type == 3) { thumblength += conv.ToUInt16(value, 0); } else { thumblength += (int)conv.ToUInt32(value, 0); } } } // Create the exif property from the interop data ExifProperty prop = ExifPropertyFactory.Get(tag, type, count, value, ByteOrder, currentifd, Encoding); Properties.Add(prop); } // 1st IFD pointer var firstifdpointer = (int)conv.ToUInt32(header, ifdoffset + 2 + (12 * fieldcount)); if (firstifdpointer != 0) { ifdqueue.Add(firstifdpointer, IFD.First); } // Read thumbnail if (thumboffset != -1 && thumblength != 0 && Thumbnail == null) { if (thumbtype == 0) { using (var ts = new MemoryStream(header, tiffoffset + thumboffset, thumblength)) { Thumbnail = FromStream(ts); } } } } }
/// <summary> /// Creates an ExifProperty from the given interoperability parameters. /// </summary> /// <param name="tag">The tag id of the exif property.</param> /// <param name="type">The type id of the exif property.</param> /// <param name="count">Byte or component count.</param> /// <param name="value">Field data as an array of bytes.</param> /// <param name="byteOrder">Byte order of value.</param> /// <param name="ifd">IFD section containing this property.</param> /// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param> /// <returns>an ExifProperty initialized from the interoperability parameters.</returns> public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value, BitConverterEx.ByteOrder byteOrder, IFD ifd, Encoding encoding) { var conv = new BitConverterEx(byteOrder, BitConverterEx.SystemByteOrder); // Find the exif tag corresponding to given tag id ExifTag etag = ExifTagFactory.GetExifTag(ifd, tag); if (ifd == IFD.Zeroth) { // Compression if (tag == 0x103) { return(new ExifEnumProperty <Compression>(ExifTag.Compression, (Compression)conv.ToUInt16(value, 0))); } // PhotometricInterpretation if (tag == 0x106) { return(new ExifEnumProperty <PhotometricInterpretation>( ExifTag.PhotometricInterpretation, (PhotometricInterpretation)conv.ToUInt16(value, 0))); } // Orientation if (tag == 0x112) { return(new ExifEnumProperty <Orientation>(ExifTag.Orientation, (Orientation)conv.ToUInt16(value, 0))); } // PlanarConfiguration if (tag == 0x11c) { return(new ExifEnumProperty <PlanarConfiguration>( ExifTag.PlanarConfiguration, (PlanarConfiguration)conv.ToUInt16(value, 0))); } // YCbCrPositioning if (tag == 0x213) { return(new ExifEnumProperty <YCbCrPositioning>( ExifTag.YCbCrPositioning, (YCbCrPositioning)conv.ToUInt16(value, 0))); } // ResolutionUnit if (tag == 0x128) { return(new ExifEnumProperty <ResolutionUnit>( ExifTag.ResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0))); } // DateTime if (tag == 0x132) { return(new ExifDateTime(ExifTag.DateTime, ExifBitConverter.ToDateTime(value))); } if (tag == 0x9c9b || tag == 0x9c9c || // Windows tags tag == 0x9c9d || tag == 0x9c9e || tag == 0x9c9f) { return(new WindowsByteString( etag, Encoding.Unicode.GetString(value).TrimEnd(Constants.CharArrays.NullTerminator))); } } else if (ifd == IFD.EXIF) { // ExifVersion if (tag == 0x9000) { return(new ExifVersion(ExifTag.ExifVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII))); } // FlashpixVersion if (tag == 0xa000) { return(new ExifVersion(ExifTag.FlashpixVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII))); } // ColorSpace if (tag == 0xa001) { return(new ExifEnumProperty <ColorSpace>(ExifTag.ColorSpace, (ColorSpace)conv.ToUInt16(value, 0))); } // UserComment if (tag == 0x9286) { // Default to ASCII Encoding enc = Encoding.ASCII; bool hasenc; if (value.Length < 8) { hasenc = false; } else { hasenc = true; var encstr = enc.GetString(value, 0, 8); if (string.Compare(encstr, "ASCII\0\0\0", StringComparison.OrdinalIgnoreCase) == 0) { enc = Encoding.ASCII; } else if (string.Compare(encstr, "JIS\0\0\0\0\0", StringComparison.OrdinalIgnoreCase) == 0) { enc = Encoding.GetEncoding("Japanese (JIS 0208-1990 and 0212-1990)"); } else if (string.Compare(encstr, "Unicode\0", StringComparison.OrdinalIgnoreCase) == 0) { enc = Encoding.Unicode; } else { hasenc = false; } } var val = (hasenc ? enc.GetString(value, 8, value.Length - 8) : enc.GetString(value)).Trim( Constants.CharArrays.NullTerminator); return(new ExifEncodedString(ExifTag.UserComment, val, enc)); } // DateTimeOriginal if (tag == 0x9003) { return(new ExifDateTime(ExifTag.DateTimeOriginal, ExifBitConverter.ToDateTime(value))); } // DateTimeDigitized if (tag == 0x9004) { return(new ExifDateTime(ExifTag.DateTimeDigitized, ExifBitConverter.ToDateTime(value))); } // ExposureProgram if (tag == 0x8822) { return(new ExifEnumProperty <ExposureProgram>( ExifTag.ExposureProgram, (ExposureProgram)conv.ToUInt16(value, 0))); } // MeteringMode if (tag == 0x9207) { return(new ExifEnumProperty <MeteringMode>(ExifTag.MeteringMode, (MeteringMode)conv.ToUInt16(value, 0))); } // LightSource if (tag == 0x9208) { return(new ExifEnumProperty <LightSource>(ExifTag.LightSource, (LightSource)conv.ToUInt16(value, 0))); } // Flash if (tag == 0x9209) { return(new ExifEnumProperty <Flash>(ExifTag.Flash, (Flash)conv.ToUInt16(value, 0), true)); } // SubjectArea if (tag == 0x9214) { if (count == 3) { return(new ExifCircularSubjectArea( ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } if (count == 4) { return(new ExifRectangularSubjectArea( ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } return(new ExifPointSubjectArea( ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } // FocalPlaneResolutionUnit if (tag == 0xa210) { return(new ExifEnumProperty <ResolutionUnit>( ExifTag.FocalPlaneResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0), true)); } // SubjectLocation if (tag == 0xa214) { return(new ExifPointSubjectArea( ExifTag.SubjectLocation, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } // SensingMethod if (tag == 0xa217) { return(new ExifEnumProperty <SensingMethod>( ExifTag.SensingMethod, (SensingMethod)conv.ToUInt16(value, 0), true)); } // FileSource if (tag == 0xa300) { return(new ExifEnumProperty <FileSource>(ExifTag.FileSource, (FileSource)conv.ToUInt16(value, 0), true)); } // SceneType if (tag == 0xa301) { return(new ExifEnumProperty <SceneType>(ExifTag.SceneType, (SceneType)conv.ToUInt16(value, 0), true)); } // CustomRendered if (tag == 0xa401) { return(new ExifEnumProperty <CustomRendered>( ExifTag.CustomRendered, (CustomRendered)conv.ToUInt16(value, 0), true)); } // ExposureMode if (tag == 0xa402) { return(new ExifEnumProperty <ExposureMode>(ExifTag.ExposureMode, (ExposureMode)conv.ToUInt16(value, 0), true)); } // WhiteBalance if (tag == 0xa403) { return(new ExifEnumProperty <WhiteBalance>(ExifTag.WhiteBalance, (WhiteBalance)conv.ToUInt16(value, 0), true)); } // SceneCaptureType if (tag == 0xa406) { return(new ExifEnumProperty <SceneCaptureType>( ExifTag.SceneCaptureType, (SceneCaptureType)conv.ToUInt16(value, 0), true)); } // GainControl if (tag == 0xa407) { return(new ExifEnumProperty <GainControl>(ExifTag.GainControl, (GainControl)conv.ToUInt16(value, 0), true)); } // Contrast if (tag == 0xa408) { return(new ExifEnumProperty <Contrast>(ExifTag.Contrast, (Contrast)conv.ToUInt16(value, 0), true)); } // Saturation if (tag == 0xa409) { return(new ExifEnumProperty <Saturation>(ExifTag.Saturation, (Saturation)conv.ToUInt16(value, 0), true)); } // Sharpness if (tag == 0xa40a) { return(new ExifEnumProperty <Sharpness>(ExifTag.Sharpness, (Sharpness)conv.ToUInt16(value, 0), true)); } // SubjectDistanceRange if (tag == 0xa40c) { return(new ExifEnumProperty <SubjectDistanceRange>( ExifTag.SubjectDistanceRange, (SubjectDistanceRange)conv.ToUInt16(value, 0), true)); } } else if (ifd == IFD.GPS) { // GPSVersionID if (tag == 0) { return(new ExifVersion(ExifTag.GPSVersionID, ExifBitConverter.ToString(value))); } // GPSLatitudeRef if (tag == 1) { return(new ExifEnumProperty <GPSLatitudeRef>(ExifTag.GPSLatitudeRef, (GPSLatitudeRef)value[0])); } // GPSLatitude if (tag == 2) { return(new GPSLatitudeLongitude( ExifTag.GPSLatitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } // GPSLongitudeRef if (tag == 3) { return(new ExifEnumProperty <GPSLongitudeRef>(ExifTag.GPSLongitudeRef, (GPSLongitudeRef)value[0])); } // GPSLongitude if (tag == 4) { return(new GPSLatitudeLongitude( ExifTag.GPSLongitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } // GPSAltitudeRef if (tag == 5) { return(new ExifEnumProperty <GPSAltitudeRef>(ExifTag.GPSAltitudeRef, (GPSAltitudeRef)value[0])); } // GPSTimeStamp if (tag == 7) { return(new GPSTimeStamp( ExifTag.GPSTimeStamp, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } // GPSStatus if (tag == 9) { return(new ExifEnumProperty <GPSStatus>(ExifTag.GPSStatus, (GPSStatus)value[0])); } // GPSMeasureMode if (tag == 10) { return(new ExifEnumProperty <GPSMeasureMode>(ExifTag.GPSMeasureMode, (GPSMeasureMode)value[0])); } // GPSSpeedRef if (tag == 12) { return(new ExifEnumProperty <GPSSpeedRef>(ExifTag.GPSSpeedRef, (GPSSpeedRef)value[0])); } // GPSTrackRef if (tag == 14) { return(new ExifEnumProperty <GPSDirectionRef>(ExifTag.GPSTrackRef, (GPSDirectionRef)value[0])); } // GPSImgDirectionRef if (tag == 16) { return(new ExifEnumProperty <GPSDirectionRef>(ExifTag.GPSImgDirectionRef, (GPSDirectionRef)value[0])); } // GPSDestLatitudeRef if (tag == 19) { return(new ExifEnumProperty <GPSLatitudeRef>(ExifTag.GPSDestLatitudeRef, (GPSLatitudeRef)value[0])); } // GPSDestLatitude if (tag == 20) { return(new GPSLatitudeLongitude( ExifTag.GPSDestLatitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } // GPSDestLongitudeRef if (tag == 21) { return(new ExifEnumProperty <GPSLongitudeRef>(ExifTag.GPSDestLongitudeRef, (GPSLongitudeRef)value[0])); } // GPSDestLongitude if (tag == 22) { return(new GPSLatitudeLongitude( ExifTag.GPSDestLongitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } // GPSDestBearingRef if (tag == 23) { return(new ExifEnumProperty <GPSDirectionRef>(ExifTag.GPSDestBearingRef, (GPSDirectionRef)value[0])); } // GPSDestDistanceRef if (tag == 25) { return(new ExifEnumProperty <GPSDistanceRef>(ExifTag.GPSDestDistanceRef, (GPSDistanceRef)value[0])); } // GPSDate if (tag == 29) { return(new ExifDateTime(ExifTag.GPSDateStamp, ExifBitConverter.ToDateTime(value, false))); } // GPSDifferential if (tag == 30) { return(new ExifEnumProperty <GPSDifferential>( ExifTag.GPSDifferential, (GPSDifferential)conv.ToUInt16(value, 0))); } } else if (ifd == IFD.Interop) { // InteroperabilityIndex if (tag == 1) { return(new ExifAscii(ExifTag.InteroperabilityIndex, ExifBitConverter.ToAscii(value, Encoding.ASCII), Encoding.ASCII)); } // InteroperabilityVersion if (tag == 2) { return(new ExifVersion( ExifTag.InteroperabilityVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII))); } } else if (ifd == IFD.First) { // Compression if (tag == 0x103) { return(new ExifEnumProperty <Compression>( ExifTag.ThumbnailCompression, (Compression)conv.ToUInt16(value, 0))); } // PhotometricInterpretation if (tag == 0x106) { return(new ExifEnumProperty <PhotometricInterpretation>( ExifTag.ThumbnailPhotometricInterpretation, (PhotometricInterpretation)conv.ToUInt16(value, 0))); } // Orientation if (tag == 0x112) { return(new ExifEnumProperty <Orientation>( ExifTag.ThumbnailOrientation, (Orientation)conv.ToUInt16(value, 0))); } // PlanarConfiguration if (tag == 0x11c) { return(new ExifEnumProperty <PlanarConfiguration>( ExifTag.ThumbnailPlanarConfiguration, (PlanarConfiguration)conv.ToUInt16(value, 0))); } // YCbCrPositioning if (tag == 0x213) { return(new ExifEnumProperty <YCbCrPositioning>( ExifTag.ThumbnailYCbCrPositioning, (YCbCrPositioning)conv.ToUInt16(value, 0))); } // ResolutionUnit if (tag == 0x128) { return(new ExifEnumProperty <ResolutionUnit>( ExifTag.ThumbnailResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0))); } // DateTime if (tag == 0x132) { return(new ExifDateTime(ExifTag.ThumbnailDateTime, ExifBitConverter.ToDateTime(value))); } } // 1 = BYTE An 8-bit unsigned integer. if (type == 1) { if (count == 1) { return(new ExifByte(etag, value[0])); } return(new ExifByteArray(etag, value)); } // 2 = ASCII An 8-bit byte containing one 7-bit ASCII code. if (type == 2) { return(new ExifAscii(etag, ExifBitConverter.ToAscii(value, encoding), encoding)); } // 3 = SHORT A 16-bit (2-byte) unsigned integer. if (type == 3) { if (count == 1) { return(new ExifUShort(etag, conv.ToUInt16(value, 0))); } return(new ExifUShortArray(etag, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } // 4 = LONG A 32-bit (4-byte) unsigned integer. if (type == 4) { if (count == 1) { return(new ExifUInt(etag, conv.ToUInt32(value, 0))); } return(new ExifUIntArray(etag, ExifBitConverter.ToUIntArray(value, (int)count, byteOrder))); } // 5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses the denominator. if (type == 5) { if (count == 1) { return(new ExifURational(etag, ExifBitConverter.ToURational(value, byteOrder))); } return(new ExifURationalArray(etag, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } // 7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition. if (type == 7) { return(new ExifUndefined(etag, value)); } // 9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation). if (type == 9) { if (count == 1) { return(new ExifSInt(etag, conv.ToInt32(value, 0))); } return(new ExifSIntArray(etag, ExifBitConverter.ToSIntArray(value, (int)count, byteOrder))); } // 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the denominator. if (type == 10) { if (count == 1) { return(new ExifSRational(etag, ExifBitConverter.ToSRational(value, byteOrder))); } return(new ExifSRationalArray(etag, ExifBitConverter.ToSRationalArray(value, (int)count, byteOrder))); } throw new ArgumentException("Unknown property type."); }
/// <summary> /// Returns a <see cref="ImageFileDirectory" /> initialized from the given byte data. /// </summary> /// <param name="data">The data.</param> /// <param name="offset">The offset into <paramref name="data" />.</param> /// <param name="byteOrder">The byte order of <paramref name="data" />.</param> /// <returns>A <see cref="ImageFileDirectory" /> initialized from the given byte data.</returns> public static ImageFileDirectory FromBytes(byte[] data, uint offset, BitConverterEx.ByteOrder byteOrder) { var ifd = new ImageFileDirectory(); var conv = new BitConverterEx(byteOrder, BitConverterEx.SystemByteOrder); var stripOffsets = new List <uint>(); var stripLengths = new List <uint>(); // Count var fieldcount = conv.ToUInt16(data, offset); // Read fields for (uint i = 0; i < fieldcount; i++) { var fieldoffset = offset + 2 + (12 * i); var field = ImageFileDirectoryEntry.FromBytes(data, fieldoffset, byteOrder); ifd.Fields.Add(field); // Read strip offsets if (field.Tag == 273) { var baselen = field.Data.Length / (int)field.Count; for (uint j = 0; j < field.Count; j++) { var val = new byte[baselen]; Array.Copy(field.Data, j * baselen, val, 0, baselen); var stripOffset = field.Type == 3 ? BitConverter.ToUInt16(val, 0) : BitConverter.ToUInt32(val, 0); stripOffsets.Add(stripOffset); } } // Read strip lengths if (field.Tag == 279) { var baselen = field.Data.Length / (int)field.Count; for (uint j = 0; j < field.Count; j++) { var val = new byte[baselen]; Array.Copy(field.Data, j * baselen, val, 0, baselen); var stripLength = field.Type == 3 ? BitConverter.ToUInt16(val, 0) : BitConverter.ToUInt32(val, 0); stripLengths.Add(stripLength); } } } // Save strips if (stripOffsets.Count != stripLengths.Count) { throw new NotValidTIFFileException(); } for (var i = 0; i < stripOffsets.Count; i++) { ifd.Strips.Add(new TIFFStrip(data, stripOffsets[i], stripLengths[i])); } // Offset to next ifd ifd.NextIFDOffset = conv.ToUInt32(data, offset + 2 + (12 * fieldcount)); return(ifd); }
/// <summary> /// Creates an ExifProperty from the given interoperability parameters. /// </summary> /// <param name="tag">The tag id of the exif property.</param> /// <param name="type">The type id of the exif property.</param> /// <param name="count">Byte or component count.</param> /// <param name="value">Field data as an array of bytes.</param> /// <param name="byteOrder">Byte order of value.</param> /// <param name="ifd">IFD section containing this propery.</param> /// <returns>an ExifProperty initialized from the interoperability parameters.</returns> public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value, BitConverterEx.ByteOrder byteOrder, IFD ifd) { BitConverterEx conv = new BitConverterEx(byteOrder, BitConverterEx.ByteOrder.System); if (ifd == IFD.Zeroth) { if (tag == 0x103) // Compression { return(new ExifEnumProperty <Compression>(ExifTag.Compression, (Compression)conv.ToUInt16(value, 0))); } else if (tag == 0x106) // PhotometricInterpretation { return(new ExifEnumProperty <PhotometricInterpretation>(ExifTag.PhotometricInterpretation, (PhotometricInterpretation)conv.ToUInt16(value, 0))); } else if (tag == 0x112) // Orientation { return(new ExifEnumProperty <Orientation>(ExifTag.Orientation, (Orientation)conv.ToUInt16(value, 0))); } else if (tag == 0x11c) // PlanarConfiguration { return(new ExifEnumProperty <PlanarConfiguration>(ExifTag.PlanarConfiguration, (PlanarConfiguration)conv.ToUInt16(value, 0))); } else if (tag == 0x213) // YCbCrPositioning { return(new ExifEnumProperty <YCbCrPositioning>(ExifTag.YCbCrPositioning, (YCbCrPositioning)conv.ToUInt16(value, 0))); } else if (tag == 0x128) // ResolutionUnit { return(new ExifEnumProperty <ResolutionUnit>(ExifTag.ResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0))); } else if (tag == 0x132) // DateTime { return(new ExifDateTime(ExifTag.DateTime, ExifBitConverter.ToDateTime(value))); } } else if (ifd == IFD.EXIF) { if (tag == 0x9000) // ExifVersion { return(new ExifVersion(ExifTag.ExifVersion, ExifBitConverter.ToAscii(value))); } else if (tag == 0xa000) // FlashpixVersion { return(new ExifVersion(ExifTag.FlashpixVersion, ExifBitConverter.ToAscii(value))); } else if (tag == 0xa001) // ColorSpace { return(new ExifEnumProperty <ColorSpace>(ExifTag.ColorSpace, (ColorSpace)conv.ToUInt16(value, 0))); } else if (tag == 0x9286) // UserComment { byte[] encbytes = new byte[8]; byte[] strbytes = new byte[value.Length - 8]; Array.Copy(value, encbytes, 8); Array.Copy(value, 8, strbytes, 0, value.Length - 8); Encoding enc = Encoding.ASCII; string encstr = enc.GetString(encbytes); if (encstr == "ASCII\0\0\0") { enc = Encoding.ASCII; } else if (encstr == "JIS\0\0\0\0\0") { enc = Encoding.GetEncoding("Japanese (JIS 0208-1990 and 0212-1990)"); } else if (encstr == "Unicode\0") { enc = Encoding.Unicode; } else { enc = null; } int len = Array.IndexOf(strbytes, (byte)0); if (len == -1) { len = strbytes.Length; } return(new ExifEncodedString(ExifTag.UserComment, (enc == null ? Encoding.ASCII.GetString(strbytes, 0, len) : enc.GetString(strbytes, 0, len)), enc)); } else if (tag == 0x9003) // DateTimeOriginal { return(new ExifDateTime(ExifTag.DateTimeOriginal, ExifBitConverter.ToDateTime(value))); } else if (tag == 0x9004) // DateTimeDigitized { return(new ExifDateTime(ExifTag.DateTimeDigitized, ExifBitConverter.ToDateTime(value))); } else if (tag == 0x8822) // ExposureProgram { return(new ExifEnumProperty <ExposureProgram>(ExifTag.ExposureProgram, (ExposureProgram)conv.ToUInt16(value, 0))); } else if (tag == 0x9207) // MeteringMode { return(new ExifEnumProperty <MeteringMode>(ExifTag.MeteringMode, (MeteringMode)conv.ToUInt16(value, 0))); } else if (tag == 0x9208) // LightSource { return(new ExifEnumProperty <LightSource>(ExifTag.LightSource, (LightSource)conv.ToUInt16(value, 0))); } else if (tag == 0x9209) // Flash { return(new ExifEnumProperty <Flash>(ExifTag.Flash, (Flash)conv.ToUInt16(value, 0), true)); } else if (tag == 0x9214) // SubjectArea { if (count == 3) { return(new ExifCircularSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } else if (count == 4) { return(new ExifRectangularSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } else // count == 2 { return(new ExifPointSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } } else if (tag == 0xa210) // FocalPlaneResolutionUnit { return(new ExifEnumProperty <ResolutionUnit>(ExifTag.FocalPlaneResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa214) // SubjectLocation { return(new ExifPointSubjectArea(ExifTag.SubjectLocation, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } else if (tag == 0xa217) // SensingMethod { return(new ExifEnumProperty <SensingMethod>(ExifTag.SensingMethod, (SensingMethod)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa300) // FileSource { return(new ExifEnumProperty <FileSource>(ExifTag.FileSource, (FileSource)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa301) // SceneType { return(new ExifEnumProperty <SceneType>(ExifTag.SceneType, (SceneType)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa401) // CustomRendered { return(new ExifEnumProperty <CustomRendered>(ExifTag.CustomRendered, (CustomRendered)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa402) // ExposureMode { return(new ExifEnumProperty <ExposureMode>(ExifTag.ExposureMode, (ExposureMode)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa403) // WhiteBalance { return(new ExifEnumProperty <WhiteBalance>(ExifTag.WhiteBalance, (WhiteBalance)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa406) // SceneCaptureType { return(new ExifEnumProperty <SceneCaptureType>(ExifTag.SceneCaptureType, (SceneCaptureType)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa407) // GainControl { return(new ExifEnumProperty <GainControl>(ExifTag.GainControl, (GainControl)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa408) // Contrast { return(new ExifEnumProperty <Contrast>(ExifTag.Contrast, (Contrast)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa409) // Saturation { return(new ExifEnumProperty <Saturation>(ExifTag.Saturation, (Saturation)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa40a) // Sharpness { return(new ExifEnumProperty <Sharpness>(ExifTag.Sharpness, (Sharpness)conv.ToUInt16(value, 0), true)); } else if (tag == 0xa40c) // SubjectDistanceRange { return(new ExifEnumProperty <SubjectDistanceRange>(ExifTag.SubjectDistance, (SubjectDistanceRange)conv.ToUInt16(value, 0), true)); } } else if (ifd == IFD.GPS) { if (tag == 0) // GPSVersionID { return(new ExifVersion(ExifTag.GPSVersionID, ExifBitConverter.ToString(value))); } else if (tag == 1) // GPSLatitudeRef { return(new ExifEnumProperty <GPSLatitudeRef>(ExifTag.GPSLatitudeRef, (GPSLatitudeRef)value[0])); } else if (tag == 2) // GPSLatitude { return(new GPSLatitudeLongitude(ExifTag.GPSLatitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } else if (tag == 3) // GPSLongitudeRef { return(new ExifEnumProperty <GPSLongitudeRef>(ExifTag.GPSLongitudeRef, (GPSLongitudeRef)value[0])); } else if (tag == 4) // GPSLongitude { return(new GPSLatitudeLongitude(ExifTag.GPSLongitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } else if (tag == 5) // GPSAltitudeRef { return(new ExifEnumProperty <GPSAltitudeRef>(ExifTag.GPSAltitudeRef, (GPSAltitudeRef)value[0])); } else if (tag == 7) // GPSTimeStamp { return(new GPSTimeStamp(ExifTag.GPSTimeStamp, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } else if (tag == 9) // GPSStatus { return(new ExifEnumProperty <GPSStatus>(ExifTag.GPSStatus, (GPSStatus)value[0])); } else if (tag == 10) // GPSMeasureMode { return(new ExifEnumProperty <GPSMeasureMode>(ExifTag.GPSMeasureMode, (GPSMeasureMode)value[0])); } else if (tag == 12) // GPSSpeedRef { return(new ExifEnumProperty <GPSSpeedRef>(ExifTag.GPSSpeedRef, (GPSSpeedRef)value[0])); } else if (tag == 14) // GPSTrackRef { return(new ExifEnumProperty <GPSDirectionRef>(ExifTag.GPSTrackRef, (GPSDirectionRef)value[0])); } else if (tag == 16) // GPSImgDirectionRef { return(new ExifEnumProperty <GPSDirectionRef>(ExifTag.GPSImgDirectionRef, (GPSDirectionRef)value[0])); } else if (tag == 19) // GPSDestLatitudeRef { return(new ExifEnumProperty <GPSLatitudeRef>(ExifTag.GPSDestLatitudeRef, (GPSLatitudeRef)value[0])); } else if (tag == 20) // GPSDestLatitude { return(new GPSLatitudeLongitude(ExifTag.GPSDestLatitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } else if (tag == 21) // GPSDestLongitudeRef { return(new ExifEnumProperty <GPSLongitudeRef>(ExifTag.GPSDestLongitudeRef, (GPSLongitudeRef)value[0])); } else if (tag == 22) // GPSDestLongitude { return(new GPSLatitudeLongitude(ExifTag.GPSDestLongitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } else if (tag == 23) // GPSDestBearingRef { return(new ExifEnumProperty <GPSDirectionRef>(ExifTag.GPSDestBearingRef, (GPSDirectionRef)value[0])); } else if (tag == 25) // GPSDestDistanceRef { return(new ExifEnumProperty <GPSDistanceRef>(ExifTag.GPSDestDistanceRef, (GPSDistanceRef)value[0])); } else if (tag == 29) // GPSDate { return(new ExifDateTime(ExifTag.GPSDateStamp, ExifBitConverter.ToDateTime(value, false))); } else if (tag == 30) // GPSDifferential { return(new ExifEnumProperty <GPSDifferential>(ExifTag.GPSDifferential, (GPSDifferential)conv.ToUInt16(value, 0))); } } else if (ifd == IFD.Interop) { if (tag == 1) // InteroperabilityIndex { return(new ExifAscii(ExifTag.InteroperabilityIndex, ExifBitConverter.ToAscii(value))); } else if (tag == 2) // InteroperabilityVersion { return(new ExifVersion(ExifTag.InteroperabilityVersion, ExifBitConverter.ToAscii(value))); } } else if (ifd == IFD.First) { if (tag == 0x103) // Compression { return(new ExifEnumProperty <Compression>(ExifTag.ThumbnailCompression, (Compression)conv.ToUInt16(value, 0))); } else if (tag == 0x106) // PhotometricInterpretation { return(new ExifEnumProperty <PhotometricInterpretation>(ExifTag.ThumbnailPhotometricInterpretation, (PhotometricInterpretation)conv.ToUInt16(value, 0))); } else if (tag == 0x112) // Orientation { return(new ExifEnumProperty <Orientation>(ExifTag.ThumbnailOrientation, (Orientation)conv.ToUInt16(value, 0))); } else if (tag == 0x11c) // PlanarConfiguration { return(new ExifEnumProperty <PlanarConfiguration>(ExifTag.ThumbnailPlanarConfiguration, (PlanarConfiguration)conv.ToUInt16(value, 0))); } else if (tag == 0x213) // YCbCrPositioning { return(new ExifEnumProperty <YCbCrPositioning>(ExifTag.ThumbnailYCbCrPositioning, (YCbCrPositioning)conv.ToUInt16(value, 0))); } else if (tag == 0x128) // ResolutionUnit { return(new ExifEnumProperty <ResolutionUnit>(ExifTag.ThumbnailResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0))); } else if (tag == 0x132) // DateTime { return(new ExifDateTime(ExifTag.ThumbnailDateTime, ExifBitConverter.ToDateTime(value))); } } // Find the exif tag corresponding to given tag id ExifTag etag = ExifTagFactory.GetExifTag(ifd, tag); if (type == 1) // 1 = BYTE An 8-bit unsigned integer. { if (count == 1) { return(new ExifByte(etag, value[0])); } else { return(new ExifByteArray(etag, value)); } } else if (type == 2) // 2 = ASCII An 8-bit byte containing one 7-bit ASCII code. { return(new ExifAscii(etag, ExifBitConverter.ToAscii(value))); } else if (type == 3) // 3 = SHORT A 16-bit (2-byte) unsigned integer. { if (count == 1) { return(new ExifUShort(etag, conv.ToUInt16(value, 0))); } else { return(new ExifUShortArray(etag, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder))); } } else if (type == 4) // 4 = LONG A 32-bit (4-byte) unsigned integer. { if (count == 1) { return(new ExifUInt(etag, conv.ToUInt32(value, 0))); } else { return(new ExifUIntArray(etag, ExifBitConverter.ToUIntArray(value, (int)count, byteOrder))); } } else if (type == 5) // 5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses the denominator. { if (count == 1) { return(new ExifURational(etag, ExifBitConverter.ToURational(value, byteOrder))); } else { return(new ExifURationalArray(etag, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder))); } } else if (type == 7) // 7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition. { return(new ExifUndefined(etag, value)); } else if (type == 9) // 9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation). { if (count == 1) { return(new ExifSInt(etag, conv.ToInt32(value, 0))); } else { return(new ExifSIntArray(etag, ExifBitConverter.ToSIntArray(value, (int)count, byteOrder))); } } else if (type == 10) // 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the denominator. { if (count == 1) { return(new ExifSRational(etag, ExifBitConverter.ToSRational(value, byteOrder))); } else { return(new ExifSRationalArray(etag, ExifBitConverter.ToSRationalArray(value, (int)count, byteOrder))); } } else { throw new ArgumentException("Unknown property type."); } }
public static ushort ReadUInt16(this FileStream stream, bool isLittleEndian) { return(stream.Read(bytes => BitConverterEx.ToUInt16(bytes, 0, isLittleEndian))); }