Agregar archivos de proyecto.

This commit is contained in:
2026-05-27 17:48:50 +02:00
commit 905514c2a9
34 changed files with 8253 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace tsPDFUtilsCore
{
public class DatosFuente
{
public string NombreFuente;
public byte[] memoryFont;
}
}

View File

@@ -0,0 +1,18 @@

using static tsPDFUtilsCore.Enums;
namespace tsPDFUtilsCore
{
public class DatosImagenFirma
{
public EsquinaEnum PosicionEsquina;
public int Ancho;
public int Alto;
public int PosicionX;
public int PosicionY;
public byte[] Imagen;
public int AnguloRotacion;
}
}

View File

@@ -0,0 +1,23 @@
using System.Drawing;
using static tsPDFUtilsCore.Enums;
namespace tsPDFUtilsCore
{
public class DatosTextos
{
public string NombreFuente;
public EsquinaEnum PosicionEsquina;
public AlineamientoEnum AlineacionTexto;
public float size;
public float anguloRotacion;
public string texto;
public int distanciaX;
public int distanciaY;
public Brush colorTexto;
public FontStyle estiloTexto;
}
}

45
tsPDFUtilsCore/Enums.cs Normal file
View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace tsPDFUtilsCore
{
public class Enums
{
public enum EsquinaEnum : int
{
INFERIOR_IZQUIERDA = 0,
INFERIOR_DERECHA = 1,
SUPERIOR_IZQUIERDA = 2,
SUPERIOR_DERECHA = 3
}
public enum AlineamientoEnum : int
{
IZQUIERDA = 0,
DERECHA = 1,
CENTRO = 2,
JUSTIFICADO = 3
}
public enum FuenteEnum
{
COURIER,
COURIER_BOLD,
COURIER_BOLDOBLIQUE,
COURIER_OBLIQUE,
HELVETICA,
HELVETICA_BOLD,
HELVETICA_BOLDOBLIQUE,
HELVETICA_OBLIQUE,
SYMBOL,
TIMES_ROMAN,
TIMES_BOLD,
TIMES_BOLDITALIC,
TIMES_ITALIC,
ZAPFDINGBATS
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace tsPDFUtilsCore
{
public class ImagenEnPdf
{
public byte[] Imagen { get; set; }
public EsquinaEnum EsquinaReferencia { get; set; }
public double Transparencia { get; set; } = 1;
public float CoordenadaX { get; set; }
public float CoordenadaY { get; set; }
public float EscalaVertical { get; set; }
public float EscalaHorizontal { get; set; }
public float AnguloRotacion { get; set; }
public int PaginaInicio { get; set; }
public int PaginaFin { get; set; }
}
}

580
tsPDFUtilsCore/Imagenes.cs Normal file
View File

@@ -0,0 +1,580 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using TSpdf.Kernel.Font;
using TSpdf.IO.Font.Constants;
using static tsPDFUtilsCore.Imagenes;
using static tsPDFUtilsCore.Enums;
namespace tsPDFUtilsCore
{
public class Imagenes
{
public static Bitmap RedimensionaImagen(Bitmap Original, int NuevoAlto, int NuevoAncho, int CoordenadaX, int CoordenadaY)
{
Bitmap newImage = new Bitmap(NuevoAncho, NuevoAlto);
using (Graphics g = Graphics.FromImage(newImage))
{
g.Clear(Color.Transparent);
g.DrawImage(Original, CoordenadaX, CoordenadaY, Original.Width, Original.Height);
}
return newImage;
}
public static Bitmap crearBitMapFirmas(List<DatosTextos> listadoTextos, List<DatosImagenFirma> listadoImagenes, List<DatosFuente> ListadoFuentes, TSpdf.Kernel.Geom.Rectangle medidas)
{
int dpi = 600;
int anchoPixeles = (int)medidas.GetWidth() * dpi / 72;
int altoPixeles = (int)medidas.GetHeight() * dpi / 72;
Bitmap bmp = new Bitmap(anchoPixeles, altoPixeles, PixelFormat.Format32bppArgb);
bmp.SetResolution(dpi, dpi);
Graphics g = Graphics.FromImage(bmp);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.Clear(Color.Transparent);
// Dibujar textos
foreach (var texto in listadoTextos)
{
Font font = null;
if (FontFamily.Families.Any(x => x.Name == texto.NombreFuente))
font = new Font(FontFamily.Families.Where(x => x.Name == texto.NombreFuente).First(), texto.size, texto.estiloTexto, GraphicsUnit.Point);
else if (ListadoFuentes != null && ListadoFuentes.Any(x => x.NombreFuente == texto.NombreFuente))
{
var fuente = ListadoFuentes.Where(x => x.NombreFuente == texto.NombreFuente).First();
int dataLength = fuente.memoryFont.Length;
IntPtr ptrData = Marshal.AllocCoTaskMem(dataLength);
Marshal.Copy(fuente.memoryFont, 0, ptrData, dataLength);
PrivateFontCollection privateFontCollection = new PrivateFontCollection();
privateFontCollection.AddMemoryFont(ptrData, dataLength);
font = new Font(privateFontCollection.Families.FirstOrDefault(), texto.size, texto.estiloTexto, GraphicsUnit.Point);
}
else
throw new Exception("Fuente " + texto.NombreFuente + " no encontrada");
var sizeTexto = g.MeasureString(texto.texto, font);
var coordenadaX = calcularX(texto.distanciaX, texto.distanciaY, texto.PosicionEsquina, bmp, texto.anguloRotacion, (int)sizeTexto.Width, (int)sizeTexto.Height);
var coordenadaY = calcularY(texto.distanciaY, texto.distanciaX, texto.PosicionEsquina, bmp, texto.anguloRotacion, (int)sizeTexto.Width, (int)sizeTexto.Height);
PointF rotationPoint = new PointF(texto.distanciaX, texto.distanciaY);
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
StringFormat stringFormat = new StringFormat();
g.TranslateTransform(0, 0);
g.RotateTransform(texto.anguloRotacion);
if (texto.AlineacionTexto != AlineamientoEnum.JUSTIFICADO)
g.DrawString(texto.texto, font, texto.colorTexto, new PointF(coordenadaX, coordenadaY));
else
DrawJustifiedString(ref g, texto.texto, font, texto.colorTexto, new RectangleF(coordenadaX, coordenadaY, altoPixeles, sizeTexto.Height), stringFormat);
g.ResetTransform();
}
foreach (var imagen in listadoImagenes)
{
MemoryStream stream = new MemoryStream();
stream.Write(imagen.Imagen, 0, imagen.Imagen.Length);
System.Drawing.Image myImage = System.Drawing.Image.FromStream(stream);
g.TranslateTransform(0, 0);
g.RotateTransform(imagen.AnguloRotacion);
int coordenadaX = calcularX(imagen.PosicionX, imagen.PosicionY, imagen.PosicionEsquina, bmp, imagen.AnguloRotacion, myImage.Width, myImage.Height);
int coordenadaY = calcularY(imagen.PosicionY, imagen.PosicionX, imagen.PosicionEsquina, bmp, imagen.AnguloRotacion, myImage.Width, myImage.Height);
if (altoPixeles > anchoPixeles)
g.DrawImage(myImage, new Rectangle(coordenadaX, coordenadaY, altoPixeles, anchoPixeles));
else
g.DrawImage(myImage, new Rectangle(coordenadaX, coordenadaY, anchoPixeles, altoPixeles));
g.ResetTransform();
}
return bmp;
}
public static byte[] BitMapAByteArray(Bitmap bmp)
{
MemoryStream msSalida = new MemoryStream();
bmp.Save(msSalida, ImageFormat.Png);
byte[] byteArray = msSalida.ToArray();
msSalida.Close();
return byteArray;
}
public static void DrawJustifiedString(ref Graphics g, string txt, Font font, Brush brush, RectangleF destination, StringFormat format)
{
using (StringFormat fmt = (StringFormat)format.Clone())
{
fmt.FormatFlags = fmt.FormatFlags | StringFormatFlags.MeasureTrailingSpaces;
CharacterRange[] cr = { new CharacterRange(0, 1) };
fmt.SetMeasurableCharacterRanges(cr);
fmt.Alignment = StringAlignment.Center;
float txtWidth = g.MeasureString(txt, font, destination.Location, fmt).Width;
float spacing = (destination.Width - txtWidth) / (txt.Length - 1);
RectangleF dest = new RectangleF(destination.X, destination.Y, 0, destination.Height);
foreach (char c in txt.AsEnumerable())
{
// Graphics#MeasureString is too inaccurate for character placement
dest.Width = g.MeasureCharacterRanges(c.ToString(), font, destination, fmt)[0].GetBounds(g).Width;
g.DrawString(c.ToString(), font, brush, dest, fmt);
dest.X += dest.Width + spacing;
}
}
}
private static int calcularX(int coordenadaX, int coordenadaY, EsquinaEnum PosicionEsquina, Bitmap medidasFirma, float rotacionElemento, int anchoElemento, int altoElemento)
{
int anchoFirma = medidasFirma.Width;
int altoFirma = medidasFirma.Height;
int ejeX = 0;
switch (PosicionEsquina)
{
case EsquinaEnum.SUPERIOR_IZQUIERDA:
{
switch (rotacionElemento)
{
case 90:
{
ejeX = coordenadaY;
break;
}
case 180:
{
ejeX = -coordenadaX - anchoElemento;
break;
}
case 270:
{
ejeX = -coordenadaY - anchoElemento;
break;
}
default:
{
ejeX = coordenadaX;
break;
}
}
break;
}
case EsquinaEnum.INFERIOR_IZQUIERDA:
{
switch (rotacionElemento)
{
case 90:
{
ejeX = (altoFirma - (coordenadaY + anchoElemento));
break;
}
case 180:
{
ejeX = -coordenadaX - anchoElemento;
break;
}
case 270:
{
ejeX = coordenadaY - altoFirma;
break;
}
default:
{
ejeX = coordenadaX;
break;
}
}
break;
}
case EsquinaEnum.SUPERIOR_DERECHA:
{
switch (rotacionElemento)
{
case 90:
{
ejeX = coordenadaY;
break;
}
case 180:
{
ejeX = -anchoFirma + coordenadaX;
break;
}
case 270:
{
ejeX = -coordenadaY - anchoElemento;
break;
}
default:
{
ejeX = anchoFirma - (anchoElemento + coordenadaX);
break;
}
}
break;
}
case EsquinaEnum.INFERIOR_DERECHA:
{
switch (rotacionElemento)
{
case 90:
{
ejeX = (altoFirma - (coordenadaY + anchoElemento));
break;
}
case 180:
{
ejeX = -anchoFirma + coordenadaX;
break;
}
case 270:
{
ejeX = coordenadaY - altoFirma;
break;
}
default:
{
ejeX = anchoFirma - (anchoElemento + coordenadaX);
break;
}
}
break;
}
}
return ejeX;
}
private static int calcularY(int coordenadaY, int coordenadaX, EsquinaEnum PosicionEsquina, Bitmap medidasFirma, float rotacionElemento, int anchoElemento, int altoElemento)
{
int anchoFirma = medidasFirma.Width;
int altoFirma = medidasFirma.Height;
int ejeY = 0;
switch (PosicionEsquina)
{
case EsquinaEnum.SUPERIOR_IZQUIERDA:
{
switch (rotacionElemento)
{
case 90:
{
ejeY = -coordenadaX - altoElemento;
break;
}
case 180:
{
ejeY = -coordenadaY - altoElemento;
break;
}
case 270:
{
ejeY = coordenadaX;
break;
}
default:
{
ejeY = coordenadaY;
break;
}
}
break;
}
case EsquinaEnum.INFERIOR_IZQUIERDA:
{
switch (rotacionElemento)
{
case 90:
{
ejeY = -coordenadaX - altoElemento;
break;
}
case 180:
{
ejeY = -altoFirma + coordenadaY;
break;
}
case 270:
{
ejeY = coordenadaX;
break;
}
default:
{
ejeY = altoFirma - (altoElemento + coordenadaY);
break;
}
}
break;
}
case EsquinaEnum.SUPERIOR_DERECHA:
{
switch (rotacionElemento)
{
case 90:
{
ejeY = coordenadaX - (anchoFirma);
break;
}
case 180:
{
ejeY = -coordenadaY - altoElemento;
break;
}
case 270:
{
ejeY = anchoFirma - (altoElemento + coordenadaX);
break;
}
default:
{
ejeY = coordenadaY;
break;
}
}
break;
}
case EsquinaEnum.INFERIOR_DERECHA:
{
switch (rotacionElemento)
{
case 90:
{
ejeY = coordenadaX - (anchoFirma);
break;
}
case 180:
{
ejeY = -altoFirma + coordenadaY;
break;
}
case 270:
{
ejeY = anchoFirma - (altoElemento + coordenadaX);
break;
}
default:
{
ejeY = altoFirma - (altoElemento + coordenadaY);
break;
}
}
break;
}
}
return ejeY;
}
private static TSpdf.Kernel.Font.PdfFont devolverTipoFuente(string nombreFuente)
{
TSpdf.Kernel.Font.PdfFont tipoFuente;
switch (nombreFuente)
{
case "COURIER":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.COURIER);
break;
}
case "COURIER_BOLD":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.COURIER_BOLD);
break;
}
case "COURIER_BOLDOBLIQUE":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.COURIER_BOLDOBLIQUE);
break;
}
case "COURIER_OBLIQUE":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.COURIER_OBLIQUE);
break;
}
case "HELVETICA":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
break;
}
case "HELVETICA_BOLD":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);
break;
}
case "HELVETICA_BOLDOBLIQUE":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLDOBLIQUE);
break;
}
case "HELVETICA_OBLIQUE":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_OBLIQUE);
break;
}
case "SYMBOL":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.SYMBOL);
break;
}
case "TIMES_ROMAN":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
break;
}
case "TIMES_BOLD":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_BOLD);
break;
}
case "TIMES_BOLDITALIC":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_BOLDITALIC);
break;
}
case "TIMES_ITALIC":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_ITALIC);
break;
}
case "ZAPFDINGBATS":
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.ZAPFDINGBATS);
break;
}
default:
{
tipoFuente = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
break;
}
}
return tipoFuente;
}
}
}
public enum EsquinaEnum : int
{
INFERIOR_IZQUIERDA = 0,
INFERIOR_DERECHA = 1,
SUPERIOR_IZQUIERDA = 2,
SUPERIOR_DERECHA = 3
}
public enum AlineamientoEnum : int
{
IZQUIERDA = 0,
DERECHA = 1,
CENTRO = 2,
JUSTIFICADO = 3,
JUSTIFICADO_ALL = 4
}
public enum TipoTextoEnum : int
{
NORMAL = 0,
NUMERO_PAGINA = 1,
NUMERO_PAGINA_TOTAL_PAGINAS = 2,
}
public enum FuenteEnum
{
COURIER,
COURIER_BOLD,
COURIER_BOLDOBLIQUE,
COURIER_OBLIQUE,
HELVETICA,
HELVETICA_BOLD,
HELVETICA_BOLDOBLIQUE,
HELVETICA_OBLIQUE,
SYMBOL,
TIMES_ROMAN,
TIMES_BOLD,
TIMES_BOLDITALIC,
TIMES_ITALIC,
ZAPFDINGBATS
}

