Подтвердить что ты не робот

Альтернативы System.Drawing для использования с ASP.NET?

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

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

Таким образом, WPF также не поддерживается в веб-приложениях, и я считаю, что: -S

Ответ 4

ImageSharp

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

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

Ответ 5

Большинство проблем, которые я прочитал, относятся к ресурсам, которые не располагаются должным образом.

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

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

}

Ответ 6

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

Ответ 7

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

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

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

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