简体   繁体   English

使用ImageResizer进行大小调整时,在System.Drawing.Image中失去透明度

[英]Loosing transparency in System.Drawing.Image when using ImageResizer for resizing

For my current WPF appliaction I have to down scale some System.Drawing.Image ( objects which I load from PNG files (some of them with transparent background). I've tried multiple approaches for the resizing of the images and all of them worked fine in terms of having a smaller image afterwards. But unfortunately they all make the images loose their transparency. 对于我当前的WPF应用程序,我必须缩小一些System.Drawing.Image (我从PNG文件加载的对象(其中一些具有透明背景)。我尝试了多种方法来调整图像的大小,所有这些都有效之后有一个较小的图像。但不幸的是,它们都使图像失去透明度。

My last try was to use ImageResizer an external library to get the job done as I expected it to handle that problem easily, but I still have the same issue: Original image is displayed with transparent background; 我的最后一次尝试是使用ImageResizer一个外部库来完成工作,因为我希望它能轻松处理这个问题,但我仍然有同样的问题:原始图像以透明背景显示; Resized image displayed is displayed with black background. 显示的已调整大小的图像以黑色背景显示。

Here's my code for the usage of the ImageResizer library: 这是我使用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;

These are my other two approaches, which also basically deliver the same result (Image resized: yet; Transparency preserved: Nope): 这些是我的另外两种方法,它们基本上也提供了相同的结果(图像已调整大小:尚未保留透明度:Nope):

return originalImage.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero); // Transparency gets lost

return new System.Drawing.Bitmap(originalImage, new System.Drawing.Size(newWidth, newHeight));  // Transparency gets lost

Any ideas on what I have to do in order preserve the transparency while resizing? 有关我必须做什么的任何想法,以便在调整大小时保持透明度?

Regards 问候

Ralf 拉尔夫

ImageResizer always preserves transparency. ImageResizer 始终保持透明度。

You're losing transparency during the encoding (or display) of the image, which happens after you've taken control away from ImageResizer. 在图像的编码(或显示)过程中,您将失去透明度,这是您从ImageResizer中取消控制之后发生的。 Instead of passing in typeof(System.Drawing.Bitmap) , pass in an output path or output stream. 传入输出路径或输出流,而不是传入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 can't control how an image is encoded if you take a raw Bitmap from it instead. 如果从中获取原始位图,ImageResizer无法控制图像的编码方式。


You didn't specific how you're using the results, which is very important. 您没有具体说明如何使用结果,这非常重要。 If you are not writing them to disk or a stream, but are instead displaying them, then you're looking for the problem in the wrong place. 如果您没有将它们写入磁盘或流,而是显示它们,那么您在错误的位置寻找问题。 It's likely that the code responsible for compositing the results onto the display surface is failing to treat the image as a 32-bit image, and is instead ignoring the alpha channel. 负责将结果合成到显示表面的代码很可能无法将图像视为32位图像,而是忽略了alpha通道。

Even though you're using WPF, you're working with System.Drawing.Image objects, so you can do this: 即使你正在使用WPF,你也在使用System.Drawing.Image对象,所以你可以这样做:

    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;
    }

Afterwards, be sure to save it with the PNG encoder: 之后,请务必使用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;
    }

and then 然后

    codec = GetEncoder(ImageFormat.Png);
    newBitmap.Save(newFile, codec, null);

(Note I'm using the standard .Net class libraries rather than a 3rd party library; hope that's OK.) (注意我使用的是标准的.Net类库而不是第三方库;希望没问题。)

Update 更新

Incidentally, since you are working in WPF, why not use WPF's image manipulation ? 顺便说一句,既然你在WPF工作,为什么不使用WPF的图像处理呢?

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;
    }
}

Maybe you're losing transparencies converting images in the older format to WPF format? 也许您正在丢失将旧格式的图像转换为WPF格式的透明度?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM