C# 使用ImageResizer调整大小时,System.Drawing.Image中的透明度降低

C# 使用ImageResizer调整大小时,System.Drawing.Image中的透明度降低,c#,image,bitmap,transparency,imageresizer,C#,Image,Bitmap,Transparency,Imageresizer,对于我当前的WPF应用程序,我必须缩小一些System.Drawing.Image(我从PNG文件加载的对象(其中一些具有透明背景).我尝试了多种方法来调整图像的大小,所有这些方法都很好地解决了之后图像变小的问题。但不幸的是,它们都使图像失去了透明度 我最后一次尝试是使用ImageResizer(一个外部库)来完成工作,因为我希望它能够轻松处理该问题,但我仍然有相同的问题:原始图像显示为透明背景;显示的已调整大小的图像显示为黑色背景 以下是我使用ImageResizer库的代码: ImageRe

对于我当前的WPF应用程序,我必须缩小一些
System.Drawing.Image
(我从PNG文件加载的对象(其中一些具有透明背景).我尝试了多种方法来调整图像的大小,所有这些方法都很好地解决了之后图像变小的问题。但不幸的是,它们都使图像失去了透明度

我最后一次尝试是使用ImageResizer(一个外部库)来完成工作,因为我希望它能够轻松处理该问题,但我仍然有相同的问题:原始图像显示为透明背景;显示的已调整大小的图像显示为黑色背景

以下是我使用ImageResizer库的代码:

ImageResizer.Instructions inst = new ImageResizer.Instructions("width=" + newWidth.ToString() + ";height=" + newHeight.ToString() + ";format=png;mode=max");
ImageResizer.ImageJob job = new ImageResizer.ImageJob(originalImage, typeof(System.Drawing.Bitmap), inst);
job.Build();
return job.Result as System.Drawing.Image;
这是我的另外两种方法,它们基本上也提供了相同的结果(图像大小:但是;透明度保持:没有):

在调整尺寸时,我需要做些什么来保持透明度,有什么想法吗

问候


Ralf

即使您使用的是WPF,您也在使用对象,因此您可以执行以下操作:

    public static Bitmap ResizeImage(Image imgToResize, int newHeight)
    {
        int sourceWidth = imgToResize.Width;
        int sourceHeight = imgToResize.Height;

        float nPercentH = ((float)newHeight / (float)sourceHeight);

        int destWidth = Math.Max((int)Math.Round(sourceWidth * nPercentH), 1); // Just in case;
        int destHeight = newHeight;

        Bitmap b = new Bitmap(destWidth, destHeight);
        using (Graphics g = Graphics.FromImage((Image)b))
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.PixelOffsetMode = PixelOffsetMode.HighQuality;
            g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
        }

        return b;
    }
之后,请确保使用PNG编码器保存:

    public static System.Drawing.Imaging.ImageCodecInfo GetEncoder(System.Drawing.Imaging.ImageFormat format)
    {
        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
        foreach (ImageCodecInfo codec in codecs)
        {
            if (codec.FormatID == format.Guid)
            {
                return codec;
            }
        }
        return null;
    }
然后

    codec = GetEncoder(ImageFormat.Png);
    newBitmap.Save(newFile, codec, null);
(注意,我使用的是标准的.Net类库,而不是第三方库;希望没问题。)

更新

顺便说一句,既然您在WPF中工作,为什么不使用WPF呢

公共静态类BitmapHelper
{
公共静态void SaveToPng(此位图源位图,字符串文件名)
{
var encoder=新的PngBitmapEncoder();
SaveUsingEncoder(位图、文件名、编码器);
}
公共静态void SaveUsingEncoder(此位图源位图、字符串文件名、位图编码器)
{
BitmapFrame=BitmapFrame.Create(位图);
编码器。帧。添加(帧);
使用(var stream=File.Create(文件名))
{
编码器。保存(流);
}
}
公共静态void ImageLoadResizeAndSave(字符串填充、字符串输出文件、整型新像素高度)
{
BitmapImage=新的BitmapImage();
image.BeginInit();
image.UriSource=新Uri(infle);
image.EndInit();
var newImage=BitmapHelper.ResizeImageToHeight(图像,newPixelHeight);
BitmapHelper.SaveToPng(新图像,输出文件);
}
/// 
///调整图像大小,使其具有选定的高度,并保持宽度成比例。
/// 
/// 
/// 
/// 
公共静态BitmapSource ResizeImageToHeight(BitmapSource imgToResize,int newPixelHeight)
{
double sourceWidth=imgToResize.PixelWidth;
double sourceHeight=imgToResize.PixelHeight;
var nPercentH=((双)新像素高度/源高度);
double destWidth=Math.Max((int)Math.Round(sourceWidth*nPercentH),1);//以防万一;
double destHeight=新像素高度;
var bitmap=新的转换位图(imgToResize,新的ScaleTransform(destWidth/imgToResize.PixelWidth,destHeight/imgToResize.PixelHeight));
返回位图;
}
}

