'Form messed up when DPI above 96 and specific method is called
I have an overloaded method which gets the bytes in an uploaded image that seems to be causing my entire application to resize. This only seems to happen when the display scaling is anything other than 100%.
The weird thing is that the application resizes when it enters the overloaded method but before any actual code in the method is run. Even stranger, if I set the DPI scale to 100%, do the usual actions that would resize the form, and then switch the display scaling back to 125% then the resizing does not happen.
This is the method:
public static byte[] GetMultiPageImageBytes(byte[] imageBytes, double? rotationAngle, string subject)
{
using (MemoryStream inStream = new MemoryStream(imageBytes))
{
return GetMultiPageImageBytes(inStream, rotationAngle, subject);
}
}
and the overloaded method(where the resizing occurs):
public static byte[] GetMultiPageImageBytes(Stream inStream, double? rotationAngle, string subject)
{ /************************ APP RESIZES ON THIS LINE ************************/
BitmapDecoder decoder = new TiffBitmapDecoder(inStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
foreach (BitmapFrame frame in decoder.Frames)
{
BitmapMetadata metadata = null;
if (subject != null)
{
metadata = new BitmapMetadata("tiff");
metadata.Subject = subject;
}
TransformedBitmap rotatedImage = null;
if (rotationAngle != null)
{
System.Windows.Media.RotateTransform transform = new System.Windows.Media.RotateTransform(rotationAngle.Value);
rotatedImage = new TransformedBitmap(frame, transform);
}
BitmapSource sourceImage = rotatedImage != null ? (BitmapSource)rotatedImage : (BitmapSource)frame;
BitmapFrame newFrame = BitmapFrame.Create(sourceImage, frame.Thumbnail, metadata, frame.ColorContexts);
encoder.Frames.Add(newFrame);
}
using (MemoryStream outStream = new MemoryStream())
{
encoder.Save(outStream);
return outStream.ToArray();
}
}
I've tried SetProcessDPIAware() which got rid of the problem but that messed up the layout of dozens of other forms and components. The application is too big in order to optimize for DPI awareness at this point as I would need to reformat dozens of components.
I also tried removing the using statement in the original method which calls the overloaded method and just manually disposing the stream but that didn't work either:
// Didn't work
public static byte[] GetMultiPageImageBytes(byte[] imageBytes, double? rotationAngle, string subject)
{
MemoryStream inStream = new MemoryStream(imageBytes);
byte[] bytes;
bytes = GetMultiPageImageBytes(inStream, rotationAngle, subject);
inStream.Dispose();
inStream.Close();
return bytes;
}
Any ideas as to what might be causing this? Any help with this would be greatly appreciated!
Solution 1:[1]
Partial answer - this is probably happening in a static constructor for some class that is first used in this method. Static constructors are guaranteed to have been called some time before the first instantiation of the class or call to one of its static methods. It's pretty typical to see this happen at the start of a method like this. So that explains the weird timing. I'm afraid I don't know enough about WinForm or WPF to explain the rest, so I'll not speculate.
Specifically, I'm suggesting that any of the following classes' static constructors would be expected to be invoked at the beginning of your second GetMultiPageImageBytes method, if they haven't been already:
- TiffBitmapDecoder
- TiffBitmapEncoder
- BitmapMetadata
- RotateTransform
- TransformedBitmap
- BitmapFrame
- Any of their base classes
The .NET specification won't say exactly when the static constructor will be invoked, only that it will be invoked some time before the first instantiation of the class or call to one of its static methods. Typically the behaviour that you will see is that it will be invoked at the start of a method that is going to do one of those things. That's why I'm saying it is a plausible mechanism for strange stuff happening on the first line of your method, even though it hasn't done anything yet. It could well be that such a static constructor, or other code that it causes to run, is what's causing your strange behaviour.
Indeed, this answer suggests that loading any WPF classses causes the process to be set to DPI-aware. Based on that, it could be that your problem is that the WPF classes are simply not designed to be used independently in a non-WPF application. From the "WinForm" in your question title I assume that none of the rest of your app is WPF.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
