我正在开发Windows窗体应用程序,用于在PDF文件中生成发票。
此Winform应用程序使用PDF模板来创建PDF文件。
这是PDF模板的屏幕截图(此模板是使用 Adobe Acrobat XI Lite Portable 创建的):
我在此代码中使用itextsharp (版本5.5.13)来生成PDF文件:
private void GenerateInvoice(DataTable tbl_template_variables, DataTable tbl_details_invoice)
{
using (PdfReader pdfReader = new PdfReader(plantilla__Invoice__manual))
{
try
{
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(location_output_file, FileMode.Create));
AcroFields pdfFormFields = pdfStamper.AcroFields;
// Loop DataTable and set the value in the specified field.
for (int i = 0; i < tbl_template_variables.Rows.Count; i++)
{
pdfFormFields.SetField(tbl_template_variables.Rows[i][0].ToString(), tbl_template_variables.Rows[i][1].ToString(), true);// set form pdfFormFields
}
#region Details's table Invoice
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;
for (int i = 0; i < tbl_details_invoice.Rows.Count; i++)
{
DataRow row = tbl_details_invoice.Rows[i];
object Invoice_PDFColumn0_value = row.Field<string>("PROVIDER") == null ? string.Empty : row.Field<string>("PROVIDER").ToString();
object Invoice_PDFColumn1_value = row.Field<string>("DESCRIPTION") == null ? string.Empty : row.Field<string>("DESCRIPTION").ToString();
object Invoice_PDFColumn2_value = row.Field<string>("PPTO") == null ? string.Empty : row.Field<string>("PPTO").ToString();
object Invoice_PDFColumn3_value = row.Field<string>("JOB_MEDIA_TYPE") == null ? string.Empty : row.Field<string>("JOB_MEDIA_TYPE").ToString();
object Invoice_PDFColumn4_value = row.Field<string>("VEND_INV_NO") == null ? string.Empty : row.Field<string>("VEND_INV_NO").ToString();
//object Invoice_PDFColumn5_value = row.Field<string>("ORDER_MEDIA") == null ? string.Empty : row.Field<string>("ORDER_MEDIA").ToString();
//object Invoice_PDFColumn6_value = row.Field<string>("ACTIVITY_MONTH") == null ? string.Empty : row.Field<string>("ACTIVITY_MONTH").ToString();
object Invoice_PDFColumn7_value = row.Field<string>("COMMISSIONABLE") == null ? string.Empty : row.Field<string>("COMMISSIONABLE").ToString();
object Invoice_PDFColumn8_value = row.Field<string>("NON_COMMISSIONABLE") == null ? string.Empty : row.Field<string>("NON_COMMISSIONABLE").ToString();
string Invoice_PDFColumn9_value = row.Field<string>("IVA_PROVEEDOR") == null ? string.Empty : row.Field<string>("IVA_PROVEEDOR").ToString();
string Invoice_PDFColumn10_value = row.Field<string>("TOTAL") == null ? string.Empty : row.Field<string>("TOTAL").ToString();
//Columns table
cell = PhraseCell(new Phrase(Invoice_PDFColumn0.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(Invoice_PDFColumn1.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(Invoice_PDFColumn2.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(Invoice_PDFColumn3.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(Invoice_PDFColumn4.ToString(), GettypeStyle()));
table.AddCell(cell);
//cell = PhraseCell(new Phrase(Invoice_PDFColumn5.ToString(), GettypeStyle()));
//table.AddCell(cell);
//cell = PhraseCell(new Phrase(Invoice_PDFColumn6.ToString(), GettypeStyle()));
//table.AddCell(cell);
cell = PhraseCell(new Phrase(Invoice_PDFColumn7.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(Invoice_PDFColumn8.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(Invoice_PDFColumn9.ToString(), GettypeStyle()));
table.AddCell(cell);
cell = PhraseCell(new Phrase(Invoice_PDFColumn10.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
}
catch (Exception ex)
{
// No errors (yet).
}
}
}
这是结果(只有一些细节):
此代码面临的问题是,如果明细表中有更多行,则这些行将在生成的页面中被覆盖(并且不再生成任何页面)。
>这是数据被覆盖的结果:
我正在寻找使用此PDF模板正确生成PDF发票的方法(如果可能)。
这是迄今为止我尝试过的最接近的有利结果:
HtmlConverter.ConvertToPdf
功能,但是在这种情况下,生成旋转的PDF时遇到问题。该文档位于我不熟悉的Java 中。所有提到的尝试给我带来的问题多于解决方案,因此,我想使用PDF模板方法集中精力一点。
我整周忙于这项任务,但我没主意。
我将编辑我的问题,以添加与我面临的相同问题相关的问题:
我几乎不想避免创建给我代码问题,但是,欢迎提出任何有关如何正确生成PDF文件的建议或想法。
答案 0 :(得分:0)
由于时间和其他与工作有关的问题,经过整整一周的搜索,我得到了以下解决方案:
如果任何人有兴趣知道如何在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();
我正在使用code from this answer将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模板的发票。
在这里,我需要将“存储在DataTable
变量中的详细信息”划分为10个记录/行的块。
要设置数据块(我需要设置10个记录/行的数据块),我向名为{PAGE_SEPARATOR“的DataColumn
变量添加了一个新的DataTable
,并更新了“ PAGE_SEPARATOR”列的值以及该划分结果:
// Set chunk separator.
for (int r = 0; r < items.Rows.Count; r++)
{
items.Rows[r]["SEPARADOR"] = r/10;
}
有关此代码的完整说明,请参见here
对于每条记录,我必须添加具有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;
}
这是我在Stack Overflow in spanish中密切相关的条目。