/// <summary> /// Set exif data to Jpeg file; It blocks thread. /// Mess of this library; everything are caused by crazy Exif format. /// Note that this function overwrites ALL Exif data in the given image. /// </summary> /// <param name="OriginalImage">Target image</param> /// <param name="MetaData">An Exif data which will be added to the image.</param> /// <returns>New image</returns> public static byte[] SetMetaData(byte[] OriginalImage, JpegMetaData MetaData) { var OriginalMetaData = JpegMetaDataParser.ParseImage(OriginalImage); // Debug.WriteLine("Original image size: " + OriginalImage.Length.ToString("X")); // It seems there's a bug handling little endian jpeg image on WP OS. var OutputImageMetadataEndian = Definitions.Endian.Big; var App0Offset = 0; if (Util.GetUIntValue(OriginalImage, 2, 2, Definitions.Endian.Big) == Definitions.APP0_MARKER) { App0Offset = 2 + (int)Util.GetUIntValue(OriginalImage, 4, 2, Definitions.Endian.Big); // Debug.WriteLine("APP0 marker detected. " + App0Offset); } // Note: App1 size and ID are fixed to Big endian. UInt32 OriginalApp1DataSize = Util.GetUIntValue(OriginalImage, 4 + App0Offset, 2, Definitions.Endian.Big); // Debug.WriteLine("Original App1 size: " + OriginalApp1DataSize.ToString("X")); // 0-5 byte: Exif identify code. E, x, i, f, \0, \0 // 6-13 byte: TIFF header. endian, 0x002A, Offset to Primary IFD in 4 bytes. generally, 8 is set as the offset. var OriginalApp1Data = new byte[OriginalApp1DataSize]; Array.Copy(OriginalImage, 6 + App0Offset, OriginalApp1Data, 0, (int)OriginalApp1DataSize); var NewApp1Data = CreateApp1Data(OriginalMetaData, MetaData, OriginalApp1Data, OutputImageMetadataEndian); // Only size of App1 data is different. var NewImage = new byte[OriginalImage.Length - OriginalApp1DataSize + NewApp1Data.Length]; // Debug.WriteLine("New image size: " + NewImage.Length.ToString("X")); // Copy SOI, App1 marker var newImageHeader = new byte[4] { 0xFF, 0xD8, 0xFF, 0xE1 }; Array.Copy(newImageHeader, 0, NewImage, 0, 2 + 2); // Important note again: App 1 data size is stored in Big endian. var App1SizeData = Util.ToByte((UInt32)NewApp1Data.Length, 2, Definitions.Endian.Big); Array.Copy(App1SizeData, 0, NewImage, 4, 2); // After that, copy App1 data to new image. Array.Copy(NewApp1Data, 0, NewImage, 6, NewApp1Data.Length); // At last, copy body from original image. Array.Copy(OriginalImage, 2 + 2 + 2 + App0Offset + (int)OriginalApp1DataSize, NewImage, 2 + 2 + 2 + NewApp1Data.Length, OriginalImage.Length - 2 - 2 - 2 - App0Offset - (int)OriginalApp1DataSize); return(NewImage); }
public void OverwriteGeotag() { var task = WaitLocation(); task.Wait(); var position = task.Result; Debug.WriteLine("pos: " + position.Coordinate.Longitude + " " + position.Coordinate.Latitude); var mediaLibrary = new MediaLibrary(); int count = 0; foreach (string filename in TestFiles.ValidImages) { var image = TestUtil.GetResourceByteArray(filename); var originalMetadata = JpegMetaDataParser.ParseImage(image); var NewImage = MetaDataOperator.AddGeoposition(image, position, true); var newMetadata = JpegMetaDataParser.ParseImage(NewImage); try { var pic = mediaLibrary.SavePicture(string.Format("Exif addition test_" + count + "_{0:yyyyMMdd_HHmmss}.jpg", DateTime.Now), NewImage); } catch (NullReferenceException) { } GC.Collect(); TestUtil.IsGpsDataAdded(originalMetadata, newMetadata); using (var imageStream = TestUtil.GetResourceStream(filename)) { originalMetadata = JpegMetaDataParser.ParseImage(imageStream); var newImageStream = MetaDataOperator.AddGeoposition(imageStream, position, true); try { var pic2 = mediaLibrary.SavePicture(string.Format("Exif addition test_" + count + "_stream_{0:yyyyMMdd_HHmmss}.jpg", DateTime.Now), newImageStream); } catch (NullReferenceException) { } finally { newImageStream.Dispose(); } TestUtil.IsGpsDataAdded(originalMetadata, newMetadata); count++; } GC.Collect(); // Saving many big images in short time, memory mey be run out and it may throws NullReferenceException or OutOfMemoryException. } }
public override async Task <Tuple <BitmapImage, JpegMetaData> > PlaybackStillImage(Thumbnail content) { using (var stream = await content.CacheFile.OpenStreamForReadAsync()) { var bitmap = new BitmapImage(); await bitmap.SetSourceAsync(stream.AsRandomAccessStream()); try { var meta = await JpegMetaDataParser.ParseImageAsync(stream); return(Tuple.Create(bitmap, meta)); } catch (UnsupportedFileFormatException) { return(Tuple.Create <BitmapImage, JpegMetaData>(bitmap, null)); } } }
public override async Task <Tuple <BitmapImage, JpegMetaData> > PlaybackStillImage(Thumbnail content) { using (var res = await HttpClient.GetAsync(new Uri(content.Source.LargeUrl))) { if (!res.IsSuccessStatusCode) { throw new IOException(); } var buff = await res.Content.ReadAsBufferAsync(); using (var stream = new InMemoryRandomAccessStream()) { await stream.WriteAsync(buff); // Copy to the new stream to avoid stream crash issue. if (stream.Size == 0) { throw new IOException(); } stream.Seek(0); var bitmap = new BitmapImage(); await bitmap.SetSourceAsync(stream); try { var meta = await JpegMetaDataParser.ParseImageAsync(stream.AsStream()); return(Tuple.Create(bitmap, meta)); } catch (UnsupportedFileFormatException) { return(Tuple.Create <BitmapImage, JpegMetaData>(bitmap, null)); } } } }
/// <summary> /// Set exif data to Jpeg file; It blocks thread. /// Mess of this library; everything are caused by crazy Exif format. /// Note that this function overwrites ALL Exif data in the given image. /// </summary> /// <param name="OriginalImage">Target image. This will be disposed.</param> /// <param name="MetaData">An Exif data which will be added to the image.</param> /// <returns>New image on new stream.</returns> public static Stream SetMetaData(Stream OriginalImage, JpegMetaData MetaData) { OriginalImage.Seek(0, SeekOrigin.Begin); var OriginalMetaData = JpegMetaDataParser.ParseImage(OriginalImage); var OutputImageMetaDataEndian = Definitions.Endian.Big; var endian = Definitions.Endian.Big; OriginalImage.Position = 2; var FirstMarker = new byte[2]; OriginalImage.Read(FirstMarker, 0, 2); var App0Offset = 0; if (Util.GetUIntValue(FirstMarker, 0, 2, endian) == Definitions.APP0_MARKER) { var App0SizeData = new byte[2]; OriginalImage.Read(App0SizeData, 0, 2); App0Offset = 2 + (int)Util.GetUIntValue(App0SizeData, 0, 2, endian); } OriginalImage.Position = 4 + App0Offset; var app1sizeData = new byte[2]; OriginalImage.Read(app1sizeData, 0, 2); var OriginalApp1Size = Util.GetUIntValue(app1sizeData, 0, 2, endian); OriginalImage.Position = 6 + App0Offset; var OriginalApp1Data = new byte[OriginalApp1Size]; OriginalImage.Read(OriginalApp1Data, 0, (int)OriginalApp1Size); var NewApp1Data = CreateApp1Data(OriginalMetaData, MetaData, OriginalApp1Data, OutputImageMetaDataEndian); // first 6 bytes; var NewImageHeader = new byte[6] { 0xFF, 0xD8, 0xFF, 0xE1, 0x0, 0x0 }; // No APP0 section will be stored on new image. // Important note again: App 1 data size is stored in Big endian. var App1SizeData = Util.ToByte((UInt32)NewApp1Data.Length, 2, Definitions.Endian.Big); Array.Copy(App1SizeData, 0, NewImageHeader, 4, 2); Util.DumpByteArrayAll(NewImageHeader); var NewImage = new MemoryStream(); NewImage.Write(NewImageHeader, 0, 6); NewImage.Write(NewApp1Data, 0, NewApp1Data.Length); // forward pointer to start position of original body data OriginalImage.Position = 6 + App0Offset + OriginalApp1Size; // Copy all other data from original image. int BufSize = 4096; byte[] buffer = new byte[BufSize]; int numBytes; int count = 0; while ((numBytes = OriginalImage.Read(buffer, 0, BufSize)) > 0) { NewImage.Write(buffer, 0, numBytes); count += numBytes; } NewImage.Seek(0, SeekOrigin.Begin); // Debug.WriteLine("image size: " + NewImage.Length); OriginalImage.Dispose(); return(NewImage); }