private void TryAlternateMethodsOfPersistingMetadata(string sourceFileName, string outputFileName, MetadataItemName metaName, MetaPersistAction persistAction) { // Three alternate attempts to persist the metadata: // 1. Use outputFileName parameter and a cloned copy of the file's metadata // 2. Use outputFileName parameter and the original file's metadata // 3. Rename the file and try again using a cloned copy of the file's metadata // Adapted from: https://code.google.com/p/flickrmetasync/source/browse/trunk/FlickrMetadataSync/Picture.cs?spec=svn29&r=29 bool tryOneLastMethod = false; using (Stream originalFile = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { const BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile; BitmapDecoder original = BitmapDecoder.Create(originalFile, createOptions, BitmapCacheOption.None); var output = new JpegBitmapEncoder(); if (original.Frames[0] != null && original.Frames[0].Metadata != null) { BitmapMetadata bitmapMetadata = original.Frames[0].Metadata.Clone() as BitmapMetadata; bitmapMetadata.SetQuery("/app1/ifd/PaddingSchema:Padding", MetadataPaddingInBytes); bitmapMetadata.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", MetadataPaddingInBytes); bitmapMetadata.SetQuery("/xmp/PaddingSchema:Padding", MetadataPaddingInBytes); SetMetadata(bitmapMetadata, metaName, persistAction); output.Frames.Add(BitmapFrame.Create(original.Frames[0], original.Frames[0].Thumbnail, bitmapMetadata, original.Frames[0].ColorContexts)); } try { using (Stream outputFile = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite)) { output.Save(outputFile); } } catch (Exception e) //System.Exception, NotSupportedException, InvalidOperationException, ArgumentException { if (e is NotSupportedException || e is ArgumentException) { output = new JpegBitmapEncoder(); output.Frames.Add(BitmapFrame.Create(original.Frames[0], original.Frames[0].Thumbnail, original.Metadata, original.Frames[0].ColorContexts)); using (Stream outputFile = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite)) { output.Save(outputFile); } tryOneLastMethod = true; } else { throw new Exception("Error saving picture.", e); } } } if (tryOneLastMethod) { File.Move(outputFileName, outputFileName + "tmp"); using (Stream recentlyOutputFile = new FileStream(outputFileName + "tmp", FileMode.Open, FileAccess.Read, FileShare.Read)) { const BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile; BitmapDecoder original = BitmapDecoder.Create(recentlyOutputFile, createOptions, BitmapCacheOption.None); JpegBitmapEncoder output = new JpegBitmapEncoder(); if (original.Frames[0] != null && original.Frames[0].Metadata != null) { BitmapMetadata bitmapMetadata = original.Frames[0].Metadata.Clone() as BitmapMetadata; bitmapMetadata.SetQuery("/app1/ifd/PaddingSchema:Padding", MetadataPaddingInBytes); bitmapMetadata.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", MetadataPaddingInBytes); bitmapMetadata.SetQuery("/xmp/PaddingSchema:Padding", MetadataPaddingInBytes); SetMetadata(bitmapMetadata, metaName, persistAction); output.Frames.Add(BitmapFrame.Create(original.Frames[0], original.Frames[0].Thumbnail, bitmapMetadata, original.Frames[0].ColorContexts)); } using (Stream outputFile = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite)) { output.Save(outputFile); } } File.Delete(outputFileName + "tmp"); } }
private void SetMetadata(BitmapMetadata bitmapMetadata, MetadataItemName metaName, MetaPersistAction persistAction) { if (!UpdatableMetaItems.ContainsKey(metaName)) { throw new ArgumentException(String.Format("This function does not support persisting the meta item {0}.", metaName)); } switch (metaName) { case MetadataItemName.Orientation: SetOrientationMetadata(bitmapMetadata, metaName, persistAction); break; default: throw new InvalidEnumArgumentException(String.Format(CultureInfo.CurrentCulture, "This function is not designed to handle the enumeration value {0}. The function must be updated.", metaName)); } //if (caption != null) //{ // bitmapMetadata.Comment = caption; //} //if (dateTaken.HasValue) //{ // bitmapMetadata.DateTaken = dateTaken.Value.ToString("M/d/yyyy HH:mm:ss"); // bitmapMetadata.SetQuery(DATE_TAKEN_QUERY, dateTaken.Value.ToString("yyyy:MM:dd HH:mm:ss")); // bitmapMetadata.SetQuery(DIGITIZED_DATE_QUERY, dateTaken.Value.ToString("yyyy:MM:dd HH:mm:ss")); // bitmapMetadata.SetQuery(ORIGINAL_DATE_QUERY, dateTaken.Value.ToString("yyyy:MM:dd HH:mm:ss")); //} ////-----------tags---------------------- //List<String> tagsList = new List<String>(); //foreach (string tag in tags) //{ // if (tag.Length > 0) // tagsList.Add(tag); //} //if (tagsList.Count == 0) // tagsList.Add(""); ////XMP //bitmapMetadata.Keywords = new System.Collections.ObjectModel.ReadOnlyCollection<string>(tagsList); ////IPTC //string[] iptcTagsList = tagsList.ToArray(); //bitmapMetadata.SetQuery(IPTC_KEYWORDS_QUERY, iptcTagsList); ////-----------tags---------------------- }
private void SetOrientationMetadata(BitmapMetadata bitmapMetadata, MetadataItemName metaName, MetaPersistAction persistAction) { switch (persistAction) { case MetaPersistAction.Delete: bitmapMetadata.RemoveQuery(UpdatableMetaItems[metaName]); break; case MetaPersistAction.Save: IGalleryObjectMetadataItem orientationMeta; if (GalleryObject.MetadataItems.TryGetMetadataItem(metaName, out orientationMeta)) { ushort orientationRaw; if (UInt16.TryParse(orientationMeta.RawValue, out orientationRaw) && MetadataEnumHelper.IsValidOrientation((Orientation)orientationRaw)) { bitmapMetadata.SetQuery(UpdatableMetaItems[metaName], orientationRaw); } } break; default: throw new InvalidEnumArgumentException(String.Format(CultureInfo.CurrentCulture, "This function is not designed to handle the enumeration value {0}. The function must be updated.", persistAction)); } }
/// <summary> /// Persists the meta value. /// </summary> /// <param name="metaName">Name of the meta.</param> /// <param name="persistAction">The persist action.</param> private void PersistMetaValue(MetadataItemName metaName, MetaPersistAction persistAction) { if (!UpdatableMetaItems.ContainsKey(metaName)) { EventController.RecordEvent(String.Format("This version of Gallery Server Pro does not support modifying the meta value {0} in the original file. The request to save or delete the meta value was ignored.", metaName)); return; } lock (_sharedLock) { bool isSuccessful = false; var filePath = GalleryObject.Original.FileNamePhysicalPath; using (Stream savedFile = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite)) { var output = BitmapDecoder.Create(savedFile, BitmapCreateOptions.None, BitmapCacheOption.Default); var bitmapMetadata = output.Frames[0].CreateInPlaceBitmapMetadataWriter(); if (bitmapMetadata != null) { SetMetadata(bitmapMetadata, metaName, persistAction); if (bitmapMetadata.TrySave()) { isSuccessful = true; } } } // If the save wasn't successful, try to save another way. if (!isSuccessful) { string tmpFilePath = Path.Combine(AppSetting.Instance.TempUploadDirectory, String.Concat(Guid.NewGuid().ToString(), ".tmp")); TryAlternateMethodsOfPersistingMetadata(filePath, tmpFilePath, metaName, persistAction); ReplaceFileSafely(tmpFilePath, filePath); } } }