public static UInt16 RotateImageViaInPlaceBitmapMetadataWriter(string filename, UInt16 prevOrient) { // InPlaceBitmapMetadataWriter allows us to modify the metadata (exif) directly to the original file (without a temp file) // assuming there is enough space, otherwise padding must be added. For orientation the space is constant, so it should // always work if the orientation field already exists UInt16 orient = 1; orient = (UInt16)GetNextRotationOrientation(prevOrient); // get new rotation // This only works for jpg photos if (!filename.EndsWith("jpg")) { Console.WriteLine("The file you passed in is not a JPEG."); throw new ArgumentException("The file you passed in is not a JPEG:\n " + filename, "filename"); } // This code is based on http://blogs.msdn.com/b/rwlodarc/archive/2007/07/18/using-wpf-s-inplacebitmapmetadatawriter.aspx using (Stream originalFile = File.Open(filename, FileMode.Open, FileAccess.ReadWrite)) { ConsoleColor originalColor = Console.ForegroundColor; BitmapDecoder output = BitmapDecoder.Create(originalFile, BitmapCreateOptions.None, BitmapCacheOption.Default); InPlaceBitmapMetadataWriter metadata = output.Frames[0].CreateInPlaceBitmapMetadataWriter(); // Within the InPlaceBitmapMetadataWriter, you can add, update, or remove metadata. if (!metadata.ContainsQuery("/app1")) { metadata.SetQuery("/app1", new BitmapMetadata("app1")); } if (!metadata.ContainsQuery("/app1/{ushort=0}")) { metadata.SetQuery("/app1/{ushort=0}", new BitmapMetadata("ifd")); } metadata.SetQuery("/app1/{ushort=0}/{ushort=274}", orient); //set next rotation if (metadata.TrySave()) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("InPlaceMetadataWriter succeeded!"); } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("InPlaceMetadataWriter failed!"); throw new Exception("Rotate Image failed. Try to 'S' (Show in Folder) and manually rotate it."); } Console.ForegroundColor = originalColor; return(orient); } }
private void CreateAndShowMainWindow() { // Create the application's main window mainWindow = new Window(); mainWindow.Title = "Image Metadata"; // <SnippetSetQuery> Stream pngStream = new System.IO.FileStream("smiley.png", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); PngBitmapDecoder pngDecoder = new PngBitmapDecoder(pngStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); BitmapFrame pngFrame = pngDecoder.Frames[0]; InPlaceBitmapMetadataWriter pngInplace = pngFrame.CreateInPlaceBitmapMetadataWriter(); if (pngInplace.TrySave() == true) { pngInplace.SetQuery("/Text/Description", "Have a nice day."); } pngStream.Close(); // </SnippetSetQuery> // Draw the Image Image myImage = new Image(); myImage.Source = new BitmapImage(new Uri("smiley.png", UriKind.Relative)); myImage.Stretch = Stretch.None; myImage.Margin = new Thickness(20); // <SnippetGetQuery> // Add the metadata of the bitmap image to the text block. TextBlock myTextBlock = new TextBlock(); myTextBlock.Text = "The Description metadata of this image is: " + pngInplace.GetQuery("/Text/Description").ToString(); // </SnippetGetQuery> // Define a StackPanel to host Controls StackPanel myStackPanel = new StackPanel(); myStackPanel.Orientation = Orientation.Vertical; myStackPanel.Height = 200; myStackPanel.VerticalAlignment = VerticalAlignment.Top; myStackPanel.HorizontalAlignment = HorizontalAlignment.Center; // Add the Image and TextBlock to the parent Grid myStackPanel.Children.Add(myImage); myStackPanel.Children.Add(myTextBlock); // Add the StackPanel as the Content of the Parent Window Object mainWindow.Content = myStackPanel; mainWindow.Show(); }
// ReSharper disable once InconsistentNaming public static void WriteIPTC(string filename, IIPTCModel iptc) { Console.WriteLine($"{iptc.ByLine} {iptc.Caption} {iptc.CopyrightNotice} {iptc.Headline} {iptc.Keywords}"); string filePath = Path.Combine(Constants.PicPath, filename); using (Stream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { JpegBitmapDecoder decoder = new JpegBitmapDecoder(fs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); BitmapFrame frame = decoder.Frames[0]; var metadata = frame.Metadata.Clone() as BitmapMetadata; InPlaceBitmapMetadataWriter jpgInPlace = frame.CreateInPlaceBitmapMetadataWriter(); if (jpgInPlace != null) { jpgInPlace.SetQuery(@"/app13/irb/8bimiptc/iptc/caption", iptc.Caption); jpgInPlace.SetQuery(@"/app13/irb/8bimiptc/iptc/keywords", iptc.Keywords); jpgInPlace.SetQuery(@"/app13/irb/8bimiptc/iptc/by-line", iptc.ByLine); jpgInPlace.SetQuery(@"/app13/irb/8bimiptc/iptc/copyright notice", iptc.CopyrightNotice); jpgInPlace.SetQuery(@"/app13/irb/8bimiptc/iptc/headline", iptc.Headline); } fs.Close(); } }
public void SaveBitmap(Bitmap bitmap) { const string filetype = ".png"; string filename = DateTime.Today.Year.ToString() + "_" + DateTime.Today.Month.ToString() + "_" + DateTime.Today.Day.ToString(); filename = Path.Combine(screenshotFolder, filename); if (File.Exists(filename + filetype)) { var ExistingImage = Image.FromFile(filename + filetype); int n = 1; while (File.Exists(filename + "(" + n.ToString() + ")" + filetype)) { n++; } filename += "(" + n.ToString() + ")"; } //FileStream stream = new FileStream(filename + ".png", FileMode.CreateNew); var prop = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem)); prop.Id = 37510; prop.Type = 2; prop.Value = Encoding.UTF8.GetBytes("Hello World!"); prop.Len = prop.Value.Length; bitmap.SetPropertyItem(prop); bitmap.Save(filename + filetype); BitmapMetadata data; //FileStream stream = new FileStream(filename + filetype, FileMode.Create); //BitmapMetadata myBitmapMetadata = new BitmapMetadata("jpeg"); //myBitmapMetadata.Comment = "this is a comment"; //var encoder3 = new JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); Stream pngStream = new FileStream(filename + filetype, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); PngBitmapDecoder pngDecoder = new PngBitmapDecoder(pngStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); BitmapFrame pngFrame = pngDecoder.Frames[0]; InPlaceBitmapMetadataWriter pngInplace = pngFrame.CreateInPlaceBitmapMetadataWriter(); if (pngInplace.TrySave() == true) { pngInplace.SetQuery("/Text/Description", "Have a nice day."); } pngStream.Close(); //ImageMetadata metadata = new ImageMetadata("blah","erik","fractal","this is a comment"); //SaveEXIFMetadata(bitmap, metadata, filename + ".jpeg"); //SaveEXIFMetadataProperty(bitmap,"hello", filename + ".png"); }
//ajouter des metadata au images public void AddTags(string filename, string[] tags) { //ouvre un stream pour l'image using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { //decode l'image pour récupérer les metadata BitmapDecoder decoder = BitmapDecoder.Create(fs, BitmapCreateOptions.None, BitmapCacheOption.None); // saisi les frames bitmap, qui contiennent les metadata BitmapFrame frame = decoder.Frames[0]; // obtiens les metadata en tant que BitmapMetadata BitmapMetadata metadata = frame.Metadata as BitmapMetadata; // instancie InPlaceBitmapMetadataWriter pour écrire les metadata dans l'image InPlaceBitmapMetadataWriter writer = frame.CreateInPlaceBitmapMetadataWriter(); string[] keys; //si des metadata existent déjà if (metadata.Keywords != null) { //créé la liste complète des tags, vieux et nouveau keys = new string[metadata.Keywords.Count + tags.Length]; //récupère les valeurs des textbox var tag2 = TagWriter2.Text; int i = 0; //récupère la valeur des mots clé existant foreach (string keyword in metadata.Keywords) { keys[i] = keyword; i++; } // récupère la valeur des nouveaus mots clé foreach (string tag in tags) { keys[i] = tag; i++; } //écrit les nouvelles metadata dans l'image writer.SetQuery("System.Keywords", keys); writer.SetQuery("System.Author", tag2); } //si il n'y a pas de metadata existante else { keys = tags; //récupère les valeurs des textbox var Tag = TagWriter.Text; var tag2 = TagWriter2.Text; //écrit les nouvelles metadata dans l'image writer.SetQuery("System.Title", Tag); writer.SetQuery("System.Author", tag2); } //si il n'y a pas d'espace pour stocké les nouvelles metadata if (!writer.TrySave()) { fs.Close(); fs.Dispose(); string test = TagWriter.Text; SetUpMetadataOnImage(filename, test); } } }
public static void SetImageMetadata(string imagesFolderPath) { string originalPath = @"C:\Users\test\Desktop\test.jpg"; string outputPath = Environment.CurrentDirectory + @"\output.jpg"; string finalPath = Environment.CurrentDirectory + @"\output_beforeInPlaceBitmapMetadataWriter.jpg"; BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile; uint paddingAmount = 2048; // 2Kb padding for this example, but really this can be any value. // Our recommendation is to keep this between 1Kb and 5Kb as most metadata updates are not large. // High level overview: // 1. Perform a lossles transcode on the JPEG // 2. Add appropriate padding // 3. Optionally add whatever metadata we need to add initially // 4. Save the file // 5. For sanity, we verify that we really did a lossless transcode // 6. Open the new file and add metadata in-place using (Stream originalFile = File.Open(originalPath, FileMode.Open, FileAccess.Read)) { // Notice the BitmapCreateOptions and BitmapCacheOption. Using these options in the manner here // will inform the JPEG decoder and encoder that we're doing a lossless transcode operation. If the // encoder is anything but a JPEG encoder, then this no longer is a lossless operation. // ( Details: Basically BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile // tell the decoder to use the original image bits and BitmapCacheOption.None tells the decoder to wait // with decoding. So, at the time of encoding the JPEG encoder understands that the input was a JPEG // and just copies over the image bits without decompressing and recompressing them. Hence, this is a // lossless operation. ) BitmapDecoder original = BitmapDecoder.Create(originalFile, createOptions, BitmapCacheOption.None); if (!original.CodecInfo.FileExtensions.Contains("jpg")) { Console.WriteLine("The file you passed in is not a JPEG."); return; } JpegBitmapEncoder output = new JpegBitmapEncoder(); // If you're just interested in doing a lossless transcode without adding metadata, just do this: //output.Frames = original.Frames; // If you want to add metadata to the image using the InPlaceBitmapMetadataWriter, first add padding: if (original.Frames[0] != null && original.Frames[0].Metadata != null) { // Your gut feel may want you to do something like: // output.Frames = original.Frames; // BitmapMetadata metadata = output.Frames[0].Metadata as BitmapMetadata; // if (metadata != null) // { // metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", paddingAmount); // } // However, the BitmapMetadata object is frozen. So, you need to clone the BitmapMetadata and then // set the padding on it. Lastly, you need to create a "new" frame with the updated metadata. BitmapMetadata metadata = original.Frames[0].Metadata.Clone() as BitmapMetadata; // Of the metadata handlers that we ship in WIC, padding can only exist in IFD, EXIF, and XMP. // Third parties implementing their own metadata handler may wish to support IWICFastMetadataEncoder // and hence support padding as well. metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", paddingAmount); metadata.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", paddingAmount); metadata.SetQuery("/xmp/PaddingSchema:Padding", paddingAmount); // Since you're already adding metadata now, you can go ahead and add metadata up front. metadata.SetQuery("/app1/ifd/{uint=897}", "hello there"); metadata.SetQuery("/app1/ifd/{uint=898}", "this is a test"); metadata.Title = "This is a title"; // Create a new frame identical to the one from the original image, except the metadata will have padding. // Essentially we want to keep this as close as possible to: // output.Frames = original.Frames; output.Frames.Add(BitmapFrame.Create(original.Frames[0], original.Frames[0].Thumbnail, metadata, original.Frames[0].ColorContexts)); } using (Stream outputFile = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) { output.Save(outputFile); } } // For sanity, let's verify that the original and the output contain image bits that are the same. using (Stream originalFile = File.Open(originalPath, FileMode.Open, FileAccess.Read)) { BitmapDecoder original = BitmapDecoder.Create(originalFile, createOptions, BitmapCacheOption.None); using (Stream savedFile = File.Open(outputPath, FileMode.Open, FileAccess.Read)) { BitmapDecoder output = BitmapDecoder.Create(savedFile, createOptions, BitmapCacheOption.None); Compare(original.Frames[0], output.Frames[0], 0, "foo", Console.Out); } } // Let's copy the file before we use the InPlaceBitmapMetadataWriter so that you can verify the metadata changes. File.Copy(outputPath, finalPath, true); Console.WriteLine(); // Now let's use the InPlaceBitmapMetadataWriter. using (Stream savedFile = File.Open(outputPath, FileMode.Open, FileAccess.ReadWrite)) { ConsoleColor originalColor = Console.ForegroundColor; BitmapDecoder output = BitmapDecoder.Create(savedFile, BitmapCreateOptions.None, BitmapCacheOption.Default); InPlaceBitmapMetadataWriter metadata = output.Frames[0].CreateInPlaceBitmapMetadataWriter(); // Within the InPlaceBitmapMetadataWriter, you can add, update, or remove metadata. //metadata.SetQuery("/app1/ifd/{uint=899}", "this is a test of the InPlaceBitmapMetadataWriter"); //metadata.RemoveQuery("/app1/ifd/{uint=898}"); //metadata.SetQuery("/app1/ifd/{uint=897}", "Hello there!!"); Console.WriteLine("#####################"); Console.WriteLine(metadata.GetQuery(@"/app13/irb/8bimiptc/iptc/City")); Console.WriteLine("#####################"); metadata.SetQuery(@"/app13/irb/8bimiptc/iptc/Headline", "TEst"); metadata.SetQuery(@"/app13/irb/8bimiptc/iptc/City", "TEst"); metadata.SetQuery(@"/app13/irb/8bimiptc/iptc/CountryPrimaryLocationName", "TEst"); metadata.SetQuery(@"/app13/irb/8bimiptc/iptc/ByLine", "TEst"); metadata.SetQuery(@"/app13/irb/8bimiptc/iptc/CaptionAbstract", "TEst"); Console.WriteLine("#####################"); Console.WriteLine(metadata.GetQuery(@"/app13/irb/8bimiptc/iptc/City")); Console.WriteLine("#####################"); if (metadata.TrySave()) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("InPlaceMetadataWriter succeeded!"); } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("InPlaceMetadataWriter failed!"); } Console.ForegroundColor = originalColor; } FileInfo originalInfo = new FileInfo(originalPath); FileInfo outputInfo = new FileInfo(outputPath); FileInfo finalInfo = new FileInfo(finalPath); Console.WriteLine(outputPath); Console.WriteLine(); Console.WriteLine("Original File Size: \t\t\t{0}", originalInfo.Length); Console.WriteLine("After Padding File Size: \t\t{0}", outputInfo.Length); Console.WriteLine("After InPlaceBitmapWriter File Size: \t{0}", finalInfo.Length); }