2009-05-28 4 views
11

Sto utilizzando le classi System.Drawing per generare miniature e immagini con filigrana da foto caricate dall'utente. Gli utenti sono anche in grado di ritagliare le immagini utilizzando jCrop dopo aver caricato l'originale. Ho preso in mano questo codice da qualcun altro e sto cercando di semplificarlo e ottimizzarlo (viene utilizzato su un sito Web ad alto traffico).Gestione efficiente delle immagini in C#

Il precedente aveva metodi statici che hanno ricevuto un bitmap come parametro e ne ha restituito uno, allocando e smaltendo internamente un oggetto Graphics. La mia comprensione è che un'istanza Bitmap contiene l'intera immagine in memoria, mentre Graphics è fondamentalmente una coda di operazioni di disegno e che è idempotente.

Il processo attualmente funziona come segue:

  • ricevere l'immagine e conservarla in un file temporaneo.
  • Ricevi le coordinate di ritaglio.
  • Carica la bitmap originale in memoria.
  • Creare una nuova bitmap dall'originale, applicando il ritaglio.
  • Regolazione della luminosità assurda sulla nuova bitmap, forse (?) Restituire una nuova bitmap (preferirei non toccarla, l'aritmetica del puntatore abbonda!), Chiamarla A.
  • Creare un'altra bitmap da la risultante uno, applicando la filigrana (consente di chiamare questo B1)
  • Creare un bitmap 175x175 da anteprima A.
  • Creare un bitmap 45x45 da anteprima A.

questo mi sembra un sacco di allocazioni di memoria; la mia domanda è questa: è una buona idea riscrivere parti del codice e riutilizzare le istanze Graphics, creando in effetti una pipeline? In effetti, ho solo bisogno di 1 immagine in memoria (il caricamento originale), mentre il resto può essere scritto direttamente su disco. Tutte le immagini generate avranno bisogno delle trasformazioni di ritaglio e luminosità e una singola trasformazione che è unica per quella versione, creando effettivamente un albero di operazioni.

Qualche idea o idea?

Oh, e dovrei probabilmente dire che questa è la prima volta che sto lavorando con .NET, quindi se qualcosa che dico sembra confuso, per favore, sopportami e datemi qualche suggerimento.

+0

È un po 'sfortunato che questa sia la tua prima interazione con .NET. Il modello IDisposable è la mia unica vera frustrazione duratura con la struttura. Questo business 'uso' è la caratteristica più usata regolarmente esoterica - la maggior parte delle cose è molto semplice. – overslacked

+0

Buona domanda, dico! +1 – Cerebrus

+1

Ho dovuto cercare "idempotente" ... buona parola. – JasonRShaver

risposta

3

oggetti Riutilizzo grafiche non porteranno probabilmente ad un significativo aumento di prestazioni.

Il codice GDI sottostante crea semplicemente un contesto di dispositivo per la bitmap caricata nella RAM (una memoria CC).

Il collo di bottiglia delle operazioni sembra essere nel caricare l'immagine dal disco.

Perché ricaricare l'immagine dal disco? Se è già presente in una matrice di byte nella RAM, quale dovrebbe essere quando viene caricato, è sufficiente creare un flusso di memoria sull'array di byte e quindi creare una bitmap da quel flusso di memoria.

In altre parole, salvarlo sul disco, ma non ricaricarlo, basta operare su di esso dalla RAM.

Inoltre, non dovrebbe essere necessario creare una nuova bitmap per applicare il watermark (a seconda di come aveva fatto.)

Si dovrebbe profilare l'operazione per vedere dove deve migliorare (o anche se è deve essere migliorato)

3

Il processo sembra ragionevole. Ogni immagine deve esistere in memoria prima di essere salvata sul disco, quindi ogni versione delle miniature sarà prima in memoria. La chiave per assicurarti che funzioni in modo efficiente è quello di disporre gli oggetti Graphics e Bitmap. Il modo più semplice per farlo è con l'istruzione using.

using(Bitmap b = new Bitmap(175, 175)) 
using(Graphics g = Graphics.FromBitmap(b)) 
{ 
    ... 
} 
+0

La mia vera domanda è più simile: mi darà un aumento delle prestazioni se riutilizzerò l'oggetto 'Graphics'? –

0

io sono solo andando a buttare questo là fuori casualmente, ma se si voleva un veloce 'guida' per le migliori pratiche per lavorare con immagini, guarda il progetto Paint.NET. Per strumenti gratuiti ad alta proformance per la manipolazione delle immagini, guarda a AForge.NET.

Il vantaggio di AForge è quello di consentire di fare un sacco di questi passaggi senza creare una nuova bitmap ogni volta. Se questo è per un sito web, posso quasi garantire che il codice con cui stai lavorando sarà il collo di bottiglia delle prestazioni per l'applicazione.

2

Ho completato un progetto simile qualche tempo fa e ho fatto alcuni test pratici per vedere se ci fosse una differenza nelle prestazioni se avessi riutilizzato l'oggetto Graphics invece di crearne uno nuovo per ogni immagine. Nel mio caso, stavo lavorando su un flusso costante di un gran numero di immagini (> 10.000 in un "lotto"). Ho scoperto che ho ottenuto un leggero aumento delle prestazioni riutilizzando l'oggetto Graphics.

Inoltre, ho riscontrato un leggero aumento utilizzando i GraphicsContainer nell'oggetto Graphics per scambiare facilmente diversi stati in/out dell'oggetto, come è stato utilizzato per eseguire varie azioni. (In particolare, ho dovuto applicare un ritaglio e disegnare del testo e una casella (rettangolo) su ogni immagine.) Non so se questo ha senso per ciò che devi fare. Si potrebbe voler esaminare i metodi BeginContainer e EndContainer nell'oggetto Graphics.

Nel mio caso, la differenza era leggera. Non so se otterresti più o meno miglioramenti nella tua implementazione. Ma dal momento che dovrai sostenere un costo per riscrivere il tuo codice, potresti prendere in considerazione la possibilità di terminare il progetto corrente e di eseguire alcuni test di perf-test prima di riscrivere. Solo un pensiero.

Alcuni link che potreste trovare utili:

Using Nested Graphics Containers
GraphicsContainer Class