PDFlib使用(三)

九.表格示例

以下示例中,均假设中文宋体字库已放到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 =
        "&#x4f60;&#x597d;&#x3C;\n"
        "<fontsize=14>工业大数据\n"
        "<fontsize=10>工业是国民经济的基础和支柱,也是一国经济实力和竞争力的重要标志。随着云计算、大数据和物联网等新兴技术的发展,\n"
        "全球掀起了以制造业转型升级为首要任务的新一轮工业变革,世界上主要的工业发达体纷纷制定工业再发展战略。\n"
        "&#x3C;工业大数据应用热点\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,并添加了目录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值