|
This is probably embarrassingly simple to accomplish but in researching and researching I can't find the answer.
I've captured the BitmapMetadata from the image file I'm transforming. Then I have successfully used TransformBitmap and ScaleTransform to scale from and to any of the six image formats supported by WPF, all without a hitch -- except one hitch which I knew I would have to deal with after getting the basic scaling mechanism working. The problem is getting the metadata transferred from the source image files to the destination image files.
There are Metadata properties in all six encoders but when I try to assign the metadata from the original image I get an exception complaining, "The designated BitmapEncoder does not support global metadata." Is "non-global metadata" a BitmapFrame? That only has a "get" property, no "set". That's the problem with all the speculations I've come up with to solve this problem: you can't assign a BitmapMetadata object to the Metadata property of any BitmapSource-derived class that I've been able to find. Looking for a solution in that direction just leads me up blind alleys.
A related issue is that I've read that when creating a new image from existing bitmap data, if you want metadata in the image, it has to be added before the bitmap data. But I haven't been able to figure out how to do that, either.
I have several books on WPF. None of them get remotely near to dealing with these issues, as fundamental as they are.
So what is the solution? It's got to be embarrassingly simple and I'm going to kick myself when I see it, but I'll be eternally grateful to anyone who supplies me with the answer.
|
|
|
|
|
I thought I finally came up with the solution very elegantly, but was shocked to find out that what seemed like the obvious answer simply does not work. As I mentioned, I am correctly capturing the metadata from the original image. Then in doggedly perusing the MSDN documentation, I slapped myself aside the head when I noticed an additional signature to BitmapFrame.Create() that seemed to supply the answer. Originally I was using this signature:
public static BitmapFrame Create(BitmapSource source)
After looking over the additional signatures for Create, I noticed this one:
public static BitmapFrame Create(
BitmapSource source,
BitmapSource thumbnail,
BitmapMetadata metadata,
ReadOnlyCollection<ColorContext> colorContexts
)
Eureka! I thought. But after enhancing my call to the latter, the destination files still have no metadata, as if the metadata parameter is just being ignored.
I am just stunned. The source parameter isn't being ignored: the original image is correctly scaled in the new file. At least I'm not getting an exception anymore, but now I am more baffled than ever. Here is my code, expanded more than is needed if the code worked, but parameters exposed so I could trace into the code to see if anything looked wrong (destinationPath and metadata are input parameters to the function):
WmpBitmapEncoder encoderWmp = new WmpBitmapEncoder();
FileStream stream = new FileStream(destinationPath, FileMode.Create);
BitmapMetadata bm = (BitmapMetadata)metadata;
encoderWmp.Frames.Add(BitmapFrame.Create(scaledBitmap, null, bm, null));
BitmapFrame bf = encoderWmp.Frames[0];
encoderWmp.Save(stream);
I wanted to see if bf still contained my original bitmap metadata. Tracing into the code indicates that it does! How could anything be set up more perfectly? Yet the metadata does not get into the image when the Save in the last statement is executed.
What seemed like an obvious oversight on my part is just another dead end. This would have been a supremely elegant solution to the problem, but it doesn't work.
|
|
|
|
|
Either nobody cares about image processing in WPF or everyone thinks the answer to the question is so obvious that it doesn't deserve an answer. Well, I have beaten my head against the wall for 10 hours today on this one and gotten nowhere. I have also had a fellow programmer working on this for about five hours and he must be just as brain-damaged as I am because he isn't getting anywhere, either.
The BitmapFrame I create has my metadata in it. When I add it to the BitmapEncoder its Metadata property is null. bf in my previous code snip above has my metadata in it intact, but a lot of good it does because it disappears once the BitmapEncoder is saved. Not that anyone really cares apparently.
|
|
|
|
|
After agonizing over this for three days, it occurred to me that my mistake may be one I've made several times before with C#, thinking like the C++ programmer I was for 20 years and failing to distinguish between reference and value parameters. When I "grab" the metadata from the source file, I'm not really grabbing the data. I'm just grabbing a reference to it and, sure, when I put that reference into the destination file, it shows up in the debugger -- until I close the source file and the reference is destroyed. Then when I look in the destination file, the reference is null. So maybe I'm doing the right thing, except I should be making a deep copy of the metadata, not just shoving a reference down the throat of the BitmapFrame.Create() call. So somehow I have to figure out how to put a copy of the metadata into the destination, and not just a reference to the copy in the destination, either. This may be nothing more than a C# misunderstanding. Maybe nobody has responded because everybody reading this thread realized that and figured I'm just a beginniner who should go learn C# first before posting up here.
modified on Sunday, May 3, 2009 7:58 AM
|
|
|
|
|
After further thought, I'm no longer convinced that my explanation of reference vs. value type parameters isn't anything more than a rationalization of something that Microsoft simply failed to implement. So what if I'm passing in a reference? Internally, the function that takes the metadata parameter should itself make the deep copy and add it to the destination file. The client shouldn't have to concern himself with this issue.
At any rate, there is a method called
BitmapMetadata.Clone() that is supposed to make a deep copy of the metadata and I tried it and of course it doesn't solve the problem. I just don't think .NET 3.5 is ready to do this yet.
|
|
|
|
|
There isn't a trivial solution to this problem. My feeling (without actually pulling the code together to try it) is that you may need to use a variation on this[^] to accomplish it.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Thanks for the reference. I'll try that solution. Of course I'm now off on another aspect of my program, but there is strong demand for not losing metadata after image scaling or rotating, so I'll be getting back to this within a few days. My original scaling dialog involved over 1,000 lines of code (any format to any format and from any size, to any size), so proportionally speaking, the suggested solution is only a fraction of what I've already had to do for this one operation in my program.
|
|
|
|
|
I may have a play round with it this week. If I can get something working, I'll post it up on my blog and let you know.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
That would be fantastic. I'm head over heals right now. But putting together a generic class to do this would be extremely valuable to all us WPF image rendering folks who don't want to destroy existing metadata. I don't expect you to write such a class. Just a proof of concept would be great. I'd probably wrap it up into a nice tidy class, for my own use if for nothing else, and if I get it to work, offer it to this site. I expect something like that will be available in .NET 4.0 for WPF, but that's months away.
|
|
|
|
|
fjparisIII wrote: I don't expect you to write such a class.
When I write for my blog, I normally try to create a functioning application to work things out. That way I don't end up looking like a total nugget.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Did you ever get around to trying this? I've run out of important things to do on my project so this is next. I'm going to investigate the information on the link you provided and see how far I get.
|
|
|
|
|
I tried to get the code in the link you provided to work and it's an utter joke. It doesn't work at all. I get the following exception: "The image data generated an overflow during processing." Real helpful. I only found one reference on the WEB to that message. Someone asked what it meant and no one answered.
I've read dozens and dozens of posts about people failing in the attempt to copy metadata under WPF. It just doesn't work. The fact that you never responded back after expressing an intention to see if you could get it to work tells me that you failed as well.
|
|
|
|
|
Does anyone here have any thoughts or comments on this?
Because of the way that Silverlight apps run it seems to me that it would be simpler to store stuff that would typically go into a cookie in isolated storage. However, the users expectation to be able to clear data by using the Internet properties window would not (I think) have an impact any any of these stored settings so...
Thoughts?
|
|
|
|
|
Even though they can be used the same way, they are different.
Isolated storage provides a complete virtual file system to a restricted
application, which is much more robust than cookies.
I don't have good "answer" for this, but I would say - examine the pros and cons of both
and use what's appropriate.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Put a GUID in the cookie, store that GUID in your isolated storage, if they go to the page and the GUID is missing then wipe the part of the isolated storage you would have expected the user to "clear" by manually clearing it. This way you can properly clear user data, but get the benefits of using local storage instead of a cookie.
(If it's a security issue, put a key in the cookie instead of a GUID).
|
|
|
|
|
Good people,
I have a few quick questions.
1) Is it ok to use data binding and value converters in data templates defined in my resource dictionary?
2) If so, is it a bug in my expression blend that it is not allowing me to do that?
3) If I can't what is the best work-around.
Any information you provide would be greatly appreciated.
Thank,
Blitz
|
|
|
|
|
Yes you can do this. I do it all the time.
Check you converter. Your converter must be able to handle a null value being passed in without throwing an exception.
Please post your converter code.
modified 27-Feb-21 21:01pm.
|
|
|
|
|
First, thanks for replying. I really appreciate your help.
Below is the code for my value converter:
<code>
public class DoubleToStringEventAverageDuration : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double average = (double)value;
int digits = 1;
return Constants.EventLogisticsAverageDuration + Math.Round(average, digits).ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// Not implemented
return Constants.EmptyNumericValue;
}
}
</code>
Let me know your thoughts.
Thanks,
Blitz
|
|
|
|
|
You MUST add a null check for value before ever using it. If it's null (like when it's in the designer because there is no data) this will be a big problem.
If value is null, just return a default value that makes sense, like 0.
modified 27-Feb-21 21:01pm.
|
|
|
|
|
Thanks again,
I thought "double" couldn't be null.
So should I change it from the explicit cast and use the "as" cast then test for null?
Blitz
|
|
|
|
|
double can't, but object can, and you're casting from an object to double. Try using double.TryParse in the conversion, e.g.
double doublevalue = 0M;
double.TryParse(value, out doublevalue);
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
No check if value is null. If it is return a sensible value like 0.
modified 27-Feb-21 21:01pm.
|
|
|
|
|
Thank you both. I made the corrections.
It seems, however, that Blend still won't do it. In fact, it is not even allowing me to do the databinding in templates within the resource dictionary (when I use the designer).
I figure it must be a bug with Blend.
Thanks again,
Blitz
|
|
|
|
|
Hey all,
I have done a few wpf apps now and decided to make a deployable xbap app. I am mucking around with ellipses and wanted to be able to move an ellipse in a canvas. I have done this fine using the mouse click (i.e. if clicked move ellipse right 20) but for some reason I can't handle the keyup events in the app?
Can an xbap handle page level key presses?
Thanks
Some days robin you just can't get rid of a bomb.
|
|
|
|
|
Hi
anyone please help.
I want multi lingual support for my product developing in silverlight
I read many articles from Net, but coul'd sucessfully implement it.
I am unable to read strings from Resource file and show in the different language chosen.
although I changed in InternetExplorer settings, only default language is shown(interestingly the silverlight controls' names are getting changed)
Regards,
Manju
|
|
|
|