将旧格式的图像转换为WPF格式可能会丢失透明度?

ImageResizer始终保持透明度

在图像编码(或显示)过程中,您正在丢失透明度,这是在您从ImageResizer获取控制权后发生的。请传入输出路径或输出流,而不是
typeof(System.Drawing.Bitmap)

var i = new Instructions(){ Width = newWidth,Height = newHeight, OutputFormat= OutputFormat.Png, Mode= FitMode.Max};
new ImageJob(originalImage, "output.png", i).Build();
如果取而代之的是原始位图,则ImageResizer无法控制图像的编码方式



您没有具体说明如何使用结果,这一点非常重要。如果您没有将结果写入磁盘或流,而是显示结果,那么您在错误的位置查找问题。负责将结果合成到显示表面的代码可能无法将图像视为32位图像,而忽略alpha通道。

我想你是对的。我删除了我的答案,这可能解决不了拉尔夫的问题。另外,我看到你是ImageResizer的作者,所以你可能知道你在说什么:)我必须承认你是对的,透明度很可能在使用ImageResizer之前或之后的某个地方丢失了。因此,我尝试使用
MemoryStream
作为
source
dest
参数,以避免在最终显示图像之前使用
System.Drawing.Bitmap
。不幸的是,这对我不起作用,因为
结果
随后保持为空(
Null
)。不知怎的,我一定是把图像大小调整器用错了。然而,我决定尝试一下dbc的建议,并使用了
BitmapImage
类。这解决了我的问题,不再需要ImageResizer。虽然问题的目标是使用
System.Drawing.Image
,但我认为这仍然是正确的答案:简单地使用
BitmapImage
类,它似乎更适合WPF,在失去透明度的情况下解决了我的问题。此外,我注意到BitmapImage有两个有用的属性,分别是
DecodePixelWidth
DecodePixelHeight
,这使得我的情况下调整大小更加容易。
public static class BitmapHelper
{
    public static void SaveToPng(this BitmapSource bitmap, string fileName)
    {
        var encoder = new PngBitmapEncoder();
        SaveUsingEncoder(bitmap, fileName, encoder);
    }

    public static void SaveUsingEncoder(this BitmapSource bitmap, string fileName, BitmapEncoder encoder)
    {
        BitmapFrame frame = BitmapFrame.Create(bitmap);
        encoder.Frames.Add(frame);

        using (var stream = File.Create(fileName))
        {
            encoder.Save(stream);
        }
    }

    public static void ImageLoadResizeAndSave(string inFile, string outFile, int newPixelHeight)
    {
        BitmapImage image = new BitmapImage();
        image.BeginInit();
        image.UriSource = new Uri(inFile);
        image.EndInit();

        var newImage = BitmapHelper.ResizeImageToHeight(image, newPixelHeight);

        BitmapHelper.SaveToPng(newImage, outFile);
    }

    /// <summary>
    /// Resize the image to have the selected height, keeping the width proportionate.
    /// </summary>
    /// <param name="imgToResize"></param>
    /// <param name="newHeight"></param>
    /// <returns></returns>
    public static BitmapSource ResizeImageToHeight(BitmapSource imgToResize, int newPixelHeight)
    {
        double sourceWidth = imgToResize.PixelWidth;
        double sourceHeight = imgToResize.PixelHeight;

        var nPercentH = ((double)newPixelHeight / sourceHeight);

        double destWidth = Math.Max((int)Math.Round(sourceWidth * nPercentH), 1); // Just in case;
        double destHeight = newPixelHeight;

        var bitmap = new TransformedBitmap(imgToResize, new ScaleTransform(destWidth / imgToResize.PixelWidth, destHeight / imgToResize.PixelHeight));

        return bitmap;
    }
}
var i = new Instructions(){ Width = newWidth,Height = newHeight, OutputFormat= OutputFormat.Png, Mode= FitMode.Max};
new ImageJob(originalImage, "output.png", i).Build();