All checks were successful
Deploy ASP.NET MVC to OCI / build-and-deploy (push) Successful in 9m32s
273 lines
12 KiB
C#
273 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.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"];
|
|
}
|
|
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
} |