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(); }
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); }