Implementación de Recorte de Imágenes y Generación de Miniaturas para Avatares en MVC

Funcionalidad de Recorte de Avatares

Pltaaformas sociales requieren funcionalidad para subir avatares, recortarlos y generar múltiples miniaturas de distintos tamaños.

Código Frontend

<p class="texto-foto">Seleccione su imagen</p>
<div class="subir-archivo">
  @using (Html.BeginForm("SubirAvatar", "Usuario", FormMethod.Post, new { id = "form-avatar", enctype = "multipart/form-data" }))
  {
    <input type="file" name="avatar" class="btn-archivo" onchange="$('#contenedor-subida').hide();$('#contenedor-vista').show();$('#form-avatar').submit();" />
    <input type="button" class="btn-imagen" value="Subir avatar" />
  }
</div>

<div class="controles">
  @using (Html.BeginForm("GuardarAvatar", "Usuario", FormMethod.Post, new { id = "form-parametros" }))
  {
    @Html.Hidden("nombreArchivo", "", new { id = "nombre-archivo" })
    @Html.Hidden("posX", 0, new { id = "pos-x" })
    @Html.Hidden("posY", 0, new { id = "pos-y" })
    @Html.Hidden("ancho", 0, new { id = "ancho" })
    @Html.Hidden("alto", 0, new { id = "alto" })
    <input type="submit" class="btn-confirmar" value="Confirmar">
  }
</div>

Manejo de Eventos

$(function() {
  $("#form-avatar").ajaxForm({
    success: function(respuesta) {
      if(respuesta.archivo) {
        UtilitarioAvatar.inicializar("/avatares/temp/" + respuesta.archivo);
      }
    }
  });
  
  $("#form-parametros").ajaxForm({
    success: function(respuesta) {
      if(respuesta.estado === 1) {
        $(".img-avatar").attr("src", "/avatares/" + respuesta.tamanio + "/" + respuesta.archivo);
      }
    }
  });
});

Código Backend

Controlador para Subida

[HttpPost]
public ActionResult SubirAvatar(HttpPostedFileBase avatar)
{
  string[] formatosPermitidos = { "jpg", "png", "gif" };
  string extension = Path.GetExtension(avatar.FileName).TrimStart('.');
  
  if(!formatosPermitidos.Contains(extension)) 
    return Json(new { estado = -1 });
  
  string nombreTemp = $"{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(1000)}.{extension}";
  string rutaTemp = Server.MapPath("~/avatares/temp/" + nombreTemp);
  
  avatar.SaveAs(rutaTemp);
  return Json(new { archivo = nombreTemp });
}

Cotnrolador para Guardado

[HttpPost]
public ActionResult GuardarAvatar(string nombreArchivo, int posX, int posY, int ancho, int alto)
{
  string rutaOriginal = Server.MapPath($"~/avatares/temp/{nombreArchivo}");
  string extension = Path.GetExtension(nombreArchivo);
  string nombreFinal = $"{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(1000)}{extension}";
  
  int[] tamanios = { 180, 75, 50, 25 };
  foreach(int tamanio in tamanios) {
    string rutaDestino = Server.MapPath($"~/avatares/{tamanio}/{nombreFinal}");
    GenerarMiniatura(rutaOriginal, posX, posY, ancho, alto, tamanio, rutaDestino);
  }
  
  return Json(new { estado = 1, archivo = nombreFinal });
}

Generación de Miniaturas

private void GenerarMiniatura(string origen, int x, int y, int anchoRecorte, int altoRecorte, int tamanioSalida, string destino)
{
  using(var imagenOriginal = Image.FromFile(origen))
  using(var bitmap = new Bitmap(tamanioSalida, tamanioSalida))
  using(var graficos = Graphics.FromImage(bitmap))
  {
    graficos.InterpolationMode = InterpolationMode.HighQualityBicubic;
    graficos.DrawImage(imagenOriginal, 
                      new Rectangle(0, 0, tamanioSalida, tamanioSalida),
                      x, y, anchoRecorte, altoRecorte, 
                      GraphicsUnit.Pixel);
    
    ImageCodecInfo codec = ObtenerCodec(imagenOriginal.RawFormat);
    EncoderParameters parametros = new EncoderParameters(1);
    parametros.Param[0] = new EncoderParameter(Encoder.Quality, 75L);
    bitmap.Save(destino, codec, parametros);
  }
}

Utilidad JavaScript

var UtilitarioAvatar = {
  inicializar: function(rutaImagen) {
    $("#imagen-origen").attr("src", rutaImagen).imgAreaSelect({
      aspectRatio: "1:1",
      onSelectChange: function(seleccion) {
        this.actualizarVistaPrevia(seleccion);
      }.bind(this)
    });
  },
  
  actualizarVistaPrevia: function(seleccion) {
    $("#pos-x").val(seleccion.x);
    $("#pos-y").val(seleccion.y);
    $("#ancho").val(seleccion.ancho);
    $("#alto").val(seleccion.alto);
  }
};

Manejo de Imágenes Móviles

private RotateFlipType CorregirOrientacion(Image imagen)
{
  const int ID_ORIENTACION = 0x0112;
  if(!imagen.PropertyIdList.Contains(ID_ORIENTACION)) 
    return RotateFlipType.RotateNoneFlipNone;

  byte[] datos = imagen.GetPropertyItem(ID_ORIENTACION).Value;
  return datos[0] switch {
    1 => RotateFlipType.RotateNoneFlipNone,
    3 => RotateFlipType.Rotate180FlipNone,
    6 => RotateFlipType.Rotate90FlipNone,
    8 => RotateFlipType.Rotate270FlipNone,
    _ => RotateFlipType.RotateNoneFlipNone
  };
}

Etiquetas: ASP.NET MVC C# jQuery JavaScript

Publicado el 7-31 08:27