2009-09-27 7 views
53

Ho creato una piccola app C# per creare un'immagine in formato .jpg.Qualità di un JPG salvato in C#

L'immagine è stata creata correttamente. Inserisco una foto originale, ne faccio qualcosa e la salvo. La qualità di questa nuova immagine tuttavia è inferiore a quella dell'originale.

C'è un modo per impostare la qualità desiderata?

risposta

71

Nell'esempio di codice seguente viene illustrato come creare un parametro Encoder utilizzando il costruttore EncoderParameter. Per eseguire questo esempio, incollare il codice e chiamare il metodo VaryQualityLevel.

Questo esempio richiede un file immagine denominato TestPhoto.jpg situato in c :.

private void VaryQualityLevel() 
{ 
    // Get a bitmap. 
    Bitmap bmp1 = new Bitmap(@"c:\TestPhoto.jpg"); 
    ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg); 

    // Create an Encoder object based on the GUID 
    // for the Quality parameter category. 
    System.Drawing.Imaging.Encoder myEncoder = 
     System.Drawing.Imaging.Encoder.Quality; 

    // Create an EncoderParameters object. 
    // An EncoderParameters object has an array of EncoderParameter 
    // objects. In this case, there is only one 
    // EncoderParameter object in the array. 
    EncoderParameters myEncoderParameters = new EncoderParameters(1); 

    EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 
     50L); 
    myEncoderParameters.Param[0] = myEncoderParameter; 
    bmp1.Save(@"c:\TestPhotoQualityFifty.jpg", jgpEncoder, 
     myEncoderParameters); 

    myEncoderParameter = new EncoderParameter(myEncoder, 100L); 
    myEncoderParameters.Param[0] = myEncoderParameter; 
    bmp1.Save(@"c:\TestPhotoQualityHundred.jpg", jgpEncoder, 
     myEncoderParameters); 

    // Save the bitmap as a JPG file with zero quality level compression. 
    myEncoderParameter = new EncoderParameter(myEncoder, 0L); 
    myEncoderParameters.Param[0] = myEncoderParameter; 
    bmp1.Save(@"c:\TestPhotoQualityZero.jpg", jgpEncoder, 
     myEncoderParameters); 

} 

private ImageCodecInfo GetEncoder(ImageFormat format) 
{ 
    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); 
    foreach (ImageCodecInfo codec in codecs) 
    { 
     if (codec.FormatID == format.Guid) 
     { 
      return codec; 
     } 
    } 
    return null; 
} 

Rif: http://msdn.microsoft.com/en-us/library/system.drawing.imaging.encoderparameter.aspx

+2

che funziona. Sembrerebbe che senza tutto questo si utilizzi una qualità standard di 50 litri. – KdgDev

+0

Hai un errore di battitura. jgpEncoder quando intendevi jpgEncoder;) –

+0

EncoderParameter può utilizzare risorse non gestite e deve essere eliminato. La documentazione di Msdn è un po 'carente su questo argomento. Dovrebbe affermare che l'array 'Param' è inizializzato con elementi null (quindi nulla da eliminare prima del primo assegnamento a ciascun elemento), e che' EncoderParameters' dispone i propri parametri correnti sul proprio oggetto. –

13

Questa è una discussione precedente, ma ho riscritto Microsoft (come per la risposta di Dustin Getz) per essere un po 'più utile: ridurre GetEncoderInfo e creare un'estensione su Image. Comunque nulla di veramente nuovo, ma può essere utile:

/// <summary> 
    /// Retrieves the Encoder Information for a given MimeType 
    /// </summary> 
    /// <param name="mimeType">String: Mimetype</param> 
    /// <returns>ImageCodecInfo: Mime info or null if not found</returns> 
    private static ImageCodecInfo GetEncoderInfo(String mimeType) 
    { 
     var encoders = ImageCodecInfo.GetImageEncoders(); 
     return encoders.FirstOrDefault(t => t.MimeType == mimeType); 
    } 

    /// <summary> 
    /// Save an Image as a JPeg with a given compression 
    /// Note: Filename suffix will not affect mime type which will be Jpeg. 
    /// </summary> 
    /// <param name="image">Image: Image to save</param> 
    /// <param name="fileName">String: File name to save the image as. Note: suffix will not affect mime type which will be Jpeg.</param> 
    /// <param name="compression">Long: Value between 0 and 100.</param> 
    private static void SaveJpegWithCompressionSetting(Image image, string fileName, long compression) 
    { 
     var eps = new EncoderParameters(1); 
     eps.Param[0] = new EncoderParameter(Encoder.Quality, compression); 
     var ici = GetEncoderInfo("image/jpeg"); 
     image.Save(fileName, ici, eps); 
    } 

    /// <summary> 
    /// Save an Image as a JPeg with a given compression 
    /// Note: Filename suffix will not affect mime type which will be Jpeg. 
    /// </summary> 
    /// <param name="image">Image: This image</param> 
    /// <param name="fileName">String: File name to save the image as. Note: suffix will not affect mime type which will be Jpeg.</param> 
    /// <param name="compression">Long: Value between 0 and 100.</param> 
    public static void SaveJpegWithCompression(this Image image, string fileName, long compression) 
    { 
     SaveJpegWithCompressionSetting(image, fileName, compression); 
    } 
