九.表格示例
以下示例中,均假设中文宋体字库已放到PDFlib所设置的搜索目录下,文件采用visual studio中文缺省的gb2312编码。
1.简单表格示例
int simple_table(void)
{
auto PDFError = [](PDFlib& pdf, const char *caption, int error)->int
{
std::cerr << caption << pdf.get_errmsg() << std::endl;
return error;
};
const string searchpath = "E:\\PDFlibx64.10.0.3\\bind\\data";
const string imagefile = "nesrin.jpg";
const string graphicsfile = "PDFlib-logo.svg";
int font, zhfont, imgid, grhid, tf = -1, tbl = -1;
int row, col;
int rowmax = 50, colmax = 4;
double llx = 50, lly = 50, urx = 550, ury = 800;
const string headertext = "Table header (row 1)";
string result;
ostringstream optlist;
/* Dummy text for filling a cell with multi-line Textflow */
const string tf_text =
"你好<\n"
"<fontsize=14>工业大数据\n"
"<fontsize=10>工业是国民经济的基础和支柱,也是一国经济实力和竞争力的重要标志。随着云计算、大数据和物联网等新兴技术的发展,\n"
"全球掀起了以制造业转型升级为首要任务的新一轮工业变革,世界上主要的工业发达体纷纷制定工业再发展战略。\n"
"<工业大数据应用热点\n"
"工业大数据挖掘和分析的结果可广泛应用于企业研发设计、 复杂生产过程、产品需求预测、工业供应链优化和工业绿色发展等各个环节。";
PDFlib pdf;
try {
// This means we must check return values of load_font() etc.
pdf.set_option("errorpolicy=return");
// Set the search path for fonts and PDF files
optlist.str(""); optlist << "searchpath={{" << searchpath << "}}";
pdf.set_option(optlist.str());
//-----------------------------------------------------------------------------------------------
if (pdf.begin_document("simple_table.pdf", "") == -1)
return PDFError(pdf, "create pdf:", 1);
pdf.set_info("Creator", "PDFlib starter sample");
pdf.set_info("Title", "simple_table");
//load 2 fonts
font = pdf.load_font("NotoSerif-Regular", "unicode", "");
if(font==-1) return PDFError(pdf, "load font NotoSerif-Regular:", 2);
zhfont = pdf.load_font("SimSun", "unicode", "");
if (zhfont == -1) return PDFError(pdf, "load font SimSun:", 3);
// ---------- Row 1: table header (spans all columns)
row = 1; col = 1;
optlist.str(""); optlist << "fittextline={position=center font=" << font << " fontsize=14} colspan=" << colmax;
tbl = pdf.add_table_cell(tbl, col, row, headertext, optlist.str());
if (tbl == -1) return PDFError(pdf, "create table:", 4);
// ---------- Row 2: images
row++;
col = 1;
imgid = pdf.load_image("jpeg", imagefile, "");
if (imgid == -1) return PDFError(pdf, "load image:", 4);
optlist.str(""); optlist << "rowheight=300 colspan=2 image=" << imgid;
tbl = pdf.add_table_cell(tbl, col, row, "", optlist.str());
if (tbl == -1) return PDFError(pdf, "create table:", 4);
col = 3;
grhid = pdf.load_graphics("svg", graphicsfile, "");
if(grhid == -1) return PDFError(pdf, "load image:", 4);
optlist.str(""); optlist << "colspan=2 graphics=" << grhid;
tbl = pdf.add_table_cell(tbl, col, row, "", optlist.str());
if (tbl == -1) return PDFError(pdf, "create table:", 4);
// ---------- Rows: regular cells
for (row++; row <= 10; row++) {
for (col = 1; col <= colmax; col++)
{
ostringstream num;
num << "Col " << col << "/Row " << row << " 1234567890abced";
optlist.str("");
optlist << "colwidth=25% fittextline={font=" << font << " fontsize=12}";
tbl = pdf.add_table_cell(tbl, col, row, num.str(), optlist.str());
if (tbl == -1) return PDFError(pdf, "adding cell:", 4);
}
}
row--;
// ---------- Next Row : various kinds of content
row++;
//simple text
col = 1;
optlist.str(""); optlist << "fittextline={font=" << font << " fontsize=12 orientate=west}";
tbl = pdf.add_table_cell(tbl, col, row, "vertical line", optlist.str());
if (tbl == -1) return PDFError(pdf, "adding cell:", 5);
// ----- Colorized background
col++;
optlist.str(""); optlist << "fittextline={font=" << font << " fontsize=12 fillcolor=white} matchbox={fillcolor={orange}}";
tbl = pdf.add_table_cell(tbl, col, row, "colorized cel", optlist.str());
if (tbl == -1) return PDFError(pdf, "adding cell:", 6);
// ----- Multi-line chinese text with Textflow
col++;
std::string ss = GB2312ToUTF8(tf_text);
tf = pdf.add_textflow(tf, ss, "inlineoptions charref=true fontname=SimSun fontsize=10 alignment=justify leading=300%");
if (tf== -1) return PDFError(pdf, "create textflow:", 7);
optlist.str(""); optlist << "marginleft=2 marginright=2 margintop=2 marginbottom=2 textflow=" << tf;
tbl = pdf.add_table_cell(tbl, col, row, "", optlist.str());
if (tbl == -1) return PDFError(pdf, "adding cell:", 8);
do {
pdf.begin_page_ext(0, 0, "width=a4.width height=a4.height");
// Place the table
result = pdf.fit_table(tbl, llx, lly, urx, ury,
"rowheightdefault=auto "
"fill={{area=rowodd fillcolor={gray 0.9}}} "
"stroke={{line=other}}");
if (result == "_error") return PDFError(pdf, "place table: :", 9);
pdf.end_page_ext("");
} while (result == "_boxfull");
// Check the result; "_stop" means all things are ok.
if (result != "_stop")
{
if (result == "_error") return PDFError(pdf, "place table: ", 10);
else
{
// Any other return value is a user exit caused by the "return" option; this requires dedicated code to deal with.
return PDFError(pdf, "User return found in Table: ", 11);
}
}
pdf.delete_table(tbl, "");
pdf.end_document("");
}
catch (PDFlib::Exception& ex)
{
cerr << "PDFlib exception occurred:" << endl
<< "[" << ex.get_errnum() << "] " << ex.get_apiname()
<< ": " << ex.get_errmsg() << endl;
return 99;
}
catch (exception& e)
{
cerr << "C++ exception occurred: " << e.what() << endl;
return 99;
}
catch (...) {
cerr << "Generic C++ exception occurred!" << endl;
return 99;
}
return 0;
}
以上示例中,由于中文采用gb2312,PDFlib采用缺省的utf8方式,因而中文需转成utf8编码,然后输入给PDFlib函数,其中的GB2312ToUTF8(示例中未附)即完成此功能。
类似html,多行文本textflow支持“inline-style”,可在文本中设置格式(还有一种方式为定义macro)。另外,文本中也可直接采用unicode编码,如上面的”你好“等字符,这两种特性需要在textflow的optlist设置“inlineoptions charref”,即它们为true。
这个示例输出的pdf分为2页,如下图所示。注意最后一行被分配到了下一页,也就是说,缺省情况下,完整的一行不会被分割,如果允许跨页,最简单的方法就是设置minrowheight,可自行设置后看看效果。


