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 _localizer; private readonly ILogger _logger; public HeicToJpgController(IStringLocalizer localizer, ILogger 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 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 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"); } } } }