PDFlib

高度なPDFアプリケーションの開発を支援する定番プログラムライブラリー Supported by インフォテック株式会社

PDFlib サンプル集(クックブック)

本サンプルプログラムは、PDF 文書生成ライブラリーの実装である PDFlib の基本的な機能を実際のプログラムで紹介したものです。

本サイトでダウンロードした PDFlib は、一部機能の制限を除き、評価版として無償でお使いいただけます。

テーブルを使ったスケジュール表の作成

テーブルを使い、PDF のスケジュール表を作成します。

colspan と matchbox のオプションを利用し、結合したセルに色をつけています。

必要な製品:PDFlib または PDFlib+PDI または PPS


/*
 * Table schedule:
 * Create a weekly booking plan for the meeting rooms of a company
 * 
 * For the weekly bookings of the meeting rooms in a company, create a table
 * with each cell representing a period of time on a day of the week for a
 * certain meeting room. If a meeting room is booked for a certain period of 
 * time on a certain day of the week the corresponding cells will be colorized
 * and provided with some booking text. 
 * Use the "colwidth" and "rowheight" options of add_table_cell() to create the
 * table as a kind of grid with unique and fixed column width and row height. 
 * Use the "fitmethod=auto" option to decrease the font size if the booking text
 * is too large to fit completely into the cell.
 * Use the "matchbox" option of add_table_cell() to colorize cells.
 * 
 * The table is to be spread over two pages with a defined row being the last
 * one on the first page. Use the "return" option of add_table_cell() to force
 * fit_table() to a break after having placed the last row containing the cell. 
 *  
 * Required software: PDFlib/PDFlib+PDI/PPS 9
 * Required data: none
 */
package com.pdflib.cookbook.pdflib.table;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.Locale;

import com.pdflib.pdflib;
import com.pdflib.PDFlibException;

