I have a set of methods in my utility class.
They should be converting between WPF and Windows image types but when I use them my image gets downscaled by a lot(from reviewing the code it should only resize it by 1 pixel or so on both axes due to double to int conversions but I'm obviously missing something)
I apologize for the gigantic post, I just can't seem to find the problem.
ImageSource (WPF) to Bitmap (Windows) methods :
public Bitmap ImageSourceToBitmap(Image source)
{
var targetBitmap = new RenderTargetBitmap(
(int) source.Source.Width,
(int) source.Source.Height,
96d, 96d,
PixelFormats.Pbgra32);
targetBitmap.Render(source);
var memoryStream = new MemoryStream();
var bitmapEncoder = new BmpBitmapEncoder();
bitmapEncoder.Frames.Add(BitmapFrame.Create(targetBitmap));
bitmapEncoder.Save(memoryStream);
memoryStream.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memoryStream;
bitmapImage.EndInit();
var resultBitmap = BitmapSourceToBitmap(bitmapImage);
return resultBitmap;
}
public Bitmap BitmapSourceToBitmap(BitmapSource source)
{
var width = source.PixelWidth;
var height = source.PixelHeight;
var stride = width * ((source.Format.BitsPerPixel + 7) / 8);
var ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(height * stride);
source.CopyPixels(new Int32Rect(0, 0, width, height), ptr, height * stride, stride);
using (var bitmap = new Bitmap(width, height, stride,
PixelFormat.Format32bppPArgb, ptr))
{
return new Bitmap(bitmap);
}
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
}
Bitmap(Windows) to BitmapSource(WPF) Method :
public BitmapSource BitmapToBitmapSource(Bitmap source)
{
var bitmapData = source.LockBits(
new Rectangle( 0, 0,source.Width, source.Height ),
ImageLockMode.ReadOnly,
source.PixelFormat );
//Names might be a bit confusing but I didn't have time to refactor
var bitmapSource = BitmapSource.Create(
bitmapData.Width,
bitmapData.Height,
source.HorizontalResolution,
source.VerticalResolution,
PixelFormats.Pbgra32,
null,
bitmapData.Scan0,
bitmapData.Stride * bitmapData.Height,
bitmapData.Stride );
source.UnlockBits(bitmapData);
return bitmapSource;
}
XAML of my Image Control :
<Border Name="CurrentImageGridBorder" Grid.Column="0" Grid.Row="2" Margin="10" BorderThickness="1" Width="Auto" Height="Auto">
<Border.BorderBrush>
<SolidColorBrush Color="{DynamicResource BorderColor}"/>
</Border.BorderBrush>
<Grid x:Name="CurrentImageGrid" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center">
<Image x:Name="CurrentImage"
RenderOptions.BitmapScalingMode="HighQuality"
UseLayoutRounding="True"
SnapsToDevicePixels="True"/>
</Grid>
</Border>
WPF Control that triggers my GetImageSource method
<Button x:Name="OpenButton"
Content="Open"
Style="{DynamicResource {x:Type Button}}"
HorizontalAlignment="Left" Margin="20" VerticalAlignment="Top" Width="75" Height="20"
Click="GetImageSource"/>
GetImageSource Method :
private void GetImageSource(object sender, RoutedEventArgs e)
{
var openFileDialog = new OpenFileDialog
{
Title = "Select an Image",
Filter = "Image Files (*.jpg;*.jpeg;*.png;*.bmp)|*.jpg;*.jpeg;*.png;*.bmp|" +
"JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
"Portable Network Graphic|*.png",
ValidateNames = true,
Multiselect = false
};
if (openFileDialog.ShowDialog() != true) return;
CurrentImage.Source = new BitmapImage(new Uri(openFileDialog.FileName));
CurrentImage.Stretch = Stretch.None;
if (!(CurrentImage.Source.Width > CurrentImageGridBorder.ActualWidth) &&
!(CurrentImage.Source.Height > CurrentImageGridBorder.ActualHeight)) return;
CurrentImage.StretchDirection = StretchDirection.Both;
CurrentImage.Stretch = Stretch.Uniform;
}