Из-за нехватки времени и других проблем, связанных с работой, после поиска в течение целой недели я получаю следующее решение:
- Вместо того, чтобы сосредоточиться на добавлении страниц в файл PDF в процессе разработки, ярешил сгенерировать X количество временных файлов PDF (каждый со связанными именами, например: PDF_File_0.pdf , PDF_File_1.pdf , PDF_File_2.pdf и т. д.) .
- После создания временных PDF-файлов я использовал код, обнаруженный в в этом ответе , для объединения всех PDF-файлов в один PDF-файл.
Если кому-то интересно узнать, как добавить несколько страниц в файл PDF (пока он создан) , вы можете использовать этот код:
string PDF_filePath = @"C:\New Folder\myPdfTest.pdf";
Document doc = new Document();
PdfSmartCopy copy = new PdfSmartCopy(doc, new FileStream(PDF_filePath, FileMode.Create));
doc.Open();
double qtyPages = 8; // it will be added eight pages.
// In each loop iteration a page will be added "which is a Rectangle, actually"
// with the standard size of a LETTER paper format - landscape orientation.
for (int pag = 0; pag < qtyPages; pag++)
{
iTextSharp.text.Rectangle rect1 = new iTextSharp.text.Rectangle(PageSize.LETTER.Rotate());
rect1.Border = iTextSharp.text.Rectangle.BOX;
copy.AddPage(rect1, 0);
}
// Close the document with the changes made.
doc.Close();
Я использую код из этого ответа для «слияния» временных файлов PDF в один файл PDF:
/// <summary>
/// Merge PDF's in a single PDF file.
/// Source: https://stackoverflow.com/a/26883360/4092887
/// </summary>
/// <param name="fileNames">List with (filepath & filename) of PDF temp files.</param>
/// <param name="targetPdf">Path and filename of the PDF unified file.</param>
/// <returns>bool</returns>
public bool MergePDFs(IEnumerable<string> fileNames, string targetPdf)
{
bool merged = true;
try
{
using (FileStream stream = new FileStream(targetPdf, FileMode.Create))
{
Document document = new Document();
PdfCopy pdf = new PdfCopy(document, stream);
PdfReader reader = null;
try
{
document.Open();
foreach (string file in fileNames)
{
reader = new PdfReader(file);
pdf.AddDocument(reader);
reader.Close();
}
}
catch (Exception)
{
merged = false;
if (reader != null)
{
reader.Close();
}
}
finally
{
if (document != null)
{
document.Close();
}
}
}
}
catch (Exception ex)
{
// Log error in the log file - omitted here for clarity's sake.
MessageBox.Show("An error ocurred at merginf the PDF files: " + SALTO_DE_LINEA +
"Check the application log file for more details", TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return merged;
}
Создаемый файл PDF на самом деле является счетом, в котором используется файл PDF.template.
Здесь мне нужно разделить детали, «хранящиеся в переменной DataTable
», на куски по 10записи / строки.
Для установки чанков (мне нужно установить чанки из 10 записей / строк) , я добавил новый DataColumn
в переменную DataTable
с именем "PAGE_SEPARATOR" иобновите значение столбца «PAGE_SEPARATOR» с результатом этого деления:
// Set chunk separator.
for (int r = 0; r < items.Rows.Count; r++)
{
items.Rows[r]["SEPARADOR"] = r/10;
}
Полное объяснение этого кода можно найти здесь
Для каждого куска записейМне нужно добавить новую страницу со структурой шаблона PDF.
Это полный код для создания файла счета-фактуры PDF с использованием шаблона PDF и создания файлов PDF для каждого фрагмента записей;в конце процесса вызовите метод MergePdfs и удалите временные PDF-файлы:
ПРИМЕЧАНИЕ. Вы можете найти комментарии на испанском языке, но я надеюсь, что код достаточно ясен для понимания и изменения в соответствии сваши цели.
/// <summary>
/// Generate PDF invoice file.
/// It wuill create X PDF temp files "with consecutive file names" for - at the end
/// of the process - merge those PDF temp files in a single one PDF file.
/// Temp PDF files will be deleted after creating the PDF merged file.
/// </summary>
/// <param name="formFactura">DataTable with the values of the PDF template.</param>
/// <param name="DetalleFactura">DataTable with the JSON - DataTable (known as details or detalles).</param>
/// <param name="ruta_archivo_salida">File name and path of the PDF unified file.</param>
/// <returns>string</returns>
private string GenerateInvoice(DataTable formFactura, DataTable DetalleFactura, string ruta_archivo_salida)
{
// Inicializar variables.
string msg = "";
List<string> rutas_archivos = new List<string>();
try
{
if (File.Exists(plantilla_factura_manual))
{
try
{
// Crear X cantidad de archivos.
// "PAGE_SEPARATOR" es el nombre de la columna que posee los valores separados por bloques.
DataView view = new DataView(DetalleFactura);
DataTable distinctValues = view.ToTable(true, "PAGE_SEPARATOR");
double cantPaginas = distinctValues.Rows.Count;
for (int pagina = 0; pagina < cantPaginas; pagina++)
{
using (PdfReader pdfReader = new PdfReader(plantilla_factura_manual))
{
// Agregar la ruta del archivo temporal PDF a generar.
rutas_archivos.Add(ruta_factura_generada.Replace(".pdf", "(" + pagina + ").pdf"));
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(ruta_factura_generada.Replace(".pdf", "(" + pagina + ").pdf"), FileMode.OpenOrCreate));
AcroFields pdfFormFields = pdfStamper.AcroFields;
// Llenar las variables de la plantilla en el archivo PDF en construcción.
for (int i = 0; i < formFactura.Rows.Count; i++)
{
pdfFormFields.SetField(formFactura.Rows[i][0].ToString(), formFactura.Rows[i][1].ToString(), true);// set form pdfFormFields
}
#region Diseño grid factura
PdfPCell cell = null;
PdfPTable table = null;
table = new PdfPTable(9);
table.HorizontalAlignment = Element.ALIGN_LEFT;
table.SetWidths(new float[] { 22f, 22f, 22f, 22f, 22f, 22f, 22f, 22f, 22f });
//table.SpacingBefore = 5;
table.TotalWidth = 800f;
DataRow[] filas_a_usar = DetalleFactura.Select("PAGE_SEPARATOR = " + pagina);
foreach (DataRow r in filas_a_usar)
{
DataRow row = r;
object valorFacturaPDFColumna0 = row.Field<string>("PROVIDER") == null ? string.Empty : row.Field<string>("PROVIDER").ToString();
object valorFacturaPDFColumna1 = row.Field<string>("DESCRIPTION") == null ? string.Empty : row.Field<string>("DESCRIPTION").ToString();
object valorFacturaPDFColumna2 = row.Field<string>("PPTO") == null ? string.Empty : row.Field<string>("PPTO").ToString();
object valorFacturaPDFColumna3 = row.Field<string>("JOB_MEDIA_TYPE") == null ? string.Empty : row.Field<string>("JOB_MEDIA_TYPE").ToString();
object valorFacturaPDFColumna4 = row.Field<string>("VEND_INV_NO") == null ? string.Empty : row.Field<string>("VEND_INV_NO").ToString();
//object valorFacturaPDFColumna5 = row.Field<string>("ORDER_MEDIA") == null ? string.Empty : row.Field<string>("ORDER_MEDIA").ToString();
//object valorFacturaPDFColumna6 = row.Field<string>("ACTIVITY_MONTH") == null ? string.Empty : row.Field<string>("ACTIVITY_MONTH").ToString();
object valorFacturaPDFColumna7 = row.Field<string>("COMMISSIONABLE") == null ? string.Empty : row.Field<string>("COMMISSIONABLE").ToString();
object valorFacturaPDFColumna8 = row.Field<string>("NON_COMMISSIONABLE") == null ? string.Empty : row.Field<string>("NON_COMMISSIONABLE").ToString();
string valorFacturaPDFColumna9 = row.Field<string>("IVA_PROVEEDOR") == null ? string.Empty : row.Field<string>("IVA_PROVEEDOR").ToString();
string valorFacturaPDFColumna10 = row.Field<string>("TOTAL") == null ? string.Empty : row.Field<string>("TOTAL").ToString();
//Columnas table
cell = PhraseCell(new Phrase(valorFacturaPDFColumna0.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(valorFacturaPDFColumna1.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(valorFacturaPDFColumna2.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(valorFacturaPDFColumna3.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(valorFacturaPDFColumna4.ToString(), GettypeStyle()));
table.AddCell(cell);
//cell = PhraseCell(new Phrase(valorFacturaPDFColumna5.ToString(), GettypeStyle()));
//table.AddCell(cell);
//cell = PhraseCell(new Phrase(valorFacturaPDFColumna6.ToString(), GettypeStyle()));
//table.AddCell(cell);
cell = PhraseCell(new Phrase(valorFacturaPDFColumna7.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(valorFacturaPDFColumna8.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(valorFacturaPDFColumna9.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(valorFacturaPDFColumna10.ToString(), GettypeStyle()));
table.AddCell(cell);
}
ColumnText ct = new ColumnText(pdfStamper.GetOverContent(1));
ct.AddElement(table);
//iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(18, 370, 800, 36);
iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(16, 320, 900, 16);
rect.Border = iTextSharp.text.Rectangle.LEFT_BORDER | iTextSharp.text.Rectangle.RIGHT_BORDER;
rect.BorderWidth = 15;
rect.BorderColor = new BaseColor(0, 0, 0);
rect.Border = iTextSharp.text.Rectangle.BOX;
ct.SetSimpleColumn(rect);
ct.Go();
#endregion
// flatten the form to remove editting options, set it to false
// to leave the form open to subsequent manual edits
pdfStamper.FormFlattening = true;
pdfStamper.FreeTextFlattening = true;
pdfStamper.Writer.CloseStream = true;
pdfStamper.Close();// close the pdf
}
}
// Unir los archivos PDF's en uno solo.
MergePDFs(rutas_archivos, ruta_archivo_salida);
#region Eliminar archivos PDF temporales.
try
{
foreach (string archivo in rutas_archivos)
{
File.Delete(archivo);
}
}
catch (Exception ex)
{
RegistrarEventosDelPrograma("Error al eliminar archivos PDF temporales: " + ex.ToString(), "Error al eliminar archivos PDF temporales");
}
#endregion
}
catch (Exception ex)
{
msg += "- Hay un error con la plantilla. Consulte el log de eventos." + SALTO_DE_LINEA;
RegistrarEventosDelPrograma("Error al usar la plantilla (" + Path.GetFileName(plantilla_factura_manual) + "): " + ex.ToString(), "Error al usar la plantilla (" + Path.GetFileName(plantilla_factura_manual) + ")");
}
}
}
catch (Exception ex)
{
msg += "- Hubo un error inesperado al generar el archivo PDF. Consulte el log de eventos.";
RegistrarEventosDelPrograma("Error al generar el archivo PDF. Detalles: " + ex.ToString(), "Error al generar PDF - Plantilla");
}
return msg;
}
Это моя тесно связанная запись в Переполнение стека на испанском .