Ridimensionare un'immagine senza perdere la qualità [chiuso]


108

Come posso ridimensionare un'immagine senza che la qualità dell'immagine venga modificata?


Puoi darci maggiori dettagli? Quanto sono grandi le tue immagini e di che dimensione hai bisogno che siano?
Mark Ransom


6
imageresizing.net - Questa libreria produce immagini di altissima qualità che puoi ottenere con .NET
Lilith River

Risposte:


217

Come dice rcar , non puoi senza perdere un po 'di qualità, il meglio che puoi fare in c # è:

Bitmap newImage = new Bitmap(newWidth, newHeight);
using (Graphics gr = Graphics.FromImage(newImage))
{
    gr.SmoothingMode = SmoothingMode.HighQuality;
    gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
    gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
    gr.DrawImage(srcImage, new Rectangle(0, 0, newWidth, newHeight));
}

2
Potrei aggiungere che (se possibile) l'utente dovrebbe iniziare con un'immagine bitmap che è, diciamo, due volte più grande di quanto deve essere e quindi ridimensionare. L'immagine risultante dovrebbe essere abbastanza liscia.
Pretzel

2
gr.SmoothingMode = SmoothingMode.HighQuality è un codice migliore. Attualmente, HighQuality e AntiAlias ​​sono la stessa cosa, ma forse in futuro Microsoft inventerà qualcosa di nuovo. HighQuality dovrebbe sempre essere un alias per il meglio.
Eyal

4
Il metodo "System.Drawing.Image.Save (string filename, ImageFormat format)" salva i JPG con qualità 75. L'immagine era sfocata e non accettabile dal client. Ciò che ha risolto il problema di qualità era utilizzare invece Salva (string filename, ImageCodecInfo encoder, EncoderParameters encoderParams) e specificare un valore di qualità più vicino a 100.
Riga

3
A volte questo lascia artefatti sul bordo dell'immagine ...
jjxtra

1
Ho avuto artefatti sul confine usando questo. Eventuali suggerimenti?
Gopichandar

32

A meno che tu non stia facendo grafica vettoriale, non c'è modo di ridimensionare un'immagine senza potenzialmente perdere un po 'di qualità dell'immagine.


1
a meno che tu non lo stia espandendo ...
Blair Conrad

Puoi espanderlo senza perdere alcuna informazione, ma ci sono diversi tipi di filtri che puoi usare che danno risultati diversi - blocco ordine zero, passa basso, ecc.
Adam Rosenfield

24
private static Image resizeImage(Image imgToResize, Size size)
{
    int sourceWidth = imgToResize.Width;
    int sourceHeight = imgToResize.Height;

    float nPercent = 0;
    float nPercentW = 0;
    float nPercentH = 0;

    nPercentW = ((float)size.Width / (float)sourceWidth);
    nPercentH = ((float)size.Height / (float)sourceHeight);

    if (nPercentH < nPercentW)
        nPercent = nPercentH;
    else
        nPercent = nPercentW;

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);

    Bitmap b = new Bitmap(destWidth, destHeight);
    Graphics g = Graphics.FromImage((Image)b);
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;

    g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
    g.Dispose();

    return (Image)b;
}

da qui


Funziona, ma restituisce una qualità identica alla risposta di Kris Erickso. Bello vedere le dimensioni usate però ...
Sam Jones


3

A meno che non si ridimensiona, non è possibile farlo con la grafica raster.

Quello che puoi fare con un buon filtraggio e levigatura è ridimensionare senza perdere alcuna qualità evidente .

Puoi anche modificare i metadati DPI dell'immagine (supponendo che ne abbia alcuni) che manterranno esattamente lo stesso numero di pixel, ma cambieranno il modo in cui gli editor di immagini la pensano nelle misurazioni del "mondo reale".

