/// <summary> /// Initializes a new instance of the <see cref="JPEGFile" /> class from the /// specified data stream. /// </summary> /// <param name="stream">A <see cref="Sytem.IO.Stream" /> that contains image data.</param> /// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param> protected internal TIFFFile(Stream stream, Encoding encoding) { Format = ImageFileFormat.TIFF; IFDs = new List <ImageFileDirectory>(); Encoding = encoding; // Read the entire stream var data = Utility.GetStreamBytes(stream); // Read the TIFF header TIFFHeader = TIFFHeader.FromBytes(data, 0); var nextIFDOffset = TIFFHeader.IFDOffset; if (nextIFDOffset == 0) { throw new NotValidTIFFileException("The first IFD offset is zero."); } // Read IFDs in order while (nextIFDOffset != 0) { var ifd = ImageFileDirectory.FromBytes(data, nextIFDOffset, TIFFHeader.ByteOrder); nextIFDOffset = ifd.NextIFDOffset; IFDs.Add(ifd); } // Process IFDs // TODO: Add support for multiple frames foreach (ImageFileDirectoryEntry field in IFDs[0].Fields) { Properties.Add(ExifPropertyFactory.Get(field.Tag, field.Type, field.Count, field.Data, BitConverterEx.SystemByteOrder, IFD.Zeroth, Encoding)); } }
private void SaveImageToCameraRoll(Stream stream, MemoryStream thumbStream) { string fileName = DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff") + "#" + m_sequenceGuid.ToString(); ExifFile exif = ExifFile.ReadStream(stream); string metadata = GetMetadata(fileName); byte[] data = Encoding.UTF8.GetBytes(metadata); uint length = (uint)data.Length; ushort type = 2; var imgDescProp = ExifPropertyFactory.Get(0x010e, type, length, data, BitConverterEx.ByteOrder.BigEndian, IFD.Zeroth); exif.Properties.Add(ExifTag.ImageDescription, imgDescProp); using (var ml = new MediaLibrary()) { exif.SaveToCameraRoll("mapi_" + fileName + ".jpg", ml); using (var memstream = new MemoryStream()) { WriteableBitmap bmp = new WriteableBitmap(100, 75); bmp = bmp.FromStream(thumbStream); WriteableBitmap tBmp = bmp.Resize(100, 75, WriteableBitmapExtensions.Interpolation.NearestNeighbor); tBmp.SaveJpeg(memstream, 100, 75, 0, 90); memstream.Seek(0, SeekOrigin.Begin); ml.SavePictureToCameraRoll("mapi_thumb_" + fileName + ".jpg", memstream); } } stream.Close(); thumbStream.Close(); stream.Dispose(); thumbStream.Dispose(); }
private void SaveImageToIsoStore(Stream stream, MemoryStream thumbStream) { string fileName = DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff") + "#" + m_sequenceGuid.ToString(); ExifFile exif = ExifFile.ReadStream(stream); string metadata = GetMetadata(fileName); byte[] data = Encoding.UTF8.GetBytes(metadata); uint length = (uint)data.Length; ushort type = 2; var imgDescProp = ExifPropertyFactory.Get(0x010e, type, length, data, BitConverterEx.ByteOrder.BigEndian, IFD.Zeroth); exif.Properties.Add(ExifTag.ImageDescription, imgDescProp); using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication()) { if (!isStore.DirectoryExists("shared")) { isStore.CreateDirectory("shared"); } if (!isStore.DirectoryExists("shared\\transfers")) { isStore.CreateDirectory("shared\\transfers"); } using (IsolatedStorageFileStream targetStream = isStore.OpenFile(@"shared\\transfers\" + fileName + ".jpg", FileMode.Create, FileAccess.Write)) { exif.SaveStream(targetStream); } using (IsolatedStorageFileStream thumbtargetStream = isStore.OpenFile(@"shared\\transfers\thumb_" + fileName + ".jpg", FileMode.Create, FileAccess.Write)) { WriteableBitmap bmp = new WriteableBitmap(100, 75); bmp = bmp.FromStream(thumbStream); WriteableBitmap tBmp = bmp.Resize(100, 75, WriteableBitmapExtensions.Interpolation.NearestNeighbor); tBmp.SaveJpeg(thumbtargetStream, 100, 75, 0, 90); } stream.Close(); thumbStream.Close(); stream.Dispose(); thumbStream.Dispose(); } }
/// <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 rotateBtn_Click(object sender, RoutedEventArgs e) { previewImage.Source = null; if (m_selectedFile != null) { Dictionary <ExifTag, ExifProperty> exifProperties = new Dictionary <ExifTag, ExifProperty>(); using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) { WriteableBitmap bmp = new WriteableBitmap(0, 0); string exifData = null; using (var fileStream = storage.OpenFile(m_selectedFile.Path, FileMode.Open, FileAccess.Read, FileShare.Read)) { ExifFile exif = ExifFile.ReadStream(fileStream); var data = exif.Properties[ExifTag.ImageDescription]; exifData = (string)data.Value; fileStream.Close(); } using (var fileStream = storage.OpenFile(m_selectedFile.Path, FileMode.Open, FileAccess.Read, FileShare.Read)) { bmp = bmp.FromStream(fileStream); bmp = bmp.Rotate(90); fileStream.Close(); } lock (readLock) { using (IsolatedStorageFileStream stream = storage.CreateFile(@"shared\\transfers\" + m_selectedFile.Name)) { bmp.SaveJpeg(stream, bmp.PixelWidth, bmp.PixelHeight, 0, 98); stream.Close(); } } ExifFile exifRotated; using (var fileStream = storage.OpenFile(m_selectedFile.Path, FileMode.Open, FileAccess.Read, FileShare.Read)) { exifRotated = ExifFile.ReadStream(fileStream); fileStream.Close(); byte[] data = Encoding.UTF8.GetBytes(exifData); uint length = (uint)data.Length; ushort type = 2; var imgDescProp = ExifPropertyFactory.Get(0x010e, type, length, data, BitConverterEx.ByteOrder.BigEndian, IFD.Zeroth); exifRotated.Properties.Add(ExifTag.ImageDescription, imgDescProp); } lock (readLock) { using (IsolatedStorageFileStream targetStream = storage.OpenFile(m_selectedFile.Path, FileMode.Create, FileAccess.Write, FileShare.None)) { exifRotated.SaveStream(targetStream); targetStream.Close(); } } previewImage.Source = bmp; } } if (m_selectedThumbFile != null) { using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication()) { var bmp = new WriteableBitmap(0, 0); bool exist = storage.FileExists(m_selectedThumbFile.Path); if (exist) { using (var fileStream = storage.OpenFile(m_selectedThumbFile.Path, FileMode.Open, FileAccess.Read, FileShare.None)) { bmp = bmp.FromStream(fileStream); bmp = bmp.Rotate(90); fileStream.Close(); } lock (readLock) { using (IsolatedStorageFileStream stream = storage.CreateFile(@"shared\\transfers\" + m_selectedThumbFile.Name)) { bmp.SaveJpeg(stream, bmp.PixelWidth, bmp.PixelHeight, 0, 98); stream.Close(); } } viewModel.PhotoList[m_selectionIndex - 1].ImageSource = new BitmapImage(new Uri(m_selectedThumbFile.Path)) { CreateOptions = BitmapCreateOptions.IgnoreImageCache }; } } } }