Альтернативы System.Drawing для использования с ASP.NET? - PullRequest
32 голосов
/ 07 октября 2009

После нескольких дней отслеживания причудливых ошибок GDI + я наткнулся на этот маленький камень на MSDN :

Классы в пространстве имен System.Drawing не поддерживаются для использования в службе Windows или ASP.NET. Попытка использовать эти классы из одного из этих типов приложений может привести к непредвиденным проблемам, таким как снижение производительности службы и исключения во время выполнения.

Я не знаю, означает ли «служба ASP.NET» «веб-приложение» в этом контексте, но «снижение производительности службы», безусловно, охватывает случайный ассортимент «Общая ошибка произошла в GDI +» и «Вне ошибки памяти, которые выбрасывает мое приложение - периодические, невоспроизводимые ошибки чтения и записи изображений JPEG, которые - во многих случаях - фактически были созданы System.Drawing.Imaging в первую очередь.

Итак - если GDI + не может надежно читать и записывать файлы JPEG в веб-приложении, что я должен использовать вместо этого?

Я хочу, чтобы пользователи могли загружать изображения (требуется JPEG, другие форматы, которые есть в наличии), повторно выбирать их , надежно и отображать полезные сообщения об ошибках, если что-то пойдет не так. Есть идеи? Стоит ли рассматривать пространства имен System.Media из WPF?

РЕДАКТИРОВАТЬ: Да, я знаю, GDI + работает "большую часть времени". Это не достаточно хорошо, потому что, когда он терпит неудачу, он делает это так, что его невозможно изолировать или восстановить изящно. Меня не интересуют примеры кода GDI +, который работает для вас: я ищу альтернативные библиотеки, которые можно использовать для обработки изображений.

Ответы [ 7 ]

10 голосов
/ 16 августа 2012

В блоге есть отличное сообщение, включающее код C # об использовании графической библиотеки ImageMagick через Interop на TopTen Software Blog . Эта статья посвящена запуску ASP.net в Linux под mono; тем не менее, код C # должен быть идеально пригоден для копирования и вставки, единственное, что вам нужно изменить, это атрибуты Interop, если вы работаете в Windows, ссылающейся на двоичный файл окна (DLL).

ImageMagick® - это программный пакет для создания, редактирования, создания или преобразования растровые изображения. Он может читать и писать изображения в различных форматах (более 100), включая DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD, PNG, Postscript, SVG и TIFF. Используйте ImageMagick, чтобы изменить размер, перевернуть, зеркальное отражение, поворот, искажение, сдвиг и преобразование изображений, настройка изображения цвета, применять различные специальные эффекты или рисовать текст, линии, многоугольники, эллипсы и кривые Безье.

Существует также проект разработки ImageMagick .Net на codeplex, который объединяет все для вас. Но он не показывает активной разработки с 2009 года, поэтому может отставать от текущей версии библиотеки ImageMagick. Для небольшой тривиальной процедуры изменения размера я, вероятно, придерживаюсь взаимодействия. Вам просто нужно внимательно следить за вашей реализацией на предмет утечек памяти или невыпущенных ресурсов (сама библиотека хорошо протестирована и проверена сообществом).

Библиотека бесплатная и с открытым исходным кодом. Лицензия Apache 2 совместима как с личными, так и с коммерческими целями. См. Страница лицензии ImageMagick .

Библиотека является полностью кроссплатформенной и реализует множество мощных процедур обработки и преобразования изображений, которых нет в GDI + (или не реализованных в режиме mono), и имеет хорошую репутацию в качестве альтернативы для обработки изображений ASP.net.

Обновление: похоже, здесь есть обновленная версия оболочки .NET: http://magick.codeplex.com/

9 голосов
/ 16 августа 2012

Вы можете найти очень хорошую статью от сотрудника Microsoft здесь: Изменение размера изображений с сервера с использованием WPF / WIC вместо GDI + , в котором предлагается использовать WPF вместо GDI +. Это больше про миниатюры, но в целом это те же проблемы.

Во всяком случае, в конце говорится следующее:

Я связался с командой WPF, чтобы узнать, является ли это поддерживается. К сожалению, это не так, и документация в настоящее время обновляется соответственно. Я извиняюсь за путаницу, которая может иметь вызвало. Мы ищем способы сделать эту историю более приемлемой в будущее.

Итак, WPF также не поддерживается в веб-приложениях, и я все еще верю: -S

9 голосов
/ 12 октября 2011

Да, используйте классы WPF System.Windows.Media. Будучи полностью управляемыми, они не страдают от тех же проблем, что и GDI.

Вот выдержка из некоторого кода MVC, который я использую для визуализации градиентов, чтобы дать вам представление о том, как перейти от WPF Visual к PNG:

