2014-09-16 1 views
4

Для моего текущего приложения WPF мне нужно уменьшить масштаб System.Drawing.Image (объекты, которые я загружаю из файлов PNG (некоторые из них с прозрачным фоном). Я пробовал несколько подходы к изменению размеров изображений, и все они отлично работали с точки зрения меньшего изображения после этого, но, к сожалению, все они делают изображения свободными от их прозрачности.Потеря прозрачности в System.Drawing.Image при использовании ImageResizer для изменения размера

Моя последняя попытка состояла в том, чтобы использовать 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; 

Это мои другие два подхода, которые также в основном обеспечивают тот же результат (изображение изменяется: еще; Прозрачность сохраняется: неа):

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 

Любые идеи о том, что я должен делать, чтобы сохранить прозрачность при изменении размера?

С уважением

Ralf

ответ

1

Даже если вы используете 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; 
    } 

Затем, не забудьте сохранить его с кодером 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, а не стороннюю библиотеку; надеюсь, что это нормально.)

Update

Кстати, поскольку вы работаете в WPF, почему бы не использовать WPF-х image manipulation?

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

Возможно, вы теряете прозрачные пленки, преобразующие изображения в старом формате в формат WPF?

+0

Хотя вопрос был направлен на использование 'System.Drawing.Image', я думаю, что это по-прежнему правильный ответ: просто используя класс« BitmapImage », который, кажется, более подходит для WPF, решил мою проблему с помощью потерял прозрачность. Кроме того, я заметил, что BitmapImage имеет два полезных свойства, называемых DecodePixelWidth и DecodePixelHeight, которые делают изменение размера еще более простым для моего случая. – Ralf

2

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-битное изображение и вместо этого игнорирует альфа-канал.

+0

Я думаю, вы правы. Я удалил свой ответ, вероятно, не решит проблему Ральфа. Плюс я вижу, что вы являетесь автором ImageResizer, поэтому вы, вероятно, знаете, о чем говорите :) – Bedford

+0

Я должен признать, что вы были правы, что прозрачность, скорее всего, была потеряна где-то до или после использования ImageResizer. Поэтому я попытался использовать 'MemoryStream' для параметров' source' и 'dest', чтобы избежать использования' System.Drawing.Bitmap' перед окончательным отображением изображения. К сожалению, это не сработало для меня, так как «Результат» остался пустым («Null'). Почему-то я, должно быть, неправильно использовал ImageResizer. Однако я решил дать предложение dbc попробовать и использовать класс «BitmapImage». Это решило проблему для меня, и ImageResizer больше не нужен. – Ralf

 Смежные вопросы

  • Нет связанных вопросов^_^