Быстрый + качественный алгоритм изменения размера изображения в C # без использования GDI + / WPF - PullRequest
2 голосов
/ 29 августа 2011

Мне нужно изменить размер многих изображений без потери качества.
Использование PresentationFramework (WPF) довольно быстро, но качество оставляет желать лучшего.
Используя GDI +, это хорошее качество, но привязано к UI-Thread -> singleCored. : - (
Есть ли хороший и быстрый алгоритм, сочетающий скорость и качество в одном куске кода? ; -)

Ответы [ 2 ]

1 голос
/ 29 августа 2011

GDI + (он же System.Drawing) не нуждается в обработчике сообщений и будет успешно работать в нескольких потоках;это могут делать только реальные элементы управления - вы даже можете использовать Bitmap в консольном приложении (в котором нет обработчика сообщений).

Таким образом, например, вы можете сделать следующее (я проверял это):

static void Main(string[] args)
{
    foreach (var file in Directory.GetFiles("C:\\MyImages", "*.jpg"))
    {
        // Spawn threads.
        new Action<string, float>(ResizeImage).BeginInvoke(file, 0.1f, null, null);
    }
    Console.ReadLine();
}

public static void ResizeImage(string filename, float scale)
{
    using (var bitmap = Image.FromFile(filename))
    using (var resized = ResizeBitmap(bitmap, 0.1f, InterpolationMode.HighQualityBicubic))
    {
        var newFile = Path.ChangeExtension(filename, ".thumbnail" + Path.GetExtension(filename));
        if (File.Exists(newFile))
            File.Delete(newFile);
        resized.Save(newFile);
    }
}

public static Bitmap ResizeBitmap(Image source, float scale, InterpolationMode quality)
{
    if (source == null)
        throw new ArgumentNullException("source");

    // Figure out the new size.
    var width = (int)(source.Width * scale);
    var height = (int)(source.Height * scale);

    // Create the new bitmap.
    // Note that Bitmap has a resize constructor, but you can't control the quality.
    var bmp = new Bitmap(width, height);

    using (var g = Graphics.FromImage(bmp))
    {
        g.InterpolationMode = quality;
        g.DrawImage(source, new Rectangle(0, 0, width, height));
        g.Save();
    }

    return bmp;
}

Редактировать: Согласно этой записи кажется, что System.Drawing имеет глобальную блокировку;особенно с DrawImage() (хотя имейте в виду, это не из-за сообщения сообщения).К сожалению, единственный способ получить многопоточный доступ, вероятно, заключается в использовании DirectX / SharpDX и создании устройства с включенной многопоточностью;создайте несколько буферов и сделайте там изменение размера - затем вы можете настроить фильтры минимизации / максимизации.Я не уверен, что вы можете Draw() из нескольких потоков в DirectX - но даже если вы не можете, вы сможете получить гораздо большую пропускную способность от него (даже в одном потоке).

0 голосов
/ 29 августа 2011

Нет причин не открывать отдельный насос сообщений для этого в отдельном потоке, что просто означает, что вы можете сделать это в 100 потоках параллельно;).

Я знаю, это более загадочночасть, но есть приложения, которые имеют отдельный поток для каждого окна, реализуя определенные насосы сообщений Windows в каждом запущенном потоке.Тот же подход может быть использован для этого.Возьмите его за уровень программирования .NET UI 201.

...