Redimensionando uma imagem no asp.net sem perder a qualidade da imagem

Estou desenvolvendo um aplicativo da Web ASP.NET 3.5 no qual estou permitindo que meus usuários façam upload de imagens jpeg, gif, bmp ou png. Se as dimensões da imagem carregada forem maiores que 103 x 32, eu quero resize a imagem enviada para 103 x 32. Eu li alguns posts e artigos, e também tentei alguns exemplos de código, mas nada parece funcionar corretamente. Alguém conseguiu fazer isso?

Eu tive o mesmo problema há algum tempo e lidei com isso da seguinte maneira:

 private Image RezizeImage(Image img, int maxWidth, int maxHeight) { if(img.Height < maxHeight && img.Width < maxWidth) return img; using (img) { Double xRatio = (double)img.Width / maxWidth; Double yRatio = (double)img.Height / maxHeight; Double ratio = Math.Max(xRatio, yRatio); int nnx = (int)Math.Floor(img.Width / ratio); int nny = (int)Math.Floor(img.Height / ratio); Bitmap cpy = new Bitmap(nnx, nny, PixelFormat.Format32bppArgb); using (Graphics gr = Graphics.FromImage(cpy)) { gr.Clear(Color.Transparent); // This is said to give best quality when resizing images gr.InterpolationMode = InterpolationMode.HighQualityBicubic; gr.DrawImage(img, new Rectangle(0, 0, nnx, nny), new Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel); } return cpy; } } private MemoryStream BytearrayToStream(byte[] arr) { return new MemoryStream(arr, 0, arr.Length); } private void HandleImageUpload(byte[] binaryImage) { Image img = RezizeImage(Image.FromStream(BytearrayToStream(binaryImage)), 103, 32); img.Save("IMAGELOCATION.png", System.Drawing.Imaging.ImageFormat.Gif); } 

Acabei de ler que esta era a maneira de obter a mais alta qualidade.

Este é o código que eu uso. Suporta rotação e também define a resolução da imagem para os padrões JPEG de 72 dpi @ cor de 24 bits (por padrão, o GDI + salva imagens a 96 dpi @ cor de 32 bits). Ele também corrige o problema de borda preto / cinza que algumas pessoas experimentam ao resize imagens.

 ///  /// Resizes and rotates an image, keeping the original aspect ratio. Does not dispose the original /// Image instance. ///  /// Image instance /// desired width /// desired height /// desired RotateFlipType /// new resized/rotated Image instance public static Image Resize(Image image, int width, int height, RotateFlipType rotateFlipType) { // clone the Image instance, since we don't want to resize the original Image instance var rotatedImage = image.Clone() as Image; rotatedImage.RotateFlip(rotateFlipType); var newSize = CalculateResizedDimensions(rotatedImage, width, height); var resizedImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format32bppArgb); resizedImage.SetResolution(72, 72); using (var graphics = Graphics.FromImage(resizedImage)) { // set parameters to create a high-quality thumbnail graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; // use an image attribute in order to remove the black/gray border around image after resize // (most obvious on white images), see this post for more information: // http://www.codeproject.com/KB/GDI-plus/imgresizoutperfgdiplus.aspx using (var attribute = new ImageAttributes()) { attribute.SetWrapMode(WrapMode.TileFlipXY); // draws the resized image to the bitmap graphics.DrawImage(rotatedImage, new Rectangle(new Point(0, 0), newSize), 0, 0, rotatedImage.Width, rotatedImage.Height, GraphicsUnit.Pixel, attribute); } } return resizedImage; } ///  /// Calculates resized dimensions for an image, preserving the aspect ratio. ///  /// Image instance /// desired width /// desired height /// Size instance with the resized dimensions private static Size CalculateResizedDimensions(Image image, int desiredWidth, int desiredHeight) { var widthScale = (double)desiredWidth / image.Width; var heightScale = (double)desiredHeight / image.Height; // scale to whichever ratio is smaller, this works for both scaling up and scaling down var scale = widthScale < heightScale ? widthScale : heightScale; return new Size { Width = (int) (scale * image.Width), Height = (int) (scale * image.Height) }; } 

O código associado ao redimensionamento real do bitmap é o seguinte.

 public static Bitmap ResizeBitmap( Bitmap originalBitmap, int requiredHeight, int requiredWidth ) { int[] heightWidthRequiredDimensions; // Pass dimensions to worker method depending on image type required heightWidthRequiredDimensions = WorkDimensions(originalBitmap.Height, originalBitmap.Width, requiredHeight, requiredWidth); Bitmap resizedBitmap = new Bitmap( heightWidthRequiredDimensions[1], heightWidthRequiredDimensions[0] ); const float resolution = 72; resizedBitmap.SetResolution( resolution, resolution ); Graphics graphic = Graphics.FromImage( (Image) resizedBitmap ); graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; graphic.DrawImage( originalBitmap, 0, 0, resizedBitmap.Width, resizedBitmap.Height ); graphic.Dispose(); originalBitmap.Dispose(); //resizedBitmap.Dispose(); // Still in use return resizedBitmap; } private static int[] WorkDimensions(int originalHeight, int originalWidth, int requiredHeight, int requiredWidth ) { int imgHeight = 0; int imgWidth = 0; imgWidth = requiredHeight; imgHeight = requiredWidth; int requiredHeightLocal = originalHeight; int requiredWidthLocal = originalWidth; double ratio = 0; // Check height first // If original height exceeds maximum, get new height and work ratio. if ( originalHeight > imgHeight ) { ratio = double.Parse( ( (double) imgHeight / (double) originalHeight ).ToString() ); requiredHeightLocal = imgHeight; requiredWidthLocal = (int) ( (decimal) originalWidth * (decimal) ratio ); } // Check width second. It will most likely have been sized down enough // in the previous if statement. If not, change both dimensions here by width. // If new width exceeds maximum, get new width and height ratio. if ( requiredWidthLocal >= imgWidth ) { ratio = double.Parse( ( (double) imgWidth / (double) originalWidth ).ToString() ); requiredWidthLocal = imgWidth; requiredHeightLocal = (int) ( (double) originalHeight * (double) ratio ); } int[] heightWidthDimensionArr = { requiredHeightLocal, requiredWidthLocal }; return heightWidthDimensionArr; } } 

Esta postagem de blog contém código-fonte completo para redimensionamento de imagens e compactação (se necessário)

http://blog.bombdefused.com/2010/08/bulk-image-optimizer-in-c-full-source.html

Eu consegui fazer isso criando um bitmap da imagem e redimensionando o bitmap … Não tenho certeza se essa é a maneira melhor ou mais eficiente de fazer isso, mas funciona para mim.

No meu caso, eu precisava cortar a altura e a largura da imagem pela metade.

Aqui está o que eu fiz.

  private Image getImageFromBytes(byte[] myByteArray) { System.IO.MemoryStream newImageStream = new System.IO.MemoryStream(myByteArray, 0, myByteArray.Length); Image image = Image.FromStream(newImageStream, true); Bitmap resized = new Bitmap(image, image.Width / 2, image.Height / 2); image.Dispose(); newImageStream.Dispose(); return resized; }