Zmiana rozmiaru obrazu bez utraty jakości [zamknięte]

109

Jak mogę zmienić rozmiar obrazu, nie zmieniając jego jakości?

publiczne statyczne
źródło
Czy możesz podać nam więcej szczegółów? Jak duże są Twoje obrazy i jakiego rozmiaru potrzebujesz?
Mark Ransom
6
imageresizing.net - Ta biblioteka tworzy obrazy najwyższej jakości, jakie można uzyskać dzięki platformie .NET
Lilith River,

Odpowiedzi:

218

Jak mówi rcar , nie możesz bez utraty jakości, najlepsze, co możesz zrobić w C # to:

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
źródło
2
Mogę dodać, że (jeśli to możliwe) użytkownik powinien zacząć od obrazu bitmapowego, który jest, powiedzmy, dwa razy większy niż powinien, a następnie skalować w dół. Wynikowy obraz powinien być dość gładki.
Precel
2
gr.SmoothingMode = SmoothingMode.HighQuality to lepszy kod. Obecnie HighQuality i AntiAlias ​​to to samo, ale być może w przyszłości Microsoft wymyśli coś nowego. Wysoka jakość zawsze powinna być aliasem dla najlepszego.
Eyal,
4
Metoda „System.Drawing.Image.Save (nazwa pliku ciągu znaków, format ImageFormat)” zapisuje pliki JPG z jakością 75. Obraz był zamazany i nie został zaakceptowany przez klienta. Rozwiązaniem problemu z jakością było użycie Save (nazwa pliku ciągu, koder ImageCodecInfo, EncoderParameters encoderParams) i określenie wartości jakości bliższej 100.
Ryga
3
To czasami pozostawia artefakty na granicy obrazu ...
jjxtra
1
Miałem artefakty na granicy używania tego. Jakieś sugestie?
Gopichandar
32

O ile nie robisz grafiki wektorowej, nie ma możliwości zmiany rozmiaru obrazu bez potencjalnej utraty jakości obrazu.

Niespokojny
źródło
1
chyba że go rozbudowujesz ...
Blair Conrad,
Możesz go rozszerzyć bez utraty informacji, ale istnieją różne typy filtrów, których możesz użyć, które dają różne wyniki - wstrzymanie zamówienia zerowego, dolnoprzepustowy itp.
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;
}

od tutaj

ozba
źródło
To działa, ale zwraca tę samą jakość, co odpowiedź Krisa Erickso. Miło widzieć, że rozmiar został użyty ...
Sam Jones
3

Jeśli nie zmienisz rozmiaru w górę, nie możesz tego zrobić z grafiką rastrową.

To, co możesz zrobić z dobrym filtrowaniem i wygładzaniem, to zmiana rozmiaru bez utraty zauważalnej jakości.

Możesz także zmienić metadane DPI obrazu (zakładając, że ma kilka), które zachowają dokładnie taką samą liczbę pikseli, ale zmieni sposób, w jaki redaktorzy obrazu myślą o tym w pomiarach w „rzeczywistym świecie”.

Aby objąć wszystkie podstawy, jeśli naprawdę chodziło Ci o rozmiar pliku obrazu, a nie o rzeczywiste wymiary obrazu, proponuję przyjrzeć się bezstratnemu kodowaniu danych obrazu. Moją sugestią byłoby ponowne zapisanie obrazu jako pliku .png (zwykle używam farby jako darmowego transkodera dla obrazów w systemie Windows. Załaduj obraz w farbie, zapisz jak w nowym formacie)

workmad3
źródło
3

Nie możesz zmienić rozmiaru obrazu bez utraty jakości, po prostu dlatego, że zmniejszasz liczbę pikseli.

Nie zmniejszaj rozmiaru po stronie klienta, ponieważ przeglądarki nie radzą sobie dobrze ze zmianą rozmiaru obrazów.

Możesz programowo zmienić rozmiar przed renderowaniem lub w momencie przesłania go przez użytkownika.

Oto artykuł, który wyjaśnia jeden sposób zrobienia tego w języku c #: http://www.codeproject.com/KB/GDI-plus/imageresize.aspx

AaronS
źródło
„przeglądarki nie radzą sobie dobrze ze zmianą rozmiaru obrazów” - to mogło być prawdą w 2008 roku, ale na szczęście jesteśmy teraz daleko do przodu w tej dziedzinie (w dużej mierze ze względu na powolne zanikanie starych wersji IE).
Camilo Martin,
2

Sprawdź, czy podoba Ci się jakość zmiany rozmiaru obrazu tego modułu ASP.NET typu open source. Jest demo na żywo, więc możesz sobie z tym poradzić. Daje wyniki, których (dla mnie) nie da się odróżnić od wyjścia Photoshopa. Ma również podobne rozmiary plików - MS wykonał dobrą robotę ze swoim koderem JPEG.


źródło
Cóż, JPEG jest stosunkowo prostym formatem. Niewiele można zrobić, aby pokonać implementacje referencyjne pod względem jakości / rozmiaru pliku, ponieważ na końcu są to tylko współczynniki DCT z ogólną kompresją.
Camilo Martin,
1

Coś tam jest, zmiana rozmiaru uwzględniająca kontekst, nie wiem, czy będziesz w stanie z tego skorzystać, ale na pewno warto się temu przyjrzeć

Ładne demo wideo (powiększenie pojawia się w środku) http://www.youtube.com/watch?v=vIFCV2spKtg

Tutaj może być kod. http://www.semanticmetadata.net/2007/08/30/content-aware-image-resizing-gpl-implementation/

Czy to była przesada? Może są jakieś proste filtry, które możesz zastosować do powiększonego obrazu, aby nieco rozmyć piksele, możesz się temu przyjrzeć.

Zwycięzca
źródło
Podejrzewam, że nie ma to nic wspólnego z pierwotnym pytaniem, ale uwielbiam tę technikę.
Matt Cruikshank,
1

Czy zmieniasz rozmiar na większy czy mniejszy? Mały procent czy większy czynnik, jak 2x, 3x? Co masz na myśli mówiąc o jakości swojej aplikacji? A jakiego typu obrazy - fotografie, ostre rysunki kreskowe czy co? Piszesz własny niskopoziomowy kod do szlifowania pikseli lub próbujesz zrobić to tak często, jak to możliwe, z istniejącymi bibliotekami (.net lub cokolwiek)?

Istnieje obszerna wiedza na ten temat. Kluczową koncepcją jest interpolacja.

Zalecenia dotyczące przeglądania:
* http://www.all-in-one.ee/~dersch/interpolator/interpolator.html
* http://www.cambridgeincolour.com/tutorials/image-interpolation.htm
* dla 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 * dotyczy języka Java, ale może mieć charakter edukacyjny - http: //today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

DarenW
źródło
1

Tutaj możesz również znaleźć kody znaków wodnych w tej klasie:

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
źródło