private void lvExif_SelectedIndexChanged(object sender, EventArgs e) { if (lvExif.SelectedItems.Count == 0) { tbField.Text = ""; } else { ExifProperty item = (ExifProperty)lvExif.SelectedItems[0].Tag; StringBuilder s = new StringBuilder(); s.AppendFormat("Tag: {0}{1}", item.Tag, Environment.NewLine); string val = item.ToString(); if (val.Length > 50) { val = val.Substring(0, 50) + " ..."; } s.AppendFormat("Value: {0}{1}", val, Environment.NewLine); s.AppendFormat("IFD: {0}{1}", item.IFD, Environment.NewLine); s.AppendFormat("Interop. TagID: {0} (0x{0:X2}){1}", item.Interoperability.TagID, Environment.NewLine); s.AppendFormat("Interop. Type: {0} (0x{0:X2}){1}", item.Interoperability.TypeID, Environment.NewLine); s.AppendFormat("Interop. Count: {0} (0x{0:X4}){1}", item.Interoperability.Count, Environment.NewLine); s.AppendFormat("Interop. Data Length: {0}{1}", item.Interoperability.Data.Length, Environment.NewLine); s.AppendFormat("Interop. Data: {0}", ByteArrayToString(item.Interoperability.Data), Environment.NewLine); tbField.Text = s.ToString(); } }
/// <summary> /// Gets the date the photo was taken. /// </summary> private void ReadDateTaken() { if (this.PhotoBitmap != null) { DateTime datetaken = DateTime.Now; Bitmap photo = this.PhotoBitmap; // Extract exif metadata ExifFile file = ExifFile.Read(this.FilePath); ExifProperty exifProperty = file.Properties[ExifTag.DateTime]; if (exifProperty != null) { try { datetaken = Convert.ToDateTime(exifProperty.Value); this.PhotoDateTime = datetaken; } catch { } } return; } else { throw new NullReferenceException(); } }
/// <summary> /// Sets the property int16. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <param name="value">The value.</param> protected void SetPropertyInt16(ExifProperty propertyId, Int16 value) { byte[] data = new byte[2] { (byte)(value & 0xFF), (byte)((value & 0xFF00) >> 8) }; SetProperty(propertyId, data, ExifDataTypes.SignedShort); }
/// <summary> /// Sets the property int32. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <param name="value">The value.</param> protected void SetPropertyInt32(ExifProperty propertyId, Int32 value) { byte[] data = new byte[4]; for (int I = 0; I < 4; I++) { data[I] = (byte)(value & 0xFF); value >>= 8; } SetProperty(propertyId, data, ExifDataTypes.SignedLong); }
/// <summary> /// Adds an EXIF property to an image. /// </summary> /// <param name="inputPath">file path of original image</param> /// <param name="outputPath">file path of modified image</param> /// <param name="property"></param> public static void AddExifData(string inputPath, string outputPath, ExifProperty property) { // minimally load image Image image; using (ExifReader.LoadImage(inputPath, out image)) { using (image) { ExifWriter.AddExifData(image, property); image.Save(outputPath); } } }
/// <summary> /// Sets the property. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <param name="data">The data.</param> /// <param name="type">The type.</param> protected void SetProperty(ExifProperty propertyId, byte[] data, ExifDataTypes type) { try { var property = this._image.PropertyItems[0]; property.Id = (int)propertyId; property.Value = data; property.Type = (Int16)type; property.Len = data.Length; this._image.SetPropertyItem(property); } catch (Exception ex) { throw ex.Handle(new { propertyId, type }); } }
private void lvExif_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Delete) { List <ListViewItem> toRemove = new List <ListViewItem>(); foreach (ListViewItem lvItem in lvExif.SelectedItems) { ExifProperty item = (ExifProperty)lvItem.Tag; data.Properties.Remove(item); toRemove.Add(lvItem); } foreach (ListViewItem lvItem in toRemove) { lvExif.Items.Remove(lvItem); } } }
private void cmsInterop_Opening(object sender, CancelEventArgs e) { cmsInterop.Items.Clear(); if (lvExif.SelectedItems.Count == 0) { ToolStripMenuItem menu = new ToolStripMenuItem("Select a tag to view."); menu.Enabled = false; cmsInterop.Items.Add(menu); } else { ToolStripItem menu = null; ExifProperty item = (ExifProperty)lvExif.SelectedItems[0].Tag; ExifBitConverter conv = new ExifBitConverter(BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder); byte[] bytes = item.Interoperability.Data; if (bytes.Length >= 2) { menu = new ToolStripMenuItem("ushort: " + conv.ToUInt16(bytes, 0)); cmsInterop.Items.Add(menu); menu = new ToolStripMenuItem("short: " + conv.ToInt16(bytes, 0)); cmsInterop.Items.Add(menu); menu = new ToolStripSeparator(); cmsInterop.Items.Add(menu); } if (bytes.Length >= 4) { menu = new ToolStripMenuItem("uint: " + conv.ToUInt32(bytes, 0)); cmsInterop.Items.Add(menu); menu = new ToolStripMenuItem("int: " + conv.ToInt32(bytes, 0)); cmsInterop.Items.Add(menu); menu = new ToolStripSeparator(); cmsInterop.Items.Add(menu); } { menu = new ToolStripMenuItem("ascii: " + Encoding.ASCII.GetString(bytes)); cmsInterop.Items.Add(menu); menu = new ToolStripMenuItem("utf-8: " + Encoding.UTF8.GetString(bytes)); cmsInterop.Items.Add(menu); menu = new ToolStripMenuItem("utf-16: " + Encoding.Unicode.GetString(bytes)); cmsInterop.Items.Add(menu); } } }
/// <summary> /// Adds an EXIF property to an image. /// </summary> /// <param name="image"></param> /// <param name="property"></param> public static void AddExifData(Image image, ExifProperty property) { if (image == null) { throw new ArgumentNullException("image"); } if (property == null) { return; } PropertyItem propertyItem; // The .NET interface for GDI+ does not allow instantiation of the // PropertyItem class. Therefore one must be stolen off the Image // and repurposed. GDI+ uses PropertyItem by value so there is no // side effect when changing the values and reassigning to the image. if (image.PropertyItems == null || image.PropertyItems.Length < 1) { propertyItem = ExifWriter.CreatePropertyItem(); } else { propertyItem = image.PropertyItems[0]; } propertyItem.Id = (int)property.Tag; propertyItem.Type = (short)property.Type; Type dataType = ExifDataTypeAttribute.GetDataType(property.Tag); propertyItem.Value = ExifEncoder.ConvertData(dataType, property.Type, property.Value); propertyItem.Len = propertyItem.Value.Length; // This appears to not be necessary ExifWriter.RemoveExifData(image, property.Tag); image.SetPropertyItem(propertyItem); }
/// <summary> /// /// </summary> private void buildDB(System.Drawing.Imaging.PropertyItem[] parr) { properties.Clear(); // // // foreach (System.Drawing.Imaging.PropertyItem p in parr) { if (!Enum.IsDefined(typeof(ExifProperty), p.Id)) { continue; } string v = ""; // tag not found. skip it // ExifProperty name = (ExifProperty)p.Id;; //1 = BYTE An 8-bit unsigned integer., if (p.Type == 0x1) { if (p.Id >= 0x9C9B && p.Id <= 0x9C9F) { v = cleanZeroCharacter(Encoding.Unicode.GetString(p.Value)); } else { v = cleanZeroCharacter(p.Value[0].ToString()); } } //2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL., else if (p.Type == 0x2) { // string v = getString(p.Value); } //3 = SHORT A 16-bit (2 -byte) unsigned integer, else if (p.Type == 0x3) { // orientation // lookup table switch (p.Id) { case 0x8827: // ISO v = "ISO-" + convertToInt16U(p.Value).ToString(); break; case 0xA217: // sensing method { switch (convertToInt16U(p.Value)) { case 1: v = "Not defined"; break; case 2: v = "One-chip color area sensor"; break; case 3: v = "Two-chip color area sensor"; break; case 4: v = "Three-chip color area sensor"; break; case 5: v = "Color sequential area sensor"; break; case 7: v = "Trilinear sensor"; break; case 8: v = "Color sequential linear sensor"; break; default: v = " reserved"; break; } } break; case 0x8822: // aperture switch (convertToInt16U(p.Value)) { case 0: v = "Not defined"; break; case 1: v = "Manual"; break; case 2: v = "Normal program"; break; case 3: v = "Aperture priority"; break; case 4: v = "Shutter priority"; break; case 5: v = "Creative program (biased toward depth of field)"; break; case 6: v = "Action program (biased toward fast shutter speed)"; break; case 7: v = "Portrait mode (for closeup photos with the background out of focus)"; break; case 8: v = "Landscape mode (for landscape photos with the background in focus)"; break; default: v = "reserved"; break; } break; case 0x9207: // metering mode switch (convertToInt16U(p.Value)) { case 0: v = "unknown"; break; case 1: v = "Average"; break; case 2: v = "CenterWeightedAverage"; break; case 3: v = "Spot"; break; case 4: v = "MultiSpot"; break; case 5: v = "Pattern"; break; case 6: v = "Partial"; break; case 255: v = "Other"; break; default: v = "reserved"; break; } break; case 0x9208: // light source { switch (convertToInt16U(p.Value)) { case 0: v = "unknown"; break; case 1: v = "Daylight"; break; case 2: v = "Fluorescent"; break; case 3: v = "Tungsten"; break; case 17: v = "Standard light A"; break; case 18: v = "Standard light B"; break; case 19: v = "Standard light C"; break; case 20: v = "D55"; break; case 21: v = "D65"; break; case 22: v = "D75"; break; case 255: v = "other"; break; default: v = "reserved"; break; } } break; case 0x9209: { switch (convertToInt16U(p.Value)) { case 0: v = "Flash did not fire"; break; case 1: v = "Flash fired"; break; case 5: v = "Strobe return light not detected"; break; case 7: v = "Strobe return light detected"; break; default: v = "reserved"; break; } } break; default: v = convertToInt16U(p.Value).ToString(); break; } } //4 = LONG A 32-bit (4 -byte) unsigned integer, else if (p.Type == 0x4) { // orientation // lookup table v = convertToInt32U(p.Value).ToString(); } //5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses the//denominator., else if (p.Type == 0x5) { // rational byte[] n = new byte[p.Len / 2]; byte[] d = new byte[p.Len / 2]; Array.Copy(p.Value, 0, n, 0, p.Len / 2); Array.Copy(p.Value, p.Len / 2, d, 0, p.Len / 2); uint a = convertToInt32U(n); uint b = convertToInt32U(d); Rational r = new Rational(a, b); // //convert here // switch (p.Id) { case 0x9202: // aperture v = "F/" + Math.Round(Math.Pow(Math.Sqrt(2), r.ToDouble()), 2).ToString(); break; case 0x920A: v = r.ToDouble().ToString(); break; case 0x829A: v = r.ToDouble().ToString(); break; case 0x829D: // F-number v = "F/" + r.ToDouble().ToString(); break; default: v = r.ToString("/"); break; } } //7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition, else if (p.Type == 0x7) { switch (p.Id) { case 0xA000: v = getString(p.Value); break; case 0xA300: { if (p.Value[0] == 3) { v = "DSC"; } else { v = "reserved"; } break; } case 0xA301: if (p.Value[0] == 1) { v = "A directly photographed image"; } else { v = "Not a directly photographed image"; } break; case 0x9286: if (Encoding.UTF8.GetString(p.Value, 0, 8) == "UNICODE\0") { v = cleanZeroCharacter(Encoding.Unicode.GetString(p.Value, 8, p.Len - 8)); } else { v = getString(p.Value); } break; case 36864: v = getString(p.Value); break; default: v = "-"; break; } } //9 = SLONG A 32-bit (4 -byte) signed integer (2's complement notation), else if (p.Type == 0x9) { v = convertToInt32(p.Value).ToString(); } //10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the //denominator. else if (p.Type == 0xA) { // rational byte[] n = new byte[p.Len / 2]; byte[] d = new byte[p.Len / 2]; Array.Copy(p.Value, 0, n, 0, p.Len / 2); Array.Copy(p.Value, p.Len / 2, d, 0, p.Len / 2); int a = convertToInt32(n); int b = convertToInt32(d); Rational r = new Rational(a, b); // // convert here // switch (p.Id) { case 0x9201: // shutter speed v = "1/" + Math.Round(Math.Pow(2, r.ToDouble()), 2).ToString(); break; case 0x9203: v = Math.Round(r.ToDouble(), 4).ToString(); break; default: v = r.ToString("/"); break; } } // add it to the list properties[name] = v; } }
/// <summary> /// Sets the property string. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <param name="value">The value.</param> protected void SetPropertyString(ExifProperty propertyId, string value) { byte[] data = System.Text.Encoding.UTF8.GetBytes(value.SafeToString() + '\0'); SetProperty(propertyId, data, ExifDataTypes.AsciiString); }
/// <summary> /// Gets the property geo coordinate. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <returns>System.Nullable<GeoPosition>.</returns> protected GeoCoordinate?GetPropertyGeoCoordinate(ExifProperty propertyId) { return((IsPropertyDefined(propertyId)) ? GetGeoCoordinate(this._image.GetPropertyItem((int)propertyId).Value) : null); }
/// <summary> /// Gets the property rational. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <returns>Rational.</returns> protected FractionObject?GetPropertyFractionObject(ExifProperty propertyId) { return((IsPropertyDefined(propertyId)) ? GetFractionObject(this._image.GetPropertyItem((int)propertyId).Value) : null); }
/// <summary> /// Gets the property. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <param name="defaultValue">The default value.</param> /// <returns>System.Byte[].</returns> protected byte[] GetProperty(ExifProperty propertyId, byte[] defaultValue = null) { return(IsPropertyDefined(propertyId) ? this._image.GetPropertyItem((int)propertyId).Value : defaultValue); }
/// <summary> /// Gets the property string. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <param name="defaultValue">The default value.</param> /// <returns>System.String.</returns> protected string GetPropertyString(ExifProperty propertyId, string defaultValue = "") { return(IsPropertyDefined(propertyId) ? GetString(this._image.GetPropertyItem((int)propertyId).Value) : defaultValue); }
/// <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); } } } } }
private void updateImage(bool forceUpdate) { if (!Dispatcher.CheckAccess()) // CheckAccess returns true if you're on the dispatcher thread { Dispatcher.Invoke(() => updateImage(forceUpdate)); return; } if (!IrfanWatcher.updateNeeded() && !forceUpdate) { return; } // choose an image //Console.Write("Enter image load path: "); string imagePath = IrfanWatcher.getFilePathToCurrentlyOpenedFileInIrfan(); if (String.IsNullOrEmpty(imagePath)) { return; } //Console.WriteLine(); //---------------------------------------------- // minimally loads image and closes it ExifPropertyCollection properties = ExifReader.GetExifData(imagePath); ExifProperty gpsLatitudeRefProperty = properties.FirstOrDefault(p => p.DisplayName == "GPS Latitude Ref"); if (gpsLatitudeRefProperty == null) { setImageReplacement("Picture does not contain GPS information"); return; } else { removeImageReplacement(); } string gpsLatitudeRef = ""; if (gpsLatitudeRefProperty != null) { gpsLatitudeRef = gpsLatitudeRefProperty.DisplayValue; } ExifProperty gpsLatitudeProperty = properties.First(p => p.DisplayName == "GPS Latitude"); double latitudeAsDouble = 0; if (gpsLatitudeProperty != null) { ExifUtils.Rational <uint>[] latitudeAsRational = (ExifUtils.Rational <uint>[])gpsLatitudeProperty.Value; double latitudeDegree = latitudeAsRational[0].Numerator / latitudeAsRational[0].Denominator; double latitudeMinute = latitudeAsRational[1].Numerator / latitudeAsRational[1].Denominator; double latitudeSecond = latitudeAsRational[2].Numerator / latitudeAsRational[2].Denominator; latitudeAsDouble = latitudeDegree + latitudeMinute / 60 + latitudeSecond / 3600; } if (gpsLatitudeRef == "S") { latitudeAsDouble *= -1; } ExifProperty gpsLongitudeRefProperty = properties.First(p => p.DisplayName == "GPS Longitude Ref"); string gpsLongitudeRef = ""; if (gpsLongitudeRefProperty != null) { gpsLongitudeRef = gpsLongitudeRefProperty.DisplayValue; } ExifProperty gpsLongitudeProperty = properties.First(p => p.DisplayName == "GPS Longitude"); double longitudeAsDouble = 0; if (gpsLongitudeProperty != null) { ExifUtils.Rational <uint>[] longitudeAsRational = (ExifUtils.Rational <uint>[])gpsLongitudeProperty.Value; double longitudeDegree = longitudeAsRational[0].Numerator / longitudeAsRational[0].Denominator; double longitudeMinute = longitudeAsRational[1].Numerator / longitudeAsRational[1].Denominator; double longitudeSecond = longitudeAsRational[2].Numerator / longitudeAsRational[2].Denominator; longitudeAsDouble = longitudeDegree + longitudeMinute / 60 + longitudeSecond / 3600; } if (gpsLongitudeRef == "W") { longitudeAsDouble *= -1; } int picSizeHeight = (int)this.Height; int picSizeWidth = (int)this.Width; string apiKey = ""; string mapType = "roadmap"; string floatFormatString = "F6"; string center = latitudeAsDouble.ToString(floatFormatString, CultureInfo.InvariantCulture.NumberFormat) + "," + longitudeAsDouble.ToString(floatFormatString, CultureInfo.InvariantCulture.NumberFormat); //"40.702147,-74.015794"; string zoom = zoomLevel.ToString(); string markerLocation = center; string size = picSizeWidth + "x" + picSizeHeight; System.Drawing.Image mapFromGMaps = null; if (String.IsNullOrEmpty(apiKey)) { mapFromGMaps = GetImageFromUrl("http://maps.googleapis.com/maps/api/staticmap?center=" + center + "&maptype=" + mapType + "&zoom=" + zoom + "&markers=color:red|" + markerLocation + "&size=" + size); // + "&key=" + apiKey); } else { mapFromGMaps = GetImageFromUrl("http://maps.googleapis.com/maps/api/staticmap?center=" + center + "&maptype=" + mapType + "&zoom=" + zoom + "&markers=color:red|" + markerLocation + "&size=" + size + "&key=" + apiKey); } // ImageSource ... BitmapImage bi = new BitmapImage(); bi.BeginInit(); MemoryStream ms = new MemoryStream(); // Save to a memory stream... mapFromGMaps.Save(ms, ImageFormat.Png); // Rewind the stream... ms.Seek(0, SeekOrigin.Begin); // Tell the WPF image to use this stream... bi.StreamSource = ms; bi.EndInit(); mapImage.Source = bi; }
/// <summary> /// /// </summary> /// <param name="image"></param> /// <returns></returns> public static ImageExif GetExifInfo(Image image) { //http://www.exiv2.org/tags.html ImageExif exif = new ImageExif(); List<ExifProperty> properties = new List<ExifProperty>(); exif.RawFormatID = image.RawFormat.Guid; foreach (int hex in image.PropertyIdList) { var exit = new ExifProperty(image.GetPropertyItem(hex)); properties.Add(exit); switch ((int)hex) { case 274: { var value = Convert.ToUInt16(exit.DisplayValue); if (value != 0) exif.Orientation = ObjectUtility.Cast<Orientation>(value); break; } case 40091: exif.Title = ObjectUtility.Cast<string>(exit.DisplayValue); break; case 40092: exif.Comment = GetStringUnicode(image, hex); break; case 40093: exif.Author = ObjectUtility.Cast<string>(exit.DisplayValue); break; case 40094: exif.Keyword = GetStringUnicode(image, hex); break; case 40095: exif.Subject = GetStringUnicode(image, hex); break; case 33432: exif.Copyright = ObjectUtility.Cast<string>(exit.DisplayValue); break; case 270: exif.Description = ObjectUtility.Cast<string>(exit.DisplayValue); break; case 271: exif.EquipmentMake = ObjectUtility.Cast<string>(exit.DisplayValue); break; case 272: exif.EquipmentModel = ObjectUtility.Cast<string>(exit.DisplayValue); break; case 34850: { var value = ObjectUtility.Cast<short>(exit.DisplayValue); exif.ExposureProgram = ObjectUtility.Cast<ExposurePrograms>(value); ; break; } case 34855: exif.ISOSpeedRatings = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 37384: exif.Flash = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 37385: exif.LightSource = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 37383: exif.MeteringMode = ObjectUtility.Cast<int>(exit.DisplayValue); break; case 18246: exif.Rating = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 41987: exif.WhiteBalance = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 41992: exif.Contrast = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 41993: exif.Saturation = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 41994: exif.Sharpness = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 33434: exif.ExposureTime =Rational.GetRational(exit.Value) ; break; case 41989: exif.FocalLengthIn35mmFilm = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 36867: exif.DateTimeOriginal = GetDateTime(image, hex); break; case 37377: exif.ShutterSpeed = GetDouble(image, hex); break; case 36868: exif.DateTimeDigitized = GetDateTime(image, hex); break; case 36864: exif.ExifVersion = ObjectUtility.Cast<string>(exit.DisplayValue); break; case 531: exif.YCbCrPositioning = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 20625: exif.ChrominanceTable = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 20624: exif.LuminanceTable = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 20507: exif.ThumbnailData = image.GetPropertyItem(hex).Value; break; case 20528: exif.ThumbnailResolutionUnit = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 20515: exif.ThumbnailCompression = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 296: exif.ResolutionUnit = ObjectUtility.Cast<short>(exit.DisplayValue); break; case 282: case 283: { var unit = exif.ResolutionUnit; if (unit == 0 && image.PropertyIdList.Contains(296)) { unit = GetInt(image, 296); } var r = (unit == 3) ? 2.54f : 1f; if (exif.Resolution == null && image.PropertyIdList.Contains(282) && image.PropertyIdList.Contains(283)) exif.Resolution = new SizeF(r * GetInt(image, 282), r * GetInt(image, 283)); break; } case 20525: case 20526: { if (exif.Pix == null && image.PropertyIdList.Contains(20525) && image.PropertyIdList.Contains(20526)) exif.ThumbnailResolution = new Size(GetInt(image, 20525), GetInt(image, 20526)); break; } case 40962: case 40963: { if (exif.Pix == null && image.PropertyIdList.Contains(40962) && image.PropertyIdList.Contains(40963)) exif.Pix = new Size(GetInt(image, 40962), GetInt(image, 40963)); break; } case 1: case 2: case 3: case 4: case 5: case 6: case 29: { if (image.PropertyIdList.Contains(1) && image.PropertyIdList.Contains(2)) { if (exif.GPS == null) { exif.GPS = new GPSGeo() { LatitudeRef = GetStringAsc(image, 1), Latitude = GetDouble(image, 2), }; } else { exif.GPS.LatitudeRef = GetStringAsc(image, 1); exif.GPS.Latitude = GetDouble(image, 2); } } if (image.PropertyIdList.Contains(3) && image.PropertyIdList.Contains(4)) { if (exif.GPS == null) { exif.GPS = new GPSGeo() { LongitudeRef = GetStringAsc(image, 3), Longitude = GetDouble(image, 4), }; } else { exif.GPS.LongitudeRef = GetStringAsc(image, 3); exif.GPS.Longitude = GetDouble(image, 4); } } if (image.PropertyIdList.Contains(5) && image.PropertyIdList.Contains(6)) { if (exif.GPS == null) { exif.GPS = new GPSGeo() { AltitudeRef = GetStringAsc(image, 5), Altitude = GetDouble(image, 6), }; } else { exif.GPS.AltitudeRef = GetStringAsc(image, 5); exif.GPS.Altitude = GetDouble(image, 6); } } if (image.PropertyIdList.Contains(29)) { if (exif.GPS == null) { exif.GPS = new GPSGeo() { DateStamp = DateTime.ParseExact(GetStringAsc(image, 29), "yyyy:MM:dd", null) }; } else { exif.GPS.DateStamp = DateTime.ParseExact(GetStringAsc(image, 29), "yyyy:MM:dd", null); } } break; } } } exif.Properties = new ExifPropertyCollection(properties); return exif; }
static void Main(string[] args) { // choose an image Console.Write("Enter image load path: "); string imagePath = Console.ReadLine(); int lastDot = imagePath.LastIndexOf('.'); Console.WriteLine(); //---------------------------------------------- // minimally loads image and closes it ExifPropertyCollection properties = ExifReader.GetExifData(imagePath); string dumpPath = imagePath.Substring(0, lastDot) + "_EXIF" + imagePath.Substring(lastDot) + ".txt"; using (StreamWriter dumpWriter = File.CreateText(dumpPath)) { // dump properties to console foreach (ExifProperty property in properties) { dumpWriter.WriteLine("{0}.{1}: \"{2}\"", property.Tag.GetType().Name, property.Tag, property.DisplayName); dumpWriter.WriteLine("{0}: {1}", GetPropertyTypeName(property.Value), property.Value); dumpWriter.WriteLine("\"{0}\"", property.DisplayValue); dumpWriter.WriteLine(); } } Console.WriteLine(); //---------------------------------------------- #if TEST string outputPath = imagePath.Substring(0, lastDot) + "_COPYRIGHT_LOREM_IPSUM" + imagePath.Substring(lastDot); Console.WriteLine("Adding dummy copyright to image and saving to:\r\n\t" + outputPath); // add copyright tag ExifProperty copyright = new ExifProperty(); copyright.Tag = ExifTag.Copyright; copyright.Value = String.Format( "Copyright (c){0} Lorem ipsum dolor sit amet. All rights reserved.", DateTime.Now.Year); ExifWriter.AddExifData(imagePath, outputPath, copyright); Console.WriteLine(); //---------------------------------------------- foreach (ExifTagOrientation i in Enum.GetValues(typeof(ExifTagOrientation))) { outputPath = imagePath.Substring(0, lastDot) + "_Orientation_" + (int)i + imagePath.Substring(lastDot); Console.WriteLine("Adding orientation to image and saving to:\r\n\t" + outputPath); // add orientation tag ExifProperty orientTag = new ExifProperty(); orientTag.Tag = ExifTag.Orientation; orientTag.Value = i; ExifWriter.AddExifData(imagePath, outputPath, orientTag); Console.WriteLine(); } #endif }
/// <summary> /// update EXIF datetime from GPS Data. /// optional rename file to correct DateTime /// https://oozcitak.github.io/exiflibrary/articles/ReadFile.html /// </summary> /// <param name="filename">input filename. full path</param> /// <param name="outPutFolderName">folder to save fixed file. empty to use same.</param> /// <param name="RenameFile">rename output to date_time</param> /// <returns></returns> /// public static string FixEXIFtimestamp(string filename) { bool keepExistingFile = true; FileInfo fi = new FileInfo(filename); if (string.IsNullOrEmpty(outPutFolderName)) { outPutFolderName = fi.Directory.FullName; keepExistingFile = false; OverwriteFile = true; } if (fi.Name == "Thumbs.db") { return(""); //dont process } ExifLibrary.ImageFile exiffile; try { exiffile = ExifLibrary.ImageFile.FromFile(filename); } catch (ExifLibrary.NotValidImageFileException) { if (RenameVids) { //does the name match datetime yyyyMMdd_HHmmss string saveVName; char[] separators = new char[] { '_', '-' }; string[] dateparts = Path.GetFileNameWithoutExtension(fi.Name).Split(separators, StringSplitOptions.RemoveEmptyEntries); string stdfmt = string.Format("{0}-{1}", dateparts[0], dateparts[1]); bool success = DateTime.TryParseExact( stdfmt, "yyyyMMdd-HHmmss", CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out DateTime fileNameDate); if (success) { //rename the file as date_time var nextGPStime = fileNameDate.Add(lastCameraOffset); string newName = nextGPStime.ToString("yyyyMMdd_HHmmss"); newName += fi.Extension; saveVName = Path.Combine(outPutFolderName, newName); if (OverwriteFile && saveVName == fi.FullName) { keepExistingFile = false; } else { keepExistingFile = true; }; } else { return(""); } if (!keepExistingFile) { fi.MoveTo(saveVName); //rename file; //delete the redundant original as saved to new folder or new name } else { fi.CopyTo(saveVName); } //keep existing return(saveVName); } else { return(""); } } catch (Exception) { throw; } // GPS latitude is a custom type with three rational values // representing degrees/minutes/seconds of the latitude var gpsLatTag = exiffile.Properties.Get <GPSLatitudeLongitude>(ExifTag.GPSLatitude); var gpsLongTag = exiffile.Properties.Get <GPSLatitudeLongitude>(ExifTag.GPSLongitude); var gpsDate = exiffile.Properties.Get <ExifDate>(ExifTag.GPSDateStamp); var gpsTime = exiffile.Properties.Get <GPSTimeStamp>(ExifTag.GPSTimeStamp); string cameramodel = exiffile.Properties.Get(ExifTag.Model).Value.ToString(); if (!cameraTimeOffsetbase.ContainsKey(cameramodel)) { throw new Exception("unexpected camera model"); } TimeSpan baseOffset = cameraTimeOffsetbase[cameramodel]; if (!cameraTimeOffset.ContainsKey(cameramodel)) { cameraTimeOffset.Add(cameramodel, baseOffset); lastCameraOffset = baseOffset; } else { lastCameraOffset = cameraTimeOffset[cameramodel]; } ExifProperty exifDatetag = exiffile.Properties.Get(ExifTag.DateTimeOriginal); if (exifDatetag == null) { exifDatetag = exiffile.Properties.Get(ExifTag.DateTime); } DateTime cameraDateTime = (exifDatetag as ExifDateTime).Value; DateTime localGPStime; if (gpsDate is null) { //use lastCameraOffset; if (OffsetUseFixed) { lastCameraOffset = baseOffset; } localGPStime = cameraDateTime.Add(lastCameraOffset); //ExifProperty exifDateOriginal = exiffile.Properties.Get(ExifTag.DateTimeOriginal); exiffile.Properties.Set(ExifTag.DateTime, localGPStime); exiffile.Properties.Set(ExifTag.DateTimeOriginal, localGPStime); } else { var gpsLatTagR = exiffile.Properties.Get <ExifEnumProperty <GPSLatitudeRef> >(ExifTag.GPSLatitudeRef); var gpsLongTagR = exiffile.Properties.Get <ExifEnumProperty <GPSLongitudeRef> >(ExifTag.GPSLongitudeRef); float gpsLat = gpsLatTag.ToFloat(); if (gpsLat > 0 && gpsLatTagR.Value == GPSLatitudeRef.South) { gpsLat *= -1; //North = 1, south = -1 } float gpsLong = gpsLongTag.ToFloat(); if (gpsLong > 0 && gpsLongTagR.Value == GPSLongitudeRef.West) { gpsLong *= -1; //east=1, west=-1 } DateTime UTCDateTime = gpsDate.Value + new TimeSpan((int)gpsTime.Hour, (int)gpsTime.Minute, (int)gpsTime.Second); localGPStime = GPSMethods.GetLocalTimefromGPS(gpsLat, gpsLong, UTCDateTime); lastCameraOffset = localGPStime.Subtract(cameraDateTime); //save for next time if (!cameraTimeOffset.ContainsKey(cameramodel)) { cameraTimeOffset.Add(cameramodel, lastCameraOffset); } else { cameraTimeOffset[cameramodel] = lastCameraOffset; } // ExifProperty exifDateOriginal = exiffile.Properties.Get(ExifTag.DateTimeOriginal); exiffile.Properties.Set(ExifTag.DateTime, localGPStime); exiffile.Properties.Set(ExifTag.DateTimeOriginal, localGPStime); } string saveName; if (RenameFile_asDate) { //rename the file as date_time string newName = localGPStime.ToString("yyyyMMdd_HHmmss"); int uniquenum = 0; saveName = Path.Combine(outPutFolderName, newName + fi.Extension); while (File.Exists(saveName) && saveName != fi.FullName) { uniquenum++; saveName = Path.Combine(outPutFolderName, newName + string.Format("-{0}", uniquenum) + fi.Extension); } if (OverwriteFile && saveName != fi.FullName) { keepExistingFile = false; } else { keepExistingFile = true; }; } else { saveName = Path.Combine(outPutFolderName, filename); } if (!keepExistingFile) { fi.Delete(); //delete the redundant original as saved to new folder or new name } exiffile.Save(saveName); //save exif data back to file return(saveName); }
/// <summary> /// Determines whether [is property defined] [the specified property identifier]. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <returns><c>true</c> if [is property defined] [the specified property identifier]; otherwise, <c>false</c>.</returns> protected bool IsPropertyDefined(ExifProperty propertyId) { return(Array.IndexOf(this._image.PropertyIdList, (int)propertyId) > -1); }
private void LoadbaseProps() { ExifProperty exifDatetag = ExifFile.Properties.Get(ExifTag.DateTimeOriginal); if (exifDatetag == null) { exifDatetag = ExifFile.Properties.Get(ExifTag.DateTime); } if (exifDatetag == null) { return; } CameraDate = (exifDatetag as ExifDateTime).Value; CameraName = ExifFile.Properties.Get(ExifTag.Model).Value.ToString(); CameraMake = ExifFile.Properties.Get(ExifTag.Make).Value.ToString(); // GPS latitude is a custom type with three rational values // representing degrees/minutes/seconds of the latitude var gpsLatTag = ExifFile.Properties.Get <GPSLatitudeLongitude>(ExifTag.GPSLatitude); var gpsLongTag = ExifFile.Properties.Get <GPSLatitudeLongitude>(ExifTag.GPSLongitude); var gpsLatRef = ExifFile.Properties.Get <ExifEnumProperty <GPSLatitudeRef> >(ExifTag.GPSLatitudeRef); var gpsLongRef = ExifFile.Properties.Get <ExifEnumProperty <GPSLongitudeRef> >(ExifTag.GPSLongitudeRef); var gpsDate = ExifFile.Properties.Get <ExifDate>(ExifTag.GPSDateStamp); var gpsTime = ExifFile.Properties.Get <GPSTimeStamp>(ExifTag.GPSTimeStamp); if (gpsLatTag is null) { GPSLongitude = -999; GPSLatitude = -999; GPSUTCDate = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Unspecified); return; } else { GPSLatitude = gpsLatTag.ToFloat(); GPSLongitude = gpsLongTag.ToFloat(); if (gpsLatRef.Value == GPSLatitudeRef.South) { GPSLatitude *= -1; } if (gpsLongRef.Value == GPSLongitudeRef.West) { GPSLongitude *= -1; } } if (gpsDate is null) { GPSUTCDate = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Unspecified); } else { GPSUTCDate = gpsDate.Value + new TimeSpan((int)gpsTime.Hour, (int)gpsTime.Minute, (int)gpsTime.Second); GPSUTCDate = DateTime.SpecifyKind(GPSUTCDate, DateTimeKind.Utc); } }
/// <summary> /// Gets the property int16. /// </summary> /// <param name="propertyId">The property identifier.</param> /// <param name="defaultValue">The default value.</param> /// <returns>Int16.</returns> protected Int16 GetPropertyInt16(ExifProperty propertyId, Int16 defaultValue = 0) { return(IsPropertyDefined(propertyId) ? GetInt16(this._image.GetPropertyItem((int)propertyId).Value) : defaultValue); }
private void WriteIFD(MemoryStream stream, Dictionary <ExifTag, ExifProperty> ifd, IFD ifdtype, long tiffoffset, bool preserveMakerNote) { BitConverterEx conv = new BitConverterEx(BitConverterEx.ByteOrder.System, ByteOrder); // Create a queue of fields to write Queue <ExifProperty> fieldqueue = new Queue <ExifProperty>(); foreach (ExifProperty prop in ifd.Values) { if (prop.Tag != ExifTag.MakerNote) { fieldqueue.Enqueue(prop); } } // Push the maker note data to the end if (ifd.ContainsKey(ExifTag.MakerNote)) { fieldqueue.Enqueue(ifd[ExifTag.MakerNote]); } // Offset to start of field data from start of TIFF header uint dataoffset = (uint)(2 + ifd.Count * 12 + 4 + stream.Position - tiffoffset); uint currentdataoffset = dataoffset; long absolutedataoffset = stream.Position + (2 + ifd.Count * 12 + 4); bool makernotewritten = false; // Field count stream.Write(conv.GetBytes((ushort)ifd.Count), 0, 2); // Fields while (fieldqueue.Count != 0) { ExifProperty field = fieldqueue.Dequeue(); ExifInterOperability interop = field.Interoperability; uint fillerbytecount = 0; // Try to preserve the makernote data offset if (!makernotewritten && !makerNoteProcessed && makerNoteOffset != 0 && ifdtype == IFD.EXIF && field.Tag != ExifTag.MakerNote && interop.Data.Length > 4 && currentdataoffset + interop.Data.Length > makerNoteOffset && ifd.ContainsKey(ExifTag.MakerNote)) { // Delay writing this field until we write makernote data fieldqueue.Enqueue(field); continue; } else if (field.Tag == ExifTag.MakerNote) { makernotewritten = true; // We may need to write filler bytes to preserve maker note offset if (preserveMakerNote && !makerNoteProcessed) { fillerbytecount = makerNoteOffset - currentdataoffset; } else { fillerbytecount = 0; } } // Tag stream.Write(conv.GetBytes(interop.TagID), 0, 2); // Type stream.Write(conv.GetBytes(interop.TypeID), 0, 2); // Count stream.Write(conv.GetBytes(interop.Count), 0, 4); // Field data byte[] data = interop.Data; if (ByteOrder != BitConverterEx.SystemByteOrder) { if (interop.TypeID == 1 || interop.TypeID == 3 || interop.TypeID == 4 || interop.TypeID == 9) { Array.Reverse(data); } else if (interop.TypeID == 5 || interop.TypeID == 10) { Array.Reverse(data, 0, 4); Array.Reverse(data, 4, 4); } } // Fields containing offsets to other IFDs // Just store their offets, we will write the values later on when we know the lengths of IFDs if (ifdtype == IFD.Zeroth && interop.TagID == 0x8769) { exifIFDFieldOffset = stream.Position; } else if (ifdtype == IFD.Zeroth && interop.TagID == 0x8825) { gpsIFDFieldOffset = stream.Position; } else if (ifdtype == IFD.EXIF && interop.TagID == 0xa005) { interopIFDFieldOffset = stream.Position; } else if (ifdtype == IFD.First && interop.TagID == 0x201) { thumbOffsetLocation = stream.Position; } else if (ifdtype == IFD.First && interop.TagID == 0x202) { thumbSizeLocation = stream.Position; } // Write 4 byte field value or field data if (data.Length <= 4) { stream.Write(data, 0, data.Length); for (int i = data.Length; i < 4; i++) { stream.WriteByte(0); } } else { // Pointer to data area relative to TIFF header stream.Write(conv.GetBytes(currentdataoffset + fillerbytecount), 0, 4); // Actual data long currentoffset = stream.Position; stream.Seek(absolutedataoffset, SeekOrigin.Begin); // Write filler bytes for (int i = 0; i < fillerbytecount; i++) { stream.WriteByte(0xFF); } stream.Write(data, 0, data.Length); stream.Seek(currentoffset, SeekOrigin.Begin); // Increment pointers currentdataoffset += fillerbytecount + (uint)data.Length; absolutedataoffset += fillerbytecount + data.Length; } } // Offset to 1st IFD // We will write zeros for now. This will be filled after we write all IFDs if (ifdtype == IFD.Zeroth) { firstIFDFieldOffset = stream.Position; } stream.Write(new byte[] { 0, 0, 0, 0 }, 0, 4); // Seek to end of IFD stream.Seek(absolutedataoffset, SeekOrigin.Begin); // Write thumbnail data if (ifdtype == IFD.First) { if (Thumbnail != null) { MemoryStream ts = new MemoryStream(); Thumbnail.Save(ts); ts.Close(); byte[] thumb = ts.ToArray(); thumbOffsetValue = (uint)(stream.Position - tiffoffset); thumbSizeValue = (uint)thumb.Length; stream.Write(thumb, 0, thumb.Length); ts.Dispose(); } else { thumbOffsetValue = 0; thumbSizeValue = 0; } } }
public ExifPropertyDescriptor(ExifProperty property) : base(property.Name, new Attribute[] { new BrowsableAttribute(true) }) { linkedProperty = property; originalValue = property.Value; }