Convert-it/Areas/ImageConverters/Controllers/HeicToJpgController.cs

278 lines
12 KiB
C#

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using System.IO;
using HeyRed.ImageSharp.Heif;
namespace Convert_It_Online.Areas.ImageConverters.Controllers
{
[Area("ImageConverters")]
public class HeicToJpgController : Controller
{
private readonly IStringLocalizer<SharedResource> _localizer;
private readonly ILogger<HeicToJpgController> _logger;
public HeicToJpgController(IStringLocalizer<SharedResource> localizer, ILogger<HeicToJpgController> logger)
{
_localizer = localizer;
_logger = logger;
}
private void SetCommonViewBagProperties()
{
ViewBag.HomeLink = _localizer["HomeLink"];
ViewBag.TextMenuTitle = _localizer["TextMenuTitle"];
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
ViewBag.DocumentMenuTitle = _localizer["DocumentMenuTitle"];
ViewBag.PdfToTextTitle = _localizer["PdfToTextTitle"];
ViewBag.PdfBarcodeTitle = _localizer["PdfBarcodeTitle"];
ViewBag.FooterText = _localizer["FooterText"];
ViewBag.About = _localizer["About"];
ViewBag.Contact = _localizer["Contact"];
ViewBag.Terms = _localizer["Terms"];
}
private void PrepareIndexView()
{
SetCommonViewBagProperties();
ViewBag.PageTitle = _localizer["HeicConverterPageTitle"];
ViewBag.PageDescription = _localizer["HeicConverterPageDescription"];
ViewBag.HeicToJpgTabTitle = _localizer["HeicToJpgTabTitle"];
ViewBag.JpgToHeicTabTitle = _localizer["JpgToHeicTabTitle"];
ViewBag.HeicFileInputLabel = _localizer["HeicFileInputLabel"];
ViewBag.JpgFileInputLabel = _localizer["JpgFileInputLabel"];
ViewBag.ConvertToJpgButton = _localizer["ConvertToJpgButton"];
ViewBag.ConvertToHeicButton = _localizer["ConvertToHeicButton"];
// FAQ properties
ViewBag.FaqWhatTitle = _localizer["HeicFaqWhatTitle"];
ViewBag.FaqWhatContent = _localizer["HeicFaqWhatContent"];
ViewBag.FaqHowTitle = _localizer["HeicFaqHowTitle"];
ViewBag.FaqHowContent = _localizer["HeicFaqHowContent"];
ViewBag.FaqWhyTitle = _localizer["HeicFaqWhyTitle"];
ViewBag.FaqWhyContent = _localizer["HeicFaqWhyContent"];
ViewBag.FaqSecurityTitle = _localizer["HeicFaqSecurityTitle"];
ViewBag.FaqSecurityContent = _localizer["HeicFaqSecurityContent"];
ViewBag.FaqLimitsTitle = _localizer["HeicFaqLimitsTitle"];
ViewBag.FaqLimitsContent = _localizer["HeicFaqLimitsContent"];
ViewBag.MetaDescription = ViewBag.PageDescription;
}
public IActionResult Index()
{
PrepareIndexView();
return View();
}
[HttpPost]
public async Task<IActionResult> ConvertHeicToJpg(IFormFile heicFile, bool preview = false)
{
if (heicFile == null || heicFile.Length == 0)
{
_logger.LogWarning("[HEIC-CONVERTER] Tentativa de conversão sem arquivo");
if (preview)
{
return Json(new { success = false, message = _localizer["SelectFileError"].Value });
}
ModelState.AddModelError("heicFile", _localizer["SelectFileError"]);
PrepareIndexView();
return View("Index");
}
var allowedTypes = new[] { "image/heic", "image/heif", "application/octet-stream" };
if (!allowedTypes.Contains(heicFile.ContentType) && !heicFile.FileName.ToLower().EndsWith(".heic") && !heicFile.FileName.ToLower().EndsWith(".heif"))
{
_logger.LogWarning("[HEIC-CONVERTER] Arquivo inválido: {ContentType}", heicFile.ContentType);
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidHeicFileError"].Value });
}
ModelState.AddModelError("heicFile", _localizer["InvalidHeicFileError"]);
PrepareIndexView();
return View("Index");
}
try
{
_logger.LogInformation("[HEIC-CONVERTER] Iniciando conversão HEIC→JPG: {FileName} ({Size} bytes)",
heicFile.FileName, heicFile.Length);
var originalSize = heicFile.Length;
// Limite para preview: 10MB
const long maxPreviewSize = 10 * 1024 * 1024;
using var heicStream = heicFile.OpenReadStream();
using var image = await Image.LoadAsync(heicStream);
using var memoryStream = new MemoryStream();
await image.SaveAsJpegAsync(memoryStream);
var jpegData = memoryStream.ToArray();
var convertedSize = jpegData.Length;
var fileName = Path.GetFileNameWithoutExtension(heicFile.FileName) + ".jpg";
_logger.LogInformation("[HEIC-CONVERTER] Conversão HEIC→JPG concluída: {OutputFileName} (Original: {OriginalSize}bytes → Convertido: {ConvertedSize}bytes)",
fileName, originalSize, convertedSize);
// Se é request de preview e o arquivo não é muito grande
if (preview && originalSize <= maxPreviewSize && convertedSize <= maxPreviewSize)
{
var base64 = Convert.ToBase64String(jpegData);
var base64DataUrl = $"data:image/jpeg;base64,{base64}";
return Json(new
{
success = true,
base64 = base64DataUrl,
filename = fileName,
originalSize = originalSize,
convertedSize = convertedSize
});
}
// Download normal (lógica original)
return File(jpegData, "image/jpeg", fileName);
}
catch (UnknownImageFormatException)
{
_logger.LogWarning("[HEIC-CONVERTER] O arquivo HEIC parece ser inválido ou o formato não é suportado. Verifique se a biblioteca 'libheif' está instalada no sistema.");
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidHeicFileError"].Value });
}
ModelState.AddModelError("heicFile", _localizer["InvalidHeicFileError"]);
ViewBag.ConversionError = _localizer["InvalidHeicFileError"];
PrepareIndexView();
return View("Index");
}
catch (Exception ex)
{
_logger.LogError(ex, "[HEIC-CONVERTER] Erro ao converter HEIC para JPG: {FileName}", heicFile.FileName);
if (preview)
{
return Json(new { success = false, message = _localizer["ProcessingError"].Value });
}
ModelState.AddModelError("heicFile", _localizer["ProcessingError"]);
ViewBag.ConversionError = _localizer["ProcessingError"];
PrepareIndexView();
return View("Index");
}
}
[HttpPost]
public async Task<IActionResult> ConvertJpgToHeic(IFormFile jpgFile, bool preview = false)
{
if (jpgFile == null || jpgFile.Length == 0)
{
_logger.LogWarning("[HEIC-CONVERTER] Tentativa de conversão JPG→HEIC sem arquivo");
if (preview)
{
return Json(new { success = false, message = _localizer["SelectFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["SelectFileError"]);
PrepareIndexView();
return View("Index");
}
if (jpgFile.ContentType != "image/jpeg" && !jpgFile.FileName.ToLower().EndsWith(".jpg") && !jpgFile.FileName.ToLower().EndsWith(".jpeg"))
{
_logger.LogWarning("[HEIC-CONVERTER] Arquivo JPG inválido: {ContentType}", jpgFile.ContentType);
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidJpgFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["InvalidJpgFileError"]);
PrepareIndexView();
return View("Index");
}
try
{
_logger.LogInformation("[HEIC-CONVERTER] Iniciando conversão JPG→HEIC: {FileName} ({Size} bytes)",
jpgFile.FileName, jpgFile.Length);
var originalSize = jpgFile.Length;
// Limite para preview: 10MB
const long maxPreviewSize = 10 * 1024 * 1024;
using var jpgStream = jpgFile.OpenReadStream();
using var image = await Image.LoadAsync(jpgStream);
using var memoryStream = new MemoryStream();
// Salvar como HEIC usando o encoder disponível
await image.SaveAsync(memoryStream, new HeyRed.ImageSharp.Heif.Formats.Heif.HeifEncoder());
var heicData = memoryStream.ToArray();
var convertedSize = heicData.Length;
var fileName = Path.GetFileNameWithoutExtension(jpgFile.FileName) + ".heic";
_logger.LogInformation("[HEIC-CONVERTER] Conversão JPG→HEIC concluída: {OutputFileName} (Original: {OriginalSize}bytes → Convertido: {ConvertedSize}bytes)",
fileName, originalSize, convertedSize);
// Se é request de preview e o arquivo não é muito grande
if (preview && originalSize <= maxPreviewSize && convertedSize <= maxPreviewSize)
{
var base64 = Convert.ToBase64String(heicData);
var base64DataUrl = $"data:image/heic;base64,{base64}";
return Json(new
{
success = true,
base64 = base64DataUrl,
filename = fileName,
originalSize = originalSize,
convertedSize = convertedSize
});
}
// Download normal
return File(heicData, "image/heic", fileName);
}
catch (UnknownImageFormatException)
{
_logger.LogWarning("[HEIC-CONVERTER] O arquivo JPG parece ser inválido ou o formato não é suportado.");
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidJpgFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["InvalidJpgFileError"]);
ViewBag.ConversionError = _localizer["InvalidJpgFileError"];
PrepareIndexView();
return View("Index");
}
catch (NotSupportedException)
{
_logger.LogWarning("[HEIC-CONVERTER] Conversão JPG→HEIC não é suportada pela biblioteca atual.");
var errorMsg = "Conversão JPG→HEIC ainda não está disponível. A biblioteca não suporta encoding HEIC.";
if (preview)
{
return Json(new { success = false, message = errorMsg });
}
ModelState.AddModelError("jpgFile", errorMsg);
ViewBag.ConversionError = errorMsg;
PrepareIndexView();
return View("Index");
}
catch (Exception ex)
{
_logger.LogError(ex, "[HEIC-CONVERTER] Erro ao converter JPG para HEIC: {FileName}", jpgFile.FileName);
if (preview)
{
return Json(new { success = false, message = _localizer["ProcessingError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["ProcessingError"]);
ViewBag.ConversionError = _localizer["ProcessingError"];
PrepareIndexView();
return View("Index");
}
}
}
}