160 lines
7.1 KiB
C#
160 lines
7.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using PdfSharpCore.Drawing;
|
|
using PdfSharpCore.Pdf;
|
|
using PdfSharpCore.Pdf.IO;
|
|
|
|
namespace GestionaDenuncias.Shared.Helpers
|
|
{
|
|
public static class PdfHelper
|
|
{
|
|
/// <summary>
|
|
/// Fusiona varios ficheros (PDF, imágenes, TXT) en un único PDF.
|
|
/// Los .txt se renderizan con márgenes iguales, alineación a la izquierda y ajuste de líneas,
|
|
/// preservando líneas en blanco.
|
|
/// </summary>
|
|
/// <param name="files">Secuencia de tuplas (FileName, ContentBytes)</param>
|
|
/// <returns>Bytes del PDF combinado</returns>
|
|
public static byte[] MergeFilesToPdf(IEnumerable<(string FileName, byte[] Content)> files)
|
|
{
|
|
if (files == null) throw new ArgumentNullException(nameof(files));
|
|
|
|
var outputDoc = new PdfDocument();
|
|
|
|
foreach (var (fileName, content) in files)
|
|
{
|
|
if (string.IsNullOrEmpty(fileName) || content == null || content.Length == 0)
|
|
throw new InvalidOperationException($"El archivo '{fileName}' no tiene contenido.");
|
|
|
|
var ext = Path.GetExtension(fileName).ToLowerInvariant();
|
|
switch (ext)
|
|
{
|
|
case ".pdf":
|
|
using (var src = PdfReader.Open(new MemoryStream(content), PdfDocumentOpenMode.Import))
|
|
foreach (var page in src.Pages)
|
|
outputDoc.AddPage(page);
|
|
break;
|
|
|
|
case ".jpg":
|
|
case ".jpeg":
|
|
case ".png":
|
|
case ".gif":
|
|
using (var img = XImage.FromStream(() => new MemoryStream(content)))
|
|
{
|
|
var page = outputDoc.AddPage();
|
|
page.Width = XUnit.FromPoint(img.PointWidth);
|
|
page.Height = XUnit.FromPoint(img.PointHeight);
|
|
using var gfxImg = XGraphics.FromPdfPage(page);
|
|
gfxImg.DrawImage(img, 0, 0, page.Width, page.Height);
|
|
}
|
|
break;
|
|
|
|
case ".txt":
|
|
// Renderizado de TXT con margen y ajuste de líneas, preservando líneas en blanco
|
|
var text = Encoding.UTF8.GetString(content);
|
|
PdfPage pageTxt = outputDoc.AddPage();
|
|
XGraphics gfxTxt = XGraphics.FromPdfPage(pageTxt);
|
|
|
|
const double marginLeft = 40;
|
|
const double marginRight = 40;
|
|
const double marginTop = 40;
|
|
const double marginBottom = 40;
|
|
var font = new XFont("Courier New", 10, XFontStyle.Regular);
|
|
var sample = gfxTxt.MeasureString("Ay", font);
|
|
var lineHeight = sample.Height * 1.2;
|
|
|
|
double y = marginTop;
|
|
double pageWidth = pageTxt.Width.Point;
|
|
double pageHeight = pageTxt.Height.Point;
|
|
double maxWidth = pageWidth - marginLeft - marginRight;
|
|
|
|
foreach (var origLine in text.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n'))
|
|
{
|
|
// Línea en blanco: preservarla
|
|
if (string.IsNullOrWhiteSpace(origLine))
|
|
{
|
|
y += lineHeight;
|
|
if (y + lineHeight > pageHeight - marginBottom)
|
|
{
|
|
gfxTxt.Dispose();
|
|
pageTxt = outputDoc.AddPage();
|
|
gfxTxt = XGraphics.FromPdfPage(pageTxt);
|
|
y = marginTop;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
var words = origLine.Split(' ');
|
|
string currentLine = string.Empty;
|
|
|
|
foreach (var word in words)
|
|
{
|
|
var testLine = string.IsNullOrEmpty(currentLine) ? word : currentLine + " " + word;
|
|
var size = gfxTxt.MeasureString(testLine, font);
|
|
if (size.Width <= maxWidth)
|
|
{
|
|
currentLine = testLine;
|
|
}
|
|
else
|
|
{
|
|
// Dibujar la línea acumulada
|
|
gfxTxt.DrawString(
|
|
currentLine,
|
|
font,
|
|
XBrushes.Black,
|
|
new XRect(marginLeft, y, maxWidth, lineHeight),
|
|
XStringFormats.TopLeft);
|
|
y += lineHeight;
|
|
currentLine = word;
|
|
|
|
// Paginación si se sale por abajo
|
|
if (y + lineHeight > pageHeight - marginBottom)
|
|
{
|
|
gfxTxt.Dispose();
|
|
pageTxt = outputDoc.AddPage();
|
|
gfxTxt = XGraphics.FromPdfPage(pageTxt);
|
|
y = marginTop;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dibujar la última línea del párrafo
|
|
if (!string.IsNullOrEmpty(currentLine))
|
|
{
|
|
gfxTxt.DrawString(
|
|
currentLine,
|
|
font,
|
|
XBrushes.Black,
|
|
new XRect(marginLeft, y, maxWidth, lineHeight),
|
|
XStringFormats.TopLeft);
|
|
y += lineHeight;
|
|
|
|
if (y + lineHeight > pageHeight - marginBottom)
|
|
{
|
|
gfxTxt.Dispose();
|
|
pageTxt = outputDoc.AddPage();
|
|
gfxTxt = XGraphics.FromPdfPage(pageTxt);
|
|
y = marginTop;
|
|
}
|
|
}
|
|
}
|
|
|
|
gfxTxt.Dispose();
|
|
break;
|
|
|
|
default:
|
|
throw new NotSupportedException($"Extensión no soportada: {ext}");
|
|
}
|
|
}
|
|
|
|
using var ms = new MemoryStream();
|
|
outputDoc.Save(ms);
|
|
return ms.ToArray();
|
|
}
|
|
|
|
|
|
|
|
}
|
|
} |