将图像加载到ImageSource中 - 宽度和高度不正确

16

我的问题是,从应用程序资源中加载图像似乎不正确。这是代码:

    BitmapImage bi = new BitmapImage();
    bi.BeginInit();
    bi.UriSource = new Uri(@"pack://application:,,,/WpfApplication3;component/Resources/Images/16x16_incorrect.png", UriKind.Absolute);
    bi.EndInit();

    ImageSource s = bi;

图像文件 16x16_incorrect.png 是一张 16x16 的32位PNG文件,但在执行上述代码后,s.Width = s.Height = 21,59729。我还有另一张文件 - 16x16_correct.png,加载时,ImageSource的 WidthHeight 都等于16.002。

其他图片都加载不正确,看起来模糊或平滑,因为系统将它们从16x16拉伸到21x21。

  • 正确图片:Correct Image
  • 不正确图片:Incorrect Image

是什么导致了这种情况?如果问题在源图像文件中,我该如何更改 ImageSource.Width 以达到所需尺寸并使用这些文件呢?

3个回答

21
如果您不想在外部更改DPI,您可以按照以下方式进行操作:
public static BitmapSource ConvertBitmapTo96DPI(BitmapImage bitmapImage)
{
    double dpi = 96;
    int width = bitmapImage.PixelWidth;
    int height = bitmapImage.PixelHeight;

    int stride = width * bitmapImage.Format.BitsPerPixel;
    byte[] pixelData = new byte[stride * height];
    bitmapImage.CopyPixels(pixelData, stride, 0);

    return BitmapSource.Create(width, height, dpi, dpi, bitmapImage.Format, null, pixelData, stride);
}

如果你只需要在Image.Source.Width/Height中获得正确的值,你可以像我这样做:

this.myImage.Tag = new double[] { bitmapImage.DpiX, bitmapImage.DpiY };
this.myImage.Source = bitmapImage;

并可以像这样调整大小:

public static void ResizeImage(Image img, double maxWidth, double maxHeight)
{
    if (img == null || img.Source == null)
        return;

    double srcWidth = img.Source.Width;
    double srcHeight = img.Source.Height;

    // Set your image tag to the sources DPI value for smart resizing if DPI != 96
    if (img.Tag != null && img.Tag.GetType() == typeof(double[]))
    {
        double[] DPI = (double[])img.Tag;
        srcWidth = srcWidth / (96 / DPI[0]);
        srcHeight = srcHeight / (96 / DPI[1]);
    }

    double resizedWidth = srcWidth;
    double resizedHeight = srcHeight;

    double aspect = srcWidth / srcHeight;

    if (resizedWidth > maxWidth)
    {
        resizedWidth = maxWidth;
        resizedHeight = resizedWidth / aspect;
    }
    if (resizedHeight > maxHeight)
    {
        aspect = resizedWidth / resizedHeight;
        resizedHeight = maxHeight;
        resizedWidth = resizedHeight * aspect;
    }

    img.Width = resizedWidth;
    img.Height = resizedHeight;
}

4
借用了你的DPI方法,谢谢。为了回报,我修复了一个bug(原本无法使用,例如对于黑白tif文件)。 - user1228

12

您需要将图像分辨率设置为96 DPI(当前不正确的PNG文件为71.12)。

您可以使用免费的Paint.net程序(http://getpaint.net)来完成此操作。从“图像”菜单中选择“画布大小”,然后将“分辨率”字段设置为96即可。


7
这是由于图像的DPI问题导致的。WPF默认使用96 dpi进行渲染。如果您查看不正确的png图像的dpi,您会发现它被设置为72。这会导致WPF将图像缩放到96 DPI并保持原始大小。
有两个解决方案。 您可以:
  1. Modify the DPI using e.g XnView. Set it to 96.
  2. Set the Width and Height properties to 16, and the Stretch property to Uniform

    <Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Image x:Name="MyIncorrectImageFixed" Source="http://i.piccy.info/i5/24/41/504124/16x16_incorrect.png" Width="16" Height="16" Stretch="Uniform"  />
    <Image x:Name="MyIncorrectImage" Source="http://i.piccy.info/i5/24/41/504124/16x16_incorrect.png"  Stretch="None" Grid.Row="1"  />
    <Image x:Name="MyCorrectImage" Source="http://i.piccy.info/i5/22/41/504122/16x16_correct.png" Stretch="None" Grid.Row="2"  />
    


第二种解决方案根本不会改变 DPI,它只会将原始图像拉伸以(均匀地)填充容器,这可能会导致图像模糊。 - Lukáš Koten
实际上,对于问题中的示例,我认为这并没有什么区别。 - hkon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接