E solo per coprire tutte le basi, se intendi davvero solo la dimensione del file dell'immagine e non le dimensioni effettive dell'immagine, ti suggerisco di guardare una codifica senza perdite dei dati dell'immagine. Il mio suggerimento per questo sarebbe salvare nuovamente l'immagine come file .png (tendo a usare paint come transcodificatore gratuito per le immagini in Windows. Carica l'immagine in Paint, salva come nel nuovo formato)


3

Non puoi ridimensionare un'immagine senza perdere un po 'di qualità, semplicemente perché stai riducendo il numero di pixel.

Non ridurre le dimensioni lato client, perché i browser non fanno un buon lavoro di ridimensionamento delle immagini.

Quello che puoi fare è modificare programmaticamente le dimensioni prima di renderlo o come un utente lo carica.

Ecco un articolo che spiega un modo per farlo in c #: http://www.codeproject.com/KB/GDI-plus/imageresize.aspx


"i browser non fanno un buon lavoro nel ridimensionare le immagini" - questo potrebbe essere stato vero nel '08, ma fortunatamente siamo chilometri più avanti in quest'area ora (in gran parte a causa delle vecchie versioni di IE che stanno lentamente svanendo).
Camilo Martin

2

Vedi se ti piace la qualità di ridimensionamento dell'immagine di questo modulo ASP.NET open source. C'è una demo dal vivo, quindi puoi giocarci da solo. Produce risultati che sono (per me) impossibili da distinguere dall'output di Photoshop. Ha anche dimensioni di file simili: MS ha fatto un buon lavoro con il suo codificatore JPEG.


Bene, JPEG è un formato relativamente semplice. Non c'è molto che puoi fare per battere le implementazioni di riferimento in termini di qualità / dimensione del file perché alla fine sono solo coefficienti DCT con compressione generica.
Camilo Martin

1

C'è qualcosa là fuori, ridimensionamento consapevole del contesto, non so se sarai in grado di usarlo, ma vale la pena guardarlo, questo è certo

Un bel video dimostrativo (l'ingrandimento appare verso il centro) http://www.youtube.com/watch?v=vIFCV2spKtg

Qui potrebbe esserci del codice. http://www.semanticmetadata.net/2007/08/30/content-aware-image-resizing-gpl-implementation/

È stato eccessivo? Forse ci sono alcuni semplici filtri che puoi applicare a un'immagine ingrandita per sfocare un po 'i pixel, potresti esaminarli.


Sospetto che non abbia nulla a che fare con la domanda originale, ma adoro questa tecnica.
Matt Cruikshank

1

Stai ridimensionando più grande o più piccolo? Di una piccola% o di un fattore maggiore come 2x, 3x? Cosa intendi per qualità per la tua applicazione? E che tipo di immagini: fotografie, disegni al tratto netti o cosa? Stai scrivendo il tuo codice di macinazione pixel di basso livello o cercando di farlo il più possibile con le librerie esistenti (.net o altro)?

C'è un ampio corpo di conoscenza su questo argomento. Il concetto chiave è l'interpolazione.

Suggerimenti per la navigazione:
* http://www.all-in-one.ee/~dersch/interpolator/interpolator.html
* http://www.cambridgeincolour.com/tutorials/image-interpolation.htm
* per C #: https: //secure.codeproject.com/KB/GDI-plus/imageprocessing4.aspx?display=PrintAll&fid=3657&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=26&select=629945 * questo è specifico per Java ma potrebbe essere educativo - http: //today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html


1

Qui puoi trovare anche aggiungere codici di filigrana in questa classe:

public class ImageProcessor
    {
        public Bitmap Resize(Bitmap image, int newWidth, int newHeight, string message)
        {
            try
            {
                Bitmap newImage = new Bitmap(newWidth, Calculations(image.Width, image.Height, newWidth));

                using (Graphics gr = Graphics.FromImage(newImage))
                {
                    gr.SmoothingMode = SmoothingMode.AntiAlias;
                    gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    gr.DrawImage(image, new Rectangle(0, 0, newImage.Width, newImage.Height));

                    var myBrush = new SolidBrush(Color.FromArgb(70, 205, 205, 205));

                    double diagonal = Math.Sqrt(newImage.Width * newImage.Width + newImage.Height * newImage.Height);

                    Rectangle containerBox = new Rectangle();

                    containerBox.X = (int)(diagonal / 10);
                    float messageLength = (float)(diagonal / message.Length * 1);
                    containerBox.Y = -(int)(messageLength / 1.6);

                    Font stringFont = new Font("verdana", messageLength);

                    StringFormat sf = new StringFormat();

                    float slope = (float)(Math.Atan2(newImage.Height, newImage.Width) * 180 / Math.PI);

                    gr.RotateTransform(slope);
                    gr.DrawString(message, stringFont, myBrush, containerBox, sf);
                    return newImage;
                }
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

        public int Calculations(decimal w1, decimal h1, int newWidth)
        {
            decimal height = 0;
            decimal ratio = 0;


            if (newWidth < w1)
            {
                ratio = w1 / newWidth;
                height = h1 / ratio;

                return height.To<int>();
            }

            if (w1 < newWidth)
            {
                ratio = newWidth / w1;
                height = h1 * ratio;
                return height.To<int>();
            }

            return height.To<int>();
        }

    }

0

Ecco un thread del forum che fornisce un esempio di codice di ridimensionamento dell'immagine C #. È possibile utilizzare uno dei raccoglitori della libreria GD per eseguire il ricampionamento in C #.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.