Cambiar el tamaño de una imagen sin perder calidad [cerrado]

108

¿Cómo puedo cambiar el tamaño de una imagen sin que la calidad de la imagen se vea afectada?

público estático
fuente
¿Puede darnos más detalles? ¿Qué tan grandes son sus imágenes y qué tamaño necesita que sean?
Mark Ransom
6
imageresizing.net - Esta biblioteca produce imágenes de la más alta calidad que puede obtener con .NET
Lilith River

Respuestas:

217

Como dice rcar , no puede sin perder algo de calidad, lo mejor que puede hacer en c # es:

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));
}
Kris Erickson
fuente
2
Debo agregar que (si es posible) el usuario debe comenzar con una imagen de mapa de bits que sea, digamos, el doble de grande de lo necesario y luego reducirla. La imagen resultante debería ser bastante suave.
Pretzel
2
gr.SmoothingMode = SmoothingMode.HighQuality es mejor código. Actualmente, HighQuality y AntiAlias ​​son lo mismo, pero quizás en el futuro Microsoft invente algo nuevo. HighQuality siempre debe ser un alias para los mejores.
Eyal
4
El método 'System.Drawing.Image.Save (nombre de archivo de cadena, formato ImageFormat)' guarda JPG con calidad 75. La imagen estaba borrosa y el cliente no la aceptaba. Lo que solucionó el problema de calidad fue usar Guardar (nombre de archivo de cadena, codificador ImageCodecInfo, EncoderParameters encoderParams) en su lugar y especificar un valor de calidad más cercano a 100.
Riga
3
Esto deja artefactos en el borde de la imagen a veces ...
jjxtra
1
Tenía artefactos en la frontera al usar esto. ¿Alguna sugerencia?
Gopichandar
32

A menos que esté haciendo gráficos vectoriales, no hay forma de cambiar el tamaño de una imagen sin perder potencialmente algo de calidad de imagen.

Cachondo
fuente
1
a menos que lo esté expandiendo ...
Blair Conrad
Puede expandirlo sin perder ninguna información, pero hay diferentes tipos de filtros que puede usar que dan diferentes resultados: retención de orden cero, paso bajo, etc.
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;
}

desde aqui

ozba
fuente
Esto funciona, pero devuelve una calidad idéntica a la respuesta de Kris Erickso. Sin embargo, es bueno ver el tamaño usado ...
Sam Jones
3

A menos que cambie el tamaño, no puede hacer esto con gráficos rasterizados.

Lo que puede hacer con un buen filtrado y suavizado es cambiar el tamaño sin perder una calidad notable .

También puede alterar los metadatos DPI de la imagen (suponiendo que tenga algunos), lo que mantendrá exactamente el mismo recuento de píxeles, pero alterará la forma en que los editores de imágenes lo consideran en las mediciones del 'mundo real'.

Y solo para cubrir todas las bases, si realmente se refería solo al tamaño del archivo de la imagen y no a las dimensiones reales de la imagen, le sugiero que mire una codificación sin pérdidas de los datos de la imagen. Mi sugerencia para esto sería volver a guardar la imagen como un archivo .png (tiendo a usar paint como un transcodificador gratuito para imágenes en Windows. Cargar imagen en paint, guardar como en el nuevo formato)

workmad3
fuente
3

No puede cambiar el tamaño de una imagen sin perder algo de calidad, simplemente porque está reduciendo el número de píxeles.

No reduzca el tamaño del lado del cliente, porque los navegadores no hacen un buen trabajo al cambiar el tamaño de las imágenes.

Lo que puede hacer es cambiar programáticamente el tamaño antes de renderizarlo o cuando un usuario lo carga.

Aquí hay un artículo que explica una forma de hacer esto en c #: http://www.codeproject.com/KB/GDI-plus/imageresize.aspx

AaronS
fuente
"los navegadores no hacen un buen trabajo al cambiar el tamaño de las imágenes" - esto podría haber sido cierto en el '08, pero afortunadamente ahora estamos muy por delante en esta área (en gran medida debido a que las versiones antiguas de IE están desapareciendo lentamente).
Camilo Martin
2

Vea si le gusta la calidad de cambio de tamaño de la imagen de este módulo ASP.NET de código abierto. Hay una demostración en vivo, por lo que puede jugar con ella usted mismo. Produce resultados que son (para mí) imposibles de distinguir de la salida de Photoshop. También tiene tamaños de archivo similares: MS hizo un buen trabajo en su codificador JPEG.


fuente
Bueno, JPEG es un formato relativamente sencillo. No hay mucho que pueda hacer para superar las implementaciones de referencia en términos de calidad / porque al final son solo coeficientes DCT con compresión genérica.
Camilo Martin
1

Hay algo ahí fuera, cambio de tamaño consciente del contexto, no sé si podrá usarlo, pero vale la pena mirarlo, eso es seguro

Un buen video de demostración (la ampliación aparece hacia el medio) http://www.youtube.com/watch?v=vIFCV2spKtg

Aquí podría haber algún código. http://www.semanticmetadata.net/2007/08/30/content-aware-image-resizing-gpl-implementation/

¿Fue exagerado? Tal vez haya algunos filtros fáciles que pueda aplicar a una imagen ampliada para difuminar un poco los píxeles, podría investigar eso.

Víctor
fuente
Sospecho que no tiene nada que ver con la pregunta original, pero me encanta esta técnica.
Matt Cruikshank
1

¿Está cambiando el tamaño más grande o más pequeño? ¿Por un porcentaje pequeño o por un factor mayor como 2x, 3x? ¿Qué quiere decir con calidad para su aplicación? ¿Y qué tipo de imágenes: fotografías, dibujos de líneas bien definidas o qué? ¿Escribir su propio código de pulido de píxeles de bajo nivel o intentar hacerlo tanto como sea posible con las bibliotecas existentes (.net o lo que sea)?

Existe una gran cantidad de conocimientos sobre este tema. El concepto clave es la interpolación.

Recomendaciones de navegación:
* http://www.all-in-one.ee/~dersch/interpolator/interpolator.html
* http://www.cambridgeincolour.com/tutorials/image-interpolation.htm
* para 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 * esto es específico de Java pero puede ser educativo - http: //today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

DarenW
fuente
1

Aquí puede encontrar también agregar códigos de marca de agua en esta clase:

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

    }
cagin
fuente