Open Evheni opened 2 years ago
TrySave
here isn't the same as the other Try*
methods where you get a result indicating success or failure. TrySave is actually testing to see if you can modify the metadata or not. If it returns true
you should be able to write directly to the metadat with .SetQuery
. When the stream is closed the metadata should be written.
What makes you think it's not working? And are you using .NET 6 or .NET Framework?
EDIT:
My description of TrySave
was based on the API documentation, which is misleading. Looking at the source code confirms it actually does try to save and returns the result of that save.
I'm using .Net Framework 4.7.2
I assume, when we read (.GetQuery
) the same query, the return value shouldn't be null.
I tried both saving before and after .SetQuery
.
Do you need the image I used?
@Evheni I've transferred this issue to the WPF team.
I can't figure this out. I've been trying to for 1.5 hours and it just doesn't work. Can someone please help this customer?
You most certainly need to call TrySave
to save the changes done by SetQuery
which is the only way to invoke IWICFastMeatadataEncoder::Commit
, see an example here: https://learn.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicfastmetadataencoder
If it returns false
, the changes cannot be done in place and you need to re-encode the bitmap.
The example (which is on multiple pages) could use some improvements indeed.
Thanks @miloush
@Evheni After a lot of trial and error, I got it working:
const string FILE = @"c:\path\to\your\file.png";
// Open the file for reading
using (Stream pngStream = new FileStream(FILE, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
var pngDecoder = new PngBitmapDecoder(pngStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapFrame pngFrame = pngDecoder.Frames[0];
InPlaceBitmapMetadataWriter pngInplace = pngFrame.CreateInPlaceBitmapMetadataWriter();
// Set metadata here
pngInplace.SetQuery("/Text/Description", "Have a nice day.");
// Try to save in place, if failed, recreate the png
if (!pngInplace.TrySave())
{
// Use a secondary stream for writing
using (var pngSaveStream = new FileStream(FILE, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
var pngEncoder = new PngBitmapEncoder();
// Duplicate each frame
foreach (var frame in pngDecoder.Frames)
pngEncoder.Frames.Add(BitmapFrame.Create(frame));
// Set the required metadata
((BitmapMetadata)pngEncoder.Frames[0].Metadata).SetQuery("/Text/Description", "Have a nice day.");
pngEncoder.Save(pngSaveStream);
} // close\dispose pngSaveStream
}
} // close\dispose pngStream
Works for me. Thanks. Will you update the example section?
I agree the documentation should be fixed, but this is not a very nice example. It also does not make much sense, since the built-in PNG codec does not support in-place metadata at all, see the table here: https://learn.microsoft.com/en-us/windows/win32/wic/-wic-about-metadata#supported-metadata-formats
Sure thing, I'll get things updated.
@miloush I tried using a jpg but I get an error trying to save the file:
System.NotSupportedException: 'No imaging component suitable to complete this operation was found.'
using (var imageStream = new System.IO.FileStream("smiley.jpg", FileMode.Open,
FileAccess.ReadWrite,
FileShare.ReadWrite))
{
var decoder = new JpegBitmapDecoder(imageStream,
BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.Default);
BitmapFrame frame = decoder.Frames[0];
// Try to set the metadata directly on the image
InPlaceBitmapMetadataWriter inplaceMetadata = frame.CreateInPlaceBitmapMetadataWriter();
inplaceMetadata.SetQuery("/Text/Description", "Have a nice day.");
if (!inplaceMetadata.TrySave())
{
// In place metadata save failed, must rencode image
using (var saveStream = new FileStream("smiley.jpg", FileMode.Open,
FileAccess.Write,
FileShare.ReadWrite))
{
var encoder = new JpegBitmapEncoder();
// Duplicate each frame
foreach (var cloneFrame in decoder.Frames)
encoder.Frames.Add(BitmapFrame.Create(cloneFrame));
// Set metadata
((BitmapMetadata)encoder.Frames[0].Metadata).SetQuery("/Text/Description", "Have a nice day.");
encoder.Save(saveStream); // <------- ERROR
}
}
}
How did you come up with /Text/Description
? I believe that is supposed to be PNG tEXt chunk. Would e.g. System.Title
work for you? See https://learn.microsoft.com/en-us/windows/win32/wic/-wic-native-image-format-metadata-queries for supported format-specific queries.
I don't know, it was in the example. The error was vague so I didn't really know what to do. Thank you for that link, it clears up a lot of things.
Yeah just scratch that example. On one of the pages it even says it's an example for TIFF files...
I think it's important for users to know that WIC is providing the imaging features in WPF and they can reach out there for details. If you can sneak that somewhere somehow, that would be great!
Yep, will do!
This submission has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 14 days.
It will be closed if no further activity occurs within 7 days of this comment.
This is still in progress.. I've just not found the time to get back to the docs and update them.
This submission has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 14 days.
It will be closed if no further activity occurs within 7 days of this comment.
@adegeo Is this still in progress ? If so, I think we can remove the waiting-author-feedback label.
Code example doesn't work. TrySave method is called before the changes in metadata. If we add saving after the changes, the TrySave method returns false.
Document Details
⚠ Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.