.NET: Redimensionar imágenes

Importante: Junto con este artículo y el anterior (Subir archivos al servidor/base de datos), recomiendo leer un artículo más nuevo: Redimensionar y guardar imágenes en ASP.NET, con el cual se resuelven algunos detalles de este.

Como dije en mi último post, si vamos a permitir que el usuario suba imágenes en una aplicación, hay que tener controlado el tamaño de dichas imágenes. Dejar que los usuarios suban imágenes de cualquier tamaño es muy riesgoso, tanto en sobrecarga de información en el servidor de almacenamiento como en la transferencia de datos en la red (local o Internet).

Tampoco podemos ponernos estrictos con el usuario y decirle «la imagen debe ser máximo de 320×240», o algo así. No todos somos diseñadores. No todos tenemos Fireworks, Photoshop, Paint.NET o algún programa para modificar imágenes. Lo mejor es que nosotros mismos hagamos ese ajuste a las imágenes, una vez que el usuario las haya subido y antes de guardarlas en nuestro servidor.

Retomando el ejemplo del artículo anterior, modificaremos el método GuardarArchivo:

private void GuardarArchivo(HttpPostedFile file) {
  // Se carga la ruta física de la carpeta temp del sitio
  string ruta = Server.MapPath("~/temp");

  // Si el directorio no existe, crearlo
  if (!Directory.Exists(ruta))
    Directory.CreateDirectory(ruta);

  string archivo = String.Format("{0}\\{1}", ruta, file.FileName);
  
  // Se usará un objeto Image para guardar la imagen cargada
  Image img = RedimensionarImagen(file.InputStream);

  // Verificar que el archivo no exista
  if (File.Exists(archivo))
    MensajeError(String.Format(
      "Ya existe una imagen con nombre\"{0}\".", file.FileName));
  else {
    // Se revisa el formato de la imagen
    string ext = file.ContentType.Substring(
      file.ContentType.LastIndexOf("/") + 1);
    ImageFormat format;
    switch (ext){
      case "gif":
        format = ImageFormat.Gif;
        break;
      case "bmp":
        format = ImageFormat.Bmp;
        break;
      case "png":
        format = ImageFormat.Png;
        break;
      default:
        format = ImageFormat.Jpeg;
        break;
    }
    img.Save(archivo, format);
  }
}

El objeto System.Drawing.Image (hay que tener cuidado con no confundirlo con el control en System.Web.UI.WebControls) también tiene su método para guardar una imagen en disco, aunque es algo más complicado. Tenemos que revisar el tipo de imagen para indicar el formato con el que se va a guardar. En caso de ser un formato que no tenemos enlistado (como TIF, por ejemplo), se convertirá a JPEG.

Lo siguiente es definir el método RedimensionarImagen:

private static Image RedimensionarImagen(Stream stream) {
  // Se crea un objeto Image, que contiene las propiedades de la imagen
  Image img = Image.FromStream(stream);

  // Tamaño máximo de la imagen (altura o anchura)
  const int max = 200;

  int h = img.Height;
  int w = img.Width;
  int newH, newW;

  if (h > w && h > max) {
    // Si la imagen es vertical y la altura es mayor que max,
    // se redefinen las dimensiones.
    newH = max;
    newW = (w * max) / h;
  } else if (w > h && w > max){
    // Si la imagen es horizontal y la anchura es mayor que max,
    // se redefinen las dimensiones.
    newW = max;
    newH = (h * max) / w;
  } else {
    newH = h;
    newW = w;
  }
  if (h != newH && w != newW) {
    // Si las dimensiones cambiaron, se modifica la imagen
    Bitmap newImg = new Bitmap(img, newW, newH);
    Graphics g = Graphics.FromImage(newImg);
    g.InterpolationMode =
      System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
    g.DrawImage(img, 0, 0, newImg.Width, newImg.Height);
    return newImg;
  } else
    return img;
}

Existe un método GetThumbnailImage en la clase Image, pero no lo recomiendo, ya que de entrada, crea imágenes de muy mala calidad (para que se den una idea, es peor que guardar una imagen en formato JPEG en el MS Paint o.O), además de que requiere ciertos parámetros más complejos. Usar la clase Graphics nos permite redimensionar la imagen bajo un modo de interpolación a nuestra elección, y aunque se ve muy complejo, se basa en operaciones sencillas.

El objeto devuelto es una imagen con unas dimensiones estándares. También podríamos definir las dimensiones máximas como parámetros, o como variables configurables, o de cualquier otro modo, pero eso ya depende de cada quien.

11 comentarios sobre “.NET: Redimensionar imágenes

  1. está excelente, sólo le agregaría que valide el residuo para ver si le aumenta un pixel, bueno comparando el calculo a como redimensiona Photoshop 🙂

  2. Lo quiero traducir a VB.NET pero me quedo en la primera linea
    private static Image RedimensionarImagen(Stream stream)
    pues aunque coloco Imports System.Drawing no me aparece el tipo stream … no encuentro cual es el error o que debo imports. Ya lo agregue como referencia tambien a system.drawing

  3. Hola Cesar, estoy con lo mismo que tú, subir y redimensionar imágenes usando ASP.NET y VB.NET, podrías mandarme el código de la rutina RedimensionarImage(). Mi correo es antonio@siinet.com
    Muchas gracias

  4. Hola, probe tu codigo, me funciono correctamente, el detalle que vi, es que una imagen en png de 1366 x 768 pixeles que pesa 118KB, al reducir el tamaño lo hace correctamente, pero el peso de la imagen quedo en: 143KB subio,

    esto sera correcto?

Replica a Antonio Aranzana Cancelar la respuesta