Как создать растровое изображение во время выполнения в проекте ASP.NET Core Web Application [дубликат]

Когда вы выполняете метод async, он начинает работать синхронно до тех пор, пока он не достигнет оператора await, а остальная часть кода будет выполняться асинхронно, а выполнение вернется к вызывающему.

В вашем код callCount() запускается синхронно с await task, затем возвращается к Main() методу, и поскольку вы не дожидаетесь завершения метода, программа заканчивается без метода count().

Вы можете увидеть желаемое поведение, изменив тип возвращаемого значения на Task и вызывая Wait() в методе Main().

static void Main(string[] args)
{
    callCount().Wait();
}

static void count()
{
    for (int i = 0; i < 5; i++)
    {
        System.Threading.Thread.Sleep(2000);
        Console.WriteLine("count loop: " + i);
    }
}

static async Task callCount()
{
    Task task = new Task(count);
    task.Start();
    for (int i = 0; i < 3; i++)
    {
        System.Threading.Thread.Sleep(1000);
        Console.WriteLine("Writing from callCount loop: " + i);
    }
    Console.WriteLine("just before await");
    await task;
    Console.WriteLine("callCount completed");
}

EDIT: Так выполняется ваш код:

(для лучшего понимания изменения типа CallCount() возвращаются к Task)

  1. программа запускается с использованием метода Main().
  2. CallCount() .
  3. создается задача, все это в том же потоке.
  4. Затем задача запускается. На этом этапе создается новый поток, запускающий параллельный метод Count().
  5. Выполнение продолжается в CallCount (), для цикла выполняется и «just before await» печатается.
  6. Затем достигается await task;. Это когда роль асинхронного ожидания играет свою роль. await не похож на Wait(), он не блокирует текущий поток до тех пор, пока задача не завершится, но вернет управление исполнением в метод Main() и все остальные инструкции в CallCount() (в данном случае только Console.WriteLine("callCount completed"); ) будет исполнена после завершения задачи.
  7. В Main() вызов CallCount() возвращает Task (с оставшимися инструкциями CallCount() и исходной задачей), и выполнение продолжается .
  8. Если вы не дождались завершения этой задачи, выполнение в Main() продолжит завершение работы программы и уничтожаемых задач.
  9. Если вы вызываете Wait() (если CallCount() недействительно, чтобы вы не ожидали выполнения задачи), вы позволяете завершить задачу, удерживая ее в Main() для выполнения Count() и печатаемой «callCount».

Если вы хотите дождаться окончания задания счетчика в CallCount(), не возвращаясь к методу Main(), вызовите task.Wait();, вся программа будет ждать Count(), но это не то, что await будет делать.

Эта ссылка подробно описывает шаблон асинхронного ожидания.

H opes, эта диаграмма рабочего процесса вашего кода помогает вам.

30
задан rick schott 30 November 2011 в 06:11
поделиться

7 ответов

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

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

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

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

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

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

9
ответ дан Jaked222 20 August 2018 в 10:40
поделиться
  • 1
    Это выглядит очень мило, на самом деле ... Я попробую и дам вам знать, как я нахожусь :) Спасибо. – Dylan Beattie 16 August 2012 в 18:41
  • 2
    @DylanBeattie Я использовал консольную контр-часть imagemagick в приложении с низким трафиком без каких-либо проблем, поэтому вы также можете проверить это тоже – Jaguar 22 August 2012 в 09:55
  • 3
    Хорошо, некоторые ранние хаки, похоже, указывают на то, что довольно просто подключиться к API MagickWand с .NET - так щедрость идет на это, хотя некоторые другие ответы также выглядят многообещающими. – Dylan Beattie 22 August 2012 в 16:45

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

0
ответ дан alfred barthand 20 August 2018 в 10:40
поделиться

Да, используйте классы 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;
        }
    }
}
11
ответ дан Duncan Smart 20 August 2018 в 10:40
поделиться
  • 1
    Они не полностью управляются, они являются оболочками для WIC, что также не поддерживается (несмотря на то, что говорится в документации). У них большая часть тех же проблем плюс новые. – Lilith River 24 October 2011 в 14:00
  • 2
    WPF / WIC также не поддерживается в ASP.NET. – Dylan Beattie 18 August 2012 в 17:34

У меня было хорошее поведение из библиотеки Каира (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.

0
ответ дан FMM 20 August 2018 в 10:40
поделиться

ImageSharp

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

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

4
ответ дан Mathieu Renda 20 August 2018 в 10:40
поделиться

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

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

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

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

8
ответ дан Simon Mourier 20 August 2018 в 10:40
поделиться

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

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

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

}
1
ответ дан Stefan Steiger 20 August 2018 в 10:40
поделиться
  • 1
    @rick: это означает, что методы System.Drawing, которые вы вызываете, поддерживаются в приложении ASP.NET? – John Saunders 7 October 2009 в 01:41
  • 2
    Вызовы API, используемые в этой функции, широко используются в нескольких веб-приложениях, и до сих пор у меня не было проблем. Я не могу сказать наверняка, что это поддерживается. – rick schott 7 October 2009 в 01:56
  • 3
    @rick: Я бы подумал, что предупреждение об обнаружении OP применимо и к этим методам. И с .NET 4.0 в ближайшее время, «он всегда работает», становится менее привлекательным. – John Saunders 7 October 2009 в 05:41
Другие вопросы по тегам:

Похожие вопросы: