fix: banners entre sites
This commit is contained in:
parent
5db9199705
commit
3b0c93a35e
@ -17,7 +17,10 @@
|
|||||||
"WebFetch(domain:github.com)",
|
"WebFetch(domain:github.com)",
|
||||||
"WebFetch(domain:gist.github.com)",
|
"WebFetch(domain:gist.github.com)",
|
||||||
"Bash(dotnet list:*)",
|
"Bash(dotnet list:*)",
|
||||||
"Bash(dotnet build:*)"
|
"Bash(dotnet build:*)",
|
||||||
|
"Bash(rm:*)",
|
||||||
|
"Bash(dotnet add package:*)",
|
||||||
|
"Bash(dir:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
319
Areas/DocumentConverters/Controllers/PdfBarcodeLineController.cs
Normal file
319
Areas/DocumentConverters/Controllers/PdfBarcodeLineController.cs
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
using iText.Kernel.Pdf;
|
||||||
|
using iText.Kernel.Pdf.Canvas.Parser;
|
||||||
|
using iText.Kernel.Pdf.Canvas.Parser.Listener;
|
||||||
|
using iText.Kernel.Exceptions;
|
||||||
|
|
||||||
|
namespace Convert_It_Online.Areas.DocumentConverters.Controllers
|
||||||
|
{
|
||||||
|
[Area("DocumentConverters")]
|
||||||
|
public class PdfBarcodeLineController : Controller
|
||||||
|
{
|
||||||
|
private readonly IStringLocalizer<SharedResource> _localizer;
|
||||||
|
private readonly ILogger<PdfBarcodeLineController> _logger;
|
||||||
|
private const long MaxPreviewSize = 5 * 1024 * 1024; // 5MB
|
||||||
|
private static readonly Regex CandidatePattern = new(@"[0-9\s\.-]{44,70}", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public PdfBarcodeLineController(IStringLocalizer<SharedResource> localizer, ILogger<PdfBarcodeLineController> logger)
|
||||||
|
{
|
||||||
|
_localizer = localizer;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetCommonViewBagProperties()
|
||||||
|
{
|
||||||
|
ViewBag.HomeLink = _localizer["HomeLink"];
|
||||||
|
ViewBag.TextMenuTitle = _localizer["TextMenuTitle"];
|
||||||
|
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
|
||||||
|
ViewBag.DocumentMenuTitle = _localizer["DocumentMenuTitle"];
|
||||||
|
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
||||||
|
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
|
||||||
|
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
|
||||||
|
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["PdfBarcodeConverterPageTitle"];
|
||||||
|
ViewBag.PageDescription = _localizer["PdfBarcodeConverterPageDescription"];
|
||||||
|
ViewBag.PdfBarcodeDetectTabTitle = _localizer["PdfBarcodeDetectTabTitle"];
|
||||||
|
ViewBag.PdfBarcodeDownloadTabTitle = _localizer["PdfBarcodeDownloadTabTitle"];
|
||||||
|
ViewBag.PdfBarcodeFileInputLabel = _localizer["PdfBarcodeFileInputLabel"];
|
||||||
|
ViewBag.PdfPasswordLabel = _localizer["PdfPasswordLabel"];
|
||||||
|
ViewBag.PdfPasswordPlaceholder = _localizer["PdfPasswordPlaceholder"];
|
||||||
|
ViewBag.PdfBarcodePasswordHint = _localizer["PdfBarcodePasswordHint"];
|
||||||
|
ViewBag.DetectBarcodeButton = _localizer["DetectBarcodeButton"];
|
||||||
|
ViewBag.DownloadBarcodeButton = _localizer["DownloadBarcodeButton"];
|
||||||
|
ViewBag.PdfBarcodePreviewTitle = _localizer["PdfBarcodePreviewTitle"];
|
||||||
|
ViewBag.SelectFileError = _localizer["SelectFileError"];
|
||||||
|
ViewBag.CopyButtonLabel = _localizer["CopyButtonLabel"];
|
||||||
|
ViewBag.CopyButtonSuccess = _localizer["CopyButtonSuccess"];
|
||||||
|
|
||||||
|
ViewBag.FaqWhatTitle = _localizer["PdfBarcodeFaqWhatTitle"];
|
||||||
|
ViewBag.FaqWhatContent = _localizer["PdfBarcodeFaqWhatContent"];
|
||||||
|
ViewBag.FaqHowTitle = _localizer["PdfBarcodeFaqHowTitle"];
|
||||||
|
ViewBag.FaqHowContent = _localizer["PdfBarcodeFaqHowContent"];
|
||||||
|
ViewBag.FaqWhyTitle = _localizer["PdfBarcodeFaqWhyTitle"];
|
||||||
|
ViewBag.FaqWhyContent = _localizer["PdfBarcodeFaqWhyContent"];
|
||||||
|
ViewBag.FaqSecurityTitle = _localizer["PdfBarcodeFaqSecurityTitle"];
|
||||||
|
ViewBag.FaqSecurityContent = _localizer["PdfBarcodeFaqSecurityContent"];
|
||||||
|
ViewBag.FaqLimitsTitle = _localizer["PdfBarcodeFaqLimitsTitle"];
|
||||||
|
ViewBag.FaqLimitsContent = _localizer["PdfBarcodeFaqLimitsContent"];
|
||||||
|
|
||||||
|
ViewBag.MetaDescription = ViewBag.PageDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
PrepareIndexView();
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> DetectLine(IFormFile pdfFile, string? password, bool preview = false)
|
||||||
|
{
|
||||||
|
return await HandleDetection(pdfFile, password, preview, forDownload: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> DownloadLine(IFormFile pdfFile, string? password, bool preview = false)
|
||||||
|
{
|
||||||
|
return await HandleDetection(pdfFile, password, preview, forDownload: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IActionResult> HandleDetection(IFormFile? pdfFile, string? password, bool preview, bool forDownload)
|
||||||
|
{
|
||||||
|
if (pdfFile == null || pdfFile.Length == 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("[PDF-BARCODE] Attempt without file");
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = _localizer["SelectFileError"].Value });
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelState.AddModelError("pdfFile", _localizer["SelectFileError"]);
|
||||||
|
PrepareIndexView();
|
||||||
|
return View("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidPdf(pdfFile))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("[PDF-BARCODE] Invalid file type: {ContentType}", pdfFile.ContentType);
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = _localizer["InvalidPdfFileError"].Value });
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelState.AddModelError("pdfFile", _localizer["InvalidPdfFileError"]);
|
||||||
|
PrepareIndexView();
|
||||||
|
return View("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preview && pdfFile.Length > MaxPreviewSize)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = _localizer["PdfPreviewTooLarge"].Value });
|
||||||
|
}
|
||||||
|
|
||||||
|
var extraction = await TryExtractTextAsync(pdfFile, password);
|
||||||
|
if (!extraction.Success)
|
||||||
|
{
|
||||||
|
var message = _localizer[extraction.ErrorKey].Value;
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message });
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelState.AddModelError("pdfFile", _localizer[extraction.ErrorKey]);
|
||||||
|
ViewBag.ConversionError = message;
|
||||||
|
PrepareIndexView();
|
||||||
|
return View("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
var lineResult = FindBarcodeLine(extraction.Content ?? string.Empty);
|
||||||
|
if (lineResult == null)
|
||||||
|
{
|
||||||
|
var message = _localizer["PdfNoBarcodeFound"].Value;
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message });
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelState.AddModelError("pdfFile", _localizer["PdfNoBarcodeFound"]);
|
||||||
|
ViewBag.ConversionError = message;
|
||||||
|
PrepareIndexView();
|
||||||
|
return View("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new
|
||||||
|
{
|
||||||
|
success = true,
|
||||||
|
content = lineResult,
|
||||||
|
format = "digit-line"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileBaseName = Path.GetFileNameWithoutExtension(pdfFile.FileName);
|
||||||
|
var downloadFileName = string.IsNullOrWhiteSpace(fileBaseName) ? "linha-digitavel.txt" : fileBaseName + "-linha-digitavel.txt";
|
||||||
|
var payload = Encoding.UTF8.GetBytes(lineResult + Environment.NewLine);
|
||||||
|
return File(payload, "text/plain", downloadFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<(bool Success, string? Content, string ErrorKey)> TryExtractTextAsync(IFormFile pdfFile, string? password)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var memoryStream = new MemoryStream();
|
||||||
|
await pdfFile.CopyToAsync(memoryStream);
|
||||||
|
var pdfBytes = memoryStream.ToArray();
|
||||||
|
|
||||||
|
// Try multiple password encodings
|
||||||
|
var passwords = new List<byte[]?> { null }; // Start with no password
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
passwords.Add(System.Text.Encoding.UTF8.GetBytes(password));
|
||||||
|
passwords.Add(System.Text.Encoding.ASCII.GetBytes(password));
|
||||||
|
passwords.Add(System.Text.Encoding.Latin1.GetBytes(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pwd in passwords)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ReaderProperties readerProperties = new ReaderProperties();
|
||||||
|
if (pwd != null)
|
||||||
|
{
|
||||||
|
readerProperties.SetPassword(pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var pdfReader = new PdfReader(new MemoryStream(pdfBytes), readerProperties);
|
||||||
|
using var pdfDocument = new PdfDocument(pdfReader);
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
int numberOfPages = pdfDocument.GetNumberOfPages();
|
||||||
|
|
||||||
|
for (int i = 1; i <= numberOfPages; i++)
|
||||||
|
{
|
||||||
|
var page = pdfDocument.GetPage(i);
|
||||||
|
|
||||||
|
// Try multiple extraction strategies for barcode detection
|
||||||
|
var strategies = new ITextExtractionStrategy[]
|
||||||
|
{
|
||||||
|
new LocationTextExtractionStrategy(),
|
||||||
|
new SimpleTextExtractionStrategy()
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var strategy in strategies)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pageText = PdfTextExtractor.GetTextFromPage(page, strategy);
|
||||||
|
if (!string.IsNullOrWhiteSpace(pageText))
|
||||||
|
{
|
||||||
|
builder.AppendLine(pageText);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = builder.ToString();
|
||||||
|
if (!string.IsNullOrWhiteSpace(result))
|
||||||
|
{
|
||||||
|
return (true, result, string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (BadPasswordException) when (pwd != null)
|
||||||
|
{
|
||||||
|
continue; // Try next password encoding
|
||||||
|
}
|
||||||
|
catch (BadPasswordException) when (pwd == null && !string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
return (false, null, "PdfInvalidPassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, null, "InvalidPdfFileError");
|
||||||
|
}
|
||||||
|
catch (BadPasswordException)
|
||||||
|
{
|
||||||
|
return (false, null, string.IsNullOrEmpty(password) ? "PdfPasswordRequired" : "PdfInvalidPassword");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "[PDF-BARCODE] Failed to extract text from {FileName}", pdfFile.FileName);
|
||||||
|
return (false, null, "InvalidPdfFileError");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsValidPdf(IFormFile file)
|
||||||
|
{
|
||||||
|
if (file == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentType = file.ContentType?.ToLowerInvariant();
|
||||||
|
if (contentType == "application/pdf" || contentType == "application/x-pdf")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Path.GetExtension(file.FileName).Equals(".pdf", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? FindBarcodeLine(string rawText)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(rawText))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Match match in CandidatePattern.Matches(rawText))
|
||||||
|
{
|
||||||
|
var digits = Regex.Replace(match.Value, "[^0-9]", string.Empty);
|
||||||
|
if (digits.Length == 47 || digits.Length == 48 || digits.Length == 44)
|
||||||
|
{
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback: check full text digits
|
||||||
|
var fullDigits = Regex.Replace(rawText, "[^0-9]", string.Empty);
|
||||||
|
if (fullDigits.Length >= 44)
|
||||||
|
{
|
||||||
|
var candidates = new[] { 48, 47, 44 };
|
||||||
|
foreach (var length in candidates)
|
||||||
|
{
|
||||||
|
if (fullDigits.Length >= length)
|
||||||
|
{
|
||||||
|
return fullDigits.Substring(0, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
318
Areas/DocumentConverters/Controllers/PdfToTextController.cs
Normal file
318
Areas/DocumentConverters/Controllers/PdfToTextController.cs
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
using iText.Kernel.Pdf;
|
||||||
|
using iText.Kernel.Pdf.Canvas.Parser;
|
||||||
|
using iText.Kernel.Pdf.Canvas.Parser.Listener;
|
||||||
|
using iText.Kernel.Exceptions;
|
||||||
|
|
||||||
|
namespace Convert_It_Online.Areas.DocumentConverters.Controllers
|
||||||
|
{
|
||||||
|
[Area("DocumentConverters")]
|
||||||
|
public class PdfToTextController : Controller
|
||||||
|
{
|
||||||
|
private readonly IStringLocalizer<SharedResource> _localizer;
|
||||||
|
private readonly ILogger<PdfToTextController> _logger;
|
||||||
|
private const long MaxPreviewSize = 10 * 1024 * 1024; // 10MB
|
||||||
|
|
||||||
|
public PdfToTextController(IStringLocalizer<SharedResource> localizer, ILogger<PdfToTextController> logger)
|
||||||
|
{
|
||||||
|
_localizer = localizer;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetCommonViewBagProperties()
|
||||||
|
{
|
||||||
|
ViewBag.HomeLink = _localizer["HomeLink"];
|
||||||
|
ViewBag.TextMenuTitle = _localizer["TextMenuTitle"];
|
||||||
|
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
|
||||||
|
ViewBag.DocumentMenuTitle = _localizer["DocumentMenuTitle"];
|
||||||
|
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
||||||
|
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
|
||||||
|
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
|
||||||
|
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["PdfTextConverterPageTitle"];
|
||||||
|
ViewBag.PageDescription = _localizer["PdfTextConverterPageDescription"];
|
||||||
|
ViewBag.PdfPlainTextTabTitle = _localizer["PdfPlainTextTabTitle"];
|
||||||
|
ViewBag.PdfMarkdownTabTitle = _localizer["PdfMarkdownTabTitle"];
|
||||||
|
ViewBag.PdfFileInputLabel = _localizer["PdfFileInputLabel"];
|
||||||
|
ViewBag.PdfPasswordLabel = _localizer["PdfPasswordLabel"];
|
||||||
|
ViewBag.PdfPasswordPlaceholder = _localizer["PdfPasswordPlaceholder"];
|
||||||
|
ViewBag.PdfPasswordHint = _localizer["PdfPasswordHint"];
|
||||||
|
ViewBag.ExtractPlainTextButton = _localizer["ExtractPlainTextButton"];
|
||||||
|
ViewBag.ExtractMarkdownButton = _localizer["ExtractMarkdownButton"];
|
||||||
|
ViewBag.DownloadPlainTextButton = _localizer["DownloadPlainTextButton"];
|
||||||
|
ViewBag.DownloadMarkdownButton = _localizer["DownloadMarkdownButton"];
|
||||||
|
ViewBag.PdfTextPreviewTitle = _localizer["PdfTextPreviewTitle"];
|
||||||
|
ViewBag.SelectFileError = _localizer["SelectFileError"];
|
||||||
|
|
||||||
|
ViewBag.FaqWhatTitle = _localizer["PdfTextFaqWhatTitle"];
|
||||||
|
ViewBag.FaqWhatContent = _localizer["PdfTextFaqWhatContent"];
|
||||||
|
ViewBag.FaqHowTitle = _localizer["PdfTextFaqHowTitle"];
|
||||||
|
ViewBag.FaqHowContent = _localizer["PdfTextFaqHowContent"];
|
||||||
|
ViewBag.FaqWhyTitle = _localizer["PdfTextFaqWhyTitle"];
|
||||||
|
ViewBag.FaqWhyContent = _localizer["PdfTextFaqWhyContent"];
|
||||||
|
ViewBag.FaqSecurityTitle = _localizer["PdfTextFaqSecurityTitle"];
|
||||||
|
ViewBag.FaqSecurityContent = _localizer["PdfTextFaqSecurityContent"];
|
||||||
|
ViewBag.FaqLimitsTitle = _localizer["PdfTextFaqLimitsTitle"];
|
||||||
|
ViewBag.FaqLimitsContent = _localizer["PdfTextFaqLimitsContent"];
|
||||||
|
|
||||||
|
ViewBag.MetaDescription = ViewBag.PageDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
PrepareIndexView();
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult Test()
|
||||||
|
{
|
||||||
|
return Json(new { success = true, message = "Roteamento funcionando!", timestamp = DateTime.Now });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> ExtractPlainText(IFormFile pdfFile, string? password, bool preview = false)
|
||||||
|
{
|
||||||
|
return await HandleExtraction(pdfFile, password, preview, toMarkdown: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> ExtractMarkdown(IFormFile pdfFile, string? password, bool preview = false)
|
||||||
|
{
|
||||||
|
return await HandleExtraction(pdfFile, password, preview, toMarkdown: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IActionResult> HandleExtraction(IFormFile? pdfFile, string? password, bool preview, bool toMarkdown)
|
||||||
|
{
|
||||||
|
if (pdfFile == null || pdfFile.Length == 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("[PDF-TEXT] Attempt without file");
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = _localizer["SelectFileError"].Value });
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelState.AddModelError("pdfFile", _localizer["SelectFileError"]);
|
||||||
|
PrepareIndexView();
|
||||||
|
return View("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidPdf(pdfFile))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("[PDF-TEXT] Invalid file type: {ContentType}", pdfFile.ContentType);
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = _localizer["InvalidPdfFileError"].Value });
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelState.AddModelError("pdfFile", _localizer["InvalidPdfFileError"]);
|
||||||
|
PrepareIndexView();
|
||||||
|
return View("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preview && pdfFile.Length > MaxPreviewSize)
|
||||||
|
{
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message = _localizer["PdfPreviewTooLarge"].Value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var extraction = await TryExtractTextAsync(pdfFile, password);
|
||||||
|
if (!extraction.Success)
|
||||||
|
{
|
||||||
|
var message = _localizer[extraction.ErrorKey].Value;
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new { success = false, message });
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelState.AddModelError("pdfFile", _localizer[extraction.ErrorKey]);
|
||||||
|
ViewBag.ConversionError = message;
|
||||||
|
PrepareIndexView();
|
||||||
|
return View("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
var textContent = extraction.Content ?? string.Empty;
|
||||||
|
if (toMarkdown)
|
||||||
|
{
|
||||||
|
textContent = ToMarkdown(textContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileBaseName = Path.GetFileNameWithoutExtension(pdfFile.FileName);
|
||||||
|
var extension = toMarkdown ? ".md" : ".txt";
|
||||||
|
var downloadFileName = string.IsNullOrWhiteSpace(fileBaseName) ? (toMarkdown ? "resultado.md" : "resultado.txt") : fileBaseName + extension;
|
||||||
|
var contentType = toMarkdown ? "text/markdown" : "text/plain";
|
||||||
|
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
return Json(new
|
||||||
|
{
|
||||||
|
success = true,
|
||||||
|
content = textContent,
|
||||||
|
filename = downloadFileName,
|
||||||
|
format = toMarkdown ? "markdown" : "text"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload = Encoding.UTF8.GetBytes(textContent);
|
||||||
|
return File(payload, contentType, downloadFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<(bool Success, string? Content, string ErrorKey)> TryExtractTextAsync(IFormFile pdfFile, string? password)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var memoryStream = new MemoryStream();
|
||||||
|
await pdfFile.CopyToAsync(memoryStream);
|
||||||
|
var pdfBytes = memoryStream.ToArray();
|
||||||
|
|
||||||
|
// Try multiple password encodings and extraction strategies
|
||||||
|
var passwords = new List<byte[]?> { null }; // Start with no password
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
passwords.Add(System.Text.Encoding.UTF8.GetBytes(password));
|
||||||
|
passwords.Add(System.Text.Encoding.ASCII.GetBytes(password));
|
||||||
|
passwords.Add(System.Text.Encoding.Latin1.GetBytes(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pwd in passwords)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ReaderProperties readerProperties = new ReaderProperties();
|
||||||
|
if (pwd != null)
|
||||||
|
{
|
||||||
|
readerProperties.SetPassword(pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var pdfReader = new PdfReader(new MemoryStream(pdfBytes), readerProperties);
|
||||||
|
using var pdfDocument = new PdfDocument(pdfReader);
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
int numberOfPages = pdfDocument.GetNumberOfPages();
|
||||||
|
|
||||||
|
for (int i = 1; i <= numberOfPages; i++)
|
||||||
|
{
|
||||||
|
var page = pdfDocument.GetPage(i);
|
||||||
|
|
||||||
|
// Try multiple extraction strategies
|
||||||
|
var strategies = new ITextExtractionStrategy[]
|
||||||
|
{
|
||||||
|
new LocationTextExtractionStrategy(),
|
||||||
|
new SimpleTextExtractionStrategy()
|
||||||
|
};
|
||||||
|
|
||||||
|
string pageText = "";
|
||||||
|
foreach (var strategy in strategies)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pageText = PdfTextExtractor.GetTextFromPage(page, strategy);
|
||||||
|
if (!string.IsNullOrWhiteSpace(pageText))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(pageText))
|
||||||
|
{
|
||||||
|
builder.AppendLine(pageText);
|
||||||
|
builder.AppendLine();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[Página {i} - texto não detectado ou pode conter apenas imagens]");
|
||||||
|
builder.AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = builder.ToString().Trim();
|
||||||
|
if (!string.IsNullOrWhiteSpace(result))
|
||||||
|
{
|
||||||
|
return (true, result, string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (BadPasswordException) when (pwd != null)
|
||||||
|
{
|
||||||
|
continue; // Try next password encoding
|
||||||
|
}
|
||||||
|
catch (BadPasswordException) when (pwd == null && !string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
// Document requires password but none worked
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here, either password was wrong or no text found
|
||||||
|
if (!string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
return (false, null, "PdfInvalidPassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, null, "InvalidPdfFileError");
|
||||||
|
}
|
||||||
|
catch (BadPasswordException)
|
||||||
|
{
|
||||||
|
return (false, null, string.IsNullOrEmpty(password) ? "PdfPasswordRequired" : "PdfInvalidPassword");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "[PDF-TEXT] Failed to extract text from {FileName}", pdfFile.FileName);
|
||||||
|
return (false, null, "InvalidPdfFileError");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsValidPdf(IFormFile file)
|
||||||
|
{
|
||||||
|
if (file == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentType = file.ContentType?.ToLowerInvariant();
|
||||||
|
if (contentType == "application/pdf" || contentType == "application/x-pdf")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Path.GetExtension(file.FileName).Equals(".pdf", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToMarkdown(string text)
|
||||||
|
{
|
||||||
|
var normalized = text.Replace("\r\n", "\n").Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(normalized))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
var lines = normalized.Split('\n');
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
var trimmed = line.TrimEnd();
|
||||||
|
builder.AppendLine(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString().Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
354
Areas/DocumentConverters/Views/PdfBarcodeLine/Index.cshtml
Normal file
354
Areas/DocumentConverters/Views/PdfBarcodeLine/Index.cshtml
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
@{
|
||||||
|
ViewData["Title"] = ViewBag.PageTitle;
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="display-5">@ViewBag.PageTitle</h1>
|
||||||
|
<p class="lead text-muted">@ViewBag.PageDescription</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-10 col-xl-8">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-header bg-primary text-white">
|
||||||
|
<h5 class="mb-0">
|
||||||
|
<i class="bi bi-upc-scan me-2"></i>@ViewBag.DocumentMenuTitle
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
@if (ViewBag.ConversionError != null)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||||
|
@ViewBag.ConversionError
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs mb-4" id="barcodeTabs" role="tablist">
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link active" id="detect-tab" data-bs-toggle="tab" data-bs-target="#detect" type="button" role="tab" aria-controls="detect" aria-selected="true">
|
||||||
|
<i class="bi bi-eyeglasses me-2"></i>@ViewBag.PdfBarcodeDetectTabTitle
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="download-tab" data-bs-toggle="tab" data-bs-target="#download" type="button" role="tab" aria-controls="download" aria-selected="false">
|
||||||
|
<i class="bi bi-download me-2"></i>@ViewBag.PdfBarcodeDownloadTabTitle
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content" id="barcodeTabContent">
|
||||||
|
<div class="tab-pane fade show active" id="detect" role="tabpanel" aria-labelledby="detect-tab">
|
||||||
|
<form id="detectForm" action="/pt-BR/DocumentConverters/PdfBarcodeLine/DetectLine" method="post" enctype="multipart/form-data" class="needs-validation" novalidate>
|
||||||
|
<div asp-validation-summary="ModelOnly" class="alert alert-danger" role="alert"></div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="detectPdfFile" class="form-label fw-semibold">@ViewBag.PdfBarcodeFileInputLabel</label>
|
||||||
|
<input class="form-control" type="file" id="detectPdfFile" name="pdfFile" accept=".pdf" required>
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
@ViewBag.SelectFileError
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="detectPassword" class="form-label fw-semibold">@ViewBag.PdfPasswordLabel</label>
|
||||||
|
<input class="form-control" type="password" id="detectPassword" name="password" placeholder="@ViewBag.PdfPasswordPlaceholder">
|
||||||
|
<div class="form-text">
|
||||||
|
<i class="bi bi-shield-lock me-1"></i>@ViewBag.PdfBarcodePasswordHint
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button type="button" id="previewDetectBtn" class="btn btn-primary">
|
||||||
|
<i class="bi bi-upc-scan me-2"></i>@ViewBag.DetectBarcodeButton
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-outline-secondary">
|
||||||
|
<i class="bi bi-download me-2"></i>@ViewBag.DownloadBarcodeButton
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane fade" id="download" role="tabpanel" aria-labelledby="download-tab">
|
||||||
|
<form id="downloadForm" action="/pt-BR/DocumentConverters/PdfBarcodeLine/DownloadLine" method="post" enctype="multipart/form-data" class="needs-validation" novalidate>
|
||||||
|
<div asp-validation-summary="ModelOnly" class="alert alert-danger" role="alert"></div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="downloadPdfFile" class="form-label fw-semibold">@ViewBag.PdfBarcodeFileInputLabel</label>
|
||||||
|
<input class="form-control" type="file" id="downloadPdfFile" name="pdfFile" accept=".pdf" required>
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
@ViewBag.SelectFileError
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="downloadPassword" class="form-label fw-semibold">@ViewBag.PdfPasswordLabel</label>
|
||||||
|
<input class="form-control" type="password" id="downloadPassword" name="password" placeholder="@ViewBag.PdfPasswordPlaceholder">
|
||||||
|
<div class="form-text">
|
||||||
|
<i class="bi bi-shield-lock me-1"></i>@ViewBag.PdfBarcodePasswordHint
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button type="button" id="previewDownloadBtn" class="btn btn-primary">
|
||||||
|
<i class="bi bi-eye me-2"></i>@ViewBag.DetectBarcodeButton
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-outline-secondary">
|
||||||
|
<i class="bi bi-download me-2"></i>@ViewBag.DownloadBarcodeButton
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="barcodeLoading" class="text-center my-4" style="display: none;">
|
||||||
|
<div class="spinner-border text-primary" role="status">
|
||||||
|
<span class="visually-hidden">Carregando...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="barcodePreview" class="mt-4" style="display: none;">
|
||||||
|
<h5 class="mb-3">@ViewBag.PdfBarcodePreviewTitle</h5>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" id="barcodeResult" class="form-control" readonly>
|
||||||
|
<button id="copyBarcodeBtn" class="btn btn-outline-success" type="button">
|
||||||
|
<i class="bi bi-clipboard-check me-1"></i>@ViewBag.CopyButtonLabel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="text-end mt-3">
|
||||||
|
<button id="downloadBarcodeBtn" class="btn btn-success btn-sm">
|
||||||
|
<i class="bi bi-box-arrow-down me-2"></i>@ViewBag.DownloadBarcodeButton
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="barcodeError" class="mt-4" style="display: none;">
|
||||||
|
<div class="alert alert-warning" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||||
|
<span id="barcodeErrorMessage"></span>
|
||||||
|
<button id="fallbackBarcodeBtn" class="btn btn-outline-primary btn-sm ms-2">
|
||||||
|
@ViewBag.DownloadBarcodeButton
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-5">
|
||||||
|
<div class="col-lg-10 mx-auto">
|
||||||
|
<div class="converter-faq">
|
||||||
|
<h3 class="h4 mb-3 text-center">Perguntas Frequentes</h3>
|
||||||
|
<div class="accordion" id="barcodeFaqAccordion">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="barcodeFaqWhat">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#barcodeCollapseWhat" aria-expanded="false" aria-controls="barcodeCollapseWhat">
|
||||||
|
<i class="bi bi-question-circle me-2"></i>@ViewBag.FaqWhatTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="barcodeCollapseWhat" class="accordion-collapse collapse" aria-labelledby="barcodeFaqWhat" data-bs-parent="#barcodeFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqWhatContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="barcodeFaqHow">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#barcodeCollapseHow" aria-expanded="false" aria-controls="barcodeCollapseHow">
|
||||||
|
<i class="bi bi-gear me-2"></i>@ViewBag.FaqHowTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="barcodeCollapseHow" class="accordion-collapse collapse" aria-labelledby="barcodeFaqHow" data-bs-parent="#barcodeFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqHowContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="barcodeFaqWhy">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#barcodeCollapseWhy" aria-expanded="false" aria-controls="barcodeCollapseWhy">
|
||||||
|
<i class="bi bi-lightbulb me-2"></i>@ViewBag.FaqWhyTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="barcodeCollapseWhy" class="accordion-collapse collapse" aria-labelledby="barcodeFaqWhy" data-bs-parent="#barcodeFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqWhyContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="barcodeFaqSecurity">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#barcodeCollapseSecurity" aria-expanded="false" aria-controls="barcodeCollapseSecurity">
|
||||||
|
<i class="bi bi-shield-check me-2"></i>@ViewBag.FaqSecurityTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="barcodeCollapseSecurity" class="accordion-collapse collapse" aria-labelledby="barcodeFaqSecurity" data-bs-parent="#barcodeFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqSecurityContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="barcodeFaqLimits">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#barcodeCollapseLimits" aria-expanded="false" aria-controls="barcodeCollapseLimits">
|
||||||
|
<i class="bi bi-exclamation-triangle me-2"></i>@ViewBag.FaqLimitsTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="barcodeCollapseLimits" class="accordion-collapse collapse" aria-labelledby="barcodeFaqLimits" data-bs-parent="#barcodeFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqLimitsContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#barcodeResult {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner-border {
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
const detectForm = document.getElementById('detectForm');
|
||||||
|
const downloadForm = document.getElementById('downloadForm');
|
||||||
|
const previewDetectBtn = document.getElementById('previewDetectBtn');
|
||||||
|
const previewDownloadBtn = document.getElementById('previewDownloadBtn');
|
||||||
|
const downloadBarcodeBtn = document.getElementById('downloadBarcodeBtn');
|
||||||
|
const fallbackBarcodeBtn = document.getElementById('fallbackBarcodeBtn');
|
||||||
|
const copyBarcodeBtn = document.getElementById('copyBarcodeBtn');
|
||||||
|
const barcodeLoading = document.getElementById('barcodeLoading');
|
||||||
|
const barcodePreview = document.getElementById('barcodePreview');
|
||||||
|
const barcodeError = document.getElementById('barcodeError');
|
||||||
|
const barcodeResult = document.getElementById('barcodeResult');
|
||||||
|
const barcodeErrorMessage = document.getElementById('barcodeErrorMessage');
|
||||||
|
|
||||||
|
let currentLine = '';
|
||||||
|
let currentFileName = 'linha-digitavel.txt';
|
||||||
|
|
||||||
|
const forms = document.querySelectorAll('.needs-validation');
|
||||||
|
Array.from(forms).forEach(function (form) {
|
||||||
|
form.addEventListener('submit', function (event) {
|
||||||
|
if (!form.checkValidity()) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
form.classList.add('was-validated');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
previewDetectBtn.addEventListener('click', function () {
|
||||||
|
handlePreview(detectForm);
|
||||||
|
});
|
||||||
|
|
||||||
|
previewDownloadBtn.addEventListener('click', function () {
|
||||||
|
handlePreview(downloadForm);
|
||||||
|
});
|
||||||
|
|
||||||
|
downloadBarcodeBtn.addEventListener('click', function () {
|
||||||
|
if (!currentLine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const blob = new Blob([currentLine + '\n'], { type: 'text/plain;charset=utf-8' });
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
anchor.href = url;
|
||||||
|
anchor.download = currentFileName;
|
||||||
|
document.body.appendChild(anchor);
|
||||||
|
anchor.click();
|
||||||
|
document.body.removeChild(anchor);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
fallbackBarcodeBtn.addEventListener('click', function () {
|
||||||
|
const activeTab = document.querySelector('.nav-link.active');
|
||||||
|
const currentForm = activeTab.id === 'detect-tab' ? detectForm : downloadForm;
|
||||||
|
currentForm.submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
copyBarcodeBtn.addEventListener('click', function () {
|
||||||
|
if (!currentLine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
navigator.clipboard.writeText(currentLine).then(function () {
|
||||||
|
copyBarcodeBtn.innerHTML = '<i class="bi bi-clipboard-check-fill me-1"></i>@ViewBag.CopyButtonSuccess';
|
||||||
|
setTimeout(function () {
|
||||||
|
copyBarcodeBtn.innerHTML = '<i class="bi bi-clipboard-check me-1"></i>@ViewBag.CopyButtonLabel';
|
||||||
|
}, 1500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function handlePreview(form) {
|
||||||
|
if (!form.checkValidity()) {
|
||||||
|
form.classList.add('was-validated');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showLoading();
|
||||||
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
fetch(form.action + '?preview=true', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
}).then(async response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
const text = await response.text();
|
||||||
|
throw new Error(text || response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.message || 'Erro na conversão');
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLine = result.content;
|
||||||
|
currentFileName = (form === downloadForm ? 'linha-digitavel-download.txt' : 'linha-digitavel.txt');
|
||||||
|
barcodeResult.value = currentLine;
|
||||||
|
showPreview();
|
||||||
|
}).catch(error => {
|
||||||
|
showError(error.message || 'Erro inesperado.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLoading() {
|
||||||
|
barcodeLoading.style.display = 'block';
|
||||||
|
barcodePreview.style.display = 'none';
|
||||||
|
barcodeError.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPreview() {
|
||||||
|
barcodeLoading.style.display = 'none';
|
||||||
|
barcodeError.style.display = 'none';
|
||||||
|
barcodePreview.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showError(message) {
|
||||||
|
barcodeLoading.style.display = 'none';
|
||||||
|
barcodePreview.style.display = 'none';
|
||||||
|
barcodeErrorMessage.textContent = message;
|
||||||
|
barcodeError.style.display = 'block';
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
}
|
||||||
350
Areas/DocumentConverters/Views/PdfToText/Index.cshtml
Normal file
350
Areas/DocumentConverters/Views/PdfToText/Index.cshtml
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
@{
|
||||||
|
ViewData["Title"] = ViewBag.PageTitle;
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="display-5">@ViewBag.PageTitle</h1>
|
||||||
|
<p class="lead text-muted">@ViewBag.PageDescription</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-10 col-xl-8">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-header bg-primary text-white">
|
||||||
|
<h5 class="mb-0">
|
||||||
|
<i class="bi bi-file-earmark-text me-2"></i>@ViewBag.DocumentMenuTitle
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
@if (ViewBag.ConversionError != null)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||||
|
@ViewBag.ConversionError
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs mb-4" id="pdfTextTabs" role="tablist">
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link active" id="plain-text-tab" data-bs-toggle="tab" data-bs-target="#plain-text" type="button" role="tab" aria-controls="plain-text" aria-selected="true">
|
||||||
|
<i class="bi bi-file-text me-2"></i>@ViewBag.PdfPlainTextTabTitle
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="markdown-tab" data-bs-toggle="tab" data-bs-target="#markdown" type="button" role="tab" aria-controls="markdown" aria-selected="false">
|
||||||
|
<i class="bi bi-markdown me-2"></i>@ViewBag.PdfMarkdownTabTitle
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content" id="pdfTextTabContent">
|
||||||
|
<div class="tab-pane fade show active" id="plain-text" role="tabpanel" aria-labelledby="plain-text-tab">
|
||||||
|
<form id="plainTextForm" action="/pt-BR/DocumentConverters/PdfToText/ExtractPlainText" method="post" enctype="multipart/form-data" class="needs-validation" novalidate>
|
||||||
|
<div asp-validation-summary="ModelOnly" class="alert alert-danger" role="alert"></div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="plainTextPdfFile" class="form-label fw-semibold">@ViewBag.PdfFileInputLabel</label>
|
||||||
|
<input class="form-control" type="file" id="plainTextPdfFile" name="pdfFile" accept=".pdf" required>
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
@ViewBag.SelectFileError
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="plainTextPassword" class="form-label fw-semibold">@ViewBag.PdfPasswordLabel</label>
|
||||||
|
<input class="form-control" type="password" id="plainTextPassword" name="password" placeholder="@ViewBag.PdfPasswordPlaceholder">
|
||||||
|
<div class="form-text">
|
||||||
|
<i class="bi bi-shield-lock me-1"></i>@ViewBag.PdfPasswordHint
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button type="button" id="previewPlainTextBtn" class="btn btn-primary">
|
||||||
|
<i class="bi bi-eye me-2"></i>@ViewBag.ExtractPlainTextButton
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-outline-secondary">
|
||||||
|
<i class="bi bi-download me-2"></i>@ViewBag.DownloadPlainTextButton
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane fade" id="markdown" role="tabpanel" aria-labelledby="markdown-tab">
|
||||||
|
<form id="markdownForm" action="/pt-BR/DocumentConverters/PdfToText/ExtractMarkdown" method="post" enctype="multipart/form-data" class="needs-validation" novalidate>
|
||||||
|
<div asp-validation-summary="ModelOnly" class="alert alert-danger" role="alert"></div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="markdownPdfFile" class="form-label fw-semibold">@ViewBag.PdfFileInputLabel</label>
|
||||||
|
<input class="form-control" type="file" id="markdownPdfFile" name="pdfFile" accept=".pdf" required>
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
@ViewBag.SelectFileError
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="markdownPassword" class="form-label fw-semibold">@ViewBag.PdfPasswordLabel</label>
|
||||||
|
<input class="form-control" type="password" id="markdownPassword" name="password" placeholder="@ViewBag.PdfPasswordPlaceholder">
|
||||||
|
<div class="form-text">
|
||||||
|
<i class="bi bi-shield-lock me-1"></i>@ViewBag.PdfPasswordHint
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button type="button" id="previewMarkdownBtn" class="btn btn-primary">
|
||||||
|
<i class="bi bi-eye me-2"></i>@ViewBag.ExtractMarkdownButton
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-outline-secondary">
|
||||||
|
<i class="bi bi-download me-2"></i>@ViewBag.DownloadMarkdownButton
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="loadingSpinner" class="text-center my-4" style="display: none;">
|
||||||
|
<div class="spinner-border text-primary" role="status">
|
||||||
|
<span class="visually-hidden">Carregando...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="previewArea" class="mt-4" style="display: none;">
|
||||||
|
<h5 class="mb-3">@ViewBag.PdfTextPreviewTitle</h5>
|
||||||
|
<textarea id="previewTextArea" class="form-control" rows="12" readonly></textarea>
|
||||||
|
<div class="text-end mt-3">
|
||||||
|
<button id="downloadPreviewBtn" class="btn btn-success btn-sm">
|
||||||
|
<i class="bi bi-box-arrow-down me-2"></i>@ViewBag.DownloadPlainTextButton
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="errorArea" class="mt-4" style="display: none;">
|
||||||
|
<div class="alert alert-warning" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||||
|
<span id="errorMessage"></span>
|
||||||
|
<button id="fallbackDownloadBtn" class="btn btn-outline-primary btn-sm ms-2">
|
||||||
|
@ViewBag.DownloadPlainTextButton
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-5">
|
||||||
|
<div class="col-lg-10 mx-auto">
|
||||||
|
<div class="converter-faq">
|
||||||
|
<h3 class="h4 mb-3 text-center">Perguntas Frequentes</h3>
|
||||||
|
<div class="accordion" id="pdfTextFaqAccordion">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="faqWhat">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWhat" aria-expanded="false" aria-controls="collapseWhat">
|
||||||
|
<i class="bi bi-question-circle me-2"></i>@ViewBag.FaqWhatTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapseWhat" class="accordion-collapse collapse" aria-labelledby="faqWhat" data-bs-parent="#pdfTextFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqWhatContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="faqHow">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseHow" aria-expanded="false" aria-controls="collapseHow">
|
||||||
|
<i class="bi bi-gear me-2"></i>@ViewBag.FaqHowTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapseHow" class="accordion-collapse collapse" aria-labelledby="faqHow" data-bs-parent="#pdfTextFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqHowContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="faqWhy">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWhy" aria-expanded="false" aria-controls="collapseWhy">
|
||||||
|
<i class="bi bi-lightbulb me-2"></i>@ViewBag.FaqWhyTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapseWhy" class="accordion-collapse collapse" aria-labelledby="faqWhy" data-bs-parent="#pdfTextFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqWhyContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="faqSecurity">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSecurity" aria-expanded="false" aria-controls="collapseSecurity">
|
||||||
|
<i class="bi bi-shield-check me-2"></i>@ViewBag.FaqSecurityTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapseSecurity" class="accordion-collapse collapse" aria-labelledby="faqSecurity" data-bs-parent="#pdfTextFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqSecurityContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="faqLimits">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseLimits" aria-expanded="false" aria-controls="collapseLimits">
|
||||||
|
<i class="bi bi-exclamation-triangle me-2"></i>@ViewBag.FaqLimitsTitle
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapseLimits" class="accordion-collapse collapse" aria-labelledby="faqLimits" data-bs-parent="#pdfTextFaqAccordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@ViewBag.FaqLimitsContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#previewTextArea {
|
||||||
|
font-family: monospace;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner-border {
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
const plainForm = document.getElementById('plainTextForm');
|
||||||
|
const markdownForm = document.getElementById('markdownForm');
|
||||||
|
const previewPlainBtn = document.getElementById('previewPlainTextBtn');
|
||||||
|
const previewMarkdownBtn = document.getElementById('previewMarkdownBtn');
|
||||||
|
const downloadPreviewBtn = document.getElementById('downloadPreviewBtn');
|
||||||
|
const fallbackDownloadBtn = document.getElementById('fallbackDownloadBtn');
|
||||||
|
const loadingSpinner = document.getElementById('loadingSpinner');
|
||||||
|
const previewArea = document.getElementById('previewArea');
|
||||||
|
const errorArea = document.getElementById('errorArea');
|
||||||
|
const previewTextArea = document.getElementById('previewTextArea');
|
||||||
|
const errorMessage = document.getElementById('errorMessage');
|
||||||
|
const previewTitleButton = document.getElementById('downloadPreviewBtn');
|
||||||
|
|
||||||
|
let previewContent = '';
|
||||||
|
let previewFileName = 'resultado.txt';
|
||||||
|
let previewMime = 'text/plain';
|
||||||
|
|
||||||
|
const forms = document.querySelectorAll('.needs-validation');
|
||||||
|
Array.from(forms).forEach(function (form) {
|
||||||
|
form.addEventListener('submit', function (event) {
|
||||||
|
if (!form.checkValidity()) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
form.classList.add('was-validated');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
previewPlainBtn.addEventListener('click', function () {
|
||||||
|
handlePreview(plainForm, 'text/plain');
|
||||||
|
});
|
||||||
|
|
||||||
|
previewMarkdownBtn.addEventListener('click', function () {
|
||||||
|
handlePreview(markdownForm, 'text/markdown');
|
||||||
|
});
|
||||||
|
|
||||||
|
downloadPreviewBtn.addEventListener('click', function () {
|
||||||
|
if (!previewContent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const blob = new Blob([previewContent], { type: previewMime + ';charset=utf-8' });
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
anchor.href = url;
|
||||||
|
anchor.download = previewFileName;
|
||||||
|
document.body.appendChild(anchor);
|
||||||
|
anchor.click();
|
||||||
|
document.body.removeChild(anchor);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
fallbackDownloadBtn.addEventListener('click', function () {
|
||||||
|
const activeTab = document.querySelector('.nav-link.active');
|
||||||
|
const currentForm = activeTab.id === 'plain-text-tab' ? plainForm : markdownForm;
|
||||||
|
currentForm.submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
function handlePreview(form, mimeType) {
|
||||||
|
if (!form.checkValidity()) {
|
||||||
|
form.classList.add('was-validated');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showLoading();
|
||||||
|
const formData = new FormData(form);
|
||||||
|
const requestUrl = form.action + '?preview=true';
|
||||||
|
|
||||||
|
console.log('DEBUG: Requesting URL:', requestUrl);
|
||||||
|
console.log('DEBUG: Form action:', form.action);
|
||||||
|
|
||||||
|
fetch(requestUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
}).then(async response => {
|
||||||
|
console.log('DEBUG: Response status:', response.status);
|
||||||
|
console.log('DEBUG: Response headers:', response.headers.get('content-type'));
|
||||||
|
|
||||||
|
const responseText = await response.text();
|
||||||
|
console.log('DEBUG: Response text (first 200 chars):', responseText.substring(0, 200));
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(responseText || response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = JSON.parse(responseText);
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.message || 'Erro na conversão');
|
||||||
|
}
|
||||||
|
|
||||||
|
previewContent = result.content;
|
||||||
|
previewFileName = result.filename;
|
||||||
|
previewMime = mimeType;
|
||||||
|
previewTextArea.value = result.content;
|
||||||
|
previewTitleButton.innerHTML = `<i class="bi bi-box-arrow-down me-2"></i>${result.format === 'markdown' ? '@ViewBag.DownloadMarkdownButton' : '@ViewBag.DownloadPlainTextButton'}`;
|
||||||
|
showPreview();
|
||||||
|
}).catch(error => {
|
||||||
|
showError(error.message || 'Erro inesperado.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLoading() {
|
||||||
|
loadingSpinner.style.display = 'block';
|
||||||
|
previewArea.style.display = 'none';
|
||||||
|
errorArea.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPreview() {
|
||||||
|
loadingSpinner.style.display = 'none';
|
||||||
|
errorArea.style.display = 'none';
|
||||||
|
previewArea.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showError(message) {
|
||||||
|
loadingSpinner.style.display = 'none';
|
||||||
|
previewArea.style.display = 'none';
|
||||||
|
errorMessage.textContent = message;
|
||||||
|
errorArea.style.display = 'block';
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
}
|
||||||
@ -27,6 +27,9 @@ namespace Convert_It_Online.Areas.ImageConverters.Controllers
|
|||||||
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
||||||
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
|
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
|
||||||
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
|
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
|
||||||
|
ViewBag.DocumentMenuTitle = _localizer["DocumentMenuTitle"];
|
||||||
|
ViewBag.PdfToTextTitle = _localizer["PdfToTextTitle"];
|
||||||
|
ViewBag.PdfBarcodeTitle = _localizer["PdfBarcodeTitle"];
|
||||||
ViewBag.FooterText = _localizer["FooterText"];
|
ViewBag.FooterText = _localizer["FooterText"];
|
||||||
ViewBag.About = _localizer["About"];
|
ViewBag.About = _localizer["About"];
|
||||||
ViewBag.Contact = _localizer["Contact"];
|
ViewBag.Contact = _localizer["Contact"];
|
||||||
@ -56,6 +59,7 @@ namespace Convert_It_Online.Areas.ImageConverters.Controllers
|
|||||||
ViewBag.FaqSecurityContent = _localizer["HeicFaqSecurityContent"];
|
ViewBag.FaqSecurityContent = _localizer["HeicFaqSecurityContent"];
|
||||||
ViewBag.FaqLimitsTitle = _localizer["HeicFaqLimitsTitle"];
|
ViewBag.FaqLimitsTitle = _localizer["HeicFaqLimitsTitle"];
|
||||||
ViewBag.FaqLimitsContent = _localizer["HeicFaqLimitsContent"];
|
ViewBag.FaqLimitsContent = _localizer["HeicFaqLimitsContent"];
|
||||||
|
ViewBag.MetaDescription = ViewBag.PageDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
|
|||||||
@ -25,6 +25,10 @@ namespace Convert_It_Online.Areas.ImageConverters.Controllers
|
|||||||
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
|
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
|
||||||
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
||||||
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
|
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.FooterText = _localizer["FooterText"];
|
||||||
ViewBag.About = _localizer["About"];
|
ViewBag.About = _localizer["About"];
|
||||||
ViewBag.Contact = _localizer["Contact"];
|
ViewBag.Contact = _localizer["Contact"];
|
||||||
@ -54,6 +58,7 @@ namespace Convert_It_Online.Areas.ImageConverters.Controllers
|
|||||||
ViewBag.FaqSecurityContent = _localizer["JpgWebpFaqSecurityContent"];
|
ViewBag.FaqSecurityContent = _localizer["JpgWebpFaqSecurityContent"];
|
||||||
ViewBag.FaqLimitsTitle = _localizer["JpgWebpFaqLimitsTitle"];
|
ViewBag.FaqLimitsTitle = _localizer["JpgWebpFaqLimitsTitle"];
|
||||||
ViewBag.FaqLimitsContent = _localizer["JpgWebpFaqLimitsContent"];
|
ViewBag.FaqLimitsContent = _localizer["JpgWebpFaqLimitsContent"];
|
||||||
|
ViewBag.MetaDescription = ViewBag.PageDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
|
|||||||
@ -37,6 +37,10 @@ namespace Convert_It_Online.Areas.TextTools.Controllers
|
|||||||
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
|
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
|
||||||
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
||||||
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
|
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.FooterText = _localizer["FooterText"];
|
||||||
ViewBag.About = _localizer["About"];
|
ViewBag.About = _localizer["About"];
|
||||||
ViewBag.Contact = _localizer["Contact"];
|
ViewBag.Contact = _localizer["Contact"];
|
||||||
@ -66,6 +70,7 @@ namespace Convert_It_Online.Areas.TextTools.Controllers
|
|||||||
ViewBag.FaqSecurityContent = _localizer["CaseFaqSecurityContent"];
|
ViewBag.FaqSecurityContent = _localizer["CaseFaqSecurityContent"];
|
||||||
ViewBag.FaqLimitsTitle = _localizer["CaseFaqLimitsTitle"];
|
ViewBag.FaqLimitsTitle = _localizer["CaseFaqLimitsTitle"];
|
||||||
ViewBag.FaqLimitsContent = _localizer["CaseFaqLimitsContent"];
|
ViewBag.FaqLimitsContent = _localizer["CaseFaqLimitsContent"];
|
||||||
|
ViewBag.MetaDescription = ViewBag.PageTitle;
|
||||||
|
|
||||||
var model = new CaseConverterViewModel();
|
var model = new CaseConverterViewModel();
|
||||||
return View(model);
|
return View(model);
|
||||||
@ -83,6 +88,7 @@ namespace Convert_It_Online.Areas.TextTools.Controllers
|
|||||||
ViewBag.ToLowerButton = _localizer["ToLowerButton"];
|
ViewBag.ToLowerButton = _localizer["ToLowerButton"];
|
||||||
ViewBag.ToSentenceCaseButton = _localizer["ToSentenceCaseButton"];
|
ViewBag.ToSentenceCaseButton = _localizer["ToSentenceCaseButton"];
|
||||||
ViewBag.ResultTitle = _localizer["ResultTitle"];
|
ViewBag.ResultTitle = _localizer["ResultTitle"];
|
||||||
|
ViewBag.MetaDescription = ViewBag.PageTitle;
|
||||||
|
|
||||||
if (!ModelState.IsValid || string.IsNullOrEmpty(model.InputText))
|
if (!ModelState.IsValid || string.IsNullOrEmpty(model.InputText))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -13,10 +13,12 @@ Convert-It Online é uma aplicação web ASP.NET Core que oferece ferramentas gr
|
|||||||
**Português (pt-BR):**
|
**Português (pt-BR):**
|
||||||
- Ferramentas de Texto: `/pt-BR/ferramentas-de-texto/conversor-de-maiusculas-minusculas`
|
- Ferramentas de Texto: `/pt-BR/ferramentas-de-texto/conversor-de-maiusculas-minusculas`
|
||||||
- Conversores de Imagem: `/pt-BR/conversores-de-imagem/jpg-para-webp`
|
- Conversores de Imagem: `/pt-BR/conversores-de-imagem/jpg-para-webp`
|
||||||
|
- Conversores de Documento: `/pt-BR/conversores-de-documento/pdf-para-texto`
|
||||||
|
|
||||||
**Espanhol (es-MX, es-CL, es-PY):**
|
**Espanhol (es-MX, es-CL, es-PY):**
|
||||||
- Herramientas de Texto: `/es-MX/herramientas-de-texto/conversor-de-mayusculas-minusculas`
|
- Herramientas de Texto: `/es-MX/herramientas-de-texto/conversor-de-mayusculas-minusculas`
|
||||||
- Convertidores de Imagen: `/es-MX/convertidores-de-imagen/jpg-a-webp`
|
- Convertidores de Imagen: `/es-MX/convertidores-de-imagen/jpg-a-webp`
|
||||||
|
- Convertidores de Documento: `/es-MX/convertidores-de-documento/pdf-a-texto`
|
||||||
|
|
||||||
### Arquitetura do Sistema de URLs
|
### Arquitetura do Sistema de URLs
|
||||||
|
|
||||||
@ -53,6 +55,12 @@ Convert-It Online é uma aplicação web ASP.NET Core que oferece ferramentas gr
|
|||||||
- **URL PT**: `/pt-BR/conversores-de-imagem/jpg-para-webp`
|
- **URL PT**: `/pt-BR/conversores-de-imagem/jpg-para-webp`
|
||||||
- **URL ES**: `/es-MX/convertidores-de-imagen/jpg-a-webp`
|
- **URL ES**: `/es-MX/convertidores-de-imagen/jpg-a-webp`
|
||||||
|
|
||||||
|
### DocumentConverters
|
||||||
|
- **Controllers**: `PdfToTextController`, `PdfBarcodeLineController`
|
||||||
|
- **Funcionalidades**: Extrair texto/Markdown de PDFs e detectar linha digitável de boletos
|
||||||
|
- **URL PT**: `/pt-BR/conversores-de-documento/pdf-para-texto` e `/pt-BR/conversores-de-documento/linha-digitavel-do-pdf`
|
||||||
|
- **URL ES**: `/es-MX/convertidores-de-documento/pdf-a-texto` e `/es-MX/convertidores-de-documento/linea-digitada-desde-pdf`
|
||||||
|
|
||||||
## Desenvolvimento Guidelines
|
## Desenvolvimento Guidelines
|
||||||
|
|
||||||
### Adicionando Novos Conversores
|
### Adicionando Novos Conversores
|
||||||
|
|||||||
@ -32,6 +32,9 @@ namespace Convert_It_Online.Controllers
|
|||||||
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
|
||||||
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
|
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
|
||||||
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
|
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
|
||||||
|
ViewBag.DocumentMenuTitle = _localizer["DocumentMenuTitle"];
|
||||||
|
ViewBag.PdfToTextTitle = _localizer["PdfToTextTitle"];
|
||||||
|
ViewBag.PdfBarcodeTitle = _localizer["PdfBarcodeTitle"];
|
||||||
ViewBag.FooterText = _localizer["FooterText"];
|
ViewBag.FooterText = _localizer["FooterText"];
|
||||||
ViewBag.About = _localizer["About"];
|
ViewBag.About = _localizer["About"];
|
||||||
ViewBag.Contact = _localizer["Contact"];
|
ViewBag.Contact = _localizer["Contact"];
|
||||||
@ -51,6 +54,7 @@ namespace Convert_It_Online.Controllers
|
|||||||
ViewBag.SecurityContent = _localizer["SecurityContent"];
|
ViewBag.SecurityContent = _localizer["SecurityContent"];
|
||||||
ViewBag.AllConvertersTitle = _localizer["AllConvertersTitle"];
|
ViewBag.AllConvertersTitle = _localizer["AllConvertersTitle"];
|
||||||
ViewBag.UseConverterButton = _localizer["UseConverterButton"];
|
ViewBag.UseConverterButton = _localizer["UseConverterButton"];
|
||||||
|
ViewBag.MetaDescription = ViewBag.Subtitle;
|
||||||
|
|
||||||
var individualConverters = new List<ToolViewModel>
|
var individualConverters = new List<ToolViewModel>
|
||||||
{
|
{
|
||||||
@ -77,6 +81,22 @@ namespace Convert_It_Online.Controllers
|
|||||||
Area = "ImageConverters",
|
Area = "ImageConverters",
|
||||||
Controller = "HeicToJpg",
|
Controller = "HeicToJpg",
|
||||||
IconClass = "bi-phone"
|
IconClass = "bi-phone"
|
||||||
|
},
|
||||||
|
new ToolViewModel
|
||||||
|
{
|
||||||
|
Title = _localizer["PdfToTextIndividualTitle"],
|
||||||
|
Description = _localizer["PdfToTextIndividualDescription"],
|
||||||
|
Area = "DocumentConverters",
|
||||||
|
Controller = "PdfToText",
|
||||||
|
IconClass = "bi-file-text"
|
||||||
|
},
|
||||||
|
new ToolViewModel
|
||||||
|
{
|
||||||
|
Title = _localizer["PdfBarcodeIndividualTitle"],
|
||||||
|
Description = _localizer["PdfBarcodeIndividualDescription"],
|
||||||
|
Area = "DocumentConverters",
|
||||||
|
Controller = "PdfBarcodeLine",
|
||||||
|
IconClass = "bi-upc-scan"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,6 +117,7 @@ namespace Convert_It_Online.Controllers
|
|||||||
ViewBag.Feature3 = _localizer["Feature3"];
|
ViewBag.Feature3 = _localizer["Feature3"];
|
||||||
ViewBag.Feature4 = _localizer["Feature4"];
|
ViewBag.Feature4 = _localizer["Feature4"];
|
||||||
ViewBag.StartConverting = _localizer["StartConverting"];
|
ViewBag.StartConverting = _localizer["StartConverting"];
|
||||||
|
ViewBag.MetaDescription = ViewBag.WhatIsContent;
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +130,7 @@ namespace Convert_It_Online.Controllers
|
|||||||
ViewBag.SupportTitle = _localizer["SupportTitle"];
|
ViewBag.SupportTitle = _localizer["SupportTitle"];
|
||||||
ViewBag.SupportTime = _localizer["SupportTime"];
|
ViewBag.SupportTime = _localizer["SupportTime"];
|
||||||
ViewBag.FaqTitle = _localizer["FaqTitle"];
|
ViewBag.FaqTitle = _localizer["FaqTitle"];
|
||||||
|
ViewBag.MetaDescription = ViewBag.ContactIntro;
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +151,7 @@ namespace Convert_It_Online.Controllers
|
|||||||
ViewBag.ChangesContent = _localizer["ChangesContent"];
|
ViewBag.ChangesContent = _localizer["ChangesContent"];
|
||||||
ViewBag.LastUpdated = _localizer["LastUpdated"];
|
ViewBag.LastUpdated = _localizer["LastUpdated"];
|
||||||
ViewBag.BackToHome = _localizer["BackToHome"];
|
ViewBag.BackToHome = _localizer["BackToHome"];
|
||||||
|
ViewBag.MetaDescription = ViewBag.TermsIntro;
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
@ -11,6 +11,7 @@
|
|||||||
<PackageReference Include="HeyRed.ImageSharp.Heif" Version="2.1.3" />
|
<PackageReference Include="HeyRed.ImageSharp.Heif" Version="2.1.3" />
|
||||||
<PackageReference Include="LibHeif.Native.win-x64" Version="1.15.1" />
|
<PackageReference Include="LibHeif.Native.win-x64" Version="1.15.1" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
||||||
|
<PackageReference Include="itext7" Version="8.0.5" />
|
||||||
<PackageReference Include="Serilog" Version="4.1.0" />
|
<PackageReference Include="Serilog" Version="4.1.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
||||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
||||||
|
|||||||
@ -35,6 +35,14 @@ namespace Convert_It_Online.Middleware
|
|||||||
var translatedController = match.Groups[3].Value;
|
var translatedController = match.Groups[3].Value;
|
||||||
var action = match.Groups[4].Success ? match.Groups[4].Value : "Index";
|
var action = match.Groups[4].Success ? match.Groups[4].Value : "Index";
|
||||||
|
|
||||||
|
// Skip if this is already an internal area/controller name (starts with capital letter)
|
||||||
|
if (char.IsUpper(translatedArea[0]) || char.IsUpper(translatedController[0]))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Skipping internal path: {path}");
|
||||||
|
await _next(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_logger.LogInformation($"Matched: culture={cultureName}, area={translatedArea}, controller={translatedController}, action={action}");
|
_logger.LogInformation($"Matched: culture={cultureName}, area={translatedArea}, controller={translatedController}, action={action}");
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|||||||
@ -16,22 +16,26 @@ namespace Convert_It_Online.Services
|
|||||||
["pt-BR"] = new Dictionary<string, string>
|
["pt-BR"] = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
["TextTools"] = "ferramentas-de-texto",
|
["TextTools"] = "ferramentas-de-texto",
|
||||||
["ImageConverters"] = "conversores-de-imagem"
|
["ImageConverters"] = "conversores-de-imagem",
|
||||||
|
["DocumentConverters"] = "conversores-de-documento"
|
||||||
},
|
},
|
||||||
["es-MX"] = new Dictionary<string, string>
|
["es-MX"] = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
["TextTools"] = "herramientas-de-texto",
|
["TextTools"] = "herramientas-de-texto",
|
||||||
["ImageConverters"] = "convertidores-de-imagen"
|
["ImageConverters"] = "convertidores-de-imagen",
|
||||||
|
["DocumentConverters"] = "convertidores-de-documento"
|
||||||
},
|
},
|
||||||
["es-CL"] = new Dictionary<string, string>
|
["es-CL"] = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
["TextTools"] = "herramientas-de-texto",
|
["TextTools"] = "herramientas-de-texto",
|
||||||
["ImageConverters"] = "convertidores-de-imagen"
|
["ImageConverters"] = "convertidores-de-imagen",
|
||||||
|
["DocumentConverters"] = "convertidores-de-documento"
|
||||||
},
|
},
|
||||||
["es-PY"] = new Dictionary<string, string>
|
["es-PY"] = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
["TextTools"] = "herramientas-de-texto",
|
["TextTools"] = "herramientas-de-texto",
|
||||||
["ImageConverters"] = "convertidores-de-imagen"
|
["ImageConverters"] = "convertidores-de-imagen",
|
||||||
|
["DocumentConverters"] = "convertidores-de-documento"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,25 +45,33 @@ namespace Convert_It_Online.Services
|
|||||||
{
|
{
|
||||||
["CaseConverter"] = "conversor-de-maiusculas-minusculas",
|
["CaseConverter"] = "conversor-de-maiusculas-minusculas",
|
||||||
["JpgToWebp"] = "jpg-para-webp",
|
["JpgToWebp"] = "jpg-para-webp",
|
||||||
["HeicToJpg"] = "heic-para-jpg"
|
["HeicToJpg"] = "heic-para-jpg",
|
||||||
|
["PdfToText"] = "pdf-para-texto",
|
||||||
|
["PdfBarcodeLine"] = "linha-digitavel-do-pdf"
|
||||||
},
|
},
|
||||||
["es-MX"] = new Dictionary<string, string>
|
["es-MX"] = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
||||||
["JpgToWebp"] = "jpg-a-webp",
|
["JpgToWebp"] = "jpg-a-webp",
|
||||||
["HeicToJpg"] = "heic-a-jpg"
|
["HeicToJpg"] = "heic-a-jpg",
|
||||||
|
["PdfToText"] = "pdf-a-texto",
|
||||||
|
["PdfBarcodeLine"] = "linea-digitada-desde-pdf"
|
||||||
},
|
},
|
||||||
["es-CL"] = new Dictionary<string, string>
|
["es-CL"] = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
||||||
["JpgToWebp"] = "jpg-a-webp",
|
["JpgToWebp"] = "jpg-a-webp",
|
||||||
["HeicToJpg"] = "heic-a-jpg"
|
["HeicToJpg"] = "heic-a-jpg",
|
||||||
|
["PdfToText"] = "pdf-a-texto",
|
||||||
|
["PdfBarcodeLine"] = "linea-digitada-desde-pdf"
|
||||||
},
|
},
|
||||||
["es-PY"] = new Dictionary<string, string>
|
["es-PY"] = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
||||||
["JpgToWebp"] = "jpg-a-webp",
|
["JpgToWebp"] = "jpg-a-webp",
|
||||||
["HeicToJpg"] = "heic-a-jpg"
|
["HeicToJpg"] = "heic-a-jpg",
|
||||||
|
["PdfToText"] = "pdf-a-texto",
|
||||||
|
["PdfBarcodeLine"] = "linea-digitada-desde-pdf"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -51,12 +51,21 @@
|
|||||||
<data name="ImageMenuTitle" xml:space="preserve">
|
<data name="ImageMenuTitle" xml:space="preserve">
|
||||||
<value>Imagen</value>
|
<value>Imagen</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DocumentMenuTitle" xml:space="preserve">
|
||||||
|
<value>Documentos</value>
|
||||||
|
</data>
|
||||||
<data name="CaseConverterTitle" xml:space="preserve">
|
<data name="CaseConverterTitle" xml:space="preserve">
|
||||||
<value>Convertidor de Mayúsculas/Minúsculas</value>
|
<value>Convertidor de Mayúsculas/Minúsculas</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="JpgToWebpTitle" xml:space="preserve">
|
<data name="JpgToWebpTitle" xml:space="preserve">
|
||||||
<value>JPG a WebP</value>
|
<value>JPG a WebP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PdfToTextTitle" xml:space="preserve">
|
||||||
|
<value>PDF a Texto/Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeTitle" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<data name="FooterText" xml:space="preserve">
|
<data name="FooterText" xml:space="preserve">
|
||||||
@ -113,12 +122,24 @@
|
|||||||
<data name="UrlImageConverters" xml:space="preserve">
|
<data name="UrlImageConverters" xml:space="preserve">
|
||||||
<value>convertidores-de-imagen</value>
|
<value>convertidores-de-imagen</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UrlDocumentConverters" xml:space="preserve">
|
||||||
|
<value>convertidores-de-documento</value>
|
||||||
|
</data>
|
||||||
<data name="UrlCaseConverter" xml:space="preserve">
|
<data name="UrlCaseConverter" xml:space="preserve">
|
||||||
<value>conversor-de-mayusculas-minusculas</value>
|
<value>conversor-de-mayusculas-minusculas</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UrlJpgToWebp" xml:space="preserve">
|
<data name="UrlJpgToWebp" xml:space="preserve">
|
||||||
<value>jpg-a-webp</value>
|
<value>jpg-a-webp</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UrlHeicToJpg" xml:space="preserve">
|
||||||
|
<value>heic-a-jpg</value>
|
||||||
|
</data>
|
||||||
|
<data name="UrlPdfToText" xml:space="preserve">
|
||||||
|
<value>pdf-a-texto</value>
|
||||||
|
</data>
|
||||||
|
<data name="UrlPdfBarcode" xml:space="preserve">
|
||||||
|
<value>linea-digitada-desde-pdf</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- New individual converter resources - Mexican Spanish -->
|
<!-- New individual converter resources - Mexican Spanish -->
|
||||||
<data name="AllConvertersTitle" xml:space="preserve">
|
<data name="AllConvertersTitle" xml:space="preserve">
|
||||||
@ -142,6 +163,18 @@
|
|||||||
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
|
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
|
||||||
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
|
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PdfToTextIndividualTitle" xml:space="preserve">
|
||||||
|
<value>Extraer texto de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfToTextIndividualDescription" xml:space="preserve">
|
||||||
|
<value>Transforma tus PDFs en texto simple o Markdown, incluso cuando requieren contraseña.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeIndividualTitle" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeIndividualDescription" xml:space="preserve">
|
||||||
|
<value>Obtén la línea digitada de boletos directamente desde el PDF, con soporte para archivos protegidos.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- HEIC converter menu item -->
|
<!-- HEIC converter menu item -->
|
||||||
<data name="HeicToJpgTitle" xml:space="preserve">
|
<data name="HeicToJpgTitle" xml:space="preserve">
|
||||||
@ -204,16 +237,167 @@
|
|||||||
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
|
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<!-- PDF to Text Converter Resources -->
|
||||||
|
<data name="PdfTextConverterPageTitle" xml:space="preserve">
|
||||||
|
<value>Extraer texto de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextConverterPageDescription" xml:space="preserve">
|
||||||
|
<value>Convierte tus PDFs en texto simple o Markdown con soporte para archivos protegidos con contraseña.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPlainTextTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Texto simple</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfMarkdownTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfFileInputLabel" xml:space="preserve">
|
||||||
|
<value>Seleccionar archivo PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordLabel" xml:space="preserve">
|
||||||
|
<value>Contraseña del PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordPlaceholder" xml:space="preserve">
|
||||||
|
<value>Ingresa la contraseña si el PDF está protegido</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordHint" xml:space="preserve">
|
||||||
|
<value>Si el PDF requiere contraseña de apertura, escríbela aquí. De lo contrario, deja el campo vacío.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExtractPlainTextButton" xml:space="preserve">
|
||||||
|
<value>Extraer y visualizar</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExtractMarkdownButton" xml:space="preserve">
|
||||||
|
<value>Extraer en Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadPlainTextButton" xml:space="preserve">
|
||||||
|
<value>Descargar texto</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadMarkdownButton" xml:space="preserve">
|
||||||
|
<value>Descargar Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextPreviewTitle" xml:space="preserve">
|
||||||
|
<value>Vista previa del contenido</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhatTitle" xml:space="preserve">
|
||||||
|
<value>¿Qué hace este conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhatContent" xml:space="preserve">
|
||||||
|
<value>Extrae el contenido textual del PDF y lo entrega como texto simple o Markdown, preservando cortes y secciones siempre que sea posible.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqHowTitle" xml:space="preserve">
|
||||||
|
<value>¿Cómo usar el conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqHowContent" xml:space="preserve">
|
||||||
|
<value>Selecciona el archivo PDF, ingresa la contraseña si es necesario y elige la pestaña deseada. Visualiza el resultado en línea o descarga el archivo.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhyTitle" xml:space="preserve">
|
||||||
|
<value>¿Por qué convertir PDF a texto o Markdown?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhyContent" xml:space="preserve">
|
||||||
|
<value>El texto simple permite ediciones rápidas, mientras que Markdown facilita reutilizar el contenido en blogs o documentación.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqSecurityTitle" xml:space="preserve">
|
||||||
|
<value>¿Es seguro subir mis PDFs?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqSecurityContent" xml:space="preserve">
|
||||||
|
<value>Sí. Procesamos los archivos siguiendo estrictas políticas de privacidad y los eliminamos tras la conversión.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqLimitsTitle" xml:space="preserve">
|
||||||
|
<value>¿Existen límites de tamaño?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqLimitsContent" xml:space="preserve">
|
||||||
|
<value>Para la vista previa recomendamos PDFs de hasta 10MB. Archivos mayores pueden descargarse directamente en texto o Markdown.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<!-- PDF Barcode Converter Resources -->
|
||||||
|
<data name="PdfBarcodeConverterPageTitle" xml:space="preserve">
|
||||||
|
<value>Extraer línea digitada de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeConverterPageDescription" xml:space="preserve">
|
||||||
|
<value>Detecta la línea digitada de boletos o facturas directamente desde el PDF, incluso si está protegido.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeDetectTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Ver línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeDownloadTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Descargar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFileInputLabel" xml:space="preserve">
|
||||||
|
<value>Seleccionar PDF del boleto</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodePasswordHint" xml:space="preserve">
|
||||||
|
<value>Si el PDF está protegido con contraseña, ingrésala para permitir la lectura.</value>
|
||||||
|
</data>
|
||||||
|
<data name="DetectBarcodeButton" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadBarcodeButton" xml:space="preserve">
|
||||||
|
<value>Descargar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodePreviewTitle" xml:space="preserve">
|
||||||
|
<value>Línea digitada detectada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhatTitle" xml:space="preserve">
|
||||||
|
<value>¿Qué es la línea digitada?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhatContent" xml:space="preserve">
|
||||||
|
<value>Es la secuencia numérica del código de barras del boleto, utilizada para realizar pagos en bancos y aplicaciones.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqHowTitle" xml:space="preserve">
|
||||||
|
<value>¿Cómo funciona el conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqHowContent" xml:space="preserve">
|
||||||
|
<value>Extrae el texto del PDF, identifica patrones de boletos (47 o 48 dígitos) y muestra la línea lista para copiar o descargar.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhyTitle" xml:space="preserve">
|
||||||
|
<value>¿Cuándo usar este recurso?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhyContent" xml:space="preserve">
|
||||||
|
<value>Ideal para boletos sin código de barras legible o cuando necesitas copiar la línea digitada para pagar en línea.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqSecurityTitle" xml:space="preserve">
|
||||||
|
<value>¿Mis datos están seguros?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqSecurityContent" xml:space="preserve">
|
||||||
|
<value>Sí. El PDF se procesa solo para extraer la línea digitada y se descarta inmediatamente después.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqLimitsTitle" xml:space="preserve">
|
||||||
|
<value>¿Existen limitaciones?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqLimitsContent" xml:space="preserve">
|
||||||
|
<value>Para mejores resultados utiliza PDFs con texto seleccionable. Boletos en formato de imagen pueden requerir una solución OCR externa.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- Error Messages -->
|
<!-- Error Messages -->
|
||||||
<data name="SelectFileError" xml:space="preserve">
|
<data name="SelectFileError" xml:space="preserve">
|
||||||
<value>Por favor, selecciona un archivo para convertir.</value>
|
<value>Por favor, selecciona un archivo para convertir.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CopyButtonLabel" xml:space="preserve">
|
||||||
|
<value>Copiar</value>
|
||||||
|
</data>
|
||||||
|
<data name="CopyButtonSuccess" xml:space="preserve">
|
||||||
|
<value>¡Copiado!</value>
|
||||||
|
</data>
|
||||||
<data name="InvalidHeicFileError" xml:space="preserve">
|
<data name="InvalidHeicFileError" xml:space="preserve">
|
||||||
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
|
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InvalidJpgFileError" xml:space="preserve">
|
<data name="InvalidJpgFileError" xml:space="preserve">
|
||||||
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
|
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="InvalidPdfFileError" xml:space="preserve">
|
||||||
|
<value>Archivo PDF inválido, dañado o con protecciones no compatibles.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordRequired" xml:space="preserve">
|
||||||
|
<value>Este PDF está protegido. Ingresa la contraseña para continuar.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfInvalidPassword" xml:space="preserve">
|
||||||
|
<value>La contraseña ingresada no pudo desbloquear el PDF.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfNoBarcodeFound" xml:space="preserve">
|
||||||
|
<value>No encontramos una línea digitada en este PDF.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPreviewTooLarge" xml:space="preserve">
|
||||||
|
<value>El contenido es demasiado grande para la vista previa. Descarga el resultado directamente.</value>
|
||||||
|
</data>
|
||||||
<!-- JPG to WebP Converter Resources -->
|
<!-- JPG to WebP Converter Resources -->
|
||||||
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
|
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
|
||||||
<value>Convertidor JPG ↔ WebP Online Gratis</value>
|
<value>Convertidor JPG ↔ WebP Online Gratis</value>
|
||||||
|
|||||||
@ -51,12 +51,21 @@
|
|||||||
<data name="ImageMenuTitle" xml:space="preserve">
|
<data name="ImageMenuTitle" xml:space="preserve">
|
||||||
<value>Imagen</value>
|
<value>Imagen</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DocumentMenuTitle" xml:space="preserve">
|
||||||
|
<value>Documentos</value>
|
||||||
|
</data>
|
||||||
<data name="CaseConverterTitle" xml:space="preserve">
|
<data name="CaseConverterTitle" xml:space="preserve">
|
||||||
<value>Convertidor de Mayúsculas/Minúsculas</value>
|
<value>Convertidor de Mayúsculas/Minúsculas</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="JpgToWebpTitle" xml:space="preserve">
|
<data name="JpgToWebpTitle" xml:space="preserve">
|
||||||
<value>JPG a WebP</value>
|
<value>JPG a WebP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PdfToTextTitle" xml:space="preserve">
|
||||||
|
<value>PDF a Texto/Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeTitle" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<data name="FooterText" xml:space="preserve">
|
<data name="FooterText" xml:space="preserve">
|
||||||
@ -113,12 +122,21 @@
|
|||||||
<data name="UrlImageConverters" xml:space="preserve">
|
<data name="UrlImageConverters" xml:space="preserve">
|
||||||
<value>convertidores-de-imagen</value>
|
<value>convertidores-de-imagen</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UrlDocumentConverters" xml:space="preserve">
|
||||||
|
<value>convertidores-de-documento</value>
|
||||||
|
</data>
|
||||||
<data name="UrlCaseConverter" xml:space="preserve">
|
<data name="UrlCaseConverter" xml:space="preserve">
|
||||||
<value>conversor-de-mayusculas-minusculas</value>
|
<value>conversor-de-mayusculas-minusculas</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UrlJpgToWebp" xml:space="preserve">
|
<data name="UrlJpgToWebp" xml:space="preserve">
|
||||||
<value>jpg-a-webp</value>
|
<value>jpg-a-webp</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UrlPdfToText" xml:space="preserve">
|
||||||
|
<value>pdf-a-texto</value>
|
||||||
|
</data>
|
||||||
|
<data name="UrlPdfBarcode" xml:space="preserve">
|
||||||
|
<value>linea-digitada-desde-pdf</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- New individual converter resources - Mexican Spanish -->
|
<!-- New individual converter resources - Mexican Spanish -->
|
||||||
<data name="AllConvertersTitle" xml:space="preserve">
|
<data name="AllConvertersTitle" xml:space="preserve">
|
||||||
@ -142,6 +160,18 @@
|
|||||||
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
|
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
|
||||||
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
|
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PdfToTextIndividualTitle" xml:space="preserve">
|
||||||
|
<value>Extraer texto de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfToTextIndividualDescription" xml:space="preserve">
|
||||||
|
<value>Transforma tus PDFs en texto simple o Markdown, incluso cuando requieren contraseña.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeIndividualTitle" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeIndividualDescription" xml:space="preserve">
|
||||||
|
<value>Obtén la línea digitada de boletos directamente desde el PDF, con soporte para archivos protegidos.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- HEIC converter menu item -->
|
<!-- HEIC converter menu item -->
|
||||||
<data name="HeicToJpgTitle" xml:space="preserve">
|
<data name="HeicToJpgTitle" xml:space="preserve">
|
||||||
@ -204,16 +234,167 @@
|
|||||||
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
|
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<!-- PDF to Text Converter Resources -->
|
||||||
|
<data name="PdfTextConverterPageTitle" xml:space="preserve">
|
||||||
|
<value>Extraer texto de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextConverterPageDescription" xml:space="preserve">
|
||||||
|
<value>Convierte tus PDFs en texto simple o Markdown con soporte para archivos protegidos con contraseña.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPlainTextTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Texto simple</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfMarkdownTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfFileInputLabel" xml:space="preserve">
|
||||||
|
<value>Seleccionar archivo PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordLabel" xml:space="preserve">
|
||||||
|
<value>Contraseña del PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordPlaceholder" xml:space="preserve">
|
||||||
|
<value>Ingresa la contraseña si el PDF está protegido</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordHint" xml:space="preserve">
|
||||||
|
<value>Si el PDF requiere contraseña de apertura, escríbela aquí. De lo contrario, deja el campo vacío.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExtractPlainTextButton" xml:space="preserve">
|
||||||
|
<value>Extraer y visualizar</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExtractMarkdownButton" xml:space="preserve">
|
||||||
|
<value>Extraer en Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadPlainTextButton" xml:space="preserve">
|
||||||
|
<value>Descargar texto</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadMarkdownButton" xml:space="preserve">
|
||||||
|
<value>Descargar Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextPreviewTitle" xml:space="preserve">
|
||||||
|
<value>Vista previa del contenido</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhatTitle" xml:space="preserve">
|
||||||
|
<value>¿Qué hace este conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhatContent" xml:space="preserve">
|
||||||
|
<value>Extrae el contenido textual del PDF y lo entrega como texto simple o Markdown, preservando cortes y secciones siempre que sea posible.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqHowTitle" xml:space="preserve">
|
||||||
|
<value>¿Cómo usar el conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqHowContent" xml:space="preserve">
|
||||||
|
<value>Selecciona el archivo PDF, ingresa la contraseña si es necesario y elige la pestaña deseada. Visualiza el resultado en línea o descarga el archivo.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhyTitle" xml:space="preserve">
|
||||||
|
<value>¿Por qué convertir PDF a texto o Markdown?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhyContent" xml:space="preserve">
|
||||||
|
<value>El texto simple permite ediciones rápidas, mientras que Markdown facilita reutilizar el contenido en blogs o documentación.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqSecurityTitle" xml:space="preserve">
|
||||||
|
<value>¿Es seguro subir mis PDFs?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqSecurityContent" xml:space="preserve">
|
||||||
|
<value>Sí. Procesamos los archivos siguiendo estrictas políticas de privacidad y los eliminamos tras la conversión.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqLimitsTitle" xml:space="preserve">
|
||||||
|
<value>¿Existen límites de tamaño?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqLimitsContent" xml:space="preserve">
|
||||||
|
<value>Para la vista previa recomendamos PDFs de hasta 10MB. Archivos mayores pueden descargarse directamente en texto o Markdown.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<!-- PDF Barcode Converter Resources -->
|
||||||
|
<data name="PdfBarcodeConverterPageTitle" xml:space="preserve">
|
||||||
|
<value>Extraer línea digitada de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeConverterPageDescription" xml:space="preserve">
|
||||||
|
<value>Detecta la línea digitada de boletos o facturas directamente desde el PDF, incluso si está protegido.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeDetectTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Ver línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeDownloadTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Descargar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFileInputLabel" xml:space="preserve">
|
||||||
|
<value>Seleccionar PDF del boleto</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodePasswordHint" xml:space="preserve">
|
||||||
|
<value>Si el PDF está protegido con contraseña, ingrésala para permitir la lectura.</value>
|
||||||
|
</data>
|
||||||
|
<data name="DetectBarcodeButton" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadBarcodeButton" xml:space="preserve">
|
||||||
|
<value>Descargar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodePreviewTitle" xml:space="preserve">
|
||||||
|
<value>Línea digitada detectada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhatTitle" xml:space="preserve">
|
||||||
|
<value>¿Qué es la línea digitada?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhatContent" xml:space="preserve">
|
||||||
|
<value>Es la secuencia numérica del código de barras del boleto, utilizada para realizar pagos en bancos y aplicaciones.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqHowTitle" xml:space="preserve">
|
||||||
|
<value>¿Cómo funciona el conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqHowContent" xml:space="preserve">
|
||||||
|
<value>Extrae el texto del PDF, identifica patrones de boletos (47 o 48 dígitos) y muestra la línea lista para copiar o descargar.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhyTitle" xml:space="preserve">
|
||||||
|
<value>¿Cuándo usar este recurso?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhyContent" xml:space="preserve">
|
||||||
|
<value>Ideal para boletos sin código de barras legible o cuando necesitas copiar la línea digitada para pagar en línea.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqSecurityTitle" xml:space="preserve">
|
||||||
|
<value>¿Mis datos están seguros?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqSecurityContent" xml:space="preserve">
|
||||||
|
<value>Sí. El PDF se procesa solo para extraer la línea digitada y se descarta inmediatamente después.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqLimitsTitle" xml:space="preserve">
|
||||||
|
<value>¿Existen limitaciones?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqLimitsContent" xml:space="preserve">
|
||||||
|
<value>Para mejores resultados utiliza PDFs con texto seleccionable. Boletos en formato de imagen pueden requerir una solución OCR externa.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- Error Messages -->
|
<!-- Error Messages -->
|
||||||
<data name="SelectFileError" xml:space="preserve">
|
<data name="SelectFileError" xml:space="preserve">
|
||||||
<value>Por favor, selecciona un archivo para convertir.</value>
|
<value>Por favor, selecciona un archivo para convertir.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CopyButtonLabel" xml:space="preserve">
|
||||||
|
<value>Copiar</value>
|
||||||
|
</data>
|
||||||
|
<data name="CopyButtonSuccess" xml:space="preserve">
|
||||||
|
<value>¡Copiado!</value>
|
||||||
|
</data>
|
||||||
<data name="InvalidHeicFileError" xml:space="preserve">
|
<data name="InvalidHeicFileError" xml:space="preserve">
|
||||||
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
|
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InvalidJpgFileError" xml:space="preserve">
|
<data name="InvalidJpgFileError" xml:space="preserve">
|
||||||
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
|
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="InvalidPdfFileError" xml:space="preserve">
|
||||||
|
<value>Archivo PDF inválido, dañado o con protecciones no compatibles.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordRequired" xml:space="preserve">
|
||||||
|
<value>Este PDF está protegido. Ingresa la contraseña para continuar.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfInvalidPassword" xml:space="preserve">
|
||||||
|
<value>La contraseña ingresada no pudo desbloquear el PDF.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfNoBarcodeFound" xml:space="preserve">
|
||||||
|
<value>No encontramos una línea digitada en este PDF.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPreviewTooLarge" xml:space="preserve">
|
||||||
|
<value>El contenido es demasiado grande para la vista previa. Descarga el resultado directamente.</value>
|
||||||
|
</data>
|
||||||
<!-- JPG to WebP Converter Resources -->
|
<!-- JPG to WebP Converter Resources -->
|
||||||
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
|
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
|
||||||
<value>Convertidor JPG ↔ WebP Online Gratis</value>
|
<value>Convertidor JPG ↔ WebP Online Gratis</value>
|
||||||
|
|||||||
@ -51,12 +51,21 @@
|
|||||||
<data name="ImageMenuTitle" xml:space="preserve">
|
<data name="ImageMenuTitle" xml:space="preserve">
|
||||||
<value>Imagen</value>
|
<value>Imagen</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DocumentMenuTitle" xml:space="preserve">
|
||||||
|
<value>Documentos</value>
|
||||||
|
</data>
|
||||||
<data name="CaseConverterTitle" xml:space="preserve">
|
<data name="CaseConverterTitle" xml:space="preserve">
|
||||||
<value>Convertidor de Mayúsculas/Minúsculas</value>
|
<value>Convertidor de Mayúsculas/Minúsculas</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="JpgToWebpTitle" xml:space="preserve">
|
<data name="JpgToWebpTitle" xml:space="preserve">
|
||||||
<value>JPG a WebP</value>
|
<value>JPG a WebP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PdfToTextTitle" xml:space="preserve">
|
||||||
|
<value>PDF a Texto/Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeTitle" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<data name="FooterText" xml:space="preserve">
|
<data name="FooterText" xml:space="preserve">
|
||||||
@ -113,12 +122,21 @@
|
|||||||
<data name="UrlImageConverters" xml:space="preserve">
|
<data name="UrlImageConverters" xml:space="preserve">
|
||||||
<value>convertidores-de-imagen</value>
|
<value>convertidores-de-imagen</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UrlDocumentConverters" xml:space="preserve">
|
||||||
|
<value>convertidores-de-documento</value>
|
||||||
|
</data>
|
||||||
<data name="UrlCaseConverter" xml:space="preserve">
|
<data name="UrlCaseConverter" xml:space="preserve">
|
||||||
<value>conversor-de-mayusculas-minusculas</value>
|
<value>conversor-de-mayusculas-minusculas</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UrlJpgToWebp" xml:space="preserve">
|
<data name="UrlJpgToWebp" xml:space="preserve">
|
||||||
<value>jpg-a-webp</value>
|
<value>jpg-a-webp</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UrlPdfToText" xml:space="preserve">
|
||||||
|
<value>pdf-a-texto</value>
|
||||||
|
</data>
|
||||||
|
<data name="UrlPdfBarcode" xml:space="preserve">
|
||||||
|
<value>linea-digitada-desde-pdf</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- New individual converter resources - Mexican Spanish -->
|
<!-- New individual converter resources - Mexican Spanish -->
|
||||||
<data name="AllConvertersTitle" xml:space="preserve">
|
<data name="AllConvertersTitle" xml:space="preserve">
|
||||||
@ -142,6 +160,18 @@
|
|||||||
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
|
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
|
||||||
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
|
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PdfToTextIndividualTitle" xml:space="preserve">
|
||||||
|
<value>Extraer texto de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfToTextIndividualDescription" xml:space="preserve">
|
||||||
|
<value>Transforma tus PDFs en texto simple o Markdown, incluso cuando requieren contraseña.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeIndividualTitle" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeIndividualDescription" xml:space="preserve">
|
||||||
|
<value>Obtén la línea digitada de boletos directamente desde el PDF, con soporte para archivos protegidos.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- HEIC converter menu item -->
|
<!-- HEIC converter menu item -->
|
||||||
<data name="HeicToJpgTitle" xml:space="preserve">
|
<data name="HeicToJpgTitle" xml:space="preserve">
|
||||||
@ -204,16 +234,167 @@
|
|||||||
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
|
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<!-- PDF to Text Converter Resources -->
|
||||||
|
<data name="PdfTextConverterPageTitle" xml:space="preserve">
|
||||||
|
<value>Extraer texto de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextConverterPageDescription" xml:space="preserve">
|
||||||
|
<value>Convierte tus PDFs en texto simple o Markdown con soporte para archivos protegidos con contraseña.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPlainTextTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Texto simple</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfMarkdownTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfFileInputLabel" xml:space="preserve">
|
||||||
|
<value>Seleccionar archivo PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordLabel" xml:space="preserve">
|
||||||
|
<value>Contraseña del PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordPlaceholder" xml:space="preserve">
|
||||||
|
<value>Ingresa la contraseña si el PDF está protegido</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordHint" xml:space="preserve">
|
||||||
|
<value>Si el PDF requiere contraseña de apertura, escríbela aquí. De lo contrario, deja el campo vacío.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExtractPlainTextButton" xml:space="preserve">
|
||||||
|
<value>Extraer y visualizar</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExtractMarkdownButton" xml:space="preserve">
|
||||||
|
<value>Extraer en Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadPlainTextButton" xml:space="preserve">
|
||||||
|
<value>Descargar texto</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadMarkdownButton" xml:space="preserve">
|
||||||
|
<value>Descargar Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextPreviewTitle" xml:space="preserve">
|
||||||
|
<value>Vista previa del contenido</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhatTitle" xml:space="preserve">
|
||||||
|
<value>¿Qué hace este conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhatContent" xml:space="preserve">
|
||||||
|
<value>Extrae el contenido textual del PDF y lo entrega como texto simple o Markdown, preservando cortes y secciones siempre que sea posible.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqHowTitle" xml:space="preserve">
|
||||||
|
<value>¿Cómo usar el conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqHowContent" xml:space="preserve">
|
||||||
|
<value>Selecciona el archivo PDF, ingresa la contraseña si es necesario y elige la pestaña deseada. Visualiza el resultado en línea o descarga el archivo.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhyTitle" xml:space="preserve">
|
||||||
|
<value>¿Por qué convertir PDF a texto o Markdown?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhyContent" xml:space="preserve">
|
||||||
|
<value>El texto simple permite ediciones rápidas, mientras que Markdown facilita reutilizar el contenido en blogs o documentación.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqSecurityTitle" xml:space="preserve">
|
||||||
|
<value>¿Es seguro subir mis PDFs?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqSecurityContent" xml:space="preserve">
|
||||||
|
<value>Sí. Procesamos los archivos siguiendo estrictas políticas de privacidad y los eliminamos tras la conversión.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqLimitsTitle" xml:space="preserve">
|
||||||
|
<value>¿Existen límites de tamaño?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqLimitsContent" xml:space="preserve">
|
||||||
|
<value>Para la vista previa recomendamos PDFs de hasta 10MB. Archivos mayores pueden descargarse directamente en texto o Markdown.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<!-- PDF Barcode Converter Resources -->
|
||||||
|
<data name="PdfBarcodeConverterPageTitle" xml:space="preserve">
|
||||||
|
<value>Extraer línea digitada de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeConverterPageDescription" xml:space="preserve">
|
||||||
|
<value>Detecta la línea digitada de boletos o facturas directamente desde el PDF, incluso si está protegido.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeDetectTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Ver línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeDownloadTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Descargar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFileInputLabel" xml:space="preserve">
|
||||||
|
<value>Seleccionar PDF del boleto</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodePasswordHint" xml:space="preserve">
|
||||||
|
<value>Si el PDF está protegido con contraseña, ingrésala para permitir la lectura.</value>
|
||||||
|
</data>
|
||||||
|
<data name="DetectBarcodeButton" xml:space="preserve">
|
||||||
|
<value>Detectar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadBarcodeButton" xml:space="preserve">
|
||||||
|
<value>Descargar línea digitada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodePreviewTitle" xml:space="preserve">
|
||||||
|
<value>Línea digitada detectada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhatTitle" xml:space="preserve">
|
||||||
|
<value>¿Qué es la línea digitada?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhatContent" xml:space="preserve">
|
||||||
|
<value>Es la secuencia numérica del código de barras del boleto, utilizada para realizar pagos en bancos y aplicaciones.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqHowTitle" xml:space="preserve">
|
||||||
|
<value>¿Cómo funciona el conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqHowContent" xml:space="preserve">
|
||||||
|
<value>Extrae el texto del PDF, identifica patrones de boletos (47 o 48 dígitos) y muestra la línea lista para copiar o descargar.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhyTitle" xml:space="preserve">
|
||||||
|
<value>¿Cuándo usar este recurso?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhyContent" xml:space="preserve">
|
||||||
|
<value>Ideal para boletos sin código de barras legible o cuando necesitas copiar la línea digitada para pagar en línea.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqSecurityTitle" xml:space="preserve">
|
||||||
|
<value>¿Mis datos están seguros?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqSecurityContent" xml:space="preserve">
|
||||||
|
<value>Sí. El PDF se procesa solo para extraer la línea digitada y se descarta inmediatamente después.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqLimitsTitle" xml:space="preserve">
|
||||||
|
<value>¿Existen limitaciones?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqLimitsContent" xml:space="preserve">
|
||||||
|
<value>Para mejores resultados utiliza PDFs con texto seleccionable. Boletos en formato de imagen pueden requerir una solución OCR externa.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- Error Messages -->
|
<!-- Error Messages -->
|
||||||
<data name="SelectFileError" xml:space="preserve">
|
<data name="SelectFileError" xml:space="preserve">
|
||||||
<value>Por favor, selecciona un archivo para convertir.</value>
|
<value>Por favor, selecciona un archivo para convertir.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CopyButtonLabel" xml:space="preserve">
|
||||||
|
<value>Copiar</value>
|
||||||
|
</data>
|
||||||
|
<data name="CopyButtonSuccess" xml:space="preserve">
|
||||||
|
<value>¡Copiado!</value>
|
||||||
|
</data>
|
||||||
<data name="InvalidHeicFileError" xml:space="preserve">
|
<data name="InvalidHeicFileError" xml:space="preserve">
|
||||||
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
|
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InvalidJpgFileError" xml:space="preserve">
|
<data name="InvalidJpgFileError" xml:space="preserve">
|
||||||
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
|
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="InvalidPdfFileError" xml:space="preserve">
|
||||||
|
<value>Archivo PDF inválido, dañado o con protecciones no compatibles.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordRequired" xml:space="preserve">
|
||||||
|
<value>Este PDF está protegido. Ingresa la contraseña para continuar.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfInvalidPassword" xml:space="preserve">
|
||||||
|
<value>La contraseña ingresada no pudo desbloquear el PDF.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfNoBarcodeFound" xml:space="preserve">
|
||||||
|
<value>No encontramos una línea digitada en este PDF.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPreviewTooLarge" xml:space="preserve">
|
||||||
|
<value>El contenido es demasiado grande para la vista previa. Descarga el resultado directamente.</value>
|
||||||
|
</data>
|
||||||
<!-- JPG to WebP Converter Resources -->
|
<!-- JPG to WebP Converter Resources -->
|
||||||
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
|
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
|
||||||
<value>Convertidor JPG ↔ WebP Online Gratis</value>
|
<value>Convertidor JPG ↔ WebP Online Gratis</value>
|
||||||
|
|||||||
@ -183,12 +183,21 @@
|
|||||||
<data name="ImageMenuTitle" xml:space="preserve">
|
<data name="ImageMenuTitle" xml:space="preserve">
|
||||||
<value>Imagem</value>
|
<value>Imagem</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DocumentMenuTitle" xml:space="preserve">
|
||||||
|
<value>Documentos</value>
|
||||||
|
</data>
|
||||||
<data name="CaseConverterTitle" xml:space="preserve">
|
<data name="CaseConverterTitle" xml:space="preserve">
|
||||||
<value>Conversor de Maiúsculas/Minúsculas</value>
|
<value>Conversor de Maiúsculas/Minúsculas</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="JpgToWebpTitle" xml:space="preserve">
|
<data name="JpgToWebpTitle" xml:space="preserve">
|
||||||
<value>JPG para WebP</value>
|
<value>JPG para WebP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PdfToTextTitle" xml:space="preserve">
|
||||||
|
<value>PDF para Texto/Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeTitle" xml:space="preserve">
|
||||||
|
<value>Extrair Linha Digitável</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- Footer Resources -->
|
<!-- Footer Resources -->
|
||||||
<data name="FooterText" xml:space="preserve">
|
<data name="FooterText" xml:space="preserve">
|
||||||
@ -211,12 +220,24 @@
|
|||||||
<data name="UrlImageConverters" xml:space="preserve">
|
<data name="UrlImageConverters" xml:space="preserve">
|
||||||
<value>conversores-de-imagem</value>
|
<value>conversores-de-imagem</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UrlDocumentConverters" xml:space="preserve">
|
||||||
|
<value>conversores-de-documento</value>
|
||||||
|
</data>
|
||||||
<data name="UrlCaseConverter" xml:space="preserve">
|
<data name="UrlCaseConverter" xml:space="preserve">
|
||||||
<value>conversor-de-maiusculas-minusculas</value>
|
<value>conversor-de-maiusculas-minusculas</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UrlJpgToWebp" xml:space="preserve">
|
<data name="UrlJpgToWebp" xml:space="preserve">
|
||||||
<value>jpg-para-webp</value>
|
<value>jpg-para-webp</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="UrlHeicToJpg" xml:space="preserve">
|
||||||
|
<value>heic-para-jpg</value>
|
||||||
|
</data>
|
||||||
|
<data name="UrlPdfToText" xml:space="preserve">
|
||||||
|
<value>pdf-para-texto</value>
|
||||||
|
</data>
|
||||||
|
<data name="UrlPdfBarcode" xml:space="preserve">
|
||||||
|
<value>linha-digitavel-do-pdf</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- FAQ Resources for Contact Page -->
|
<!-- FAQ Resources for Contact Page -->
|
||||||
<data name="Faq1Question" xml:space="preserve">
|
<data name="Faq1Question" xml:space="preserve">
|
||||||
@ -254,6 +275,18 @@
|
|||||||
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
|
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
|
||||||
<value>Converta fotos HEIC do iPhone para o formato JPG universalmente compatível.</value>
|
<value>Converta fotos HEIC do iPhone para o formato JPG universalmente compatível.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PdfToTextIndividualTitle" xml:space="preserve">
|
||||||
|
<value>Extrair Texto de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfToTextIndividualDescription" xml:space="preserve">
|
||||||
|
<value>Transforme PDFs protegidos ou não em texto simples ou Markdown em poucos segundos.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeIndividualTitle" xml:space="preserve">
|
||||||
|
<value>Detectar Linha Digitável</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeIndividualDescription" xml:space="preserve">
|
||||||
|
<value>Identifique a linha digitável de boletos diretamente do PDF, mesmo quando há proteção por senha.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- HEIC converter menu item -->
|
<!-- HEIC converter menu item -->
|
||||||
<data name="HeicToJpgTitle" xml:space="preserve">
|
<data name="HeicToJpgTitle" xml:space="preserve">
|
||||||
@ -316,6 +349,136 @@
|
|||||||
<value>Não há limites para a quantidade de conversões. Para garantir um bom desempenho, recomendamos arquivos de até 10MB. O processamento é mais rápido em computadores modernos.</value>
|
<value>Não há limites para a quantidade de conversões. Para garantir um bom desempenho, recomendamos arquivos de até 10MB. O processamento é mais rápido em computadores modernos.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<!-- PDF to Text Converter Resources -->
|
||||||
|
<data name="PdfTextConverterPageTitle" xml:space="preserve">
|
||||||
|
<value>Extrair Texto de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextConverterPageDescription" xml:space="preserve">
|
||||||
|
<value>Converta seus PDFs em texto simples ou Markdown, com suporte a arquivos protegidos por senha.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPlainTextTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Texto Simples</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfMarkdownTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfFileInputLabel" xml:space="preserve">
|
||||||
|
<value>Selecionar arquivo PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordLabel" xml:space="preserve">
|
||||||
|
<value>Senha do PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordPlaceholder" xml:space="preserve">
|
||||||
|
<value>Informe a senha, se o PDF estiver protegido</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordHint" xml:space="preserve">
|
||||||
|
<value>Se o PDF exigir senha de abertura, digite-a abaixo. Caso contrário, deixe em branco.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExtractPlainTextButton" xml:space="preserve">
|
||||||
|
<value>Extrair e Visualizar</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExtractMarkdownButton" xml:space="preserve">
|
||||||
|
<value>Extrair em Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadPlainTextButton" xml:space="preserve">
|
||||||
|
<value>Baixar Texto</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadMarkdownButton" xml:space="preserve">
|
||||||
|
<value>Baixar Markdown</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextPreviewTitle" xml:space="preserve">
|
||||||
|
<value>Pré-visualização do Conteúdo</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhatTitle" xml:space="preserve">
|
||||||
|
<value>O que faz este conversor PDF para Texto?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhatContent" xml:space="preserve">
|
||||||
|
<value>Ele extrai o conteúdo textual do seu PDF e o disponibiliza como texto simples ou Markdown, preservando quebras de linha e seções sempre que possível.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqHowTitle" xml:space="preserve">
|
||||||
|
<value>Como usar o conversor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqHowContent" xml:space="preserve">
|
||||||
|
<value>Selecione o arquivo PDF, informe a senha se necessário e escolha a aba desejada. Visualize o resultado online ou faça o download direto.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhyTitle" xml:space="preserve">
|
||||||
|
<value>Por que converter PDF para texto ou Markdown?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqWhyContent" xml:space="preserve">
|
||||||
|
<value>Texto simples facilita edições rápidas, enquanto Markdown permite reaproveitar o conteúdo em blogs, documentações e geradores de site estático.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqSecurityTitle" xml:space="preserve">
|
||||||
|
<value>É seguro enviar meus PDFs?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqSecurityContent" xml:space="preserve">
|
||||||
|
<value>Sim. O processamento ocorre seguindo políticas rígidas de privacidade e os arquivos são descartados após a conversão.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqLimitsTitle" xml:space="preserve">
|
||||||
|
<value>Existem limites de tamanho?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfTextFaqLimitsContent" xml:space="preserve">
|
||||||
|
<value>Para pré-visualização recomendamos PDFs de até 10MB. Conteúdos maiores podem ser baixados diretamente em texto ou Markdown.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<!-- PDF Barcode Converter Resources -->
|
||||||
|
<data name="PdfBarcodeConverterPageTitle" xml:space="preserve">
|
||||||
|
<value>Extrair Linha Digitável de PDF</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeConverterPageDescription" xml:space="preserve">
|
||||||
|
<value>Detecte a linha digitável de boletos ou faturas diretamente a partir do PDF, com suporte a arquivos protegidos.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeDetectTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Visualizar Linha Digitável</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeDownloadTabTitle" xml:space="preserve">
|
||||||
|
<value>PDF → Baixar Linha Digitável</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFileInputLabel" xml:space="preserve">
|
||||||
|
<value>Selecionar PDF do boleto</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodePasswordHint" xml:space="preserve">
|
||||||
|
<value>Caso o PDF esteja protegido por senha, informe-a abaixo para permitir a leitura.</value>
|
||||||
|
</data>
|
||||||
|
<data name="DetectBarcodeButton" xml:space="preserve">
|
||||||
|
<value>Detectar Linha Digitável</value>
|
||||||
|
</data>
|
||||||
|
<data name="DownloadBarcodeButton" xml:space="preserve">
|
||||||
|
<value>Baixar Linha Digitável</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodePreviewTitle" xml:space="preserve">
|
||||||
|
<value>Linha Digitável Detectada</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhatTitle" xml:space="preserve">
|
||||||
|
<value>O que é a linha digitável?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhatContent" xml:space="preserve">
|
||||||
|
<value>É a sequência numérica que representa o código de barras de boletos e faturas, usada para pagamentos em bancos e aplicativos.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqHowTitle" xml:space="preserve">
|
||||||
|
<value>Como o conversor funciona?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqHowContent" xml:space="preserve">
|
||||||
|
<value>O sistema extrai o texto do PDF, identifica padrões numéricos de boletos (47 ou 48 dígitos) e exibe a linha digitável pronta para copiar ou baixar.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhyTitle" xml:space="preserve">
|
||||||
|
<value>Quando usar este recurso?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqWhyContent" xml:space="preserve">
|
||||||
|
<value>Ideal para boletos sem código de barras legível ou quando você precisa copiar a linha digitável para pagamento online rapidamente.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqSecurityTitle" xml:space="preserve">
|
||||||
|
<value>Meus dados ficam seguros?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqSecurityContent" xml:space="preserve">
|
||||||
|
<value>Sim. O PDF é processado apenas para extrair a linha digitável e o conteúdo é descartado logo após a operação.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqLimitsTitle" xml:space="preserve">
|
||||||
|
<value>Existe algum limite?</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfBarcodeFaqLimitsContent" xml:space="preserve">
|
||||||
|
<value>Para melhores resultados, utilize PDFs com texto selecionável. Boletos apenas com imagem podem exigir uma solução OCR externa.</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- JPG to WebP Converter Resources -->
|
<!-- JPG to WebP Converter Resources -->
|
||||||
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
|
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
|
||||||
<value>Conversor JPG ↔ WebP Online Grátis</value>
|
<value>Conversor JPG ↔ WebP Online Grátis</value>
|
||||||
@ -370,6 +533,12 @@
|
|||||||
<data name="UseConverterButton" xml:space="preserve">
|
<data name="UseConverterButton" xml:space="preserve">
|
||||||
<value>Acessar Conversor</value>
|
<value>Acessar Conversor</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CopyButtonLabel" xml:space="preserve">
|
||||||
|
<value>Copiar</value>
|
||||||
|
</data>
|
||||||
|
<data name="CopyButtonSuccess" xml:space="preserve">
|
||||||
|
<value>Copiado!</value>
|
||||||
|
</data>
|
||||||
|
|
||||||
<!-- Error Messages -->
|
<!-- Error Messages -->
|
||||||
<data name="SelectFileError" xml:space="preserve">
|
<data name="SelectFileError" xml:space="preserve">
|
||||||
@ -384,6 +553,21 @@
|
|||||||
<data name="JpgToHeicNotAvailableError" xml:space="preserve">
|
<data name="JpgToHeicNotAvailableError" xml:space="preserve">
|
||||||
<value>A conversão de JPG para HEIC ainda não está disponível. Esta funcionalidade será implementada em breve.</value>
|
<value>A conversão de JPG para HEIC ainda não está disponível. Esta funcionalidade será implementada em breve.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="InvalidPdfFileError" xml:space="preserve">
|
||||||
|
<value>Arquivo PDF inválido, corrompido ou protegido por recursos não suportados.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPasswordRequired" xml:space="preserve">
|
||||||
|
<value>Este PDF está protegido. Informe a senha para continuar.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfInvalidPassword" xml:space="preserve">
|
||||||
|
<value>A senha informada não conseguiu desbloquear o PDF.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfNoBarcodeFound" xml:space="preserve">
|
||||||
|
<value>Não encontramos uma linha digitável neste PDF.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PdfPreviewTooLarge" xml:space="preserve">
|
||||||
|
<value>O conteúdo é muito grande para pré-visualização. Faça o download direto.</value>
|
||||||
|
</data>
|
||||||
<data name="ProcessingError" xml:space="preserve">
|
<data name="ProcessingError" xml:space="preserve">
|
||||||
<value>Ocorreu um erro ao processar sua solicitação. Tente novamente mais tarde.</value>
|
<value>Ocorreu um erro ao processar sua solicitação. Tente novamente mais tarde.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
@using Microsoft.AspNetCore.Localization
|
@using Microsoft.AspNetCore.Localization
|
||||||
@using Microsoft.Extensions.Options
|
@using Microsoft.Extensions.Options
|
||||||
|
@using Microsoft.Extensions.Configuration
|
||||||
|
|
||||||
@inject IOptions<RequestLocalizationOptions> LocOptions
|
@inject IOptions<RequestLocalizationOptions> LocOptions
|
||||||
|
@inject IConfiguration Configuration
|
||||||
|
|
||||||
@{
|
@{
|
||||||
var requestCulture = Context.Features.Get<IRequestCultureFeature>();
|
var requestCulture = Context.Features.Get<IRequestCultureFeature>();
|
||||||
var supportedCultures = LocOptions.Value.SupportedCultures;
|
var supportedCultures = LocOptions.Value.SupportedCultures;
|
||||||
|
|
||||||
|
// Configuração de Ads
|
||||||
|
var adSection = Configuration.GetSection("Ads");
|
||||||
|
var adEnabled = adSection.GetValue<bool>("Enabled");
|
||||||
|
var adProvider = adSection.GetValue<string>("Provider"); // "House" ou "Google"
|
||||||
|
var googlePublisherId = adSection.GetValue<string>("GooglePublisherId");
|
||||||
|
var slotTop = adSection.GetValue<string>("Slots:Top");
|
||||||
|
var slotSide = adSection.GetValue<string>("Slots:Side");
|
||||||
}
|
}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -13,11 +23,18 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="description" content="@(ViewBag.MetaDescription ?? ViewBag.PageDescription ?? ViewBag.Subtitle ?? ViewBag.PageTitle ?? "Convert-It Online")" />
|
||||||
<title>@ViewData["Title"] - Convert-It Online</title>
|
<title>@ViewData["Title"] - Convert-It Online</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" />
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" />
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||||
<link rel="stylesheet" href="~/css/site.css" />
|
<link rel="stylesheet" href="~/css/site.css" />
|
||||||
|
|
||||||
|
@if (adEnabled && adProvider == "Google" && !string.IsNullOrEmpty(googlePublisherId))
|
||||||
|
{
|
||||||
|
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=@googlePublisherId"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
@ -42,6 +59,19 @@
|
|||||||
</a></li>
|
</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item dropdown mx-2">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" id="documentToolsDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<i class="bi bi-file-earmark-text me-1"></i>@ViewBag.DocumentMenuTitle
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="documentToolsDropdown">
|
||||||
|
<li><a class="dropdown-item" href="@Html.LocalizedUrl("DocumentConverters", "PdfToText")">
|
||||||
|
<i class="bi bi-file-text me-2"></i>@ViewBag.PdfToTextTitle
|
||||||
|
</a></li>
|
||||||
|
<li><a class="dropdown-item" href="@Html.LocalizedUrl("DocumentConverters", "PdfBarcodeLine")">
|
||||||
|
<i class="bi bi-upc-scan me-2"></i>@ViewBag.PdfBarcodeTitle
|
||||||
|
</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
<li class="nav-item dropdown mx-2">
|
<li class="nav-item dropdown mx-2">
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="imageToolsDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" id="imageToolsDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<i class="bi bi-image-alt me-1"></i>@ViewBag.ImageMenuTitle
|
<i class="bi bi-image-alt me-1"></i>@ViewBag.ImageMenuTitle
|
||||||
@ -84,17 +114,98 @@
|
|||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
<div class="ad-placeholder ad-top d-none d-lg-flex">
|
<!-- AD TOP -->
|
||||||
<span>Ad Placeholder (Top)</span>
|
@if (adEnabled)
|
||||||
|
{
|
||||||
|
@if (adProvider == "House")
|
||||||
|
{
|
||||||
|
<a href="https://qrrapido.site" target="_blank" class="house-ad-top text-decoration-none d-none d-lg-block">
|
||||||
|
<div class="ad-content">
|
||||||
|
<div class="qr-animation">
|
||||||
|
<div class="qr-box"></div>
|
||||||
|
<div class="scan-line"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ad-text">
|
||||||
|
<span class="badge bg-warning text-dark mb-1">NOVO</span>
|
||||||
|
<h5>Gerador de QR Code Ultrarrápido</h5>
|
||||||
|
<p>Crie QR Codes para WiFi, Links e Pix em 1 segundo. Grátis!</p>
|
||||||
|
</div>
|
||||||
|
<div class="cta-button">
|
||||||
|
Criar Agora <i class="bi bi-arrow-right"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
else if (adProvider == "Google" && !string.IsNullOrEmpty(slotTop))
|
||||||
|
{
|
||||||
|
<div class="d-none d-lg-block mb-4" style="min-height: 90px; text-align:center;">
|
||||||
|
<!-- Topo -->
|
||||||
|
<ins class="adsbygoogle"
|
||||||
|
style="display:block"
|
||||||
|
data-ad-client="@googlePublisherId"
|
||||||
|
data-ad-slot="@slotTop"
|
||||||
|
data-ad-format="auto"
|
||||||
|
data-full-width-responsive="true"></ins>
|
||||||
|
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<!-- Placeholder visível apenas se não houver ad configurado e estiver em debug/dev se desejado -->
|
||||||
|
<!-- <div class="ad-placeholder ad-top d-none d-lg-flex"><span>Ad Space</span></div> -->
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
<main role="main" class="pb-3">
|
<main role="main" class="pb-3">
|
||||||
@RenderBody()
|
@RenderBody()
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 d-none d-lg-block">
|
<div class="col-lg-3 d-none d-lg-block">
|
||||||
<div class="ad-placeholder ad-side">
|
<!-- AD SIDE -->
|
||||||
<span>Ad Placeholder (Side)</span>
|
@if (adEnabled)
|
||||||
|
{
|
||||||
|
@if (adProvider == "House")
|
||||||
|
{
|
||||||
|
<a href="https://jobmaker.com.br" target="_blank" class="house-ad-side text-decoration-none">
|
||||||
|
<div class="terminal-header">
|
||||||
|
<span class="dot red"></span><span class="dot yellow"></span><span class="dot green"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ad-body">
|
||||||
|
<div class="code-typing">
|
||||||
|
<span class="comment">// Precisa integrar sistemas?</span><br>
|
||||||
|
<span class="keyword">await</span> JobMaker.<span class="method">Automate</span>(legacy_sys);<br>
|
||||||
|
<span class="success">>> Processo Otimizado!</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4">
|
||||||
|
<h5>Especialistas em .NET e Integrações</h5>
|
||||||
|
<ul class="list-unstyled text-small text-muted mt-2">
|
||||||
|
<li><i class="bi bi-check2"></i> APIs & Microserviços</li>
|
||||||
|
<li><i class="bi bi-check2"></i> Robôs de Dados</li>
|
||||||
|
<li><i class="bi bi-check2"></i> Modernização de Legado</li>
|
||||||
|
</ul>
|
||||||
|
<button class="btn btn-outline-primary btn-sm w-100 mt-3">Fale Conosco</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
else if (adProvider == "Google" && !string.IsNullOrEmpty(slotSide))
|
||||||
|
{
|
||||||
|
<div class="mt-4 sticky-top" style="top: 2rem; min-height: 600px;">
|
||||||
|
<!-- Lateral -->
|
||||||
|
<ins class="adsbygoogle"
|
||||||
|
style="display:block"
|
||||||
|
data-ad-client="@googlePublisherId"
|
||||||
|
data-ad-slot="@slotSide"
|
||||||
|
data-ad-format="auto"
|
||||||
|
data-full-width-responsive="true"></ins>
|
||||||
|
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<!-- <div class="ad-placeholder ad-side"><span>Ad Space</span></div> -->
|
||||||
|
}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,5 +9,14 @@
|
|||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"Serilog": {
|
"Serilog": {
|
||||||
"OpenSearchUrl": ""
|
"OpenSearchUrl": ""
|
||||||
|
},
|
||||||
|
"Ads": {
|
||||||
|
"Enabled": true,
|
||||||
|
"Provider": "House",
|
||||||
|
"GooglePublisherId": "pub-3475956393038764",
|
||||||
|
"Slots": {
|
||||||
|
"Top": "0000000000",
|
||||||
|
"Side": "0000000000"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -431,3 +431,190 @@ h1, h2, h3, h4, h5, h6, p, div, span, a {
|
|||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--text-muted);
|
background: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========== HOUSE ADS (BANNERS PRÓPRIOS) ========== */
|
||||||
|
|
||||||
|
/* Banner Topo - QR Rápido */
|
||||||
|
.house-ad-top {
|
||||||
|
display: block;
|
||||||
|
background: linear-gradient(135deg, #6610f2 0%, #d63384 100%);
|
||||||
|
border-radius: 1rem;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
color: white !important;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
border: none;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 20px rgba(102, 16, 242, 0.3);
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top .ad-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
z-index: 2;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top .qr-animation {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 8px;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top .qr-box {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border: 3px solid white;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top .qr-box::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top .scan-line {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: #00ff00;
|
||||||
|
top: 10%;
|
||||||
|
left: 0;
|
||||||
|
animation: scanMove 1.5s infinite alternate ease-in-out;
|
||||||
|
box-shadow: 0 0 4px #00ff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scanMove {
|
||||||
|
0% { top: 10%; }
|
||||||
|
100% { top: 90%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top .ad-text h5 {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top .ad-text p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-top .cta-button {
|
||||||
|
background: white;
|
||||||
|
color: #6610f2;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Banner Lateral - JobMaker */
|
||||||
|
.house-ad-side {
|
||||||
|
display: block;
|
||||||
|
background-color: #0f172a; /* Slate 900 */
|
||||||
|
border-radius: 1rem;
|
||||||
|
border: 1px solid #1e293b;
|
||||||
|
color: #e2e8f0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
position: sticky;
|
||||||
|
top: 2rem;
|
||||||
|
text-decoration: none !important;
|
||||||
|
transition: border-color 0.3s ease;
|
||||||
|
min-height: auto; /* Remove min-height fixo se necessário */
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side:hover {
|
||||||
|
border-color: #3b82f6;
|
||||||
|
color: #e2e8f0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side .terminal-header {
|
||||||
|
background: #1e293b;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
border-bottom: 1px solid #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side .dot {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side .dot.red { background: #ef4444; }
|
||||||
|
.house-ad-side .dot.yellow { background: #f59e0b; }
|
||||||
|
.house-ad-side .dot.green { background: #22c55e; }
|
||||||
|
|
||||||
|
.house-ad-side .ad-body {
|
||||||
|
padding: 1.5rem;
|
||||||
|
font-family: 'Consolas', 'Monaco', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side .code-typing {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side .comment { color: #64748b; }
|
||||||
|
.house-ad-side .keyword { color: #c084fc; }
|
||||||
|
.house-ad-side .method { color: #60a5fa; }
|
||||||
|
.house-ad-side .success { color: #4ade80; display: block; margin-top: 0.5rem; font-weight: bold;}
|
||||||
|
|
||||||
|
.house-ad-side h5 {
|
||||||
|
font-family: system-ui, -apple-system, sans-serif;
|
||||||
|
color: white !important;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side .text-muted {
|
||||||
|
color: #94a3b8 !important; /* Slate 400 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side .btn-outline-primary {
|
||||||
|
border-color: #3b82f6;
|
||||||
|
color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.house-ad-side .btn-outline-primary:hover {
|
||||||
|
background-color: #3b82f6;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsividade para o House Ad Top */
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.house-ad-top {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user