Domanda

Dopo diversi giorni di rintracciare bizzarro GDI + errori, ho imbattuti in questo piccolo gioiello su MSDN :

  

Corsi all'interno del namespace System.Drawing non sono supportati per l'utilizzo all'interno di un servizio di Windows o ASP.NET. Il tentativo di utilizzare queste classi all'interno di uno di questi tipi di applicazioni può produrre problemi imprevisti, come ad esempio le prestazioni del servizio diminuita e run-time eccezioni.

Non so se "servizio ASP.NET" significa "web application" in questo contesto, ma "le prestazioni del servizio diminuita" certamente sembra coprire l'assortimento casuale di "un errore generico si è verificato in GDI +" e "Out of errori di memoria" che la mia applicazione sta gettando - intermittenti, errori non riproducibili lettura e la scrittura immagini JPEG che - in molti casi -. sono stati effettivamente creati dal System.Drawing.Imaging in primo luogo

Quindi - se GDI + non sa leggere e scrivere file JPEG in modo affidabile in una web app, che cosa dovrei usare invece

Voglio che gli utenti siano in grado di caricare le immagini (JPEG richiesta, altri formati nice-to-have), li in modo affidabile ricampionare, e visualizzare i messaggi di errore utili se qualcosa va storto. Qualche idea? Sono gli spazi dei nomi System.Media da WPF da prendere in considerazione?

Modifica Sì, lo so GDI + funziona "la maggior parte del tempo". Questo non è abbastanza buono, perché quando non riesce, lo fa in un modo che è impossibile isolare o recuperare dalla grazia. Io non sono interessato a esempi di GDI + codice che funziona per voi: Sto cercando librerie alternative da utilizzare per l'elaborazione delle immagini

.
È stato utile?

Soluzione

C'è un ottimo post sul blog tra cui C # codice sull'utilizzo del ImageMagick Graphics Library attraverso Interop sopra a TopTen Software Blog . Questo offerte pubblicare specificamente in esecuzione su Linux ASP.net in mono; Tuttavia, il codice C # dovrebbe essere copia-incolla-in grado perfettamente, l'unica cosa che devi cambiare è attributi di interoperabilità se si esegue sotto Windows fa riferimento a un binario finestra (DLL).

  

ImageMagick® è una suite di software per creare, modificare, comporre, o convertire   immagini bitmap. E 'in grado di leggere e scrivere le immagini in una varietà di formati   (Oltre 100) tra cui DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD,   PNG, Postscript, SVG, e TIFF. Utilizzare ImageMagick per ridimensionare, capovolgere,   specchio, ruotare, distorcere, taglio e trasformare immagini, regolare immagine   i colori, applicare vari effetti speciali, o disegnare testo, linee, poligoni,   ellissi e curve di Bézier.

C'è anche un href="http://imagemagick.codeplex.com/" rel="nofollow noreferrer"> progetto di sviluppo su CodePlex che avvolge tutto per voi. Ma non mostra sviluppo attivo dal 2009, quindi potrebbe essere in ritardo rispetto l'attuale versione della libreria ImageMagick. Per una piccola routine di ridimensionamento banale, probabilmente sarei bastone con l'interoperabilità. Hai solo bisogno di guardare con attenzione l'implementazione per il proprio perdita di memoria o le risorse inedite (la biblioteca è ben collaudato e verificata dalla comunità).

La biblioteca è libero e open source. La licenza Apache 2 sembra essere compatibile sia con scopi personali e commerciali. Vedere ImageMagick Licenza Pagina .

La biblioteca è la piattaforma totalmente trasversale e implementa molte potenti routine di gestione e trasformazione dell'immagine che non si trovano in GDI + (o non implementato sotto mono) e ha una buona reputazione come alternativa per ASP.net l'elaborazione delle immagini.

Aggiornamento: Sembra che ci sia una versione aggiornata di un wrapper .NET qui: http: //magick.codeplex. com /

Altri suggerimenti

Sì, utilizzare le classi System.Windows.Media WPF. Essendo completamente gestite non soffrono gli stessi problemi come la roba GDI.

Ecco un estratto da un codice MVC che uso per il rendering gradienti, per darvi un'idea di come ottenere da un Visual WPF a un 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;
        }
    }
}

Si può trovare un ottimo articolo da un dipendente Microsoft qui: Ridimensionamento immagini dal server utilizzando WPF / WIC invece di GDI + che si propone di utilizzare WPF invece di GDI +. E 'più di miniature, ma è nel complesso gli stessi problemi.

In ogni caso, alla fine si afferma questo:

  

Ho contattato il team di WPF di avere l'ultima parola su se questo è   supportato. Purtroppo, non è, e la documentazione è in corso   aggiornato di conseguenza. Mi scuso di qualsiasi confusione questo può avere   causato. Stiamo cercando il modo per rendere la storia più accettabile in   il futuro.

Così WPF è anche supportato in applicazioni web ed è tuttora credo: -S

ImageSharp

ImageSharp è un cross-platform libreria grafica 2D open-source. E 'scritto in C # in cima alla nuova .NET standard, senza alcuna dipendenza da qualsiasi API specifiche del sistema operativo.

E 'attualmente ancora in pre-release su MyGet (dovrete aggiungere l'origine del pacchetto nelle opzioni VS o un file NuGet.config), ma stiamo già utilizzando con alcuni risultati molto positivi.

La maggior parte dei problemi che ho letto su riguardare le risorse non in via di dismissione correttamente.

Ho usato varianti di questo ora di un codice e più volte senza problemi da applicazioni web:

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

}

Si può avere uno sguardo a http://gd-sharp.sourceforge.net/ che è un wrapper per la libreria GD. Non ho ancora testato, ma sembra promettente.

Ho avuto un buon comportamento dalla biblioteca del Cairo (http://www.cairographics.org) in un ambiente server web ASP.Net. Io in realtà sono trasferito al Cairo da WPF a causa della scarsa modello di utilizzo della memoria di WPF per le cose di web-based.

WPF tende in realtà per eseguire il processo di lavoro di memoria. Nessuno dei WPF oggetti implementare IDisposable, e molti di loro riferimento memoria non gestita che è liberato solo attraverso un finalizzatore. L'uso continuo della WPF (specialmente se il server è significativamente CPU-tassato) alla fine si esaurisce la memoria perché la coda di finalizzatore viene saturato. Quando mi è stato profiling mia app, per esempio, la coda di finalizzazione ha avuto verso l'alto di 50.000 oggetti su di esso, molti dei quali in possesso riferimenti a memoria non gestita. Il Cairo si è comportato molto meglio per me, e il suo modello di utilizzo della memoria è stata molto più prevedibile rispetto WPF di.

Se siete interessati ad utilizzare cairo, afferrare le librerie dal sito web 's GTK +. Hanno un sistema x86, nonché un insieme di file binari x64.

L'unico inconveniente è che Cairo non può leggere / JPG scrittura nativo; tuttavia, si potrebbe facilmente adattare la roba di WPF per leggere / scrivere JPG e fare il ricampionamento / scala / disegno / quant'altro utilizzando Cairo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top