View File

@@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Este código fue generado por una herramienta.
// Versión de runtime:4.0.30319.42000
//
// Los cambios en este archivo podrían causar un comportamiento incorrecto y se perderán si
// se vuelve a generar el código.
// </auto-generated>
//------------------------------------------------------------------------------
namespace tsPDFUtilsCore.Properties {
using System;
/// <summary>
/// Clase de recurso fuertemente tipado, para buscar cadenas traducidas, etc.
/// </summary>
// StronglyTypedResourceBuilder generó automáticamente esta clase
// a través de una herramienta como ResGen o Visual Studio.
// Para agregar o quitar un miembro, edite el archivo .ResX y, a continuación, vuelva a ejecutar ResGen
// con la opción /str o recompile su proyecto de VS.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Devuelve la instancia de ResourceManager almacenada en caché utilizada por esta clase.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("tsPDFUtilsCore.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Reemplaza la propiedad CurrentUICulture del subproceso actual para todas las
/// búsquedas de recursos mediante esta clase de recurso fuertemente tipado.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Busca un recurso adaptado de tipo System.Byte[].
/// </summary>
public static byte[] fogra39L {
get {
object obj = ResourceManager.GetObject("fogra39L", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Busca un recurso adaptado de tipo System.Byte[].
/// </summary>
public static byte[] sRGB2014 {
get {
object obj = ResourceManager.GetObject("sRGB2014", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="fogra39L" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\fogra39L.icc;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="sRGB2014" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\sRGB2014.icc;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

Binary file not shown.

Binary file not shown.

1446
tsPDFUtilsCore/Sellado.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace tsPDFUtilsCore
{
public class TextoEnPdf
{
public string Texto { get; set; }
public FuenteEnum Fuente { get; set; }
public float TamañoFuente { get; set; }
public System.Drawing.Color Color { get; set; }
public double Transparencia { get; set; }
public EsquinaEnum EsquinaReferencia { get; set; }
public float AnguloRotacion { get; set; }
public AlineamientoEnum Alineamiento { get; set; }
public float CoordenadaX { get; set; }
public float CoordenadaY { get; set; }
public int PaginaInicio { get; set; }
public int PaginaFin { get; set; }
public float anchoTexto { get; set; }
public float altoTexto { get; set; }
public TipoTextoEnum TipoTexto { get; set; }
}
}

View File

@@ -0,0 +1,158 @@
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;
}
}
}

View File

@@ -0,0 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Globals">
<SccProjectName>SAK</SccProjectName>
<SccProvider>SAK</SccProvider>
<SccAuxPath>SAK</SccAuxPath>
<SccLocalPath>SAK</SccLocalPath>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net48</TargetFrameworks>
<AssemblyVersion>1.0.16</AssemblyVersion>
<FileVersion>1.0.16</FileVersion>
<OutputType>Library</OutputType>
<RootNamespace>tsPDFUtilsCore</RootNamespace>
<PackageId>tsPDFUtilsCore</PackageId>
<PackageTags>netstandard2.0, libreria</PackageTags>
<Version>1.0.16</Version>
<Authors>Manuel, Perea</Authors>
<Company>Tecnosis S.A</Company>
<Description>Utilidades de tratamiento de pdf, de firmas digitales e imagenes.</Description>
<PackageReleaseNotes>
- 1.0.16 2026-05-20 Correcciones dependencias Microsoft.Extensions.Logging
- 1.0.12 2025-10-23 se posiciona en 0 la posicion del stream original
- 1.0.10 2025-10-23 Se relanzan exepciones en caso de error
- 1.0.9 2025-10-23 Se añade parámetro para en caso de pdf/a3b poder decidir si es obligatorio o no
- 1.0.8 2025-10-06 Se añade parámetro para crear el standard pdf/a3b
- 1.0.7 2025-10-06 Se deja solo net standard
- 1.0.6 2025-10-06 Actualización de dependencias microsoft.extensions.options
- 1.0.5 Actualización de dependencias microsoft.extensions.options
- 1.0.4 Corrección en TSpdf.io
- Primera versión estable.
- Probando Nuget
</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.9" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
<PackageReference Include="TSpdf.kernel" Version="3.0.0" />
<PackageReference Include="TSpdf.layout" Version="3.0.0" />
<PackageReference Include="TSpdf.pdfa" Version="3.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>