2.手工设置输出表格
1)单元格边框的设置
PDFlib中, 单元格边框的设置并不在add_table_cell中,而是在fit_table的optlist中(单元格的背景色也在这里设置),因而这里的设置是针对所有单元格的。以下是几个示例:
stroke = { {line=vert1 linewidth=0.5} {line=other linewidth=0.1} }
stroke = { {line=hor0 linewidth=0.5} }
stroke = { {line= horlast linewidth=0.5 strokecolor = {rgb 1 0 0} } }
其中第一行将第二条垂直线宽度设置为0.5,其余线宽为0.1,第二行将第一条水平线宽度设置为0.5;第三行将最后一条水平线设置为红色,线宽0.5
如果需要单独设置某一个单元格边框,可采用matchbox,此时是用matchbox的边框“覆盖”table原有的边框。参见“分割表格”一节。
2)将一段长文按长度平均放置到3个单元格中(分属两个表)。
int test_table()
{
auto PDFError = [](PDFlib& pdf, const char* caption, int error)->int
{
std::cerr << caption << pdf.get_errmsg() << std::endl;
return error;
};
struct pdf_rect_t
{
double x1;
double y1;
double height;
double width;
};
auto MatchboxRect = [](PDFlib& pdf, const char* boxname, pdf_rect_t* prect, int count = 1)->bool
{
bool bb = true;
for (int i = 0, j = 1; i < count; ++i, ++j)
{
prect[i].x1 = pdf.info_matchbox(boxname, j, "x1");
bb = prect[i].x1 > 0;
if (!bb) break;
prect[i].y1 = pdf.info_matchbox(boxname, j, "y1");
prect[i].width = pdf.info_matchbox(boxname, j, "x3") - prect[i].x1;
prect[i].height = pdf.info_matchbox(boxname, j, "y3") - prect[i].y1;
}
return bb;
};
PDFlib pdf;
const string searchpath = "E:\\PDFlibx64.10.0.3\\bind\\data";
const string imagefile = "nesrin.jpg";
int font, image, tf = -1, tbl = -1;
ostringstream optlist;
int pagewidth = 595, pageheight = 800;
int c1 = 80, c2 = 120;
double llx = 50, lly = 400, urx = 300, ury = 650;
string tf_text =
"This tutorial assumes a decent mathematical background.Most examples require knowledge "
"lower than a calculus level, and some require knowledge at a calculus level.Some of the "
"advanced features require more than this.If you come across a section that uses some "
"mathematical function you are not familiar with, you can probably skip over it, or replace it with a "
"similar one that you are more familiar with.";
try {
pdf.set_option("errorpolicy=return");
// Set the search path for fonts and PDF files
optlist.str(""); optlist << "searchpath={{" << searchpath << "}}";
pdf.set_option(optlist.str());
//-----------------------------------------------------------------------------------------------
if (pdf.begin_document("table1.pdf", "") == -1)
return PDFError(pdf, "create pdf:", 1);
if( (font = pdf.load_font("NotoSerif-Regular", "unicode", ""))==-1)
return PDFError(pdf, "load font NotoSerif-Regular:", 2);
pdf.begin_page_ext(pagewidth, pageheight, "");
pdf.setfont(font, 11);
if((image = pdf.load_image("auto", imagefile, ""))==-1)
return PDFError(pdf, "create img:", 2);
optlist.str(""); optlist << "font=" << font << " fontsize=8 leading=110% charref";
if((tf = pdf.add_textflow(-1, tf_text, optlist.str()))==-1)
return PDFError(pdf, "create textflow:", 4);
//calc the height of the textflow
if(pdf.fit_textflow(tf, 0, 0, c1, 500, "blind")=="_error")
return PDFError(pdf, "calc textflow:", 4);
double tf_height=pdf.info_textflow(tf, "textheight");
if ((tf = pdf.add_textflow(-1, tf_text, optlist.str())) == -1)
return PDFError(pdf, "create textflow:", 5);
optlist.str(""); optlist << "textflow=" << tf << " fittextflow={firstlinedist=capheight} " << "colwidth=" << c1 << " rowheight=" << tf_height/3 << " continuetextflow";
tbl = pdf.add_table_cell(tbl, 1, 1, "", optlist.str());
if (tbl == -1) return PDFError(pdf, "add table cell:", 6);
tbl = pdf.add_table_cell(tbl, 1, 2, "", optlist.str()); // Continue the Textflow table cell
if (tbl == -1) return PDFError(pdf, "add table cell:", 7);
ostringstream optlist1;
optlist1.str(""); optlist1 << "fittextline={fontsize=12} matchbox={name=abc}";
tbl = pdf.add_table_cell(tbl, 2, 1, "", optlist1.str());
if (tbl == -1) return PDFError(pdf, "add table cell:", 8);
int tbl2 = -1;
tbl2 = pdf.add_table_cell(tbl2, 1, 2, "", optlist.str()); // Continue the Textflow table cell
if (tbl2 == -1) return PDFError(pdf, "add table cell:", 9);
tbl2 = pdf.add_table_cell(tbl2, 2, 2, "", optlist1.str());
if (tbl2 == -1) return PDFError(pdf, "add table cell:", 10);
std::string result = pdf.fit_table(tbl, llx, 300, urx, 700, "rowheightdefault=auto stroke={{line=other}}");
result = pdf.fit_table(tbl2, llx, 200, urx, 500, "rowheightdefault=auto stroke={{line=other}}");
pdf_rect_t mrect;
if (MatchboxRect(pdf, "abc", &mrect))
{
pdf.fit_textline("Find the matchbox", mrect.x1,mrect.y1, "");
}
// Check the result; "_stop" means all is ok
if (result!="_stop")
{
if (result == "_error")
{
return PDFError(pdf, "placing table:", 20);
}
else
{
// Other return values require dedicated code to deal with
}
}
// Delete the table handle. This will also delete any Textflow handles used in the table
pdf.delete_table(tbl, "");
pdf.end_page_ext("");
pdf.end_document("");
}
catch (PDFlib::Exception& ex) {
cerr << "PDFlib exception occurred:" << endl
<< "[" << ex.get_errnum() << "] " << ex.get_apiname()
<< ": " << ex.get_errmsg() << endl;
return 99;
}
catch (exception& e) {
cerr << "C++ exception occurred: " << e.what() << endl;
return 99;
}
catch (...) {
cerr << "Generic C++ exception occurred!" << endl;
return 99;
}
return 0;
}
以上示例中,首先用fit_textflow的blind输出,计算长文本在某一设定宽度下的高度,然后将分属两个table的三个单元格的大小设置为此宽度,此高度的三分之一,最后将长文本输出到这三个单元格中。
此例中,在一个单元格中设置了命名的matchbox,之后获取它的位置,然后在table之外,将一行文本输出到matchbox内(也就是单元格内)。
输出的pdf如下图所示。