2

Se si utilizza il .NET Compact Framework, un'alternativa potrebbe essere quella di utilizzare il cioè formato lossless PNG:

image.Save(filename, ImageFormat.Png); 
30

Ecco un ancora più compatto pezzo di codice per il salvataggio in formato JPEG con una qualità specifica:

var encoder = ImageCodecInfo.GetImageEncoders().First(c => c.FormatID == ImageFormat.Jpeg.Guid); 
var encParams = new EncoderParameters() { Param = new[] { new EncoderParameter(Encoder.Quality, 90L) } }; 
image.Save(path, encoder, encParams); 

Oppure, se le linee larghe 120 caratteri sono troppo lunghi per voi:

var encoder = ImageCodecInfo.GetImageEncoders() 
          .First(c => c.FormatID == ImageFormat.Jpeg.Guid); 
var encParams = new EncoderParameters(1); 
encParams.Param[0] = new EncoderParameter(Encoder.Quality, 90L); 
image.Save(path, encoder, encParams); 

Assicurarsi che la qualità è un long o si otterrà un ArgumentException!

+0

Andando a destra nella mia libreria di codice grazie mille! – JustJohn

+0

Vedi anche [risposta bytecode77] (https://stackoverflow.com/a/39493/199499994) per una versione di questo che usa 'using' per essere sicuro che' Dispose' avvenga prontamente alla fine. – ToolmakerSteve

4

Utilizzo degli attributi di stile GDI + senza scrittura (https://msdn.microsoft.com/en-us/library/windows/desktop/ms533845(v=vs.85).aspx) per l'impostazione dell'aspetto eccessivo della qualità JPEG.

Un modo diretto dovrebbe essere simile a questo:

FileStream stream = new FileStream("new.jpg", FileMode.Create); 
JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
encoder.QualityLevel = 100; // "100" for maximum quality (largest file size). 
encoder.Frames.Add(BitmapFrame.Create(image)); 
encoder.Save(stream); 

Rif: https://msdn.microsoft.com/en-us/library/system.windows.media.imaging.jpegbitmapencoder.rotation(v=vs.110).aspx#Anchor_2

+0

Nota secondaria: Poiché la domanda originale era una lamentela sulla bassa qualità, per risolvere il problema utilizzare la massima qualità: 'encoder.QualityLevel = 100'. – ToolmakerSteve

3

La comunità wiki risposta, che è accettata, referrs ad un esempio da Microsoft.

Tuttavia, al fine di risparmiare un po 'di tempo, ho bollito giù ad un'essenza e

  • imballato in un metodo corretto
  • Implementato IDisposable. Non ho visto using (...) { in nessun'altra risposta.Per evitare perdite di memoria, è consigliabile disporre di tutto ciò che implementa IDisposable.

public static void SaveJpeg(string path, Bitmap image) 
{ 
    SaveJpeg(path, image, 95L); 
} 
public static void SaveJpeg(string path, Bitmap image, long quality) 
{ 
    using (EncoderParameters encoderParameters = new EncoderParameters(1)) 
    using (EncoderParameter encoderParameter = new EncoderParameter(Encoder.Quality, quality)) 
    { 
     ImageCodecInfo codecInfo = ImageCodecInfo.GetImageDecoders().First(codec => codec.FormatID == ImageFormat.Jpeg.Guid); 
     encoderParameters.Param[0] = encoderParameter; 
     image.Save(path, codecInfo, encoderParameters); 
    } 
} 
+0

Nota secondaria: "95L" come mostrato per la qualità è un buon valore di default perché è vicino al massimo di "100L", ma farà risparmiare un po 'sulle dimensioni del file, per immagini molto dettagliate. Generalmente uso "90L" su "100L" per la conservazione della qualità hiqh, "70L" su "85L" per una qualità decente, ma dimensioni di file più ragionevoli. Dipende anche dal fatto che si stia eseguendo una "modifica ripetuta" di un file. Se è così, usa "100L" fino all'ultima modifica (o modifica in .png per essere senza perdita di dati), quindi fai il salvataggio finale con qualsiasi qualità tu abbia bisogno. – ToolmakerSteve