Redimensionar uma imagem sem perder qualidade [fechado]

108

Como posso redimensionar uma imagem, sem afetar a qualidade da imagem?

estática pública
fonte
Você pode nos dar mais detalhes? Qual é o tamanho das suas imagens e que tamanho você precisa que elas tenham?
Mark Ransom
6
imageresizing.net - Esta biblioteca produz as imagens da mais alta qualidade que você pode obter com .NET
Lilith River

Respostas:

217

Como diz o rcar , você não pode sem perder alguma qualidade, o melhor que você pode fazer em 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));
}
Kris Erickson
fonte
2
Devo acrescentar que (se possível) o usuário deve começar com uma imagem Bitmap que seja, digamos, duas vezes maior do que o necessário e, em seguida, diminuir. A imagem resultante deve ser bem lisa.
Pretzel de
2
gr.SmoothingMode = SmoothingMode.HighQuality é um código melhor. Atualmente, HighQuality e AntiAlias ​​são a mesma coisa, mas talvez no futuro a Microsoft invente algo novo. HighQuality deve sempre ser um apelido para o melhor.
Eyal
4
O método 'System.Drawing.Image.Save (string filename, ImageFormat format)' salva JPGs com qualidade 75. A imagem estava borrada e não era aceitável pelo cliente. O que corrigiu o problema de qualidade foi usar Salvar (string nome do arquivo, codificador ImageCodecInfo, EncoderParameters encoderParams) e especificar um valor de qualidade próximo a 100.
Riga,
3
Isso deixa artefatos na borda da imagem às vezes ...
jjxtra
1
Eu tinha artefatos na fronteira ao usar isso. Alguma sugestão?
Gopichandar,
32

A menos que você esteja fazendo gráficos vetoriais, não há como redimensionar uma imagem sem potencialmente perder parte da qualidade da imagem.

Randy
fonte
1
a menos que você esteja expandindo ...
Blair Conrad,
Você pode expandi-lo sem perder nenhuma informação, mas existem diferentes tipos de filtros que você pode usar que fornecem resultados diferentes - espera de ordem zero, passa-baixa, 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;
}

a partir daqui

Ozba
fonte
Isso funciona, mas retorna qualidade idêntica à resposta de Kris Erickso. Bom ver o tamanho usado ...
Sam Jones
3

A menos que você redimensione, você não pode fazer isso com gráficos raster.

O que você pode fazer com uma boa filtragem e suavização é redimensionar sem perder nenhuma qualidade perceptível .

Você também pode alterar os metadados de DPI da imagem (supondo que haja alguns), que manterão exatamente a mesma contagem de pixels, mas alterarão a forma como os editores de imagem pensam sobre isso nas medições do 'mundo real'.

E apenas para cobrir todas as bases, se você realmente quis dizer apenas o tamanho do arquivo da imagem e não as dimensões reais da imagem, sugiro que você olhe para uma codificação sem perdas dos dados da imagem. Minha sugestão para isso seria salvar novamente a imagem como um arquivo .png (eu tendo a usar o paint como um transcodificador gratuito para imagens em janelas. Carregue a imagem no paint, salve como no novo formato)

workmad3
fonte
3

Você não pode redimensionar uma imagem sem perder alguma qualidade, simplesmente porque você está reduzindo o número de pixels.

Não reduza o tamanho do lado do cliente, porque os navegadores não fazem um bom trabalho de redimensionamento de imagens.

O que você pode fazer é alterar programaticamente o tamanho antes de renderizá-lo ou conforme um usuário o carrega.

Aqui está um artigo que explica uma maneira de fazer isso em c #: http://www.codeproject.com/KB/GDI-plus/imageresize.aspx

AaronS
fonte
"navegadores não fazem um bom trabalho de redimensionamento de imagens" - isso pode ter sido verdade em 2008, mas felizmente estamos quilômetros à frente nesta área agora (em grande parte devido às versões antigas do IE lentamente desaparecendo).
Camilo Martin de
2

Veja se você gosta da qualidade de redimensionamento de imagem deste módulo ASP.NET de código aberto. Há uma demonstração ao vivo, para que você mesmo possa mexer nela. Ele produz resultados que são (para mim) impossíveis de distinguir da saída do Photoshop. Ele também tem tamanhos de arquivo semelhantes - a MS fez um bom trabalho em seu codificador JPEG.


fonte
Bem, JPEG é um formato relativamente simples. Não há muito que você possa fazer para superar as implementações de referência em termos de qualidade / tamanho do arquivo porque, no final, são apenas coeficientes DCT com compactação genérica.
Camilo Martin de
1

Tem algo lá fora, redimensionamento sensível ao contexto, não sei se você vai conseguir usar, mas vale a pena dar uma olhada, com certeza

Um bom vídeo de demonstração (a ampliação aparece no meio) http://www.youtube.com/watch?v=vIFCV2spKtg

Aqui pode haver algum código. http://www.semanticmetadata.net/2007/08/30/content-aware-image-resizing-gpl-implementation/

Isso foi um exagero? Talvez existam alguns filtros fáceis que você pode aplicar a uma imagem ampliada para desfocar um pouco os pixels, você pode dar uma olhada nisso.

Vencedor
fonte
Suspeito que não tenha nada a ver com a pergunta original, mas adoro essa técnica.
Matt Cruikshank,
1

Você está redimensionando para maior ou menor? Por uma pequena% ou por um fator maior, como 2x, 3x? O que você quer dizer com qualidade para sua aplicação? E que tipo de imagens - fotografias, desenhos de linhas bem definidas ou o quê? Escrever seu próprio código de moagem de pixel de baixo nível ou tentar fazer isso o máximo possível com as bibliotecas existentes (.net ou qualquer outra)?

Existe um grande conhecimento sobre este assunto. O conceito chave é a interpolação.

Recomendações de navegação:
* 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 * isto é específico para java, mas pode ser educacional - http: //today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

DarenW
fonte
1

Aqui você também pode adicionar códigos de marca d'água nesta 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>();
        }

    }
cagin
fonte
0

Aqui está um tópico de fórum que fornece um exemplo de código de redimensionamento de imagem C #. Você pode usar um dos fichários da biblioteca GD para fazer a reamostragem em C #.

jimg
fonte