public class table_schedule
{
    public static void main (String argv[])
    {
    /* This is where the data files are. Adjust as necessary. */
    String searchpath = "../input";
    String outfile = "table_schedule.pdf";
    String title = "Table Schedule";
    
    pdflib p = null;
    int exitcode = 0;

    int row, col, tf=-1, tbl=-1;
    int i, j, t, regularfont, boldfont;
      
    String tlcell_opts;
    String fittab_opts, tfcell_opts;
     
    String result;
      
    final double pagewidth = 842, pageheight = 595;
    final double fontsize = 12;
    final double capheight = 8.5;
    final int margin = 4;
    final double rowheight1 = 16, rowheight2 = 32;
    final String leading = "120%";
      
    final int dayspan = 5, timespan=3, mroomspan = 2, croomspan=3;
    final double tstart = 5, tend = 22, tbreak = 12;
    
    /* The table coordinates are fixed */
    final int llx = 50, urx = (int) pagewidth - llx;
    final int lly = 120, ury = (int) pageheight - lly;
       
    final int yoffset = 15;
    final int yheading = ury + 2 * yoffset;
    final int ycontinued = lly - yoffset;
           
    /* The widths of the first and the other columns is fixed */
    final int cwfirst = 50, cwother = 30;
    
    final int maxdays = 6;
    
    final String days [] = {
        "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
    };
    
    final int maxrooms = 5;
    
    final String rooms [] = {
        "M1", "M2", "C1", "C2", "C3"
    };
    
    final int idxDay = 0, idxStart = 1, idxEnd = 2, idxRoom = 3;
    final int idxText = 4, idxColor = 5;
    
    final int maxbookings = 6;
    
    final String bookings [] [] = {
    /*   day, start, end,  room, text,                  color */
        {"1", "8",   "12", "1",  "Company Meeting",     "rgb 0.8 0.36 0.36"},
        {"2", "11",  "20", "4",  "Technical Workgroup", "rgb 1.0 0.84 0.0"},
        {"4", "8",   "16", "2",  "QM Meeting",          "rgb 0.0 0.8 0.82"},
        {"5", "10",  "12", "4",  "Admin Training",      "rgb 0.6 0.8 0.92"},
        {"5", "14",  "18", "4",  "Admin Training",      "rgb 0.6 0.8 0.92"},
        {"6", "14",  "22", "5",  "Admin Training",      "rgb 0.6 0.8 0.92"}
     };

      
    try {
        p = new pdflib();

        p.set_option("searchpath={" + searchpath + "}");
        
        /* This means we must check return values of load_font() etc. */
        p.set_option("errorpolicy=return");

        if (p.begin_document(outfile, "") == -1)
        throw new Exception("Error: " + p.get_errmsg());

        p.set_info("Creator", "PDFlib Cookbook");
        p.set_info("Title", title);

        /* Load the bold and regular styles of a font */
        boldfont = p.load_font("Helvetica-Bold", "unicode", "");
        if (boldfont == -1)
        throw new Exception("Error: " + p.get_errmsg());
        
        regularfont = p.load_font("Helvetica", "unicode", "");
        if (regularfont == -1)
        throw new Exception("Error: " + p.get_errmsg());
        
        /* Start the output page */
        p.begin_page_ext(pagewidth, pageheight, "");

        /* Output the heading */
        p.setfont(boldfont, fontsize);
        p.fit_textline("Booking Schedule", llx, yheading, "");
          
        /* Prepare the general option list for adding a Textflow.
         * For an exact vertical alignment of Textflow and text lines note the
         * following:
         * The height of an uppercase letter is exactly represented by the
         * capheight value of the font. For this reason use the capheight in the
         * font size specification. For example, a capheight of 8.5 will
         * approximately result in a font size of 12 points. 
         * "alignment=center" centers the text.
         * "leading" specifies the distance between to text lines.
         */
        final String tf_opts = "font=" + regularfont + " alignment=center" + 
        " fontsize={capheight=" + capheight + "} leading=" + leading; 


        /* -------------------------------------------------------------------
         * Add the Textflow cell containing the time heading which spans three
         * rows
         * -------------------------------------------------------------------
         */
        col = 1; row = 1;
        
        /* Add the Textflow to be placed in the heading cell */
        tf = p.add_textflow(-1, "Time\nfrom\nto", tf_opts);
        if (tf == -1)
        throw new Exception("Error: " + p.get_errmsg());
        
        /* Prepare the option list for adding the Textflow cell 
         * 
         * The first line of the Textflow should be aligned with the baseline of
         * the text lines. At the same time, the text lines should have the same
         * distance from the top cell border as the Textflow. To avoid any space
         * from the top add the Textflow cell using
         * "fittextflow={firstlinedist=capheight}".
         * "colwidth" defines the width of the first column the cell is spanned.
         * "rowheight" defines the row height.
         * "margin" adds some empty space between the text and the cell borders.
         * "colspan" defines the number of columns the cell is spanned.
         */
        tfcell_opts = 
        "textflow=" + tf + 
        " fittextflow={firstlinedist=capheight fitmethod=auto}" + 
        " colwidth=" + cwfirst +
        " rowheight=" + rowheight1 +
        " margin=" + margin +
        " rowspan=" + timespan;
        
        tbl = p.add_table_cell(tbl, col, row, "", tfcell_opts);
        
        if (tbl == -1)
        throw new Exception("Error: " + p.get_errmsg());
        
         
        /* -------------------------------------------------------------------
         * Add the text line cells containing the days of the week headings in
         * the first row, spanning several columns each
         * -------------------------------------------------------------------
         */
        col = 2; row = 1;
        
        /* Prepare the option list:
         * "position={center top}" positions the text on the top left. 
         * "fitmethod=auto" decreases the font size of the text if it is too
         * large to fit completely into the cell instead of increasing the row 
         * height.
         * The height of an uppercase letter is exactly represented by the
         * capheight value of the font. For this reason use the capheight in the
         * font size specification. For example, to match a row height of 16,
         * you could use a capheight of 8.5 and a margin of 4.
         * "fitmethod=auto" will decrease the font size, if necessary, until the
         * text line fits completely into the cell.
         * "colwidth" defines the width of the first column the cell is spanned.
         * "rowheight" defines the row height.
         * "margin" adds some empty space between the text and the cell borders.
         * "colspan" defines the number of columns the cell is spanned.
         */
        tlcell_opts = "fittextline={position={center top} fitmethod=auto" +
        " font=" + boldfont + " fontsize={capheight=" + capheight + "}} " +
        " colwidth=" + cwother +
        " rowheight=" + rowheight1 +
        " margin=" + margin +
        " colspan=" + dayspan;
             
        /* Add the table cells containing the days of the week */
        for (i = 0; i < maxdays; i++)
        {
        tbl = p.add_table_cell(tbl, col, row, days[i], tlcell_opts);
        
        if (tbl == -1)
            throw new Exception("Error adding cell: " + p.get_errmsg());
        
        col += dayspan;
        }
        
        
        /* --------------------------------------------------------------------
         * In the second row below each day of the week, add the "Meeting Room"
         * and "Conference Room" Textflow heading cells. The two cells together
         * span the same number of columns as spanned by the day of the week. 
         * --------------------------------------------------------------------
         */
        col = 2; row = 2;
        
        /* Loop over the number of days of the week */
        for (i = 0; i < maxdays; i++)
        {
        /* Add the "Meeting Room" Textflow */
        tf = p.add_textflow(-1, "Meeting Room", tf_opts);
        if (tf == -1)
            throw new Exception("Error: " + p.get_errmsg());
        
        /* Add the "Meeting Room" Textflow cell */
        tfcell_opts = "textflow=" + tf + 
            " fittextflow={firstlinedist=capheight fitmethod=auto}" + 
            " colwidth=" + cwother +
            " rowheight=" + rowheight2 +
            " margin=" + margin +
            " colspan=" + mroomspan;
               
        tbl = p.add_table_cell(tbl, col, row, "", tfcell_opts);
        
        if (tbl == -1)
            throw new Exception("Error: " + p.get_errmsg());
        
        col += mroomspan;
        
        /* Add the "Conference Room" Textflow */
        tf = p.add_textflow(-1, "Conference Room", tf_opts);
        if (tf == -1)
            throw new Exception("Error: " + p.get_errmsg());
        
        /* Add the "Conference Room" Textflow cell */
        tfcell_opts = "textflow=" + tf +
        " fittextflow={firstlinedist=capheight fitmethod=auto}" + 
        " colwidth=" + cwother + 
        " rowheight=" + rowheight2 +
        " margin=" + margin +
        " colspan=" + croomspan;
        
        tbl = p.add_table_cell(tbl, col, row, "", tfcell_opts);
        
        if (tbl == -1)
            throw new Exception("Error: " + p.get_errmsg());
        
        col += croomspan;
        }
        
        
        /* ---------------------------------------------------------------------
         * In the third row below the "Meeting Room" and "Conference Room" cells
         * for each day of the week add five text line heading cells containing
         * the names of the meeting rooms. 
         * ---------------------------------------------------------------------
         */
        col = 2; row = 3;
        
        /* Prepare the option list for adding the cells */
        tlcell_opts = "fittextline={position={center top} fitmethod=auto" +
        " font=" + regularfont + " fontsize={capheight=" + capheight + "}}"+
        " colwidth=" + cwother +
        " rowheight=" + rowheight1 +
        " margin=" + margin;
     
        /* Loop over the number of days of the week */
        for (i = 0; i < maxdays; i++)
        {
        /* Add the cells with the names of the room */
        for (j = 0; j < maxrooms; j++) {
            tbl = p.add_table_cell(tbl, col++, row, rooms[j], tlcell_opts);
            
            if (tbl == -1)
            throw new Exception("Error adding cell: " + p.get_errmsg());
        }
        }
        
        
        /* --------------------------------------------------------------
         * In the first column add the Textflow cells containing the time 
         * intervals, one cell for each hour
         * --------------------------------------------------------------
         */
        col = 1; row = 4;
        
        /* For outputting the time of the day, initialize the maximum number
         * of fraction digits to two
         */
        NumberFormat form = NumberFormat.getInstance(Locale.US);
        form.setMaximumFractionDigits(2);
        form.setMinimumFractionDigits(2);
        
        /* Loop over all time intervals */
        for (i = 1, t = (int) tstart; i <= tend - tstart; i++, t++)
        {
        /* Format the current time interval to a maximum of two fraction
         * digits
         */
        BigDecimal value = new BigDecimal(t);
        BigDecimal roundedValue = 
            value.setScale(2, RoundingMode.HALF_UP);
        
        String text = roundedValue.toString() + "\n";
        
        value = new BigDecimal(t+1);
        roundedValue = value.setScale(2, RoundingMode.HALF_UP);
        text += roundedValue.toString();
           
        /* Add the time interval Textflow */
        tf = p.add_textflow(-1, text, tf_opts);
        if (tf == -1)
            throw new Exception("Error: " + p.get_errmsg());
        
        /* Prepare the option list for adding the time interval headings */
        tfcell_opts = "textflow=" + tf + 
        " fittextflow={firstlinedist=capheight  fitmethod=auto}" + 
        " colwidth=" + cwfirst +
        " rowheight=" + rowheight2 +
        " margin=" + margin;
        
        /* We want to spread the table over two pages. The last row placed 
         * on the first page should be the one representing a defined time
         * interval, e.g. of 12-13. To accomplish this use the "return" 
         * option of add_table_cell() when adding the respective cell. This
         * signals to fit_table() to return after having placed the
         * corresponding table row, and we can fit the following table rows
         * in a subsequent call on the second page.    
         */
        if (t == tbreak)
            tfcell_opts += " return break";
        
        /* Add the time interval Textflow cell */
        tbl = p.add_table_cell(tbl, col, row++, "", tfcell_opts);
               
        if (tbl == -1)
            throw new Exception("Error adding cell: " + p.get_errmsg());
        }
        
        
        /* -----------------------------------------------------------------
         * For each booking item add a text line cell containing the booking
         * text and colorize it. Place the cell according to the day of the
         * week, time interval and meeting room affected.
         * -----------------------------------------------------------------
         */
        
        /* Loop over all bookings */
        for (i = 0; i < maxbookings; i++) {
        /* Read the attributes of the current booking */
        int start = Integer.valueOf(bookings[i][idxStart]).intValue();
        int end = Integer.valueOf(bookings[i][idxEnd]).intValue();
        int day = Integer.valueOf(bookings[i][idxDay]).intValue();
        int room = Integer.valueOf(bookings[i][idxRoom]).intValue();
        String text = bookings[i][idxText];
        
        /* Get the column and row as well as the number of rows spanned by
         * the cell
         */
        int rowspan = 1;
        
        col = 2 + ((day - 1) * dayspan) + (room - 1);
        row = 4 + (start - (int) tstart);
        
        if (end != start)
            rowspan = end - start;
        
        /* Prepare the option list for adding the booking item cell */
        String opts = "fittextline={position={center} " +
            " fitmethod=auto font=" + regularfont + " orientate=west" + 
            " fontsize={capheight=" + capheight + "}} " +
            " colwidth=" + cwother + 
            " rowheight=" + rowheight2 + 
            " margin=" + margin + 
            " rowspan=" + rowspan + 
            " matchbox={fillcolor={" + bookings[i][idxColor] + "}}";
        
        tbl = p.add_table_cell(tbl, col, row, text, opts);
        if (tbl == -1)
            throw new Exception("Error adding cell: " + p.get_errmsg());    
        }
            
         
        /* ------------------------------------
         * Place the table on one or more pages
         * ------------------------------------
         */

        /* Prepare the option list for fitting the table.
         * "header=3" will repeat the first three rows at the beginning of
         * each new page. The "stroke" option will stroke lines with two 
         * different line widths. The table frame as well as each vertical
         * line to the right of a day-of-the-week cell is stroked with a
         * line width of 1, all other lines are stroked with a line width of
         * 0.3.
         */
        fittab_opts = "header=3 stroke={" +
        "{line=frame linewidth=1} {line=other linewidth=0.3} ";
        
        for (i = 0; i < maxdays; i++)
        fittab_opts += "{line=vert" + (1+i*maxrooms) + " linewidth=1} ";     
              
        fittab_opts += "}";
        
        /* Loop until all of the table is placed; create new pages as long as
         * more table instances need to be placed
         */
        do {
        /* Place the table instance */
        result = p.fit_table(tbl, llx, lly, urx, ury, fittab_opts);

        if (result.equals("_error"))
            throw new Exception ("Couldn't place table: " +
            p.get_errmsg());
        
        /* A return value of "break" has been explicitly specified in 
         * add_table_cell() when adding the cell for a certain time interval
         * after which a new page shall be started. 
         */
        if (result.equals("_boxfull") || result.equals("break")) {
            p.setfont(regularfont, fontsize);
            p.fit_textline("-- Continued --", urx, ycontinued, 
            "position {right top}");
            
            p.end_page_ext("");
            p.begin_page_ext(pagewidth, pageheight, "");
        }
        } while (result.equals("_boxfull") || result.equals("break"));
        
        p.end_page_ext("");
       
        p.end_document("");
      
        } catch (PDFlibException e) {
            System.err.println("PDFlib exception occurred:");
            System.err.println("[" + e.get_errnum() + "] " + e.get_apiname() +
                ": " + e.get_errmsg());
        exitcode = 1;
        } catch (Exception e) {
            System.err.println(e.toString());
        exitcode = 1;
        } finally {
            if (p != null) {
                p.delete();
            }
        System.exit(exitcode);
        }
    }
}
(Sep 18, 2013 - Oct 23, 2022)