using System;
using System.IO;
using System.Web.Mvc;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace MyMvcWebApp.Controllers
{
    public class ImageGenController : Controller
    {
        // GET: ~/ImageGen/Gradient?color1=red&color2=pink
        [OutputCache(CacheProfile = "Image")]
        public ActionResult Gradient(Color color1, Color color2, int width = 1, int height = 30, double angle = 90)
        {
            var visual = new DrawingVisual();
            using (DrawingContext dc = visual.RenderOpen())
            {
                Brush brush = new LinearGradientBrush(color1, color2, angle);
                dc.DrawRectangle(brush, null, new Rect(0, 0, width, height));
            }

            return new FileStreamResult(renderPng(visual, width, height), "image/png");
        }

        static Stream renderPng(Visual visual, int width, int height)
        {
            var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
            rtb.Render(visual);

            var frame = BitmapFrame.Create(rtb);
            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(frame);

            var stream = new MemoryStream();
            encoder.Save(stream);
            stream.Position = 0;

            return stream;
        }
    }
}
4 голосов
/ 03 июля 2017

ImageSharp

ImageSharp - это кроссплатформенная библиотека 2D-графики с открытым исходным кодом. Он написан на C # поверх нового стандарта .NET, без какой-либо зависимости от API-интерфейса для конкретной ОС.

В настоящее время он еще находится в предварительной версии на MyGet (вам необходимо добавить исходный код пакета в параметрах VS или в файле NuGet.config), но мы уже используем его с некоторыми очень положительными результатами.

1 голос
/ 07 октября 2009

Большинство вопросов, о которых я читал, касаются неправильной утилизации ресурсов.

Я использовал варианты этого кода снова и снова без проблем с веб-приложениями:

public void GenerateThumbNail(HttpPostedFile fil, string sPhysicalPath, 
                              string sOrgFileName,string sThumbNailFileName,
                              System.Drawing.Imaging.ImageFormat oFormat, int rez)
{

    try
    {

        System.Drawing.Image oImg = System.Drawing.Image.FromStream(fil.InputStream);

        decimal pixtosubstract = 0;
        decimal percentage;

        //default
        Size ThumbNailSizeToUse = new Size();
        if (ThumbNailSize.Width < oImg.Size.Width || ThumbNailSize.Height < oImg.Size.Height)
        {
            if (oImg.Size.Width > oImg.Size.Height)
            {
                percentage = (((decimal)oImg.Size.Width - (decimal)ThumbNailSize.Width) / (decimal)oImg.Size.Width);
                pixtosubstract = percentage * oImg.Size.Height;
                ThumbNailSizeToUse.Width = ThumbNailSize.Width;
                ThumbNailSizeToUse.Height = oImg.Size.Height - (int)pixtosubstract;
            }
            else
            {
                percentage = (((decimal)oImg.Size.Height - (decimal)ThumbNailSize.Height) / (decimal)oImg.Size.Height);
                pixtosubstract = percentage * (decimal)oImg.Size.Width;
                ThumbNailSizeToUse.Height = ThumbNailSize.Height;
                ThumbNailSizeToUse.Width = oImg.Size.Width - (int)pixtosubstract;
            }

        }
        else
        {
            ThumbNailSizeToUse.Width = oImg.Size.Width;
            ThumbNailSizeToUse.Height = oImg.Size.Height;
        }

        Bitmap bmp = new Bitmap(ThumbNailSizeToUse.Width, ThumbNailSizeToUse.Height);
        bmp.SetResolution(rez, rez);
        System.Drawing.Image oThumbNail = bmp;

        bmp = null;

        Graphics oGraphic = Graphics.FromImage(oThumbNail);

        oGraphic.CompositingQuality = CompositingQuality.HighQuality;

        oGraphic.SmoothingMode = SmoothingMode.HighQuality;

        oGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;

        Rectangle oRectangle = new Rectangle(0, 0, ThumbNailSizeToUse.Width, ThumbNailSizeToUse.Height);

        oGraphic.DrawImage(oImg, oRectangle);

        oThumbNail.Save(sPhysicalPath  + sThumbNailFileName, oFormat);

        oImg.Dispose();

    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
    }

}
0 голосов
/ 22 августа 2012

У меня хорошее поведение из библиотеки Cairo (http://www.cairographics.org) в среде веб-сервера ASP.Net. Я фактически перешел в cairo из WPF из-за плохой модели использования памяти WPF для веб-приложений.

WPF на самом деле стремится запустить ваш рабочий процесс из памяти. Ни один из объектов WPF не реализует IDisposable, и многие из них ссылаются на неуправляемую память, которая освобождается только через финализатор. Интенсивное использование WPF (особенно если ваш сервер сильно нагружен ЦП) в конечном итоге приведет к нехватке памяти, поскольку ваша очередь финализатора переполнена. Например, когда я профилировал свое приложение, в очереди завершения было более 50 000 объектов, многие из которых содержали ссылки на неуправляемую память. Каир вел себя намного лучше для меня, и его схема использования памяти была гораздо более предсказуемой, чем у WPF.

Если вы заинтересованы в использовании cairo, скачайте библиотеки с сайта GTK +. Они имеют набор двоичных файлов x86 и x64.

Единственным недостатком является то, что Каир не может читать / писать JPG изначально; тем не менее, вы можете легко адаптировать материал WPF для чтения / записи JPG и выполнять пересчет / масштабирование / рисование / что угодно еще, используя Cairo.

0 голосов
/ 23 декабря 2009

Вы можете взглянуть на http://gd -sharp.sourceforge.net / , который является оберткой для библиотеки GD. Я не проверял это, но это кажется многообещающим.

...