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
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
|
|
};
|
|
}
|
|
}
|
|
}
|