3)分割表格
如果将表格中某一行的optlist设置为如下形式,就可以使表格输出一空行。
optlist.str("");
optlist << "rowheight=30 colspan="<<colmax<<" fittextline={font=" << font <<" fontsize=10} matchbox={borderwidth=2 drawbottom=false drawtop=false fillcolor={white} strokecolor = {rgb 1 1 1}}";
tbl = pdf.add_table_cell(tbl, 1, row, " ", optlist.str());
实际上,使该行所有列(上面中colmax是表格的列数)进行合并,并用一个matchbox标记该单元格,将matchbox左右两边的垂直线设置为白色以覆盖table本身的单元格线,由此将这个table“分割”成了两个table。
4)合并表格
与分割对应的是合并,不过PDFlib中并没有合并table的概念,这种场景下,需要计算第一个表格的位置,将二个表格顶部与第一个表格的底部设置成一样即可。
十.合并两个pdf
int merge_pdf()
{
auto PDFError = [](PDFlib& pdf, const char* caption, int error)->int
{
std::cerr << caption << pdf.get_errmsg() << std::endl;
return error;
};
ostringstream optlist;
try {
PDFlib pdf;
pdf.set_option("errorpolicy=return"); // 错误处理
if (pdf.begin_document("dest.pdf", "") == -1) return PDFError(pdf, "create pdf:", 1);
int docid1 = pdf.open_pdi_document("source1.pdf", "");
if (docid1 == -1) return PDFError(pdf, "load pdf:", 2);
int pagecount1 = (int)pdf.pcos_get_number(docid1, "length:pages");
for (int i = 0; i < pagecount1; ++i)
{
pdf.begin_page_ext(0, 0, "width=a4.width height=a4.height");
int pageid = pdf.open_pdi_page(docid1, i + 1, "");
if (pageid > -1)
{
pdf.fit_pdi_page(pageid, 0, 0, "");
pdf.close_pdi_page(pageid);
}
pdf.end_page_ext("");
}
pdf.close_pdi_document(docid1);
int docid2 = pdf.open_pdi_document("source2.pdf", "");
if (docid2 == -1) return PDFError(pdf, "load pdf:", 3);
int pagecount2 = (int)pdf.pcos_get_number(docid2, "length:pages");
for (int i = 0; i < pagecount2; ++i)
{
pdf.begin_page_ext(0, 0, "width=a4.width height=a4.height");
int pageid = pdf.open_pdi_page(docid2, i + 1, "");
if (pageid > -1)
{
pdf.fit_pdi_page(pageid, 0, 0, "");
pdf.close_pdi_page(pageid);
}
pdf.end_page_ext("");
}
pdf.close_pdi_document(docid2);
optlist.str(""); optlist << "index=-1 destination={page=1}";
int cat1 = pdf.create_bookmark("source1.pdf", optlist.str());
optlist.str(""); optlist << " index=-1 destination={page="<<pagecount1+1<<"}";
int cat2 = pdf.create_bookmark("source2.pdf", optlist.str());
pdf.end_document("");
}
catch (PDFlib::Exception& ex) {
std::cerr << "PDFlib异常: [" << ex.get_errnum() << "] "
<< ex.get_apiname() << ": " << ex.get_errmsg() << std::endl;
return 1;
}
return 0;
}
上面示例代码如上,其中将source1.pdf与source2.pdf合并称dest.pdf,并添加了目录。
&spm=1001.2101.3001.5002&articleId=158807274&d=1&t=3&u=4880276cd2ab46b0abfebc07e21b5bac)
2956

被折叠的 条评论
为什么被折叠?



