2010-10-07 8 views
9

Ho una schermata che prendo nella mia app mobile. Lo screenshot richiede circa 32 KB se salvato come png su un disco.Come ridurre la dimensione di un'immagine in C# e .NET 3.5?

Invio questi a un server SQL centrale e 32 KB è troppo grande per il numero di volte necessario per archiviare tale schermata (circa 2500 volte al giorno).

C'è qualche tipo di inganno che posso fare per farlo risparmiare?

Ecco il codice che sto usando ora di prendere da Bitmap a byte (da inviare al server per l'archiviazione):

MemoryStream stream = new MemoryStream(); 
_signatureImage.Save(stream, ImageFormat.Png); 
return stream.ToArray(); 

_signatureImage è un Bitmap ed è lo screenshot in questione.

Ecco un esempio di schermata Mi risparmio:

Screen Shot Image

Cose che compaiono in mente (ma non so come fare loro):

  1. Ridurre l'altezza e la larghezza effettive dell'immagine (ma si spera in un modo che non la distorca).
  2. Cambiare su un'immagine in bianco e nero (non sono sicuro se vedrò risparmi di spazio reali da questo)
  3. Comprimerlo di più (non mi piace tanto perché non è leggibile dal database) .

Nota, tutto ciò deve essere fatto in modo programmatico e non può richiedere molto tempo, così le complesse manipolazioni di immagini sono fuori.

Grazie per qualsiasi aiuto.

+0

Non riesco a vedere l'immagine che hai postato (http filtrata al lavoro). Quali sono le dimensioni? – Kendrick

+0

@Kendrick È 480 x 640. – jdmichal

risposta

10
private static Image ResizeImage(int newSize, Image originalImage) 
    { 
     if (originalImage.Width <= newSize) 
      newSize = originalImage.Width; 

     var newHeight = originalImage.Height * newSize/originalImage.Width; 

     if (newHeight > newSize) 
     { 
      // Resize with height instead 
      newSize = originalImage.Width * newSize/originalImage.Height; 
      newHeight = newSize; 
     } 

     return originalImage.GetThumbnailImage(newSize, newHeight, null, IntPtr.Zero); 
    } 

Questo dovrebbe funzionare con il tuo tipo di oggetto bitmap e ridimensionare l'altezza o larghezza, a seconda di quale è appropriato per le dimensioni delle immagini. Inoltre manterrà la scala.

EDIT:

Si potrebbe creare un nuovo oggetto bitmap e ridimensionare l'immagine originale in tale oggetto bitmap.

Bitmap b = new Bitmap(newWidth, newHeight); 
Graphics g = Graphics.FromImage((Image)b); 
g.InterpolationMode = InterpolationMode.HighQualityBicubic; 

g.DrawImage(imgToResize, 0, 0, newWidth, newHeight); 
g.Dispose(); 

return (Image)b; 

Non ho installato Compact Framework, ma sembra che questo dovrebbe funzionare per voi.

+0

Sembra buono. Ma non posso facilmente usarlo. Avrei dovuto indicarlo, ma questa app si trova su Compact Framework e GetThumbnailImage non è nel framework compatto. Se ci si avvicina, posso ridimensionare l'immagine sul lato server, ma preferirei inviare un'immagine più piccola in aria, se possibile. – Vaccano

+0

Dovresti evitare comunque GetThumbnailImage - è adatto solo per immagini 40x40 o più piccole. –

3

Se la profondità del colore non è un problema, è possibile modificarlo in bianco e nero o in modalità 16 colori. Ci dovrebbe essere un notevole risparmio rispetto ai requisiti di archiviazione di 24-bpp (o 32-bpp con alpha) di png. L'altra cosa a cui pensare è salvarla come un file .gif in 256 modalità colore.

Mentre si salvano i dati delle firme, penso che cambiare le dimensioni dell'immagine sarebbe una cattiva idea. Potresti anche prendere in considerazione l'idea di applicare una compressione senza perdita come zip, ma è probabile che sia più intensivo dal punto di vista computazionale del necessario.

+0

Qualche suggerimento su come farlo in C#? – Vaccano

+0

Non personalmente, ma una ricerca rapida ha generato questo collegamento: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=554acd82-d87d-43c6-a984-8c625387b198&displaylang=it Citazione selezionata: "Nel .NET Compact Framework, non esiste un metodo semplice per salvare oggetti Bitmap o ottenere un handle bitmap da un oggetto Bitmap, quindi è necessario utilizzare un po 'di trucchetti per accedere ai dati dei pixel di una bitmap. " – arootbeer

+0

Il prodotto della mia azienda, DotImage Photo, può farlo ed è un SDK gratuito. Basta chiamare GetChangedPixelFormat() su AtalaImage - passare in un formato indicizzato, quindi salvare con AtalaImage.Save(). https://www.atalasoft.com/photofree –

0

Provare a convertire in una bitmap monocromatica pura. Questi sono estremamente piccoli, dal momento che usano solo un bit per pixel.

EDIT: Sono un bugiardo. Ho appena provato questo in Paint ed è circa 40k rispetto al 20k originale. Avrei giurato quelli che avevano enormi risparmi di spazio quando li usai prima ...

MODIFICA MODIFICA: OK, a quanto pare hanno enormi risparmi. È solo che per queste immagini, PNG ha un risparmio ancora maggiore. Ho appena provato una bitmap a 16 colori e l'ho mandata a 150k.

MODIFICA MODIFICA MODIFICA: MA, le bitmap monocromatiche si chiudono a 9k byte, mentre il PNG rimane a 20k anche con zip.


Così, sembra che se si vuole andare l'itinerario di compressione, è possibile prima convertire in bitmap monocromatica, quindi comprimere le immagini per circa la metà delle dimensioni del PNG.

Si potrebbe anche togliere alcune informazioni dall'immagine. Ad esempio, su quello schermo, l'unica cosa che ha davvero bisogno di rimanere un'immagine è la firma. Le barre sopra e sotto potrebbero essere strappate e le informazioni numeriche potrebbero essere inviate come tali e memorizzate separatamente.

+0

Non sono sicuro di come Windows memorizzi i suoi file bitmap, ma so che sono completamente non compressi. .png ha almeno una certa compressione. – arootbeer

0

di accensione dei fuochi d'artificio con una foto, che non sarà lo stesso, ma dovrebbe dare un'idea

66% quality JPG with no smoothing is 17.5k 
PNG8 with 256 colours is 58K (down to 42 using websnap palette) 
PNG8 with black and white palette is 14k 

Nota che molti file di immagine sarà più piccola con un colpo di schermo dal momento che ci sono grandi gruppi contigui di stesso colore, e questo può essere particolarmente vero con il bianco e nero. Probabilmente dipenderà anche dall'algoritmo usato per convertire l'immagine, ma potresti voler andare con qualsiasi cosa tu possa trovare ...

2

Cambia la tavolozza dei colori ad una profondità di colore inferiore. Dai uno sguardo allo this question (guarda bene il risponditore) che mostra la conversione in 1bpp. Potresti andare su 8bpp anziché su 1bpp e ottenere risparmi significativi. Il meccanismo per la conversione sarà lo stesso di quello mostrato.

EDIT

Pensare fuori dalla scatola, si potrebbe anche prendere in considerazione solo l'invio di punti dati dalla parte superiore dello schermo e il vettore di firma, e che il server ricreare lo schermo per voi. Se la dimensione è davvero un grosso problema, probabilmente lo indagherei.

EDIT 2

Se semplicemente ridimensionare l'immagine è una soluzione ragionevole (si, ovviamente, perdere i dati in questo modo), allora è possibile utilizzare lo spazio dei nomi Imaging nella SDF per creare una miniatura come Alex explains here.

1

Se l'immagine monocromatica è accettabile, è possibile provare TIFF G4 (compressione senza perdita di dati). TIFF G4 è noto per essere molto efficace nelle dimensioni del file per memorizzare immagini in bianco e nero. Purtroppo non ho informazioni disponibili su come si confronta con PNG, ma vale la pena indagare su di esso.

Here è informazioni e esempio su come farlo in C#

0

FWIW memorizzare l'immagine fisicamente all'interno del server SQL non è una soluzione ottimale. Se si sta utilizzando SQL Server 2008, è necessario esaminare il supporto del flusso di file che consente di archiviare le immagini fisiche su disco e accedervi come se fossero interne a SQL Server.Questo probabilmente allevierebbe il tuo bisogno di preoccuparti della dimensione dei file.