Files
TSpdfUtils/tsPDFUtilsCore/Utilidades.cs
2026-05-27 17:48:50 +02:00

159 lines
5.3 KiB
C#

using System.IO;
using TSpdf.Kernel.Pdf;
using TSpdf.Kernel.Utils;
using TSpdf.Pdfa;
namespace tsPDFUtilsCore
{
public class Utilidades
{
public static MemoryStream crearPDFA(Stream pdfOrigen)
{
var reader = new PdfReader(pdfOrigen);
MemoryStream ms = new MemoryStream();
var writerProps = new WriterProperties();
writerProps.SetPdfVersion(PdfVersion.PDF_2_0);
writerProps.UseSmartMode();
var writer = new PdfWriter(ms, writerProps);
writer.SetSmartMode(true);
// Necesario para que el memoryStream no se cierre, y no de una execpción donde se llame a la función
writer.SetCloseStream(false);
var sourcePDF = new PdfDocument(reader);
bool esRGB = recorrerPaginas(sourcePDF);
// Se recorre las páginas para comprobar que no falte la anotación F, en tal caso la mete
for (int page = 1; page <= sourcePDF.GetNumberOfPages(); page++)
{
var paginaActual = sourcePDF.GetPage(page);
var anotaciones = paginaActual.GetAnnotations();
if (anotaciones != null)
{
foreach (var anotacionActual in anotaciones)
{
var diccionario = anotacionActual.GetPdfObject();
if (!diccionario.ContainsKey(PdfName.F))
{
diccionario.Put(PdfName.F, new PdfNumber(4));
}
}
}
}
PdfADocument disPDF;
if (esRGB)
{
disPDF = new PdfADocument(writer, PdfAConformanceLevel.PDF_A_3B, new PdfOutputIntent("Custom"
, "", "https://www.color.org", "sRGB", new MemoryStream(Properties.Resources.sRGB2014)));
}
else
{
disPDF = new PdfADocument(writer, PdfAConformanceLevel.PDF_A_3B, new PdfOutputIntent("Custom"
, "", "https://www.color.org", "FOGRA39", new MemoryStream(Properties.Resources.fogra39L)));
}
disPDF.InitializeOutlines();
// Configurar parámetros requeridos
disPDF.SetTagged();
disPDF.GetCatalog().SetLang(new PdfString("es-ES"));
disPDF.GetCatalog().SetViewerPreferences(new PdfViewerPreferences().SetDisplayDocTitle(true));
var merger = new PdfMerger(disPDF, true,true);
merger.Merge(sourcePDF, 1, sourcePDF.GetNumberOfPages());
sourcePDF.Close();
disPDF.Close();
reader.Close();
writer.Close();
// Esto hace falta para volver al inicio del memorystream
ms.Position = 0;
return ms;
}
static bool controlarInterpolate(PdfDictionary resources, bool tieneRGB)
{
var xObjects = resources?.GetAsDictionary(PdfName.XObject);
bool tieneRGBActual = tieneRGB;
foreach (var key in xObjects.KeySet())
{
var stream = xObjects.GetAsStream(key);
// se mira que tenga el prefijo subtype qye es la forma como el pdf pone las imagenes y los formularios -> /Subtype /Image ó /Subtype /Form
var subtype = stream.GetAsName(PdfName.Subtype);
// En caso de que sea una imagen, pone el interpolate a false, que es lo que causaba el fallo en alguno de los pdfs
if (PdfName.Image.Equals(subtype))
{
if (stream.GetAsBoolean(PdfName.Interpolate)?.GetValue() == true)
{
stream.Put(PdfName.Interpolate, PdfBoolean.FALSE);
}
// Detectar RGB
var colorSpace = stream.Get(PdfName.ColorSpace);
if (colorSpace != null && colorSpace.Equals(PdfName.DeviceRGB))
{
tieneRGBActual = true;
tieneRGB = true;
}
}
// En caso de que sea un formulario, vuelve a llamar al metodo para buscar imagenes dentro
else if (PdfName.Form.Equals(subtype))
{
var formRes = stream.GetAsDictionary(PdfName.Resources);
if (formRes != null)
{
bool hijoTieneRGB = controlarInterpolate(formRes, tieneRGBActual);
if (hijoTieneRGB)
{
tieneRGBActual = true;
}
}
}
}
return tieneRGBActual;
}
static bool recorrerPaginas(PdfDocument pdf)
{
bool tieneRGB = false;
for (int i = 1; i <= pdf.GetNumberOfPages(); i++)
{
bool rgbMinimo = false;
var diccPaginaActual = pdf.GetPage(i).GetResources().GetPdfObject();
rgbMinimo = controlarInterpolate(diccPaginaActual, tieneRGB);
if (rgbMinimo)
{
tieneRGB = true;
}
}
return tieneRGB;
}
}
}