You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

414 lines
13 KiB

namespace ReportEngine
{
using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
public class ReportPainter
{
public enum ImageScale
{
IS_KeepOrigin = 0,
IS_Width = 1,
IS_FitWidth = 2
}
public class ColumnMeta
{
public string Title { get; set; }
public float Width { get; set; }
public string DisplayFormat { get; set; }
}
public class TableMeta
{
public DataTable Table { get; set; }
public List<ColumnMeta> Columns { get; set; }
}
public class DataCell
{
public enum EDC_TYPE
{
EDC_CONTENT = 0,
EDC_EMPTY = 1
}
public int ColumnSpan { get; set; } = 1;
public int RowSpan { get; set; } = 1;
public int Align { get; set; } = Element.ALIGN_LEFT;
public int VAlign { get; set; } = Element.ALIGN_MIDDLE;
public string Content { get; set; }
public EDC_TYPE CellType { get; set; } = EDC_TYPE.EDC_CONTENT;
public float Height { get; set; } = -1;
}
public class CellTable
{
public int ColumnNum { get; set; } = 10;
public float ColumnWidth { get; set; } = 75;
public List<DataCell> Cells { get; set; }
}
readonly Document _dDocument;
readonly ReportCanvasOptions _rcoOption;
readonly PdfWriter _pfWriter;
readonly double dFontHeight;
public ReportPainter(Document i_dDocument, ReportCanvasOptions i_rcoOption, PdfWriter i_pfWriter)
{
_dDocument = i_dDocument;
_rcoOption = i_rcoOption;
_pfWriter = i_pfWriter;
float ascent = _rcoOption.BaseFont.GetAscentPoint("Some String", _rcoOption.FontSize);
float descent = _rcoOption.BaseFont.GetDescentPoint("Some String", _rcoOption.FontSize);
dFontHeight = ascent - descent;
}
public void NewPage() => _dDocument.NewPage();
public void WriteText(string text = "\r\n", int i_nAlign = PdfContentByte.ALIGN_LEFT, Font font = null)
{
Paragraph p = new Paragraph(text, font ?? _rcoOption.NormalFont)
{
Alignment = i_nAlign
};
_dDocument.Add(p);
}
public string WriteImage(string i_sFilePath, int i_nAlign = PdfContentByte.ALIGN_LEFT, ImageScale i_isScale = ImageScale.IS_KeepOrigin)
{
string sMsg = null;
if (System.IO.File.Exists(i_sFilePath))
{
Image image = Image.GetInstance(filename: i_sFilePath);
switch (i_isScale)
{
case ImageScale.IS_KeepOrigin:
{
_dDocument.Add(image);
}
break;
case ImageScale.IS_Width:
{
float fNewWidth = _rcoOption.PageSize.Width - _rcoOption.PageMarginRight - _rcoOption.PageMarginLeft;
float fHeight = fNewWidth * image.Height / image.Width;
image.ScaleToFit(fNewWidth, fHeight);
_dDocument.Add(image);
}
break;
case ImageScale.IS_FitWidth:
{
float fNewWidth = _rcoOption.PageSize.Width;
float fHeight = fNewWidth * image.Height / image.Width;
float fY = _pfWriter.GetVerticalPosition(true);
image.ScaleToFit(fNewWidth, fHeight);
image.SetAbsolutePosition(0, fY - fHeight);
Paragraph p = new Paragraph
{
image
};
_dDocument.Add(p);
int nLine = (int)Math.Ceiling(fHeight / dFontHeight / 2) + 2;
for (int n = 0; n < nLine; n++) // Workaround for vertical shift
{
WriteText();
}
}
break;
default:
break;
}
}
else
{
sMsg = $"Image not exist! Path = {i_sFilePath}";
}
return sMsg;
}
public void WriteTable(CellTable i_ctTableInfo, int i_nAlign = PdfContentByte.ALIGN_CENTER)
{
List<float> lf = new List<float>();
for (int nIdx = 0; nIdx < i_ctTableInfo.ColumnNum; nIdx++)
{
lf.Add(i_ctTableInfo.ColumnWidth);
}
PdfPTable pptTable = GeneratePTable(lf.ToArray(), 0);
foreach (DataCell dc in i_ctTableInfo.Cells)
{
if (dc.CellType == DataCell.EDC_TYPE.EDC_CONTENT)
{
pptTable.AddCell(GeneratePCell(dc.Content, dc.RowSpan, dc.ColumnSpan, dc.Align, dc.VAlign));
}
else if (dc.CellType == DataCell.EDC_TYPE.EDC_EMPTY)
{
StringBuilder sb = new StringBuilder();
for (int nIdx = 0; nIdx < dc.RowSpan; nIdx++)
{
sb.Append(Environment.NewLine);
}
PdfPCell pc = new PdfPCell(new Phrase(sb.ToString()))
{
Colspan = dc.ColumnSpan
};
if(dc.Height != -1)
{
pc.FixedHeight = dc.Height;
}
pptTable.AddCell(pc);
}
}
Paragraph para = new Paragraph
{
Alignment = i_nAlign
};
para.Add(pptTable);
_dDocument.Add(para);
}
public void WriteTable(TableMeta i_tmMeta, int i_nAlign = PdfContentByte.ALIGN_CENTER)
{
PdfPTable pptTable = GeneratePTable(i_tmMeta.Columns.Select(f => f.Width).ToArray());
string[] asTitles = i_tmMeta.Columns.Select(f => f.Title).ToArray();
foreach (string sTitle in asTitles)
{
pptTable.AddCell(GeneratePCell(sTitle, align: Element.ALIGN_CENTER));
}
DataTable dtData = i_tmMeta.Table;
// 表格內容
foreach (DataRow row in dtData.Rows)
{
foreach (ColumnMeta cm in i_tmMeta.Columns)
{
var cellValue = GetValue(row, cm);
pptTable.AddCell(GeneratePCell(cellValue, align: Element.ALIGN_CENTER));
}
}
var cell = GeneratePCell(string.Format("Total records: {0}", dtData.Rows.Count), 1, i_tmMeta.Columns.Count, Element.ALIGN_LEFT);
pptTable.AddCell(cell);
Paragraph para = new Paragraph
{
Alignment = i_nAlign
};
para.Add(pptTable);
_dDocument.Add(para);
}
public void WriteTable(PdfPTable i_pptTable, int i_nAlign = PdfContentByte.ALIGN_CENTER)
{
Paragraph para = new Paragraph
{
Alignment = i_nAlign
};
para.Add(i_pptTable);
_dDocument.Add(para);
}
public void WriteTable(DataTable i_dtTable, int i_nAlign = PdfContentByte.ALIGN_CENTER)
{
Paragraph para = new Paragraph();
PdfPTable pdfTable = GenerateTable(i_dtTable);
para.Alignment = i_nAlign;
para.Add(pdfTable);
_dDocument.Add(para);
}
protected PdfPTable GenerateTable(DataTable dataTable)
{
// 欄位設定
DataColumn[] columns = dataTable.Columns.Cast<DataColumn>().OrderBy(x => x.Ordinal).ToArray();
float[] columnWidths = GetColumnWidths(columns);
PdfPTable pdfTable = GeneratePTable(columnWidths, 1);
// 表頭
var captions = columns.Select(x => x.Caption ?? x.ColumnName);
foreach (var caption in captions)
{
var cell = GeneratePCell(caption);
pdfTable.AddCell(cell);
}
// 表格內容
foreach (DataRow row in dataTable.Rows)
{
foreach (var column in columns)
{
var cellValue = GetValue(row, column);
var cell = GeneratePCell(cellValue, align: Element.ALIGN_CENTER);
pdfTable.AddCell(cell);
}
}
// 表尾
// 如果不存在指定變數,或變數設定false就不顯示,反之顯示
if (dataTable.ExtendedProperties["RowCount"] as bool? != false)
{
var cell = GeneratePCell(string.Format("總計: {0} 筆紀錄", dataTable.Rows.Count), 1, columns.Length, Element.ALIGN_LEFT);
pdfTable.AddCell(cell);
}
return pdfTable;
}
public string GetValue(DataRow row, ColumnMeta column)
{
if (!row.Table.Columns.Contains(column.Title))
{
return "";
}
DataColumn dc = row.Table.Columns[column.Title];
var value = row[dc];
// 當有設定欄位時,以欄位為主
if (column.DisplayFormat != null)
{
return string.Format(column.DisplayFormat, value);
}
var type = dc.DataType;
if (type == typeof(int))
{
return string.Format("{0:N0}", value);
}
else if (type == typeof(double) || type == typeof(decimal))
{
return string.Format("{0:0,0.##}", value);
}
else if (type == typeof(DateTime))
{
return string.Format("{0:yyyy/MM/dd HH\\:mm\\:ss}", value);
}
else if (type == typeof(TimeSpan))
{
return string.Format("{0:hh\\:mm}", value);
}
return value.ToString();
}
/// <summary>
/// 新增表格
/// </summary>
/// <param name="numColumns">最多幾個儲存格</param>
/// <param name="headerRows">固定標題列</param>
/// <returns></returns>
public string GetValue(DataRow row, DataColumn column)
{
var value = row[column];
if (value == null)
{
return "";
}
// 當有設定欄位時,以欄位為主
var format = column.ExtendedProperties["Format"] as string;
if (!string.IsNullOrEmpty(format))
{
return string.Format(format, value);
}
var type = column.DataType;
if (type == typeof(int))
{
return string.Format("{0:N0}", value);
}
else if (type == typeof(double) || type == typeof(decimal))
{
return string.Format("{0:0,0.##}", value);
}
else if (type == typeof(DateTime))
{
return string.Format("{0:yyyy/MM/dd HH\\:mm}", value);
}
else if (type == typeof(TimeSpan))
{
return string.Format("{0:hh\\:mm}", value);
}
return value.ToString();
}
protected float[] GetColumnWidths(DataColumn[] columns)
{
return columns.Select(x => x.ExtendedProperties.ContainsKey("Width") ? Convert.ToSingle(x.ExtendedProperties["Width"]) : 80f).ToArray();
}
public PdfPTable GeneratePTable(float[] columnWidths, int headerRows = 1)
{
var table = new PdfPTable(columnWidths.Length)
{
HeaderRows = headerRows
};
table.SetTotalWidth(columnWidths);
table.SetWidths(columnWidths);
table.LockedWidth = true;
return table;
}
public PdfPCell GeneratePCell(string text, int rowspan = 1, int colspan = 1, int align = Element.ALIGN_LEFT, int verticalAlign = Element.ALIGN_MIDDLE)
{
return new PdfPCell(new Phrase(text, _rcoOption.NormalFont))
{
PaddingBottom = 5,
HorizontalAlignment = align,
VerticalAlignment = verticalAlign,
Rowspan = rowspan,
Colspan = colspan
};
}
}
}