Jak mogę zmienić rozmiar obrazu, nie zmieniając jego jakości?
Jak mogę zmienić rozmiar obrazu, nie zmieniając jego jakości?
Odpowiedzi:
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));
}
O ile nie robisz grafiki wektorowej, nie ma możliwości zmiany rozmiaru obrazu bez potencjalnej utraty jakości obrazu.
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;
}
Uważam, że to, czego szukasz, to „Zmień rozmiar / ponowne próbkowanie” swoich obrazów. Oto dobra strona, która zawiera instrukcje i zapewnia klasę użytkową (której również używam):
http://www.codeproject.com/KB/GDI-plus/imgresizoutperfgdiplus.aspx
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)
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
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.
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ć.
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
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>();
}
}
Oto wątek forum zawierający przykładowy kod zmiany rozmiaru obrazu C #. Możesz użyć jednego z binderów biblioteki GD do ponownego próbkowania w C #.