mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2024-12-25 12:58:21 +01:00
Save work on docos.
This commit is contained in:
parent
52b508bdd2
commit
5dc68f3285
241
doc/pdfio.md
241
doc/pdfio.md
@ -1425,9 +1425,8 @@ Four functions handle the formatting of the markdown document:
|
|||||||
- `format_table`: formats a table.
|
- `format_table`: formats a table.
|
||||||
|
|
||||||
Formatted content is organized into arrays of `linefrag_t` and `tablerow_t`
|
Formatted content is organized into arrays of `linefrag_t` and `tablerow_t`
|
||||||
structures for a line of content or row of table cells, respectively. These
|
structures for a line of content or row of table cells, respectively.
|
||||||
are passed to the `render_line` and `render_row` functions to actually produce
|
|
||||||
content in the PDF document.
|
|
||||||
|
|
||||||
#### High-Level Formatting
|
#### High-Level Formatting
|
||||||
|
|
||||||
@ -2037,196 +2036,92 @@ format_table(docdata_t *dd, // I - Document data
|
|||||||
|
|
||||||
### Rendering the Markdown Document
|
### Rendering the Markdown Document
|
||||||
|
|
||||||
|
The formatted content in arrays of `linefrag_t` and `tablerow_t` structures
|
||||||
|
are passed to the `render_line` and `render_row` functions respectively to
|
||||||
|
produce content in the PDF document.
|
||||||
|
|
||||||
|
|
||||||
#### Rendering a Line in a Paragraph, Heading, or Table Cell
|
#### Rendering a Line in a Paragraph, Heading, or Table Cell
|
||||||
|
|
||||||
|
The `render_line` function adds content from the `linefrag_t` array to a PDF
|
||||||
|
page. It starts by determining whether a new page is needed:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
static void
|
if (!dd->st)
|
||||||
render_line(docdata_t *dd, // I - Document data
|
|
||||||
double margin_left, // I - Left margin
|
|
||||||
double margin_top, // I - Top margin
|
|
||||||
double need_bottom, // I - How much space is needed after
|
|
||||||
double lineheight, // I - Height of line
|
|
||||||
size_t num_frags, // I - Number of line fragments
|
|
||||||
linefrag_t *frags) // I - Line fragments
|
|
||||||
{
|
{
|
||||||
size_t i; // Looping var
|
new_page(dd);
|
||||||
linefrag_t *frag; // Current line fragment
|
margin_top = 0.0;
|
||||||
bool in_text = false; // Are we in a text block?
|
}
|
||||||
|
|
||||||
|
dd->y -= margin_top + lineheight;
|
||||||
|
if ((dd->y - need_bottom) < dd->art_box.y1)
|
||||||
|
{
|
||||||
|
new_page(dd);
|
||||||
|
|
||||||
if (!dd->st)
|
dd->y -= lineheight;
|
||||||
{
|
|
||||||
new_page(dd);
|
|
||||||
margin_top = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd->y -= margin_top + lineheight;
|
|
||||||
if ((dd->y - need_bottom) < dd->art_box.y1)
|
|
||||||
{
|
|
||||||
new_page(dd);
|
|
||||||
|
|
||||||
dd->y -= lineheight;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, frag = frags; i < num_frags; i ++, frag ++)
|
|
||||||
{
|
|
||||||
if (frag->type == MMD_TYPE_CHECKBOX)
|
|
||||||
{
|
|
||||||
// Draw checkbox...
|
|
||||||
set_color(dd, frag->color);
|
|
||||||
|
|
||||||
if (in_text)
|
|
||||||
{
|
|
||||||
pdfioContentTextEnd(dd->st);
|
|
||||||
in_text = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add box
|
|
||||||
pdfioContentPathRect(dd->st, frag->x + 1.0 + margin_left, dd->y, frag->width - 3.0, frag->height - 3.0);
|
|
||||||
|
|
||||||
if (frag->text)
|
|
||||||
{
|
|
||||||
// Add check
|
|
||||||
pdfioContentPathMoveTo(dd->st, frag->x + 3.0 + margin_left, dd->y + 2.0);
|
|
||||||
pdfioContentPathLineTo(dd->st, frag->x + frag->width - 4.0 + margin_left, dd->y + frag->height - 5.0);
|
|
||||||
|
|
||||||
pdfioContentPathMoveTo(dd->st, frag->x + 3.0 + margin_left, dd->y + frag->height - 5.0);
|
|
||||||
pdfioContentPathLineTo(dd->st, frag->x + frag->width - 4.0 + margin_left, dd->y + 2.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioContentStroke(dd->st);
|
|
||||||
}
|
|
||||||
else if (frag->text)
|
|
||||||
{
|
|
||||||
// Draw text
|
|
||||||
if (!in_text)
|
|
||||||
{
|
|
||||||
pdfioContentTextBegin(dd->st);
|
|
||||||
pdfioContentTextMoveTo(dd->st, frag->x + margin_left, dd->y);
|
|
||||||
|
|
||||||
in_text = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frag->ws && frag->font == DOCFONT_MONOSPACE)
|
|
||||||
{
|
|
||||||
set_font(dd, DOCFONT_REGULAR, frag->height);
|
|
||||||
pdfioContentTextShow(dd->st, UNICODE_VALUE, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
set_color(dd, frag->color);
|
|
||||||
set_font(dd, frag->font, frag->height);
|
|
||||||
|
|
||||||
if (frag->font == DOCFONT_MONOSPACE)
|
|
||||||
pdfioContentTextShow(dd->st, UNICODE_VALUE, frag->text);
|
|
||||||
else
|
|
||||||
pdfioContentTextShowf(dd->st, UNICODE_VALUE, "%s%s", frag->ws ? " " : "", frag->text);
|
|
||||||
|
|
||||||
if (frag->url && dd->num_links < DOCLINK_MAX)
|
|
||||||
{
|
|
||||||
doclink_t *l = dd->links + dd->num_links;
|
|
||||||
// Pointer to this link record
|
|
||||||
|
|
||||||
if (!strcmp(frag->url, "@"))
|
|
||||||
{
|
|
||||||
// Use mapped text as link target...
|
|
||||||
char targetlink[129]; // Targeted link
|
|
||||||
|
|
||||||
targetlink[0] = '#';
|
|
||||||
make_target_name(targetlink + 1, frag->text, sizeof(targetlink) - 1);
|
|
||||||
|
|
||||||
l->url = pdfioStringCreate(dd->pdf, targetlink);
|
|
||||||
}
|
|
||||||
else if (!strcmp(frag->url, "@@"))
|
|
||||||
{
|
|
||||||
// Use literal text as anchor...
|
|
||||||
l->url = pdfioStringCreatef(dd->pdf, "#%s", frag->text);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Use URL as-is...
|
|
||||||
l->url = frag->url;
|
|
||||||
}
|
|
||||||
|
|
||||||
l->box.x1 = frag->x;
|
|
||||||
l->box.y1 = dd->y;
|
|
||||||
l->box.x2 = frag->x + frag->width;
|
|
||||||
l->box.y2 = dd->y + frag->height;
|
|
||||||
|
|
||||||
dd->num_links ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Draw image
|
|
||||||
char imagename[32]; // Current image name
|
|
||||||
|
|
||||||
if (in_text)
|
|
||||||
{
|
|
||||||
pdfioContentTextEnd(dd->st);
|
|
||||||
in_text = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(imagename, sizeof(imagename), "I%u", (unsigned)frag->imagenum);
|
|
||||||
pdfioContentDrawImage(dd->st, imagename, frag->x + margin_left, dd->y, frag->width, frag->height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_text)
|
|
||||||
pdfioContentTextEnd(dd->st);
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Rendering a Table Row
|
We then loops through the fragments for the current line, drawing checkboxes,
|
||||||
|
images, and text as needed. When a hyperlink is present, we add the link to the
|
||||||
|
`links` array in the `docdata_t` structure, mapping "@" and "@@" to an internal
|
||||||
|
link corresponding to the linked text:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
static void
|
if (frag->url && dd->num_links < DOCLINK_MAX)
|
||||||
render_row(docdata_t *dd, // I - Document data
|
|
||||||
size_t num_cols, // I - Number of columns
|
|
||||||
tablecol_t *cols, // I - Column information
|
|
||||||
tablerow_t *row) // I - Row
|
|
||||||
{
|
{
|
||||||
size_t col; // Current column
|
doclink_t *l = dd->links + dd->num_links;
|
||||||
double row_y; // Start of row
|
// Pointer to this link record
|
||||||
docfont_t deffont; // Default font
|
|
||||||
|
|
||||||
|
if (!strcmp(frag->url, "@"))
|
||||||
// Start a new page as needed...
|
|
||||||
if (!dd->st)
|
|
||||||
new_page(dd);
|
|
||||||
|
|
||||||
if ((dd->y - row->height) < dd->art_box.y1)
|
|
||||||
new_page(dd);
|
|
||||||
|
|
||||||
if (mmdGetType(row->cells[0]) == MMD_TYPE_TABLE_HEADER_CELL)
|
|
||||||
{
|
{
|
||||||
// Header row, no border...
|
// Use mapped text as link target...
|
||||||
deffont = DOCFONT_BOLD;
|
char targetlink[129]; // Targeted link
|
||||||
|
|
||||||
|
targetlink[0] = '#';
|
||||||
|
make_target_name(targetlink + 1, frag->text, sizeof(targetlink) - 1);
|
||||||
|
|
||||||
|
l->url = pdfioStringCreate(dd->pdf, targetlink);
|
||||||
|
}
|
||||||
|
else if (!strcmp(frag->url, "@@"))
|
||||||
|
{
|
||||||
|
// Use literal text as anchor...
|
||||||
|
l->url = pdfioStringCreatef(dd->pdf, "#%s", frag->text);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Regular body row, add borders...
|
// Use URL as-is...
|
||||||
deffont = DOCFONT_REGULAR;
|
l->url = frag->url;
|
||||||
|
|
||||||
set_color(dd, DOCCOLOR_GRAY);
|
|
||||||
pdfioContentPathRect(dd->st, cols[0].left - TABLE_PADDING, dd->y - row->height, cols[num_cols - 1].right - cols[0].left + 2.0 * TABLE_PADDING, row->height);
|
|
||||||
for (col = 1; col < num_cols; col ++)
|
|
||||||
{
|
|
||||||
pdfioContentPathMoveTo(dd->st, cols[col].left - TABLE_PADDING, dd->y);
|
|
||||||
pdfioContentPathLineTo(dd->st, cols[col].left - TABLE_PADDING, dd->y - row->height);
|
|
||||||
}
|
|
||||||
pdfioContentStroke(dd->st);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
row_y = dd->y;
|
l->box.x1 = frag->x;
|
||||||
|
l->box.y1 = dd->y;
|
||||||
|
l->box.x2 = frag->x + frag->width;
|
||||||
|
l->box.y2 = dd->y + frag->height;
|
||||||
|
|
||||||
for (col = 0; col < num_cols; col ++)
|
dd->num_links ++;
|
||||||
{
|
|
||||||
dd->y = row_y;
|
|
||||||
|
|
||||||
format_block(dd, row->cells[col], deffont, SIZE_TABLE, cols[col].left, cols[col].right, /*leader*/NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
dd->y = row_y - row->height;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
These are later written as annotations in the `add_links` function.
|
||||||
|
|
||||||
|
|
||||||
|
#### Rendering a Table Row
|
||||||
|
|
||||||
|
The `render_row` function takes a row of cells and the corresponding column
|
||||||
|
definitions, draws the border boxes around body cells, and then formats each
|
||||||
|
cell using the `format_block` function described previously. The key is to
|
||||||
|
reset the page `y` value before formatting each cell:
|
||||||
|
|
||||||
|
```c
|
||||||
|
row_y = dd->y;
|
||||||
|
|
||||||
|
for (col = 0; col < num_cols; col ++)
|
||||||
|
{
|
||||||
|
dd->y = row_y;
|
||||||
|
|
||||||
|
format_block(dd, row->cells[col], deffont, SIZE_TABLE, cols[col].left, cols[col].right, /*leader*/NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
dd->y = row_y - row->height;
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user