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
};
}