mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2024-12-26 13:28:22 +01:00
Compare commits
3 Commits
b8b9d7ef8a
...
d3d6683041
Author | SHA1 | Date | |
---|---|---|---|
|
d3d6683041 | ||
|
0d08dd5f1b | ||
|
00c9905317 |
@ -10,6 +10,8 @@ v1.4.0 - YYYY-MM-DD
|
||||
- Added new `pdfioFileCreateNameObj` and `pdfioObjGetName` APIs for creating and
|
||||
getting name object values (Issue #76)
|
||||
- Updated documentation (Issue #78)
|
||||
- Updated `pdfioContentTextMeasure` to support measuring PDF base fonts created
|
||||
with `pdfioFileCreateFontObjFromBase` (Issue #84)
|
||||
- Fixed reading of PDF files whose trailer is missing a newline (Issue #80)
|
||||
- Fixed builds with some versions of VC++ (Issue #81)
|
||||
|
||||
|
@ -93,6 +93,7 @@ typedef struct docdata_s // Document formatting data
|
||||
|
||||
typedef struct linefrag_s // Line fragment
|
||||
{
|
||||
mmd_type_t type; // Type of fragment
|
||||
double x, // X position of item
|
||||
width, // Width of item
|
||||
height; // Height of item
|
||||
@ -105,6 +106,25 @@ typedef struct linefrag_s // Line fragment
|
||||
|
||||
#define LINEFRAG_MAX 200 // Maximum number of fragments on a line
|
||||
|
||||
typedef struct tablecol_s // Table column data
|
||||
{
|
||||
double min_width, // Minimum required width of column
|
||||
max_width, // Maximum required width of column
|
||||
width, // Width of column
|
||||
left, // Left edge
|
||||
right; // Right edge
|
||||
} tablecol_t;
|
||||
|
||||
#define TABLECOL_MAX 20 // Maximum number of table columns
|
||||
|
||||
typedef struct tablerow_s // Table row
|
||||
{
|
||||
mmd_t *cells[TABLECOL_MAX]; // Cells in row
|
||||
double height; // Row height
|
||||
} tablerow_t;
|
||||
|
||||
#define TABLEROW_MAX 1000 // Maximum number of table rows
|
||||
|
||||
|
||||
//
|
||||
// Macros...
|
||||
@ -118,6 +138,10 @@ typedef struct linefrag_s // Line fragment
|
||||
// Constants...
|
||||
//
|
||||
|
||||
#define USE_TRUETYPE 1 // Set to 1 to use Roboto TrueType fonts
|
||||
|
||||
#if USE_TRUETYPE
|
||||
# define UNICODE_VALUE true // `true` for Unicode text, `false` for ISO-8859-1
|
||||
static const char * const docfont_filenames[] =
|
||||
{
|
||||
"Roboto-Regular.ttf",
|
||||
@ -125,6 +149,16 @@ static const char * const docfont_filenames[] =
|
||||
"Roboto-Italic.ttf",
|
||||
"RobotoMono-Regular.ttf"
|
||||
};
|
||||
#else
|
||||
# define UNICODE_VALUE false // `true` for Unicode text, `false` for ISO-8859-1
|
||||
static const char * const docfont_filenames[] =
|
||||
{
|
||||
"Helvetica",
|
||||
"Helvetica-Bold",
|
||||
"Helvetica-Oblique",
|
||||
"Courier"
|
||||
};
|
||||
#endif // USE_TRUETYPE
|
||||
|
||||
static const char * const docfont_names[] =
|
||||
{
|
||||
@ -134,6 +168,8 @@ static const char * const docfont_names[] =
|
||||
"FM"
|
||||
};
|
||||
|
||||
#define IMAGE_PPI 100.0 // Pixels per inch for images
|
||||
|
||||
#define LINE_HEIGHT 1.4 // Multiplier for line height
|
||||
|
||||
#define SIZE_BODY 11.0 // Size of body text (points)
|
||||
@ -159,7 +195,7 @@ static const char * const docfont_names[] =
|
||||
// Vertical position of header
|
||||
#define PAGE_FOOTER in2pt(0.5) // Vertical position of footer
|
||||
|
||||
#define UNICODE_VALUE true // `true` for Unicode text, `false` for ISO-8859-1
|
||||
#define TABLE_PADDING 4.5 // Table padding value
|
||||
|
||||
|
||||
//
|
||||
@ -221,8 +257,6 @@ add_images(docdata_t *dd, // I - Document data
|
||||
url = mmdGetURL(current);
|
||||
ext = strrchr(url, '.');
|
||||
|
||||
// fprintf(stderr, "IMAGE(%s), ext=\"%s\"\n", url, ext);
|
||||
|
||||
if (!access(url, 0) && ext && (!strcmp(ext, ".png") || !strcmp(ext, ".jpg") || !strcmp(ext, ".jpeg")))
|
||||
{
|
||||
// Local JPEG or PNG file, so add it if we haven't already...
|
||||
@ -246,6 +280,38 @@ add_images(docdata_t *dd, // I - Document data
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'find_image()' - Find an image in the document.
|
||||
//
|
||||
|
||||
static pdfio_obj_t * // O - Image object or `NULL` if none
|
||||
find_image(docdata_t *dd, // I - Document data
|
||||
const char *url, // I - Image URL
|
||||
size_t *imagenum) // O - Image number
|
||||
{
|
||||
size_t i; // Looping var
|
||||
|
||||
|
||||
// Look for a matching URL...
|
||||
for (i = 0; i < dd->num_images; i ++)
|
||||
{
|
||||
if (!strcmp(dd->images[i].url, url))
|
||||
{
|
||||
if (imagenum)
|
||||
*imagenum = i;
|
||||
|
||||
return (dd->images[i].obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, return NULL...
|
||||
if (imagenum)
|
||||
*imagenum = 0;
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'set_color()' - Set the stroke and fill color as needed.
|
||||
//
|
||||
@ -418,6 +484,7 @@ new_page(docdata_t *dd) // I - Document data
|
||||
|
||||
static void
|
||||
render_line(docdata_t *dd, // I - Document data
|
||||
double margin_left, // I - Left margin
|
||||
double margin_top, // I - Top margin
|
||||
double lineheight, // I - Height of line
|
||||
size_t num_frags, // I - Number of line fragments
|
||||
@ -439,22 +506,44 @@ render_line(docdata_t *dd, // I - Document data
|
||||
dd->y -= lineheight;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "num_frags=%u, y=%g\n", (unsigned)num_frags, dd->y);
|
||||
|
||||
for (i = 0, frag = frags; i < num_frags; i ++, frag ++)
|
||||
{
|
||||
if (frag->text)
|
||||
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
|
||||
// fprintf(stderr, " text=\"%s\", font=%d, color=%d, x=%g\n", frag->text, frag->font, frag->color, frag->x);
|
||||
|
||||
set_color(dd, frag->color);
|
||||
set_font(dd, frag->font, frag->height);
|
||||
|
||||
if (!in_text)
|
||||
{
|
||||
pdfioContentTextBegin(dd->st);
|
||||
pdfioContentTextMoveTo(dd->st, frag->x, dd->y);
|
||||
pdfioContentTextMoveTo(dd->st, frag->x + margin_left, dd->y);
|
||||
|
||||
in_text = true;
|
||||
}
|
||||
@ -469,8 +558,6 @@ render_line(docdata_t *dd, // I - Document data
|
||||
// Draw image
|
||||
char imagename[32]; // Current image name
|
||||
|
||||
// fprintf(stderr, " imagenum=%u, x=%g, width=%g, height=%g\n", (unsigned)frag->imagenum, frag->x, frag->width, frag->height);
|
||||
|
||||
if (in_text)
|
||||
{
|
||||
pdfioContentTextEnd(dd->st);
|
||||
@ -478,7 +565,7 @@ render_line(docdata_t *dd, // I - Document data
|
||||
}
|
||||
|
||||
snprintf(imagename, sizeof(imagename), "I%u", (unsigned)frag->imagenum);
|
||||
pdfioContentDrawImage(dd->st, imagename, frag->x, dd->y, frag->width, frag->height);
|
||||
pdfioContentDrawImage(dd->st, imagename, frag->x + margin_left, dd->y, frag->width, frag->height);
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,13 +604,18 @@ format_block(docdata_t *dd, // I - Document data
|
||||
double x, // Current position
|
||||
width, // Width of current fragment
|
||||
wswidth, // Width of whitespace
|
||||
margin_left, // Left margin
|
||||
margin_top, // Top margin
|
||||
height, // Height of current fragment
|
||||
lineheight; // Height of current line
|
||||
|
||||
|
||||
blocktype = mmdGetType(block);
|
||||
margin_top = fsize * LINE_HEIGHT;
|
||||
|
||||
if (blocktype >= MMD_TYPE_TABLE_HEADER_CELL && blocktype <= MMD_TYPE_TABLE_BODY_CELL_RIGHT)
|
||||
margin_top = 0.0;
|
||||
else
|
||||
margin_top = fsize * LINE_HEIGHT;
|
||||
|
||||
if (leader)
|
||||
{
|
||||
@ -560,31 +652,16 @@ format_block(docdata_t *dd, // I - Document data
|
||||
wswidth = 0.0;
|
||||
next = mmd_walk_next(block, current);
|
||||
|
||||
if (type == MMD_TYPE_CHECKBOX)
|
||||
text = text ? "[x]" : "[ ]";
|
||||
|
||||
// Process the node...
|
||||
if (type == MMD_TYPE_IMAGE && url)
|
||||
{
|
||||
// Embed an image
|
||||
size_t i; // Looping var
|
||||
|
||||
for (i = 0; i < dd->num_images; i ++)
|
||||
{
|
||||
if (!strcmp(dd->images[i].url, url))
|
||||
{
|
||||
image = dd->images[i].obj;
|
||||
imagenum = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!image)
|
||||
if ((image = find_image(dd, url, &imagenum)) == NULL)
|
||||
continue;
|
||||
|
||||
// Image - treat as 100dpi
|
||||
width = 72.0 * pdfioImageGetWidth(image) / 100.0;
|
||||
height = 72.0 * pdfioImageGetHeight(image) / 100.0;
|
||||
width = 72.0 * pdfioImageGetWidth(image) / IMAGE_PPI;
|
||||
height = 72.0 * pdfioImageGetHeight(image) / IMAGE_PPI;
|
||||
text = NULL;
|
||||
|
||||
if (width > (right - left))
|
||||
@ -602,7 +679,14 @@ format_block(docdata_t *dd, // I - Document data
|
||||
}
|
||||
else if (type == MMD_TYPE_HARD_BREAK && num_frags > 0)
|
||||
{
|
||||
render_line(dd, margin_top, lineheight, num_frags, frags);
|
||||
if (blocktype == MMD_TYPE_TABLE_HEADER_CELL || blocktype == MMD_TYPE_TABLE_BODY_CELL_CENTER)
|
||||
margin_left = 0.5 * (right - x);
|
||||
else if (blocktype == MMD_TYPE_TABLE_BODY_CELL_RIGHT)
|
||||
margin_left = right - x;
|
||||
else
|
||||
margin_left = 0.0;
|
||||
|
||||
render_line(dd, margin_left, margin_top, lineheight, num_frags, frags);
|
||||
|
||||
num_frags = 0;
|
||||
frag = frags;
|
||||
@ -612,6 +696,11 @@ format_block(docdata_t *dd, // I - Document data
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (type == MMD_TYPE_CHECKBOX)
|
||||
{
|
||||
// Checkbox
|
||||
width = height = fsize;
|
||||
}
|
||||
else if (!text)
|
||||
{
|
||||
continue;
|
||||
@ -646,7 +735,14 @@ format_block(docdata_t *dd, // I - Document data
|
||||
if ((num_frags > 0 && (x + width + wswidth) >= right) || num_frags == LINEFRAG_MAX)
|
||||
{
|
||||
// No, render this line and start over...
|
||||
render_line(dd, margin_top, lineheight, num_frags, frags);
|
||||
if (blocktype == MMD_TYPE_TABLE_HEADER_CELL || blocktype == MMD_TYPE_TABLE_BODY_CELL_CENTER)
|
||||
margin_left = 0.5 * (right - x);
|
||||
else if (blocktype == MMD_TYPE_TABLE_BODY_CELL_RIGHT)
|
||||
margin_left = right - x;
|
||||
else
|
||||
margin_left = 0.0;
|
||||
|
||||
render_line(dd, margin_left, margin_top, lineheight, num_frags, frags);
|
||||
|
||||
num_frags = 0;
|
||||
frag = frags;
|
||||
@ -662,6 +758,7 @@ format_block(docdata_t *dd, // I - Document data
|
||||
wswidth = 0.0;
|
||||
}
|
||||
|
||||
frag->type = type;
|
||||
frag->x = x;
|
||||
frag->width = width + wswidth;
|
||||
frag->height = text ? fsize : height;
|
||||
@ -679,7 +776,16 @@ format_block(docdata_t *dd, // I - Document data
|
||||
}
|
||||
|
||||
if (num_frags > 0)
|
||||
render_line(dd, margin_top, lineheight, num_frags, frags);
|
||||
{
|
||||
if (blocktype == MMD_TYPE_TABLE_HEADER_CELL || blocktype == MMD_TYPE_TABLE_BODY_CELL_CENTER)
|
||||
margin_left = 0.5 * (right - x);
|
||||
else if (blocktype == MMD_TYPE_TABLE_BODY_CELL_RIGHT)
|
||||
margin_left = right - x;
|
||||
else
|
||||
margin_left = 0.0;
|
||||
|
||||
render_line(dd, margin_left, margin_top, lineheight, num_frags, frags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -746,6 +852,329 @@ format_code(docdata_t *dd, // I - Document data
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'measure_cell()' - Measure the dimensions of a table cell.
|
||||
//
|
||||
|
||||
static double // O - Formatted height
|
||||
measure_cell(docdata_t *dd, // I - Document data
|
||||
mmd_t *cell, // I - Cell node
|
||||
tablecol_t *col) // O - Column data
|
||||
{
|
||||
mmd_t *current, // Current node
|
||||
*next; // Next node
|
||||
mmd_type_t type; // Node type
|
||||
const char *text, // Current text
|
||||
*url; // Current URL, if any
|
||||
bool ws; // Current whitespace
|
||||
docfont_t font; // Current font
|
||||
double x = 0.0, // Current X position
|
||||
width, // Width of node
|
||||
wswidth, // Width of whitespace
|
||||
height, // Height of node
|
||||
lineheight = 0.0, // Height of line
|
||||
cellheight = 0.0; // Height of cell
|
||||
|
||||
|
||||
for (current = mmdGetFirstChild(cell); current; current = next)
|
||||
{
|
||||
next = mmd_walk_next(cell, current);
|
||||
type = mmdGetType(current);
|
||||
text = mmdGetText(current);
|
||||
url = mmdGetURL(current);
|
||||
ws = mmdGetWhitespace(current);
|
||||
wswidth = 0.0;
|
||||
|
||||
if (type == MMD_TYPE_IMAGE && url)
|
||||
{
|
||||
// Embed an image
|
||||
pdfio_obj_t *image = find_image(dd, url, /*imagenum*/NULL);
|
||||
// Image object
|
||||
|
||||
if (!image)
|
||||
continue;
|
||||
|
||||
// Image - treat as 100dpi
|
||||
width = 72.0 * pdfioImageGetWidth(image) / IMAGE_PPI;
|
||||
height = 72.0 * pdfioImageGetHeight(image) / IMAGE_PPI;
|
||||
|
||||
if (col->width > 0.0 && width > col->width)
|
||||
{
|
||||
// Too wide, scale to width...
|
||||
width = col->width;
|
||||
height = width * pdfioImageGetHeight(image) / pdfioImageGetWidth(image);
|
||||
}
|
||||
else if (height > (dd->art_box.y2 - dd->art_box.y1))
|
||||
{
|
||||
// Too tall, scale to height...
|
||||
height = dd->art_box.y2 - dd->art_box.y1;
|
||||
width = height * pdfioImageGetWidth(image) / pdfioImageGetHeight(image);
|
||||
}
|
||||
}
|
||||
else if (type == MMD_TYPE_HARD_BREAK && x > 0.0)
|
||||
{
|
||||
// Hard break...
|
||||
if (x > col->max_width)
|
||||
col->max_width = x;
|
||||
|
||||
cellheight += lineheight;
|
||||
x = 0.0;
|
||||
lineheight = 0.0;
|
||||
continue;
|
||||
}
|
||||
else if (type == MMD_TYPE_CHECKBOX)
|
||||
{
|
||||
// Checkbox...
|
||||
width = height = SIZE_TABLE;
|
||||
}
|
||||
else if (!text)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Text fragment...
|
||||
if (type == MMD_TYPE_EMPHASIZED_TEXT)
|
||||
font = DOCFONT_ITALIC;
|
||||
else if (type == MMD_TYPE_STRONG_TEXT)
|
||||
font = DOCFONT_BOLD;
|
||||
else if (type == MMD_TYPE_CODE_TEXT)
|
||||
font = DOCFONT_MONOSPACE;
|
||||
else if (mmdGetType(cell) == MMD_TYPE_TABLE_HEADER_CELL)
|
||||
font = DOCFONT_BOLD;
|
||||
else
|
||||
font = DOCFONT_REGULAR;
|
||||
|
||||
width = pdfioContentTextMeasure(dd->fonts[font], text, SIZE_TABLE);
|
||||
height = SIZE_TABLE * LINE_HEIGHT;
|
||||
|
||||
if (ws && x > 0.0)
|
||||
wswidth = pdfioContentTextMeasure(dd->fonts[font], " ", SIZE_TABLE);
|
||||
}
|
||||
|
||||
if (width > col->min_width)
|
||||
col->min_width = width;
|
||||
|
||||
// See if this node will fit on the current line
|
||||
if (col->width > 0.0 && (x + width + wswidth) >= col->width)
|
||||
{
|
||||
// No, record the new line...
|
||||
if (x > col->max_width)
|
||||
col->max_width = x;
|
||||
|
||||
cellheight += lineheight;
|
||||
x = 0.0;
|
||||
lineheight = 0.0;
|
||||
wswidth = 0.0;
|
||||
}
|
||||
|
||||
x += width + wswidth;
|
||||
|
||||
if (height > lineheight)
|
||||
lineheight = height;
|
||||
}
|
||||
|
||||
// Capture the last line's measurements...
|
||||
if (x > col->max_width)
|
||||
col->max_width = x;
|
||||
|
||||
if (x > 0.0)
|
||||
cellheight += lineheight;
|
||||
|
||||
// Return the total height...
|
||||
return (cellheight);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'render_row()' - Render a table row...
|
||||
//
|
||||
|
||||
static void
|
||||
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
|
||||
double row_y; // Start of row
|
||||
docfont_t deffont; // Default font
|
||||
|
||||
|
||||
// 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...
|
||||
deffont = DOCFONT_BOLD;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Regular body row, add borders...
|
||||
deffont = DOCFONT_REGULAR;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'format_table()' - Format a table...
|
||||
//
|
||||
|
||||
static void
|
||||
format_table(docdata_t *dd, // I - Document data
|
||||
mmd_t *table, // I - Table node
|
||||
double left, // I - Left margin
|
||||
double right) // I - Right margin
|
||||
{
|
||||
mmd_t *current, // Current node
|
||||
*next; // Next node
|
||||
mmd_type_t type; // Node type
|
||||
size_t col, // Current column
|
||||
num_cols; // Number of columns
|
||||
tablecol_t cols[TABLECOL_MAX]; // Columns
|
||||
size_t row, // Current row
|
||||
num_rows; // Number of rows
|
||||
tablerow_t rows[TABLEROW_MAX], // Rows
|
||||
*rowptr; // Pointer to current row
|
||||
double x, // Current X position
|
||||
height, // Height of cell
|
||||
format_width, // Maximum format width of table
|
||||
table_width; // Total width of table
|
||||
|
||||
|
||||
// Find all of the rows and columns in the table...
|
||||
num_cols = num_rows = 0;
|
||||
|
||||
memset(cols, 0, sizeof(cols));
|
||||
memset(rows, 0, sizeof(rows));
|
||||
|
||||
rowptr = rows;
|
||||
|
||||
for (current = mmdGetFirstChild(table); current && num_rows < TABLEROW_MAX; current = next)
|
||||
{
|
||||
next = mmd_walk_next(table, current);
|
||||
type = mmdGetType(current);
|
||||
|
||||
if (type == MMD_TYPE_TABLE_ROW)
|
||||
{
|
||||
// Parse row...
|
||||
for (col = 0, current = mmdGetFirstChild(current); current && num_cols < TABLECOL_MAX; current = mmdGetNextSibling(current), col ++)
|
||||
{
|
||||
rowptr->cells[col] = current;
|
||||
|
||||
measure_cell(dd, current, cols + col);
|
||||
|
||||
if (col >= num_cols)
|
||||
num_cols = col + 1;
|
||||
}
|
||||
|
||||
rowptr ++;
|
||||
num_rows ++;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out the width of each column...
|
||||
for (col = 0, table_width = 0.0; col < num_cols; col ++)
|
||||
{
|
||||
cols[col].max_width += 2.0 * TABLE_PADDING;
|
||||
|
||||
table_width += cols[col].max_width;
|
||||
cols[col].width = cols[col].max_width;
|
||||
}
|
||||
|
||||
format_width = right - left - 2.0 * TABLE_PADDING * num_cols;
|
||||
|
||||
if (table_width > format_width)
|
||||
{
|
||||
// Content too wide, try scaling the widths...
|
||||
double avg_width, // Average column width
|
||||
base_width, // Base width
|
||||
remaining_width, // Remaining width
|
||||
scale_width; // Width for scaling
|
||||
size_t num_remaining_cols = 0; // Number of remaining columns
|
||||
|
||||
// First mark any columns that are narrower than the average width...
|
||||
avg_width = format_width / num_cols;
|
||||
|
||||
for (col = 0, base_width = 0.0, remaining_width = 0.0; col < num_cols; col ++)
|
||||
{
|
||||
if (cols[col].width > avg_width)
|
||||
{
|
||||
remaining_width += cols[col].width;
|
||||
num_remaining_cols ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
base_width += cols[col].width;
|
||||
}
|
||||
}
|
||||
|
||||
// Then proportionately distribute the remaining width to the other columns...
|
||||
format_width -= base_width;
|
||||
|
||||
for (col = 0, table_width = 0.0; col < num_cols; col ++)
|
||||
{
|
||||
if (cols[col].width > avg_width)
|
||||
cols[col].width = cols[col].width * format_width / remaining_width;
|
||||
|
||||
table_width += cols[col].width;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the margins of each column in preparation for formatting
|
||||
for (col = 0, x = left + TABLE_PADDING; col < num_cols; col ++)
|
||||
{
|
||||
cols[col].left = x;
|
||||
cols[col].right = x + cols[col].width;
|
||||
|
||||
x += cols[col].width + 2.0 * TABLE_PADDING;
|
||||
}
|
||||
|
||||
// Calculate the height of each row and cell in preparation for formatting
|
||||
for (row = 0, rowptr = rows; row < num_rows; row ++, rowptr ++)
|
||||
{
|
||||
for (col = 0; col < num_cols; col ++)
|
||||
{
|
||||
height = measure_cell(dd, rowptr->cells[col], cols + col) + 2.0 * TABLE_PADDING;
|
||||
if (height > rowptr->height)
|
||||
rowptr->height = height;
|
||||
}
|
||||
}
|
||||
|
||||
// Render each table row...
|
||||
if (dd->st)
|
||||
dd->y -= SIZE_TABLE * LINE_HEIGHT;
|
||||
|
||||
for (row = 0, rowptr = rows; row < num_rows; row ++, rowptr ++)
|
||||
render_row(dd, num_cols, cols, rowptr);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'format_doc()' - Format a document.
|
||||
//
|
||||
@ -820,6 +1249,10 @@ format_doc(docdata_t *dd, // I - Document data
|
||||
format_block(dd, current, DOCFONT_REGULAR, SIZE_BODY, left, right, /*leader*/NULL);
|
||||
break;
|
||||
|
||||
case MMD_TYPE_TABLE :
|
||||
format_table(dd, current, left, right);
|
||||
break;
|
||||
|
||||
case MMD_TYPE_CODE_BLOCK :
|
||||
format_code(dd, current, left + 36.0, right - 36.0);
|
||||
break;
|
||||
@ -912,8 +1345,13 @@ main(int argc, // I - Number of command-line arguments
|
||||
// Add fonts...
|
||||
for (fontface = DOCFONT_REGULAR; fontface < DOCFONT_MAX; fontface ++)
|
||||
{
|
||||
#if USE_TRUETYPE
|
||||
if ((dd.fonts[fontface] = pdfioFileCreateFontObjFromFile(dd.pdf, docfont_filenames[fontface], UNICODE_VALUE)) == NULL)
|
||||
return (1);
|
||||
#else
|
||||
if ((dd.fonts[fontface] = pdfioFileCreateFontObjFromBase(dd.pdf, docfont_filenames[fontface])) == NULL)
|
||||
return (1);
|
||||
#endif // USE_TRUETYPE
|
||||
}
|
||||
|
||||
// Add images...
|
||||
|
308
pdfio-base-font-widths.h
Normal file
308
pdfio-base-font-widths.h
Normal file
@ -0,0 +1,308 @@
|
||||
//
|
||||
// PDF base font widths for PDFio.
|
||||
//
|
||||
// Copyright © 2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
//
|
||||
|
||||
#ifndef PDFIO_BASE_FONT_WIDTHS_H
|
||||
# define PDFIO_BASE_FONT_WIDTHS_H 1
|
||||
|
||||
|
||||
static short courier_bold_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_boldoblique_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_oblique_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short courier_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0,
|
||||
600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600,
|
||||
0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
|
||||
600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_bold_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
|
||||
975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
|
||||
333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
|
||||
611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
|
||||
556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 351, 351, 333, 611, 556, 278, 333, 351, 365, 556, 869, 869, 869, 611,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_boldoblique_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
|
||||
975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
|
||||
333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
|
||||
611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
|
||||
556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 444, 444, 333, 611, 556, 278, 333, 444, 365, 556, 1055, 1055, 1055, 611,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_oblique_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
|
||||
1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
|
||||
333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
|
||||
556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
|
||||
556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 390, 390, 333, 556, 537, 278, 333, 390, 365, 556, 947, 947, 947, 611,
|
||||
667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500
|
||||
};
|
||||
|
||||
|
||||
static short helvetica_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
|
||||
1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
|
||||
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
|
||||
333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
|
||||
556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
|
||||
556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0,
|
||||
0, 222, 221, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
|
||||
0, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 584, 737, 333,
|
||||
606, 584, 351, 351, 333, 556, 537, 278, 333, 351, 365, 556, 869, 869, 869, 611,
|
||||
667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
|
||||
722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 666, 666, 611,
|
||||
556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
|
||||
556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 555, 500
|
||||
};
|
||||
|
||||
|
||||
static short symbol_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444,
|
||||
549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722,
|
||||
768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500,
|
||||
500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549,
|
||||
549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
762, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603,
|
||||
400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658,
|
||||
823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713,
|
||||
768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603,
|
||||
494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494,
|
||||
0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0
|
||||
};
|
||||
|
||||
|
||||
static short times_bold_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
|
||||
930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778,
|
||||
611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500,
|
||||
333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500,
|
||||
556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 0,
|
||||
500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 0, 667, 0,
|
||||
0, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 444, 722,
|
||||
0, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 570, 747, 333,
|
||||
400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500,
|
||||
722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389,
|
||||
722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556,
|
||||
500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500
|
||||
};
|
||||
|
||||
|
||||
static short times_bolditalic_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
|
||||
832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722,
|
||||
611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500,
|
||||
333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500,
|
||||
500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 0,
|
||||
500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 0, 611, 0,
|
||||
0, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 389, 611,
|
||||
0, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 606, 747, 333,
|
||||
400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500,
|
||||
667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389,
|
||||
722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500,
|
||||
500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444
|
||||
};
|
||||
|
||||
|
||||
static short times_italic_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500,
|
||||
920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722,
|
||||
611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500,
|
||||
333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500,
|
||||
500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 0,
|
||||
500, 0, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 0, 556, 0,
|
||||
0, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 0, 389, 556,
|
||||
0, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 675, 760, 333,
|
||||
400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500,
|
||||
611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333,
|
||||
722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500,
|
||||
500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444
|
||||
};
|
||||
|
||||
|
||||
static short times_roman_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444,
|
||||
921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722,
|
||||
556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500,
|
||||
333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500,
|
||||
500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 0,
|
||||
500, 0, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 0, 611, 0,
|
||||
0, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 0, 444, 722,
|
||||
0, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 564, 760, 333,
|
||||
400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444,
|
||||
722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333,
|
||||
722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500,
|
||||
444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278,
|
||||
500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500
|
||||
};
|
||||
|
||||
|
||||
static short zapf_dingbats_widths[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933,
|
||||
911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537,
|
||||
577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831,
|
||||
923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826,
|
||||
815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762,
|
||||
762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
|
||||
788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834,
|
||||
873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874,
|
||||
0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0
|
||||
};
|
||||
|
||||
|
||||
#endif // !PDFIO_BASE_FONT_WIDTHS_H
|
169
pdfio-content.c
169
pdfio-content.c
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Content helper functions for PDFio.
|
||||
//
|
||||
// Copyright © 2021-2023 by Michael R Sweet.
|
||||
// Copyright © 2021-2024 by Michael R Sweet.
|
||||
//
|
||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||
// information.
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
#include "pdfio-private.h"
|
||||
#include "pdfio-content.h"
|
||||
#include "pdfio-base-font-widths.h"
|
||||
#include "ttf.h"
|
||||
#include <math.h>
|
||||
#ifndef M_PI
|
||||
@ -1074,7 +1075,7 @@ pdfioContentTextMeasure(
|
||||
const char *s, // I - UTF-8 string
|
||||
double size) // I - Font size/height
|
||||
{
|
||||
const char *subtype; // Font sub-type
|
||||
const char *basefont; // Base font name
|
||||
ttf_t *ttf = (ttf_t *)_pdfioObjGetExtension(font);
|
||||
// TrueType font data
|
||||
ttf_rect_t extents; // Text extents
|
||||
@ -1083,75 +1084,124 @@ pdfioContentTextMeasure(
|
||||
*tempptr; // Pointer into temporary string
|
||||
|
||||
|
||||
if ((subtype = pdfioObjGetSubtype(font)) == NULL || strcmp(subtype, "Type0"))
|
||||
if (!ttf && (basefont = pdfioDictGetName(pdfioObjGetDict(font), "BaseFont")) != NULL)
|
||||
{
|
||||
// Map non-CP1282 characters to '?', everything else as-is...
|
||||
tempptr = temp;
|
||||
// Measure the width using the compiled-in base font tables...
|
||||
const short *widths; // Widths
|
||||
int width = 0; // Current width
|
||||
|
||||
while (*s && tempptr < (temp + sizeof(temp) - 3))
|
||||
if (strcmp(basefont, "Symbol") && strcmp(basefont, "Zapf-Dingbats"))
|
||||
{
|
||||
if ((*s & 0xe0) == 0xc0)
|
||||
{
|
||||
// Two-byte UTF-8
|
||||
ch = ((s[0] & 0x1f) << 6) | (s[1] & 0x3f);
|
||||
s += 2;
|
||||
}
|
||||
else if ((*s & 0xf0) == 0xe0)
|
||||
{
|
||||
// Three-byte UTF-8
|
||||
ch = ((s[0] & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f);
|
||||
s += 3;
|
||||
}
|
||||
else if ((*s & 0xf8) == 0xf0)
|
||||
{
|
||||
// Four-byte UTF-8
|
||||
ch = ((s[0] & 0x07) << 18) | ((s[1] & 0x3f) << 12) | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f);
|
||||
s += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = *s++;
|
||||
}
|
||||
// Map non-CP1282 characters to '?', everything else as-is...
|
||||
tempptr = temp;
|
||||
|
||||
if (ch > 255)
|
||||
while (*s && tempptr < (temp + sizeof(temp) - 3))
|
||||
{
|
||||
// Try mapping from Unicode to CP1252...
|
||||
size_t i; // Looping var
|
||||
|
||||
for (i = 0; i < (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])); i ++)
|
||||
if ((*s & 0xe0) == 0xc0)
|
||||
{
|
||||
if (ch == _pdfio_cp1252[i])
|
||||
break;
|
||||
// Two-byte UTF-8
|
||||
ch = ((s[0] & 0x1f) << 6) | (s[1] & 0x3f);
|
||||
s += 2;
|
||||
}
|
||||
else if ((*s & 0xf0) == 0xe0)
|
||||
{
|
||||
// Three-byte UTF-8
|
||||
ch = ((s[0] & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f);
|
||||
s += 3;
|
||||
}
|
||||
else if ((*s & 0xf8) == 0xf0)
|
||||
{
|
||||
// Four-byte UTF-8
|
||||
ch = ((s[0] & 0x07) << 18) | ((s[1] & 0x3f) << 12) | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f);
|
||||
s += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = *s++;
|
||||
}
|
||||
|
||||
if (i >= (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])))
|
||||
ch = '?'; // Unsupported chars map to ?
|
||||
if (ch > 255)
|
||||
{
|
||||
// Try mapping from Unicode to CP1252...
|
||||
size_t i; // Looping var
|
||||
|
||||
for (i = 0; i < (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])); i ++)
|
||||
{
|
||||
if (ch == _pdfio_cp1252[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])))
|
||||
ch = '?'; // Unsupported chars map to ?
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 2048)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | ((ch >> 6) & 0x1f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | ((ch >> 12) & 0x0f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
if (ch < 128)
|
||||
{
|
||||
// ASCII
|
||||
*tempptr++ = (char)ch;
|
||||
}
|
||||
else if (ch < 2048)
|
||||
{
|
||||
// 2-byte UTF-8
|
||||
*tempptr++ = (char)(0xc0 | ((ch >> 6) & 0x1f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 3-byte UTF-8
|
||||
*tempptr++ = (char)(0xe0 | ((ch >> 12) & 0x0f));
|
||||
*tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*tempptr++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
*tempptr = '\0';
|
||||
s = temp;
|
||||
}
|
||||
|
||||
*tempptr = '\0';
|
||||
s = temp;
|
||||
// Choose the appropriate table...
|
||||
if (!strcmp(basefont, "Courier"))
|
||||
widths = courier_widths;
|
||||
else if (!strcmp(basefont, "Courier-Bold"))
|
||||
widths = courier_bold_widths;
|
||||
else if (!strcmp(basefont, "Courier-BoldOblique"))
|
||||
widths = courier_boldoblique_widths;
|
||||
else if (!strcmp(basefont, "Courier-Oblique"))
|
||||
widths = courier_oblique_widths;
|
||||
else if (!strcmp(basefont, "Helvetica"))
|
||||
widths = helvetica_widths;
|
||||
else if (!strcmp(basefont, "Helvetica-Bold"))
|
||||
widths = helvetica_bold_widths;
|
||||
else if (!strcmp(basefont, "Helvetica-BoldOblique"))
|
||||
widths = helvetica_boldoblique_widths;
|
||||
else if (!strcmp(basefont, "Helvetica-Oblique"))
|
||||
widths = helvetica_oblique_widths;
|
||||
else if (!strcmp(basefont, "Symbol"))
|
||||
widths = symbol_widths;
|
||||
else if (!strcmp(basefont, "Times-Bold"))
|
||||
widths = times_bold_widths;
|
||||
else if (!strcmp(basefont, "Times-BoldItalic"))
|
||||
widths = times_bolditalic_widths;
|
||||
else if (!strcmp(basefont, "Times-Italic"))
|
||||
widths = times_italic_widths;
|
||||
else if (!strcmp(basefont, "Times-Roman"))
|
||||
widths = times_roman_widths;
|
||||
else if (!strcmp(basefont, "Zapf-Dingbats"))
|
||||
widths = zapf_dingbats_widths;
|
||||
else
|
||||
return (0.0);
|
||||
|
||||
// Calculate the width using the corresponding table...
|
||||
while (*s)
|
||||
{
|
||||
width += widths[*s & 255];
|
||||
s ++;
|
||||
}
|
||||
|
||||
return (size * 0.001 * width);
|
||||
}
|
||||
|
||||
// If we get here then we need to measure using the TrueType library...
|
||||
ttfGetExtents(ttf, (float)size, s, &extents);
|
||||
|
||||
return (extents.right - extents.left);
|
||||
@ -1421,8 +1471,9 @@ pdfioContentTextShowJustified(
|
||||
// - "Times-Roman"
|
||||
// - "ZapfDingbats"
|
||||
//
|
||||
// Base fonts always use the Windows CP1252 (ISO-8859-1 with additional
|
||||
// characters such as the Euro symbol) subset of Unicode.
|
||||
// Aside from "Symbol" and "Zapf-Dingbats", Base fonts use the Windows CP1252
|
||||
// (ISO-8859-1 with additional characters such as the Euro symbol) subset of
|
||||
// Unicode.
|
||||
//
|
||||
|
||||
pdfio_obj_t * // O - Font object
|
||||
|
Loading…
Reference in New Issue
Block a user